toystore 0.13.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Changelog.md +12 -0
  2. data/Guardfile +2 -2
  3. data/README.md +26 -35
  4. data/examples/attributes_abbreviation.rb +2 -2
  5. data/examples/attributes_virtual.rb +2 -2
  6. data/examples/identity_map.rb +2 -2
  7. data/examples/memcached.rb +2 -2
  8. data/examples/memory.rb +2 -2
  9. data/examples/mongo.rb +2 -2
  10. data/examples/namespacing_keys.rb +1 -1
  11. data/examples/plain_old_object.rb +2 -2
  12. data/examples/plain_old_object_on_roids.rb +13 -22
  13. data/examples/redis.rb +2 -2
  14. data/examples/riak.rb +2 -2
  15. data/lib/toy.rb +4 -0
  16. data/lib/toy/attributes.rb +10 -21
  17. data/lib/toy/cloneable.rb +1 -3
  18. data/lib/toy/dirty.rb +0 -6
  19. data/lib/toy/equality.rb +3 -14
  20. data/lib/toy/extensions/symbol.rb +17 -0
  21. data/lib/toy/extensions/uuid.rb +6 -2
  22. data/lib/toy/identity.rb +39 -2
  23. data/lib/toy/inspect.rb +3 -4
  24. data/lib/toy/object.rb +1 -5
  25. data/lib/toy/persistence.rb +34 -5
  26. data/lib/toy/querying.rb +9 -9
  27. data/lib/toy/reloadable.rb +3 -3
  28. data/lib/toy/store.rb +1 -0
  29. data/lib/toy/types/json.rb +20 -0
  30. data/lib/toy/version.rb +1 -1
  31. data/spec/helper.rb +1 -0
  32. data/spec/toy/attributes_spec.rb +21 -59
  33. data/spec/toy/cloneable_spec.rb +1 -8
  34. data/spec/toy/equality_spec.rb +18 -19
  35. data/spec/toy/extensions/symbol_spec.rb +26 -0
  36. data/spec/toy/extensions/uuid_spec.rb +31 -11
  37. data/spec/toy/identity/uuid_key_factory_spec.rb +4 -4
  38. data/spec/toy/identity_spec.rb +111 -5
  39. data/spec/toy/inheritance_spec.rb +4 -4
  40. data/spec/toy/inspect_spec.rb +3 -3
  41. data/spec/toy/object_spec.rb +0 -40
  42. data/spec/toy/persistence_spec.rb +99 -1
  43. data/spec/toy/reloadable_spec.rb +9 -4
  44. data/spec/toy/serialization_spec.rb +16 -21
  45. data/spec/toy/types/json_spec.rb +37 -0
  46. data/spec/toy/validations_spec.rb +13 -0
  47. metadata +10 -4
@@ -30,13 +30,6 @@ describe Toy::Cloneable do
30
30
  user.clone.skills.should_not equal(user.skills)
31
31
  end
32
32
 
33
- it "regenerates id" do
34
- user.clone.tap do |clone|
35
- clone.id.should_not be_nil
36
- clone.id.should_not == user.id
37
- end
38
- end
39
-
40
33
  it "nullifies defined instance variables" do
41
34
  user.instance_variable_set("@foo", true)
42
35
  user.clone.tap do |clone|
@@ -44,4 +37,4 @@ describe Toy::Cloneable do
44
37
  end
45
38
  end
46
39
  end
47
- end
40
+ end
@@ -1,39 +1,38 @@
1
1
  require 'helper'
2
2
 
3
3
  describe Toy::Equality do
4
- uses_objects('User', 'Person')
4
+ uses_objects('User')
5
5
 
6
- describe "#eql?" do
7
- it "returns true if same class and id" do
8
- User.new(:id => 1).should eql(User.new(:id => 1))
6
+ before do
7
+ User.attribute :name, String
8
+ end
9
+
10
+ shared_examples_for 'object equality' do |method_name|
11
+ it "returns true if same class and attributes" do
12
+ User.new(:name => 'John').send(method_name, User.new(:name => 'John')).should be_true
9
13
  end
10
14
 
11
15
  it "return false if different class" do
12
- User.new(:id => 1).should_not eql(Person.new(:id => 1))
16
+ User.new(:name => 'John').send(method_name, Object.new).should be_false
13
17
  end
14
18
 
15
- it "returns false if different id" do
16
- User.new(:id => 1).should_not eql(User.new(:id => 2))
19
+ it "returns false if different attributes" do
20
+ User.new(:name => 'John').send(method_name, User.new(:name => 'Steve')).should be_false
17
21
  end
18
22
  end
19
23
 
20
- describe "#equal?" do
21
- it "returns true if same object" do
22
- user = User.new(:id => 1)
23
- user.should equal(user)
24
- end
24
+ describe "#eql?" do
25
+ include_examples 'object equality', :eql?
26
+ end
25
27
 
26
- it "returns false if not same object" do
27
- user = User.new
28
- other_user = User.new
29
- user.should_not equal(other_user)
30
- end
28
+ describe "#==" do
29
+ include_examples 'object equality', :==
31
30
  end
32
31
 
33
32
  describe "#hash" do
34
- it "returns the hash of the id" do
33
+ it "returns the hash of the attributes" do
35
34
  user = User.new
36
- user.hash.should eq(user.id.hash)
35
+ user.hash.should eq(user.attributes.hash)
37
36
  end
38
37
  end
39
38
  end
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ describe Symbol, ".to_store" do
4
+ it "should convert value to string" do
5
+ ['foo', :foo].each do |value|
6
+ described_class.to_store(value).should eq('foo')
7
+ end
8
+ end
9
+
10
+ it "should be nil if nil" do
11
+ described_class.to_store(nil).should be_nil
12
+ end
13
+ end
14
+
15
+ describe Symbol, ".from_store" do
16
+ it "should convert value to symbol" do
17
+ ['foo', :foo].each do |value|
18
+ described_class.from_store(value).should == :foo
19
+ end
20
+ end
21
+
22
+ it "should return nil if nil" do
23
+ described_class.from_store(nil).should be_nil
24
+ end
25
+ end
26
+
@@ -1,19 +1,39 @@
1
1
  require 'helper'
2
2
 
3
- describe "SimpleUUID::UUID.to_store" do
4
- it "should convert value to uuid" do
5
- uuid = SimpleUUID::UUID.new
6
- [uuid, uuid.to_guid, uuid.to_s, uuid.to_i].each do |value|
7
- SimpleUUID::UUID.from_store(value).should eq(uuid)
3
+ describe SimpleUUID::UUID do
4
+ describe ".to_store" do
5
+ it "returns nil if value is already nil" do
6
+ described_class.to_store(nil).should be(nil)
7
+ end
8
+
9
+ it "returns value if value is already uuid" do
10
+ uuid = described_class.new
11
+ described_class.to_store(uuid).should be(uuid)
12
+ end
13
+
14
+ it "converts value to uuid if not already uuid" do
15
+ uuid = described_class.new
16
+ [uuid.to_guid, uuid.to_s, uuid.to_i].each do |value|
17
+ described_class.from_store(value).should eq(uuid)
18
+ end
8
19
  end
9
20
  end
10
- end
11
21
 
12
- describe "SimpleUUID::UUID.from_store" do
13
- it "should convert value to uuid" do
14
- uuid = SimpleUUID::UUID.new
15
- [uuid, uuid.to_guid, uuid.to_s, uuid.to_i].each do |value|
16
- SimpleUUID::UUID.from_store(value).should eq(uuid)
22
+ describe ".from_store" do
23
+ it "returns nil if value is already nil" do
24
+ described_class.from_store(nil).should be(nil)
25
+ end
26
+
27
+ it "returns value if value is already uuid" do
28
+ uuid = described_class.new
29
+ described_class.from_store(uuid).should be(uuid)
30
+ end
31
+
32
+ it "converts value to uuid if not already uuid" do
33
+ uuid = described_class.new
34
+ [uuid.to_guid, uuid.to_s, uuid.to_i].each do |value|
35
+ described_class.from_store(value).should eq(uuid)
36
+ end
17
37
  end
18
38
  end
19
39
  end
@@ -13,11 +13,11 @@ describe Toy::Identity::UUIDKeyFactory do
13
13
 
14
14
  describe "#eql?" do
15
15
  it "returns true for same class and key type" do
16
- subject.eql?(Toy::Identity::UUIDKeyFactory.new).should be_true
16
+ subject.eql?(described_class.new).should be_true
17
17
  end
18
18
 
19
19
  it "returns false for same class and different key type" do
20
- other = Toy::Identity::UUIDKeyFactory.new
20
+ other = described_class.new
21
21
  other.stub(:key_type).and_return(Integer)
22
22
  subject.eql?(other).should be_false
23
23
  end
@@ -29,11 +29,11 @@ describe Toy::Identity::UUIDKeyFactory do
29
29
 
30
30
  describe "#==" do
31
31
  it "returns true for same class and key type" do
32
- subject.==(Toy::Identity::UUIDKeyFactory.new).should be_true
32
+ subject.==(described_class.new).should be_true
33
33
  end
34
34
 
35
35
  it "returns false for same class and different key type" do
36
- other = Toy::Identity::UUIDKeyFactory.new
36
+ other = described_class.new
37
37
  other.stub(:key_type).and_return(Integer)
38
38
  subject.==(other).should be_false
39
39
  end
@@ -1,7 +1,13 @@
1
1
  require 'helper'
2
2
 
3
3
  describe Toy::Identity do
4
- uses_objects('User', 'Piece')
4
+ uses_constants('User')
5
+
6
+ describe "including" do
7
+ it "adds id attribute" do
8
+ User.attributes.keys.should == ['id']
9
+ end
10
+ end
5
11
 
6
12
  describe "setting the key" do
7
13
  it "should set key factory to UUIDKeyFactory" do
@@ -51,12 +57,112 @@ describe Toy::Identity do
51
57
  end
52
58
  end
53
59
 
60
+ describe "#initialize" do
61
+ before do
62
+ User.attribute :name, String
63
+ User.attribute :age, Integer
64
+ end
65
+
66
+ it "writes id" do
67
+ id = User.new.id
68
+ id.should_not be_nil
69
+ id.size.should == 36
70
+ end
71
+
72
+ it "does not attempt to set id if already set" do
73
+ user = User.new(:id => 'frank')
74
+ user.id.should == 'frank'
75
+ end
76
+
77
+ it "defaults attributes to hash with only id" do
78
+ attrs = User.new.attributes
79
+ attrs.keys.should eq(['id'])
80
+ end
81
+ end
82
+
83
+ describe "#clone" do
84
+ it "regenerates id" do
85
+ user = User.new
86
+ user.clone.tap do |clone|
87
+ clone.id.should_not be_nil
88
+ clone.id.should_not == user.id
89
+ end
90
+ end
91
+ end
92
+
93
+ shared_examples_for 'identity equality' do |method_name|
94
+ it "returns true if same class and id" do
95
+ User.new(:id => 1).send(method_name, User.new(:id => 1)).should be_true
96
+ end
97
+
98
+ it "returns true if same class and id even if other attributes have changed" do
99
+ User.new(:id => 1, :name => 'John').send(method_name, User.new(:id => 1, :name => 'Steve')).should be_true
100
+ end
101
+
102
+ it "return false if different class" do
103
+ User.new(:id => 1).send(method_name, Object.new).should be_false
104
+ end
105
+
106
+ it "returns false if different id" do
107
+ User.new(:id => 1).send(method_name, User.new(:id => 2)).should be_false
108
+ end
109
+ end
110
+
111
+ describe "#eql?" do
112
+ include_examples 'identity equality', :eql?
113
+ end
114
+
115
+ describe "#==" do
116
+ include_examples 'identity equality', :==
117
+ end
118
+
119
+ describe "#equal?" do
120
+ it "returns true if same object" do
121
+ user = User.new(:name => 'John')
122
+ user.should equal(user)
123
+ end
124
+
125
+ it "returns false if not same object" do
126
+ user = User.new
127
+ other_user = User.new
128
+ user.should_not equal(other_user)
129
+ end
130
+ end
131
+
54
132
  describe "initializing the id" do
55
133
  it "should pass use pass the new object" do
56
- Piece.attribute(:name, String)
57
- Piece.attribute(:number, Integer)
58
- Piece.key(NameAndNumberKeyFactory.new)
59
- Piece.new(:name => 'Rook', :number => 1).id.should == 'Rook-1'
134
+ User.key NameAndNumberKeyFactory.new
135
+ User.attribute :name, String
136
+ User.attribute :number, Integer
137
+ User.new(:name => 'John', :number => 1).id.should == 'John-1'
138
+ end
139
+ end
140
+
141
+ describe "#to_key" do
142
+ it "returns [id] if persisted" do
143
+ user = User.new
144
+ user.stub(:persisted?).and_return(true)
145
+ user.to_key.should == [user.id]
146
+ end
147
+
148
+ it "returns nil if not persisted" do
149
+ User.new.to_key.should be_nil
150
+ end
151
+
152
+ context "with native uuid" do
153
+ before do
154
+ User.key :native_uuid
155
+ end
156
+
157
+ it "returns array with guid if persisted" do
158
+ user = User.new
159
+ user.stub(:persisted?).and_return(true)
160
+ user.to_key.should == [user.id.to_guid]
161
+ end
162
+
163
+ it "returns nil if not persisted" do
164
+ User.new.to_key.should be_nil
165
+ end
60
166
  end
61
167
  end
62
168
  end
@@ -36,10 +36,6 @@ describe 'Toy Inheritance' do
36
36
  it "sets type to class name" do
37
37
  Child.new.type.should eq('Child')
38
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
39
  end
44
40
 
45
41
  describe 'using Toy::Store' do
@@ -89,5 +85,9 @@ describe 'Toy Inheritance' do
89
85
  it "sets the adapter to the same as the parent" do
90
86
  Child.adapter.should eq(Parent.adapter)
91
87
  end
88
+
89
+ it "sets the key factory to same as parent" do
90
+ Child.key_factory.should eq(Parent.key_factory)
91
+ end
92
92
  end
93
93
  end
@@ -10,14 +10,14 @@ describe Toy::Attributes do
10
10
 
11
11
  describe ".inspect" do
12
12
  it "prints out attribute names and types" do
13
- User.inspect.should == %Q(User(id:String age:Integer name:String))
13
+ User.inspect.should == %Q(User(age:Integer name:String))
14
14
  end
15
15
  end
16
16
 
17
17
  describe "#inspect" do
18
- it "prints out object id and attributes sorted with values" do
18
+ it "prints out attributes sorted with values" do
19
19
  user = User.new(:age => 28, :name => 'John')
20
- user.inspect.should == %Q(#<User:#{user.object_id} id: "#{user.id}", age: 28, name: "John">)
20
+ user.inspect.should == %Q(#<User:#{user.object_id} age: 28, name: "John">)
21
21
  end
22
22
  end
23
23
  end
@@ -24,44 +24,4 @@ describe Toy::Object do
24
24
  User.new.persisted?.should be_false
25
25
  end
26
26
  end
27
-
28
- describe "#to_key" do
29
- it "returns [id] if persisted" do
30
- user = User.new
31
- user.stub(:persisted?).and_return(true)
32
- user.to_key.should == [user.id]
33
- end
34
-
35
- it "returns nil if not persisted" do
36
- User.new.to_key.should be_nil
37
- end
38
-
39
- context "with native uuid" do
40
- before do
41
- User.key :native_uuid
42
- end
43
-
44
- it "returns array with guid if persisted" do
45
- user = User.new
46
- user.stub(:persisted?).and_return(true)
47
- user.to_key.should == [user.id.to_guid]
48
- end
49
-
50
- it "returns nil if not persisted" do
51
- User.new.to_key.should be_nil
52
- end
53
- end
54
- end
55
-
56
- describe "#to_param" do
57
- it "returns key joined by - if to_key present" do
58
- user = User.new
59
- user.stub(:persisted?).and_return(true)
60
- user.to_param.should == user.to_key.join('-')
61
- end
62
-
63
- it "returns nil if to_key nil" do
64
- User.new.to_param.should be_nil
65
- end
66
- end
67
27
  end
@@ -1,7 +1,7 @@
1
1
  require 'helper'
2
2
 
3
3
  describe Toy::Persistence do
4
- uses_constants('User')
4
+ uses_constants('User', 'Game')
5
5
 
6
6
  let(:klass) do
7
7
  Class.new { include Toy::Store }
@@ -42,6 +42,37 @@ describe Toy::Persistence do
42
42
  end
43
43
  end
44
44
 
45
+ describe ".persisted_attributes" do
46
+ before do
47
+ @name = User.attribute(:name, String)
48
+ @password = User.attribute(:password, String, :virtual => true)
49
+ end
50
+
51
+ it "includes attributes that are not virtual" do
52
+ User.persisted_attributes.should include(@name)
53
+ end
54
+
55
+ it "excludes attributes that are virtual" do
56
+ User.persisted_attributes.should_not include(@password)
57
+ end
58
+
59
+ it "memoizes after first call" do
60
+ User.should_receive(:attributes).once.and_return({
61
+ 'name' => @name,
62
+ 'password' => @password,
63
+ })
64
+ User.persisted_attributes
65
+ User.persisted_attributes
66
+ User.persisted_attributes
67
+ end
68
+
69
+ it "is unmemoized when declaring a new attribute" do
70
+ User.persisted_attributes
71
+ age = User.attribute :age, Integer
72
+ User.persisted_attributes.map(&:name).sort.should eq(%w[age name])
73
+ end
74
+ end
75
+
45
76
  describe ".create" do
46
77
  before do
47
78
  User.attribute :name, String
@@ -318,6 +349,13 @@ describe Toy::Persistence do
318
349
  doc.delete
319
350
  User.key?(doc.id).should be_false
320
351
  end
352
+
353
+ it "uses persisted id for adapter delete" do
354
+ user = User.new
355
+ user.stub(:persisted_id => 1)
356
+ user.adapter.should_receive(:delete).with(1)
357
+ user.delete
358
+ end
321
359
  end
322
360
 
323
361
  describe "#destroy" do
@@ -354,4 +392,64 @@ describe Toy::Persistence do
354
392
  user.clone.should_not be_destroyed
355
393
  end
356
394
  end
395
+
396
+ describe "#persisted_id" do
397
+ it "returns id attribute value converted for storage" do
398
+ raw_value = 1
399
+ typecast_for_store_value = '1'
400
+ user = User.new(:id => raw_value)
401
+ user.persisted_id.should eq(typecast_for_store_value)
402
+ end
403
+ end
404
+
405
+ describe "#persisted_attributes" do
406
+ before do
407
+ @over = Game.attribute(:over, Boolean)
408
+ @score = Game.attribute(:creator_score, Integer, :virtual => true)
409
+ @abbr = Game.attribute(:super_secret_hash, String, :abbr => :ssh)
410
+ @rewards = Game.attribute(:rewards, Set)
411
+ @time = Game.attribute(:time, Time)
412
+ @game = Game.new({
413
+ :over => true,
414
+ :creator_score => 20,
415
+ :rewards => %w(twigs berries).to_set,
416
+ :ssh => 'h4x',
417
+ :time => nil,
418
+ })
419
+ end
420
+
421
+ it "includes persisted attributes" do
422
+ @game.persisted_attributes.should have_key('over')
423
+ end
424
+
425
+ it "includes abbreviated names for abbreviated attributes" do
426
+ @game.persisted_attributes.should have_key('ssh')
427
+ end
428
+
429
+ it "does not include full names for abbreviated attributes" do
430
+ @game.persisted_attributes.should_not have_key('super_secret_hash')
431
+ end
432
+
433
+ it "does not include virtual attributes" do
434
+ @game.persisted_attributes.should_not have_key(:creator_score)
435
+ end
436
+
437
+ it "includes to_store values for attributes" do
438
+ @game.persisted_attributes['rewards'].should be_instance_of(Array)
439
+ @game.persisted_attributes['rewards'].should == @rewards.to_store(@game.rewards)
440
+ end
441
+
442
+ it "does not include nil attributes" do
443
+ @game.persisted_attributes.should_not have_key('time')
444
+ end
445
+ end
446
+
447
+ describe "#persist" do
448
+ it "calls write on adapter with persisted id and attributes" do
449
+ user = User.new
450
+ user.stub(persisted_id: 1, persisted_attributes: {one: 'two'})
451
+ user.adapter.should_receive(:write).with(1, {one: 'two'})
452
+ user.persist
453
+ end
454
+ end
357
455
  end