circulator 2.1.2 → 2.1.3

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: 1a3d83bc194cf2440d13e088b1b23e72cf3ec89071ae9d046d575a7e5d1014c7
4
- data.tar.gz: 4c1afec2234a2edf3675048519aac13e4b64f2c8bbb08b98387603fc5f354ea8
3
+ metadata.gz: bdd2e4e17046d72b53d25ea469b8f037316abf74cb7a34fe010091ff4f8b5bfa
4
+ data.tar.gz: 879a93ab33bb08c07fb6239ce490c5d900272cbd3cd03a65c66516f95439499e
5
5
  SHA512:
6
- metadata.gz: a5bf023b56fe2f8352fbb2fadce2c8a29cb9a47cfd5b011c80c098646696b9dcd5735c2b027c8f4a126c285005f11c8b46e9c009ac8ad243df3e1bc8a5979523
7
- data.tar.gz: e4f99d8cd3e1cdbf87a15eb0b588ffc778f0fdf412c897fb5bf6796ff1295351fcf542c6ea80d1f883b1c3fa6afd817925ecddbda39ac1e16ffc9a59665754cb
6
+ metadata.gz: 910cd9755d9b9c02996d9d38329082733d019019151c19bc839663893e3523a6c64be9149485317bc7a0979f10223d15c4e0bb34ae0a9942f30d1c473acf8378
7
+ data.tar.gz: a98cad092d4da49cf93c38db6462489730061c38439f9825e2d2378ef58def38d3db243784c570f50697704442d271d8ac3aa0b1eddd5147e7f4a65b2a346c8a
data/CHANGELOG.md CHANGED
@@ -5,8 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [2.1.2] - 2025-10-17
8
+ ## [2.1.3] - 2025-10-27
9
+
10
+ ### Fixed
11
+
12
+ - Ignore nil states in predicate methods (73c74c2)
9
13
 
10
14
  ### Added
11
15
 
12
- - Hash-based allow_if for nested state dependencies (411a6b5)
16
+ - Attribute predicate methods and documentation (8f9cc33)
data/README.md CHANGED
@@ -6,7 +6,7 @@ A lightweight and flexible state machine implementation for Ruby that allows you
6
6
 
7
7
  - **Lightweight**: Minimal dependencies and simple implementation
8
8
  - **Flexible DSL**: Intuitive syntax for defining states and transitions
9
- - **Dynamic Method Generation**: Automatically creates helper methods for state transitions
9
+ - **Dynamic Method Generation**: Automatically creates action methods for transitions and predicate methods for state checks
10
10
  - **Conditional Transitions**: Support for guards and conditional logic
11
11
  - **Nested State Dependencies**: State machines can depend on the state of other attributes
12
12
  - **Transition Callbacks**: Execute code before, during, or after transitions
@@ -72,6 +72,37 @@ order.status_ship # => :shipped
72
72
  order.status_deliver # => :delivered
73
73
  ```
74
74
 
75
+ ### Generated Methods
76
+
77
+ Circulator automatically generates two types of helper methods for your state machines:
78
+
79
+ #### Action Methods
80
+
81
+ For each action defined in your state machine, Circulator creates a method that performs the transition:
82
+
83
+ ```ruby
84
+ order.status_process # Transitions from :pending to :processing
85
+ order.status_cancel # Transitions to :cancelled
86
+ ```
87
+
88
+ #### State Predicate Methods
89
+
90
+ For each state in your state machine, Circulator creates a predicate method to check the current state:
91
+
92
+ ```ruby
93
+ order.status = :pending
94
+
95
+ order.status_pending? # => true
96
+ order.status_processing? # => false
97
+ order.status_shipped? # => false
98
+
99
+ order.status_process
100
+ order.status_processing? # => true
101
+ order.status_pending? # => false
102
+ ```
103
+
104
+ These predicate methods work with both symbol and string values, automatically converting strings to symbols for comparison.
105
+
75
106
  ### Advanced Features
76
107
 
77
108
  #### Conditional Transitions with Guards
@@ -227,7 +258,7 @@ Circulator distinguishes itself from other Ruby state machine libraries through
227
258
  - **Minimal Magic**: Unlike AASM and state_machines, Circulator uses straightforward Ruby metaprogramming without complex DSL magic
228
259
  - **No Dependencies**: Works with plain Ruby objects without requiring Rails, ActiveRecord, or other frameworks
229
260
  - **Lightweight**: Smaller footprint compared to feature-heavy alternatives
230
- - **Clear Method Names**: Generated methods follow predictable naming patterns (`status_approve`, `priority_escalate`)
261
+ - **Clear Method Names**: Generated methods follow predictable naming patterns (`status_approve`, `status_pending?`)
231
262
  - **Flexible Architecture**: Easy to extend and customize for specific needs
232
263
 
233
264
  ### When to Use Circulator
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Circulator
4
- VERSION = "2.1.2"
4
+ VERSION = "2.1.3"
5
5
  end
data/lib/circulator.rb CHANGED
@@ -145,12 +145,38 @@ module Circulator
145
145
  Circulator.methodize_name(model)
146
146
  end
147
147
 
148
+ states = Set.new
148
149
  @flows.dig(model_key, attribute_name).transition_map.each do |action, transitions|
150
+ transitions.each do |from_state, transition_data|
151
+ states.add(from_state)
152
+ # Add the 'to' state if it's not a callable
153
+ unless transition_data[:to].respond_to?(:call)
154
+ states.add(transition_data[:to])
155
+ end
156
+ end
149
157
  define_flow_method(attribute_name:, action:, transitions:, object:, owner: flow_module)
150
158
  end
159
+
160
+ # Define predicate methods for each state (skip nil)
161
+ states.each do |state|
162
+ next if state.nil?
163
+ define_state_method(attribute_name:, state:, object:, owner: flow_module)
164
+ end
151
165
  end
152
166
  alias_method :circulator, :flow
153
167
 
168
+ def define_state_method(attribute_name:, state:, object:, owner:)
169
+ object_attribute_method = [object, attribute_name, state].compact.join("_") << "?"
170
+ return if owner.method_defined?(object_attribute_method)
171
+
172
+ owner.define_method(object_attribute_method) do
173
+ current_value = send(attribute_name)
174
+ # Convert to symbol for comparison if possible
175
+ current_value = current_value.to_sym if current_value.respond_to?(:to_sym)
176
+ current_value == state
177
+ end
178
+ end
179
+
154
180
  def define_flow_method(attribute_name:, action:, transitions:, object:, owner:)
155
181
  object_attribute_method = [object, attribute_name, action].compact.join("_")
156
182
  raise ArgumentError, "Method already defined: #{object_attribute_method}" if owner.method_defined?(object_attribute_method)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: circulator
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
@@ -46,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  requirements: []
49
- rubygems_version: 3.6.7
49
+ rubygems_version: 3.7.2
50
50
  specification_version: 4
51
51
  summary: Simple state machine
52
52
  test_files: []