active_nomad 0.0.2
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 +7 -0
- data/LICENSE +20 -0
- data/README.markdown +63 -0
- data/Rakefile +3 -0
- data/lib/active_nomad/version.rb +11 -0
- data/lib/active_nomad.rb +127 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/unit/active_nomad_spec.rb +238 -0
- metadata +110 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 George Ogata
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Active Nomad
|
|
2
|
+
|
|
3
|
+
ActiveRecord objects with a customizable persistence strategy.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Sometimes you want an Active Record object that does not live in the database.
|
|
8
|
+
Perhaps it never needs to be persisted, or you'd like to store it in a cookie,
|
|
9
|
+
or a file, but it would still be handy to have ActiveRecord's ability to cast
|
|
10
|
+
values, run validations, or fire callbacks.
|
|
11
|
+
|
|
12
|
+
Ideally, the persistence strategy would be pluggable. With Active Nomad, it is!
|
|
13
|
+
|
|
14
|
+
## How
|
|
15
|
+
|
|
16
|
+
Subclass from ActiveNomad::Base and declare your attributes with the
|
|
17
|
+
`attribute` class method. The arguments look just like creating a column in a
|
|
18
|
+
migration:
|
|
19
|
+
|
|
20
|
+
class Thing < ActiveNomad::Base
|
|
21
|
+
attribute :name, :string, :limit => 20
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
To persist the record, Active Nomad calls `persist`, which calls a
|
|
25
|
+
Proc registered by `to_save`. For example, here's how you could
|
|
26
|
+
persist to a cookie:
|
|
27
|
+
|
|
28
|
+
thing = Thing.deserialize(cookies[:thing])
|
|
29
|
+
thing.to_save do |thing|
|
|
30
|
+
cookies[:thing] = thing.serialize
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Things to note:
|
|
35
|
+
|
|
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
|
+
* The proc should return true if persistence was successful, false
|
|
40
|
+
otherwise. This will be the return value of `save`, etc.
|
|
41
|
+
* You may alternatively override `persist` in a subclass if you
|
|
42
|
+
don't want to register a proc for every instance.
|
|
43
|
+
|
|
44
|
+
## Notes
|
|
45
|
+
|
|
46
|
+
Only ActiveRecord 2.3 compatible. ActiveRecord 3.0 has a more modular
|
|
47
|
+
architecture which makes this largely unnecessary.
|
|
48
|
+
|
|
49
|
+
## Contributing
|
|
50
|
+
|
|
51
|
+
* Bug reports: http://github.com/oggy/active_nomad/issues
|
|
52
|
+
* Source: http://github.com/oggy/active_nomad
|
|
53
|
+
* Patches: Fork on Github, send pull request.
|
|
54
|
+
* Ensure patch includes tests.
|
|
55
|
+
* Leave the version alone, or bump it in a separate commit.
|
|
56
|
+
|
|
57
|
+
## Copyright
|
|
58
|
+
|
|
59
|
+
Copyright (c) 2010 George Ogata. See LICENSE for details.
|
|
60
|
+
|
|
61
|
+
## Credit
|
|
62
|
+
|
|
63
|
+
Inspired by Jonathan Viney's ActiveRecord::BaseWithoutTable.
|
data/Rakefile
ADDED
data/lib/active_nomad.rb
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
|
|
4
|
+
module ActiveNomad
|
|
5
|
+
NoPersistenceStrategy = Class.new(RuntimeError)
|
|
6
|
+
|
|
7
|
+
class Base < ActiveRecord::Base
|
|
8
|
+
#
|
|
9
|
+
# Tell this record how to save itself.
|
|
10
|
+
#
|
|
11
|
+
def to_save(&proc)
|
|
12
|
+
@save_proc = proc
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Return the attributes of this object serialized as a valid query
|
|
17
|
+
# string.
|
|
18
|
+
#
|
|
19
|
+
# Attributes are sorted by name.
|
|
20
|
+
#
|
|
21
|
+
def serialize
|
|
22
|
+
self.class.columns.map do |column|
|
|
23
|
+
name = column.name
|
|
24
|
+
value = serialize_value(send(name), column.type) or
|
|
25
|
+
next
|
|
26
|
+
"#{CGI.escape(name)}=#{value}"
|
|
27
|
+
end.compact.sort.join('&')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.deserialize(string)
|
|
31
|
+
params = string ? CGI.parse(string.strip) : {}
|
|
32
|
+
instance = new
|
|
33
|
+
columns.map do |column|
|
|
34
|
+
next if !params.key?(column.name)
|
|
35
|
+
value = params[column.name].first
|
|
36
|
+
instance.send "#{column.name}=", deserialize_value(value, column.type)
|
|
37
|
+
end
|
|
38
|
+
instance
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
protected
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# Persist the object.
|
|
45
|
+
#
|
|
46
|
+
# The default is to call the block registered with
|
|
47
|
+
# #to_save. Override if you don't want to use #to_save.
|
|
48
|
+
#
|
|
49
|
+
def persist
|
|
50
|
+
@save_proc or
|
|
51
|
+
raise NoPersistenceStrategy, "no persistence strategy - use #to_save to define one"
|
|
52
|
+
@save_proc.call(self)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
class FakeAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
|
58
|
+
def native_database_types
|
|
59
|
+
@native_database_types ||= Hash.new{|h,k| h[k] = k.to_s}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def initialize
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
FAKE_ADAPTER = FakeAdapter.new
|
|
67
|
+
|
|
68
|
+
class << self
|
|
69
|
+
#
|
|
70
|
+
# Declare a column.
|
|
71
|
+
#
|
|
72
|
+
# Works like #add_column in a migration:
|
|
73
|
+
#
|
|
74
|
+
# column :name, :string, :limit => 1, :null => false, :default => 'Joe'
|
|
75
|
+
#
|
|
76
|
+
def attribute(name, type, options={})
|
|
77
|
+
sql_type = FAKE_ADAPTER.type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
|
78
|
+
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], sql_type, options[:null] != false)
|
|
79
|
+
reset_column_information
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def columns
|
|
83
|
+
@columns ||= []
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Reset everything, except the column information
|
|
87
|
+
def reset_column_information
|
|
88
|
+
columns = @columns
|
|
89
|
+
super
|
|
90
|
+
@columns = columns
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
self.abstract_class = true
|
|
95
|
+
|
|
96
|
+
def create_or_update_without_callbacks
|
|
97
|
+
errors.empty?
|
|
98
|
+
persist
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def serialize_value(value, type)
|
|
102
|
+
return nil if value.nil?
|
|
103
|
+
case type
|
|
104
|
+
when :datetime, :timestamp, :time
|
|
105
|
+
value.to_time.to_i.to_s
|
|
106
|
+
when :date
|
|
107
|
+
(value.to_date - DATE_EPOCH).to_i.to_s
|
|
108
|
+
else
|
|
109
|
+
CGI.escape(value.to_s)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.deserialize_value(string, type)
|
|
114
|
+
return nil if string.nil?
|
|
115
|
+
case type
|
|
116
|
+
when :datetime, :timestamp, :time
|
|
117
|
+
Time.at(string.to_i)
|
|
118
|
+
when :date
|
|
119
|
+
DATE_EPOCH + string.to_i
|
|
120
|
+
else
|
|
121
|
+
CGI.unescape(string)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
DATE_EPOCH = Date.parse('1970-01-01')
|
|
126
|
+
end
|
|
127
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveNomad::Base do
|
|
4
|
+
describe ".attribute" do
|
|
5
|
+
it "should create a column with the given name and type" do
|
|
6
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
7
|
+
attribute :integer_attribute, :integer
|
|
8
|
+
attribute :string_attribute, :string
|
|
9
|
+
attribute :text_attribute, :text
|
|
10
|
+
attribute :float_attribute, :float
|
|
11
|
+
attribute :decimal_attribute, :decimal
|
|
12
|
+
attribute :datetime_attribute, :datetime
|
|
13
|
+
attribute :timestamp_attribute, :timestamp
|
|
14
|
+
attribute :time_attribute, :time
|
|
15
|
+
attribute :date_attribute, :date
|
|
16
|
+
attribute :binary_attribute, :binary
|
|
17
|
+
attribute :boolean_attribute, :boolean
|
|
18
|
+
end
|
|
19
|
+
klass.columns.should have(11).columns
|
|
20
|
+
klass.columns_hash['integer_attribute'].type.should == :integer
|
|
21
|
+
klass.columns_hash['string_attribute'].type.should == :string
|
|
22
|
+
klass.columns_hash['text_attribute'].type.should == :text
|
|
23
|
+
klass.columns_hash['float_attribute'].type.should == :float
|
|
24
|
+
klass.columns_hash['decimal_attribute'].type.should == :decimal
|
|
25
|
+
klass.columns_hash['datetime_attribute'].type.should == :datetime
|
|
26
|
+
klass.columns_hash['timestamp_attribute'].type.should == :timestamp
|
|
27
|
+
klass.columns_hash['time_attribute'].type.should == :time
|
|
28
|
+
klass.columns_hash['date_attribute'].type.should == :date
|
|
29
|
+
klass.columns_hash['binary_attribute'].type.should == :binary
|
|
30
|
+
klass.columns_hash['boolean_attribute'].type.should == :boolean
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should treat a :limit option like #add_column in a migration" do
|
|
34
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
35
|
+
attribute :name, :string, :limit => 100
|
|
36
|
+
end
|
|
37
|
+
klass.columns_hash['name'].limit.should == 100
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should treat :scale and :precision options like #add_column in a migration" do
|
|
41
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
42
|
+
attribute :value, :decimal, :precision => 5, :scale => 2
|
|
43
|
+
end
|
|
44
|
+
klass.columns_hash['value'].scale.should == 2
|
|
45
|
+
klass.columns_hash['value'].precision.should == 5
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should treat a :null option like #add_column in a migration" do
|
|
49
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
50
|
+
attribute :mandatory, :decimal, :null => false
|
|
51
|
+
attribute :optional, :decimal, :null => true
|
|
52
|
+
end
|
|
53
|
+
klass.columns_hash['mandatory'].null.should be_false
|
|
54
|
+
klass.columns_hash['optional'].null.should be_true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should treat a :default option like #add_column in a migration" do
|
|
58
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
59
|
+
attribute :name, :string, :default => 'Joe'
|
|
60
|
+
end
|
|
61
|
+
klass.columns_hash['name'].default.should == 'Joe'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "an integer attribute" do
|
|
66
|
+
it "should cast the value from a string like ActiveRecord" do
|
|
67
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
68
|
+
attribute :value, :integer
|
|
69
|
+
end
|
|
70
|
+
instance = klass.new(:value => '123')
|
|
71
|
+
instance.value.should == 123
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "#save" do
|
|
76
|
+
describe "when no save strategy has been defined" do
|
|
77
|
+
it "should raise a NoPersistenceStrategy error" do
|
|
78
|
+
instance = ActiveNomad::Base.new
|
|
79
|
+
lambda{instance.save}.should raise_error(ActiveNomad::NoPersistenceStrategy)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "when a save strategy has been defined" do
|
|
84
|
+
before do
|
|
85
|
+
saves = @saves = []
|
|
86
|
+
@instance = ActiveNomad::Base.new
|
|
87
|
+
@instance.to_save do |*args|
|
|
88
|
+
saves << args
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should call the save_proc with the record as an argument" do
|
|
93
|
+
@instance.save
|
|
94
|
+
@saves.should == [[@instance]]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "when #persist has been overridden" do
|
|
99
|
+
before do
|
|
100
|
+
saves = @saves = []
|
|
101
|
+
@klass = Class.new(ActiveNomad::Base) do
|
|
102
|
+
define_method :persist do |*args|
|
|
103
|
+
saves << args
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "should call it and return the result" do
|
|
109
|
+
instance = @klass.new
|
|
110
|
+
instance.save
|
|
111
|
+
@saves.should == [[]]
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "#serialize" do
|
|
117
|
+
it "should serialize the attributes as a query string" do
|
|
118
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
119
|
+
attribute :first_name, :string
|
|
120
|
+
attribute :last_name, :string
|
|
121
|
+
end
|
|
122
|
+
instance = klass.new(:first_name => 'Joe', :last_name => 'Blow')
|
|
123
|
+
instance.serialize.should == 'first_name=Joe&last_name=Blow'
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe ".deserialize" do
|
|
128
|
+
it "should create a new record with no attributes set if nil is given" do
|
|
129
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
130
|
+
attribute :name, :string
|
|
131
|
+
end
|
|
132
|
+
instance = klass.deserialize(nil)
|
|
133
|
+
instance.name.should be_nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "should create a new record with no attributes set if an empty string is given" do
|
|
137
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
138
|
+
attribute :name, :string
|
|
139
|
+
end
|
|
140
|
+
instance = klass.deserialize('')
|
|
141
|
+
instance.name.should be_nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should create a new record with no attributes set if a blank string is given" do
|
|
145
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
146
|
+
attribute :name, :string
|
|
147
|
+
end
|
|
148
|
+
instance = klass.deserialize(" \t")
|
|
149
|
+
instance.name.should be_nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "should leave defaults alone for attributes which are not set" do
|
|
153
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
154
|
+
attribute :name, :string, :default => 'Joe'
|
|
155
|
+
end
|
|
156
|
+
instance = klass.deserialize(" \t")
|
|
157
|
+
instance.name.should == 'Joe'
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe "roundtripping through #serialize and .deserialize" do
|
|
162
|
+
it "should not be tripped up by delimiters in the keys" do
|
|
163
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
164
|
+
attribute :'a=x', :string
|
|
165
|
+
attribute :'b&x', :string
|
|
166
|
+
end
|
|
167
|
+
original = klass.new("a=x" => "1", "b&x" => "2")
|
|
168
|
+
roundtripped = klass.deserialize(original.serialize)
|
|
169
|
+
roundtripped.send("a=x").should == "1"
|
|
170
|
+
roundtripped.send("b&x").should == "2"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should not be tripped up by delimiters in the values" do
|
|
174
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
175
|
+
attribute :a, :string
|
|
176
|
+
attribute :b, :string
|
|
177
|
+
end
|
|
178
|
+
original = klass.new(:a => "1=2", :b => "3&4")
|
|
179
|
+
roundtripped = klass.deserialize(original.serialize)
|
|
180
|
+
roundtripped.a.should == "1=2"
|
|
181
|
+
roundtripped.b.should == "3&4"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def self.it_should_roundtrip(type, value)
|
|
185
|
+
value = Time.at(value.to_i) if value.is_a?(Time) # chop off subseconds
|
|
186
|
+
it "should roundtrip #{value.inspect} correctly as a #{type}" do
|
|
187
|
+
klass = Class.new(ActiveNomad::Base) do
|
|
188
|
+
attribute :value, type
|
|
189
|
+
end
|
|
190
|
+
instance = klass.new(:value => value)
|
|
191
|
+
roundtripped = klass.deserialize(instance.serialize)
|
|
192
|
+
roundtripped.value.should == value
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it_should_roundtrip :integer, nil
|
|
197
|
+
it_should_roundtrip :integer, 0
|
|
198
|
+
it_should_roundtrip :integer, 123
|
|
199
|
+
|
|
200
|
+
it_should_roundtrip :string, nil
|
|
201
|
+
it_should_roundtrip :string, ''
|
|
202
|
+
it_should_roundtrip :string, 'hi'
|
|
203
|
+
|
|
204
|
+
it_should_roundtrip :text, nil
|
|
205
|
+
it_should_roundtrip :text, ''
|
|
206
|
+
it_should_roundtrip :text, 'hi'
|
|
207
|
+
|
|
208
|
+
it_should_roundtrip :float, nil
|
|
209
|
+
it_should_roundtrip :float, 0
|
|
210
|
+
it_should_roundtrip :float, 0.123
|
|
211
|
+
|
|
212
|
+
it_should_roundtrip :decimal, nil
|
|
213
|
+
it_should_roundtrip :decimal, BigDecimal.new('0')
|
|
214
|
+
it_should_roundtrip :decimal, BigDecimal.new('123.45')
|
|
215
|
+
|
|
216
|
+
it_should_roundtrip :datetime, nil
|
|
217
|
+
it_should_roundtrip :datetime, Time.now.in_time_zone
|
|
218
|
+
# TODO: Support DateTime here, which is used when the value is
|
|
219
|
+
# outside the range of a Time.
|
|
220
|
+
|
|
221
|
+
it_should_roundtrip :timestamp, nil
|
|
222
|
+
it_should_roundtrip :timestamp, Time.now.in_time_zone
|
|
223
|
+
|
|
224
|
+
it_should_roundtrip :time, nil
|
|
225
|
+
it_should_roundtrip :time, Time.parse('2000-01-01 01:23:34').in_time_zone
|
|
226
|
+
|
|
227
|
+
it_should_roundtrip :date, nil
|
|
228
|
+
it_should_roundtrip :date, Date.today
|
|
229
|
+
|
|
230
|
+
it_should_roundtrip :binary, nil
|
|
231
|
+
it_should_roundtrip :binary, ''
|
|
232
|
+
it_should_roundtrip :binary, "\0\1"
|
|
233
|
+
|
|
234
|
+
it_should_roundtrip :boolean, nil
|
|
235
|
+
it_should_roundtrip :boolean, true
|
|
236
|
+
it_should_roundtrip :boolean, false
|
|
237
|
+
end
|
|
238
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: active_nomad
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 27
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
- 2
|
|
10
|
+
version: 0.0.2
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- George Ogata
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-09-28 00:00:00 -04:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: activerecord
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 3
|
|
30
|
+
segments:
|
|
31
|
+
- 2
|
|
32
|
+
- 3
|
|
33
|
+
- 0
|
|
34
|
+
version: 2.3.0
|
|
35
|
+
type: :runtime
|
|
36
|
+
version_requirements: *id001
|
|
37
|
+
- !ruby/object:Gem::Dependency
|
|
38
|
+
name: rspec
|
|
39
|
+
prerelease: false
|
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ~>
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
hash: 27
|
|
46
|
+
segments:
|
|
47
|
+
- 1
|
|
48
|
+
- 3
|
|
49
|
+
- 0
|
|
50
|
+
version: 1.3.0
|
|
51
|
+
type: :development
|
|
52
|
+
version_requirements: *id002
|
|
53
|
+
description:
|
|
54
|
+
email:
|
|
55
|
+
- george.ogata@gmail.com
|
|
56
|
+
executables: []
|
|
57
|
+
|
|
58
|
+
extensions: []
|
|
59
|
+
|
|
60
|
+
extra_rdoc_files:
|
|
61
|
+
- LICENSE
|
|
62
|
+
- README.markdown
|
|
63
|
+
files:
|
|
64
|
+
- lib/active_nomad/version.rb
|
|
65
|
+
- lib/active_nomad.rb
|
|
66
|
+
- CHANGELOG
|
|
67
|
+
- LICENSE
|
|
68
|
+
- README.markdown
|
|
69
|
+
- Rakefile
|
|
70
|
+
- spec/spec_helper.rb
|
|
71
|
+
- spec/unit/active_nomad_spec.rb
|
|
72
|
+
has_rdoc: true
|
|
73
|
+
homepage: http://github.com/oggy/active_nomad
|
|
74
|
+
licenses: []
|
|
75
|
+
|
|
76
|
+
post_install_message:
|
|
77
|
+
rdoc_options:
|
|
78
|
+
- --charset=UTF-8
|
|
79
|
+
require_paths:
|
|
80
|
+
- lib
|
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
|
+
none: false
|
|
83
|
+
requirements:
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
hash: 3
|
|
87
|
+
segments:
|
|
88
|
+
- 0
|
|
89
|
+
version: "0"
|
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
|
+
none: false
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
hash: 23
|
|
96
|
+
segments:
|
|
97
|
+
- 1
|
|
98
|
+
- 3
|
|
99
|
+
- 6
|
|
100
|
+
version: 1.3.6
|
|
101
|
+
requirements: []
|
|
102
|
+
|
|
103
|
+
rubyforge_project:
|
|
104
|
+
rubygems_version: 1.3.7
|
|
105
|
+
signing_key:
|
|
106
|
+
specification_version: 3
|
|
107
|
+
summary: ActiveRecord objects with a customizable persistence strategy.
|
|
108
|
+
test_files:
|
|
109
|
+
- spec/spec_helper.rb
|
|
110
|
+
- spec/unit/active_nomad_spec.rb
|