maintain 0.1.6 → 0.1.7
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/VERSION +1 -1
- data/lib/maintain/bitmask_value.rb +1 -0
- data/lib/maintain/integer_value.rb +1 -0
- data/lib/maintain/maintainer.rb +40 -16
- data/lib/maintain/value.rb +1 -0
- data/lib/maintain.rb +11 -28
- data/maintain.gemspec +4 -2
- data/spec/active_record_spec.rb +1 -1
- data/spec/aggregates_spec.rb +1 -1
- data/spec/bitwise_spec.rb +1 -1
- data/spec/comparing_state_spec.rb +15 -12
- data/spec/defining_states_spec.rb +1 -1
- data/spec/hooks_spec.rb +19 -1
- data/spec/integer_spec.rb +1 -1
- data/spec/maintain_spec.rb +1 -1
- data/spec/proxy_spec.rb +1 -1
- data/spec/setting_state_spec.rb +1 -1
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
data/lib/maintain/maintainer.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
module Maintain
|
2
3
|
class Maintainer
|
3
4
|
def aggregate(name, options)
|
@@ -38,7 +39,7 @@ module Maintain
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def bitmask?
|
41
|
-
|
42
|
+
!!@bitmask
|
42
43
|
end
|
43
44
|
|
44
45
|
def default(state)
|
@@ -50,13 +51,11 @@ module Maintain
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def hook(event, state, instance)
|
53
|
-
if state && hooks[state.to_sym] && hooks[state.to_sym][event.to_sym]
|
54
|
-
|
55
|
-
if
|
56
|
-
|
57
|
-
|
58
|
-
instance.send(method)
|
59
|
-
end
|
54
|
+
if state && state.to_s.strip != '' && hooks[state.to_sym] && hook_definitions = hooks[state.to_sym][event.to_sym]
|
55
|
+
hook_definitions.each do |hook_definition|
|
56
|
+
next if hook_definition[:if] && !call_method_or_proc_on_instance(hook_definition[:if], instance)
|
57
|
+
next if hook_definition[:unless] && call_method_or_proc_on_instance(hook_definition[:unless], instance)
|
58
|
+
call_method_or_proc_on_instance(hook_definition[:method], instance)
|
60
59
|
end
|
61
60
|
end
|
62
61
|
end
|
@@ -74,13 +73,25 @@ module Maintain
|
|
74
73
|
@integer = !!value
|
75
74
|
end
|
76
75
|
|
77
|
-
def
|
76
|
+
def integer?
|
77
|
+
!!@integer
|
78
|
+
end
|
79
|
+
|
80
|
+
def on(*args, &block)
|
81
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
82
|
+
event, state = args.shift, args.shift
|
83
|
+
method = args.shift
|
78
84
|
if block_given?
|
79
85
|
method = block
|
80
86
|
end
|
81
87
|
hooks[state.to_sym] ||= {}
|
82
88
|
hooks[state.to_sym][event.to_sym] ||= []
|
83
|
-
|
89
|
+
method_hash = {:method => method}.merge(options)
|
90
|
+
if old_definition = hooks[state.to_sym][event.to_sym].find{|hook| hook[:method] == method}
|
91
|
+
old_definition.merge!(method_hash)
|
92
|
+
else
|
93
|
+
hooks[state.to_sym][event.to_sym].push(method_hash)
|
94
|
+
end
|
84
95
|
end
|
85
96
|
|
86
97
|
def state_name_for(value)
|
@@ -98,7 +109,7 @@ module Maintain
|
|
98
109
|
default(name)
|
99
110
|
end
|
100
111
|
@increment ||= 0
|
101
|
-
if
|
112
|
+
if bitmask?
|
102
113
|
unless value.is_a?(Integer)
|
103
114
|
value = @increment
|
104
115
|
end
|
@@ -107,7 +118,7 @@ module Maintain
|
|
107
118
|
integer(true)
|
108
119
|
end
|
109
120
|
value ||= name
|
110
|
-
states[name] = {:compare_value =>
|
121
|
+
states[name] = {:compare_value => !bitmask? && value.is_a?(Integer) ? value : @increment, :value => value}
|
111
122
|
@increment += 1
|
112
123
|
if @active_record && !maintainee.respond_to?(name)
|
113
124
|
conditions = {:conditions => {@attribute => value.is_a?(Symbol) ? value.to_s : value}}
|
@@ -138,9 +149,9 @@ module Maintain
|
|
138
149
|
end
|
139
150
|
|
140
151
|
def value(initial = nil)
|
141
|
-
if
|
152
|
+
if bitmask?
|
142
153
|
BitmaskValue.new(self, initial || @default || 0)
|
143
|
-
elsif
|
154
|
+
elsif integer?
|
144
155
|
IntegerValue.new(self, initial || @default)
|
145
156
|
else
|
146
157
|
Value.new(self, initial || @default)
|
@@ -164,9 +175,13 @@ module Maintain
|
|
164
175
|
methods = maintainee_class.public_methods + maintainee_class.private_methods + maintainee_class.protected_methods
|
165
176
|
else
|
166
177
|
respond_to = false
|
167
|
-
methods = maintainee_class.
|
178
|
+
methods = maintainee_class.instance_methods
|
179
|
+
# methods = %w(instance_methods public_instance_methods private_instance_methods protected_instance_methods).inject([]) do |methods, method|
|
180
|
+
# methods + maintainee_class.send(method)
|
181
|
+
# end.uniq
|
168
182
|
end
|
169
|
-
|
183
|
+
# Ruby 1.8 returns arrays of strings; ruby 1.9 returns arrays of symbols. "Awesome."
|
184
|
+
!respond_to && !methods.include?(method_name) && !methods.include?(method_name.to_sym)
|
170
185
|
end
|
171
186
|
|
172
187
|
def method_missing(method, *args)
|
@@ -176,5 +191,14 @@ module Maintain
|
|
176
191
|
super
|
177
192
|
end
|
178
193
|
end
|
194
|
+
|
195
|
+
private
|
196
|
+
def call_method_or_proc_on_instance(method, instance)
|
197
|
+
if method.is_a?(Proc)
|
198
|
+
instance.instance_eval(&method)
|
199
|
+
else
|
200
|
+
instance.send(method)
|
201
|
+
end
|
202
|
+
end
|
179
203
|
end
|
180
204
|
end
|
data/lib/maintain/value.rb
CHANGED
data/lib/maintain.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__))
|
3
|
+
|
1
4
|
module Maintain
|
2
5
|
# We're not really interested in loading anything into memory if we don't need to,
|
3
6
|
# so Maintainer, Value, and the Value subclasses are ignored until they're needed.
|
@@ -49,59 +52,39 @@ module Maintain
|
|
49
52
|
|
50
53
|
# Define our getters and setters - these are the only methods Maintain will stomp
|
51
54
|
# on if you've already defined them. This is because they're how Maintain works.
|
52
|
-
class_eval <<-EOC
|
55
|
+
class_eval <<-EOC, __FILE__
|
53
56
|
def #{attribute}=(value)
|
54
57
|
# If we can find the maintainer on this attribute, we'll use it to set values.
|
55
58
|
if maintainer = self.class.maintainers[#{attribute.to_sym.inspect}]
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
# Then run the exit hook if we're changing the value
|
60
|
-
maintainer.hook(:exit, #{attribute}.value, self)
|
59
|
+
# Run the exit hook if we're changing the value
|
60
|
+
maintainer.hook(:exit, #{attribute}.name, self)
|
61
61
|
|
62
62
|
# Then set the value itself. Maintainer::State will return the value you set,
|
63
63
|
# so if we're setting to nil we get rid of the attribute entirely - it's not
|
64
64
|
# needed and we want the getter to return nil in that case.
|
65
65
|
# unless
|
66
|
-
#{attribute}.set_value(value)
|
67
|
-
# @#{attribute} = nil
|
68
|
-
# Nevermind - all of our test methods rely on that attribute existing, no
|
69
|
-
# matter what (e.g. maintain(:state) { state :one } and calling "one?" will
|
70
|
-
# throw an error if we null out our maintainer)
|
71
|
-
# end#{%{
|
66
|
+
#{attribute}.set_value(value)#{%{
|
72
67
|
|
73
68
|
# If this is ActiveRecord::Base or a subclass of it, we'll make sure calling the
|
74
69
|
# setter writes a DB-friendly value.
|
75
|
-
write_attribute(#{attribute.to_s.inspect}, @#{attribute} ? @#{attribute}.value.to_s :
|
70
|
+
write_attribute(#{attribute.to_s.inspect}, @#{attribute} ? @#{attribute}.value.to_s : @#{attribute})
|
76
71
|
} if active_record}
|
77
72
|
|
78
73
|
# Last but not least, run the enter hooks for the new value - cause that's how we
|
79
74
|
# do.
|
80
|
-
maintainer.hook(:enter,
|
75
|
+
maintainer.hook(:enter, #{attribute}.name, self) if @#{attribute}
|
81
76
|
else
|
82
77
|
# If we can't find a maintainer for this attribute, make our best effort to do what
|
83
78
|
# attr_accessor does - set the instance variable.
|
84
79
|
@#{attribute} = value#{%{
|
85
80
|
|
86
81
|
# ... and on ActiveRecord::Base, we'll also write the attribute like a normal setter.
|
87
|
-
if
|
88
|
-
write_attribute(:#{attribute}, @#{attribute})
|
89
|
-
end
|
90
|
-
} if active_record}
|
82
|
+
write_attribute(:#{attribute}, @#{attribute})} if active_record}
|
91
83
|
end
|
92
84
|
end
|
93
85
|
|
94
86
|
def #{attribute}
|
95
|
-
|
96
|
-
return @#{attribute} if @#{attribute}
|
97
|
-
|
98
|
-
# If'n it doesn't already exist AND this maintained attribute has a default value (and
|
99
|
-
# bitmasks must have at least a 0 value), we'll instantiate a Maintainer::State and return
|
100
|
-
# it.
|
101
|
-
# if self.class.maintainers[#{attribute.to_sym.inspect}].default? || self.class.maintainers[#{attribute.to_sym.inspect}].bitmask?#{" || attributes['#{attribute}']" if active_record}
|
102
|
-
# Always return a State, no matter what
|
103
|
-
@#{attribute} = self.class.maintainers[#{attribute.to_sym.inspect}].value#{"(read_attribute(:#{attribute}))" if active_record}
|
104
|
-
# end
|
87
|
+
@#{attribute} ||= self.class.maintainers[#{attribute.to_sym.inspect}].value#{"(read_attribute(:#{attribute}))" if active_record}
|
105
88
|
end
|
106
89
|
EOC
|
107
90
|
|
data/maintain.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{maintain}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Flip Sasser"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-30}
|
13
13
|
s.description = %q{
|
14
14
|
Maintain is a simple state machine mixin for Ruby objects. It supports comparisons, bitmasks,
|
15
15
|
and hooks that really work. It can be used for multiple attributes and will always do its best to
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
"README.markdown"
|
21
21
|
]
|
22
22
|
s.files = [
|
23
|
+
".gitignore",
|
23
24
|
"README.markdown",
|
24
25
|
"Rakefile",
|
25
26
|
"VERSION",
|
@@ -28,6 +29,7 @@ Gem::Specification.new do |s|
|
|
28
29
|
"lib/maintain/integer_value.rb",
|
29
30
|
"lib/maintain/maintainer.rb",
|
30
31
|
"lib/maintain/value.rb",
|
32
|
+
"maintain.gemspec",
|
31
33
|
"spec/active_record_spec.rb",
|
32
34
|
"spec/aggregates_spec.rb",
|
33
35
|
"spec/bitwise_spec.rb",
|
data/spec/active_record_spec.rb
CHANGED
@@ -22,7 +22,7 @@ if proceed
|
|
22
22
|
describe "accessors" do
|
23
23
|
before :each do
|
24
24
|
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:', :pool => 5, :timeout => 5000})
|
25
|
-
class ActiveMaintainTest < ActiveRecord::Base; end
|
25
|
+
class ::ActiveMaintainTest < ActiveRecord::Base; end
|
26
26
|
silence_stream(STDOUT) do
|
27
27
|
ActiveRecord::Schema.define do
|
28
28
|
create_table :active_maintain_tests, :force => true do |t|
|
data/spec/aggregates_spec.rb
CHANGED
data/spec/bitwise_spec.rb
CHANGED
@@ -4,10 +4,24 @@ require 'lib/maintain'
|
|
4
4
|
|
5
5
|
describe Maintain do
|
6
6
|
before :each do
|
7
|
-
class MaintainTest
|
7
|
+
class ::MaintainTest
|
8
8
|
attr_accessor :existant_attribute
|
9
9
|
extend Maintain
|
10
10
|
end
|
11
|
+
|
12
|
+
class ::MaintainTestTwo
|
13
|
+
def new?
|
14
|
+
:i_existed_before_you_came_along
|
15
|
+
end
|
16
|
+
|
17
|
+
extend Maintain
|
18
|
+
|
19
|
+
maintains :state, :default => :new do
|
20
|
+
state :new
|
21
|
+
state :overdue
|
22
|
+
state :closed
|
23
|
+
end
|
24
|
+
end
|
11
25
|
end
|
12
26
|
|
13
27
|
describe "testing" do
|
@@ -66,17 +80,6 @@ describe Maintain do
|
|
66
80
|
end
|
67
81
|
|
68
82
|
it "should not override pre-existing methods" do
|
69
|
-
class MaintainTestTwo
|
70
|
-
def new?
|
71
|
-
:i_existed_before_you_came_along
|
72
|
-
end
|
73
|
-
extend Maintain
|
74
|
-
maintains :state, :default => :new do
|
75
|
-
state :new
|
76
|
-
state :overdue
|
77
|
-
state :closed
|
78
|
-
end
|
79
|
-
end
|
80
83
|
MaintainTestTwo.new.new?.should == :i_existed_before_you_came_along
|
81
84
|
end
|
82
85
|
end
|
data/spec/hooks_spec.rb
CHANGED
@@ -4,7 +4,7 @@ require 'lib/maintain'
|
|
4
4
|
|
5
5
|
describe Maintain, "hooks" do
|
6
6
|
before :each do
|
7
|
-
class MaintainTest
|
7
|
+
class ::MaintainTest
|
8
8
|
extend Maintain
|
9
9
|
end
|
10
10
|
end
|
@@ -41,4 +41,22 @@ describe Maintain, "hooks" do
|
|
41
41
|
maintain.state = :old
|
42
42
|
end
|
43
43
|
|
44
|
+
describe "guarding" do
|
45
|
+
it "should prevent hooks from running when they return false" do
|
46
|
+
MaintainTest.maintain :state do
|
47
|
+
state :new
|
48
|
+
state :old
|
49
|
+
on :enter, :new, :new_entered, :if => :run_hook?
|
50
|
+
end
|
51
|
+
|
52
|
+
maintain = MaintainTest.new
|
53
|
+
def maintain.run_hook?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
maintain.should_not_receive(:new_entered)
|
57
|
+
maintain.state = :new
|
58
|
+
maintain.state = :old
|
59
|
+
maintain.state = :old
|
60
|
+
end
|
61
|
+
end
|
44
62
|
end
|
data/spec/integer_spec.rb
CHANGED
data/spec/maintain_spec.rb
CHANGED
data/spec/proxy_spec.rb
CHANGED
data/spec/setting_state_spec.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 7
|
9
|
+
version: 0.1.7
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Flip Sasser
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-30 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|