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