micro-max-box 0.0.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 +7 -0
- data/aasm-6.0.0/CHANGELOG.md +497 -0
- data/aasm-6.0.0/LICENSE +20 -0
- data/aasm-6.0.0/README.md +1534 -0
- data/aasm-6.0.0/lib/aasm/aasm.rb +208 -0
- data/aasm-6.0.0/lib/aasm/base.rb +300 -0
- data/aasm-6.0.0/lib/aasm/configuration.rb +48 -0
- data/aasm-6.0.0/lib/aasm/core/event.rb +178 -0
- data/aasm-6.0.0/lib/aasm/core/invoker.rb +129 -0
- data/aasm-6.0.0/lib/aasm/core/invokers/base_invoker.rb +85 -0
- data/aasm-6.0.0/lib/aasm/core/invokers/class_invoker.rb +75 -0
- data/aasm-6.0.0/lib/aasm/core/invokers/literal_invoker.rb +90 -0
- data/aasm-6.0.0/lib/aasm/core/invokers/proc_invoker.rb +94 -0
- data/aasm-6.0.0/lib/aasm/core/state.rb +91 -0
- data/aasm-6.0.0/lib/aasm/core/transition.rb +83 -0
- data/aasm-6.0.0/lib/aasm/dsl_helper.rb +32 -0
- data/aasm-6.0.0/lib/aasm/errors.rb +22 -0
- data/aasm-6.0.0/lib/aasm/instance_base.rb +153 -0
- data/aasm-6.0.0/lib/aasm/localizer.rb +64 -0
- data/aasm-6.0.0/lib/aasm/minitest/allow_event.rb +13 -0
- data/aasm-6.0.0/lib/aasm/minitest/allow_transition_to.rb +13 -0
- data/aasm-6.0.0/lib/aasm/minitest/have_state.rb +13 -0
- data/aasm-6.0.0/lib/aasm/minitest/transition_from.rb +21 -0
- data/aasm-6.0.0/lib/aasm/minitest.rb +5 -0
- data/aasm-6.0.0/lib/aasm/minitest_spec.rb +15 -0
- data/aasm-6.0.0/lib/aasm/persistence/active_record_persistence.rb +174 -0
- data/aasm-6.0.0/lib/aasm/persistence/base.rb +89 -0
- data/aasm-6.0.0/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
- data/aasm-6.0.0/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
- data/aasm-6.0.0/lib/aasm/persistence/mongoid_persistence.rb +126 -0
- data/aasm-6.0.0/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
- data/aasm-6.0.0/lib/aasm/persistence/orm.rb +154 -0
- data/aasm-6.0.0/lib/aasm/persistence/plain_persistence.rb +26 -0
- data/aasm-6.0.0/lib/aasm/persistence/redis_persistence.rb +112 -0
- data/aasm-6.0.0/lib/aasm/persistence/sequel_persistence.rb +83 -0
- data/aasm-6.0.0/lib/aasm/persistence.rb +54 -0
- data/aasm-6.0.0/lib/aasm/rspec/allow_event.rb +26 -0
- data/aasm-6.0.0/lib/aasm/rspec/allow_transition_to.rb +26 -0
- data/aasm-6.0.0/lib/aasm/rspec/have_state.rb +22 -0
- data/aasm-6.0.0/lib/aasm/rspec/transition_from.rb +36 -0
- data/aasm-6.0.0/lib/aasm/rspec.rb +5 -0
- data/aasm-6.0.0/lib/aasm/state_machine.rb +53 -0
- data/aasm-6.0.0/lib/aasm/state_machine_store.rb +77 -0
- data/aasm-6.0.0/lib/aasm/version.rb +3 -0
- data/aasm-6.0.0/lib/aasm.rb +21 -0
- data/aasm-6.0.0/lib/generators/aasm/aasm_generator.rb +16 -0
- data/aasm-6.0.0/lib/generators/aasm/orm_helpers.rb +41 -0
- data/aasm-6.0.0/lib/generators/active_record/aasm_generator.rb +40 -0
- data/aasm-6.0.0/lib/generators/active_record/templates/migration.rb +8 -0
- data/aasm-6.0.0/lib/generators/active_record/templates/migration_existing.rb +5 -0
- data/aasm-6.0.0/lib/generators/mongoid/aasm_generator.rb +28 -0
- data/aasm-6.0.0/lib/generators/nobrainer/aasm_generator.rb +28 -0
- data/aasm-6.0.0/lib/motion-aasm.rb +37 -0
- data/micro-max-box.gemspec +12 -0
- metadata +94 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
require 'aasm/persistence/orm'
|
|
2
|
+
module AASM
|
|
3
|
+
module Persistence
|
|
4
|
+
module ActiveRecordPersistence
|
|
5
|
+
# This method:
|
|
6
|
+
#
|
|
7
|
+
# * extends the model with ClassMethods
|
|
8
|
+
# * includes InstanceMethods
|
|
9
|
+
#
|
|
10
|
+
# Adds
|
|
11
|
+
#
|
|
12
|
+
# after_initialize :aasm_ensure_initial_state
|
|
13
|
+
#
|
|
14
|
+
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
|
|
15
|
+
#
|
|
16
|
+
# class Foo < ActiveRecord::Base
|
|
17
|
+
# def aasm_write_state(state)
|
|
18
|
+
# "bar"
|
|
19
|
+
# end
|
|
20
|
+
# include AASM
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# class Foo < ActiveRecord::Base
|
|
24
|
+
# include AASM
|
|
25
|
+
# def aasm_write_state(state)
|
|
26
|
+
# "bar"
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
def self.included(base)
|
|
31
|
+
base.send(:include, AASM::Persistence::Base)
|
|
32
|
+
base.send(:include, AASM::Persistence::ORM)
|
|
33
|
+
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
|
34
|
+
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
|
|
35
|
+
|
|
36
|
+
base.after_initialize :aasm_ensure_initial_state
|
|
37
|
+
|
|
38
|
+
# ensure state is in the list of states
|
|
39
|
+
base.validate :aasm_validate_states
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
|
44
|
+
conditions = { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
|
45
|
+
class_eval do
|
|
46
|
+
scope scope_name, lambda { where(table_name => conditions) }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module InstanceMethods
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def aasm_execute_after_commit
|
|
56
|
+
begin
|
|
57
|
+
require 'after_commit_everywhere'
|
|
58
|
+
raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
|
|
59
|
+
|
|
60
|
+
self.extend ::AfterCommitEverywhere
|
|
61
|
+
after_commit do
|
|
62
|
+
yield
|
|
63
|
+
end
|
|
64
|
+
rescue LoadError
|
|
65
|
+
warn <<-MSG
|
|
66
|
+
[DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
|
|
67
|
+
Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
|
|
68
|
+
MSG
|
|
69
|
+
yield
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def aasm_raise_invalid_record
|
|
74
|
+
raise ActiveRecord::RecordInvalid.new(self)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def aasm_save
|
|
78
|
+
self.save
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def aasm_update_column(attribute_name, value)
|
|
82
|
+
self.class.unscoped.where(self.class.primary_key => self.id).update_all(attribute_name => value) == 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def aasm_read_attribute(name)
|
|
86
|
+
read_attribute(name)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def aasm_write_attribute(name, value)
|
|
90
|
+
write_attribute(name, value)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def aasm_transaction(requires_new, requires_lock)
|
|
94
|
+
self.class.transaction(:requires_new => requires_new) do
|
|
95
|
+
lock!(requires_lock) if requires_lock
|
|
96
|
+
yield
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def aasm_enum(name=:default)
|
|
101
|
+
case AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
|
102
|
+
when false then nil
|
|
103
|
+
when true then aasm_guess_enum_method(name)
|
|
104
|
+
when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
|
|
105
|
+
else AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def aasm_column_looks_like_enum(name=:default)
|
|
110
|
+
column_name = self.class.aasm(name).attribute_name.to_s
|
|
111
|
+
column = self.class.columns_hash[column_name]
|
|
112
|
+
raise NoMethodError.new("undefined method '#{column_name}' for #{self.class}") if column.nil?
|
|
113
|
+
column.type == :integer
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def aasm_guess_enum_method(name=:default)
|
|
117
|
+
self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def aasm_raw_attribute_value(state, name=:default)
|
|
121
|
+
if aasm_enum(name)
|
|
122
|
+
self.class.send(aasm_enum(name))[state]
|
|
123
|
+
else
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
|
129
|
+
# then the initial state gets populated after initialization
|
|
130
|
+
#
|
|
131
|
+
# foo = Foo.new
|
|
132
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
|
133
|
+
#
|
|
134
|
+
#
|
|
135
|
+
# foo = Foo.find(:first)
|
|
136
|
+
# foo.aasm_state # => 1
|
|
137
|
+
# foo.aasm_state = nil
|
|
138
|
+
# foo.valid?
|
|
139
|
+
# foo.aasm_state # => nil
|
|
140
|
+
#
|
|
141
|
+
def aasm_ensure_initial_state
|
|
142
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
143
|
+
# checking via respond_to? does not work in Rails <= 3
|
|
144
|
+
# if respond_to?(self.class.aasm(state_machine_name).attribute_name) && send(self.class.aasm(state_machine_name).attribute_name).blank? # Rails 4
|
|
145
|
+
if aasm_column_is_blank?(state_machine_name)
|
|
146
|
+
aasm(state_machine_name).enter_initial_state
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def aasm_column_is_blank?(state_machine_name)
|
|
152
|
+
attribute_name = self.class.aasm(state_machine_name).attribute_name
|
|
153
|
+
attribute_names.include?(attribute_name.to_s) &&
|
|
154
|
+
(send(attribute_name).respond_to?(:empty?) ? !!send(attribute_name).empty? : !send(attribute_name))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def aasm_validate_states
|
|
158
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
159
|
+
unless aasm_skipping_validations(state_machine_name)
|
|
160
|
+
if aasm_invalid_state?(state_machine_name)
|
|
161
|
+
self.errors.add(AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.column , "is invalid")
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def aasm_invalid_state?(state_machine_name)
|
|
168
|
+
aasm(state_machine_name).current_state && !aasm(state_machine_name).states.include?(aasm(state_machine_name).current_state)
|
|
169
|
+
end
|
|
170
|
+
end # InstanceMethods
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
end # Persistence
|
|
174
|
+
end # AASM
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module AASM
|
|
2
|
+
module Persistence
|
|
3
|
+
module Base
|
|
4
|
+
|
|
5
|
+
def self.included(base) #:nodoc:
|
|
6
|
+
base.extend ClassMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Returns the value of the aasm.attribute_name - called from <tt>aasm.current_state</tt>
|
|
10
|
+
#
|
|
11
|
+
# If it's a new record, and the aasm state column is blank it returns the initial state
|
|
12
|
+
# (example provided here for ActiveRecord, but it's true for Mongoid as well):
|
|
13
|
+
#
|
|
14
|
+
# class Foo < ActiveRecord::Base
|
|
15
|
+
# include AASM
|
|
16
|
+
# aasm :column => :status do
|
|
17
|
+
# state :opened
|
|
18
|
+
# state :closed
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# foo = Foo.new
|
|
23
|
+
# foo.current_state # => :opened
|
|
24
|
+
# foo.close
|
|
25
|
+
# foo.current_state # => :closed
|
|
26
|
+
#
|
|
27
|
+
# foo = Foo.find(1)
|
|
28
|
+
# foo.current_state # => :opened
|
|
29
|
+
# foo.aasm_state = nil
|
|
30
|
+
# foo.current_state # => nil
|
|
31
|
+
#
|
|
32
|
+
# NOTE: intended to be called from an event
|
|
33
|
+
#
|
|
34
|
+
# This allows for nil aasm states - be sure to add validation to your model
|
|
35
|
+
def aasm_read_state(name=:default)
|
|
36
|
+
state = send(self.class.aasm(name).attribute_name)
|
|
37
|
+
if !state || state.empty?
|
|
38
|
+
aasm_new_record? ? aasm(name).determine_state_name(self.class.aasm(name).initial_state) : nil
|
|
39
|
+
else
|
|
40
|
+
state.to_sym
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def aasm_new_record?
|
|
45
|
+
new_record?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module ClassMethods
|
|
49
|
+
def aasm_column(attribute_name=nil)
|
|
50
|
+
warn "[DEPRECATION] aasm_column is deprecated. Use aasm.attribute_name instead"
|
|
51
|
+
aasm.attribute_name(attribute_name)
|
|
52
|
+
end
|
|
53
|
+
end # ClassMethods
|
|
54
|
+
|
|
55
|
+
end # Base
|
|
56
|
+
end # Persistence
|
|
57
|
+
|
|
58
|
+
class Base
|
|
59
|
+
# make sure to create a (named) scope for each state
|
|
60
|
+
def state_with_scope(*args)
|
|
61
|
+
names = state_without_scope(*args)
|
|
62
|
+
names.each do |name|
|
|
63
|
+
create_scopes(name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
alias_method :state_without_scope, :state
|
|
67
|
+
alias_method :state, :state_with_scope
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def create_scope?(name)
|
|
72
|
+
@state_machine.config.create_scopes && !@klass.respond_to?(name) && @klass.respond_to?(:aasm_create_scope)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def create_scope(name)
|
|
76
|
+
@klass.aasm_create_scope(@name, name) if create_scope?(name)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def create_scopes(name)
|
|
80
|
+
if namespace?
|
|
81
|
+
# Create default scopes even when namespace? for backward compatibility
|
|
82
|
+
namepaced_name = "#{namespace}_#{name}"
|
|
83
|
+
create_scope(namepaced_name)
|
|
84
|
+
end
|
|
85
|
+
create_scope(name)
|
|
86
|
+
end
|
|
87
|
+
end # Base
|
|
88
|
+
|
|
89
|
+
end # AASM
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module AASM
|
|
2
|
+
module Persistence
|
|
3
|
+
module CoreDataQueryPersistence
|
|
4
|
+
# This method:
|
|
5
|
+
#
|
|
6
|
+
# * extends the model with ClassMethods
|
|
7
|
+
# * includes InstanceMethods
|
|
8
|
+
#
|
|
9
|
+
# Adds
|
|
10
|
+
#
|
|
11
|
+
# after_initialize :aasm_ensure_initial_state
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
def self.included(base)
|
|
15
|
+
base.send(:include, AASM::Persistence::Base)
|
|
16
|
+
base.send(:include, AASM::Persistence::CoreDataQueryPersistence::InstanceMethods)
|
|
17
|
+
base.extend AASM::Persistence::CoreDataQueryPersistence::ClassMethods
|
|
18
|
+
|
|
19
|
+
base.after_initialize :aasm_ensure_initial_state
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
|
24
|
+
scope(scope_name.to_sym, lambda { where(aasm(state_machine_name).attribute_name.to_sym).eq(scope_name.to_s) })
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module InstanceMethods
|
|
29
|
+
|
|
30
|
+
# Writes <tt>state</tt> to the state column and persists it to the database
|
|
31
|
+
# using update_attribute (which bypasses validation)
|
|
32
|
+
#
|
|
33
|
+
# foo = Foo.find(1)
|
|
34
|
+
# foo.aasm.current_state # => :opened
|
|
35
|
+
# foo.close!
|
|
36
|
+
# foo.aasm.current_state # => :closed
|
|
37
|
+
# Foo.find(1).aasm.current_state # => :closed
|
|
38
|
+
#
|
|
39
|
+
# NOTE: intended to be called from an event
|
|
40
|
+
def aasm_write_state(state, name=:default)
|
|
41
|
+
raise "Cowardly refusing to save the current CoreDataQuery context"
|
|
42
|
+
aasm_write_state_without_persistence(state, name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
|
46
|
+
#
|
|
47
|
+
# foo = Foo.find(1)
|
|
48
|
+
# foo.aasm.current_state # => :opened
|
|
49
|
+
# foo.close
|
|
50
|
+
# foo.aasm.current_state # => :closed
|
|
51
|
+
# Foo.find(1).aasm.current_state # => :opened
|
|
52
|
+
# foo.save
|
|
53
|
+
# foo.aasm.current_state # => :closed
|
|
54
|
+
# Foo.find(1).aasm.current_state # => :closed
|
|
55
|
+
#
|
|
56
|
+
# NOTE: intended to be called from an event
|
|
57
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
|
58
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
|
64
|
+
# that the initial state gets populated before validation on create
|
|
65
|
+
#
|
|
66
|
+
# foo = Foo.new
|
|
67
|
+
# foo.aasm_state # => nil
|
|
68
|
+
# foo.valid?
|
|
69
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
|
70
|
+
#
|
|
71
|
+
#
|
|
72
|
+
# foo = Foo.find(:first)
|
|
73
|
+
# foo.aasm_state # => 1
|
|
74
|
+
# foo.aasm_state = nil
|
|
75
|
+
# foo.valid?
|
|
76
|
+
# foo.aasm_state # => nil
|
|
77
|
+
#
|
|
78
|
+
def aasm_ensure_initial_state
|
|
79
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
80
|
+
next if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
|
|
81
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end # InstanceMethods
|
|
85
|
+
|
|
86
|
+
# module NamedScopeMethods
|
|
87
|
+
# def aasm_state_with_named_scope name, options = {}
|
|
88
|
+
# aasm_state_without_named_scope name, options
|
|
89
|
+
# self.named_scope name, :conditions => { "#{table_name}.#{self.aasm.attribute_name}" => name.to_s} unless self.respond_to?(name)
|
|
90
|
+
# end
|
|
91
|
+
# end
|
|
92
|
+
end
|
|
93
|
+
end # Persistence
|
|
94
|
+
end # AASM
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module AASM
|
|
2
|
+
module Persistence
|
|
3
|
+
module DynamoidPersistence
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.send(:include, AASM::Persistence::Base)
|
|
6
|
+
base.send(:include, AASM::Persistence::DynamoidPersistence::InstanceMethods)
|
|
7
|
+
|
|
8
|
+
base.after_initialize :aasm_ensure_initial_state
|
|
9
|
+
|
|
10
|
+
# Because Dynamoid only use define_method to add attribute assignment method in Class.
|
|
11
|
+
#
|
|
12
|
+
# In AASM::Base.initialize, it redefines and calls super in this method without superclass method.
|
|
13
|
+
# We override method_missing to solve this problem.
|
|
14
|
+
#
|
|
15
|
+
base.class_eval %Q(
|
|
16
|
+
def method_missing(method_name, *arguments, &block)
|
|
17
|
+
if (AASM::StateMachineStore.fetch(self.class, true).machine_names.map { |state_machine_name| self.class.aasm(state_machine_name).attribute_name.to_s + "=" }).include? method_name.to_s
|
|
18
|
+
attribute_name = method_name.to_s.gsub("=", '')
|
|
19
|
+
write_attribute(attribute_name.to_sym, *arguments)
|
|
20
|
+
else
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module InstanceMethods
|
|
28
|
+
|
|
29
|
+
# Writes <tt>state</tt> to the state column and persists it to the database
|
|
30
|
+
# using update_attribute (which bypasses validation)
|
|
31
|
+
#
|
|
32
|
+
# foo = Foo.find(1)
|
|
33
|
+
# foo.aasm.current_state # => :opened
|
|
34
|
+
# foo.close!
|
|
35
|
+
# foo.aasm.current_state # => :closed
|
|
36
|
+
# Foo.find(1).aasm.current_state # => :closed
|
|
37
|
+
#
|
|
38
|
+
# NOTE: intended to be called from an event
|
|
39
|
+
def aasm_write_state(state, name=:default)
|
|
40
|
+
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
|
41
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
|
42
|
+
|
|
43
|
+
unless self.save(:validate => false)
|
|
44
|
+
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
|
52
|
+
#
|
|
53
|
+
# foo = Foo.find(1)
|
|
54
|
+
# foo.aasm.current_state # => :opened
|
|
55
|
+
# foo.close
|
|
56
|
+
# foo.aasm.current_state # => :closed
|
|
57
|
+
# Foo.find(1).aasm.current_state # => :opened
|
|
58
|
+
# foo.save
|
|
59
|
+
# foo.aasm.current_state # => :closed
|
|
60
|
+
# Foo.find(1).aasm.current_state # => :closed
|
|
61
|
+
#
|
|
62
|
+
# NOTE: intended to be called from an event
|
|
63
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
|
64
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
|
70
|
+
# that the initial state gets populated before validation on create
|
|
71
|
+
#
|
|
72
|
+
# foo = Foo.new
|
|
73
|
+
# foo.aasm_state # => nil
|
|
74
|
+
# foo.valid?
|
|
75
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
|
76
|
+
#
|
|
77
|
+
#
|
|
78
|
+
# foo = Foo.find(:first)
|
|
79
|
+
# foo.aasm_state # => 1
|
|
80
|
+
# foo.aasm_state = nil
|
|
81
|
+
# foo.valid?
|
|
82
|
+
# foo.aasm_state # => nil
|
|
83
|
+
#
|
|
84
|
+
def aasm_ensure_initial_state
|
|
85
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
86
|
+
aasm(state_machine_name).enter_initial_state if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end # InstanceMethods
|
|
90
|
+
end
|
|
91
|
+
end # Persistence
|
|
92
|
+
end # AASM
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require 'aasm/persistence/orm'
|
|
2
|
+
module AASM
|
|
3
|
+
module Persistence
|
|
4
|
+
module MongoidPersistence
|
|
5
|
+
# This method:
|
|
6
|
+
#
|
|
7
|
+
# * extends the model with ClassMethods
|
|
8
|
+
# * includes InstanceMethods
|
|
9
|
+
#
|
|
10
|
+
# Adds
|
|
11
|
+
#
|
|
12
|
+
# before_validation :aasm_ensure_initial_state
|
|
13
|
+
#
|
|
14
|
+
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
|
|
15
|
+
#
|
|
16
|
+
# class Foo
|
|
17
|
+
# include Mongoid::Document
|
|
18
|
+
# def aasm_write_state(state)
|
|
19
|
+
# "bar"
|
|
20
|
+
# end
|
|
21
|
+
# include AASM
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# class Foo
|
|
25
|
+
# include Mongoid::Document
|
|
26
|
+
# include AASM
|
|
27
|
+
# def aasm_write_state(state)
|
|
28
|
+
# "bar"
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
def self.included(base)
|
|
33
|
+
base.send(:include, AASM::Persistence::Base)
|
|
34
|
+
base.send(:include, AASM::Persistence::ORM)
|
|
35
|
+
base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
|
|
36
|
+
base.extend AASM::Persistence::MongoidPersistence::ClassMethods
|
|
37
|
+
|
|
38
|
+
base.after_initialize :aasm_ensure_initial_state
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module ClassMethods
|
|
42
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
|
43
|
+
scope_options = lambda {
|
|
44
|
+
send(
|
|
45
|
+
:where,
|
|
46
|
+
{ aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s }
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
send(:scope, scope_name, scope_options)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module InstanceMethods
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def aasm_save
|
|
58
|
+
self.save
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def aasm_raise_invalid_record
|
|
62
|
+
raise Mongoid::Errors::Validations.new(self)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def aasm_supports_transactions?
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def aasm_update_column(attribute_name, value)
|
|
70
|
+
if Mongoid::VERSION.to_f >= 4
|
|
71
|
+
set(Hash[attribute_name, value])
|
|
72
|
+
else
|
|
73
|
+
set(attribute_name, value)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def aasm_read_attribute(name)
|
|
80
|
+
read_attribute(name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def aasm_write_attribute(name, value)
|
|
84
|
+
write_attribute(name, value)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
|
88
|
+
# that the initial state gets populated before validation on create
|
|
89
|
+
#
|
|
90
|
+
# foo = Foo.new
|
|
91
|
+
# foo.aasm_state # => nil
|
|
92
|
+
# foo.valid?
|
|
93
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
|
94
|
+
#
|
|
95
|
+
#
|
|
96
|
+
# foo = Foo.find(:first)
|
|
97
|
+
# foo.aasm_state # => 1
|
|
98
|
+
# foo.aasm_state = nil
|
|
99
|
+
# foo.valid?
|
|
100
|
+
# foo.aasm_state # => nil
|
|
101
|
+
#
|
|
102
|
+
def aasm_ensure_initial_state
|
|
103
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
104
|
+
attribute_name = self.class.aasm(state_machine_name).attribute_name.to_s
|
|
105
|
+
# Do not load initial state when object attributes are not loaded,
|
|
106
|
+
# mongoid has_many relationship does not load child object attributes when
|
|
107
|
+
# only ids are loaded, for example parent.child_ids will not load child object attributes.
|
|
108
|
+
# This feature is introduced in mongoid > 4.
|
|
109
|
+
if attribute_names.include?(attribute_name) && !attributes[attribute_name] || attributes[attribute_name].empty?
|
|
110
|
+
# attribute_missing? is defined in mongoid > 4
|
|
111
|
+
return if Mongoid::VERSION.to_f >= 4 && attribute_missing?(attribute_name)
|
|
112
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end # InstanceMethods
|
|
117
|
+
|
|
118
|
+
# module NamedScopeMethods
|
|
119
|
+
# def aasm_state_with_named_scope name, options = {}
|
|
120
|
+
# aasm_state_without_named_scope name, options
|
|
121
|
+
# self.named_scope name, :conditions => { "#{table_name}.#{self.aasm.attribute_name}" => name.to_s} unless self.respond_to?(name)
|
|
122
|
+
# end
|
|
123
|
+
# end
|
|
124
|
+
end
|
|
125
|
+
end # Persistence
|
|
126
|
+
end # AASM
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'aasm/persistence/orm'
|
|
2
|
+
module AASM
|
|
3
|
+
module Persistence
|
|
4
|
+
module NoBrainerPersistence
|
|
5
|
+
# This method:
|
|
6
|
+
#
|
|
7
|
+
# * extends the model with ClassMethods
|
|
8
|
+
# * includes InstanceMethods
|
|
9
|
+
#
|
|
10
|
+
# Adds
|
|
11
|
+
#
|
|
12
|
+
# before_validation :aasm_ensure_initial_state
|
|
13
|
+
#
|
|
14
|
+
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
|
|
15
|
+
#
|
|
16
|
+
# class Foo
|
|
17
|
+
# include NoBrainer::Document
|
|
18
|
+
# def aasm_write_state(state)
|
|
19
|
+
# "bar"
|
|
20
|
+
# end
|
|
21
|
+
# include AASM
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# class Foo
|
|
25
|
+
# include NoBrainer::Document
|
|
26
|
+
# include AASM
|
|
27
|
+
# def aasm_write_state(state)
|
|
28
|
+
# "bar"
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
def self.included(base)
|
|
33
|
+
base.send(:include, AASM::Persistence::Base)
|
|
34
|
+
base.send(:include, AASM::Persistence::ORM)
|
|
35
|
+
base.send(:include, AASM::Persistence::NoBrainerPersistence::InstanceMethods)
|
|
36
|
+
base.extend AASM::Persistence::NoBrainerPersistence::ClassMethods
|
|
37
|
+
|
|
38
|
+
base.after_initialize :aasm_ensure_initial_state
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module ClassMethods
|
|
42
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
|
43
|
+
scope_options = lambda {
|
|
44
|
+
where(aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s)
|
|
45
|
+
}
|
|
46
|
+
send(:scope, scope_name, scope_options)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module InstanceMethods
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def aasm_save
|
|
55
|
+
self.save
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def aasm_raise_invalid_record
|
|
59
|
+
raise NoBrainer::Error::DocumentInvalid.new(self)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def aasm_supports_transactions?
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def aasm_update_column(attribute_name, value)
|
|
67
|
+
write_attribute(attribute_name, value)
|
|
68
|
+
save(validate: false)
|
|
69
|
+
|
|
70
|
+
true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def aasm_read_attribute(name)
|
|
74
|
+
read_attribute(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def aasm_write_attribute(name, value)
|
|
78
|
+
write_attribute(name, value)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
|
82
|
+
# that the initial state gets populated before validation on create
|
|
83
|
+
#
|
|
84
|
+
# foo = Foo.new
|
|
85
|
+
# foo.aasm_state # => nil
|
|
86
|
+
# foo.valid?
|
|
87
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
|
88
|
+
#
|
|
89
|
+
#
|
|
90
|
+
# foo = Foo.find(:first)
|
|
91
|
+
# foo.aasm_state # => 1
|
|
92
|
+
# foo.aasm_state = nil
|
|
93
|
+
# foo.valid?
|
|
94
|
+
# foo.aasm_state # => nil
|
|
95
|
+
#
|
|
96
|
+
def aasm_ensure_initial_state
|
|
97
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |name|
|
|
98
|
+
aasm_column = self.class.aasm(name).attribute_name
|
|
99
|
+
aasm(name).enter_initial_state if !read_attribute(aasm_column) || read_attribute(aasm_column).empty?
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end # InstanceMethods
|
|
103
|
+
end
|
|
104
|
+
end # Persistence
|
|
105
|
+
end # AASM
|