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