cmdx 1.8.0 → 1.9.0

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +3 -3
  4. data/.cursor/prompts/llms.md +1 -3
  5. data/.irbrc +14 -2
  6. data/CHANGELOG.md +58 -45
  7. data/LLM.md +150 -53
  8. data/README.md +23 -85
  9. data/docs/.DS_Store +0 -0
  10. data/docs/assets/favicon.ico +0 -0
  11. data/docs/assets/favicon.svg +1 -0
  12. data/docs/attributes/coercions.md +12 -24
  13. data/docs/attributes/defaults.md +3 -16
  14. data/docs/attributes/definitions.md +16 -30
  15. data/docs/attributes/naming.md +3 -13
  16. data/docs/attributes/transformations.md +63 -0
  17. data/docs/attributes/validations.md +14 -33
  18. data/docs/basics/chain.md +14 -23
  19. data/docs/basics/context.md +13 -22
  20. data/docs/basics/execution.md +8 -26
  21. data/docs/basics/setup.md +8 -19
  22. data/docs/callbacks.md +19 -32
  23. data/docs/deprecation.md +8 -25
  24. data/docs/getting_started.md +101 -77
  25. data/docs/index.md +120 -0
  26. data/docs/internationalization.md +6 -18
  27. data/docs/interruptions/exceptions.md +10 -16
  28. data/docs/interruptions/faults.md +8 -25
  29. data/docs/interruptions/halt.md +12 -27
  30. data/docs/logging.md +7 -17
  31. data/docs/middlewares.md +13 -29
  32. data/docs/outcomes/result.md +21 -38
  33. data/docs/outcomes/states.md +8 -22
  34. data/docs/outcomes/statuses.md +10 -21
  35. data/docs/stylesheets/extra.css +42 -0
  36. data/docs/tips_and_tricks.md +7 -46
  37. data/docs/workflows.md +23 -38
  38. data/examples/active_record_query_tagging.md +46 -0
  39. data/examples/paper_trail_whatdunnit.md +39 -0
  40. data/lib/cmdx/attribute.rb +6 -5
  41. data/lib/cmdx/attribute_value.rb +31 -10
  42. data/lib/cmdx/callback_registry.rb +12 -2
  43. data/lib/cmdx/coercions/hash.rb +2 -0
  44. data/lib/cmdx/configuration.rb +10 -2
  45. data/lib/cmdx/deprecator.rb +3 -3
  46. data/lib/cmdx/executor.rb +93 -7
  47. data/lib/cmdx/pipeline.rb +4 -4
  48. data/lib/cmdx/railtie.rb +9 -0
  49. data/lib/cmdx/result.rb +10 -1
  50. data/lib/cmdx/task.rb +12 -7
  51. data/lib/cmdx/version.rb +1 -1
  52. data/lib/cmdx.rb +1 -0
  53. data/lib/generators/cmdx/templates/install.rb +9 -0
  54. data/mkdocs.yml +122 -0
  55. data/src/cmdx-dark-logo.png +0 -0
  56. data/src/cmdx-favicon.svg +1 -0
  57. data/src/cmdx-light-logo.png +0 -0
  58. data/src/cmdx-logo.svg +1 -0
  59. metadata +14 -3
  60. data/lib/cmdx/freezer.rb +0 -51
  61. data/src/cmdx-logo.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85aac46372133bca5764f5bfe14b1809e5a910aed2c449660d2d1123d79540f1
4
- data.tar.gz: 4e377e2bd36936a83f8f244ddea45e2af05277daecbf5e49db76f4cb38fe46fd
3
+ metadata.gz: 5ac9af727a0dd815dad8285e7e46d666e3f26f51eb03c3f1ec014c12e4af0e23
4
+ data.tar.gz: 8279a9ebcf5339fb281cd685cb0484b005f72b2605749f1418baea282be1afdf
5
5
  SHA512:
6
- metadata.gz: 38fec1c99ea4cb1cdd7639f65d85c76aeeac37fa1be3410344a2dda709e2a1f34cdf26d3b50cc7c7309a7234c756def0db8e2feb083972783018f6f4fc2fade1
7
- data.tar.gz: d08526598534fddb102297b1312304696bb4ffd6783d3549f7b4332cd83c8895cda84faeb1d427b14c8f60ae8a30839e983c1a649dcace3da1ec6a6978ab079d
6
+ metadata.gz: f97ef5703cacbfa7c51e4e513e214322c330750066e2420727d1bdc6469dac092b4f9b601291c8b0a721cba6bca863d22d4189bf10a8aa4b0ec53683f6598ccc
7
+ data.tar.gz: 3a1019a2f2db8088ec70821d51c5d13a10554f788a7732a70a8c14830cd9804fee354447e61dae3ca86fcf4a8a664932bdff5465a78256845d224870e78951ce
data/.DS_Store CHANGED
Binary file
@@ -3,10 +3,10 @@ You are a senior Ruby developer with expert knowledge of CMDx and writing docume
3
3
  Update the active tab using the following guidelines:
4
4
 
5
5
  - Follow best practices and implementation
6
- - Use a consistent professional voice
6
+ - Use a consistent warm, friendly and professional voice
7
7
  - Examples should be concise, non-repetitive, and realistic
8
8
  - Update any pre-existing documentation to match stated rules
9
9
  - Examples should not cross boundaries or focus
10
- - Docs must cover both typical use cases, including Invalid and error conditions
11
- - Use GitHub flavored markdown, including alerts to emphasize critical information (https://github.com/orgs/community/discussions/16925)
10
+ - Docs must cover both typical use cases, including invalid and error conditions
11
+ - Use mkdocs Admonitions to emphasize critical information (https://squidfunk.github.io/mkdocs-material/reference/admonitions/)
12
12
  - Optimize for LLM's including coding and AI agents
@@ -4,9 +4,7 @@ Process the following instructions in the order given:
4
4
  2. Append all files within `docs/**/*.md` into @LLM.md
5
5
  2a. Use order outlined in the table of contents of @README.md
6
6
  2b. Process one file at a time faster performance and improved accuracy
7
- 2c. Remove the table of contents from the chunk
8
- 2c. Remove the navigations below `---` from the chunk
9
- 2d. Wrap the chunk the files GitHub url the top and a spacer at the bottom like so:
7
+ 2c. Wrap the chunk the files GitHub url the top and a spacer at the bottom like so:
10
8
  ```
11
9
 
12
10
  ---
data/.irbrc CHANGED
@@ -2,5 +2,17 @@
2
2
 
3
3
  require "pp"
4
4
 
5
- # To reload the gem, you must exit and restart the IRB session
6
- require_relative "lib/cmdx" unless defined?(CMDx)
5
+ # rubocop:disable Style/MixinUsage
6
+ unless defined?(CMDx)
7
+ require_relative "lib/cmdx"
8
+
9
+ require_relative "spec/support/helpers/task_builders"
10
+ require_relative "spec/support/helpers/workflow_builders"
11
+ include CMDx::Testing::TaskBuilders
12
+ include CMDx::Testing::WorkflowBuilders
13
+ end
14
+ # rubocop:enable Style/MixinUsage
15
+
16
+ def reload!
17
+ exec("irb")
18
+ end
data/CHANGELOG.md CHANGED
@@ -4,27 +4,38 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [TODO]
8
- - Update exceptions with more info on how to fix the issue
9
- - Add trnasform option to attributes
10
- - Add option to output failure backtraces
11
- - Add durability (retries) to execution
12
- - N-retries (3 default)
13
- - Backoff strategy
14
- - On specific errors
15
-
16
7
  ## [UNRELEASED]
17
8
 
18
- - N/A
9
+ ## [1.9.0] - 2025-10-21
10
+
11
+ ### Added
12
+ - Added `transform` option to attributes
13
+ - Added option to output failure backtraces
14
+ - Added exception handling for non-bang methods
15
+ - Added durability with automatic retries to execution
16
+ - Added `to_h` hash coercion support
17
+ - Added comprehensive MkDocs configuration with material theme
18
+
19
+ ### Changed
20
+ - Improved performance of task settings setup
21
+ - Improved error messages for raised exceptions
22
+ - Improved inheritance of parent settings
23
+ - Cleaned halt backtrace frames for better readability
24
+
25
+ ### Removed
26
+ - Removed `Freezer` module and moved logic into executor `freeze_execution!` method
27
+ - Removed task parameter from callback signature
28
+ - Removed task and workflow arguments from conditional checks
29
+ - Removed chain persistence after execution in specs
19
30
 
20
31
  ## [1.8.0] - 2025-09-22
21
32
 
22
- ### Changes
23
- - Generalize locale values for fault `invalid` and `unspecified`
24
- - Nest attribute error messages under `error` key within metadata
25
- - Reordered logstash formatter keys
26
- - Improved already defined error message
27
- - Hash coercion for `nil` returns `{}`
33
+ ### Changed
34
+ - Generalized locale values for fault `invalid` and `unspecified`
35
+ - Nested attribute error messages under `error` key within metadata
36
+ - Reordered logstash formatter keys for consistency
37
+ - Improved error message for already defined items
38
+ - Changed hash coercion for `nil` to return `{}`
28
39
 
29
40
  ## [1.7.5] - 2025-09-10
30
41
 
@@ -42,69 +53,71 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
42
53
 
43
54
  ## [1.7.3] - 2025-09-03
44
55
 
45
- ### Changes
46
- - Return generic validation reason
47
- - Move validation full message string to `:full_message` within metadata
56
+ ### Changed
57
+ - Changed validation reasons to use generic values
58
+ - Moved validation full message string to `:full_message` key within metadata
48
59
 
49
60
  ## [1.7.2] - 2025-09-03
50
61
 
51
- ### Changes
52
- - Correlation ID is set before continuing to further steps
62
+ ### Changed
63
+ - Changed correlation ID to be set before continuing to further steps
53
64
 
54
65
  ## [1.7.1] - 2025-08-26
55
66
 
56
67
  ### Added
57
- - Yield result if block given to `execute` and `execute!` methods
68
+ - Added result yielding when block is given to `execute` and `execute!` methods
58
69
 
59
70
  ## [1.7.0] - 2025-08-25
60
71
 
61
72
  ### Added
62
- - Workflow generator
73
+ - Added workflow generator
63
74
 
64
- ### Changes
65
- - Port over `cmdx-parallel` changes
66
- - Port over `cmdx-i18n` changes
75
+ ### Changed
76
+ - Ported `cmdx-parallel` changes into core
77
+ - Ported `cmdx-i18n` changes into core
67
78
 
68
79
  ## [1.6.2] - 2025-08-24
69
80
 
70
- ### Changes
71
- - Prefix railtie I18n with `::` to play nice with `CMDx::I18n`
72
- - Use `cmdx-rspec` for matchers support
81
+ ### Changed
82
+ - Prefixed railtie I18n with `::` for compatibility with `CMDx::I18n`
83
+ - Changed to use `cmdx-rspec` for matchers support
73
84
 
74
85
  ## [1.6.1] - 2025-08-23
75
86
 
76
- ### Changes
77
- - Log task results before freezing
78
- - Rename `execute_tasks_sequentially` to `execute_tasks_in_sequence`
87
+ ### Changed
88
+ - Changed task results to be logged before freezing
89
+ - Renamed `execute_tasks_sequentially` to `execute_tasks_in_sequence`
79
90
 
80
91
  ## [1.6.0] - 2025-08-22
81
92
 
82
- ### Changes
83
- - Rename `Worker` class to `Executor`
84
- - Move workflow `work` logic into `Pipeline`
85
- - Add workflow task `:breakpoints`
93
+ ### Added
94
+ - Added workflow task `:breakpoints` support
95
+
96
+ ### Changed
97
+ - Renamed `Worker` class to `Executor`
98
+ - Moved workflow `work` logic into `Pipeline`
86
99
 
87
100
  ## [1.5.2] - 2025-08-22
88
101
 
89
- ### Changes
90
- - Rename workflow `execution_groups` attribute to `pipeline`
102
+ ### Changed
103
+ - Renamed workflow `execution_groups` attribute to `pipeline`
91
104
 
92
105
  ## [1.5.1] - 2025-08-21
93
106
 
94
- ### Changes
95
- - Prefix locale I18n with `::` to play nice with `CMDx::I18n`
96
- - Safe navigate length and numeric validators
97
- - Update railtie file path points to correct directory
107
+ ### Changed
108
+ - Prefixed locale I18n with `::` for compatibility with `CMDx::I18n`
109
+ - Added safe navigation to length and numeric validators
110
+ - Updated railtie file path to point to correct directory
98
111
 
99
112
  ## [1.5.0] - 2025-08-21
100
113
 
101
- ### Changes
102
- - BREAKING - Revamp CMDx for clarity, transparency, and higher performance
114
+ ### Changed
115
+ - **BREAKING**: Revamped CMDx for improved clarity, transparency, and higher performance
103
116
 
104
117
  ## [1.1.2] - 2025-07-20
105
118
 
106
119
  ### Changed
107
- - All items between versions `0.1.0` and `1.1.2` should be reviewed within its own tag
120
+ - All changes between versions `0.1.0` and `1.1.2` should be reviewed within their respective git tags
108
121
 
109
122
  ## [0.1.0] - 2025-03-07
110
123
 
data/LLM.md CHANGED
@@ -87,6 +87,45 @@ CMDx.configure do |config|
87
87
  end
88
88
  ```
89
89
 
90
+ ### Backtraces
91
+
92
+ Enable backtraces to be logged on any non-fault exceptions for improved debugging context. Run them through a cleaner to remove unwanted stack trace noise.
93
+
94
+ > [!NOTE]
95
+ > The `backtrace_cleaner` is set to `Rails.backtrace_cleaner.clean` in a Rails env by default.
96
+
97
+ ```ruby
98
+ CMDx.configure do |config|
99
+ # Truthy
100
+ config.backtrace = true
101
+
102
+ # Via callable (must respond to `call(backtrace)`)
103
+ config.backtrace_cleaner = AdvanceCleaner.new
104
+
105
+ # Via proc or lambda
106
+ config.backtrace_cleaner = ->(backtrace) { backtrace[0..5] }
107
+ end
108
+ ```
109
+
110
+ ### Exception Handlers
111
+
112
+ Use exception handlers are called on non-fault standard error based exceptions.
113
+
114
+ > [!TIP]
115
+ > Use exception handlers to send errors to your APM of choice.
116
+
117
+ ```ruby
118
+ CMDx.configure do |config|
119
+ # Via callable (must respond to `call(task, exception)`)
120
+ config.exception_handler = NewRelicReporter
121
+
122
+ # Via proc or lambda
123
+ config.exception_handler = proc do |task, exception|
124
+ APMService.report(exception, extra_data: { task: task.name, id: task.id })
125
+ end
126
+ end
127
+ ```
128
+
90
129
  ### Logging
91
130
 
92
131
  ```ruby
@@ -213,6 +252,8 @@ class GenerateInvoice < CMDx::Task
213
252
  # Global configuration overrides
214
253
  task_breakpoints: ["failed"], # Breakpoint override
215
254
  workflow_breakpoints: [], # Breakpoint override
255
+ backtrace: true, # Toggle backtrace
256
+ backtrace_cleaner: ->(bt) { bt[0..5] }, # Backtrace cleaner
216
257
  logger: CustomLogger.new($stdout), # Custom logger
217
258
 
218
259
  # Task configuration settings
@@ -220,7 +261,10 @@ class GenerateInvoice < CMDx::Task
220
261
  log_level: :info, # Log level override
221
262
  log_formatter: CMDx::LogFormatters::Json.new # Log formatter override
222
263
  tags: ["billing", "financial"], # Logging tags
223
- deprecated: true # Task deprecations
264
+ deprecated: true, # Task deprecations
265
+ retries: 3, # Non-fault exception retries
266
+ retry_on: [External::ApiError], # List of exceptions to retry on
267
+ retry_jitter: 1 # Space between retry iteration, eg: current retry num + 1
224
268
  )
225
269
 
226
270
  def work
@@ -229,8 +273,8 @@ class GenerateInvoice < CMDx::Task
229
273
  end
230
274
  ```
231
275
 
232
- > [!TIP]
233
- > Use task-level settings for tasks that require special handling, such as financial reporting, external API integrations, or critical system operations.
276
+ > [!IMPORTANT]
277
+ > Retries reuse the same context when executing its work. By default all `StandardErrors` will be retried if no `retry_on` option is passed.
234
278
 
235
279
  ### Registrations
236
280
 
@@ -1170,6 +1214,9 @@ result.reason #=> "[ActiveRecord::NotFoundError] record not found"
1170
1214
  result.cause #=> <ActiveRecord::NotFoundError>
1171
1215
  ```
1172
1216
 
1217
+ > [!NOTE]
1218
+ > The `exception_handler` setting only works with non-bang execution as it catches all exceptions preventing them from reaching your apps global error handler.
1219
+
1173
1220
  ### Bang execution
1174
1221
 
1175
1222
  The `execute!` method allows unhandled exceptions to propagate, enabling standard Ruby exception handling while respecting CMDx fault configuration.
@@ -1321,19 +1368,19 @@ result = BuildApplication.execute(version: "1.2.3")
1321
1368
 
1322
1369
  # Status-based handlers
1323
1370
  result
1324
- .on_success { |result| notify_deployment_ready(result) }
1325
- .on_failed { |result| handle_build_failure(result) }
1326
- .on_skipped { |result| log_skip_reason(result) }
1371
+ .handle_success { |result| notify_deployment_ready(result) }
1372
+ .handle_failed { |result| handle_build_failure(result) }
1373
+ .handle_skipped { |result| log_skip_reason(result) }
1327
1374
 
1328
1375
  # State-based handlers
1329
1376
  result
1330
- .on_complete { |result| update_build_status(result) }
1331
- .on_interrupted { |result| cleanup_partial_artifacts(result) }
1377
+ .handle_complete { |result| update_build_status(result) }
1378
+ .handle_interrupted { |result| cleanup_partial_artifacts(result) }
1332
1379
 
1333
1380
  # Outcome-based handlers
1334
1381
  result
1335
- .on_good { |result| increment_success_counter(result) }
1336
- .on_bad { |result| alert_operations_team(result) }
1382
+ .handle_good { |result| increment_success_counter(result) }
1383
+ .handle_bad { |result| alert_operations_team(result) }
1337
1384
  ```
1338
1385
 
1339
1386
  ## Pattern Matching
@@ -1455,9 +1502,9 @@ result = ProcessVideoUpload.execute
1455
1502
 
1456
1503
  # Individual state handlers
1457
1504
  result
1458
- .on_complete { |result| send_upload_notification(result) }
1459
- .on_interrupted { |result| cleanup_temp_files(result) }
1460
- .on_executed { |result| log_upload_metrics(result) }
1505
+ .handle_complete { |result| send_upload_notification(result) }
1506
+ .handle_interrupted { |result| cleanup_temp_files(result) }
1507
+ .handle_executed { |result| log_upload_metrics(result) }
1461
1508
  ```
1462
1509
 
1463
1510
  ---
@@ -1520,14 +1567,14 @@ result = ProcessNotification.execute
1520
1567
 
1521
1568
  # Individual status handlers
1522
1569
  result
1523
- .on_success { |result| mark_notification_sent(result) }
1524
- .on_skipped { |result| log_notification_skipped(result) }
1525
- .on_failed { |result| queue_retry_notification(result) }
1570
+ .handle_success { |result| mark_notification_sent(result) }
1571
+ .handle_skipped { |result| log_notification_skipped(result) }
1572
+ .handle_failed { |result| queue_retry_notification(result) }
1526
1573
 
1527
1574
  # Outcome-based handlers
1528
1575
  result
1529
- .on_good { |result| update_message_stats(result) }
1530
- .on_bad { |result| track_delivery_failure(result) }
1576
+ .handle_good { |result| update_message_stats(result) }
1577
+ .handle_bad { |result| track_delivery_failure(result) }
1531
1578
  ```
1532
1579
 
1533
1580
  ---
@@ -2419,6 +2466,80 @@ end
2419
2466
 
2420
2467
  ---
2421
2468
 
2469
+ url: https://github.com/drexed/cmdx/blob/main/docs/attributes/transformations.md
2470
+ ---
2471
+
2472
+ # Attributes - Transformations
2473
+
2474
+ Transformations allow you to modify attribute values after they are derived and coerced from their source but before any validations. This enables data normalization, formatting, and conditional processing within the attribute pipeline.
2475
+
2476
+ ## Declarations
2477
+
2478
+ ### Symbol References
2479
+
2480
+ Reference instance methods by symbol for dynamic value transformations:
2481
+
2482
+ ```ruby
2483
+ class ProcessAnalytics < CMDx::Task
2484
+ attribute :options, transform: :compact_blank
2485
+ end
2486
+ ```
2487
+
2488
+ ### Proc or Lambda
2489
+
2490
+ Use anonymous functions for dynamic value transformations:
2491
+
2492
+ ```ruby
2493
+ class CacheContent < CMDx::Task
2494
+ # Proc
2495
+ attribute :expire_hours, transform: proc { |v| v * 2 }
2496
+
2497
+ # Lambda
2498
+ attribute :compression, transform: ->(v) { v.to_s.upcase.strip[0..2] }
2499
+ end
2500
+ ```
2501
+
2502
+ ### Class or Module
2503
+
2504
+ Use any object that responds to `call` for reusable transformation logic:
2505
+
2506
+ ```ruby
2507
+ class EmailNormalizer
2508
+ def call(value)
2509
+ value.to_s.downcase.strip
2510
+ end
2511
+ end
2512
+
2513
+ class ProcessContacts < CMDx::Task
2514
+ # Class or Module
2515
+ attribute :email, transform: EmailNormalizer
2516
+
2517
+ # Instance
2518
+ attribute :email, transform: EmailNormalizer.new
2519
+ end
2520
+ ```
2521
+
2522
+ ## Validations
2523
+
2524
+ Transformed values are subject to the same validation rules as untransformed values, ensuring consistency and catching configuration errors early.
2525
+
2526
+ ```ruby
2527
+ class ScheduleBackup < CMDx::Task
2528
+ # Coercions
2529
+ attribute :retention_days, type: :integer, transform: proc { |v| v.clamp(1, 5) }
2530
+
2531
+ # Validations
2532
+ optional :frequency, transform: :downcase, inclusion: { in: %w[hourly daily weekly monthly] }
2533
+ end
2534
+ ```
2535
+
2536
+ ---
2537
+
2538
+ - **Prev:** [Attributes - Defaults](defaults.md)
2539
+ - **Next:** [Callbacks](../callbacks.md)
2540
+
2541
+ ---
2542
+
2422
2543
  url: https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
2423
2544
  ---
2424
2545
 
@@ -2487,7 +2608,7 @@ Use anonymous functions for inline callback logic:
2487
2608
  ```ruby
2488
2609
  class ProcessBooking < CMDx::Task
2489
2610
  # Proc
2490
- on_interrupted proc { |task| ReservationSystem.pause! }
2611
+ on_interrupted proc { ReservationSystem.pause! }
2491
2612
 
2492
2613
  # Lambda
2493
2614
  on_complete -> { ReservationSystem.resume! }
@@ -2534,10 +2655,10 @@ class ProcessBooking < CMDx::Task
2534
2655
  before_execution :notify_guest, if: :messaging_enabled?, unless: :messaging_blocked?
2535
2656
 
2536
2657
  # Proc
2537
- on_failure :increment_failure, if: ->(task) { Rails.env.production? && task.class.name.include?("Legacy") }
2658
+ on_failure :increment_failure, if: -> { Rails.env.production? && self.class.name.include?("Legacy") }
2538
2659
 
2539
2660
  # Lambda
2540
- on_success :ping_housekeeping, if: proc { |task| task.context.rooms_need_cleaning? }
2661
+ on_success :ping_housekeeping, if: proc { context.rooms_need_cleaning? }
2541
2662
 
2542
2663
  # Class or Module
2543
2664
  on_complete :send_confirmation, unless: MessagingPermissionCheck
@@ -2552,7 +2673,7 @@ class ProcessBooking < CMDx::Task
2552
2673
  private
2553
2674
 
2554
2675
  def messaging_enabled?
2555
- context.guest.messaging_preference.present?
2676
+ context.guest.messaging_preference == true
2556
2677
  end
2557
2678
 
2558
2679
  def messaging_blocked?
@@ -3076,7 +3197,7 @@ result = ProcessOldData.execute
3076
3197
  result.successful? #=> true
3077
3198
 
3078
3199
  # Ruby warning appears in stderr:
3079
- # [ProcessOldData] DEPRECATED: migrate to replacement or discontinue use
3200
+ # [ProcessOldData] DEPRECATED: migrate to a replacement or discontinue use
3080
3201
  ```
3081
3202
 
3082
3203
  ## Declarations
@@ -3227,10 +3348,10 @@ class OnboardingWorkflow < CMDx::Task
3227
3348
  task SendWelcomeEmail, if: :email_configured?, unless: :email_disabled?
3228
3349
 
3229
3350
  # Proc
3230
- task SendWelcomeEmail, if: ->(workflow) { Rails.env.production? && workflow.class.name.include?("Premium") }
3351
+ task SendWelcomeEmail, if: -> { Rails.env.production? && self.class.name.include?("Premium") }
3231
3352
 
3232
3353
  # Lambda
3233
- task SendWelcomeEmail, if: proc { |workflow| workflow.context.features_enabled? }
3354
+ task SendWelcomeEmail, if: proc { context.features_enabled? }
3234
3355
 
3235
3356
  # Class or Module
3236
3357
  task SendWelcomeEmail, unless: ContentAccessCheck
@@ -3244,7 +3365,7 @@ class OnboardingWorkflow < CMDx::Task
3244
3365
  private
3245
3366
 
3246
3367
  def email_configured?
3247
- context.user.email_address.present?
3368
+ context.user.email_address == true
3248
3369
  end
3249
3370
 
3250
3371
  def email_disabled?
@@ -3536,33 +3657,9 @@ class ConfigureCompany < CMDx::Task
3536
3657
  end
3537
3658
  ```
3538
3659
 
3539
- ## ActiveRecord Query Tagging
3540
-
3541
- Automatically tag SQL queries for better debugging:
3660
+ ## Advance Examples
3542
3661
 
3543
- ```ruby
3544
- # config/application.rb
3545
- config.active_record.query_log_tags_enabled = true
3546
- config.active_record.query_log_tags << :cmdx_task_class
3547
- config.active_record.query_log_tags << :cmdx_chain_id
3548
-
3549
- # app/tasks/application_task.rb
3550
- class ApplicationTask < CMDx::Task
3551
- before_execution :set_execution_context
3552
-
3553
- private
3554
-
3555
- def set_execution_context
3556
- # NOTE: This could easily be made into a middleware
3557
- ActiveSupport::ExecutionContext.set(
3558
- cmdx_task_class: self.class.name,
3559
- cmdx_chain_id: chain.id
3560
- )
3561
- end
3562
- end
3563
-
3564
- # SQL queries will now include comments like:
3565
- # /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
3566
- ```
3662
+ - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
3663
+ - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
3567
3664
 
3568
3665
  ---