pluginaweek-enumerate_by 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,10 @@
1
1
  == master
2
2
 
3
+ == 0.4.3 / 2009-06-14
4
+
5
+ * Add support for looking up enumerators by their symbol equivalent
6
+ * Fix incompatibility with Ruby 1.9
7
+ * Fix equality / xml serialization not working for non-string enumerators
3
8
  * Improve compatibility with the stable branch of Rails 2.3 [Michael Schuerig]
4
9
 
5
10
  == 0.4.2 / 2009-05-03
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/contrib/sshpublisher'
5
5
 
6
6
  spec = Gem::Specification.new do |s|
7
7
  s.name = 'enumerate_by'
8
- s.version = '0.4.2'
8
+ s.version = '0.4.3'
9
9
  s.platform = Gem::Platform::RUBY
10
10
  s.summary = 'Adds support for declaring an ActiveRecord class as an enumeration'
11
11
  s.description = s.summary
@@ -106,7 +106,7 @@ module EnumerateBy
106
106
  klass = reflection.klass
107
107
  attribute = reflection.primary_key_name
108
108
  id = if allow_multiple && enumerator.is_a?(Array)
109
- enumerator.map {|enumerator| klass.find_by_enumerator!(enumerator).id}
109
+ klass.find_all_by_enumerator!(enumerator).map(&:id)
110
110
  else
111
111
  klass.find_by_enumerator!(enumerator).id
112
112
  end
@@ -14,7 +14,21 @@ module EnumerateBy
14
14
  protected
15
15
  # Enumerator types are always strings
16
16
  def compute_type_with_enumerations
17
- enumeration_association? ? :string : compute_type_without_enumerations
17
+ if enumeration_association?
18
+ klass = @record.class.reflections[name.to_sym].klass
19
+ type = klass.columns_hash[klass.enumerator_attribute.to_s].type
20
+
21
+ case type
22
+ when :text
23
+ :string
24
+ when :time
25
+ :datetime
26
+ else
27
+ type
28
+ end
29
+ else
30
+ compute_type_without_enumerations
31
+ end
18
32
  end
19
33
 
20
34
  # Gets the real value representing the enumerator
data/lib/enumerate_by.rb CHANGED
@@ -57,8 +57,7 @@ module EnumerateBy
57
57
  # == Associations
58
58
  #
59
59
  # When using enumerations together with +belongs_to+ associations, the
60
- # enumerator value can be used as a shortcut for assigning the
61
- # association.
60
+ # enumerator value can be used as a shortcut for assigning the association.
62
61
  #
63
62
  # In addition, the enumerator value is automatically used during
64
63
  # serialization (xml and json) of the associated record instead of the
@@ -126,7 +125,7 @@ module EnumerateBy
126
125
  # Color.find_by_enumerator('red') # => #<Color id: 1, name: "red">
127
126
  # Color.find_by_enumerator('invalid') # => nil
128
127
  def find_by_enumerator(enumerator)
129
- first(:conditions => {enumerator_attribute => enumerator})
128
+ first(:conditions => {enumerator_attribute => typecast_enumerator(enumerator)})
130
129
  end
131
130
 
132
131
  # Finds the record that is associated with the given enumerator. If no
@@ -140,7 +139,7 @@ module EnumerateBy
140
139
  #
141
140
  # To avoid raising an exception on invalid enumerators, use +find_by_enumerator+.
142
141
  def find_by_enumerator!(enumerator)
143
- find_by_enumerator(enumerator) || raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute} #{enumerator.inspect}")
142
+ find_by_enumerator(enumerator) || raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute} #{typecast_enumerator(enumerator).inspect}")
144
143
  end
145
144
  alias_method :[], :find_by_enumerator!
146
145
 
@@ -148,10 +147,10 @@ module EnumerateBy
148
147
  #
149
148
  # For example,
150
149
  #
151
- # Color.find_all_by_enumerator('red', 'green') # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">]
152
- # Color.find_all_by_enumerator('invalid') # => []
150
+ # Color.find_all_by_enumerator(['red', 'green']) # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">]
151
+ # Color.find_all_by_enumerator('invalid') # => []
153
152
  def find_all_by_enumerator(enumerators)
154
- all(:conditions => {enumerator_attribute => enumerators})
153
+ all(:conditions => {enumerator_attribute => typecast_enumerator(enumerators)})
155
154
  end
156
155
 
157
156
  # Finds records with the given enumerators. If no record is found for a
@@ -160,13 +159,14 @@ module EnumerateBy
160
159
  #
161
160
  # For Example,
162
161
  #
163
- # Color.find_all_by_enumerator!('red', 'green') # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">]
162
+ # Color.find_all_by_enumerator!(['red', 'green']) # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">]
164
163
  # Color.find_all_by_enumerator!('invalid') # => ActiveRecord::RecordNotFound: Couldn't find Color with name(s) "invalid"
165
164
  #
166
165
  # To avoid raising an exception on invalid enumerators, use +find_all_by_enumerator+.
167
166
  def find_all_by_enumerator!(enumerators)
167
+ enumerators = [enumerators].flatten
168
168
  records = find_all_by_enumerator(enumerators)
169
- missing = [enumerators].flatten - records.map(&:enumerator)
169
+ missing = enumerators - records.map(&:enumerator)
170
170
  missing.empty? ? records : raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute}(s) #{missing.map(&:inspect).to_sentence}")
171
171
  end
172
172
 
@@ -178,9 +178,9 @@ module EnumerateBy
178
178
  [:find_by_sql, :exists?, :calculate].each do |method|
179
179
  define_method(method) do |*args|
180
180
  if EnumerateBy.perform_caching && perform_enumerator_caching
181
- enumerator_cache_store.fetch([method] + args) { super }
181
+ enumerator_cache_store.fetch([method] + args) { super(*args) }
182
182
  else
183
- super
183
+ super(*args)
184
184
  end
185
185
  end
186
186
  end
@@ -195,6 +195,20 @@ module EnumerateBy
195
195
  ensure
196
196
  self.perform_enumerator_caching = old
197
197
  end
198
+
199
+ private
200
+ # Typecasts the given enumerator to its actual value stored in the
201
+ # database. This will only convert symbols to strings. All other values
202
+ # will remain in the same type.
203
+ def typecast_enumerator(enumerator)
204
+ if enumerator.is_a?(Array)
205
+ enumerator.flatten!
206
+ enumerator.map! {|value| typecast_enumerator(value)}
207
+ enumerator
208
+ else
209
+ enumerator.is_a?(Symbol) ? enumerator.to_s : enumerator
210
+ end
211
+ end
198
212
  end
199
213
 
200
214
  module Bootstrapped
@@ -295,8 +309,8 @@ module EnumerateBy
295
309
  # * Dirty attributes
296
310
  #
297
311
  # Also note that records are created directly without creating instances
298
- # of the model. As a result, all of the attributes for the record must
299
- # be specified.
312
+ # of the model. As a result, all of the attributes for the record must be
313
+ # specified.
300
314
  #
301
315
  # This produces a significant performance increase when bootstrapping more
302
316
  # than several hundred records.
@@ -351,7 +365,7 @@ module EnumerateBy
351
365
  # a String, then it is compared against the enumerator. Otherwise,
352
366
  # ActiveRecord's default equality comparator is used.
353
367
  def ==(arg)
354
- arg.is_a?(String) ? self == self.class.find_by_enumerator!(arg) : super
368
+ arg.nil? || arg.is_a?(self.class) ? super : self == self.class.find_by_enumerator!(arg)
355
369
  end
356
370
 
357
371
  # Determines whether this enumeration is in the given list.
@@ -0,0 +1,3 @@
1
+ class CarPart < ActiveRecord::Base
2
+ enumerate_by :number
3
+ end
@@ -0,0 +1,3 @@
1
+ class Order < ActiveRecord::Base
2
+ belongs_to :car_part
3
+ end
@@ -0,0 +1,12 @@
1
+ class CreateCarParts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :car_parts do |t|
4
+ t.string :name
5
+ t.integer :number
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :car_parts
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class CreateOrders < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :orders do |t|
4
+ t.string :state
5
+ t.references :car_part
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :orders
11
+ end
12
+ end
data/test/factory.rb CHANGED
@@ -40,9 +40,22 @@ module Factory
40
40
  )
41
41
  end
42
42
 
43
+ build CarPart do |attributes|
44
+ attributes.reverse_merge!(
45
+ :number => 123321
46
+ )
47
+ end
48
+
43
49
  build Color do |attributes|
44
50
  attributes.reverse_merge!(
45
51
  :name => 'red'
46
52
  )
47
53
  end
54
+
55
+ build Order do |attributes|
56
+ attributes[:car_part] = create_car_part unless attributes.include?(:car_part)
57
+ attributes.reverse_merge!(
58
+ :state => 'pending'
59
+ )
60
+ end
48
61
  end
@@ -23,7 +23,12 @@ class ModelWithBelongsToAssociationTest < ActiveRecord::TestCase
23
23
  end
24
24
 
25
25
  def test_should_use_nil_if_enumeration_does_not_exist
26
- @car.color = 'blue'
26
+ assert_nothing_raised { @car.color = 'blue' }
27
+ assert_nil @car.color
28
+ end
29
+
30
+ def test_should_allow_nil
31
+ assert_nothing_raised { @car.color = nil }
27
32
  assert_nil @car.color
28
33
  end
29
34
 
@@ -12,17 +12,49 @@ class EnumerationWithFinderConditionsTest < ActiveRecord::TestCase
12
12
  assert_equal @red_car, Car.find_by_color('red')
13
13
  end
14
14
 
15
+ def test_should_raise_exception_for_invalid_enumeration_in_dynamic_finders
16
+ assert_raise(ActiveRecord::RecordNotFound) { Car.find_by_color('invalid') }
17
+ end
18
+
19
+ def test_should_still_allow_non_enumeration_in_dynamic_finders
20
+ assert_equal @red_car, Car.find_by_id(@red_car.id)
21
+ end
22
+
15
23
  def test_should_replace_multiple_enumerations_in_dynamic_finders
16
24
  assert_equal [@red_car, @blue_car], Car.find_all_by_color(%w(red blue))
17
25
  end
18
26
 
27
+ def test_should_raise_exception_for_any_invalid_enumeration_in_dynamic_finders
28
+ assert_raise(ActiveRecord::RecordNotFound) { Car.find_all_by_color(%w(red invalid)) }
29
+ end
30
+
31
+ def test_should_still_allow_multiple_non_enumerations_in_dynamic_finders
32
+ assert_equal [@red_car, @blue_car], Car.find_all_by_id([@red_car.id, @blue_car.id])
33
+ end
34
+
19
35
  def test_should_replace_enumerations_in_find_conditions
20
36
  assert_equal @red_car, Car.first(:conditions => {:color => 'red'})
21
37
  end
22
38
 
39
+ def test_should_raise_exception_for_invalid_enumeration_in_find_conditions
40
+ assert_raise(ActiveRecord::RecordNotFound) { Car.first(:conditions => {:color => 'invalid'}) }
41
+ end
42
+
43
+ def test_should_still_allow_non_enumeration_in_find_conditions
44
+ assert_equal @red_car, Car.first(:conditions => {:id => @red_car.id})
45
+ end
46
+
23
47
  def test_should_replace_multiple_enumerations_in_find_conditions
24
48
  assert_equal [@red_car, @blue_car], Car.all(:conditions => {:color => %w(red blue)})
25
49
  end
50
+
51
+ def test_should_raise_exception_for_any_invalid_enumeration_in_find_conditions
52
+ assert_raise(ActiveRecord::RecordNotFound) { Car.all(:conditions => {:color => %w(red invalid)}) }
53
+ end
54
+
55
+ def test_should_still_allow_multiple_non_enumerations_in_find_conditions
56
+ assert_equal [@red_car, @blue_car], Car.all(:conditions => {:id => [@red_car.id, @blue_car.id]})
57
+ end
26
58
  end
27
59
 
28
60
  class EnumerationWithFinderUpdatesTest < ActiveRecord::TestCase
@@ -38,6 +70,16 @@ class EnumerationWithFinderUpdatesTest < ActiveRecord::TestCase
38
70
  assert_equal @blue, @red_car.color
39
71
  end
40
72
 
73
+ def test_should_raise_exception_for_invalid_enumeration_in_update_conditions
74
+ assert_raise(ActiveRecord::RecordNotFound) { Car.update_all({:color => 'invalid'}, :name => 'Ford Mustang') }
75
+ end
76
+
77
+ def test_should_still_allow_non_enumeration_in_update_conditions
78
+ Car.update_all({:color => 'blue'}, :id => @red_car.id)
79
+ @red_car.reload
80
+ assert_equal @blue, @red_car.color
81
+ end
82
+
41
83
  def test_should_not_replace_multiple_enumerations_in_update_conditions
42
84
  Car.update_all({:color => %w(red blue)}, :name => 'Ford Mustang')
43
85
  @red_car.reload
@@ -102,7 +102,8 @@ class EnumerationWithRecordsTest < ActiveRecord::TestCase
102
102
  end
103
103
 
104
104
  def test_should_raise_exception_for_invalid_index
105
- assert_raise(ActiveRecord::RecordNotFound) {Color['white']}
105
+ exception = assert_raise(ActiveRecord::RecordNotFound) {Color['white']}
106
+ assert_equal "Couldn't find Color with name \"white\"", exception.message
106
107
  end
107
108
 
108
109
  def test_should_allow_finding_all_by_enumerator
@@ -118,11 +119,63 @@ class EnumerationWithRecordsTest < ActiveRecord::TestCase
118
119
  end
119
120
 
120
121
  def test_should_raise_exception_find_finding_all_by_unknown_enumerator!
121
- assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!('invalid') }
122
+ exception = assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!('invalid') }
123
+ assert_equal "Couldn't find Color with name(s) \"invalid\"", exception.message
122
124
  end
123
125
 
124
126
  def test_should_raise_exception_if_only_some_found_when_finding_all_by_enumerator!
125
- assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!(['red', 'invalid']) }
127
+ exception = assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!(['red', 'invalid']) }
128
+ assert_equal "Couldn't find Color with name(s) \"invalid\"", exception.message
129
+ end
130
+ end
131
+
132
+ class EnumerationWithSymbolReferencesTest < ActiveRecord::TestCase
133
+ def setup
134
+ @red = create_color(:name => 'red')
135
+ @green = create_color(:name => 'green')
136
+ end
137
+
138
+ def test_should_index_by_enumerator
139
+ assert_equal @red, Color[:red]
140
+ end
141
+
142
+ def test_should_allow_finding_by_enumerator
143
+ assert_equal @red, Color.find_by_enumerator(:red)
144
+ end
145
+
146
+ def test_should_allow_finding_by_enumerator_with_nil
147
+ assert_nil Color.find_by_enumerator(nil)
148
+ end
149
+
150
+ def test_should_find_nothing_if_finding_by_unknown_enumerator
151
+ assert_nil Color.find_by_enumerator(:invalid)
152
+ end
153
+
154
+ def test_should_raise_exception_for_invalid_index
155
+ exception = assert_raise(ActiveRecord::RecordNotFound) {Color[:white]}
156
+ assert_equal "Couldn't find Color with name \"white\"", exception.message
157
+ end
158
+
159
+ def test_should_allow_finding_all_by_enumerator
160
+ assert_equal [@red, @green], Color.find_all_by_enumerator([:red, :green])
161
+ end
162
+
163
+ def test_should_allow_finding_all_by_enumerator_with_nil
164
+ assert_equal [], Color.find_all_by_enumerator(nil)
165
+ end
166
+
167
+ def test_should_find_nothing_if_finding_all_by_unknown_enumerator
168
+ assert_equal [], Color.find_all_by_enumerator(:invalid)
169
+ end
170
+
171
+ def test_should_raise_exception_find_finding_all_by_unknown_enumerator!
172
+ exception = assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!(:invalid) }
173
+ assert_equal "Couldn't find Color with name(s) \"invalid\"", exception.message
174
+ end
175
+
176
+ def test_should_raise_exception_if_only_some_found_when_finding_all_by_enumerator!
177
+ exception = assert_raise(ActiveRecord::RecordNotFound) { Color.find_all_by_enumerator!([:red, :invalid]) }
178
+ assert_equal "Couldn't find Color with name(s) \"invalid\"", exception.message
126
179
  end
127
180
  end
128
181
 
@@ -141,6 +194,10 @@ class EnumerationAfterBeingCreatedTest < ActiveRecord::TestCase
141
194
  assert @red == 'red'
142
195
  end
143
196
 
197
+ def test_should_allow_equality_with_symbol_enumerator
198
+ assert @red == :red
199
+ end
200
+
144
201
  def test_should_allow_equality_with_record
145
202
  assert @red == @red
146
203
  end
@@ -149,6 +206,10 @@ class EnumerationAfterBeingCreatedTest < ActiveRecord::TestCase
149
206
  assert 'red' == @red
150
207
  end
151
208
 
209
+ def test_should_allow_equality_with_nil
210
+ assert @red != nil
211
+ end
212
+
152
213
  def test_should_raise_exception_on_quality_with_invalid_enumerator
153
214
  assert_raise(ActiveRecord::RecordNotFound) {@red == 'invalid'}
154
215
  end
@@ -157,6 +218,10 @@ class EnumerationAfterBeingCreatedTest < ActiveRecord::TestCase
157
218
  assert @red.in?('red')
158
219
  end
159
220
 
221
+ def test_should_be_found_in_a_list_of_valid_symbol_names
222
+ assert @red.in?(:red)
223
+ end
224
+
160
225
  def test_should_not_be_found_in_a_list_of_invalid_names
161
226
  assert !@red.in?('blue', 'green')
162
227
  end
@@ -167,6 +232,47 @@ class EnumerationAfterBeingCreatedTest < ActiveRecord::TestCase
167
232
  end
168
233
  end
169
234
 
235
+ class EnumerationWithNumericEnumeratorAttributeTest < ActiveRecord::TestCase
236
+ def setup
237
+ @engine = create_car_part(:name => 'engine', :number => 111)
238
+ @radiator = create_car_part(:name => 'radiator', :number => 222)
239
+ @transmission = create_car_part(:name => 'transmission', :number => 333)
240
+ end
241
+
242
+ def test_should_have_an_enumerator
243
+ assert_equal 111, @engine.enumerator
244
+ end
245
+
246
+ def test_should_allow_equality_with_enumerator
247
+ assert @engine == 111
248
+ end
249
+
250
+ def test_should_allow_equality_with_record
251
+ assert @engine == @engine
252
+ end
253
+
254
+ def test_should_allow_equality_with_strings
255
+ assert '111' == @engine
256
+ end
257
+
258
+ def test_should_raise_exception_on_quality_with_invalid_enumerator
259
+ assert_raise(ActiveRecord::RecordNotFound) {@engine == 123}
260
+ end
261
+
262
+ def test_should_be_found_in_a_list_of_valid_names
263
+ assert @engine.in?(111)
264
+ end
265
+
266
+ def test_should_not_be_found_in_a_list_of_invalid_names
267
+ assert !@engine.in?(222, 333)
268
+ end
269
+
270
+ def test_should_stringify_enumerator
271
+ assert_equal '111', @engine.to_s
272
+ assert_equal '111', @engine.to_str
273
+ end
274
+ end
275
+
170
276
  class EnumerationWithCachingTest < ActiveRecord::TestCase
171
277
  def setup
172
278
  @red = create_color(:name => 'red')
@@ -69,3 +69,23 @@ class XmlSerializerTest < ActiveRecord::TestCase
69
69
  assert_equal expected, @car.to_xml
70
70
  end
71
71
  end
72
+
73
+ class XmlSerializerWithNumericEnumeratorAttributeTest < ActiveRecord::TestCase
74
+ def setup
75
+ @engine = create_car_part(:name => 'engine', :number => 123321)
76
+ @order = create_order(:state => 'pending', :car_part => @engine)
77
+ end
78
+
79
+ def test_should_be_able_to_convert_to_xml
80
+ expected = <<-eos
81
+ <?xml version="1.0" encoding="UTF-8"?>
82
+ <order>
83
+ <car-part type="integer">123321</car-part>
84
+ <id type="integer">#{@order.id}</id>
85
+ <state>pending</state>
86
+ </order>
87
+ eos
88
+
89
+ assert_equal expected, @order.to_xml
90
+ end
91
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pluginaweek-enumerate_by
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Pfeifer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-08 00:00:00 -07:00
12
+ date: 2009-06-14 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -40,12 +40,16 @@ files:
40
40
  - test/app_root
41
41
  - test/app_root/app
42
42
  - test/app_root/app/models
43
+ - test/app_root/app/models/order.rb
43
44
  - test/app_root/app/models/color.rb
44
45
  - test/app_root/app/models/car.rb
46
+ - test/app_root/app/models/car_part.rb
45
47
  - test/app_root/db
46
48
  - test/app_root/db/migrate
49
+ - test/app_root/db/migrate/003_create_car_parts.rb
47
50
  - test/app_root/db/migrate/001_create_colors.rb
48
51
  - test/app_root/db/migrate/002_create_cars.rb
52
+ - test/app_root/db/migrate/004_create_orders.rb
49
53
  - test/test_helper.rb
50
54
  - CHANGELOG.rdoc
51
55
  - init.rb