axn 0.1.0.pre.alpha.2.7 → 0.1.0.pre.alpha.2.7.1

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: b128603df1eec45048f8656f01508a2e9a706e9acd92ce74813cac0bb038f550
4
- data.tar.gz: cfc86ffaadab4cc758546eab39992de2d7f3c89547007a2d88643b303d0edd4b
3
+ metadata.gz: 57d67670bb1cf60960aa2bb8234a5894a611801b69a89957057bfffd07ace8cd
4
+ data.tar.gz: 9e0025cbe4bc367e1351ea867d630b9fdb3d706547d676b9cd2162e8fda0ef38
5
5
  SHA512:
6
- metadata.gz: 2767343c37a0612a446482b52320d2ab85009af9e4094fffa0be31577bdf4a67e228f08307e31c0d182dbd3b944881f10af3c7e80d19a7d6c6f6f08a33294417
7
- data.tar.gz: fb5d3942ecbeb2e52f4f4376b5d1b90db696470704d39d1b2db55e6880956073f12f0213a13ad8a564ee2048ad76350bebb811ff90db125bf9724d2d31d3167a
6
+ metadata.gz: 70cc7c2851d95956278d43c746190dd5173ddda62a9a931ae9538374cf75b72523cc7f9b3524a6df6b8b8d57c969fb5510c07fad56b36312130ae86c59e48a15
7
+ data.tar.gz: f3f961781373a05284ddc54072baaf13998d235528110bf482c221e5f27d6142ab261516d8237bd0689d1161887eef6b567e8ecb4688d400a20ec32d1ae33837
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.2.7.1
4
+ * [FEAT] Implemented symbol method handler support for callbacks
5
+
3
6
  ## 0.1.0-alpha.2.7
4
7
  * [BREAKING] Replaced `messages` declaration with separate `success` and `error` calls
5
8
  * [BREAKING] Removed `rescues` method (use `error_from` for custom error messages; all exceptions now report to `on_exception` handlers)
@@ -7,7 +10,7 @@
7
10
  * [FEAT] Implemented conditional success message filtering as well
8
11
  * [FEAT] Added block support for `error` and `success`
9
12
  * [FEAT] `if:` now supports symbol predicates referencing instance methods (arity 0, 1, or keyword `exception:`). If the method accepts `exception:` it is passed as a keyword; else if it accepts one positional arg, it is passed positionally; otherwise it is called with no args. If the method is missing, the symbol falls back to constant lookup (e.g., `:ArgumentError`).
10
- * [FEAT] `success`/`error` and callbacks now accept symbol method names (e.g., `success :local_method`). Handlers can receive the exception via keyword (`exception:`) or single positional argument; otherwise they are called with no args.
13
+ * [FEAT] `success`/`error` now accept symbol method names (e.g., `success :local_method`). Handlers can receive the exception via keyword (`exception:`) or single positional argument; otherwise they are called with no args.
11
14
  * [BREAKING] Updated callback methods (`on_success`, `on_error`, `on_failure`, `on_exception`) to use consistent `if:` interface (matching messages)
12
15
  * [FEAT] Added `unless:` support to both `success`/`error` messages and callbacks (`on_success`, `on_error`, `on_failure`, `on_exception`)
13
16
 
@@ -13,7 +13,7 @@ Every `call` invocation on an Action will return an `Action::Result` instance, w
13
13
  | `elapsed_time` | Execution time in milliseconds (Float)
14
14
  | any `expose`d values | guaranteed to be set if `ok?` (since they have outgoing presence validations by default; any missing would have failed the action)
15
15
 
16
- NOTE: `success` and `error` (and so implicitly `message`) can be configured per-action via [the `messages` declaration](/reference/class#messages).
16
+ NOTE: `success` and `error` (and so implicitly `message`) can be configured per-action via [the `success` and `error` declarations](/reference/class#success-and-error).
17
17
 
18
18
  ### Clarification of exposed values
19
19
 
@@ -235,6 +235,16 @@ In addition to the [global exception handler](/reference/configuration#on-except
235
235
  * *Callbacks* (defined below) are executed _after_ the `call` -- exceptions or `fail!`s here will _not_ change `result.ok?`
236
236
  :::
237
237
 
238
+
239
+ **Note:** Symbol method handlers for all callback types follow the same argument pattern as [message handlers](#conditional-messages):
240
+ - If the method accepts `exception:` as a keyword, the exception is passed as a keyword
241
+ - If the method accepts one positional argument, the exception is passed positionally
242
+ - Otherwise, the method is called with no arguments
243
+
244
+ ::: warning
245
+ You cannot use both `if:` and `unless:` for the same callback - this will raise an `ArgumentError`.
246
+ :::
247
+
238
248
  ### `on_success`
239
249
 
240
250
  This is triggered after the Axn completes, if it was successful. Difference from `after`: if the given block raises an error, this WILL be reported to the global exception handler, but will NOT change `ok?` to false.
@@ -280,16 +290,14 @@ def transient_error?
280
290
  name == "temporary"
281
291
  end
282
292
 
283
- ::: warning
284
- You cannot use both `if:` and `unless:` for the same callback - this will raise an `ArgumentError`.
285
- :::
286
-
287
293
  on_exception(if: ->(e) { e.is_a?(ZeroDivisionError) }) do # [!code focus]
288
294
  # e.g. trigger a slack error
289
295
  end
290
296
  end
291
297
  ```
292
298
 
299
+
293
300
  If multiple `on_exception` handlers are provided, ALL that match the raised exception will be triggered in the order provided.
294
301
 
295
302
  The _global_ handler will be triggered _after_ all class-specific handlers.
303
+
@@ -2,7 +2,6 @@
2
2
 
3
3
  Somewhere at boot (e.g. `config/initializers/actions.rb` in Rails), you can call `Action.configure` to adjust a few global settings.
4
4
 
5
-
6
5
  ```ruby
7
6
  Action.configure do |c|
8
7
  c.log_level = :info
@@ -22,7 +21,6 @@ By default any swallowed errors are noted in the logs, but it's _highly recommen
22
21
 
23
22
  For example, if you're using Honeybadger this could look something like:
24
23
 
25
-
26
24
  ```ruby
27
25
  Action.configure do |c|
28
26
  c.on_exception = proc do |e, action:, context:|
@@ -56,13 +54,10 @@ A couple notes:
56
54
  * If your handler raises, the failure will _also_ be swallowed and logged
57
55
  * This handler is global across _all_ Axns. You can also specify per-Action handlers via [the class-level declaration](/reference/class#on-exception).
58
56
 
59
-
60
- ## `top_level_around_hook`
57
+ ## `wrap_with_trace` and `emit_metrics`
61
58
 
62
59
  If you're using an APM provider, observability can be greatly enhanced by adding automatic _tracing_ of Action calls and/or emitting count metrics after each call completes.
63
60
 
64
- ### Tracing and Metrics
65
-
66
61
  The framework provides two distinct hooks for observability:
67
62
 
68
63
  - **`wrap_with_trace`**: An around hook that wraps the entire action execution. You MUST call the provided block to execute the action.
@@ -92,7 +87,6 @@ A couple notes:
92
87
  * The `wrap_with_trace` hook is an around hook - you must call the provided block to execute the action
93
88
  * The `emit_metrics` hook is called after execution with the result - do not call any blocks
94
89
 
95
-
96
90
  ## `logger`
97
91
 
98
92
  Defaults to `Rails.logger`, if present, otherwise falls back to `Logger.new($stdout)`. But can be set to a custom logger as necessary.
@@ -115,6 +109,10 @@ For a practical example of this in practice, see [our 'memoization' recipe](/rec
115
109
 
116
110
  Sets the log level used when you call `log "Some message"` in your Action. Note this is read via a `log_level` class method, so you can easily use inheritance to support different log levels for different sets of actions.
117
111
 
112
+ ## `env`
113
+
114
+ Automatically detects the environment from `RACK_ENV` or `RAILS_ENV`, defaulting to `"development"`. This is used internally for conditional behavior (e.g., more verbose logging in non-production environments).
115
+
118
116
  ## Automatic Logging
119
117
 
120
118
  By default, every `action.call` will emit log lines when it is called and after it completes:
@@ -148,3 +146,37 @@ end
148
146
  ```
149
147
 
150
148
  The `auto_log` method supports inheritance, so subclasses will inherit the setting from their parent class unless explicitly overridden.
149
+
150
+ ## Complete Configuration Example
151
+
152
+ Here's a complete example showing all available configuration options:
153
+
154
+ ```ruby
155
+ Action.configure do |c|
156
+ # Logging
157
+ c.log_level = :info
158
+ c.logger = Rails.logger
159
+
160
+ # Exception handling
161
+ c.on_exception = proc do |e, action:, context:|
162
+ message = "[#{action.class.name}] Failing due to #{e.class.name}: #{e.message}"
163
+ Rails.logger.warn(message)
164
+ Honeybadger.notify(message, context: { axn_context: context })
165
+ end
166
+
167
+ # Observability
168
+ c.wrap_with_trace = proc do |resource, &action|
169
+ Datadog::Tracing.trace("Action", resource:) do
170
+ action.call
171
+ end
172
+ end
173
+
174
+ c.emit_metrics = proc do |resource, result|
175
+ Datadog::Metrics.increment("action.#{resource.underscore}", tags: { outcome: result.outcome })
176
+ Datadog::Metrics.histogram("action.duration", result.elapsed_time, tags: { resource: })
177
+ end
178
+
179
+ # Global includes
180
+ c.additional_includes = [MyCustomModule]
181
+ end
182
+ ```
@@ -63,7 +63,7 @@ NOTE: expects a single action call in the block -- if there are multiple calls,
63
63
 
64
64
  ::: tip Versus `call!`
65
65
  * If you just want to make sure your action fails if the subaction fails: call subaction via `call!` (any failures will raise, which will fail the parent).
66
- * Note this passes _child_ exception into _parent_ `messages :error` parsing.
66
+ * Note this passes _child_ exception into _parent_ `error` message parsing.
67
67
  * If you want _the child's_ `result.error` to become the _parent's_ `result.error` on failure, use `hoist_errors` + `call`
68
68
  :::
69
69
 
@@ -68,7 +68,7 @@ See [the reference doc](/reference/instance) for a few more handy helper methods
68
68
 
69
69
  The default `error` and `success` message strings ("Something went wrong" / "Action completed successfully", respectively) _are_ technically safe to show users, but you'll often want to set them to something more useful.
70
70
 
71
- There's a `messages` declaration for that -- you can set strings (most common) or a callable (note for the error case, if you give it a callable that expects a single argument, the exception that was raised will be passed in).
71
+ There are `success` and `error` declarations for that -- you can set strings (most common) or a callable (note for the error case, if you give it a callable that expects a single argument, the exception that was raised will be passed in).
72
72
 
73
73
  For instance, configuring the action like this:
74
74
 
@@ -79,8 +79,8 @@ class Foo
79
79
  expects :name, type: String
80
80
  exposes :meaning_of_life
81
81
 
82
- messages success: -> { "Revealed to #{name}: #{result.meaning_of_life}" }, # [!code focus:2]
83
- error: ->(e) { "No secret of life for you: #{e.message}" }
82
+ success { "Revealed to #{name}: #{result.meaning_of_life}" } # [!code focus:2]
83
+ error { |e| "No secret of life for you: #{e.message}" }
84
84
 
85
85
  def call
86
86
  fail! "Douglas already knows the meaning" if name == "Doug"
@@ -23,28 +23,29 @@ module Action
23
23
  end
24
24
 
25
25
  # ONLY raised exceptions (i.e. NOT fail!).
26
- def on_exception(**, &block) = _add_callback(:exception, **, block:)
26
+ def on_exception(handler = nil, **, &block) = _add_callback(:exception, handler:, **, block:)
27
27
 
28
28
  # ONLY raised on fail! (i.e. NOT unhandled exceptions).
29
- def on_failure(**, &block) = _add_callback(:failure, **, block:)
29
+ def on_failure(handler = nil, **, &block) = _add_callback(:failure, handler:, **, block:)
30
30
 
31
31
  # Handles both fail! and unhandled exceptions
32
- def on_error(**, &block) = _add_callback(:error, **, block:)
32
+ def on_error(handler = nil, **, &block) = _add_callback(:error, handler:, **, block:)
33
33
 
34
34
  # Executes when the action completes successfully (after all after hooks complete successfully)
35
35
  # Runs in child-first order (child handlers before parent handlers)
36
- def on_success(**, &block) = _add_callback(:success, **, block:)
36
+ def on_success(handler = nil, **, &block) = _add_callback(:success, handler:, **, block:)
37
37
 
38
38
  private
39
39
 
40
- def _add_callback(event_type, block:, **kwargs)
40
+ def _add_callback(event_type, handler: nil, block: nil, **kwargs)
41
41
  raise ArgumentError, "on_#{event_type} cannot be called with both :if and :unless" if kwargs.key?(:if) && kwargs.key?(:unless)
42
42
 
43
43
  condition = kwargs.key?(:if) ? kwargs[:if] : kwargs[:unless]
44
- raise ArgumentError, "on_#{event_type} must be called with a block" unless block
44
+ raise ArgumentError, "on_#{event_type} must be called with a block or symbol" unless block || handler
45
45
 
46
+ callback_handler = block || handler
46
47
  matcher = condition.nil? ? nil : Action::Core::Flow::Handlers::Matcher.new(condition, invert: kwargs.key?(:unless))
47
- entry = Action::Core::Flow::Handlers::CallbackHandler.new(matcher:, handler: block)
48
+ entry = Action::Core::Flow::Handlers::CallbackHandler.new(matcher:, handler: callback_handler)
48
49
  self._callbacks_registry = _callbacks_registry.register(event_type:, entry:)
49
50
  end
50
51
  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.7"
4
+ VERSION = "0.1.0-alpha.2.7.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
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.7
4
+ version: 0.1.0.pre.alpha.2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kali Donovan