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.
@@ -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