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