active_nomad 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/lib/active_nomad/version.rb +1 -1
- data/lib/active_nomad.rb +20 -15
- data/spec/unit/active_nomad_spec.rb +86 -41
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.2.3 2010-10-12
|
2
|
+
|
3
|
+
* #inspect no longer requires a database connection.
|
4
|
+
* ActiveRecord::Base.default_timezone support.
|
5
|
+
* Dirty attribute tracking works.
|
6
|
+
* Undeclared attributes are preserved when roundtripped through ActiveNomad.
|
7
|
+
|
1
8
|
== 0.2.2 2010-10-07
|
2
9
|
|
3
10
|
* Support custom destruction strategies.
|
data/lib/active_nomad/version.rb
CHANGED
data/lib/active_nomad.rb
CHANGED
@@ -26,25 +26,23 @@ module ActiveNomad
|
|
26
26
|
def to_serialized_attributes
|
27
27
|
attributes = ActiveSupport::OrderedHash.new
|
28
28
|
columns = self.class.columns_hash
|
29
|
-
|
30
|
-
column = columns[name]
|
31
|
-
|
32
|
-
attributes[name] = serialize_value(send(name), column.type)
|
29
|
+
@attributes.sort.each do |name, value|
|
30
|
+
column = columns[name]
|
31
|
+
attributes[name] = serialize_value(send(name), column ? column.type : :string)
|
33
32
|
end
|
34
33
|
attributes
|
35
34
|
end
|
36
35
|
|
37
36
|
#
|
38
|
-
# Recreate an object from
|
37
|
+
# Recreate an object from the serialized attributes returned by
|
38
|
+
# #to_serialized_attributes.
|
39
39
|
#
|
40
|
-
def self.from_serialized_attributes(
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
next
|
45
|
-
instance.send "#{column.name}=", deserialize_value(serialized_value, column.type)
|
40
|
+
def self.from_serialized_attributes(serialized_attributes)
|
41
|
+
serialized_attributes = serialized_attributes.dup
|
42
|
+
columns_hash.each do |name, column|
|
43
|
+
serialized_attributes[name] ||= column.default
|
46
44
|
end
|
47
|
-
|
45
|
+
instantiate(serialized_attributes)
|
48
46
|
end
|
49
47
|
|
50
48
|
#
|
@@ -65,9 +63,10 @@ module ActiveNomad
|
|
65
63
|
#
|
66
64
|
def self.from_query_string(string)
|
67
65
|
return new if string.blank?
|
68
|
-
serialized_attributes =
|
66
|
+
serialized_attributes = {}
|
67
|
+
string.strip.split(/&/).map do |pair|
|
69
68
|
name, value = pair.split(/=/, 2)
|
70
|
-
[CGI.unescape(name)
|
69
|
+
serialized_attributes[CGI.unescape(name)] = CGI.unescape(value)
|
71
70
|
end
|
72
71
|
from_serialized_attributes(serialized_attributes)
|
73
72
|
end
|
@@ -170,6 +169,10 @@ module ActiveNomad
|
|
170
169
|
def transaction
|
171
170
|
yield
|
172
171
|
end
|
172
|
+
|
173
|
+
def inspect
|
174
|
+
(n = name).blank? ? '(anonymous)' : n
|
175
|
+
end
|
173
176
|
end
|
174
177
|
|
175
178
|
@columns = []
|
@@ -185,6 +188,7 @@ module ActiveNomad
|
|
185
188
|
case type
|
186
189
|
when :datetime, :timestamp, :time
|
187
190
|
# The day in RFC 2822 is optional - chop it.
|
191
|
+
value = ActiveRecord::Base.default_timezone == :utc ? value.utc : value.in_time_zone(Time.zone)
|
188
192
|
value.rfc2822.sub(/\A[A-Za-z]{3}, /, '')
|
189
193
|
when :date
|
190
194
|
value.to_date.strftime(DATE_FORMAT)
|
@@ -197,7 +201,8 @@ module ActiveNomad
|
|
197
201
|
return nil if string.nil?
|
198
202
|
case type
|
199
203
|
when :datetime, :timestamp, :time
|
200
|
-
Time.parse(string)
|
204
|
+
value = Time.parse(string).in_time_zone
|
205
|
+
ActiveRecord::Base.default_timezone == :utc ? value.utc : value.in_time_zone(Time.zone)
|
201
206
|
when :date
|
202
207
|
Date.parse(string)
|
203
208
|
else
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ActiveNomad::Base do
|
4
|
+
before do
|
5
|
+
Time.zone = -5
|
6
|
+
ActiveRecord::Base.default_timezone = :utc
|
7
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
8
|
+
end
|
9
|
+
|
4
10
|
describe ".attribute" do
|
5
11
|
it "should create a column with the given name and type" do
|
6
12
|
klass = Class.new(ActiveNomad::Base) do
|
@@ -148,7 +154,7 @@ describe ActiveNomad::Base do
|
|
148
154
|
end
|
149
155
|
|
150
156
|
describe "#to_serialized_attributes" do
|
151
|
-
it "should return
|
157
|
+
it "should return an ordered hash of attribute names with serialized attributes, sorted by name" do
|
152
158
|
klass = Class.new(ActiveNomad::Base) do
|
153
159
|
attribute :integer_attribute, :integer
|
154
160
|
attribute :string_attribute, :string
|
@@ -169,15 +175,15 @@ describe ActiveNomad::Base do
|
|
169
175
|
:text_attribute => 'text',
|
170
176
|
:float_attribute => 1.23,
|
171
177
|
:decimal_attribute => BigDecimal.new('123.45'),
|
172
|
-
:datetime_attribute => Time.parse('03 Feb 2001
|
173
|
-
:timestamp_attribute => Time.parse('03 Feb 2001
|
174
|
-
:time_attribute => Time.parse('03 Feb 2001
|
178
|
+
:datetime_attribute => Time.parse('03 Feb 2001 7:34:56 -500'),
|
179
|
+
:timestamp_attribute => Time.parse('03 Feb 2001 7:34:56 -500'),
|
180
|
+
:time_attribute => Time.parse('03 Feb 2001 7:34:56 -500'),
|
175
181
|
:date_attribute => Date.parse('03 Feb 2001'),
|
176
182
|
:binary_attribute => "\0\1",
|
177
183
|
:boolean_attribute => true,
|
178
184
|
:nil_attribute => nil
|
179
185
|
)
|
180
|
-
instance.to_serialized_attributes.
|
186
|
+
instance.to_serialized_attributes.should == ActiveSupport::OrderedHash[[
|
181
187
|
['binary_attribute', "\0\1"],
|
182
188
|
['boolean_attribute', 'true'],
|
183
189
|
['date_attribute', '03 Feb 2001'],
|
@@ -190,7 +196,7 @@ describe ActiveNomad::Base do
|
|
190
196
|
['text_attribute', 'text'],
|
191
197
|
['time_attribute', '03 Feb 2001 12:34:56 -0000'],
|
192
198
|
['timestamp_attribute', '03 Feb 2001 12:34:56 -0000'],
|
193
|
-
]
|
199
|
+
]]
|
194
200
|
end
|
195
201
|
end
|
196
202
|
|
@@ -210,49 +216,34 @@ describe ActiveNomad::Base do
|
|
210
216
|
attribute :boolean_attribute, :boolean
|
211
217
|
attribute :nil_attribute, :boolean
|
212
218
|
end
|
213
|
-
instance = klass.from_serialized_attributes([
|
214
|
-
[
|
215
|
-
[
|
216
|
-
[
|
217
|
-
[
|
218
|
-
[
|
219
|
-
[
|
220
|
-
[
|
221
|
-
[
|
222
|
-
[
|
223
|
-
[
|
224
|
-
[
|
225
|
-
[
|
226
|
-
])
|
219
|
+
instance = klass.from_serialized_attributes(ActiveSupport::OrderedHash[[
|
220
|
+
['integer_attribute', '5'],
|
221
|
+
['string_attribute', 'string'],
|
222
|
+
['text_attribute', 'text'],
|
223
|
+
['float_attribute', '1.23'],
|
224
|
+
['decimal_attribute', '123.45'],
|
225
|
+
['datetime_attribute', '03 Feb 2001 12:34:56 -0000'],
|
226
|
+
['timestamp_attribute', '03 Feb 2001 12:34:56 -0000'],
|
227
|
+
['time_attribute', '03 Feb 2001 12:34:56 -0000'],
|
228
|
+
['date_attribute', '03 Feb 2001'],
|
229
|
+
['binary_attribute', "\0\1"],
|
230
|
+
['boolean_attribute', 'true'],
|
231
|
+
['nil_attribute', nil],
|
232
|
+
]])
|
227
233
|
instance.integer_attribute.should == 5
|
228
234
|
instance.string_attribute.should == 'string'
|
229
235
|
instance.text_attribute.should == 'text'
|
230
236
|
instance.float_attribute.should == 1.23
|
231
237
|
instance.decimal_attribute.should == BigDecimal.new('123.45')
|
232
|
-
instance.datetime_attribute.should == Time.parse('03 Feb 2001
|
233
|
-
instance.timestamp_attribute.should == Time.parse('03 Feb 2001
|
234
|
-
instance.time_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000')
|
238
|
+
instance.datetime_attribute.should == Time.parse('03 Feb 2001 7:34:56 -500').in_time_zone
|
239
|
+
instance.timestamp_attribute.should == Time.parse('03 Feb 2001 7:34:56 -500').in_time_zone
|
240
|
+
instance.time_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000').in_time_zone
|
235
241
|
instance.date_attribute.should == Date.parse('03 Feb 2001')
|
236
242
|
instance.binary_attribute.should == "\0\1"
|
237
243
|
instance.boolean_attribute.should be_true
|
238
244
|
instance.nil_attribute.should be_nil
|
239
245
|
end
|
240
246
|
|
241
|
-
it "should work with any enumerable" do
|
242
|
-
klass = Class.new(ActiveNomad::Base) do
|
243
|
-
attribute :name, :string
|
244
|
-
end
|
245
|
-
params = Object.new
|
246
|
-
class << params
|
247
|
-
def each
|
248
|
-
yield :name, 'joe'
|
249
|
-
end
|
250
|
-
end
|
251
|
-
params.extend Enumerable
|
252
|
-
instance = klass.from_serialized_attributes(params)
|
253
|
-
instance.name.should == 'joe'
|
254
|
-
end
|
255
|
-
|
256
247
|
it "should leave defaults alone for attributes which are not set" do
|
257
248
|
klass = Class.new(ActiveNomad::Base) do
|
258
249
|
attribute :name, :string, :default => 'Joe'
|
@@ -317,6 +308,22 @@ describe ActiveNomad::Base do
|
|
317
308
|
end
|
318
309
|
end
|
319
310
|
|
311
|
+
it "should roundtrip undeclared attributes from the store through ActiveNomad" do
|
312
|
+
klass = Class.new(ActiveNomad::Base) do
|
313
|
+
attribute :declared, :string
|
314
|
+
end
|
315
|
+
stored_attributes = ActiveSupport::OrderedHash[[
|
316
|
+
['declared', 'a'],
|
317
|
+
['undeclared', 'b'],
|
318
|
+
]]
|
319
|
+
instance = klass.from_serialized_attributes(stored_attributes)
|
320
|
+
roundtripped_attributes = instance.to_serialized_attributes
|
321
|
+
roundtripped_attributes.to_a.should == [
|
322
|
+
['declared', 'a'],
|
323
|
+
['undeclared', 'b'],
|
324
|
+
]
|
325
|
+
end
|
326
|
+
|
320
327
|
def self.it_should_roundtrip_through(serializer, deserializer, &block)
|
321
328
|
describe "roundtripping through ##{serializer} and .#{deserializer}" do
|
322
329
|
class_eval(&block) if block
|
@@ -356,15 +363,18 @@ describe ActiveNomad::Base do
|
|
356
363
|
it_should_roundtrip :decimal, BigDecimal.new('123.45')
|
357
364
|
|
358
365
|
it_should_roundtrip :datetime, nil
|
359
|
-
it_should_roundtrip :datetime, Time.
|
366
|
+
it_should_roundtrip :datetime, Time.parse('2000-01-01 01:23:34 UTC')
|
367
|
+
it_should_roundtrip :datetime, Time.parse('2000-01-01 01:23:34 EST')
|
360
368
|
# TODO: Support DateTime here, which is used when the value is
|
361
369
|
# outside the range of a Time.
|
362
370
|
|
363
371
|
it_should_roundtrip :timestamp, nil
|
364
|
-
it_should_roundtrip :timestamp, Time.
|
372
|
+
it_should_roundtrip :timestamp, Time.parse('2000-01-01 01:23:34 UTC')
|
373
|
+
it_should_roundtrip :timestamp, Time.parse('2000-01-01 01:23:34 EST')
|
365
374
|
|
366
375
|
it_should_roundtrip :time, nil
|
367
|
-
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34')
|
376
|
+
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34 UTC')
|
377
|
+
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34 EST')
|
368
378
|
|
369
379
|
it_should_roundtrip :date, nil
|
370
380
|
it_should_roundtrip :date, Date.today
|
@@ -449,4 +459,39 @@ describe ActiveNomad::Base do
|
|
449
459
|
instance.transaction_called.should be_true
|
450
460
|
end
|
451
461
|
end
|
462
|
+
|
463
|
+
describe "#ATTRIBUTE_changed?" do
|
464
|
+
describe "on a new record with no attributes" do
|
465
|
+
before do
|
466
|
+
@klass = Class.new(ActiveNomad::Base) do
|
467
|
+
attribute :i, :integer
|
468
|
+
end
|
469
|
+
@instance = @klass.new
|
470
|
+
end
|
471
|
+
|
472
|
+
it "should be false" do
|
473
|
+
@instance.i_changed?.should be_false
|
474
|
+
end
|
475
|
+
|
476
|
+
describe "when the attribute has been assigned" do
|
477
|
+
before do
|
478
|
+
@instance.i = 2
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should be true" do
|
482
|
+
@instance.i_changed?.should be_true
|
483
|
+
end
|
484
|
+
|
485
|
+
describe "when the record is roundtripped" do
|
486
|
+
before do
|
487
|
+
@instance = @klass.from_serialized_attributes(@instance.to_serialized_attributes)
|
488
|
+
end
|
489
|
+
|
490
|
+
it "should be false" do
|
491
|
+
@instance.i_changed?.should be_false
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
452
497
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_nomad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 3
|
10
|
+
version: 0.2.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- George Ogata
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-12 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|