stator 0.0.13
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/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +203 -0
- data/Rakefile +9 -0
- data/gemfiles/ar30.gemfile +10 -0
- data/gemfiles/ar31.gemfile +10 -0
- data/gemfiles/ar32.gemfile +10 -0
- data/gemfiles/ar40.gemfile +10 -0
- data/lib/stator/alias.rb +81 -0
- data/lib/stator/integration.rb +82 -0
- data/lib/stator/machine.rb +123 -0
- data/lib/stator/model.rb +71 -0
- data/lib/stator/transition.rb +103 -0
- data/lib/stator/version.rb +8 -0
- data/lib/stator.rb +11 -0
- data/spec/model_spec.rb +214 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/models.rb +177 -0
- data/spec/support/schema.rb +43 -0
- data/stator.gemspec +21 -0
- metadata +91 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
module Stator
|
2
|
+
class Transition
|
3
|
+
|
4
|
+
ANY = '__any__'
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :full_name
|
8
|
+
|
9
|
+
def initialize(class_name, name, namespace = nil)
|
10
|
+
@class_name = class_name
|
11
|
+
@name = name
|
12
|
+
@namespace = namespace
|
13
|
+
@full_name = [@namespace, @name].compact.join('_') if @name
|
14
|
+
@froms = []
|
15
|
+
@to = nil
|
16
|
+
@callbacks = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def from(*froms)
|
20
|
+
@froms |= froms.map{|f| f.try(:to_s) } # nils are ok
|
21
|
+
end
|
22
|
+
|
23
|
+
def to(to)
|
24
|
+
@to = to.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_state
|
28
|
+
@to
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_states
|
32
|
+
@froms
|
33
|
+
end
|
34
|
+
|
35
|
+
def can?(current_state)
|
36
|
+
@froms.include?(current_state) || @froms.include?(ANY) || current_state == ANY
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid?(from, to)
|
40
|
+
can?(from) &&
|
41
|
+
(@to == to || @to == ANY || to == ANY)
|
42
|
+
end
|
43
|
+
|
44
|
+
def conditional(options = {}, &block)
|
45
|
+
klass.instance_exec(conditional_string(options), &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def any
|
49
|
+
ANY
|
50
|
+
end
|
51
|
+
|
52
|
+
def evaluate
|
53
|
+
generate_methods unless @full_name.blank?
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def klass
|
59
|
+
@class_name.constantize
|
60
|
+
end
|
61
|
+
|
62
|
+
def callbacks(kind)
|
63
|
+
@callbacks[kind] || []
|
64
|
+
end
|
65
|
+
|
66
|
+
def conditional_string(options = {})
|
67
|
+
options[:use_previous] ||= false
|
68
|
+
%Q{
|
69
|
+
(
|
70
|
+
#{@froms.inspect}.include?(self._stator(#{@namespace.inspect}).integration(self).state_was(#{options[:use_previous].inspect})) ||
|
71
|
+
#{@froms.inspect}.include?(::Stator::Transition::ANY)
|
72
|
+
) && (
|
73
|
+
self._stator(#{@namespace.inspect}).integration(self).state == #{@to.inspect} ||
|
74
|
+
#{@to.inspect} == ::Stator::Transition::ANY
|
75
|
+
)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_methods
|
80
|
+
klass.class_eval <<-EV, __FILE__, __LINE__ + 1
|
81
|
+
def #{@full_name}(should_save = true)
|
82
|
+
integration = self._stator(#{@namespace.inspect}).integration(self)
|
83
|
+
integration.state = #{@to.inspect}
|
84
|
+
self.save if should_save
|
85
|
+
end
|
86
|
+
|
87
|
+
def #{@full_name}!
|
88
|
+
integration = self._stator(#{@namespace.inspect}).integration(self)
|
89
|
+
integration.state = #{@to.inspect}
|
90
|
+
self.save!
|
91
|
+
end
|
92
|
+
|
93
|
+
def can_#{@full_name}?
|
94
|
+
machine = self._stator(#{@namespace.inspect})
|
95
|
+
integration = machine.integration(self)
|
96
|
+
transition = machine.transitions.detect{|t| t.full_name.to_s == #{@full_name.inspect}.to_s }
|
97
|
+
transition.can?(integration.state)
|
98
|
+
end
|
99
|
+
EV
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
data/lib/stator.rb
ADDED
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Stator::Model do
|
4
|
+
|
5
|
+
it 'should set the default state after initialization' do
|
6
|
+
u = User.new
|
7
|
+
u.state.should eql('pending')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should see the initial setting of the state as a change with the initial state as the previous value' do
|
11
|
+
u = User.new
|
12
|
+
u.state = 'activated'
|
13
|
+
u.state_was.should eql('pending')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should not obstruct normal validations' do
|
17
|
+
u = User.new
|
18
|
+
u.should_not be_valid
|
19
|
+
u.errors[:email].grep(/length/).should_not be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should ensure a valid state transition when given a bogus state' do
|
23
|
+
u = User.new
|
24
|
+
u.state = 'anythingelse'
|
25
|
+
|
26
|
+
u.should_not be_valid
|
27
|
+
u.errors[:state].should eql(['is not a valid state'])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should allow creation at any state' do
|
31
|
+
u = User.new(:email => 'doug@example.com')
|
32
|
+
u.state = 'hyperactivated'
|
33
|
+
|
34
|
+
u.should be_valid
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should ensure a valid state transition when given an illegal state based on the current state' do
|
38
|
+
u = User.new
|
39
|
+
u.stub(:new_record?).and_return(false)
|
40
|
+
u.state = 'hyperactivated'
|
41
|
+
|
42
|
+
u.should_not be_valid
|
43
|
+
u.errors[:state].should_not be_empty
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should run conditional validations' do
|
48
|
+
u = User.new
|
49
|
+
u.state = 'semiactivated'
|
50
|
+
u.should_not be_valid
|
51
|
+
|
52
|
+
u.errors[:state].should be_empty
|
53
|
+
u.errors[:email].grep(/format/).should_not be_empty
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should invoke callbacks' do
|
57
|
+
u = User.new(:activated => true, :email => 'doug@example.com', :name => 'doug')
|
58
|
+
u.activated.should == true
|
59
|
+
|
60
|
+
u.deactivate
|
61
|
+
|
62
|
+
u.activated.should == false
|
63
|
+
u.state.should eql('deactivated')
|
64
|
+
u.activated_state_at.should be_nil
|
65
|
+
u.should be_persisted
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should blow up if the record is invalid and a bang method is used' do
|
69
|
+
u = User.new(:email => 'doug@other.com', :name => 'doug')
|
70
|
+
lambda{
|
71
|
+
u.activate!
|
72
|
+
}.should raise_error(ActiveRecord::RecordInvalid)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should allow for other fields to be used other than state' do
|
76
|
+
a = Animal.new
|
77
|
+
a.should be_valid
|
78
|
+
|
79
|
+
a.birth!
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should create implicit transitions for state declarations' do
|
83
|
+
a = Animal.new
|
84
|
+
a.should_not be_grown_up
|
85
|
+
a.status = 'grown_up'
|
86
|
+
a.save
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should allow multiple machines in the same model' do
|
90
|
+
f = Farm.new
|
91
|
+
f.should be_dirty
|
92
|
+
f.should be_house_dirty
|
93
|
+
|
94
|
+
f.cleanup
|
95
|
+
|
96
|
+
f.should_not be_dirty
|
97
|
+
f.should be_house_dirty
|
98
|
+
|
99
|
+
f.house_cleanup
|
100
|
+
|
101
|
+
f.should_not be_house_dirty
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should allow saving to be skipped' do
|
105
|
+
f = Farm.new
|
106
|
+
f.cleanup(false)
|
107
|
+
|
108
|
+
f.should_not be_persisted
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should allow no initial state' do
|
112
|
+
f = Factory.new
|
113
|
+
f.state.should be_nil
|
114
|
+
|
115
|
+
f.construct.should be_true
|
116
|
+
|
117
|
+
f.state.should eql('constructed')
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'helper methods' do
|
121
|
+
|
122
|
+
it 'should answer the question of whether the state is currently the one invoked' do
|
123
|
+
a = Animal.new
|
124
|
+
a.should be_unborn
|
125
|
+
a.should_not be_born
|
126
|
+
|
127
|
+
a.birth
|
128
|
+
|
129
|
+
a.should be_born
|
130
|
+
a.should_not be_unborn
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should determine if it can validly execute a transition' do
|
134
|
+
a = Animal.new
|
135
|
+
a.can_birth?.should be_true
|
136
|
+
|
137
|
+
a.birth
|
138
|
+
|
139
|
+
a.can_birth?.should be_false
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'tracker methods' do
|
145
|
+
|
146
|
+
before do
|
147
|
+
Time.zone = 'Eastern Time (US & Canada)'
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should store when a record changed state for the first time' do
|
151
|
+
a = Animal.new
|
152
|
+
a.unborn_status_at.should be_nil
|
153
|
+
a.born_status_at.should be_nil
|
154
|
+
a.birth
|
155
|
+
a.unborn_status_at.should be_within(1).of(Time.zone.now)
|
156
|
+
a.born_status_at.should be_within(1).of(Time.zone.now)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe 'aliasing' do
|
162
|
+
it 'should allow aliasing within the dsl' do
|
163
|
+
u = User.new(:email => 'doug@example.com')
|
164
|
+
u.should respond_to(:active?)
|
165
|
+
u.should respond_to(:inactive?)
|
166
|
+
|
167
|
+
u.should_not be_active
|
168
|
+
|
169
|
+
u.inactive?
|
170
|
+
u.should be_inactive
|
171
|
+
|
172
|
+
u.activate!
|
173
|
+
u.should be_active
|
174
|
+
u.should_not be_inactive
|
175
|
+
|
176
|
+
u.hyperactivate!
|
177
|
+
u.should be_active
|
178
|
+
u.should_not be_inactive
|
179
|
+
|
180
|
+
User::ACTIVE_STATES.should eql(['activated', 'hyperactivated'])
|
181
|
+
User::INACTIVE_STATES.should eql(['pending', 'deactivated', 'semiactivated'])
|
182
|
+
|
183
|
+
u2 = User.create(:email => 'phil@example.com')
|
184
|
+
|
185
|
+
User.active.to_sql.gsub(' ', ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
|
186
|
+
User.inactive.to_sql.gsub(' ', ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should namespace aliases just like everything else' do
|
190
|
+
f = Farm.new
|
191
|
+
f.should respond_to(:house_cleaned?)
|
192
|
+
|
193
|
+
f.should_not be_house_cleaned
|
194
|
+
f.house_cleanup!
|
195
|
+
|
196
|
+
f.should be_house_cleaned
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should allow for explicit constant and scope names to be provided' do
|
200
|
+
User.should respond_to(:luke_warmers)
|
201
|
+
defined?(User::LUKE_WARMERS).should be_true
|
202
|
+
u = User.new
|
203
|
+
u.should respond_to(:luke_warm?)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should not create constants or scopes by default' do
|
207
|
+
u = User.new
|
208
|
+
u.should respond_to(:iced_tea?)
|
209
|
+
defined?(User::ICED_TEA_STATES).should be_false
|
210
|
+
User.should_not respond_to(:iced_tea)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require 'active_record'
|
9
|
+
require 'nulldb/core'
|
10
|
+
require 'active_support/core_ext'
|
11
|
+
require 'stator'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
config.run_all_when_everything_filtered = true
|
16
|
+
config.filter_run :focus
|
17
|
+
|
18
|
+
NullDB.configure do |c|
|
19
|
+
c.project_root = File.dirname(__FILE__)
|
20
|
+
end
|
21
|
+
|
22
|
+
ActiveRecord::Base.establish_connection(
|
23
|
+
:adapter => :nulldb,
|
24
|
+
:schema => 'support/schema.rb'
|
25
|
+
)
|
26
|
+
|
27
|
+
require 'support/models'
|
28
|
+
|
29
|
+
# Run specs in random order to surface order dependencies. If you find an
|
30
|
+
# order dependency and want to debug it, you can fix the order by providing
|
31
|
+
# the seed, which is printed after each run.
|
32
|
+
# --seed 1234
|
33
|
+
config.order = 'random'
|
34
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
extend Stator::Model
|
3
|
+
|
4
|
+
|
5
|
+
# initial state = pending
|
6
|
+
stator do
|
7
|
+
|
8
|
+
transition :activate do
|
9
|
+
from :pending, :semiactivated
|
10
|
+
to :activated
|
11
|
+
end
|
12
|
+
|
13
|
+
transition :deactivate do
|
14
|
+
from any
|
15
|
+
to :deactivated
|
16
|
+
|
17
|
+
conditional do |condition|
|
18
|
+
before_save :set_deactivated, :if => condition
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
transition :semiactivate do
|
23
|
+
from :pending
|
24
|
+
to :semiactivated
|
25
|
+
|
26
|
+
conditional do |condition|
|
27
|
+
validate :check_email_validity, :if => condition
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
transition :hyperactivate do
|
32
|
+
from :activated
|
33
|
+
to :hyperactivated
|
34
|
+
end
|
35
|
+
|
36
|
+
conditional :semiactivated, :activated do |condition|
|
37
|
+
validate :check_email_presence, :if => condition
|
38
|
+
end
|
39
|
+
|
40
|
+
state_alias :active, :constant => true, :scope => true do
|
41
|
+
is :activated, :hyperactivated
|
42
|
+
opposite :inactive, :constant => true, :scope => true
|
43
|
+
end
|
44
|
+
|
45
|
+
state_alias :luke_warm, :constant => :luke_warmers, :scope => :luke_warmers do
|
46
|
+
is :semiactivated
|
47
|
+
opposite :iced_tea
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
validate :email_is_right_length
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def check_email_presence
|
57
|
+
unless self.email.present?
|
58
|
+
self.errors.add(:email, 'needs to be present')
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_email_validity
|
66
|
+
unless self.email.to_s =~ /example\.com$/
|
67
|
+
self.errors.add(:email, 'format needs to be example.com')
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def email_is_right_length
|
75
|
+
unless self.email.to_s.length == 'four@example.com'.length
|
76
|
+
self.errors.add(:email, 'needs to be the right length')
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_deactivated
|
84
|
+
self.activated = false
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
class Animal < ActiveRecord::Base
|
91
|
+
extend Stator::Model
|
92
|
+
|
93
|
+
# initial state = unborn
|
94
|
+
stator :field => :status, :helpers => true, :track => true do
|
95
|
+
|
96
|
+
transition :birth do
|
97
|
+
from :unborn
|
98
|
+
to :born
|
99
|
+
end
|
100
|
+
|
101
|
+
state :grown_up
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class Zoo < ActiveRecord::Base
|
107
|
+
extend Stator::Model
|
108
|
+
|
109
|
+
# initial state = closed
|
110
|
+
stator do
|
111
|
+
|
112
|
+
transition :open do
|
113
|
+
from :closed
|
114
|
+
to :opened
|
115
|
+
end
|
116
|
+
|
117
|
+
transition :close do
|
118
|
+
from :opened
|
119
|
+
to :closed
|
120
|
+
end
|
121
|
+
|
122
|
+
conditional :opened do |c|
|
123
|
+
validate :validate_lights_are_on, :if => c
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
def validate_lights_are_on
|
130
|
+
true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
class Farm < ActiveRecord::Base
|
136
|
+
extend Stator::Model
|
137
|
+
|
138
|
+
# initial state = dirty
|
139
|
+
stator do
|
140
|
+
transition :cleanup do
|
141
|
+
from :dirty
|
142
|
+
to :clean
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# initial state = dirty
|
148
|
+
stator :field => 'house_state', :namespace => 'house' do
|
149
|
+
transition :cleanup do
|
150
|
+
from :dirty
|
151
|
+
to :clean
|
152
|
+
end
|
153
|
+
|
154
|
+
state_alias :cleaned do
|
155
|
+
is_not :dirty
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
class Factory < ActiveRecord::Base
|
162
|
+
extend Stator::Model
|
163
|
+
|
164
|
+
# initial state = nil
|
165
|
+
stator do
|
166
|
+
transition :construct do
|
167
|
+
from nil
|
168
|
+
to :constructed
|
169
|
+
end
|
170
|
+
|
171
|
+
transition :destruct do
|
172
|
+
from :constructed
|
173
|
+
to :on_the_ground
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 20130628161227) do
|
2
|
+
|
3
|
+
create_table "users", :force => true do |t|
|
4
|
+
t.string "name"
|
5
|
+
t.string "email"
|
6
|
+
t.string "state", :default => 'pending'
|
7
|
+
t.boolean "activated", :default => true
|
8
|
+
t.datetime "created_at", :null => false
|
9
|
+
t.datetime "updated_at", :null => false
|
10
|
+
t.datetime "semiactivated_state_at"
|
11
|
+
t.datetime "activated_state_at"
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table "animals", :force => true do |t|
|
15
|
+
t.string "name"
|
16
|
+
t.string "status", :default => 'unborn'
|
17
|
+
t.datetime "created_at", :null => false
|
18
|
+
t.datetime "updated_at", :null => false
|
19
|
+
t.datetime "unborn_status_at"
|
20
|
+
t.datetime "born_status_at"
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table "zoos", :force => true do |t|
|
24
|
+
t.string "name"
|
25
|
+
t.string "state", :default => 'closed'
|
26
|
+
t.datetime "created_at", :null => false
|
27
|
+
t.datetime "updated_at", :null => false
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table "farms", :force => true do |t|
|
31
|
+
t.string "name"
|
32
|
+
t.string "state", :default => 'dirty'
|
33
|
+
t.string "house_state", :default => 'dirty'
|
34
|
+
t.datetime "created_at", :null => false
|
35
|
+
t.datetime "updated_at", :null => false
|
36
|
+
end
|
37
|
+
|
38
|
+
create_table "factories", :force => true do |t|
|
39
|
+
t.string "name"
|
40
|
+
t.string "state"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/stator.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'stator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "stator"
|
8
|
+
gem.version = Stator::VERSION
|
9
|
+
gem.authors = ["Mike Nelson"]
|
10
|
+
gem.email = ["mike@mikeonrails.com"]
|
11
|
+
gem.description = %q{The simplest of ActiveRecord state machines. Intended to be lightweight and minimalistic.}
|
12
|
+
gem.summary = %q{The simplest of ActiveRecord state machines}
|
13
|
+
gem.homepage = "http://www.mikeonrails.com"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'activerecord'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.13
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Nelson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: The simplest of ActiveRecord state machines. Intended to be lightweight
|
31
|
+
and minimalistic.
|
32
|
+
email:
|
33
|
+
- mike@mikeonrails.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- .rspec
|
40
|
+
- .ruby-gemset
|
41
|
+
- .ruby-version
|
42
|
+
- .travis.yml
|
43
|
+
- Gemfile
|
44
|
+
- LICENSE.txt
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- gemfiles/ar30.gemfile
|
48
|
+
- gemfiles/ar31.gemfile
|
49
|
+
- gemfiles/ar32.gemfile
|
50
|
+
- gemfiles/ar40.gemfile
|
51
|
+
- lib/stator.rb
|
52
|
+
- lib/stator/alias.rb
|
53
|
+
- lib/stator/integration.rb
|
54
|
+
- lib/stator/machine.rb
|
55
|
+
- lib/stator/model.rb
|
56
|
+
- lib/stator/transition.rb
|
57
|
+
- lib/stator/version.rb
|
58
|
+
- spec/model_spec.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
- spec/support/models.rb
|
61
|
+
- spec/support/schema.rb
|
62
|
+
- stator.gemspec
|
63
|
+
homepage: http://www.mikeonrails.com
|
64
|
+
licenses: []
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.25
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: The simplest of ActiveRecord state machines
|
87
|
+
test_files:
|
88
|
+
- spec/model_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- spec/support/models.rb
|
91
|
+
- spec/support/schema.rb
|