enumerate_by 0.4.0 → 0.4.1
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 +4 -0
- data/Rakefile +1 -1
- data/lib/enumerate_by.rb +54 -29
- data/test/unit/enumerate_by_test.rb +68 -14
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
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.
|
|
8
|
+
s.version = '0.4.1'
|
|
9
9
|
s.platform = Gem::Platform::RUBY
|
|
10
10
|
s.summary = 'Adds support for declaring an ActiveRecord class as an enumeration'
|
|
11
11
|
|
data/lib/enumerate_by.rb
CHANGED
|
@@ -261,16 +261,17 @@ module EnumerateBy
|
|
|
261
261
|
defaults = attributes.delete(:defaults)
|
|
262
262
|
|
|
263
263
|
# Update with new attributes
|
|
264
|
-
record =
|
|
265
|
-
record = existing[attributes[:id]]
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
record =
|
|
265
|
+
if record = existing[attributes[:id]]
|
|
266
|
+
attributes.merge!(defaults.delete_if {|attribute, value| record.send("#{attribute}?")}) if defaults
|
|
267
|
+
record.attributes = attributes
|
|
268
|
+
record
|
|
269
|
+
else
|
|
270
|
+
attributes.merge!(defaults) if defaults
|
|
271
|
+
new(attributes)
|
|
272
|
+
end
|
|
269
273
|
record.id = attributes[:id]
|
|
270
274
|
|
|
271
|
-
# Only update defaults if they aren't already specified
|
|
272
|
-
defaults.each {|attribute, value| record[attribute] = value unless record.send("#{attribute}?")} if defaults
|
|
273
|
-
|
|
274
275
|
# Force failed saves to stop execution
|
|
275
276
|
record.save!
|
|
276
277
|
record
|
|
@@ -281,39 +282,63 @@ module EnumerateBy
|
|
|
281
282
|
end
|
|
282
283
|
|
|
283
284
|
# Quickly synchronizes the given records with the existing ones. This
|
|
284
|
-
#
|
|
285
|
-
#
|
|
285
|
+
# skips ActiveRecord altogether, interacting directly with the connection
|
|
286
|
+
# instead. As a result, certain features are not available when being
|
|
287
|
+
# bootstrapped, including:
|
|
286
288
|
# * Callbacks
|
|
287
289
|
# * Validations
|
|
290
|
+
# * Transactions
|
|
288
291
|
# * Timestamps
|
|
289
292
|
# * Dirty attributes
|
|
290
293
|
#
|
|
291
|
-
#
|
|
294
|
+
# Also note that records are created directly without creating instances
|
|
295
|
+
# of the model. As a result, all of the attributes for the record must
|
|
296
|
+
# be specified.
|
|
297
|
+
#
|
|
298
|
+
# This produces a significant performance increase when bootstrapping more
|
|
292
299
|
# than several hundred records.
|
|
293
300
|
#
|
|
294
301
|
# See EnumerateBy::Bootstrapped#bootstrap for information about usage.
|
|
295
302
|
def fast_bootstrap(*records)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
method, punctuation = method.sub(/([?!=])$/, ''), $1
|
|
300
|
-
alias_method "#{method}_without_bootstrap#{punctuation}", "#{method}#{punctuation}"
|
|
301
|
-
alias_method "#{method}#{punctuation}", "#{method}_without_#{feature}#{punctuation}"
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
original_record_timestamps = self.record_timestamps
|
|
305
|
-
self.record_timestamps = false
|
|
303
|
+
# Remove records that are no longer being used
|
|
304
|
+
records.flatten!
|
|
305
|
+
delete_all(['id NOT IN (?)', records.map {|record| record[:id]}])
|
|
306
306
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
307
|
+
# Find remaining existing records (to be updated)
|
|
308
|
+
quoted_table_name = self.quoted_table_name
|
|
309
|
+
existing = connection.select_all("SELECT * FROM #{quoted_table_name}").inject({}) {|existing, record| existing[record['id'].to_i] = record; existing}
|
|
310
|
+
|
|
311
|
+
records.each do |attributes|
|
|
312
|
+
attributes.stringify_keys!
|
|
313
|
+
if defaults = attributes.delete('defaults')
|
|
314
|
+
defaults.stringify_keys!
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
id = attributes['id']
|
|
318
|
+
if existing_attributes = existing[id]
|
|
319
|
+
# Record exists: Update attributes
|
|
320
|
+
attributes.delete('id')
|
|
321
|
+
attributes.merge!(defaults.delete_if {|attribute, value| !existing_attributes[attribute].nil?}) if defaults
|
|
322
|
+
update_all(attributes, :id => id)
|
|
323
|
+
else
|
|
324
|
+
# Record doesn't exist: create new one
|
|
325
|
+
attributes.merge!(defaults) if defaults
|
|
326
|
+
column_names = []
|
|
327
|
+
values = []
|
|
328
|
+
|
|
329
|
+
attributes.each do |column_name, value|
|
|
330
|
+
column_names << connection.quote_column_name(column_name)
|
|
331
|
+
values << connection.quote(value, columns_hash[column_name])
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
connection.insert(
|
|
335
|
+
"INSERT INTO #{quoted_table_name} (#{column_names * ', '}) VALUES(#{values * ', '})",
|
|
336
|
+
"#{name} Create", primary_key, id, sequence_name
|
|
337
|
+
)
|
|
314
338
|
end
|
|
315
339
|
end
|
|
316
|
-
|
|
340
|
+
|
|
341
|
+
true
|
|
317
342
|
end
|
|
318
343
|
end
|
|
319
344
|
|
|
@@ -324,27 +324,81 @@ class EnumerationBootstrappedWithDefaultsTest < ActiveRecord::TestCase
|
|
|
324
324
|
end
|
|
325
325
|
|
|
326
326
|
class EnumerationFastBootstrappedTest < ActiveRecord::TestCase
|
|
327
|
-
def
|
|
328
|
-
|
|
327
|
+
def setup
|
|
328
|
+
@result = Color.fast_bootstrap(
|
|
329
|
+
{:id => 1, :name => 'red'},
|
|
330
|
+
{:id => 2, :name => 'green'}
|
|
331
|
+
)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def test_should_not_raise_exception_if_id_not_specified
|
|
335
|
+
assert_nothing_raised { Color.fast_bootstrap({:name => 'red'}, {:name => 'green'}) }
|
|
336
|
+
assert_equal 2, Color.count
|
|
329
337
|
end
|
|
330
338
|
|
|
331
|
-
def
|
|
332
|
-
Color.fast_bootstrap({:id => 1, :name => '
|
|
333
|
-
assert Color.record_timestamps
|
|
339
|
+
def test_should_raise_exception_if_query_fails
|
|
340
|
+
assert_raise(ActiveRecord::StatementInvalid) { Color.fast_bootstrap({:id => 1, :name => nil}, {:id => 2, :name => 'green'}) }
|
|
334
341
|
end
|
|
335
342
|
|
|
336
|
-
def
|
|
337
|
-
Color.
|
|
343
|
+
def test_should_flatten_bootstrap_records
|
|
344
|
+
Color.bootstrap(
|
|
345
|
+
[{:id => 1, :name => 'red'}],
|
|
346
|
+
[{:id => 2, :name => 'green'}]
|
|
347
|
+
)
|
|
348
|
+
assert_equal 2, Color.count
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def test_should_create_records
|
|
352
|
+
assert @result
|
|
353
|
+
assert_not_nil Color.find_by_name('red')
|
|
354
|
+
assert_not_nil Color.find_by_name('green')
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
class EnumeratioFastBootstrappedWithExistingRecordsTest < ActiveRecord::TestCase
|
|
359
|
+
def setup
|
|
360
|
+
@red = create_color(:name => 'RED')
|
|
361
|
+
@green = create_color(:name => 'GREEN')
|
|
362
|
+
|
|
363
|
+
Color.fast_bootstrap(
|
|
364
|
+
{:id => @red.id, :name => 'red'},
|
|
365
|
+
{:id => @green.id, :name => 'green'}
|
|
366
|
+
)
|
|
338
367
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
assert_raise(ActiveRecord::RecordInvalid) { color.save! }
|
|
368
|
+
@red.reload
|
|
369
|
+
@green.reload
|
|
342
370
|
end
|
|
343
371
|
|
|
344
|
-
def
|
|
345
|
-
|
|
372
|
+
def test_should_synchronize_all_attributes
|
|
373
|
+
assert_equal 'red', @red.name
|
|
374
|
+
assert_equal 'green', @green.name
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
class EnumerationFastBootstrappedWithDefaultsTest < ActiveRecord::TestCase
|
|
379
|
+
def setup
|
|
380
|
+
@red = create_color(:name => 'RED', :html => '#f00')
|
|
381
|
+
@green = create_color(:name => 'GREEN')
|
|
382
|
+
|
|
383
|
+
Color.fast_bootstrap(
|
|
384
|
+
{:id => @red.id, :name => 'red', :defaults => {:html => '#ff0000'}},
|
|
385
|
+
{:id => @green.id, :name => 'green', :defaults => {:html => '#00ff00'}}
|
|
386
|
+
)
|
|
346
387
|
|
|
347
|
-
|
|
348
|
-
|
|
388
|
+
@red.reload
|
|
389
|
+
@green.reload
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def test_should_update_all_non_default_attributes
|
|
393
|
+
assert_equal 'red', @red.name
|
|
394
|
+
assert_equal 'green', @green.name
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def test_should_not_update_default_attributes_if_defined
|
|
398
|
+
assert_equal '#f00', @red.html
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def test_should_update_default_attributes_if_not_defined
|
|
402
|
+
assert_equal '#00ff00', @green.html
|
|
349
403
|
end
|
|
350
404
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: enumerate_by
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
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-
|
|
12
|
+
date: 2009-05-01 00:00:00 -04:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|