toystore 0.13.0 → 0.13.1

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.
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