toystore 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +9 -0
- data/Changelog.md +10 -1
- data/Gemfile +14 -13
- data/README.md +213 -2
- data/examples/plain_old_object.rb +54 -0
- data/examples/plain_old_object_on_roids.rb +160 -0
- data/lib/toy.rb +3 -1
- data/lib/toy/association_serialization.rb +50 -0
- data/lib/toy/attribute.rb +17 -2
- data/lib/toy/equality.rb +5 -1
- data/lib/toy/identity/abstract_key_factory.rb +5 -0
- data/lib/toy/identity_map.rb +1 -2
- data/lib/toy/inheritance.rb +29 -0
- data/lib/toy/inspect.rb +17 -4
- data/lib/toy/object.rb +6 -0
- data/lib/toy/querying.rb +20 -3
- data/lib/toy/reference.rb +18 -4
- data/lib/toy/reloadable.rb +2 -2
- data/lib/toy/serialization.rb +1 -40
- data/lib/toy/store.rb +2 -2
- data/lib/toy/timestamps.rb +3 -1
- data/lib/toy/version.rb +2 -2
- data/spec/helper.rb +2 -3
- data/spec/support/constants.rb +15 -15
- data/spec/toy/association_serialization_spec.rb +103 -0
- data/spec/toy/attribute_spec.rb +17 -1
- data/spec/toy/equality_spec.rb +9 -2
- data/spec/toy/extensions/array_spec.rb +2 -2
- data/spec/toy/identity/uuid_key_factory_spec.rb +35 -3
- data/spec/toy/identity_map_spec.rb +4 -0
- data/spec/toy/inheritance_spec.rb +93 -0
- data/spec/toy/inspect_spec.rb +12 -4
- data/spec/toy/object_spec.rb +47 -0
- data/spec/toy/plugins_spec.rb +4 -4
- data/spec/toy/querying_spec.rb +71 -11
- data/spec/toy/reference_spec.rb +82 -72
- data/spec/toy/serialization_spec.rb +16 -111
- data/spec/toy/store_spec.rb +14 -28
- metadata +23 -13
- data/Gemfile.lock +0 -71
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Toy::AssociationSerialization do
|
4
|
+
uses_constants('User', 'Game', 'Move')
|
5
|
+
|
6
|
+
before do
|
7
|
+
User.attribute :name, String
|
8
|
+
User.attribute :age, Integer
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "serializing relationships" do
|
12
|
+
before do
|
13
|
+
User.list :games, :inverse_of => :user
|
14
|
+
Game.reference :user
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should include references" do
|
18
|
+
user = User.create(:name => 'John', :age => 28)
|
19
|
+
game = user.games.create
|
20
|
+
|
21
|
+
MultiJson.load(game.to_json(:include => [:user])).should == {
|
22
|
+
'game' => {
|
23
|
+
'id' => game.id,
|
24
|
+
'user_id' => user.id,
|
25
|
+
'user' => {
|
26
|
+
'name' => 'John',
|
27
|
+
'game_ids' => [game.id],
|
28
|
+
'id' => user.id,
|
29
|
+
'age' => 28,
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should include lists" do
|
36
|
+
user = User.create(:name => 'John', :age => 28)
|
37
|
+
game = user.games.create
|
38
|
+
MultiJson.load(user.to_json(:include => [:games])).should == {
|
39
|
+
'user' => {
|
40
|
+
'name' => 'John',
|
41
|
+
'game_ids' => [game.id],
|
42
|
+
'id' => user.id,
|
43
|
+
'age' => 28,
|
44
|
+
'games' => [{'id' => game.id, 'user_id' => user.id}],
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not cause circular reference JSON errors for references" do
|
50
|
+
user = User.create(:name => 'John', :age => 28)
|
51
|
+
game = user.games.create
|
52
|
+
|
53
|
+
MultiJson.load(ActiveSupport::JSON.encode(game.user)).should == {
|
54
|
+
'user' => {
|
55
|
+
'name' => 'John',
|
56
|
+
'game_ids' => [game.id],
|
57
|
+
'id' => user.id,
|
58
|
+
'age' => 28
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not cause circular reference JSON errors for references when called indirectly" do
|
64
|
+
user = User.create(:name => 'John', :age => 28)
|
65
|
+
game = user.games.create
|
66
|
+
|
67
|
+
MultiJson.load(ActiveSupport::JSON.encode([game.user])).should == [
|
68
|
+
'user' => {
|
69
|
+
'name' => 'John',
|
70
|
+
'game_ids' => [game.id],
|
71
|
+
'id' => user.id,
|
72
|
+
'age' => 28
|
73
|
+
}
|
74
|
+
]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not cause circular reference JSON errors for lists" do
|
78
|
+
user = User.create(:name => 'John', :age => 28)
|
79
|
+
game = user.games.create
|
80
|
+
|
81
|
+
MultiJson.load(ActiveSupport::JSON.encode(user.games)).should == [{
|
82
|
+
'game' => {
|
83
|
+
'id' => game.id,
|
84
|
+
'user_id' => user.id
|
85
|
+
}
|
86
|
+
}]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not cause circular reference JSON errors for lists when called indirectly" do
|
90
|
+
user = User.create(:name => 'John', :age => 28)
|
91
|
+
game = user.games.create
|
92
|
+
|
93
|
+
MultiJson.load(ActiveSupport::JSON.encode({:games => user.games})).should == {
|
94
|
+
'games' => [{
|
95
|
+
'game' => {
|
96
|
+
'id' => game.id,
|
97
|
+
'user_id' => user.id
|
98
|
+
}
|
99
|
+
}]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/spec/toy/attribute_spec.rb
CHANGED
@@ -72,6 +72,22 @@ describe Toy::Attribute do
|
|
72
72
|
Toy::Attribute.new(User, :age, String, :default => 1).default.should == 1
|
73
73
|
end
|
74
74
|
|
75
|
+
it "allows defaulting to nil" do
|
76
|
+
Toy::Attribute.new(User, :age, String, :default => nil).default.should be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it "works with callable default" do
|
80
|
+
default = lambda { 'foo' }
|
81
|
+
attribute = Toy::Attribute.new(User, :age, String, :default => default)
|
82
|
+
attribute.default.should == 'foo'
|
83
|
+
end
|
84
|
+
|
85
|
+
it "passes model to callable default" do
|
86
|
+
default = lambda { |model| model.name.downcase }
|
87
|
+
attribute = Toy::Attribute.new(User, :age, String, :default => default)
|
88
|
+
attribute.default.should == 'user'
|
89
|
+
end
|
90
|
+
|
75
91
|
it "returns store_default if set for type" do
|
76
92
|
Toy::Attribute.new(User, :skills, Array).default.should == []
|
77
93
|
end
|
@@ -173,4 +189,4 @@ describe Toy::Attribute do
|
|
173
189
|
Toy::Attribute.new(User, :twitter_access_token, String).abbr?.should be_false
|
174
190
|
end
|
175
191
|
end
|
176
|
-
end
|
192
|
+
end
|
data/spec/toy/equality_spec.rb
CHANGED
@@ -17,7 +17,7 @@ describe Toy::Equality do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
describe "equal?" do
|
20
|
+
describe "#equal?" do
|
21
21
|
it "returns true if same object" do
|
22
22
|
user = User.new(:id => 1)
|
23
23
|
user.should equal(user)
|
@@ -29,4 +29,11 @@ describe Toy::Equality do
|
|
29
29
|
user.should_not equal(other_user)
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
|
+
describe "#hash" do
|
34
|
+
it "returns the hash of the id" do
|
35
|
+
user = User.new
|
36
|
+
user.hash.should eq(user.id.hash)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -4,7 +4,7 @@ describe "Array.to_store" do
|
|
4
4
|
it "should convert value to_a" do
|
5
5
|
Array.to_store([1, 2, 3, 4]).should == [1, 2, 3, 4]
|
6
6
|
Array.to_store('1').should == ['1']
|
7
|
-
Array.to_store({'1' => '2'
|
7
|
+
Array.to_store({'1' => '2'}).should == [['1', '2']]
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -22,4 +22,4 @@ describe "Array.store_default" do
|
|
22
22
|
it "returns emtpy array" do
|
23
23
|
Array.store_default.should == []
|
24
24
|
end
|
25
|
-
end
|
25
|
+
end
|
@@ -4,11 +4,43 @@ describe Toy::Identity::UUIDKeyFactory do
|
|
4
4
|
uses_constants('User')
|
5
5
|
|
6
6
|
it "should use String as key_type" do
|
7
|
-
|
7
|
+
subject.key_type.should be(String)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should use uuid for next_key" do
|
11
|
-
|
11
|
+
subject.next_key(nil).length.should == 36
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#eql?" do
|
15
|
+
it "returns true for same class and key type" do
|
16
|
+
subject.eql?(Toy::Identity::UUIDKeyFactory.new).should be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns false for same class and different key type" do
|
20
|
+
other = Toy::Identity::UUIDKeyFactory.new
|
21
|
+
other.stub(:key_type).and_return(Integer)
|
22
|
+
subject.eql?(other).should be_false
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns false for different classes" do
|
26
|
+
subject.eql?(Object.new).should be_false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#==" do
|
31
|
+
it "returns true for same class and key type" do
|
32
|
+
subject.==(Toy::Identity::UUIDKeyFactory.new).should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns false for same class and different key type" do
|
36
|
+
other = Toy::Identity::UUIDKeyFactory.new
|
37
|
+
other.stub(:key_type).and_return(Integer)
|
38
|
+
subject.==(other).should be_false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns false for different classes" do
|
42
|
+
subject.==(Object.new).should be_false
|
43
|
+
end
|
12
44
|
end
|
13
45
|
|
14
46
|
describe "Declaring key to be uuid" do
|
@@ -24,4 +56,4 @@ describe Toy::Identity::UUIDKeyFactory do
|
|
24
56
|
User.attributes['id'].type.should be(String)
|
25
57
|
end
|
26
58
|
end
|
27
|
-
end
|
59
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'Toy Inheritance' do
|
4
|
+
describe 'using Toy::Object' do
|
5
|
+
before do
|
6
|
+
class ::Parent
|
7
|
+
include Toy::Object
|
8
|
+
|
9
|
+
attribute :name, String
|
10
|
+
end
|
11
|
+
|
12
|
+
class ::Child < Parent; end
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
Object.send :remove_const, 'Parent' if defined?(::Parent)
|
17
|
+
Object.send :remove_const, 'Child' if defined?(::Child)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "duplicates attributes" do
|
21
|
+
Parent.attributes.each do |name, attribute|
|
22
|
+
Child.attributes.key?(name).should be_true
|
23
|
+
Child.attributes[name].should eq(Parent.attributes[name])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does not add attributes to the parent" do
|
28
|
+
Child.attribute(:foo, String)
|
29
|
+
Parent.attributes.keys.should_not include(:foo)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "adds type attribute" do
|
33
|
+
Child.attribute?(:type).should be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sets type to class name" do
|
37
|
+
Child.new.type.should eq('Child')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "sets the key factory to same as parent" do
|
41
|
+
Child.key_factory.should eq(Parent.key_factory)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'using Toy::Store' do
|
46
|
+
before do
|
47
|
+
class ::Degree
|
48
|
+
include Toy::Store
|
49
|
+
end
|
50
|
+
|
51
|
+
class ::Parent
|
52
|
+
include Toy::Store
|
53
|
+
|
54
|
+
attribute :name, String
|
55
|
+
list :degrees, Degree
|
56
|
+
reference :degree, Degree
|
57
|
+
end
|
58
|
+
|
59
|
+
class ::Child < Parent
|
60
|
+
list :odd_degrees, Degree
|
61
|
+
reference :odd_degree, Degree
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
after do
|
66
|
+
Object.send :remove_const, 'Parent' if defined?(::Parent)
|
67
|
+
Object.send :remove_const, 'Child' if defined?(::Child)
|
68
|
+
Object.send :remove_const, 'Degree' if defined?(::Degree)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "duplicates lists" do
|
72
|
+
Child.lists.keys.should include(:degrees)
|
73
|
+
Child.lists.keys.should include(:odd_degrees)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "does not add lists to parent" do
|
77
|
+
Parent.lists.keys.should_not include(:odd_degrees)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "duplicates references" do
|
81
|
+
Child.references.keys.should include(:degree)
|
82
|
+
Child.references.keys.should include(:odd_degree)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does not add references to parent" do
|
86
|
+
Parent.references.keys.should_not include(:odd_degree)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "sets the adapter to the same as the parent" do
|
90
|
+
Child.adapter.should eq(Parent.adapter)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/toy/inspect_spec.rb
CHANGED
@@ -8,8 +8,16 @@ describe Toy::Attributes do
|
|
8
8
|
User.attribute(:age, Integer)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
describe ".inspect" do
|
12
|
+
it "prints out attribute names and types" do
|
13
|
+
User.inspect.should == %Q(User(id:String age:Integer name:String))
|
14
|
+
end
|
14
15
|
end
|
15
|
-
|
16
|
+
|
17
|
+
describe "#inspect" do
|
18
|
+
it "prints out object id and attributes sorted with values" do
|
19
|
+
user = User.new(:age => 28, :name => 'John')
|
20
|
+
user.inspect.should == %Q(#<User:#{user.object_id} id: "#{user.id}", age: 28, name: "John">)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Toy::Object do
|
4
|
+
uses_objects('User')
|
5
|
+
|
6
|
+
it "adds model naming" do
|
7
|
+
model_name = User.model_name
|
8
|
+
model_name.should == 'User'
|
9
|
+
model_name.singular.should == 'user'
|
10
|
+
model_name.plural.should == 'users'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds to_model" do
|
14
|
+
user = User.new
|
15
|
+
user.to_model.should == user
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#persisted?" do
|
19
|
+
it "returns false" do
|
20
|
+
User.new.persisted?.should be_false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#to_key" do
|
25
|
+
it "returns [id] if persisted" do
|
26
|
+
user = User.new
|
27
|
+
user.stub(:persisted?).and_return(true)
|
28
|
+
user.to_key.should == [user.id]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns nil if not persisted" do
|
32
|
+
User.new.to_key.should be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#to_param" do
|
37
|
+
it "returns key joined by - if to_key present" do
|
38
|
+
user = User.new
|
39
|
+
user.stub(:persisted?).and_return(true)
|
40
|
+
user.to_param.should == user.to_key.join('-')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns nil if to_key nil" do
|
44
|
+
User.new.to_param.should be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/spec/toy/plugins_spec.rb
CHANGED
@@ -31,9 +31,9 @@ describe Toy::Plugins do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it "adds plugins to classes declared after plugin was called" do
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
klass = Class.new { include Toy::Store }
|
35
|
+
klass.foo.should == 'foo'
|
36
|
+
klass.new.bar.should == 'bar'
|
37
37
|
end
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
data/spec/toy/querying_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe Toy::Querying do
|
4
|
-
uses_constants
|
4
|
+
uses_constants 'User', 'Game'
|
5
5
|
|
6
6
|
before do
|
7
7
|
User.attribute :name, String
|
@@ -87,20 +87,80 @@ describe Toy::Querying do
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
describe ".load
|
91
|
-
before
|
92
|
-
|
90
|
+
describe ".load" do
|
91
|
+
before do
|
92
|
+
class Admin < ::User; end
|
93
|
+
end
|
94
|
+
|
95
|
+
after do
|
96
|
+
Object.send :remove_const, 'Admin' if defined?(Admin)
|
97
|
+
end
|
98
|
+
|
99
|
+
context "without type, hash attrs" do
|
100
|
+
before do
|
101
|
+
@doc = User.load('1', :name => 'John')
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns instance" do
|
105
|
+
@doc.should be_instance_of(User)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "marks object as persisted" do
|
109
|
+
@doc.should be_persisted
|
110
|
+
end
|
111
|
+
|
112
|
+
it "decodes the object" do
|
113
|
+
@doc.name.should == 'John'
|
114
|
+
end
|
115
|
+
end
|
93
116
|
|
94
|
-
|
95
|
-
|
117
|
+
context "without type, nil attrs" do
|
118
|
+
before do
|
119
|
+
@doc = User.load('1', nil)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "returns instance" do
|
123
|
+
@doc.should be_instance_of(User)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "marks object as persisted" do
|
127
|
+
@doc.should be_persisted
|
128
|
+
end
|
129
|
+
|
130
|
+
it "decodes the object" do
|
131
|
+
@doc.name.should be_nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "with symbol type" do
|
136
|
+
before do
|
137
|
+
@doc = User.load('1', :type => 'Admin', :name => 'John')
|
138
|
+
end
|
139
|
+
|
140
|
+
it "returns instance of type" do
|
141
|
+
@doc.should be_instance_of(Admin)
|
142
|
+
end
|
96
143
|
end
|
97
144
|
|
98
|
-
|
99
|
-
|
145
|
+
context "with string type" do
|
146
|
+
before do
|
147
|
+
@doc = User.load('1', 'type' => 'Admin', :name => 'John')
|
148
|
+
end
|
149
|
+
|
150
|
+
it "returns instance of type" do
|
151
|
+
@doc.should be_instance_of(Admin)
|
152
|
+
end
|
100
153
|
end
|
101
154
|
|
102
|
-
|
103
|
-
|
155
|
+
context "for type that doesn't exist" do
|
156
|
+
before do
|
157
|
+
Object.send :remove_const, 'Admin' if defined?(::Admin)
|
158
|
+
@doc = User.load('1', 'type' => 'Admin', :name => 'John')
|
159
|
+
end
|
160
|
+
|
161
|
+
it "returns instance of loading class" do
|
162
|
+
@doc.should be_instance_of(User)
|
163
|
+
end
|
104
164
|
end
|
105
165
|
end
|
106
|
-
end
|
166
|
+
end
|