state_machine 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|