state_machine 0.9.2 → 0.9.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.
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +8 -0
- data/Rakefile +1 -1
- data/examples/merb-rest/view_edit.html.erb +2 -2
- data/examples/merb-rest/view_index.html.erb +2 -2
- data/examples/merb-rest/view_show.html.erb +2 -2
- data/examples/rails-rest/view_edit.html.erb +2 -2
- data/examples/rails-rest/view_index.html.erb +2 -2
- data/examples/rails-rest/view_show.html.erb +2 -2
- data/lib/state_machine.rb +34 -0
- data/lib/state_machine/event.rb +17 -2
- data/lib/state_machine/event_collection.rb +1 -1
- data/lib/state_machine/integrations/active_model.rb +39 -15
- data/lib/state_machine/integrations/active_model/locale.rb +2 -2
- data/lib/state_machine/integrations/active_record.rb +15 -3
- data/lib/state_machine/integrations/active_record/locale.rb +16 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +16 -2
- data/lib/state_machine/machine.rb +53 -10
- data/lib/state_machine/machine_collection.rb +1 -1
- data/lib/state_machine/state.rb +12 -1
- data/lib/state_machine/transition.rb +50 -34
- data/test/files/en.yml +9 -0
- data/test/{classes → files}/switch.rb +0 -0
- data/test/functional/state_machine_test.rb +9 -0
- data/test/unit/event_collection_test.rb +5 -7
- data/test/unit/event_test.rb +51 -0
- data/test/unit/integrations/active_model_test.rb +80 -33
- data/test/unit/integrations/active_record_test.rb +89 -30
- data/test/unit/integrations/data_mapper_test.rb +25 -1
- data/test/unit/integrations/mongo_mapper_test.rb +40 -7
- data/test/unit/integrations/sequel_test.rb +25 -1
- data/test/unit/machine_collection_test.rb +1 -1
- data/test/unit/machine_test.rb +123 -4
- data/test/unit/state_test.rb +53 -0
- data/test/unit/transition_test.rb +20 -0
- metadata +4 -3
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
== master
|
2
2
|
|
3
|
+
== 0.9.3 / 2010-06-26
|
4
|
+
|
5
|
+
* Allow access to human state / event names in transitions and for the current state
|
6
|
+
* Use human state / event names in error messages
|
7
|
+
* Fix event names being used inconsistently in error messages
|
8
|
+
* Allow access to the humanized version of state / event names via human_state_name / human_state_event_name
|
9
|
+
* Allow MongoMapper 0.8.0+ scopes to be chainable
|
10
|
+
* Fix i18n deprecation warnings in ActiveModel / ActiveRecord 3.0.0.beta4
|
11
|
+
* Fix default error message translations overriding existing locales in ActiveModel / ActiveRecord
|
12
|
+
|
3
13
|
== 0.9.2 / 2010-05-24
|
4
14
|
|
5
15
|
* Fix MongoMapper integration failing in Ruby 1.9.2
|
data/README.rdoc
CHANGED
@@ -181,6 +181,7 @@ like so:
|
|
181
181
|
vehicle = Vehicle.new # => #<Vehicle:0xb7cf4eac @state="parked", @seatbelt_on=false>
|
182
182
|
vehicle.state # => "parked"
|
183
183
|
vehicle.state_name # => :parked
|
184
|
+
vehicle.human_state_name # => "parked"
|
184
185
|
vehicle.parked? # => true
|
185
186
|
vehicle.can_ignite? # => true
|
186
187
|
vehicle.ignite_transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
|
@@ -228,6 +229,13 @@ like so:
|
|
228
229
|
vehicle.alarm_state_name # => :active
|
229
230
|
|
230
231
|
vehicle.fire_events!(:ignite, :enable_alarm) # => StateMachine::InvalidTransition: Cannot run events in parallel: ignite, enable_alarm
|
232
|
+
|
233
|
+
# Human-friendly names can be accessed for states/events
|
234
|
+
Vehicle.human_state_name(:first_gear) # => "first gear"
|
235
|
+
Vehicle.human_alarm_state_name(:active) # => "active"
|
236
|
+
|
237
|
+
Vehicle.human_state_event_name(:shift_down) # => "shift down"
|
238
|
+
Vehicle.human_alarm_state_event_name(:enable_alarm) # => "enable alarm"
|
231
239
|
|
232
240
|
== Integrations
|
233
241
|
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rake/gempackagetask'
|
|
6
6
|
|
7
7
|
spec = Gem::Specification.new do |s|
|
8
8
|
s.name = 'state_machine'
|
9
|
-
s.version = '0.9.
|
9
|
+
s.version = '0.9.3'
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
11
|
s.summary = 'Adds support for creating state machines for attributes on any Ruby class'
|
12
12
|
s.description = s.summary
|
@@ -9,12 +9,12 @@
|
|
9
9
|
|
10
10
|
<p>
|
11
11
|
<%= label :state %><br />
|
12
|
-
<%= select :state_event, :selected => @user.state_event.to_s, :collection => @user.state_transitions, :value_method => :event, :text_method => :
|
12
|
+
<%= select :state_event, :selected => @user.state_event.to_s, :collection => @user.state_transitions, :value_method => :event, :text_method => :human_to_name, :prompt => @user.human_state_name %>
|
13
13
|
</p>
|
14
14
|
|
15
15
|
<p>
|
16
16
|
<%= label :access_state %><br />
|
17
|
-
<%= select :access_state_event, :selected => @user.access_state_event.to_s, :collection => @user.access_state_transitions, :value_method => :event, :text_method => :
|
17
|
+
<%= select :access_state_event, :selected => @user.access_state_event.to_s, :collection => @user.access_state_transitions, :value_method => :event, :text_method => :human_event, :prompt => "don't change" %>
|
18
18
|
</p>
|
19
19
|
|
20
20
|
<p><%= submit 'Update' %></p>
|
@@ -10,8 +10,8 @@
|
|
10
10
|
<% @users.each do |user| %>
|
11
11
|
<tr>
|
12
12
|
<td><%=h user.name %></td>
|
13
|
-
<td><%=h user.
|
14
|
-
<td><%=h user.
|
13
|
+
<td><%=h user.human_state_name %></td>
|
14
|
+
<td><%=h user.human_access_state_name %></td>
|
15
15
|
<td><%= link_to 'Show', resource(user) %></td>
|
16
16
|
<td><%= link_to 'Edit', resource(user, :edit) %></td>
|
17
17
|
</tr>
|
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
<p>
|
7
7
|
<b>State:</b>
|
8
|
-
<%=h @user.
|
8
|
+
<%=h @user.human_state_name %>
|
9
9
|
</p>
|
10
10
|
|
11
11
|
<p>
|
12
12
|
<b>Access State:</b>
|
13
|
-
<%=h @user.
|
13
|
+
<%=h @user.human_access_state_name %>
|
14
14
|
</p>
|
15
15
|
|
16
16
|
<%= link_to 'Edit', resource(@user, :edit) %> |
|
@@ -10,12 +10,12 @@
|
|
10
10
|
|
11
11
|
<p>
|
12
12
|
<%= f.label :state %><br />
|
13
|
-
<%= f.collection_select :state_event, @user.state_transitions, :event, :
|
13
|
+
<%= f.collection_select :state_event, @user.state_transitions, :event, :human_to_name, :include_blank => @user.human_state_name %>
|
14
14
|
</p>
|
15
15
|
|
16
16
|
<p>
|
17
17
|
<%= f.label :access_state %><br />
|
18
|
-
<%= f.collection_select :access_state_event, @user.access_state_transitions, :event, :
|
18
|
+
<%= f.collection_select :access_state_event, @user.access_state_transitions, :event, :human_event, :include_blank => "don't change" %>
|
19
19
|
</p>
|
20
20
|
|
21
21
|
<p><%= f.submit 'Update' %></p>
|
@@ -10,8 +10,8 @@
|
|
10
10
|
<% @users.each do |user| %>
|
11
11
|
<tr>
|
12
12
|
<td><%=h user.name %></td>
|
13
|
-
<td><%=h user.
|
14
|
-
<td><%=h user.
|
13
|
+
<td><%=h user.human_state_name %></td>
|
14
|
+
<td><%=h user.human_access_state_name %></td>
|
15
15
|
<td><%= link_to 'Show', user %></td>
|
16
16
|
<td><%= link_to 'Edit', edit_user_path(user) %></td>
|
17
17
|
</tr>
|
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
<p>
|
7
7
|
<b>State:</b>
|
8
|
-
<%=h @user.
|
8
|
+
<%=h @user.human_state_name %>
|
9
9
|
</p>
|
10
10
|
|
11
11
|
<p>
|
12
12
|
<b>Access State:</b>
|
13
|
-
<%=h @user.
|
13
|
+
<%=h @user.human_access_state_name %>
|
14
14
|
</p>
|
15
15
|
|
16
16
|
<%= link_to 'Edit', edit_user_path(@user) %> |
|
data/lib/state_machine.rb
CHANGED
@@ -90,6 +90,37 @@ module StateMachine
|
|
90
90
|
# end
|
91
91
|
# end
|
92
92
|
#
|
93
|
+
# == Class Methods
|
94
|
+
#
|
95
|
+
# The following class methods will be automatically generated by the
|
96
|
+
# state machine based on the *name* of the machine. Any existing methods
|
97
|
+
# will not be overwritten.
|
98
|
+
# * <tt>human_state_name(state)</tt> - Gets the humanized value for the
|
99
|
+
# given state. This may be generated by internationalization libraries if
|
100
|
+
# supported by the integration.
|
101
|
+
# * <tt>human_state_event_name(event)</tt> - Gets the humanized value for
|
102
|
+
# the given event. This may be generated by internationalization
|
103
|
+
# libraries if supported by the integration.
|
104
|
+
#
|
105
|
+
# For example,
|
106
|
+
#
|
107
|
+
# class Vehicle
|
108
|
+
# state_machine :state, :initial => :parked do
|
109
|
+
# event :ignite do
|
110
|
+
# transition :parked => :idling
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# event :shift_up do
|
114
|
+
# transition :idling => :first_gear
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# Vehicle.human_state_name(:parked) # => "parked"
|
120
|
+
# Vehicle.human_state_name(:first_gear) # => "first gear"
|
121
|
+
# Vehicle.human_state_event_name(:park) # => "park"
|
122
|
+
# Vehicle.human_state_event_name(:shift_up) # => "shift up"
|
123
|
+
#
|
93
124
|
# == Instance Methods
|
94
125
|
#
|
95
126
|
# The following instance methods will be automatically generated by the
|
@@ -100,6 +131,8 @@ module StateMachine
|
|
100
131
|
# * <tt>state?(name)</tt> - Checks the given state name against the current
|
101
132
|
# state. If the name is not a known state, then an ArgumentError is raised.
|
102
133
|
# * <tt>state_name</tt> - Gets the name of the state for the current value
|
134
|
+
# * <tt>human_state_name</tt> - Gets the human-readable name of the state
|
135
|
+
# for the current value
|
103
136
|
# * <tt>state_events</tt> - Gets the list of events that can be fired on
|
104
137
|
# the current object's state (uses the *unqualified* event names)
|
105
138
|
# * <tt>state_transitions(requirements = {})</tt> - Gets the list of possible
|
@@ -125,6 +158,7 @@ module StateMachine
|
|
125
158
|
# vehicle = Vehicle.new
|
126
159
|
# vehicle.state # => "parked"
|
127
160
|
# vehicle.state_name # => :parked
|
161
|
+
# vehicle.human_state_name # => "parked"
|
128
162
|
# vehicle.state?(:parked) # => true
|
129
163
|
#
|
130
164
|
# # Changing state
|
data/lib/state_machine/event.rb
CHANGED
@@ -24,6 +24,9 @@ module StateMachine
|
|
24
24
|
# The fully-qualified name of the event, scoped by the machine's namespace
|
25
25
|
attr_reader :qualified_name
|
26
26
|
|
27
|
+
# The human-readable name for the event
|
28
|
+
attr_writer :human_name
|
29
|
+
|
27
30
|
# The list of guards that determine what state this event transitions
|
28
31
|
# objects to when fired
|
29
32
|
attr_reader :guards
|
@@ -33,10 +36,16 @@ module StateMachine
|
|
33
36
|
attr_reader :known_states
|
34
37
|
|
35
38
|
# Creates a new event within the context of the given machine
|
36
|
-
|
39
|
+
#
|
40
|
+
# Configuration options:
|
41
|
+
# * <tt>:human_name</tt> - The human-readable version of this event's name
|
42
|
+
def initialize(machine, name, options = {}) #:nodoc:
|
43
|
+
assert_valid_keys(options, :human_name)
|
44
|
+
|
37
45
|
@machine = machine
|
38
46
|
@name = name
|
39
47
|
@qualified_name = machine.namespace ? :"#{name}_#{machine.namespace}" : name
|
48
|
+
@human_name = options[:human_name] || @name.to_s.tr('_', ' ')
|
40
49
|
@guards = []
|
41
50
|
@known_states = []
|
42
51
|
|
@@ -51,6 +60,12 @@ module StateMachine
|
|
51
60
|
@known_states = @known_states.dup
|
52
61
|
end
|
53
62
|
|
63
|
+
# Transforms the event name into a more human-readable format, such as
|
64
|
+
# "turn on" instead of "turn_on"
|
65
|
+
def human_name(klass = @machine.owner_class)
|
66
|
+
@human_name.is_a?(Proc) ? @human_name.call(self, klass) : @human_name
|
67
|
+
end
|
68
|
+
|
54
69
|
# Creates a new transition that determines what to change the current state
|
55
70
|
# to when this event fires.
|
56
71
|
#
|
@@ -191,7 +206,7 @@ module StateMachine
|
|
191
206
|
if transition = transition_for(object)
|
192
207
|
transition.perform(*args)
|
193
208
|
else
|
194
|
-
machine.invalidate(object, :state, :invalid_transition, [[:event,
|
209
|
+
machine.invalidate(object, :state, :invalid_transition, [[:event, human_name(object.class)]])
|
195
210
|
false
|
196
211
|
end
|
197
212
|
end
|
@@ -106,7 +106,7 @@ module StateMachine
|
|
106
106
|
if event = self[event_name.to_sym, :name]
|
107
107
|
event.transition_for(object) || begin
|
108
108
|
# No valid transition: invalidate
|
109
|
-
machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).
|
109
|
+
machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).human_name(object.class)]]) if invalidate
|
110
110
|
false
|
111
111
|
end
|
112
112
|
else
|
@@ -224,7 +224,7 @@ module StateMachine
|
|
224
224
|
|
225
225
|
if Object.const_defined?(:I18n)
|
226
226
|
locale = "#{File.dirname(__FILE__)}/active_model/locale.rb"
|
227
|
-
I18n.load_path
|
227
|
+
I18n.load_path.unshift(locale) unless I18n.load_path.include?(locale)
|
228
228
|
end
|
229
229
|
end
|
230
230
|
end
|
@@ -262,15 +262,8 @@ module StateMachine
|
|
262
262
|
def invalidate(object, attribute, message, values = [])
|
263
263
|
if supports_validations?
|
264
264
|
attribute = self.attribute(attribute)
|
265
|
-
ancestors = ancestors_for(object.class)
|
266
|
-
|
267
265
|
options = values.inject({}) do |options, (key, value)|
|
268
|
-
|
269
|
-
group = key.to_s.pluralize
|
270
|
-
translations = ancestors.map {|ancestor| :"#{ancestor.model_name.underscore}.#{name}.#{group}.#{value}"}
|
271
|
-
translations.concat([:"#{name}.#{group}.#{value}", :"#{group}.#{value}", value.to_s])
|
272
|
-
|
273
|
-
options[key] = I18n.translate(translations.shift, :default => translations, :scope => [i18n_scope, :state_machines])
|
266
|
+
options[key] = value
|
274
267
|
options
|
275
268
|
end
|
276
269
|
|
@@ -309,22 +302,40 @@ module StateMachine
|
|
309
302
|
defined?(::ActiveModel::Dirty) && owner_class <= ::ActiveModel::Dirty && object.respond_to?("#{self.attribute}_changed?")
|
310
303
|
end
|
311
304
|
|
305
|
+
# Gets the terminator to use for callbacks
|
306
|
+
def callback_terminator
|
307
|
+
@terminator ||= lambda {|result| result == false}
|
308
|
+
end
|
309
|
+
|
312
310
|
# Determines the base scope to use when looking up translations
|
313
311
|
def i18n_scope
|
314
312
|
owner_class.i18n_scope
|
315
313
|
end
|
316
314
|
|
315
|
+
# Translates the given key / value combo. Translation keys are looked
|
316
|
+
# up in the following order:
|
317
|
+
# * <tt>#{i18n_scope}.state_machines.#{model_name}.#{machine_name}.#{plural_key}.#{value}</tt>
|
318
|
+
# * <tt>#{i18n_scope}.state_machines.#{machine_name}.#{plural_key}.#{value}
|
319
|
+
# * <tt>#{i18n_scope}.state_machines.#{plural_key}.#{value}</tt>
|
320
|
+
#
|
321
|
+
# If no keys are found, then the humanized value will be the fallback.
|
322
|
+
def translate(klass, key, value)
|
323
|
+
ancestors = ancestors_for(klass)
|
324
|
+
group = key.to_s.pluralize
|
325
|
+
value = value ? value.to_s : 'nil'
|
326
|
+
|
327
|
+
# Generate all possible translation keys
|
328
|
+
translations = ancestors.map {|ancestor| :"#{ancestor.model_name.underscore}.#{name}.#{group}.#{value}"}
|
329
|
+
translations.concat([:"#{name}.#{group}.#{value}", :"#{group}.#{value}", value.humanize.downcase])
|
330
|
+
I18n.translate(translations.shift, :default => translations, :scope => [i18n_scope, :state_machines])
|
331
|
+
end
|
332
|
+
|
317
333
|
# Build a list of ancestors for the given class to use when
|
318
334
|
# determining which localization key to use for a particular string.
|
319
335
|
def ancestors_for(klass)
|
320
336
|
klass.lookup_ancestors
|
321
337
|
end
|
322
338
|
|
323
|
-
# Gets the terminator to use for callbacks
|
324
|
-
def callback_terminator
|
325
|
-
@terminator ||= lambda {|result| result == false}
|
326
|
-
end
|
327
|
-
|
328
339
|
# Adds the default callbacks for notifying ActiveModel observers
|
329
340
|
# before/after a transition has been performed.
|
330
341
|
def after_initialize
|
@@ -371,7 +382,20 @@ module StateMachine
|
|
371
382
|
end
|
372
383
|
end
|
373
384
|
|
374
|
-
|
385
|
+
# Configures new states with the built-in humanize scheme
|
386
|
+
def add_states(new_states)
|
387
|
+
super.each do |state|
|
388
|
+
state.human_name = lambda {|state, klass| translate(klass, :state, state.name)}
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Configures new event with the built-in humanize scheme
|
393
|
+
def add_events(new_events)
|
394
|
+
super.each do |event|
|
395
|
+
event.human_name = lambda {|event, klass| translate(klass, :event, event.name)}
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
375
399
|
# Notifies observers on the given object that a callback occurred
|
376
400
|
# involving the given transition. This will attempt to call the
|
377
401
|
# following methods on observers:
|
@@ -3,8 +3,8 @@
|
|
3
3
|
:errors => {
|
4
4
|
:messages => {
|
5
5
|
:invalid => StateMachine::Machine.default_messages[:invalid],
|
6
|
-
:invalid_event => StateMachine::Machine.default_messages[:invalid_event] % ['{
|
7
|
-
:invalid_transition => StateMachine::Machine.default_messages[:invalid_transition] % ['{
|
6
|
+
:invalid_event => StateMachine::Machine.default_messages[:invalid_event] % ['%{state}'],
|
7
|
+
:invalid_transition => StateMachine::Machine.default_messages[:invalid_transition] % ['%{event}']
|
8
8
|
}
|
9
9
|
}
|
10
10
|
}
|
@@ -276,8 +276,11 @@ module StateMachine
|
|
276
276
|
# errors:
|
277
277
|
# messages:
|
278
278
|
# invalid: "is invalid"
|
279
|
-
# invalid_event: "cannot transition when {
|
280
|
-
# invalid_transition: "cannot transition via {
|
279
|
+
# invalid_event: "cannot transition when %{state}"
|
280
|
+
# invalid_transition: "cannot transition via %{event}"
|
281
|
+
#
|
282
|
+
# Notice that the interpolation syntax is %{key} in Rails 3+. In Rails 2.x,
|
283
|
+
# the appropriate syntax is {{key}}.
|
281
284
|
#
|
282
285
|
# You can override these for a specific model like so:
|
283
286
|
#
|
@@ -332,7 +335,7 @@ module StateMachine
|
|
332
335
|
|
333
336
|
if Object.const_defined?(:I18n)
|
334
337
|
locale = "#{File.dirname(__FILE__)}/active_record/locale.rb"
|
335
|
-
I18n.load_path
|
338
|
+
I18n.load_path.unshift(locale) unless I18n.load_path.include?(locale)
|
336
339
|
end
|
337
340
|
end
|
338
341
|
|
@@ -371,6 +374,15 @@ module StateMachine
|
|
371
374
|
:activerecord
|
372
375
|
end
|
373
376
|
|
377
|
+
# Only allows translation of I18n is available
|
378
|
+
def translate(klass, key, value)
|
379
|
+
if Object.const_defined?(:I18n)
|
380
|
+
super
|
381
|
+
else
|
382
|
+
value ? value.to_s.humanize.downcase : 'nil'
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
374
386
|
# Attempts to look up a class's ancestors via:
|
375
387
|
# * #lookup_ancestors
|
376
388
|
# * #self_and_descendants_from_active_record
|
@@ -1,4 +1,20 @@
|
|
1
1
|
filename = "#{File.dirname(__FILE__)}/../active_model/locale.rb"
|
2
2
|
translations = eval(IO.read(filename), binding, filename)
|
3
3
|
translations[:en][:activerecord] = translations[:en].delete(:activemodel)
|
4
|
+
|
5
|
+
# Only ActiveRecord 2.3.5+ can pull i18n >= 0.1.3 from system-wide gems (and
|
6
|
+
# therefore possibly have I18n::VERSION available)
|
7
|
+
begin
|
8
|
+
require 'i18n/version'
|
9
|
+
rescue Exception => ex
|
10
|
+
end unless ::ActiveRecord::VERSION::MAJOR == 2 && (::ActiveRecord::VERSION::MINOR < 3 || ::ActiveRecord::VERSION::TINY < 5)
|
11
|
+
|
12
|
+
# Only i18n 0.4.0+ has the new %{key} syntax
|
13
|
+
if !defined?(I18n::VERSION) || I18n::VERSION < '0.4.0'
|
14
|
+
translations[:en][:activerecord][:errors][:messages].each do |key, message|
|
15
|
+
message.gsub!('%{', '{{')
|
16
|
+
message.gsub!('}', '}}')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
4
20
|
translations
|
@@ -226,6 +226,11 @@ module StateMachine
|
|
226
226
|
def callback_terminator
|
227
227
|
end
|
228
228
|
|
229
|
+
# Don't allow translations
|
230
|
+
def translate(klass, key, value)
|
231
|
+
value.to_s.humanize.downcase
|
232
|
+
end
|
233
|
+
|
229
234
|
# Defines an initialization hook into the owner class for setting the
|
230
235
|
# initial state of the machine *before* any attributes are set on the
|
231
236
|
# object
|
@@ -282,13 +287,22 @@ module StateMachine
|
|
282
287
|
# Creates a scope for finding records *with* a particular state or
|
283
288
|
# states for the attribute
|
284
289
|
def create_with_scope(name)
|
285
|
-
lambda {|
|
290
|
+
define_scope(name, lambda {|values| {:conditions => {attribute => {'$in' => values}}}})
|
286
291
|
end
|
287
292
|
|
288
293
|
# Creates a scope for finding records *without* a particular state or
|
289
294
|
# states for the attribute
|
290
295
|
def create_without_scope(name)
|
291
|
-
lambda {|
|
296
|
+
define_scope(name, lambda {|values| {:conditions => {attribute => {'$nin' => values}}}})
|
297
|
+
end
|
298
|
+
|
299
|
+
# Defines a new scope with the given name
|
300
|
+
def define_scope(name, scope)
|
301
|
+
if defined?(::MongoMapper::Version) && ::MongoMapper::Version >= '0.8.0'
|
302
|
+
lambda {|model, values| model.query.merge(model.query(scope.call(values)))}
|
303
|
+
else
|
304
|
+
lambda {|model, values| model.all(scope.call(values))}
|
305
|
+
end
|
292
306
|
end
|
293
307
|
end
|
294
308
|
end
|