jeffp-enumerated_attribute 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,14 @@
1
1
  == master
2
2
 
3
+ == 0.1.7 / 2009-07-17
4
+
5
+ * Added abbreviated predicate methods
6
+ * Added and cleaned documentation
7
+
8
+ == 0.1.6 / 2009-07-15
9
+
10
+ * Refactored
11
+
3
12
  == 0.1.5 / 2009-07-14
4
13
 
5
14
  * Refactored to remove unnecessary class methods from class
@@ -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 support methods.
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 support methods are automatically generated, resulting in better
26
- encapsulation and quicker, more readable code.
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
- * Dynamically-generated support methods
31
- * Run-time generated attribute predicates
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.gear_is_in_neutral? # => true
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, including an incrementor and decrementor. These methods are
91
- demonstrated below using the Tractor class defined above:
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
- ==== Using Attribute Predicates
122
+ ==== Dynamically-Generating Predicates Methods
123
123
 
124
- Attribute predicates are methods used to query the state of the attribute,
125
- for instance, gear_is_neutral? is a predicate method for the gear attribute.
126
- The plugin will evaluate and respond to predicate methods
127
- for any attribute defined with it. Predicate methods are not pre-generated. By
128
- adhering to a specific format, the plugin can recognize attribute predicates
129
- and generate the methods dynamically. +enumerated_attribute+ recognizes
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, :third]
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, :third].
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, :third]
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, :third]
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, :third]
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
- def self.method_missing(methId, *args, &blk)
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.6'
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|
@@ -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
- # def included(klass); klass.extend(ClassMethods); end
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
- if @@enumerated_attribute_values.key?(attr_sym)
128
- @@enumerated_attribute_values[attr_sym].each do |v|
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
- return(false) unless (parts = parse_dynamic_method_parts(meth_name))
157
+ parts = parse_dynamic_method_parts!(meth_name)
158
+ return(false) unless parts
145
159
 
146
- negated = !!parts[1].downcase.match(/_not_/)
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
- #end
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
@@ -1,3 +1,5 @@
1
+ #irb -r cfg ==> to work configure for working in IRB
2
+ $: << '../../lib'
1
3
  require 'test_in_memory'
2
- require '../../lib/enumerated_attribute'
4
+ require 'enumerated_attribute'
3
5
  require 'race_car'
@@ -0,0 +1,6 @@
1
+ #irb -r cfg ==> to work configure for working in IRB
2
+ $: << '../lib'
3
+ require 'enumerated_attribute'
4
+ require 'tractor'
5
+ require 'car'
6
+ require 'plural'
@@ -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
@@ -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.6
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-14 00:00:00 -07:00
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