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 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.
@@ -1,5 +1,5 @@
1
1
  module ActiveNomad
2
- VERSION = [0, 2, 2]
2
+ VERSION = [0, 2, 3]
3
3
 
4
4
  class << VERSION
5
5
  include Comparable
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
- self.class.column_names.sort.each do |name|
30
- column = columns[name] or
31
- next
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 a serialized string.
37
+ # Recreate an object from the serialized attributes returned by
38
+ # #to_serialized_attributes.
39
39
  #
40
- def self.from_serialized_attributes(deserialized_attributes)
41
- instance = new
42
- deserialized_attributes.each do |name, serialized_value|
43
- column = columns_hash[name.to_s] or
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
- instance
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 = string.strip.split(/&/).map do |pair|
66
+ serialized_attributes = {}
67
+ string.strip.split(/&/).map do |pair|
69
68
  name, value = pair.split(/=/, 2)
70
- [CGI.unescape(name), CGI.unescape(value)]
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 a list of attribute names with serialized attributes, sorted by name" do
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 12:34:56 -0000'),
173
- :timestamp_attribute => Time.parse('03 Feb 2001 12:34:56 -0000'),
174
- :time_attribute => Time.parse('03 Feb 2001 12:34:56 -0000'),
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.to_a.should == [
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
- [:integer_attribute, '5'],
215
- [:string_attribute, 'string'],
216
- [:text_attribute, 'text'],
217
- [:float_attribute, '1.23'],
218
- [:decimal_attribute, '123.45'],
219
- [:datetime_attribute, '03 Feb 2001 12:34:56 -0000'],
220
- [:timestamp_attribute, '03 Feb 2001 12:34:56 -0000'],
221
- [:time_attribute, '03 Feb 2001 12:34:56 -0000'],
222
- [:date_attribute, '03 Feb 2001'],
223
- [:binary_attribute, "\0\1"],
224
- [:boolean_attribute, 'true'],
225
- [:nil_attribute, nil]
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 12:34:56 -0000')
233
- instance.timestamp_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000')
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.now.in_time_zone
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.now.in_time_zone
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').in_time_zone
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: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 2
10
- version: 0.2.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-07 00:00:00 -04:00
18
+ date: 2010-10-12 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency