toystore 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +11 -0
- data/.bundle/config +2 -0
- data/.gitignore +6 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +49 -0
- data/LICENSE +9 -0
- data/LOGGING.rdoc +16 -0
- data/README.rdoc +13 -0
- data/Rakefile +7 -0
- data/examples/memcached.rb +20 -0
- data/examples/memory.rb +20 -0
- data/examples/models.rb +51 -0
- data/examples/redis.rb +20 -0
- data/lib/toy.rb +81 -0
- data/lib/toy/attribute.rb +73 -0
- data/lib/toy/attributes.rb +137 -0
- data/lib/toy/caching.rb +20 -0
- data/lib/toy/callbacks.rb +48 -0
- data/lib/toy/collection.rb +55 -0
- data/lib/toy/connection.rb +28 -0
- data/lib/toy/dirty.rb +47 -0
- data/lib/toy/dolly.rb +30 -0
- data/lib/toy/embedded_list.rb +45 -0
- data/lib/toy/embedded_lists.rb +68 -0
- data/lib/toy/equality.rb +19 -0
- data/lib/toy/exceptions.rb +29 -0
- data/lib/toy/extensions/array.rb +22 -0
- data/lib/toy/extensions/boolean.rb +43 -0
- data/lib/toy/extensions/date.rb +24 -0
- data/lib/toy/extensions/float.rb +13 -0
- data/lib/toy/extensions/hash.rb +17 -0
- data/lib/toy/extensions/integer.rb +22 -0
- data/lib/toy/extensions/nil_class.rb +17 -0
- data/lib/toy/extensions/object.rb +26 -0
- data/lib/toy/extensions/set.rb +23 -0
- data/lib/toy/extensions/string.rb +17 -0
- data/lib/toy/extensions/time.rb +29 -0
- data/lib/toy/identity.rb +26 -0
- data/lib/toy/identity/abstract_key_factory.rb +10 -0
- data/lib/toy/identity/uuid_key_factory.rb +9 -0
- data/lib/toy/identity_map.rb +109 -0
- data/lib/toy/index.rb +74 -0
- data/lib/toy/indices.rb +56 -0
- data/lib/toy/inspect.rb +12 -0
- data/lib/toy/list.rb +46 -0
- data/lib/toy/lists.rb +37 -0
- data/lib/toy/logger.rb +26 -0
- data/lib/toy/mass_assignment_security.rb +16 -0
- data/lib/toy/persistence.rb +138 -0
- data/lib/toy/plugins.rb +23 -0
- data/lib/toy/proxies/embedded_list.rb +74 -0
- data/lib/toy/proxies/list.rb +97 -0
- data/lib/toy/proxies/proxy.rb +59 -0
- data/lib/toy/querying.rb +57 -0
- data/lib/toy/reference.rb +134 -0
- data/lib/toy/references.rb +19 -0
- data/lib/toy/serialization.rb +81 -0
- data/lib/toy/store.rb +36 -0
- data/lib/toy/timestamps.rb +22 -0
- data/lib/toy/validations.rb +45 -0
- data/lib/toy/version.rb +3 -0
- data/lib/toystore.rb +1 -0
- data/spec/helper.rb +35 -0
- data/spec/spec.opts +3 -0
- data/spec/support/constants.rb +41 -0
- data/spec/support/identity_map_matcher.rb +20 -0
- data/spec/support/name_and_number_key_factory.rb +5 -0
- data/spec/toy/attribute_spec.rb +176 -0
- data/spec/toy/attributes_spec.rb +394 -0
- data/spec/toy/caching_spec.rb +62 -0
- data/spec/toy/callbacks_spec.rb +97 -0
- data/spec/toy/connection_spec.rb +47 -0
- data/spec/toy/dirty_spec.rb +99 -0
- data/spec/toy/dolly_spec.rb +76 -0
- data/spec/toy/embedded_list_spec.rb +607 -0
- data/spec/toy/embedded_lists_spec.rb +172 -0
- data/spec/toy/equality_spec.rb +46 -0
- data/spec/toy/exceptions_spec.rb +18 -0
- data/spec/toy/extensions/array_spec.rb +25 -0
- data/spec/toy/extensions/boolean_spec.rb +41 -0
- data/spec/toy/extensions/date_spec.rb +48 -0
- data/spec/toy/extensions/float_spec.rb +14 -0
- data/spec/toy/extensions/hash_spec.rb +21 -0
- data/spec/toy/extensions/integer_spec.rb +29 -0
- data/spec/toy/extensions/nil_class_spec.rb +14 -0
- data/spec/toy/extensions/set_spec.rb +27 -0
- data/spec/toy/extensions/string_spec.rb +28 -0
- data/spec/toy/extensions/time_spec.rb +94 -0
- data/spec/toy/identity/abstract_key_factory_spec.rb +7 -0
- data/spec/toy/identity/uuid_key_factory_spec.rb +7 -0
- data/spec/toy/identity_map_spec.rb +150 -0
- data/spec/toy/identity_spec.rb +52 -0
- data/spec/toy/index_spec.rb +230 -0
- data/spec/toy/indices_spec.rb +141 -0
- data/spec/toy/inspect_spec.rb +15 -0
- data/spec/toy/list_spec.rb +576 -0
- data/spec/toy/lists_spec.rb +95 -0
- data/spec/toy/logger_spec.rb +33 -0
- data/spec/toy/mass_assignment_security_spec.rb +116 -0
- data/spec/toy/persistence_spec.rb +312 -0
- data/spec/toy/plugins_spec.rb +39 -0
- data/spec/toy/querying_spec.rb +162 -0
- data/spec/toy/reference_spec.rb +400 -0
- data/spec/toy/references_spec.rb +86 -0
- data/spec/toy/serialization_spec.rb +354 -0
- data/spec/toy/store_spec.rb +41 -0
- data/spec/toy/timestamps_spec.rb +63 -0
- data/spec/toy/validations_spec.rb +171 -0
- data/spec/toy_spec.rb +26 -0
- data/specs.watchr +52 -0
- data/test/lint_test.rb +40 -0
- data/toystore.gemspec +24 -0
- metadata +290 -0
data/lib/toy/version.rb
ADDED
data/lib/toystore.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'toy'
|
data/spec/helper.rb
ADDED
@@ -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
|
data/spec/spec.opts
ADDED
@@ -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,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
|