axn 0.1.0.pre.alpha.2.5.1.1 → 0.1.0.pre.alpha.2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb044bed464d8840289e69cb631ff47ebc44999ac7e6327fc3b69dd62a37a6af
4
- data.tar.gz: 0f0db9209a545ac84b88df56aaeaea431e6094385c433775f8d3f6501d84e870
3
+ metadata.gz: 6902996eda6bf8911d2f90f73217d56a0905ddf0772ebfee3a9c2bbf8072279e
4
+ data.tar.gz: 3615981ef31731e017b2b9399b485290041b1a79cc0ccc231c189399ddb4e5f4
5
5
  SHA512:
6
- metadata.gz: df227aa350f02e53d8141fec5bd6855ed31c1da64ec9b6567ce3906b86fce2bc6b1b4bc24a38042b565da8c7bee6df0ed95fd0bd1ab5afa8b722397ce10b5f09
7
- data.tar.gz: 35b54feff70f62f1b18e9dbe9b0ac066ee6c1b13118f871e9b4bf36a8949661410886b4ac97e019f5c3a89c5f3082c9cebe0008a12c5fc810cbea418ef1c99bc
6
+ metadata.gz: 1f9ae2c8d65defac13be5abded734bdcf1057e8d880878d8cf4c57c58ef537d257a7a96208fe83616ce8ddc89344c60042b9eadbe8575b52d14fa9fa9981489e
7
+ data.tar.gz: bcbf95ea1e179a44076cb5b451f0ab1f94001bccb30bd78fd3fbbd025472fb08bed4cda805cf934ab6f3328f4aced08a96ff4983142aeed67c7121ecddd11e2b
data/.rubocop.yml CHANGED
@@ -27,12 +27,18 @@ Style/TrailingCommaInArrayLiteral:
27
27
  Style/TrailingCommaInHashLiteral:
28
28
  EnforcedStyleForMultiline: comma
29
29
 
30
+ Style/ClassAndModuleChildren:
31
+ Enabled: false
32
+
30
33
  Style/DoubleNegation:
31
34
  Enabled: false
32
35
 
33
36
  Metrics/BlockLength:
34
37
  Enabled: false
35
38
 
39
+ Metrics/ModuleLength:
40
+ Enabled: false
41
+
36
42
  Metrics/MethodLength:
37
43
  Max: 60
38
44
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+ * N/A
5
+
6
+ ## 0.1.0-alpha.2.5.2
7
+ * [BREAKING] Removing `EnqueueAllInBackground` + `EnqueueAllWorker` - better + simply solved at application level
8
+ * [TEST] Expose spec helpers to consumers (add `require "axn/testing/spec_helpers"` to your `spec_helper.rb`)
9
+ # [FEAT] Added ability to use custom Strategies (via e.g. `use :transaction`)
10
+
11
+ ## 0.1.0-alpha.2.5.1.2
12
+ * [BUGFIX] Subfield expectations: now support hashes with string keys (using with_indifferent_access)
13
+ * [BUGFIX] Subfield expectations: Model reader fields now cache initial value (otherwise get fresh instance each call, cannot make in-memory changes)
14
+
3
15
  ## 0.1.0-alpha.2.5.1.1
4
16
  * [BUGFIX] TypeValidator must handle anonymous classes when determining if given argument is an RSpec mock
5
17
 
@@ -47,6 +47,13 @@ export default defineConfig({
47
47
  { text: 'Testing Actions', link: '/recipes/testing' },
48
48
  ]
49
49
  },
50
+ {
51
+ text: 'Strategies',
52
+ items: [
53
+ { text: 'Overview', link: '/strategies/index' },
54
+ { text: 'Transaction', link: '/strategies/transaction' },
55
+ ]
56
+ },
50
57
  {
51
58
  text: 'Additional Notes',
52
59
  items: [
@@ -0,0 +1,272 @@
1
+ # Strategies
2
+
3
+ Strategies in Axn are reusable modules that provide common functionality and configuration patterns for your actions. They allow you to DRY up your code by encapsulating frequently used behaviors into named, configurable modules.
4
+
5
+ ## What are Strategies?
6
+
7
+ Strategies are Ruby modules that can be included into your actions to add specific functionality. They're designed to be:
8
+
9
+ - **Reusable**: Once defined, they can be used across multiple actions
10
+ - **Configurable**: Many strategies support configuration options
11
+ - **Composable**: You can use multiple strategies in a single action
12
+ - **Discoverable**: Built-in strategies are automatically loaded, and custom ones can be registered
13
+
14
+ ## How to Use Strategies
15
+
16
+ ### Basic Usage
17
+
18
+ To use a strategy in your action, call the `use` method with the strategy name:
19
+
20
+ ```ruby
21
+ class CreateUser
22
+ include Action
23
+
24
+ use :transaction
25
+
26
+ expects :email, :name
27
+
28
+ def call
29
+ # This action will now run within a database transaction (including before/after hooks)
30
+ user = User.create!(email: email, name: name)
31
+ expose :user, user
32
+ end
33
+ end
34
+ ```
35
+
36
+ ### Using Strategies with Configuration
37
+
38
+ Some strategies support configuration options. These strategies have a `setup` method that accepts configuration and returns a configured module. As an _imaginary_ example:
39
+
40
+ ```ruby
41
+ class ProcessPayment
42
+ include Action
43
+
44
+ use :retry, max_attempts: 3, backoff: :exponential
45
+
46
+ expects :amount, :card_token
47
+
48
+ def call
49
+ # This action will retry up to 3 times with exponential backoff
50
+ result = PaymentProcessor.charge(amount, card_token)
51
+ expose :transaction_id, result.id
52
+ end
53
+ end
54
+ ```
55
+
56
+ ## Built-in Strategies
57
+
58
+ The list of built in strategies is available via `Action::Strategies.built_in`.
59
+
60
+ ## Registering Custom Strategies
61
+
62
+ ### Simple Strategies
63
+
64
+ To create a custom strategy, define a module that extends `ActiveSupport::Concern`:
65
+
66
+ ```ruby
67
+ module MyCustomStrategy
68
+ extend ActiveSupport::Concern
69
+
70
+ included do
71
+ # Add your strategy behavior here
72
+ # For example, add hooks, validations, or other functionality
73
+ before { log("Custom strategy before hook") }
74
+ after { log("Custom strategy after hook") }
75
+ end
76
+ end
77
+ ```
78
+
79
+ Then register it with the strategies system:
80
+
81
+ ```ruby
82
+ Action::Strategies.register(:my_custom, MyCustomStrategy)
83
+ ```
84
+
85
+ Now you can use it in your actions:
86
+
87
+ ```ruby
88
+ class MyAction
89
+ include Action
90
+
91
+ use :my_custom
92
+
93
+ def call
94
+ # Your action implementation
95
+ end
96
+ end
97
+ ```
98
+
99
+ ### Configurable Strategies
100
+
101
+ For strategies that need configuration, implement a `setup` method that returns a configured module:
102
+
103
+ ```ruby
104
+ module RetryStrategy
105
+ extend ActiveSupport::Concern
106
+
107
+ def self.setup(max_attempts: 3, backoff: :linear, &block)
108
+ Module.new do
109
+ extend ActiveSupport::Concern
110
+
111
+ included do
112
+ around do |hooked|
113
+ attempts = 0
114
+ begin
115
+ attempts += 1
116
+ hooked.call
117
+ rescue StandardError => e
118
+ if attempts < max_attempts
119
+ sleep(backoff_delay(attempts, backoff))
120
+ retry
121
+ else
122
+ raise e
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ private
129
+
130
+ def backoff_delay(attempt, type)
131
+ case type
132
+ when :linear
133
+ attempt * 0.1
134
+ when :exponential
135
+ 0.1 * (2 ** (attempt - 1))
136
+ else
137
+ 0.1
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ # Register the strategy
145
+ Action::Strategies.register(:retry, RetryStrategy)
146
+ ```
147
+
148
+ ### Strategy Registration Best Practices
149
+
150
+ 1. **Register early**: Register custom strategies during application initialization
151
+ 2. **Use descriptive names**: Choose strategy names that clearly indicate their purpose
152
+ 3. **Handle configuration validation**: Validate configuration options in your `setup` method
153
+ 4. **Return proper modules**: Always return a module from the `setup` method
154
+ 5. **Document your strategies**: Include clear documentation for how to use your custom strategies
155
+
156
+ ### Example: Complete Custom Strategy
157
+
158
+ Here's a complete example of a custom strategy that adds performance monitoring:
159
+
160
+ ```ruby
161
+ module PerformanceMonitoringStrategy
162
+ extend ActiveSupport::Concern
163
+
164
+ def self.setup(threshold_ms: 1000, notify_slow: false, &block)
165
+ Module.new do
166
+ extend ActiveSupport::Concern
167
+
168
+ included do
169
+ around do |hooked|
170
+ start_time = Time.current
171
+ result = hooked.call
172
+ duration = ((Time.current - start_time) * 1000).round(2)
173
+
174
+ if duration > threshold_ms
175
+ log("Action took #{duration}ms (threshold: #{threshold_ms}ms)", level: :warn)
176
+ notify_slow_action(duration) if notify_slow
177
+ else
178
+ log("Action completed in #{duration}ms", level: :info)
179
+ end
180
+
181
+ result
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ def notify_slow_action(duration)
188
+ # In a real implementation, this might send to a monitoring service
189
+ # like New Relic, DataDog, or a custom alerting system
190
+ Rails.logger.warn("SLOW ACTION ALERT: #{self.class.name} took #{duration}ms")
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ # Register the strategy
197
+ Action::Strategies.register(:performance_monitoring, PerformanceMonitoringStrategy)
198
+
199
+ # Use it in an action
200
+ class ExpensiveCalculation
201
+ include Action
202
+
203
+ use :performance_monitoring, threshold_ms: 500, notify_slow: true
204
+
205
+ expects :data
206
+
207
+ def call
208
+ # This action will be monitored for performance
209
+ result = perform_expensive_calculation(data)
210
+ expose :result, result
211
+ end
212
+
213
+ private
214
+
215
+ def perform_expensive_calculation(data)
216
+ # Simulate expensive operation
217
+ sleep(0.1)
218
+ data.map { |item| item * 2 }
219
+ end
220
+ end
221
+ ```
222
+
223
+ ## Strategy Management
224
+
225
+ ### Viewing Available Strategies
226
+
227
+ You can inspect all registered strategies:
228
+
229
+ ```ruby
230
+ Action::Strategies.all
231
+ # Returns a hash of strategy names to their modules
232
+ ```
233
+
234
+ ### Finding Specific Strategies
235
+
236
+ To find a specific strategy by name:
237
+
238
+ ```ruby
239
+ Action::Strategies.find(:transaction)
240
+ # Returns the strategy module for the transaction strategy
241
+
242
+ Action::Strategies.find(:nonexistent)
243
+ # Raises Action::StrategyNotFound: Strategy 'nonexistent' not found
244
+ ```
245
+
246
+ The `find` method is useful when you need to programmatically access a strategy module or verify that a strategy exists before using it.
247
+
248
+ ### Clearing Strategies
249
+
250
+ To reset strategies to only built-in ones (useful in tests):
251
+
252
+ ```ruby
253
+ Action::Strategies.clear!
254
+ ```
255
+
256
+ ### Strategy Errors
257
+
258
+ The following errors may be raised when using strategies:
259
+
260
+ - `Action::StrategyNotFound`: When trying to use a strategy that hasn't been registered
261
+ - `Action::DuplicateStrategyError`: When trying to register a strategy with a name that's already taken
262
+ - `ArgumentError`: When providing configuration to a strategy that doesn't support it
263
+
264
+ ## Best Practices
265
+
266
+ 1. **Keep strategies focused**: Each strategy should have a single, well-defined responsibility
267
+ 2. **Use meaningful names**: Strategy names should clearly indicate their purpose
268
+ 3. **Document configuration**: If your strategy accepts configuration, document all available options
269
+ 4. **Test your strategies**: Write tests for your custom strategies to ensure they work correctly
270
+ 5. **Consider composition**: Design strategies to work well together when used in combination
271
+
272
+
@@ -0,0 +1,29 @@
1
+ # Transaction Strategy
2
+
3
+ The `transaction` strategy wraps your action execution in a database transaction:
4
+
5
+ ```ruby
6
+ class TransferFunds
7
+ include Action
8
+
9
+ use :transaction
10
+
11
+ expects :from_account, :to_account, :amount
12
+
13
+ def call
14
+ from_account.withdraw!(amount)
15
+ to_account.deposit!(amount)
16
+ expose :transfer_id, SecureRandom.uuid
17
+ end
18
+ end
19
+ ```
20
+
21
+ **Important**: The transaction wraps the entire action execution, including:
22
+ - `before` hooks
23
+ - The main `call` method
24
+ - `after` hooks
25
+ - Success/failure callbacks (`on_success`, `on_failure`, etc.)
26
+
27
+ This means that if any part of the action (including hooks or callbacks) raises an exception or calls `fail!`, the entire transaction will be rolled back.
28
+
29
+ **Requirements**: Requires ActiveRecord to be available in your application.
data/docs/usage/using.md CHANGED
@@ -55,33 +55,3 @@ Sidekiq integration is NOT YET TESTED/NOT YET USED IN OUR APP, and naming will V
55
55
  * enqueue will not retry even if fails
56
56
  * enqueue! will go through normal sidekiq retries on any failure (including user-facing `fail!`)
57
57
  * Note implicit GlobalID support (if not serializable, will get ArgumentError at callsite)
58
-
59
-
60
- ### `.enqueue_all_in_background`
61
-
62
- In practice it's fairly common to need to enqueue a bunch of sidekiq jobs from a clock process.
63
-
64
- One approach is to define a class-level `.enqueue_all` method on your Action... but that ends up executing the enqueue_all logic directly from the clock process, which is undesirable.
65
-
66
-
67
- ::: danger ALPHA
68
- We are actively testing this pattern -- not yet certain we'll keep it past beta.
69
- :::
70
-
71
- Therefore we've added an `.enqueue_all_in_background` method that will automatically call your `.enqueue_all` _from a background job_ rather than directly on the active process.
72
-
73
- ```ruby
74
- class Foo
75
- include Action
76
-
77
- def self.enqueue_all
78
- SomeModel.some_scope.find_each do |record|
79
- enqueue(record:)
80
- end
81
- end
82
-
83
- ...
84
- end
85
-
86
- Foo.enqueue_all # works, but `SomeModel.some_scope.find_each` is executed in the current context
87
- Foo.enqueue_all_in_background # same, but runs in the background (via Action::Enqueueable::EnqueueAllWorker)
@@ -154,5 +154,5 @@ after hook
154
154
 
155
155
  A number of custom callback are available for you as well, if you want to take specific actions when a given Axn succeeds or fails. See the [Class Interface docs](/reference/class#callbacks) for details.
156
156
 
157
- ## Debugging
158
- Remember you can [enable debug logging](/reference/configuration.html#global-debug-logging) to print log lines before and after each action is executed.
157
+ ## Strategies
158
+ A number of [Strategies](/strategies), which are <abbr title="Don't Repeat Yourself">DRY</abbr>ed bits of commonly-used configuration, are available for your use as well.
@@ -109,6 +109,17 @@ module Action
109
109
  end
110
110
  end
111
111
 
112
+ def define_memoized_reader_method(field, &block)
113
+ define_method(field) do
114
+ ivar = :"@_memoized_reader_#{field}"
115
+ cached_val = instance_variable_get(ivar)
116
+ return cached_val if cached_val.present?
117
+
118
+ value = instance_exec(&block)
119
+ instance_variable_set(ivar, value)
120
+ end
121
+ end
122
+
112
123
  def _define_field_reader(field)
113
124
  # Allow local access to explicitly-expected fields -- even externally-expected needs to be available locally
114
125
  # (e.g. to allow success message callable to reference exposed fields)
@@ -120,7 +131,7 @@ module Action
120
131
  raise ArgumentError, "Model validation expects to be given a field ending in _id (given: #{field})" unless field.to_s.end_with?("_id")
121
132
  raise ArgumentError, "Failed to define model reader - #{name} is already defined" if method_defined?(name)
122
133
 
123
- define_method(name) do
134
+ define_memoized_reader_method(name) do
124
135
  Validators::ModelValidator.instance_for(field:, klass:, id: public_send(field))
125
136
  end
126
137
  end
@@ -82,22 +82,11 @@ module Action
82
82
  raise ArgumentError, "expects does not support duplicate sub-keys (i.e. `#{field}` is already defined)" if method_defined?(field)
83
83
 
84
84
  define_memoized_reader_method(field) do
85
- public_send(on).fetch(field)
85
+ Action::Validation::Subfields.extract(field, public_send(on))
86
86
  end
87
87
 
88
88
  _define_model_reader(field, validations[:model]) if validations.key?(:model)
89
89
  end
90
-
91
- def define_memoized_reader_method(field, &block)
92
- define_method(field) do
93
- ivar = :"@_memoized_reader_#{field}"
94
- cached_val = instance_variable_get(ivar)
95
- return cached_val if cached_val.present?
96
-
97
- value = instance_exec(&block)
98
- instance_variable_set(ivar, value)
99
- end
100
- end
101
90
  end
102
91
 
103
92
  module InstanceMethods
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Action
4
+ module UseStrategy
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def use(strategy_name, **config, &block)
9
+ strategy = Action::Strategies.all[strategy_name.to_sym]
10
+ raise StrategyNotFound, "Strategy #{strategy_name} not found" if strategy.blank?
11
+ raise ArgumentError, "Strategy #{strategy_name} does not support config" if config.any? && !strategy.respond_to?(:setup)
12
+
13
+ # Allow dynamic setup of strategy (i.e. dynamically define module before returning)
14
+ if strategy.respond_to?(:setup)
15
+ configured = strategy.setup(**config, &block)
16
+ raise ArgumentError, "Strategy #{strategy_name} setup method must return a module" unless configured.is_a?(Module)
17
+
18
+ strategy = configured
19
+ else
20
+ raise ArgumentError, "Strategy #{strategy_name} does not support config (define #setup method)" if config.any?
21
+ raise ArgumentError, "Strategy #{strategy_name} does not support blocks (define #setup method)" if block_given?
22
+ end
23
+
24
+ include strategy
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "enqueueable/via_sidekiq"
4
- require_relative "enqueueable/enqueue_all_in_background"
5
4
 
6
5
  module Action
7
6
  module Enqueueable
@@ -9,7 +8,6 @@ module Action
9
8
 
10
9
  included do
11
10
  include ViaSidekiq
12
- include EnqueueAllInBackground
13
11
  end
14
12
  end
15
13
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Action
4
+ class Strategies
5
+ module Transaction
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ raise NotImplementedError, "Transaction strategy requires ActiveRecord" unless defined?(ActiveRecord)
10
+
11
+ around do |hooked|
12
+ ActiveRecord::Base.transaction do
13
+ hooked.call
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Action
4
+ class StrategyNotFound < StandardError; end
5
+ class DuplicateStrategyError < StandardError; end
6
+
7
+ class Strategies
8
+ # rubocop:disable Style/ClassVars
9
+ class << self
10
+ def built_in
11
+ return @@built_in if defined?(@@built_in)
12
+
13
+ strategy_files = Dir[File.join(__dir__, "strategies", "*.rb")]
14
+ strategy_files.each { |file| require file }
15
+
16
+ constants = Action::Strategies.constants.map { |const| Action::Strategies.const_get(const) }
17
+ mods = constants.select { |const| const.is_a?(Module) }
18
+
19
+ @@built_in = mods.to_h { |mod| [mod.name.split("::").last.downcase.to_sym, mod] }
20
+ end
21
+
22
+ def register(name, strategy)
23
+ all # ensure built_in is initialized
24
+ key = name.to_sym
25
+ raise DuplicateStrategyError, "Strategy #{name} already registered" if @@strategies.key?(key)
26
+
27
+ @@strategies[key] = strategy
28
+ @@strategies
29
+ end
30
+
31
+ def all
32
+ @@strategies ||= built_in.dup
33
+ end
34
+
35
+ def clear!
36
+ @@strategies = built_in.dup
37
+ end
38
+
39
+ def find(name)
40
+ raise StrategyNotFound, "Strategy name cannot be nil" if name.nil?
41
+ raise StrategyNotFound, "Strategy name cannot be empty" if name.to_s.strip.empty?
42
+
43
+ all[name.to_sym] or raise StrategyNotFound, "Strategy '#{name}' not found"
44
+ end
45
+ end
46
+ # rubocop:enable Style/ClassVars
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ module Axn
6
+ module Testing
7
+ module SpecHelpers
8
+ def build_action(&block)
9
+ action = Class.new.send(:include, Action)
10
+ action.class_eval(&block) if block
11
+ action
12
+ end
13
+
14
+ def build_axn(**, &)
15
+ Axn::Factory.build(**, &)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.include Axn::Testing::SpecHelpers
23
+ end
data/lib/axn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Axn
4
- VERSION = "0.1.0-alpha.2.5.1.1"
4
+ VERSION = "0.1.0-alpha.2.5.2"
5
5
  end
data/lib/axn.rb CHANGED
@@ -18,11 +18,13 @@ require_relative "action/core/contract"
18
18
  require_relative "action/core/contract_for_subfields"
19
19
  require_relative "action/core/swallow_exceptions"
20
20
  require_relative "action/core/hoist_errors"
21
+ require_relative "action/core/use_strategy"
21
22
 
22
23
  require_relative "axn/factory"
23
24
 
24
25
  require_relative "action/attachable"
25
26
  require_relative "action/enqueueable"
27
+ require_relative "action/strategies"
26
28
 
27
29
  def Axn(callable, **) # rubocop:disable Naming/MethodName
28
30
  return callable if callable.is_a?(Class) && callable < Action
@@ -48,6 +50,8 @@ module Action
48
50
 
49
51
  include HoistErrors
50
52
 
53
+ include UseStrategy
54
+
51
55
  # --- Extensions ---
52
56
  include Attachable
53
57
  include Enqueueable
@@ -67,5 +71,3 @@ module Action
67
71
  end
68
72
  end
69
73
  end
70
-
71
- require "action/enqueueable/enqueue_all_worker"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: axn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.alpha.2.5.1.1
4
+ version: 0.1.0.pre.alpha.2.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kali Donovan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-06-26 00:00:00.000000000 Z
11
+ date: 2025-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -81,6 +81,8 @@ files:
81
81
  - docs/reference/class.md
82
82
  - docs/reference/configuration.md
83
83
  - docs/reference/instance.md
84
+ - docs/strategies/index.md
85
+ - docs/strategies/transaction.md
84
86
  - docs/usage/setup.md
85
87
  - docs/usage/using.md
86
88
  - docs/usage/writing.md
@@ -98,17 +100,19 @@ files:
98
100
  - lib/action/core/logging.rb
99
101
  - lib/action/core/swallow_exceptions.rb
100
102
  - lib/action/core/top_level_around_hook.rb
103
+ - lib/action/core/use_strategy.rb
101
104
  - lib/action/core/validation/fields.rb
102
105
  - lib/action/core/validation/subfields.rb
103
106
  - lib/action/core/validation/validators/model_validator.rb
104
107
  - lib/action/core/validation/validators/type_validator.rb
105
108
  - lib/action/core/validation/validators/validate_validator.rb
106
109
  - lib/action/enqueueable.rb
107
- - lib/action/enqueueable/enqueue_all_in_background.rb
108
- - lib/action/enqueueable/enqueue_all_worker.rb
109
110
  - lib/action/enqueueable/via_sidekiq.rb
111
+ - lib/action/strategies.rb
112
+ - lib/action/strategies/transaction.rb
110
113
  - lib/axn.rb
111
114
  - lib/axn/factory.rb
115
+ - lib/axn/testing/spec_helpers.rb
112
116
  - lib/axn/version.rb
113
117
  - package.json
114
118
  - yarn.lock
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Action
4
- module Enqueueable
5
- module EnqueueAllInBackground
6
- extend ActiveSupport::Concern
7
-
8
- module ClassMethods
9
- def enqueue_all_in_background
10
- raise NotImplementedError, "#{name} must implement a .enqueue_all method in order to use .enqueue_all_in_background" unless respond_to?(:enqueue_all)
11
-
12
- ::Action::Enqueueable::EnqueueAllWorker.enqueue(klass_name: name)
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # NOTE: this is a standalone worker for enqueueing all instances of a class.
4
- # Unlike the other files in the folder, it is NOT included in the Action stack.
5
-
6
- # Note it uses Axn-native enqueueing, so will automatically support additional
7
- # backends as they are added (initially, just Sidekiq)
8
-
9
- module Action
10
- module Enqueueable
11
- class EnqueueAllWorker
12
- include Action
13
-
14
- expects :klass_name, type: String
15
-
16
- def call
17
- klass_name.constantize.enqueue_all
18
- end
19
- end
20
- end
21
- end