makwa 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5b57daebaedd9cdfe6e14503bc559f2b3cc9dc40beeb3461c2070b1f2c659a1
4
- data.tar.gz: 1f57dc2aa9f5376a14ae4bde76d88be11ba6ad897892f8adeb69272962426116
3
+ metadata.gz: 05d88c5995c722bae7c3769dfafe68dcf56389462b9d0ae6dc1a1fb330bab923
4
+ data.tar.gz: 6cb8f9358894fa15ab384a760a07bc37a1e6ac2c14dc72286421024b4fd5fb6d
5
5
  SHA512:
6
- metadata.gz: 41aa06f6e10421a0c1fe9af084b36838670c1300f00bb359975482539537f0bf852903a28cb058a0ea8ee996bcb953f850ccc915a8ac99861aa2a74e11860182
7
- data.tar.gz: 76f38892c52dbeec20840416e10196c702e34ad351c2fd7f366c1d43aad4b2eb21221fc8ff113a793a4f83716c8703bfe18e9be751e36774003f655f0c2e0b8a
6
+ metadata.gz: 7a5426ce17f47958382bcd42cb203524e2625c9fe67a3f1b3cb3afc371592bc1ca11b4fd8db705d2710bf0c7b75202b762ec8f272d0f3cd5d234581e9c0e63e9
7
+ data.tar.gz: d71ba78909dd101447aa104d62eb49444c09713bcde3403969ad45a5b566ce10f0da4d7031c53d9aa546cbe1b3f33de6115e060f4a9663b6960e952bc4393d99
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.1] - 2022-12-01
4
+
5
+ - Fixes reference to nested class (symbol -> string)
6
+
3
7
  ## [1.0.0] - 2022-11-26
4
8
 
5
9
  - Upgrades ActiveInteraction from 4.x to 5.2.x. Please see the [ActiveInteraction CHANGELOG](https://github.com/AaronLasseigne/active_interaction/blob/main/CHANGELOG.md) for what has changed between v. 4.x and 5. There are some breaking changes.
@@ -4,10 +4,18 @@
4
4
 
5
5
  When to use an interaction:
6
6
 
7
- * Use interactions for all but the most trivial ActiveRecord mutating CRUD operations.
8
- * Replace **ALL** ActiveRecord `:after_...` callbacks with interactions. This refers to all after callbacks, not just save.
9
- * Replace **MOST** ActiveRecord `:before_...` callbacks with interactions. This refers to all `:before_…` callbacks, not just save. An exception that can remain as a callback could be a `:before_validation` callback to sanitize an email address (strip surrounding whitespace, lower case), however, if there is already an interaction to create/update a user, you may as well do it in the interaction.
10
- * Replace Model instance and class methods that implement complex behaviours with interactions. Note that you can still use the Model methods as interface, however, the implementation should live in an interaction.
7
+ * Integration with Rails CRUD forms:
8
+ * FormObject preparation.
9
+ * FormParams sanitization/transformation
10
+ * special validations
11
+ * CRUD persistence operations
12
+ * post-persistence actions like sending an email, or triggering another interaction
13
+ * Decoupling behavior from ActiveRecord classes:
14
+ * Replace **ALL** ActiveRecord `:after_...` callbacks with interactions. This refers to all after callbacks, not just save.
15
+ * Replace **MOST** ActiveRecord `:before_...` callbacks with interactions. This refers to all `:before_…` callbacks, not just save. An exception that can remain as a callback could be a `:before_validation` callback to sanitize an email address (strip surrounding whitespace, lower case), however, if there is already an interaction to create/update a user, you may as well do it in the interaction.
16
+ * Replace Model instance and class methods that implement complex behaviours with interactions. Note that you can still use the Model methods as interface, however, the implementation should live in an interaction.
17
+ * Implement complex domain behaviours by composing sub tasks into higher level processes.
18
+ * Wrap a 3rd party service so that we can swap it out in a single place if needed.
11
19
 
12
20
  ## ReturningInteractions
13
21
 
@@ -1,3 +1,95 @@
1
1
  # Features and design considerations
2
2
 
3
- TBD
3
+ ## Input validation and coercion
4
+
5
+ All input arguments are validated and coerced before the interaction is invoked. Depending on the use case we can use the following validations:
6
+
7
+ * ActiveInteraction input filters - Check for presence of input argument keys, their types, and can set default values for optional input arguments.
8
+ * ActiveModel validations in the Interaction. - Use the full power of ActiveModel::Validation to check for specific values, or higher level business rules that are specific to the interaction.
9
+ * ActiveModel validations in the ActiveRecord instance passed to a ReturningInteraction - For shared validations that apply to all related interactions.
10
+ * Dry-validation based contracts for advanced validations of deeply nested data structures.
11
+
12
+ The validation solutions listed above offer the following features:
13
+
14
+ * Type checking.
15
+ * Ability to implement complex validation rules.
16
+ * Ability to look at other input args when validating an arg.
17
+ * Composability: Input validations can be composed to prevent duplication and allow re-use. Dry validation offers this temporary workaround for composing rules: https://github.com/dry-rb/dry-validation/issues/593#issuecomment-631597226
18
+ * Type coercion, e.g., for Rails request params that need to be cast from String to Integer.
19
+ * Runtime validation (since we don’t know what arguments are passed to an Interaction at compile time).
20
+ * Default values can be assigned when using ActiveInteraction input filters.
21
+
22
+ Below are some options for input argument validation:
23
+
24
+ * ActiveModel Validations: https://api.rubyonrails.org/classes/ActiveModel/Validations.html
25
+ * ActiveInteraction filters: https://github.com/AaronLasseigne/active_interaction#filters
26
+ * dry-validation contracts: https://dry-rb.org/gems/dry-validation/
27
+
28
+ ## Composability
29
+
30
+ Interactions can be composed to facilitate re-use and modularity.
31
+
32
+ * Errors raised in composed interactions are merged into the parent interaction.
33
+ * Execution in parent interaction stops when a composed interaction fails.
34
+ * Composed interactions act like the #run! bang method with exception handling built in.
35
+
36
+ Code example:
37
+
38
+ ```
39
+ def execute
40
+ r1 = compose(Nested::Service1, arg1: 123, arg2: "a string")
41
+ r2 = compose(Nested::Service2, arg1: r1)
42
+ end
43
+ ```
44
+
45
+ Note that ActiveInteraction input filters can also be reused via `import_filters OtherInteraction`.
46
+
47
+ ## Exception handling and error reporting
48
+
49
+ * Errors (not Ruby Exceptions!) added in an interaction are accessible to the caller for testing and notification purposes.
50
+ * Errors are addable manually inside the interaction via errors.add(:base, text: "something went wrong", key: :something_went_wrong).
51
+ * Errors are mergeable from other sources, e.g., ActiveRecord objects or nested interactions via errors.merge!(@user.errors).
52
+ * Early exit of the interaction is possible if an unrecoverable error condition is detected. E.g., via return_if_errors! or return.
53
+
54
+ ## Localization
55
+
56
+ Success and error messages are customizable via Rails' default I18n mechanisms.
57
+
58
+ ## Integration with Rails forms
59
+
60
+ ReturningInteractions, are a specialized subclass of ActiveInteraction, work well with processing params submitted from Rails forms, and with possible re-rendering of the form if there are any errors.
61
+
62
+ ## Dependency injection
63
+
64
+ Dependencies can be injected into an interaction, mostly for testing. Example: We inject a fake `Git` library when testing code that makes git commits. Other examples: `File`, `Time`, `TwitterApi`, etc.
65
+
66
+ ## Serializability
67
+
68
+ Invocation of an interaction, with its input arguments, can be serialized in a simple, robust, and performant way. We accomplish this by limiting input arguments to basic Ruby types: Hashes, Arrays, Strings, Numbers, and Booleans.
69
+
70
+ ## Logging
71
+
72
+ Interactions print detailed info to the log. Output includes:
73
+
74
+ * Name of invoked interaction
75
+ * caller
76
+ * input args
77
+ * any errors
78
+
79
+ Example:
80
+
81
+ ```
82
+ Executing interaction Niiwin::NwLoader::InitialLoad (id#70361484811280)
83
+ ↳ inputs: {} (id#70361484811280)
84
+ Executing interaction Niiwin::NwLoader::NwConfigs::Load (id#70361484766000)
85
+ ↳ called from niiwin/nw_loader/initial_load.rb:14:in `initial_load_nw_config' (id#70361484766000)
86
+ ↳ inputs: {} (id#70361484766000)
87
+ ↳ outcome: succeeded (id#70361484766000)
88
+ Executing interaction Niiwin::NwLoader::NwConfigs::Validate (id#70361476717620)
89
+ ↳ called from niiwin/nw_loader/initial_load.rb:15:in `initial_load_nw_config' (id#70361476717620)
90
+ ↳ inputs: {} (id#70361476717620)
91
+ ↳ outcome: succeeded (id#70361476717620)
92
+ ↳ outcome: succeeded (id#70361484811280)
93
+ ```
94
+
95
+ You can turn off logging by overriding the `ApplicationInteraction#debug` method.
@@ -9,5 +9,6 @@
9
9
  * Commit the change with "Bump makwa to <version>"
10
10
  * Tag the commit of the new version with `v<version>`
11
11
  * Push the changes
12
+ * Build the gem with `gem build`
12
13
  * Distribute new release
13
- * `gem push makwa` - This will push the new release to rubygems.org.
14
+ * `gem push makwa-<version>.gem` - This will push the new release to rubygems.org.
@@ -15,7 +15,7 @@ end
15
15
  ```
16
16
 
17
17
  ```ruby
18
- # app/interactions/application_interaction.rb
18
+ # app/interactions/application_returning_interaction.rb
19
19
  class ApplicationReturningInteraction < Makwa::ReturningInteraction
20
20
  def debug(txt)
21
21
  # Uncomment the next line for detailed debug output
@@ -50,6 +50,12 @@ module Infrastructure
50
50
  end
51
51
  ```
52
52
 
53
+ You can then use this interaction to send emails:
54
+
55
+ ```ruby
56
+ Infrastructure::SendEmail.run!(recipient_email: "email@test.com", subject: "Email Subject", body: "Email Body")
57
+ ```
58
+
53
59
  ## Implement a ReturningInteraction to create a user
54
60
 
55
61
  ```ruby
@@ -141,7 +147,7 @@ class UsersController < ApplicationController
141
147
  end
142
148
 
143
149
  def update
144
- @user = Users::Create.run_returning!(
150
+ @user = Users::Update.run_returning!(
145
151
  {user: @user}.merge(params.fetch(:user, {}))
146
152
  )
147
153
 
@@ -187,7 +193,7 @@ Interactions follow these conventions:
187
193
  * Makes it easy to pass test data into an interaction.
188
194
  * Makes it easy to serialize the invocation of an interaction, e.g., for a Sidekiq background job.
189
195
  * We do not pass in ActiveRecord instances, but their ids instead. We rely on ActiveRecord caching to prevent multiple DB reads when passing the same record id into nested interactions. Exceptions:
190
- * You can pass a descendent of ActiveModel, e.g., an ActiveRecord instance as the returned input to a ReturningInteraction. Use the record input filter type. It accepts both the ActiveRecord instance, as well as its id attribute. That way, you can still pass in basic Ruby types, e.g., in the console when invoking the interaction.
196
+ * You can pass a descendant of ActiveModel, e.g., an ActiveRecord instance as the returned input to a ReturningInteraction. Use the record input filter type. It accepts both the ActiveRecord instance, as well as its id attribute. That way, you can still pass in basic Ruby types, e.g., in the console when invoking the interaction.
191
197
  * In some use cases with nested interactions, we may choose to pass in an ActiveRecord instance to work around persistence concerns.
192
198
  * When an interaction is concerned with an ActiveRecord instance, we pass the record’s id under the :id hash key (unless it’s a ReturningInteraction).
193
199
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Makwa
4
4
  class Interaction < ::ActiveInteraction::Base
5
- class Interrupt < Object.const_get(:"::ActiveInteraction::Interrupt")
5
+ class Interrupt < Object.const_get("::ActiveInteraction::Interrupt")
6
6
  end
7
7
 
8
8
  #
data/lib/makwa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Makwa
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makwa
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jo Hund
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-11-28 00:00:00.000000000 Z
12
+ date: 2022-12-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: active_interaction