enumerate_by 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|