active_nomad 0.0.4 → 0.1.0
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 +5 -0
- data/README.markdown +28 -18
- data/lib/active_nomad.rb +63 -22
- data/lib/active_nomad/version.rb +1 -1
- data/spec/unit/active_nomad_spec.rb +206 -60
- metadata +4 -4
data/CHANGELOG
CHANGED
data/README.markdown
CHANGED
@@ -6,16 +6,15 @@ ActiveRecord objects with a customizable persistence strategy.
|
|
6
6
|
|
7
7
|
Sometimes you want an Active Record object that does not live in the database.
|
8
8
|
Perhaps it never needs to be persisted, or you'd like to store it in a cookie,
|
9
|
-
or
|
9
|
+
or a key-value store, but it would still be handy to have ActiveRecord's ability
|
10
10
|
to cast values, run validations, or fire callbacks.
|
11
11
|
|
12
|
-
|
12
|
+
If only the persistence strategy was pluggable...
|
13
13
|
|
14
14
|
## How
|
15
15
|
|
16
|
-
Subclass from ActiveNomad::Base and declare your attributes with the
|
17
|
-
|
18
|
-
migration:
|
16
|
+
Subclass from ActiveNomad::Base and declare your attributes with the `attribute`
|
17
|
+
class method. The arguments look just like creating a column in a migration:
|
19
18
|
|
20
19
|
class Thing < ActiveNomad::Base
|
21
20
|
attribute :name, :string, :limit => 20
|
@@ -25,27 +24,38 @@ To persist the record, Active Nomad calls `persist`, which calls a
|
|
25
24
|
Proc registered by `to_save`. For example, here's how you could
|
26
25
|
persist to a cookie:
|
27
26
|
|
28
|
-
thing = Thing.
|
27
|
+
thing = Thing.from_json(cookies[:thing])
|
29
28
|
thing.to_save do |thing|
|
30
|
-
cookies[:thing] = thing.
|
29
|
+
cookies[:thing] = thing.to_json
|
31
30
|
true
|
32
31
|
end
|
33
32
|
|
34
33
|
Things to note:
|
35
34
|
|
36
|
-
* Active Nomad defines `serialize` and `deserialize` which will
|
37
|
-
serialize to and from a valid query string with predictable
|
38
|
-
attribute order (i.e., appropriate for a cookie).
|
39
35
|
* The proc should return true if persistence was successful, false
|
40
36
|
otherwise. This will be the return value of `save`, etc.
|
41
|
-
*
|
42
|
-
|
37
|
+
* Active Nomad defines `to_json` and `from_json` which will serialize to and
|
38
|
+
from a JSON string with predictable attribute order (i.e., appropriate for a
|
39
|
+
cookie).
|
40
|
+
* You may alternatively override `persist` in a subclass if you don't want to
|
41
|
+
register a proc for every instance.
|
43
42
|
|
44
|
-
|
43
|
+
### Serialization formats
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
Active Nomad provides serialization to and from:
|
46
|
+
|
47
|
+
* JSON (`to_json` and `from_json`)
|
48
|
+
* Query string (`to_query_string` and `from_query_string`)
|
49
|
+
|
50
|
+
You can define your own formats easily using `to_serialized_attributes` and
|
51
|
+
`from_serialized_attributes`. The former returns an `ActiveSupport::OrderedHash`
|
52
|
+
of attribute names to serialized values (`String`s or `nil`s).
|
53
|
+
|
54
|
+
### Transactions
|
55
|
+
|
56
|
+
In addition to customizing persistence, you can also customize transaction
|
57
|
+
semantics by overriding the `transaction` class method in a base class. Here's
|
58
|
+
an example that implements transactions with Redis:
|
49
59
|
|
50
60
|
class RedisNomad < ActiveNomad::Base
|
51
61
|
def self.transaction
|
@@ -64,8 +74,8 @@ a base class. Example:
|
|
64
74
|
end
|
65
75
|
end
|
66
76
|
|
67
|
-
`ActiveNomad::Base.transaction` simply calls the given block with no
|
68
|
-
|
77
|
+
`ActiveNomad::Base.transaction` simply calls the given block with no real
|
78
|
+
transaction semantics.
|
69
79
|
|
70
80
|
## Notes
|
71
81
|
|
data/lib/active_nomad.rb
CHANGED
@@ -13,34 +13,74 @@ module ActiveNomad
|
|
13
13
|
end
|
14
14
|
|
15
15
|
#
|
16
|
-
# Return
|
17
|
-
# string.
|
16
|
+
# Return an ActiveSupport::OrderedHash of serialized attributes.
|
18
17
|
#
|
19
|
-
# Attributes are sorted by name.
|
18
|
+
# Attributes are sorted by name. Each value is either a string or
|
19
|
+
# nil.
|
20
20
|
#
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
def to_serialized_attributes
|
22
|
+
attributes = ActiveSupport::OrderedHash.new
|
23
|
+
columns = self.class.columns_hash
|
24
|
+
self.class.column_names.sort.each do |name|
|
25
|
+
column = columns[name] or
|
25
26
|
next
|
26
|
-
|
27
|
-
end
|
27
|
+
attributes[name] = serialize_value(send(name), column.type)
|
28
|
+
end
|
29
|
+
attributes
|
28
30
|
end
|
29
31
|
|
30
32
|
#
|
31
33
|
# Recreate an object from a serialized string.
|
32
34
|
#
|
33
|
-
def self.
|
34
|
-
params = string ? CGI.parse(string.strip) : {}
|
35
|
+
def self.from_serialized_attributes(deserialized_attributes)
|
35
36
|
instance = new
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
instance.send "#{column.name}=", deserialize_value(
|
37
|
+
deserialized_attributes.each do |name, serialized_value|
|
38
|
+
column = columns_hash[name.to_s] or
|
39
|
+
next
|
40
|
+
instance.send "#{column.name}=", deserialize_value(serialized_value, column.type)
|
40
41
|
end
|
41
42
|
instance
|
42
43
|
end
|
43
44
|
|
45
|
+
#
|
46
|
+
# Serialize this record as a query string.
|
47
|
+
#
|
48
|
+
def to_query_string
|
49
|
+
to_serialized_attributes.map do |name, value|
|
50
|
+
next nil if value.nil?
|
51
|
+
"#{CGI.escape(name)}=#{CGI.escape(value)}"
|
52
|
+
end.compact.sort.join('&')
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Deserialize this record from a query string returned by
|
57
|
+
# #to_query_string.
|
58
|
+
#
|
59
|
+
def self.from_query_string(string)
|
60
|
+
return new if string.blank?
|
61
|
+
serialized_attributes = string.strip.split(/&/).map do |pair|
|
62
|
+
name, value = pair.split(/=/, 2)
|
63
|
+
[CGI.unescape(name), CGI.unescape(value)]
|
64
|
+
end
|
65
|
+
from_serialized_attributes(serialized_attributes)
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Serialize this record as a JSON string.
|
70
|
+
#
|
71
|
+
def to_json
|
72
|
+
to_serialized_attributes.to_json
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Deserialize this record from a JSON string returned by #to_json.
|
77
|
+
#
|
78
|
+
def self.from_json(string)
|
79
|
+
return new if string.blank?
|
80
|
+
serialized_attributes = JSON.parse(string)
|
81
|
+
from_serialized_attributes(serialized_attributes)
|
82
|
+
end
|
83
|
+
|
44
84
|
protected
|
45
85
|
|
46
86
|
#
|
@@ -115,11 +155,12 @@ module ActiveNomad
|
|
115
155
|
return nil if value.nil?
|
116
156
|
case type
|
117
157
|
when :datetime, :timestamp, :time
|
118
|
-
|
158
|
+
# The day in RFC 2822 is optional - chop it.
|
159
|
+
value.rfc2822.sub(/\A[A-Za-z]{3}, /, '')
|
119
160
|
when :date
|
120
|
-
|
161
|
+
value.to_date.strftime(DATE_FORMAT)
|
121
162
|
else
|
122
|
-
|
163
|
+
value.to_s
|
123
164
|
end
|
124
165
|
end
|
125
166
|
|
@@ -127,14 +168,14 @@ module ActiveNomad
|
|
127
168
|
return nil if string.nil?
|
128
169
|
case type
|
129
170
|
when :datetime, :timestamp, :time
|
130
|
-
Time.
|
171
|
+
Time.parse(string)
|
131
172
|
when :date
|
132
|
-
|
173
|
+
Date.parse(string)
|
133
174
|
else
|
134
|
-
|
175
|
+
string
|
135
176
|
end
|
136
177
|
end
|
137
178
|
|
138
|
-
|
179
|
+
DATE_FORMAT = '%d %b %Y'.freeze
|
139
180
|
end
|
140
181
|
end
|
data/lib/active_nomad/version.rb
CHANGED
@@ -123,23 +123,138 @@ describe ActiveNomad::Base do
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
-
describe "#
|
126
|
+
describe "#to_serialized_attributes" do
|
127
|
+
it "should return a list of attribute names with serialized attributes, sorted by name" do
|
128
|
+
klass = Class.new(ActiveNomad::Base) do
|
129
|
+
attribute :integer_attribute, :integer
|
130
|
+
attribute :string_attribute, :string
|
131
|
+
attribute :text_attribute, :text
|
132
|
+
attribute :float_attribute, :float
|
133
|
+
attribute :decimal_attribute, :decimal
|
134
|
+
attribute :datetime_attribute, :datetime
|
135
|
+
attribute :timestamp_attribute, :timestamp
|
136
|
+
attribute :time_attribute, :time
|
137
|
+
attribute :date_attribute, :date
|
138
|
+
attribute :binary_attribute, :binary
|
139
|
+
attribute :boolean_attribute, :boolean
|
140
|
+
attribute :nil_attribute, :string
|
141
|
+
end
|
142
|
+
instance = klass.new(
|
143
|
+
:integer_attribute => 5,
|
144
|
+
:string_attribute => 'string',
|
145
|
+
:text_attribute => 'text',
|
146
|
+
:float_attribute => 1.23,
|
147
|
+
:decimal_attribute => BigDecimal.new('123.45'),
|
148
|
+
:datetime_attribute => Time.parse('03 Feb 2001 12:34:56 -0000'),
|
149
|
+
:timestamp_attribute => Time.parse('03 Feb 2001 12:34:56 -0000'),
|
150
|
+
:time_attribute => Time.parse('03 Feb 2001 12:34:56 -0000'),
|
151
|
+
:date_attribute => Date.parse('03 Feb 2001'),
|
152
|
+
:binary_attribute => "\0\1",
|
153
|
+
:boolean_attribute => true,
|
154
|
+
:nil_attribute => nil
|
155
|
+
)
|
156
|
+
instance.to_serialized_attributes.to_a.should == [
|
157
|
+
['binary_attribute', "\0\1"],
|
158
|
+
['boolean_attribute', 'true'],
|
159
|
+
['date_attribute', '03 Feb 2001'],
|
160
|
+
['datetime_attribute', '03 Feb 2001 12:34:56 -0000'],
|
161
|
+
['decimal_attribute', '123.45'],
|
162
|
+
['float_attribute', '1.23'],
|
163
|
+
['integer_attribute', '5'],
|
164
|
+
['nil_attribute', nil],
|
165
|
+
['string_attribute', 'string'],
|
166
|
+
['text_attribute', 'text'],
|
167
|
+
['time_attribute', '03 Feb 2001 12:34:56 -0000'],
|
168
|
+
['timestamp_attribute', '03 Feb 2001 12:34:56 -0000'],
|
169
|
+
]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe ".from_serialized_attributes" do
|
174
|
+
it "should create a new record with attributes deserialized from the given parameter list" do
|
175
|
+
klass = Class.new(ActiveNomad::Base) do
|
176
|
+
attribute :integer_attribute, :integer
|
177
|
+
attribute :string_attribute, :string
|
178
|
+
attribute :text_attribute, :text
|
179
|
+
attribute :float_attribute, :float
|
180
|
+
attribute :decimal_attribute, :decimal
|
181
|
+
attribute :datetime_attribute, :datetime
|
182
|
+
attribute :timestamp_attribute, :timestamp
|
183
|
+
attribute :time_attribute, :time
|
184
|
+
attribute :date_attribute, :date
|
185
|
+
attribute :binary_attribute, :binary
|
186
|
+
attribute :boolean_attribute, :boolean
|
187
|
+
attribute :nil_attribute, :boolean
|
188
|
+
end
|
189
|
+
instance = klass.from_serialized_attributes([
|
190
|
+
[:integer_attribute, '5'],
|
191
|
+
[:string_attribute, 'string'],
|
192
|
+
[:text_attribute, 'text'],
|
193
|
+
[:float_attribute, '1.23'],
|
194
|
+
[:decimal_attribute, '123.45'],
|
195
|
+
[:datetime_attribute, '03 Feb 2001 12:34:56 -0000'],
|
196
|
+
[:timestamp_attribute, '03 Feb 2001 12:34:56 -0000'],
|
197
|
+
[:time_attribute, '03 Feb 2001 12:34:56 -0000'],
|
198
|
+
[:date_attribute, '03 Feb 2001'],
|
199
|
+
[:binary_attribute, "\0\1"],
|
200
|
+
[:boolean_attribute, 'true'],
|
201
|
+
[:nil_attribute, nil]
|
202
|
+
])
|
203
|
+
instance.integer_attribute.should == 5
|
204
|
+
instance.string_attribute.should == 'string'
|
205
|
+
instance.text_attribute.should == 'text'
|
206
|
+
instance.float_attribute.should == 1.23
|
207
|
+
instance.decimal_attribute.should == BigDecimal.new('123.45')
|
208
|
+
instance.datetime_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000')
|
209
|
+
instance.timestamp_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000')
|
210
|
+
instance.time_attribute.should == Time.parse('03 Feb 2001 12:34:56 -0000')
|
211
|
+
instance.date_attribute.should == Date.parse('03 Feb 2001')
|
212
|
+
instance.binary_attribute.should == "\0\1"
|
213
|
+
instance.boolean_attribute.should be_true
|
214
|
+
instance.nil_attribute.should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should work with any enumerable" do
|
218
|
+
klass = Class.new(ActiveNomad::Base) do
|
219
|
+
attribute :name, :string
|
220
|
+
end
|
221
|
+
params = Object.new
|
222
|
+
class << params
|
223
|
+
def each
|
224
|
+
yield :name, 'joe'
|
225
|
+
end
|
226
|
+
end
|
227
|
+
params.extend Enumerable
|
228
|
+
instance = klass.from_serialized_attributes(params)
|
229
|
+
instance.name.should == 'joe'
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should leave defaults alone for attributes which are not set" do
|
233
|
+
klass = Class.new(ActiveNomad::Base) do
|
234
|
+
attribute :name, :string, :default => 'Joe'
|
235
|
+
end
|
236
|
+
instance = klass.from_serialized_attributes({})
|
237
|
+
instance.name.should == 'Joe'
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "#to_query_string" do
|
127
242
|
it "should serialize the attributes as a query string" do
|
128
243
|
klass = Class.new(ActiveNomad::Base) do
|
129
244
|
attribute :first_name, :string
|
130
245
|
attribute :last_name, :string
|
131
246
|
end
|
132
247
|
instance = klass.new(:first_name => 'Joe', :last_name => 'Blow')
|
133
|
-
instance.
|
248
|
+
instance.to_query_string.should == 'first_name=Joe&last_name=Blow'
|
134
249
|
end
|
135
250
|
end
|
136
251
|
|
137
|
-
describe ".
|
252
|
+
describe ".from_query_string" do
|
138
253
|
it "should create a new record with no attributes set if nil is given" do
|
139
254
|
klass = Class.new(ActiveNomad::Base) do
|
140
255
|
attribute :name, :string
|
141
256
|
end
|
142
|
-
instance = klass.
|
257
|
+
instance = klass.from_query_string(nil)
|
143
258
|
instance.name.should be_nil
|
144
259
|
end
|
145
260
|
|
@@ -147,7 +262,7 @@ describe ActiveNomad::Base do
|
|
147
262
|
klass = Class.new(ActiveNomad::Base) do
|
148
263
|
attribute :name, :string
|
149
264
|
end
|
150
|
-
instance = klass.
|
265
|
+
instance = klass.from_query_string('')
|
151
266
|
instance.name.should be_nil
|
152
267
|
end
|
153
268
|
|
@@ -155,7 +270,7 @@ describe ActiveNomad::Base do
|
|
155
270
|
klass = Class.new(ActiveNomad::Base) do
|
156
271
|
attribute :name, :string
|
157
272
|
end
|
158
|
-
instance = klass.
|
273
|
+
instance = klass.from_query_string(" \t")
|
159
274
|
instance.name.should be_nil
|
160
275
|
end
|
161
276
|
|
@@ -163,19 +278,84 @@ describe ActiveNomad::Base do
|
|
163
278
|
klass = Class.new(ActiveNomad::Base) do
|
164
279
|
attribute :name, :string, :default => 'Joe'
|
165
280
|
end
|
166
|
-
instance = klass.
|
281
|
+
instance = klass.from_query_string(" \t")
|
167
282
|
instance.name.should == 'Joe'
|
168
283
|
end
|
169
284
|
end
|
170
285
|
|
171
|
-
|
286
|
+
def self.it_should_roundtrip_through(serializer, deserializer, &block)
|
287
|
+
describe "roundtripping through ##{serializer} and .#{deserializer}" do
|
288
|
+
class_eval(&block) if block
|
289
|
+
|
290
|
+
(class << self; self; end).class_eval do
|
291
|
+
define_method :it_should_roundtrip do |type, value|
|
292
|
+
value = Time.at(value.to_i) if value.is_a?(Time) # chop off subseconds
|
293
|
+
it "should roundtrip #{value.inspect} correctly as a #{type}" do
|
294
|
+
klass = Class.new(ActiveNomad::Base) do
|
295
|
+
attribute :value, type
|
296
|
+
end
|
297
|
+
instance = klass.new(:value => value)
|
298
|
+
roundtripped = klass.send(deserializer, instance.send(serializer))
|
299
|
+
roundtripped.value.should == value
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
it_should_roundtrip :integer, nil
|
305
|
+
it_should_roundtrip :integer, 0
|
306
|
+
it_should_roundtrip :integer, 123
|
307
|
+
|
308
|
+
it_should_roundtrip :string, nil
|
309
|
+
it_should_roundtrip :string, ''
|
310
|
+
it_should_roundtrip :string, 'hi'
|
311
|
+
|
312
|
+
it_should_roundtrip :text, nil
|
313
|
+
it_should_roundtrip :text, ''
|
314
|
+
it_should_roundtrip :text, 'hi'
|
315
|
+
|
316
|
+
it_should_roundtrip :float, nil
|
317
|
+
it_should_roundtrip :float, 0
|
318
|
+
it_should_roundtrip :float, 0.123
|
319
|
+
|
320
|
+
it_should_roundtrip :decimal, nil
|
321
|
+
it_should_roundtrip :decimal, BigDecimal.new('0')
|
322
|
+
it_should_roundtrip :decimal, BigDecimal.new('123.45')
|
323
|
+
|
324
|
+
it_should_roundtrip :datetime, nil
|
325
|
+
it_should_roundtrip :datetime, Time.now.in_time_zone
|
326
|
+
# TODO: Support DateTime here, which is used when the value is
|
327
|
+
# outside the range of a Time.
|
328
|
+
|
329
|
+
it_should_roundtrip :timestamp, nil
|
330
|
+
it_should_roundtrip :timestamp, Time.now.in_time_zone
|
331
|
+
|
332
|
+
it_should_roundtrip :time, nil
|
333
|
+
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34').in_time_zone
|
334
|
+
|
335
|
+
it_should_roundtrip :date, nil
|
336
|
+
it_should_roundtrip :date, Date.today
|
337
|
+
|
338
|
+
it_should_roundtrip :binary, nil
|
339
|
+
it_should_roundtrip :binary, ''
|
340
|
+
it_should_roundtrip :binary, "\t\n"
|
341
|
+
#it_should_roundtrip :binary, "\0\1" # TODO: the JSON gem does not handle this
|
342
|
+
|
343
|
+
it_should_roundtrip :boolean, nil
|
344
|
+
it_should_roundtrip :boolean, true
|
345
|
+
it_should_roundtrip :boolean, false
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
it_should_roundtrip_through(:to_serialized_attributes, :from_serialized_attributes)
|
350
|
+
|
351
|
+
it_should_roundtrip_through(:to_query_string, :from_query_string) do
|
172
352
|
it "should not be tripped up by delimiters in the keys" do
|
173
353
|
klass = Class.new(ActiveNomad::Base) do
|
174
354
|
attribute :'a=x', :string
|
175
355
|
attribute :'b&x', :string
|
176
356
|
end
|
177
357
|
original = klass.new("a=x" => "1", "b&x" => "2")
|
178
|
-
roundtripped = klass.
|
358
|
+
roundtripped = klass.from_query_string(original.to_query_string)
|
179
359
|
roundtripped.send("a=x").should == "1"
|
180
360
|
roundtripped.send("b&x").should == "2"
|
181
361
|
end
|
@@ -186,64 +366,30 @@ describe ActiveNomad::Base do
|
|
186
366
|
attribute :b, :string
|
187
367
|
end
|
188
368
|
original = klass.new(:a => "1=2", :b => "3&4")
|
189
|
-
roundtripped = klass.
|
369
|
+
roundtripped = klass.from_query_string(original.to_query_string)
|
190
370
|
roundtripped.a.should == "1=2"
|
191
371
|
roundtripped.b.should == "3&4"
|
192
372
|
end
|
373
|
+
end
|
193
374
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
attribute :value, type
|
199
|
-
end
|
200
|
-
instance = klass.new(:value => value)
|
201
|
-
roundtripped = klass.deserialize(instance.serialize)
|
202
|
-
roundtripped.value.should == value
|
375
|
+
it_should_roundtrip_through(:to_json, :from_json) do
|
376
|
+
it "should not be tripped up by delimiters in the keys" do
|
377
|
+
klass = Class.new(ActiveNomad::Base) do
|
378
|
+
attribute :"'a':b,c", :string
|
203
379
|
end
|
380
|
+
original = klass.new("'a':b,c" => "1")
|
381
|
+
roundtripped = klass.from_json(original.to_json)
|
382
|
+
roundtripped.send("'a':b,c").should == "1"
|
204
383
|
end
|
205
384
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
it_should_roundtrip :text, nil
|
215
|
-
it_should_roundtrip :text, ''
|
216
|
-
it_should_roundtrip :text, 'hi'
|
217
|
-
|
218
|
-
it_should_roundtrip :float, nil
|
219
|
-
it_should_roundtrip :float, 0
|
220
|
-
it_should_roundtrip :float, 0.123
|
221
|
-
|
222
|
-
it_should_roundtrip :decimal, nil
|
223
|
-
it_should_roundtrip :decimal, BigDecimal.new('0')
|
224
|
-
it_should_roundtrip :decimal, BigDecimal.new('123.45')
|
225
|
-
|
226
|
-
it_should_roundtrip :datetime, nil
|
227
|
-
it_should_roundtrip :datetime, Time.now.in_time_zone
|
228
|
-
# TODO: Support DateTime here, which is used when the value is
|
229
|
-
# outside the range of a Time.
|
230
|
-
|
231
|
-
it_should_roundtrip :timestamp, nil
|
232
|
-
it_should_roundtrip :timestamp, Time.now.in_time_zone
|
233
|
-
|
234
|
-
it_should_roundtrip :time, nil
|
235
|
-
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34').in_time_zone
|
236
|
-
|
237
|
-
it_should_roundtrip :date, nil
|
238
|
-
it_should_roundtrip :date, Date.today
|
239
|
-
|
240
|
-
it_should_roundtrip :binary, nil
|
241
|
-
it_should_roundtrip :binary, ''
|
242
|
-
it_should_roundtrip :binary, "\0\1"
|
243
|
-
|
244
|
-
it_should_roundtrip :boolean, nil
|
245
|
-
it_should_roundtrip :boolean, true
|
246
|
-
it_should_roundtrip :boolean, false
|
385
|
+
it "should not be tripped up by delimiters in the values" do
|
386
|
+
klass = Class.new(ActiveNomad::Base) do
|
387
|
+
attribute :a, :string
|
388
|
+
end
|
389
|
+
original = klass.new(:a => "'a':b,c")
|
390
|
+
roundtripped = klass.from_json(original.to_json)
|
391
|
+
roundtripped.a.should == "'a':b,c"
|
392
|
+
end
|
247
393
|
end
|
248
394
|
|
249
395
|
describe ".transaction" do
|
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: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.4
|
10
|
+
version: 0.1.0
|
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-05 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|