toystore 0.5

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 (113) hide show
  1. data/.autotest +11 -0
  2. data/.bundle/config +2 -0
  3. data/.gitignore +6 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.lock +49 -0
  6. data/LICENSE +9 -0
  7. data/LOGGING.rdoc +16 -0
  8. data/README.rdoc +13 -0
  9. data/Rakefile +7 -0
  10. data/examples/memcached.rb +20 -0
  11. data/examples/memory.rb +20 -0
  12. data/examples/models.rb +51 -0
  13. data/examples/redis.rb +20 -0
  14. data/lib/toy.rb +81 -0
  15. data/lib/toy/attribute.rb +73 -0
  16. data/lib/toy/attributes.rb +137 -0
  17. data/lib/toy/caching.rb +20 -0
  18. data/lib/toy/callbacks.rb +48 -0
  19. data/lib/toy/collection.rb +55 -0
  20. data/lib/toy/connection.rb +28 -0
  21. data/lib/toy/dirty.rb +47 -0
  22. data/lib/toy/dolly.rb +30 -0
  23. data/lib/toy/embedded_list.rb +45 -0
  24. data/lib/toy/embedded_lists.rb +68 -0
  25. data/lib/toy/equality.rb +19 -0
  26. data/lib/toy/exceptions.rb +29 -0
  27. data/lib/toy/extensions/array.rb +22 -0
  28. data/lib/toy/extensions/boolean.rb +43 -0
  29. data/lib/toy/extensions/date.rb +24 -0
  30. data/lib/toy/extensions/float.rb +13 -0
  31. data/lib/toy/extensions/hash.rb +17 -0
  32. data/lib/toy/extensions/integer.rb +22 -0
  33. data/lib/toy/extensions/nil_class.rb +17 -0
  34. data/lib/toy/extensions/object.rb +26 -0
  35. data/lib/toy/extensions/set.rb +23 -0
  36. data/lib/toy/extensions/string.rb +17 -0
  37. data/lib/toy/extensions/time.rb +29 -0
  38. data/lib/toy/identity.rb +26 -0
  39. data/lib/toy/identity/abstract_key_factory.rb +10 -0
  40. data/lib/toy/identity/uuid_key_factory.rb +9 -0
  41. data/lib/toy/identity_map.rb +109 -0
  42. data/lib/toy/index.rb +74 -0
  43. data/lib/toy/indices.rb +56 -0
  44. data/lib/toy/inspect.rb +12 -0
  45. data/lib/toy/list.rb +46 -0
  46. data/lib/toy/lists.rb +37 -0
  47. data/lib/toy/logger.rb +26 -0
  48. data/lib/toy/mass_assignment_security.rb +16 -0
  49. data/lib/toy/persistence.rb +138 -0
  50. data/lib/toy/plugins.rb +23 -0
  51. data/lib/toy/proxies/embedded_list.rb +74 -0
  52. data/lib/toy/proxies/list.rb +97 -0
  53. data/lib/toy/proxies/proxy.rb +59 -0
  54. data/lib/toy/querying.rb +57 -0
  55. data/lib/toy/reference.rb +134 -0
  56. data/lib/toy/references.rb +19 -0
  57. data/lib/toy/serialization.rb +81 -0
  58. data/lib/toy/store.rb +36 -0
  59. data/lib/toy/timestamps.rb +22 -0
  60. data/lib/toy/validations.rb +45 -0
  61. data/lib/toy/version.rb +3 -0
  62. data/lib/toystore.rb +1 -0
  63. data/spec/helper.rb +35 -0
  64. data/spec/spec.opts +3 -0
  65. data/spec/support/constants.rb +41 -0
  66. data/spec/support/identity_map_matcher.rb +20 -0
  67. data/spec/support/name_and_number_key_factory.rb +5 -0
  68. data/spec/toy/attribute_spec.rb +176 -0
  69. data/spec/toy/attributes_spec.rb +394 -0
  70. data/spec/toy/caching_spec.rb +62 -0
  71. data/spec/toy/callbacks_spec.rb +97 -0
  72. data/spec/toy/connection_spec.rb +47 -0
  73. data/spec/toy/dirty_spec.rb +99 -0
  74. data/spec/toy/dolly_spec.rb +76 -0
  75. data/spec/toy/embedded_list_spec.rb +607 -0
  76. data/spec/toy/embedded_lists_spec.rb +172 -0
  77. data/spec/toy/equality_spec.rb +46 -0
  78. data/spec/toy/exceptions_spec.rb +18 -0
  79. data/spec/toy/extensions/array_spec.rb +25 -0
  80. data/spec/toy/extensions/boolean_spec.rb +41 -0
  81. data/spec/toy/extensions/date_spec.rb +48 -0
  82. data/spec/toy/extensions/float_spec.rb +14 -0
  83. data/spec/toy/extensions/hash_spec.rb +21 -0
  84. data/spec/toy/extensions/integer_spec.rb +29 -0
  85. data/spec/toy/extensions/nil_class_spec.rb +14 -0
  86. data/spec/toy/extensions/set_spec.rb +27 -0
  87. data/spec/toy/extensions/string_spec.rb +28 -0
  88. data/spec/toy/extensions/time_spec.rb +94 -0
  89. data/spec/toy/identity/abstract_key_factory_spec.rb +7 -0
  90. data/spec/toy/identity/uuid_key_factory_spec.rb +7 -0
  91. data/spec/toy/identity_map_spec.rb +150 -0
  92. data/spec/toy/identity_spec.rb +52 -0
  93. data/spec/toy/index_spec.rb +230 -0
  94. data/spec/toy/indices_spec.rb +141 -0
  95. data/spec/toy/inspect_spec.rb +15 -0
  96. data/spec/toy/list_spec.rb +576 -0
  97. data/spec/toy/lists_spec.rb +95 -0
  98. data/spec/toy/logger_spec.rb +33 -0
  99. data/spec/toy/mass_assignment_security_spec.rb +116 -0
  100. data/spec/toy/persistence_spec.rb +312 -0
  101. data/spec/toy/plugins_spec.rb +39 -0
  102. data/spec/toy/querying_spec.rb +162 -0
  103. data/spec/toy/reference_spec.rb +400 -0
  104. data/spec/toy/references_spec.rb +86 -0
  105. data/spec/toy/serialization_spec.rb +354 -0
  106. data/spec/toy/store_spec.rb +41 -0
  107. data/spec/toy/timestamps_spec.rb +63 -0
  108. data/spec/toy/validations_spec.rb +171 -0
  109. data/spec/toy_spec.rb +26 -0
  110. data/specs.watchr +52 -0
  111. data/test/lint_test.rb +40 -0
  112. data/toystore.gemspec +24 -0
  113. metadata +290 -0
@@ -0,0 +1,3 @@
1
+ module Toy
2
+ VERSION = "0.5"
3
+ end
@@ -0,0 +1 @@
1
+ require 'toy'
@@ -0,0 +1,35 @@
1
+ $:.unshift(File.expand_path('../../lib', __FILE__))
2
+
3
+ require 'pathname'
4
+ require 'logger'
5
+
6
+ root_path = Pathname(__FILE__).dirname.join('..').expand_path
7
+ lib_path = root_path.join('lib')
8
+ log_path = root_path.join('log')
9
+ log_path.mkpath
10
+
11
+ require 'rubygems'
12
+ require 'bundler'
13
+
14
+ Bundler.require(:default, :development)
15
+
16
+ require 'toy'
17
+ require 'adapter/memory'
18
+ require 'support/constants'
19
+ require 'support/identity_map_matcher'
20
+ require 'support/name_and_number_key_factory'
21
+
22
+ Logger.new(log_path.join('test.log')).tap do |log|
23
+ LogBuddy.init(:logger => log)
24
+ Toy.logger = log
25
+ end
26
+
27
+ Rspec.configure do |c|
28
+ c.include(Support::Constants)
29
+ c.include(IdentityMapMatcher)
30
+
31
+ c.before(:each) do
32
+ Toy.clear
33
+ Toy.reset
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --timeout
3
+ 20
@@ -0,0 +1,41 @@
1
+ module Support
2
+ module Constants
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def uses_constants(*constants)
9
+ before { create_constants(*constants) }
10
+ end
11
+ end
12
+
13
+ def create_constants(*constants)
14
+ constants.each { |constant| create_constant(constant) }
15
+ end
16
+
17
+ def remove_constants(*constants)
18
+ constants.each { |constant| remove_constant(constant) }
19
+ end
20
+
21
+ def create_constant(constant)
22
+ remove_constant(constant)
23
+ Kernel.const_set(constant, Model(constant))
24
+ end
25
+
26
+ def remove_constant(constant)
27
+ Kernel.send(:remove_const, constant) if Kernel.const_defined?(constant)
28
+ end
29
+
30
+ def Model(name=nil)
31
+ Class.new.tap do |model|
32
+ model.class_eval """
33
+ def self.name; '#{name}' end
34
+ def self.to_s; '#{name}' end
35
+ """ if name
36
+ model.send(:include, Toy::Store)
37
+ model.store(:memory, {})
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ module IdentityMapMatcher
2
+ class BeInIdentityMap
3
+ def matches?(obj)
4
+ @obj = obj
5
+ @obj.identity_map[@obj.store_key] == @obj
6
+ end
7
+
8
+ def failure_message
9
+ "expected #{@obj} to be in identity map, but it was not"
10
+ end
11
+
12
+ def negative_failure_message
13
+ "expected #{@obj} to not be in identity map, but it was"
14
+ end
15
+ end
16
+
17
+ def be_in_identity_map
18
+ BeInIdentityMap.new
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ class NameAndNumberKeyFactory < Toy::Identity::AbstractKeyFactory
2
+ def next_key(object)
3
+ "#{object.name}-#{object.number}" unless object.name.nil? || object.number.nil?
4
+ end
5
+ end
@@ -0,0 +1,176 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Attribute do
4
+ uses_constants('User')
5
+
6
+ before do
7
+ @attribute = Toy::Attribute.new(User, :age, String)
8
+ end
9
+
10
+ let(:attribute) { @attribute }
11
+
12
+ it "has model" do
13
+ attribute.model.should == User
14
+ end
15
+
16
+ it "has name" do
17
+ attribute.name.should == :age
18
+ end
19
+
20
+ it "has type" do
21
+ attribute.type.should == String
22
+ end
23
+
24
+ it "can convert from_store using the attribute type" do
25
+ attribute.from_store(12).should == '12'
26
+ end
27
+
28
+ it "can convert to_store using the attribute type" do
29
+ attribute.to_store(12).should == '12'
30
+ end
31
+
32
+ it "raises error if option is passed that we do not know about" do
33
+ lambda {
34
+ Toy::Attribute.new(User, :age, String, :taco => 'bell')
35
+ }.should raise_error(ArgumentError)
36
+ end
37
+
38
+ describe "#virtual?" do
39
+ it "defaults to false" do
40
+ Toy::Attribute.new(User, :score, Integer).should_not be_virtual
41
+ end
42
+
43
+ it "returns true if :virtual => true" do
44
+ Toy::Attribute.new(User, :score, Integer, :virtual => true).should be_virtual
45
+ end
46
+
47
+ it "returns false if :virtual => false" do
48
+ Toy::Attribute.new(User, :score, Integer, :virtual => false).should_not be_virtual
49
+ end
50
+ end
51
+
52
+ describe "#persisted?" do
53
+ it "defaults to true" do
54
+ Toy::Attribute.new(User, :score, Integer).should be_persisted
55
+ end
56
+
57
+ it "returns false if :virtual => true" do
58
+ Toy::Attribute.new(User, :score, Integer, :virtual => true).should_not be_persisted
59
+ end
60
+
61
+ it "returns true if :virtual => false" do
62
+ Toy::Attribute.new(User, :score, Integer, :virtual => false).should be_persisted
63
+ end
64
+ end
65
+
66
+ describe "#default" do
67
+ it "defaults to nil" do
68
+ Toy::Attribute.new(User, :age, String).default.should be_nil
69
+ end
70
+
71
+ it "returns default if set" do
72
+ Toy::Attribute.new(User, :age, String, :default => 1).default.should == 1
73
+ end
74
+
75
+ it "returns store_default if set for type" do
76
+ Toy::Attribute.new(User, :skills, Array).default.should == []
77
+ end
78
+
79
+ it "returns default if set even if store_default is set" do
80
+ Toy::Attribute.new(User, :skills, Array, :default => [1]).default.should == [1]
81
+ end
82
+ end
83
+
84
+ describe "#default?" do
85
+ it "returns false if no default or store_default" do
86
+ Toy::Attribute.new(User, :age, String).default?.should be_false
87
+ end
88
+
89
+ it "returns true if default set" do
90
+ Toy::Attribute.new(User, :age, String, :default => 1).default?.should be_true
91
+ end
92
+
93
+ it "returns true if store_default set" do
94
+ Toy::Attribute.new(User, :skills, Array).default?.should be_true
95
+ end
96
+ end
97
+
98
+ describe "#store_key" do
99
+ it "returns abbr if abbreviated" do
100
+ Toy::Attribute.new(User, :age, String, :abbr => :a).store_key.should == 'a'
101
+ end
102
+
103
+ it "returns name if not abbreviated" do
104
+ Toy::Attribute.new(User, :age, String).store_key.should == 'age'
105
+ end
106
+ end
107
+
108
+ describe "attribute with default" do
109
+ before do
110
+ @attribute = Toy::Attribute.new(User, :brother_name, String, :default => 'Daryl')
111
+ end
112
+
113
+ it "returns default when reading a nil value" do
114
+ @attribute.from_store(nil).should == 'Daryl'
115
+ end
116
+
117
+ it "returns value when reading a non-nil value" do
118
+ @attribute.from_store('Larry').should == 'Larry'
119
+ end
120
+
121
+ it "returns default when writing a nil value" do
122
+ @attribute.to_store(nil).should == 'Daryl'
123
+ end
124
+
125
+ it "returns value when writing a non-nil value" do
126
+ @attribute.to_store('Larry').should == 'Larry'
127
+ end
128
+ end
129
+
130
+ describe "attribute with default that is proc" do
131
+ before do
132
+ default = proc { 'foo' }
133
+ @attribute = Toy::Attribute.new(User, :foo, String, :default => default)
134
+ end
135
+
136
+ it "returns default when reading a nil value" do
137
+ @attribute.from_store(nil).should == 'foo'
138
+ end
139
+
140
+ it "returns value when reading a non-nil value" do
141
+ @attribute.from_store('bar').should == 'bar'
142
+ end
143
+
144
+ it "returns default when writing a nil value" do
145
+ @attribute.to_store(nil).should == 'foo'
146
+ end
147
+
148
+ it "returns value when writing a non-nil value" do
149
+ @attribute.to_store('bar').should == 'bar'
150
+ end
151
+ end
152
+
153
+ describe "#abbr" do
154
+ it "returns abbr if present" do
155
+ Toy::Attribute.new(User, :twitter_access_token, String, :abbr => :tat).abbr.should == :tat
156
+ end
157
+
158
+ it "returns abbr as symbol if present as string" do
159
+ Toy::Attribute.new(User, :twitter_access_token, String, :abbr => 'tat').abbr.should == :tat
160
+ end
161
+
162
+ it "returns nil if not present" do
163
+ Toy::Attribute.new(User, :twitter_access_token, String).abbr.should be_nil
164
+ end
165
+ end
166
+
167
+ describe "#abbr?" do
168
+ it "returns true if abbreviation present" do
169
+ Toy::Attribute.new(User, :twitter_access_token, String, :abbr => :tat).abbr?.should be_true
170
+ end
171
+
172
+ it "returns false if abbreviation missing" do
173
+ Toy::Attribute.new(User, :twitter_access_token, String).abbr?.should be_false
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,394 @@
1
+ require 'helper'
2
+
3
+ describe Toy::Attributes do
4
+ uses_constants('User', 'Game', 'Move', 'Tile')
5
+
6
+ before do
7
+ Game.embedded_list(:moves)
8
+ Move.embedded_list(:tiles)
9
+ end
10
+
11
+ describe "including" do
12
+ it "adds id attribute" do
13
+ User.attributes.keys.should == ['id']
14
+ end
15
+ end
16
+
17
+ describe ".attributes" do
18
+ it "defaults to hash with id" do
19
+ User.attributes.keys.should == ['id']
20
+ end
21
+ end
22
+
23
+ describe "#persisted_attributes" do
24
+ before do
25
+ Game.embedded_list(:moves)
26
+ @over = Game.attribute(:over, Boolean)
27
+ @score = Game.attribute(:creator_score, Integer, :virtual => true)
28
+ @abbr = Game.attribute(:super_secret_hash, String, :abbr => :ssh)
29
+ @rewards = Game.attribute(:rewards, Set)
30
+ @game = Game.new({
31
+ :over => true,
32
+ :creator_score => 20,
33
+ :rewards => %w(twigs berries).to_set,
34
+ :ssh => 'h4x',
35
+ :moves => [Move.new, Move.new],
36
+ })
37
+ end
38
+
39
+ it "includes persisted attributes" do
40
+ @game.persisted_attributes.should have_key('over')
41
+ end
42
+
43
+ it "includes abbreviated names for abbreviated attributes" do
44
+ @game.persisted_attributes.should have_key('ssh')
45
+ end
46
+
47
+ it "does not include full names for abbreviated attributes" do
48
+ @game.persisted_attributes.should_not have_key('super_secret_hash')
49
+ end
50
+
51
+ it "includes embedded" do
52
+ @game.persisted_attributes.should have_key('moves')
53
+ end
54
+
55
+ it "does not include virtual attributes" do
56
+ @game.persisted_attributes.should_not have_key(:creator_score)
57
+ end
58
+
59
+ it "includes to_store values for attributes" do
60
+ @game.persisted_attributes['rewards'].should be_instance_of(Array)
61
+ @game.persisted_attributes['rewards'].should == @rewards.to_store(@game.rewards)
62
+ end
63
+ end
64
+
65
+ describe ".defaulted_attributes" do
66
+ before do
67
+ @name = User.attribute(:name, String)
68
+ @age = User.attribute(:age, Integer, :default => 10)
69
+ end
70
+
71
+ it "includes attributes with a default" do
72
+ User.defaulted_attributes.should include(@age)
73
+ end
74
+
75
+ it "excludes attributes without a default" do
76
+ User.defaulted_attributes.should_not include(@name)
77
+ end
78
+ end
79
+
80
+ describe ".attribute?" do
81
+ before do
82
+ User.attribute :age, Integer
83
+ end
84
+
85
+ it "returns true if attribute (symbol)" do
86
+ User.attribute?(:age).should be_true
87
+ end
88
+
89
+ it "returns true if attribute (string)" do
90
+ User.attribute?('age').should be_true
91
+ end
92
+
93
+ it "returns false if not attribute" do
94
+ User.attribute?(:foobar).should be_false
95
+ end
96
+ end
97
+
98
+ describe "#initialize" do
99
+ before do
100
+ User.attribute :name, String
101
+ User.attribute :age, Integer
102
+ end
103
+
104
+ it "writes id" do
105
+ id = User.new.id
106
+ id.should_not be_nil
107
+ id.size.should == 36
108
+ end
109
+
110
+ it "does not attempt to set id if already set" do
111
+ user = User.new(:id => 'frank')
112
+ user.id.should == 'frank'
113
+ end
114
+
115
+ it "sets attributes" do
116
+ instance = User.new(:name => 'John', :age => 28)
117
+ instance.name.should == 'John'
118
+ instance.age.should == 28
119
+ end
120
+
121
+ it "sets defaults" do
122
+ User.attribute(:awesome, Boolean, :default => true)
123
+ User.new.awesome.should be_true
124
+ end
125
+
126
+ it "does not fail with nil" do
127
+ User.new(nil).should be_instance_of(User)
128
+ end
129
+ end
130
+
131
+ describe "#initialize_from_database" do
132
+ before do
133
+ User.attribute(:age, Integer, :default => 20)
134
+ @user = User.allocate
135
+ end
136
+
137
+ it "sets new record to false" do
138
+ @user.initialize_from_database
139
+ @user.should_not be_new_record
140
+ end
141
+
142
+ it "sets attributes" do
143
+ @user.initialize_from_database('age' => 21)
144
+ end
145
+
146
+ it "sets defaults" do
147
+ @user.initialize_from_database
148
+ @user.age.should == 20
149
+ end
150
+
151
+ it "does not fail with nil" do
152
+ @user.initialize_from_database(nil).should == @user
153
+ end
154
+
155
+ it "returns self" do
156
+ @user.initialize_from_database.should == @user
157
+ end
158
+ end
159
+
160
+ describe "#attributes" do
161
+ it "defaults to hash with id" do
162
+ attrs = Model().new.attributes
163
+ attrs.keys.should == ['id']
164
+ end
165
+
166
+ it "includes all attributes that are not nil" do
167
+ User.attribute(:name, String)
168
+ User.attribute(:active, Boolean, :default => true)
169
+ user = User.new
170
+ user.attributes.should == {
171
+ 'id' => user.id,
172
+ 'active' => true,
173
+ }
174
+ end
175
+
176
+ it "does not include embedded documents" do
177
+ game = Game.new(:moves => [Move.new(:tiles => [Tile.new])])
178
+ game.attributes.should_not have_key('moves')
179
+ end
180
+ end
181
+
182
+ describe "#attributes=" do
183
+ it "sets attributes if present" do
184
+ User.attribute :age, Integer
185
+ record = User.new
186
+ record.attributes = {:age => 20}
187
+ record.age.should == 20
188
+ end
189
+
190
+ it "does nothing if nil" do
191
+ record = User.new
192
+ lambda { record.attributes = nil }.should_not raise_error
193
+ end
194
+
195
+ it "works with accessors that are not keys" do
196
+ User.class_eval { attr_accessor :foo }
197
+ record = User.new(:foo => 'oof')
198
+ record.foo.should == 'oof'
199
+ end
200
+
201
+ it "ignores keys that are not attributes and do not have accessors defined" do
202
+ lambda { User.new(:taco => 'bell') }.should_not raise_error
203
+ end
204
+ end
205
+
206
+ describe "reading an attribute" do
207
+ before do
208
+ User.attribute(:info, Hash)
209
+ @user = User.new(:info => {'name' => 'John'})
210
+ end
211
+
212
+ it "returns the same instance" do
213
+ @user.info.should equal(@user.info)
214
+ end
215
+ end
216
+
217
+ describe "declaring an attribute" do
218
+ before do
219
+ User.attribute :name, String
220
+ User.attribute :age, Integer
221
+ end
222
+
223
+ it "adds attribute to attributes" do
224
+ User.attributes['name'].should == Toy::Attribute.new(User, :name, String)
225
+ User.attributes[:name].should be_nil
226
+ User.attributes['age'].should == Toy::Attribute.new(User, :age, Integer)
227
+ User.attributes[:age].should be_nil
228
+ end
229
+
230
+ it "adds accessors" do
231
+ record = User.new
232
+ record.name = 'John'
233
+ record.name.should == 'John'
234
+ end
235
+
236
+ it "converts to attribute type" do
237
+ record = User.new
238
+ record.age = '12'
239
+ record.age.should == 12
240
+ end
241
+
242
+ it "adds query-ers" do
243
+ record = User.new
244
+ record.name?.should be_false
245
+ record.name = 'John'
246
+ record.name?.should be_true
247
+ end
248
+
249
+ it "knows if it responds to attribute method" do
250
+ record = User.new
251
+ record.should respond_to(:name)
252
+ record.should respond_to(:name=)
253
+ record.should respond_to(:name?)
254
+ end
255
+
256
+ it "know if it does not respond to method" do
257
+ record = User.new
258
+ record.should_not respond_to(:foobar)
259
+ end
260
+
261
+ it "aliases [] to read_attribute" do
262
+ record = User.new(:name => 'John')
263
+ record[:name].should == 'John'
264
+ end
265
+
266
+ it "aliases []= to write_attribute" do
267
+ record = User.new
268
+ record[:name] = 'John'
269
+ record.name.should == 'John'
270
+ end
271
+ end
272
+
273
+ describe "declaring an attribute with a default" do
274
+ before do
275
+ User.attribute :active, Boolean, :default => true
276
+ end
277
+
278
+ it "adds attribute to attributes" do
279
+ attribute = Toy::Attribute.new(User, :active, Boolean, {:default => true})
280
+ User.attributes['active'].should == attribute
281
+ end
282
+
283
+ it "defaults value when initialized" do
284
+ User.new.active.should be(true)
285
+ end
286
+
287
+ it "overrides default if present" do
288
+ User.new(:active => false).active.should be(false)
289
+ end
290
+ end
291
+
292
+ describe "declaring an attribute with an abbreviation" do
293
+ before do
294
+ User.attribute(:twitter_access_token, String, :abbr => 'tat')
295
+ end
296
+
297
+ it "aliases reading to abbreviation" do
298
+ user = User.new
299
+ user.twitter_access_token = '1234'
300
+ user.tat.should == '1234'
301
+ end
302
+
303
+ it "aliases writing to abbreviation" do
304
+ user = User.new
305
+ user.tat = '1234'
306
+ user.twitter_access_token.should == '1234'
307
+ end
308
+
309
+ it "persists to store using abbreviation" do
310
+ user = User.create(:twitter_access_token => '1234')
311
+ raw = user.store.read(user.store_key)
312
+ raw['tat'].should == '1234'
313
+ raw.should_not have_key('twitter_access_token')
314
+ end
315
+
316
+ it "loads from store correctly" do
317
+ user = User.create(:twitter_access_token => '1234')
318
+ user = User.get(user.id)
319
+ user.twitter_access_token.should == '1234'
320
+ user.tat.should == '1234'
321
+ end
322
+ end
323
+
324
+ describe "#reload" do
325
+ before do
326
+ User.attribute(:name, String)
327
+ @user = User.create(:name => 'John')
328
+ end
329
+ let(:user) { @user }
330
+
331
+ it "reloads record from the database" do
332
+ user.name = 'Steve'
333
+ user.reload
334
+ user.name.should == 'John'
335
+ end
336
+
337
+ it "is still persisted" do
338
+ user.should be_persisted
339
+ user.reload
340
+ user.should be_persisted
341
+ end
342
+
343
+ it "returns the record" do
344
+ user.name = 'Steve'
345
+ user.reload.should equal(user)
346
+ end
347
+
348
+ it "resets instance variables" do
349
+ user.instance_variable_set("@foo", true)
350
+ user.reload
351
+ user.instance_variable_get("@foo").should be_nil
352
+ end
353
+
354
+ it "resets lists" do
355
+ User.list(:games)
356
+ game = Game.create
357
+ user.update_attributes(:games => [game])
358
+ user.games = []
359
+ user.games.should == []
360
+ user.reload
361
+ user.games.should == [game]
362
+ end
363
+
364
+ it "resets references" do
365
+ Game.reference(:user)
366
+ game = Game.create(:user => user)
367
+ game.user = nil
368
+ game.user.should be_nil
369
+ game.reload
370
+ game.user.should == user
371
+ end
372
+
373
+ it "raises NotFound if does not exist" do
374
+ user.destroy
375
+ lambda { user.reload }.should raise_error(Toy::NotFound)
376
+ end
377
+
378
+ it "reloads defaults" do
379
+ User.attribute(:skills, Array)
380
+ @user.reload
381
+ @user.skills.should == []
382
+ end
383
+ end
384
+
385
+ describe "Initialization of array attributes" do
386
+ before do
387
+ User.attribute(:skills, Array)
388
+ end
389
+
390
+ it "initializes to empty array" do
391
+ User.new.skills.should == []
392
+ end
393
+ end
394
+ end