jeffp-enumerated_attribute 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/CHANGELOG.rdoc +9 -0
- data/README.rdoc +45 -22
- data/Rakefile +2 -25
- data/lib/enumerated_attribute.rb +0 -6
- data/lib/enumerated_attribute/attribute.rb +33 -13
- data/spec/active_record/cfg.rb +3 -1
- data/spec/cfg.rb +6 -0
- data/spec/poro_spec.rb +25 -0
- data/spec/tractor.rb +2 -0
- metadata +3 -2
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= enumerated_attribute
|
2
2
|
|
3
|
-
+enumerated_attribute+ simplifies the definition of enumeration-based attributes, their accessors, initializers and common predicate and
|
3
|
+
+enumerated_attribute+ simplifies the definition of enumeration-based attributes, their accessors, initializers and common predicate and enumeration methods.
|
4
4
|
|
5
5
|
== Resources
|
6
6
|
|
@@ -22,13 +22,13 @@ costs and wastes time.
|
|
22
22
|
|
23
23
|
+enumerated_attribute+ simplifies the definition of enumerated attributes by emphasizing
|
24
24
|
convention and DRYing the implementation. Repetitive code such as initializers, accessors,
|
25
|
-
predicate and
|
26
|
-
encapsulation
|
25
|
+
predicate and enumeration methods are automatically generated, resulting in better
|
26
|
+
encapsulation, quicker implementation and cleaner code.
|
27
27
|
|
28
28
|
Features include:
|
29
29
|
* Short and simple definition
|
30
|
-
*
|
31
|
-
*
|
30
|
+
* Auto-defined attribute methods
|
31
|
+
* Dynamically-generated predicate methods
|
32
32
|
* Attribute initialization
|
33
33
|
* Method definition short-hand (DSL)
|
34
34
|
* ActiveRecord integration
|
@@ -48,7 +48,7 @@ Here's a quick example of what +enumerated_attribute+ can do:
|
|
48
48
|
|
49
49
|
t = Tractor.new
|
50
50
|
t.gear # => :neutral
|
51
|
-
t.
|
51
|
+
t.gear_is_neutral? # => true
|
52
52
|
t.driving? # => false
|
53
53
|
t.upshift # => :first
|
54
54
|
t.driving? # => true
|
@@ -87,8 +87,8 @@ form of +enumerated_attribute+ looks like this:
|
|
87
87
|
Defining the attribute :gear has done a number things.
|
88
88
|
It has generated an instance variable '@gear', read/write accessors for the
|
89
89
|
attribute and support methods
|
90
|
-
for the enumeration,
|
91
|
-
demonstrated below using the Tractor class
|
90
|
+
for the enumeration, such as incrementor and decrementor methods. These methods are
|
91
|
+
demonstrated below using the Tractor class above:
|
92
92
|
|
93
93
|
Tractor.instance_methods(false)
|
94
94
|
# =>["gear", "gear=", "gears", "gear_next", "gear_previous", ...
|
@@ -119,15 +119,15 @@ of the enumeration array. For example:
|
|
119
119
|
t.gear_next # => :reverse
|
120
120
|
|
121
121
|
|
122
|
-
====
|
122
|
+
==== Dynamically-Generating Predicates Methods
|
123
123
|
|
124
|
-
|
125
|
-
for instance, gear_is_neutral? is a predicate method
|
126
|
-
|
127
|
-
|
128
|
-
adhering to a
|
129
|
-
and
|
130
|
-
methods of the following format:
|
124
|
+
Predicate methods are methods that query the state of the attribute,
|
125
|
+
for instance, gear_is_neutral? is a predicate method that returns 'true' if
|
126
|
+
the gear attribute is in the :neutral state.
|
127
|
+
By default, predicate methods are not predefined, instead, they are dynamically generated.
|
128
|
+
The plugin will evaluate and respond to methods adhering to a format that it
|
129
|
+
can associate with an attribute name and one of the attribute's enumeration values.
|
130
|
+
+enumerated_attribute+ recognizes predicate methods of the following format:
|
131
131
|
|
132
132
|
{attribute name}_{anything}_{enumeration value}?
|
133
133
|
|
@@ -157,6 +157,27 @@ Basically, the shortest acceptable form of a predicate method is:
|
|
157
157
|
t.gear_not_neutral? # => false
|
158
158
|
|
159
159
|
|
160
|
+
==== Abbreviating Predicate Methods
|
161
|
+
|
162
|
+
In the case that an enumeration value is associated with only one
|
163
|
+
attribute, the attribute name can be left out of the predicate method name.
|
164
|
+
The plugin will infer the attribute from the enum value in the method name.
|
165
|
+
The abbreviate format can be written like this:
|
166
|
+
|
167
|
+
{anything}{_}{enumeration value}?
|
168
|
+
|
169
|
+
And results in the following possibilities:
|
170
|
+
|
171
|
+
t.gear = :neutral
|
172
|
+
t.neutral? # => true
|
173
|
+
t.is_neutral? # => true
|
174
|
+
t.not_neutral? # => false
|
175
|
+
t.is_not_neutral? # => false
|
176
|
+
|
177
|
+
Calling the abbreviated form of the method containing an enumeration value
|
178
|
+
belonging to two or more attributes throws an AmbiguousMethod error.
|
179
|
+
|
180
|
+
|
160
181
|
==== Initializing Attributes
|
161
182
|
|
162
183
|
The plugin provides a few ways to eliminate setting the initial value of the attribute in
|
@@ -233,7 +254,7 @@ the plugin provides a short-hand for defining these methods in the
|
|
233
254
|
class Tractor
|
234
255
|
enum_attr :gear, %w(reverse ^neutral first second over_drive) do
|
235
256
|
parked? :neutral
|
236
|
-
driving? [:first, :second, :
|
257
|
+
driving? [:first, :second, :over_drive]
|
237
258
|
end
|
238
259
|
end
|
239
260
|
|
@@ -246,7 +267,7 @@ the plugin's short-hand.
|
|
246
267
|
The first method, parked?, defines a method which evaluates
|
247
268
|
the code {@gear == :neutral}. The second method, driving?, evaluates
|
248
269
|
to true if the attribute is set to one of the enumeration values defined in the array
|
249
|
-
[:first, :second, :
|
270
|
+
[:first, :second, :over_drive].
|
250
271
|
|
251
272
|
The same short-hand can be used to define methods where the attribute 'is not' equal to the
|
252
273
|
indicated value or 'is not' included in the array of values.
|
@@ -254,7 +275,7 @@ indicated value or 'is not' included in the array of values.
|
|
254
275
|
class Tractor
|
255
276
|
enum_attr :gear, %w(reverse ^neutral first second over_drive) do
|
256
277
|
not_parked? is_not :neutral
|
257
|
-
not_driving? is_not [:first, :second, :
|
278
|
+
not_driving? is_not [:first, :second, :over_drive]
|
258
279
|
end
|
259
280
|
end
|
260
281
|
|
@@ -267,7 +288,7 @@ a block can be used to define the method body.
|
|
267
288
|
class Tractor
|
268
289
|
enum_attr :gear, %w(reverse ^neutral first second over_drive) do
|
269
290
|
parked? :neutral
|
270
|
-
driving? [:first, :second, :
|
291
|
+
driving? [:first, :second, :over_drive]
|
271
292
|
end
|
272
293
|
enum_attr :plow, %w(^up down), :plural=>:plow_values do
|
273
294
|
plowing? { self.gear_is_in_first? && @plow == :down }
|
@@ -286,7 +307,7 @@ as bounded incrementor and decrementor of the gear attribute.
|
|
286
307
|
class Tractor
|
287
308
|
enum_attr :gear, %w(reverse ^neutral first second over_drive) do
|
288
309
|
parked? :neutral
|
289
|
-
driving? [:first, :second, :
|
310
|
+
driving? [:first, :second, :over_drive]
|
290
311
|
upshift { self.gear_is_in_over_drive? ? self.gear : self.gear_next }
|
291
312
|
downshift { self.driving? ? self.gear_previous : self.gear }
|
292
313
|
end
|
@@ -349,7 +370,9 @@ overwriting the plugin's methods. The best approach is shown here:
|
|
349
370
|
def self.new(*args)
|
350
371
|
...
|
351
372
|
end
|
352
|
-
|
373
|
+
|
374
|
+
private
|
375
|
+
def method_missing(methId, *args, &blk)
|
353
376
|
...
|
354
377
|
end
|
355
378
|
|
data/Rakefile
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
require 'rake/rdoctask'
|
3
3
|
require 'rake/gempackagetask'
|
4
4
|
require 'rake/contrib/sshpublisher'
|
5
|
-
|
5
|
+
|
6
6
|
spec = Gem::Specification.new do |s|
|
7
7
|
s.name = 'enumerated_attribute'
|
8
|
-
s.version = '0.1.
|
8
|
+
s.version = '0.1.7'
|
9
9
|
s.platform = Gem::Platform::RUBY
|
10
10
|
s.description = 'An enumerated attribute accessor'
|
11
11
|
s.summary = 'Add enumerated attributes with initialization, dynamic predicate methods, more ...'
|
@@ -44,29 +44,6 @@ namespace :spec do
|
|
44
44
|
task :all=>[:spec, :active_record]
|
45
45
|
end
|
46
46
|
|
47
|
-
=begin
|
48
|
-
desc "Test the #{spec.name} plugin."
|
49
|
-
Rake::TestTask.new(:test) do |t|
|
50
|
-
t.libs << 'lib'
|
51
|
-
t.libs << 'spec'
|
52
|
-
t.test_files = spec.test_files
|
53
|
-
t.verbose = true
|
54
|
-
end
|
55
|
-
|
56
|
-
begin
|
57
|
-
require 'rcov/rcovtask'
|
58
|
-
namespace :test do
|
59
|
-
desc "Test the #{spec.name} plugin with Rcov."
|
60
|
-
Rcov::RcovTask.new(:rcov) do |t|
|
61
|
-
t.libs << 'lib'
|
62
|
-
t.test_files = spec.test_files
|
63
|
-
t.rcov_opts << '--exclude="^(?!lib/)"'
|
64
|
-
t.verbose = true
|
65
|
-
end
|
66
|
-
end
|
67
|
-
rescue LoadError
|
68
|
-
end
|
69
|
-
=end
|
70
47
|
|
71
48
|
desc "Generate documentation for the #{spec.name} plugin."
|
72
49
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
data/lib/enumerated_attribute.rb
CHANGED
@@ -12,12 +12,6 @@ module EnumeratedAttribute
|
|
12
12
|
end
|
13
13
|
alias_method :enum_attr, :enumerated_attribute
|
14
14
|
|
15
|
-
#these implementations are for basic ruby objects - integrations (see Integrations::ActiveRecord and Integrations::Object) may alter them
|
16
|
-
#def define_enumerated_attribute_custom_method(symbol, attr_name, value, negated)
|
17
|
-
#private
|
18
|
-
#def define_enumerated_attribute_new_method
|
19
|
-
#def define_enumerated_attribute_writer_method name
|
20
|
-
#def define_enumerated_attribute_reader_method name
|
21
15
|
end
|
22
16
|
|
23
17
|
end
|
@@ -7,11 +7,10 @@ module EnumeratedAttribute
|
|
7
7
|
class IntegrationError < EnumeratedAttributeError; end
|
8
8
|
class InvalidEnumeration < EnumeratedAttributeError; end
|
9
9
|
class InvalidDefinition < EnumeratedAttributeError; end
|
10
|
+
class AmbiguousMethod < EnumeratedAttributeError; end
|
10
11
|
|
11
12
|
module Attribute
|
12
|
-
|
13
|
-
|
14
|
-
# module ClassMethods
|
13
|
+
|
15
14
|
private
|
16
15
|
def create_enumerated_attribute(*args, &block)
|
17
16
|
return if args.empty?
|
@@ -98,8 +97,8 @@ module EnumeratedAttribute
|
|
98
97
|
|
99
98
|
alias_method :respond_to_without_enumerated_attribute?, :respond_to?
|
100
99
|
def respond_to?(method)
|
101
|
-
respond_to_without_enumerated_attribute?(method) || !!parse_dynamic_method_parts(method.to_s)
|
102
|
-
end
|
100
|
+
respond_to_without_enumerated_attribute?(method) || (!!parse_dynamic_method_parts!(method.to_s) rescue false)
|
101
|
+
end
|
103
102
|
|
104
103
|
def initialize_enumerated_attributes(only_if_nil = false)
|
105
104
|
self.class.enumerated_attribute_initial_value_list.each do |k,v|
|
@@ -109,7 +108,7 @@ module EnumeratedAttribute
|
|
109
108
|
|
110
109
|
private
|
111
110
|
|
112
|
-
def parse_dynamic_method_parts(meth_name)
|
111
|
+
def parse_dynamic_method_parts!(meth_name)
|
113
112
|
return(nil) unless meth_name[-1, 1] == '?'
|
114
113
|
|
115
114
|
middle = meth_name.chop #remove the ?
|
@@ -120,17 +119,31 @@ module EnumeratedAttribute
|
|
120
119
|
attr = name; break
|
121
120
|
end
|
122
121
|
end
|
123
|
-
return (nil) unless attr
|
124
|
-
attr_sym = attr.to_sym
|
125
122
|
|
126
123
|
value = nil
|
127
|
-
|
128
|
-
|
124
|
+
attr_sym = attr ? attr.to_sym : nil
|
125
|
+
if (enum_values = @@enumerated_attribute_values[attr_sym] ) #nil if [nil]
|
126
|
+
enum_values.each do |v|
|
129
127
|
if middle.sub!(Regexp.new(v.to_s+"$"), "")
|
130
128
|
value = v; break
|
131
129
|
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
#search through enum values one at time and identify any ambiguities
|
133
|
+
@@enumerated_attribute_values.each do |attr_key,enums|
|
134
|
+
enums.each do|v|
|
135
|
+
if middle.match(v.to_s+"$")
|
136
|
+
raise(AmbiguousMethod, meth_name+" is ambiguous, use something like "+attr_sym.to_s+(middle[0,1]=='_'? '' : '_')+middle+"? or "+attr_key.to_s+(middle[0,1]=='_'? '' : '_')+middle+"?", caller) if attr_sym
|
137
|
+
attr_sym = attr_key
|
138
|
+
value = v
|
139
|
+
end
|
140
|
+
end
|
132
141
|
end
|
142
|
+
return (nil) unless attr_sym
|
143
|
+
attr = attr_sym.to_s
|
144
|
+
middle.sub!(Regexp.new(value.to_s+"$"), "")
|
133
145
|
end
|
146
|
+
|
134
147
|
unless value #check for nil?
|
135
148
|
return (nil) unless middle.sub!(Regexp.new('nil$'), "")
|
136
149
|
value = nil
|
@@ -141,9 +154,10 @@ module EnumeratedAttribute
|
|
141
154
|
|
142
155
|
def define_enumerated_attribute_dynamic_method(methId)
|
143
156
|
meth_name = methId.id2name
|
144
|
-
|
157
|
+
parts = parse_dynamic_method_parts!(meth_name)
|
158
|
+
return(false) unless parts
|
145
159
|
|
146
|
-
negated = !!parts[1].downcase.match(/
|
160
|
+
negated = !!parts[1].downcase.match(/(^|_)not_/)
|
147
161
|
value = parts[2] ? parts[2].to_sym : nil
|
148
162
|
self.class.define_enumerated_attribute_custom_method(methId, parts[0], value, negated)
|
149
163
|
|
@@ -203,6 +217,12 @@ module EnumeratedAttribute
|
|
203
217
|
|
204
218
|
end
|
205
219
|
end
|
206
|
-
|
220
|
+
|
221
|
+
#these methods are called by create_enumerated_attribute but defined by the integration (see Integrations::ActiveRecord and Integrations::Object) may alter them
|
222
|
+
#def define_enumerated_attribute_custom_method(symbol, attr_name, value, negated)
|
223
|
+
#private
|
224
|
+
#def define_enumerated_attribute_new_method
|
225
|
+
#def define_enumerated_attribute_writer_method name
|
226
|
+
#def define_enumerated_attribute_reader_method name
|
207
227
|
|
208
228
|
end
|
data/spec/active_record/cfg.rb
CHANGED
data/spec/cfg.rb
ADDED
data/spec/poro_spec.rb
CHANGED
@@ -26,6 +26,31 @@ describe "Plural" do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
describe "Tractor" do
|
29
|
+
|
30
|
+
it "should not raise errors for dynamic predicate methods missing attribute name" do
|
31
|
+
t=Tractor.new
|
32
|
+
lambda{ t.neutral?.should be_true }.should_not raise_error
|
33
|
+
lambda{ t.is_neutral?.should be_true }.should_not raise_error
|
34
|
+
lambda{ t.not_neutral?.should be_false}.should_not raise_error
|
35
|
+
t.gear = :first
|
36
|
+
t.neutral?.should be_false
|
37
|
+
t.not_neutral?.should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should raise AmbiguousMethod when calling :off?" do
|
41
|
+
t=Tractor.new
|
42
|
+
lambda { t.off? }.should raise_error(EnumeratedAttribute::AmbiguousMethod)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should raise AmbiguousMethod when calling :in_reverse?" do
|
46
|
+
t=Tractor.new
|
47
|
+
lambda {t.in_reverse?}.should raise_error(EnumeratedAttribute::AmbiguousMethod)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should raise AmbiguousMethod when calling :not_reverse?" do
|
51
|
+
t=Tractor.new
|
52
|
+
lambda {t.not_reverse?}.should raise_error(EnumeratedAttribute::AmbiguousMethod)
|
53
|
+
end
|
29
54
|
|
30
55
|
it "should initialize :gear for two instances of the same class" do
|
31
56
|
t=Tractor.new
|
data/spec/tractor.rb
CHANGED
@@ -20,6 +20,8 @@ class Tractor
|
|
20
20
|
upshift { self.gear_is_in_over_drive? ? self.gear : self.gear_next }
|
21
21
|
downshift { self.driving? ? self.gear_previous : self.gear }
|
22
22
|
end
|
23
|
+
|
24
|
+
enum_attr :pto, %w(reverse ^off forward)
|
23
25
|
|
24
26
|
enum_attr :plow, %w(^up down), :nil=>true do
|
25
27
|
plowing? { self.gear_is_in_first? && self.plow == :down }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jeffp-enumerated_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Patmon
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- spec/active_record/single_table_inheritance_spec.rb
|
40
40
|
- spec/active_record/test_in_memory.rb
|
41
41
|
- spec/car.rb
|
42
|
+
- spec/cfg.rb
|
42
43
|
- spec/new_and_method_missing_spec.rb
|
43
44
|
- spec/plural.rb
|
44
45
|
- spec/poro_spec.rb
|