maintain 0.2.23 → 0.3.0
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/CHANGES.md +34 -0
- data/README.markdown +9 -9
- data/lib/maintain.rb +42 -27
- data/lib/maintain/backend.rb +2 -12
- data/lib/maintain/backend/active_record.rb +17 -17
- data/lib/maintain/backend/data_mapper.rb +1 -1
- data/lib/maintain/bitmask_value.rb +7 -2
- data/lib/maintain/maintainer.rb +69 -41
- data/lib/maintain/value.rb +4 -3
- data/spec/active_record_spec.rb +75 -63
- data/spec/bitwise_spec.rb +4 -4
- data/spec/class_methods_spec.rb +2 -2
- data/spec/comparing_state_spec.rb +14 -14
- data/spec/data_mapper_spec.rb +10 -10
- data/spec/defining_states_spec.rb +8 -8
- data/spec/hooks_spec.rb +4 -4
- data/spec/integer_spec.rb +3 -3
- data/spec/maintain_spec.rb +2 -2
- data/spec/object_spec.rb +1 -1
- data/spec/proxy_spec.rb +6 -6
- data/spec/setting_state_spec.rb +1 -1
- metadata +30 -21
- data/.rspec +0 -1
- data/CHANGES +0 -27
- data/Rakefile +0 -18
- data/VERSION +0 -1
- data/autotest/discover.rb +0 -4
- data/maintain.gemspec +0 -66
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1266039e3c147c59da0d3c94b51b3511516fb0c9
|
4
|
+
data.tar.gz: 5a7da80deea1aa14248e066c485fb1010627ed69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7fcc2ef3ef53205dd0ad838da80b5b33c8d6a5b348c05bdc05407ac26e43e768ec518f07731f533f1a3338ec65c49e62f5d5ec2c5f6d530cfd9b8fa07b22911
|
7
|
+
data.tar.gz: 82432c0d707c58d028945a9a03efbf0e42e94a7b22d86b63c454bfd3f4a9d8f602ee2a2176f73482b13fa4d9ae1e46367c534559e39572d055948650f068c81c
|
data/CHANGES.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
## 0.3.0
|
2
|
+
* Rails 4 compatibility
|
3
|
+
* Ruby 1.9 required as of 0.3
|
4
|
+
* Fixed `bang!` methods not saving on the back end
|
5
|
+
|
6
|
+
## 0.2.22
|
7
|
+
* Added `bang!` method support, so now you can call `@object.awesome!`
|
8
|
+
and its state will be set to "awesome." Like all Maintain methods,
|
9
|
+
I'm saying f\*ck you to convention and letting you go nuts; you can
|
10
|
+
achieve the same effect one of three ways:
|
11
|
+
|
12
|
+
```
|
13
|
+
@object.awesome!
|
14
|
+
@object.state.awesome!
|
15
|
+
@object.state_awesome!
|
16
|
+
```
|
17
|
+
|
18
|
+
## 0.2.21
|
19
|
+
* Added Enumerable support to bitmask values, so now you can parse
|
20
|
+
through flags with each, select, map, find, and more! This also
|
21
|
+
means `to_a` is now a method on @object.maintained_attribute.
|
22
|
+
|
23
|
+
## 0.2.20
|
24
|
+
* Removed accidental debugging `puts` calls from ActiveRecord backend
|
25
|
+
|
26
|
+
## 0.2.19
|
27
|
+
* Added :force option to state and aggregate definitions, allowing you
|
28
|
+
to force a method overwrite
|
29
|
+
* Added an attribute_name alias to named scopes in the ActiveRecord
|
30
|
+
backend, since Rails 3.1 has eaten up a number of previously
|
31
|
+
usable state names
|
32
|
+
|
33
|
+
## 0.2.18
|
34
|
+
* Ruby 1.9.2 and Rails 3.1 compatibility updates (no API changes)
|
data/README.markdown
CHANGED
@@ -23,7 +23,7 @@ state on an attribute:
|
|
23
23
|
class Foo
|
24
24
|
extend Maintain
|
25
25
|
maintains :state do
|
26
|
-
state :new, :
|
26
|
+
state :new, default: true
|
27
27
|
state :old
|
28
28
|
end
|
29
29
|
end
|
@@ -45,7 +45,7 @@ But wait! What if you've already defined "new?" on the Foo class? Not to worry,
|
|
45
45
|
|
46
46
|
And when you *want* Maintain to step on your toes? You can add an optionally add:
|
47
47
|
|
48
|
-
state :new, :
|
48
|
+
state :new, force: true
|
49
49
|
|
50
50
|
...and Maintain will make sure your methods get added, even if it overwrites a previous method.
|
51
51
|
|
@@ -76,7 +76,7 @@ order you want:
|
|
76
76
|
class Foo
|
77
77
|
extend Maintain
|
78
78
|
maintains :state do
|
79
|
-
state :new, 12, :
|
79
|
+
state :new, 12, default: true
|
80
80
|
state :old, 5
|
81
81
|
end
|
82
82
|
end
|
@@ -92,8 +92,8 @@ Hooks
|
|
92
92
|
```ruby
|
93
93
|
class Foo < ActiveRecord::Base
|
94
94
|
maintains :state do
|
95
|
-
state :active, :
|
96
|
-
state :inactive, :
|
95
|
+
state :active, enter: :activated
|
96
|
+
state :inactive, exit: lambda { self.bar.baz! }
|
97
97
|
end
|
98
98
|
|
99
99
|
def activated
|
@@ -157,7 +157,7 @@ relational database - or you could implement a single bitmask column:
|
|
157
157
|
```ruby
|
158
158
|
class Foo
|
159
159
|
extend Maintain
|
160
|
-
maintains :state, :
|
160
|
+
maintains :state, bitmask: true do
|
161
161
|
# NOTE: Maintain will try to infer a bitmask value if you do not provide an integer here,
|
162
162
|
# but if you don't -- and you re-order your state calls later -- all stored bitmasks will
|
163
163
|
# be invalidated. You have been warned.
|
@@ -186,10 +186,10 @@ You can also set multiple defaults on bitmasks, just in case your defaults invol
|
|
186
186
|
```ruby
|
187
187
|
class Foo
|
188
188
|
extend Maintain
|
189
|
-
maintains :state, :
|
190
|
-
state :new, 1, :
|
189
|
+
maintains :state, bitmask: true do
|
190
|
+
state :new, 1, default: true
|
191
191
|
state :old, 2
|
192
|
-
state :borrowed, 3, :
|
192
|
+
state :borrowed, 3, default: true
|
193
193
|
state :blue, 4
|
194
194
|
end
|
195
195
|
end
|
data/lib/maintain.rb
CHANGED
@@ -3,33 +3,35 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__))
|
|
3
3
|
require 'maintain/backend'
|
4
4
|
|
5
5
|
module Maintain
|
6
|
-
# We're not really interested in loading anything into memory if we don't
|
7
|
-
# so Maintainer, Value, and the Value subclasses are ignored until
|
6
|
+
# We're not really interested in loading anything into memory if we don't
|
7
|
+
# need to, so Maintainer, Value, and the Value subclasses are ignored until
|
8
|
+
# they're needed.
|
8
9
|
autoload(:Maintainer, 'maintain/maintainer')
|
9
10
|
autoload(:Value, 'maintain/value')
|
10
11
|
autoload(:BitmaskValue, 'maintain/bitmask_value')
|
11
12
|
autoload(:IntegerValue, 'maintain/integer_value')
|
12
13
|
|
13
14
|
# The core class method of Maintain. Basic usage is:
|
14
|
-
#
|
15
|
+
#
|
15
16
|
# maintain :state do
|
16
|
-
# state :new, :
|
17
|
-
# state :expired, :
|
18
|
-
# state :reopened, :
|
19
|
-
# aggregate :accessible, :
|
17
|
+
# state :new, default: true
|
18
|
+
# state :expired, enter: :expire_children
|
19
|
+
# state :reopened, exit: lambda { children.each(&:reopen) }
|
20
|
+
# aggregate :accessible, as: [:new, :reopened]
|
20
21
|
# end
|
21
|
-
#
|
22
|
+
#
|
22
23
|
# It also supports more complex configuration options, like bitmask columns
|
23
24
|
# and integer values (for performance and portability)
|
24
|
-
#
|
25
|
-
# maintain :permissions, :
|
25
|
+
#
|
26
|
+
# maintain :permissions, bitmask: true do
|
26
27
|
# state :edit, 1
|
27
28
|
# state :delete, 2
|
28
29
|
# state :manage, 3
|
29
30
|
# end
|
30
|
-
#
|
31
|
-
# This method is aliased as `maintains` with the intention of allowing
|
32
|
-
# to code imperatively ("maintain, damn you!") or descriptively
|
31
|
+
#
|
32
|
+
# This method is aliased as `maintains` with the intention of allowing
|
33
|
+
# developers to code imperatively ("maintain, damn you!") or descriptively
|
34
|
+
# ("it maintains, man")
|
33
35
|
def maintain(attribute, options = {}, &block)
|
34
36
|
options[:back_end] ||= Maintain::Backend.detect(self)
|
35
37
|
|
@@ -40,19 +42,22 @@ module Maintain
|
|
40
42
|
maintainer.instance_eval(&block)
|
41
43
|
end
|
42
44
|
|
43
|
-
# Define our getters and setters - these are the only methods Maintain will
|
44
|
-
# on if you've already defined them. This is because they're how
|
45
|
+
# Define our getters and setters - these are the only methods Maintain will
|
46
|
+
# stomp on if you've already defined them. This is because they're how
|
47
|
+
# Maintain works.
|
45
48
|
class_eval <<-EOC, __FILE__
|
46
49
|
def #{attribute}=(value)
|
47
50
|
# Find the maintainer on this attribute so we can use it to set values.
|
48
51
|
maintainer = self.class.maintainers[:#{attribute}]
|
49
52
|
changed = #{attribute} != value
|
53
|
+
|
50
54
|
# Run the exit hook if we're changing the value
|
51
55
|
maintainer.hook(:exit, #{attribute}.name, self) if changed
|
52
56
|
|
53
|
-
# Then set the value itself. Maintainer::State will return the value
|
54
|
-
# so if we're setting to nil we get rid of the attribute
|
55
|
-
# needed and we want the getter to return nil in
|
57
|
+
# Then set the value itself. Maintainer::State will return the value
|
58
|
+
# you set, so if we're setting to nil we get rid of the attribute
|
59
|
+
# entirely - it's not needed and we want the getter to return nil in
|
60
|
+
# that case.
|
56
61
|
#{attribute}.set_value(value)
|
57
62
|
|
58
63
|
# Allow the back end to write values in an ORM-specific way
|
@@ -60,8 +65,8 @@ module Maintain
|
|
60
65
|
maintainer.back_end.write(self, :#{attribute}, #{attribute}.value)
|
61
66
|
end
|
62
67
|
|
63
|
-
# Last but not least, run the enter hooks for the new value - cause
|
64
|
-
# we do.
|
68
|
+
# Last but not least, run the enter hooks for the new value - cause
|
69
|
+
# that's how we do.
|
65
70
|
maintainer.hook(:enter, #{attribute}.name, self) if changed
|
66
71
|
end
|
67
72
|
|
@@ -73,14 +78,21 @@ module Maintain
|
|
73
78
|
class_eval <<-EOC, __FILE__
|
74
79
|
class << self
|
75
80
|
def maintain_#{attribute}
|
76
|
-
@#{attribute} ||= maintainers[:#{attribute}].states.sort
|
81
|
+
@#{attribute} ||= maintainers[:#{attribute}].states.sort do |a, b|
|
82
|
+
a_compare = a[1][:compare_value] || a[1][:value]
|
83
|
+
b_compare = b[1][:compare_value] || b[1][:value]
|
84
|
+
a_compare <=> b_compare
|
85
|
+
end.map do |key, value|
|
86
|
+
key == value[:value] ? key : [key, value[:value]]
|
87
|
+
end
|
77
88
|
end
|
78
89
|
#{"alias :#{attribute} :maintain_#{attribute}" unless respond_to?(attribute)}
|
79
90
|
end
|
80
91
|
EOC
|
81
92
|
|
82
|
-
# Last! Not least! Save our maintainer directly on this class. We'll use it
|
83
|
-
# and we'll also modify it instead of
|
93
|
+
# Last! Not least! Save our maintainer directly on this class. We'll use it
|
94
|
+
# in our setters (as in above) and we'll also modify it instead of
|
95
|
+
# replacing it outright, so subclasses or mixins can extend functionality
|
84
96
|
# without replacing it.
|
85
97
|
maintainers[attribute.to_sym] = maintainer
|
86
98
|
end
|
@@ -98,10 +110,13 @@ module Maintain
|
|
98
110
|
end
|
99
111
|
end
|
100
112
|
|
101
|
-
if
|
102
|
-
|
103
|
-
|
104
|
-
|
113
|
+
if !const_defined?(:VERSION)
|
114
|
+
version_path = File.join(File.dirname(__FILE__), '..', 'VERSION')
|
115
|
+
if File.file?(version_path)
|
116
|
+
VERSION = File.read(version_path).strip
|
117
|
+
else
|
118
|
+
VERSION = '0.3.0'
|
119
|
+
end
|
105
120
|
end
|
106
121
|
end
|
107
122
|
|
data/lib/maintain/backend.rb
CHANGED
@@ -13,16 +13,6 @@ module Maintain
|
|
13
13
|
end
|
14
14
|
# If it exists, extend it with Maintain methods automatically
|
15
15
|
owner.extend Maintain
|
16
|
-
# TODO: Try and remember why I did this
|
17
|
-
# if owner.is_a? Module
|
18
|
-
# owner.class_eval do
|
19
|
-
# class << self
|
20
|
-
# include Maintain
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
# else
|
24
|
-
# owner.extend Maintain
|
25
|
-
# end
|
26
16
|
end
|
27
17
|
end
|
28
18
|
|
@@ -58,8 +48,8 @@ module Maintain
|
|
58
48
|
end
|
59
49
|
end
|
60
50
|
|
61
|
-
# Detect if we've loaded a backend for this class - that means if its
|
62
|
-
# parent classes include any of our back-end classes.
|
51
|
+
# Detect if we've loaded a backend for this class - that means if its
|
52
|
+
# ancestors or parent classes include any of our back-end classes.
|
63
53
|
def detect(owner)
|
64
54
|
ancestors = owner.ancestors.map(&:to_s)
|
65
55
|
# While owner does not refer to "Object"
|
@@ -3,26 +3,18 @@ module Maintain
|
|
3
3
|
class ActiveRecord < Maintain::Backend::Base
|
4
4
|
def aggregate(maintainee, name, attribute, states, options = {})
|
5
5
|
# named_scope will handle the array of states as "IN" in SQL
|
6
|
-
state(maintainee, name, attribute, states, options.merge(:
|
6
|
+
state(maintainee, name, attribute, states, options.merge(dirty: false))
|
7
7
|
end
|
8
8
|
|
9
9
|
def on(maintainee, attribute, event, state, method, options)
|
10
10
|
attribute_check = "#{attribute}#{"_was" if event == :exit}_#{state}?"
|
11
11
|
hook_method = options[:after] ? :after : :before
|
12
|
-
maintainee.send("#{hook_method}_save", method, :
|
12
|
+
maintainee.send("#{hook_method}_save", method, if: lambda {|instance|
|
13
13
|
if instance.send("#{attribute}_changed?") && instance.send(attribute_check)
|
14
14
|
if options[:if]
|
15
|
-
|
16
|
-
instance.instance_eval(&options[:if])
|
17
|
-
else
|
18
|
-
instance.send(options[:if])
|
19
|
-
end
|
15
|
+
Maintainer.call_method_or_proc(options[:if], instance)
|
20
16
|
elsif options[:unless]
|
21
|
-
|
22
|
-
!instance.instance_eval(&options[:unless])
|
23
|
-
else
|
24
|
-
!instance.send(options[:unless])
|
25
|
-
end
|
17
|
+
!Maintainer.call_method_or_proc(options[:unless], instance)
|
26
18
|
else
|
27
19
|
true
|
28
20
|
end
|
@@ -37,11 +29,19 @@ module Maintain
|
|
37
29
|
end
|
38
30
|
|
39
31
|
def state(maintainee, name, attribute, value, options = {})
|
40
|
-
options = {:
|
41
|
-
conditions = {:
|
42
|
-
|
43
|
-
|
44
|
-
|
32
|
+
options = {dirty: true}.merge(options)
|
33
|
+
conditions = {conditions: {attribute => value}}
|
34
|
+
version = defined?(::ActiveRecord::VERSION) && ::ActiveRecord::VERSION::STRING
|
35
|
+
force = !maintainee.respond_to?(name) || options[:force]
|
36
|
+
if version && version >= '3'
|
37
|
+
where = "lambda { where(#{conditions[:conditions].inspect}) }"
|
38
|
+
maintainee.class_eval "scope :#{name}, #{where}" if force
|
39
|
+
maintainee.class_eval "scope :#{attribute}_#{name}, #{where}"
|
40
|
+
else
|
41
|
+
maintainee.named_scope(name, conditions)
|
42
|
+
maintainee.named_scope("#{attribute}_#{name}", conditions)
|
43
|
+
end
|
44
|
+
|
45
45
|
if options[:dirty]
|
46
46
|
maintainee.class_eval <<-dirty_tracker
|
47
47
|
def #{attribute}_was_#{name}?
|
@@ -11,7 +11,7 @@ module Maintain
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def state(maintainee, name, attribute, value)
|
14
|
-
conditions = {:
|
14
|
+
conditions = {conditions: {attribute => value}}
|
15
15
|
maintainee.class_eval <<-scope
|
16
16
|
def self.#{name}
|
17
17
|
all(#{conditions.inspect})
|
@@ -4,7 +4,9 @@ module Maintain
|
|
4
4
|
include Enumerable
|
5
5
|
|
6
6
|
def to_a
|
7
|
-
@state.states.select
|
7
|
+
@state.states.select do |key, options|
|
8
|
+
options[:value] & @value > 0
|
9
|
+
end.map(&:first)
|
8
10
|
end
|
9
11
|
|
10
12
|
def each(&block)
|
@@ -22,7 +24,10 @@ module Maintain
|
|
22
24
|
|
23
25
|
protected
|
24
26
|
def bitmask_for(states)
|
25
|
-
Array(states).compact.map
|
27
|
+
bitmask_values = Array(states).compact.map do |value|
|
28
|
+
value_for(value)
|
29
|
+
end.compact.sort
|
30
|
+
bitmask_values.inject(0) {|total, mask| total | mask.to_i }
|
26
31
|
end
|
27
32
|
|
28
33
|
def compare_value
|
data/lib/maintain/maintainer.rb
CHANGED
@@ -3,18 +3,31 @@ module Maintain
|
|
3
3
|
class Maintainer
|
4
4
|
attr_reader :back_end
|
5
5
|
|
6
|
+
class << self
|
7
|
+
def call_method_or_proc(method, instance)
|
8
|
+
if method.is_a?(Proc)
|
9
|
+
instance.instance_eval(&method)
|
10
|
+
else
|
11
|
+
instance.send(method)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
6
16
|
def aggregate(name, conditions, options = {})
|
7
17
|
if conditions.is_a?(Hash) && conditions.has_key?(:as)
|
8
18
|
options = conditions
|
9
19
|
conditions = options[:as]
|
10
20
|
end
|
11
21
|
aggregates[name] = conditions
|
12
|
-
|
13
|
-
#
|
22
|
+
|
23
|
+
# Now we're going to add proxies to test for state being in this
|
24
|
+
# aggregate. Don't create this method unless it doesn't exist.
|
14
25
|
boolean_method = "#{name}?"
|
15
26
|
if method_free?(boolean_method)
|
16
|
-
# Define it if'n it don't already
|
17
|
-
#
|
27
|
+
# Define it if'n it don't already exist! These are just proxies - so
|
28
|
+
# Foo.maintains(:state) { state :awesome } will now have
|
29
|
+
# Foo.new.awesome?. But that's really just a proxy for
|
30
|
+
# Foo.new.state.awesome?
|
18
31
|
# So they're just shortcuts for brevity's sake.
|
19
32
|
maintainee.class_eval <<-EOC
|
20
33
|
def #{boolean_method}
|
@@ -22,9 +35,21 @@ module Maintain
|
|
22
35
|
end
|
23
36
|
EOC
|
24
37
|
end
|
38
|
+
|
25
39
|
# Now define the state
|
26
40
|
if back_end
|
27
|
-
|
41
|
+
conditions = conditions.select { |value| states.has_key?(value) }
|
42
|
+
conditions = conditions.map do |value|
|
43
|
+
if states[value][:value].is_a?(Symbol)
|
44
|
+
states[value][:value].to_s
|
45
|
+
else
|
46
|
+
states[value][:value]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
conditions = conditions.compact
|
50
|
+
back_end.aggregate(maintainee, name, @attribute, conditions, {
|
51
|
+
force: options[:force]
|
52
|
+
})
|
28
53
|
end
|
29
54
|
end
|
30
55
|
|
@@ -57,11 +82,16 @@ module Maintain
|
|
57
82
|
end
|
58
83
|
|
59
84
|
def hook(event, state, instance)
|
60
|
-
if state && state.to_s.strip != '' && hooks[state.to_sym]
|
85
|
+
if state && state.to_s.strip != '' && hooks[state.to_sym]
|
86
|
+
hook_definitions = hooks[state.to_sym][event.to_sym] || []
|
61
87
|
hook_definitions.each do |hook_definition|
|
62
|
-
|
63
|
-
|
64
|
-
|
88
|
+
if hook_definition[:if]
|
89
|
+
next unless call_method_or_proc(hook_definition[:if], instance)
|
90
|
+
end
|
91
|
+
if hook_definition[:unless]
|
92
|
+
next if call_method_or_proc(hook_definition[:unless], instance)
|
93
|
+
end
|
94
|
+
call_method_or_proc(hook_definition[:method], instance)
|
65
95
|
end
|
66
96
|
end
|
67
97
|
end
|
@@ -86,7 +116,7 @@ module Maintain
|
|
86
116
|
end
|
87
117
|
|
88
118
|
def on(*args, &block)
|
89
|
-
options = {:
|
119
|
+
options = {when: :before}.merge(args.last.is_a?(Hash) ? args.pop : {})
|
90
120
|
event, state = args.shift, args.shift
|
91
121
|
method = args.shift
|
92
122
|
if block_given?
|
@@ -97,7 +127,7 @@ module Maintain
|
|
97
127
|
else
|
98
128
|
hooks[state.to_sym] ||= {}
|
99
129
|
hooks[state.to_sym][event.to_sym] ||= []
|
100
|
-
method_hash = {:
|
130
|
+
method_hash = {method: method}.merge(options)
|
101
131
|
if old_definition = hooks[state.to_sym][event.to_sym].find{|hook| hook[:method] == method}
|
102
132
|
old_definition.merge!(method_hash)
|
103
133
|
else
|
@@ -127,14 +157,15 @@ module Maintain
|
|
127
157
|
integer(true)
|
128
158
|
end
|
129
159
|
value ||= name
|
130
|
-
states[name] = {:
|
160
|
+
states[name] = {compare_value: !bitmask? && value.is_a?(Integer) ? value : @increment, value: value}
|
131
161
|
@increment += 1
|
132
162
|
if back_end
|
133
|
-
back_end.state maintainee, name, @attribute, value.is_a?(Symbol) ? value.to_s : value, :
|
163
|
+
back_end.state maintainee, name, @attribute, value.is_a?(Symbol) ? value.to_s : value, force: options[:force]
|
134
164
|
end
|
135
165
|
|
136
|
-
# We need the states hash to contain the compare_value for this guy
|
137
|
-
#
|
166
|
+
# We need the states hash to contain the compare_value for this guy
|
167
|
+
# before we can set defaults on the bitmask, since the default should
|
168
|
+
# actually be a bitmask of all possible default states
|
138
169
|
if options.has_key?(:default)
|
139
170
|
default(name)
|
140
171
|
end
|
@@ -147,26 +178,27 @@ module Maintain
|
|
147
178
|
on :exit, name.to_sym, options.delete(:exit)
|
148
179
|
end
|
149
180
|
|
150
|
-
# Now we're going
|
151
|
-
# method of their name doesn't already exist.
|
181
|
+
# Now we're going tests for state. Shortcuts to these methods only get
|
182
|
+
# added if a method of their name doesn't already exist.
|
152
183
|
boolean_method = "#{name}?"
|
153
|
-
|
184
|
+
shortcut = options[:force] || method_free?(boolean_method)
|
154
185
|
maintainee.class_eval <<-EOC
|
155
186
|
def #{@attribute}_#{boolean_method}
|
156
|
-
#{@attribute}
|
187
|
+
#{@attribute} == #{value.inspect}
|
157
188
|
end
|
158
|
-
#{"alias :#{boolean_method} :#{@attribute}_#{boolean_method}" if
|
189
|
+
#{"alias :#{boolean_method} :#{@attribute}_#{boolean_method}" if shortcut}
|
159
190
|
EOC
|
160
191
|
|
161
|
-
# Last but not least, add bang methods to automatically convert to state.
|
162
|
-
# methods above, these only get added if they're not already
|
192
|
+
# Last but not least, add bang methods to automatically convert to state.
|
193
|
+
# Like boolean methods above, these only get added if they're not already
|
194
|
+
# things that are things.
|
163
195
|
bang_method = "#{name}!"
|
164
|
-
|
196
|
+
shortcut = options[:force] || method_free?(bang_method)
|
165
197
|
maintainee.class_eval <<-EOC
|
166
198
|
def #{@attribute}_#{bang_method}
|
167
|
-
|
199
|
+
self.#{@attribute} = #{value.inspect}
|
168
200
|
end
|
169
|
-
#{"alias :#{bang_method} :#{@attribute}_#{bang_method}" if
|
201
|
+
#{"alias :#{bang_method} :#{@attribute}_#{bang_method}" if shortcut}
|
170
202
|
EOC
|
171
203
|
end
|
172
204
|
|
@@ -175,7 +207,10 @@ module Maintain
|
|
175
207
|
end
|
176
208
|
|
177
209
|
def value(instance, initial = nil)
|
178
|
-
|
210
|
+
if back_end
|
211
|
+
initial = back_end.read(instance, @attribute)
|
212
|
+
end
|
213
|
+
initial ||= initial || @default
|
179
214
|
if bitmask?
|
180
215
|
BitmaskValue.new(self, initial || 0)
|
181
216
|
elsif integer?
|
@@ -198,17 +233,14 @@ module Maintain
|
|
198
233
|
# Ugly hack so we don't fetch it 100 times for no reason
|
199
234
|
maintainee_class = maintainee
|
200
235
|
if class_method
|
201
|
-
|
202
|
-
methods = maintainee_class.public_methods
|
236
|
+
return false if maintainee_class.respond_to?(method_name)
|
237
|
+
methods = maintainee_class.public_methods
|
238
|
+
methods += maintainee_class.private_methods
|
239
|
+
methods += maintainee_class.protected_methods
|
203
240
|
else
|
204
|
-
respond_to = false
|
205
241
|
methods = maintainee_class.instance_methods
|
206
|
-
# methods = %w(instance_methods public_instance_methods private_instance_methods protected_instance_methods).inject([]) do |methods, method|
|
207
|
-
# methods + maintainee_class.send(method)
|
208
|
-
# end.uniq
|
209
242
|
end
|
210
|
-
|
211
|
-
!respond_to && !methods.include?(method_name) && !methods.include?(method_name.to_sym)
|
243
|
+
!methods.include?(method_name.to_sym)
|
212
244
|
end
|
213
245
|
|
214
246
|
def method_missing(method, *args)
|
@@ -220,12 +252,8 @@ module Maintain
|
|
220
252
|
end
|
221
253
|
|
222
254
|
private
|
223
|
-
def
|
224
|
-
|
225
|
-
instance.instance_eval(&method)
|
226
|
-
else
|
227
|
-
instance.send(method)
|
228
|
-
end
|
255
|
+
def call_method_or_proc(method, instance)
|
256
|
+
self.class.call_method_or_proc(method, instance)
|
229
257
|
end
|
230
258
|
end
|
231
|
-
end
|
259
|
+
end
|