ricordami 0.0.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.
- data/CHANGELOG.md +13 -0
- data/ISSUES.md +0 -0
- data/MIT-LICENSE +21 -0
- data/README.md +454 -0
- data/TODO.md +21 -0
- data/examples/calls.rb +64 -0
- data/examples/singers.rb +42 -0
- data/lib/ricordami/attribute.rb +52 -0
- data/lib/ricordami/can_be_queried.rb +133 -0
- data/lib/ricordami/can_be_validated.rb +27 -0
- data/lib/ricordami/can_have_relationships.rb +152 -0
- data/lib/ricordami/configuration.rb +39 -0
- data/lib/ricordami/connection.rb +22 -0
- data/lib/ricordami/exceptions.rb +14 -0
- data/lib/ricordami/has_attributes.rb +159 -0
- data/lib/ricordami/has_indices.rb +105 -0
- data/lib/ricordami/is_lockable.rb +52 -0
- data/lib/ricordami/is_persisted.rb +123 -0
- data/lib/ricordami/is_retrievable.rb +35 -0
- data/lib/ricordami/key_namer.rb +63 -0
- data/lib/ricordami/model.rb +29 -0
- data/lib/ricordami/query.rb +68 -0
- data/lib/ricordami/relationship.rb +40 -0
- data/lib/ricordami/unique_index.rb +59 -0
- data/lib/ricordami/unique_validator.rb +21 -0
- data/lib/ricordami/value_index.rb +26 -0
- data/lib/ricordami/version.rb +3 -0
- data/lib/ricordami.rb +26 -0
- data/spec/acceptance/manage_relationships_spec.rb +42 -0
- data/spec/acceptance/model_with_validation_spec.rb +78 -0
- data/spec/acceptance/query_model_spec.rb +93 -0
- data/spec/acceptance_helper.rb +2 -0
- data/spec/ricordami/attribute_spec.rb +113 -0
- data/spec/ricordami/can_be_queried_spec.rb +254 -0
- data/spec/ricordami/can_be_validated_spec.rb +115 -0
- data/spec/ricordami/can_have_relationships_spec.rb +255 -0
- data/spec/ricordami/configuration_spec.rb +45 -0
- data/spec/ricordami/connection_spec.rb +25 -0
- data/spec/ricordami/exceptions_spec.rb +43 -0
- data/spec/ricordami/has_attributes_spec.rb +266 -0
- data/spec/ricordami/has_indices_spec.rb +73 -0
- data/spec/ricordami/is_lockable_spec.rb +45 -0
- data/spec/ricordami/is_persisted_spec.rb +186 -0
- data/spec/ricordami/is_retrievable_spec.rb +55 -0
- data/spec/ricordami/key_namer_spec.rb +56 -0
- data/spec/ricordami/model_spec.rb +65 -0
- data/spec/ricordami/query_spec.rb +156 -0
- data/spec/ricordami/relationship_spec.rb +123 -0
- data/spec/ricordami/unique_index_spec.rb +87 -0
- data/spec/ricordami/unique_validator_spec.rb +41 -0
- data/spec/ricordami/value_index_spec.rb +40 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/constants.rb +43 -0
- data/spec/support/db_manager.rb +18 -0
- data/test/bin/data_loader.rb +107 -0
- data/test/data/domains.txt +462 -0
- data/test/data/first_names.txt +1220 -0
- data/test/data/last_names.txt +1028 -0
- data/test/data/people_100_000.csv.bz2 +0 -0
- data/test/data/people_10_000.csv.bz2 +0 -0
- data/test/data/people_1_000_000.csv.bz2 +0 -0
- metadata +258 -0
@@ -0,0 +1,255 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require "spec_helper"
|
3
|
+
require "ricordami/can_have_relationships"
|
4
|
+
|
5
|
+
describe Ricordami::CanHaveRelationships do
|
6
|
+
uses_constants("Computer", "Software", "Editor")
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Computer.send(:include, Ricordami::CanHaveRelationships)
|
10
|
+
Computer.attribute :model
|
11
|
+
Computer.index :unique => :model, :get_by => true
|
12
|
+
Computer.references_many :softwares
|
13
|
+
Software.send(:include, Ricordami::CanHaveRelationships)
|
14
|
+
Software.attribute :name
|
15
|
+
Software.index :unique => :name, :get_by => true
|
16
|
+
Software.referenced_in :computer
|
17
|
+
Software.referenced_in :editor
|
18
|
+
Editor.send(:include, Ricordami::CanHaveRelationships)
|
19
|
+
Editor.attribute :corp_name
|
20
|
+
Editor.index :unique => :corp_name, :get_by => true
|
21
|
+
Editor.references_one :software
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "class" do
|
25
|
+
it "can declare a :referenced_in relationship with #referenced_in" do
|
26
|
+
Software.referenced_in :computer
|
27
|
+
Software.relationships[:computer].should be_a(Ricordami::Relationship)
|
28
|
+
Software.relationships[:computer].type.should == :referenced_in
|
29
|
+
Software.relationships[:computer].name.should == :computer
|
30
|
+
Software.relationships[:computer].object_kind.should == :computer
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can declare a :references_many relationship with #references_many" do
|
34
|
+
Computer.references_many :softwares, :dependent => :nullify, :as => :softs
|
35
|
+
Computer.relationships[:softs].should be_a(Ricordami::Relationship)
|
36
|
+
Computer.relationships[:softs].type.should == :references_many
|
37
|
+
Computer.relationships[:softs].name.should == :softs
|
38
|
+
Computer.relationships[:softs].object_kind.should == :software
|
39
|
+
Computer.relationships[:softs].dependent.should == :nullify
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can declare a :references_one relationship with #references_one" do
|
43
|
+
Editor.references_one :software, :dependent => :nullify
|
44
|
+
Editor.relationships[:software].should be_a(Ricordami::Relationship)
|
45
|
+
Editor.relationships[:software].type.should == :references_one
|
46
|
+
Editor.relationships[:software].name.should == :software
|
47
|
+
Editor.relationships[:software].object_kind.should == :software
|
48
|
+
Editor.relationships[:software].dependent.should == :nullify
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "instance that is referenced..." do
|
53
|
+
it "creates an attribute for the referrer id" do
|
54
|
+
game = Software.create(:name => "Masquerade")
|
55
|
+
game.computer_id.should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "indexes the referrer id" do
|
59
|
+
iic = Computer.create(:model => "IIc")
|
60
|
+
mac = Computer.create(:model => "Macintosh")
|
61
|
+
Software.create(:name => "Masquerade", :computer_id => iic.id)
|
62
|
+
Software.create(:name => "Transylvania", :computer_id => iic.id)
|
63
|
+
Software.create(:name => "Dungeon Master", :computer_id => mac.id)
|
64
|
+
Software.where(:computer_id => iic.id).map(&:name).should =~ ["Masquerade", "Transylvania"]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can access the referrer with a method of the name of the reference" do
|
68
|
+
game = Software.create(:name => "Masquerade")
|
69
|
+
game.computer.should be_nil
|
70
|
+
computer = Computer.create(:model => "IIc")
|
71
|
+
game.computer_id = computer.id
|
72
|
+
game.computer.should be_a(Computer)
|
73
|
+
game.computer.model.should == "IIc"
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "handling caching" do
|
77
|
+
before(:each) do
|
78
|
+
%w(IIc Macintosh).each { |model| Computer.create(:model => model).should be_true }
|
79
|
+
end
|
80
|
+
|
81
|
+
it "caches the referrer isntance after it was cached" do
|
82
|
+
computer = Computer.get_by_model("IIc")
|
83
|
+
game = Software.create(:name => "Masquerade", :computer_id => computer.id)
|
84
|
+
game.computer.should == game.computer
|
85
|
+
end
|
86
|
+
|
87
|
+
it "updates the referrer when changing the referrer id" do
|
88
|
+
game = Software.create(:name => "Sorcery")
|
89
|
+
game.computer.should be_nil
|
90
|
+
game.computer_id = Computer.get_by_model("IIc").id
|
91
|
+
game.computer.model.should == "IIc"
|
92
|
+
game.computer_id = Computer.get_by_model("Macintosh").id
|
93
|
+
game.computer.model.should == "Macintosh"
|
94
|
+
game.computer_id = nil
|
95
|
+
game.computer.should be_nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it "sweeps the referrer instance from the cache after it is reloaded" do
|
99
|
+
game = Software.create(:name => "Swashbuckler",
|
100
|
+
:computer_id => Computer.get_by_model("IIc").id)
|
101
|
+
game.computer.model.should == "IIc"
|
102
|
+
game.update_attributes(:computer_id => Computer.get_by_model("Macintosh").id)
|
103
|
+
game.computer.model.should == "Macintosh"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "instance that references many..." do
|
109
|
+
before(:each) do
|
110
|
+
@iic = Computer.create(:model => "IIc")
|
111
|
+
@mac = Computer.create(:model => "MacBook Air")
|
112
|
+
[
|
113
|
+
[@iic, "Masquerade"], [@iic, "Transylvania"], [@iic, "Bruce Lee"],
|
114
|
+
[@iic, "Karateka"], [@mac, "Half-Life"], [@mac, "Chopper 2"]
|
115
|
+
].each do |computer, soft_name|
|
116
|
+
Software.create(:name => soft_name, :computer_id => computer.id)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it "has a method to access its referenced objects" do
|
121
|
+
@iic.should respond_to(:softwares)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "can list all the objects it references with the reference method" do
|
125
|
+
@iic.softwares.map(&:name).should =~ ["Masquerade", "Transylvania",
|
126
|
+
"Bruce Lee", "Karateka"]
|
127
|
+
@mac.softwares.map(&:name).should =~ ["Half-Life", "Chopper 2"]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "can return there is no reference objects when non persisted" do
|
131
|
+
Computer.new.softwares.map(&:name).should == []
|
132
|
+
Computer.new.softwares.should be_empty
|
133
|
+
Computer.new.softwares.count.should == 0
|
134
|
+
end
|
135
|
+
|
136
|
+
it "can build a new reference object through the reference method" do
|
137
|
+
soft = @mac.softwares.build
|
138
|
+
soft.should_not be_persisted
|
139
|
+
soft.computer_id.should == @mac.id
|
140
|
+
end
|
141
|
+
|
142
|
+
it "can create a new reference object through the reference method" do
|
143
|
+
soft = @mac.softwares.create(:name => "Call of Duty 4")
|
144
|
+
soft.should be_persisted
|
145
|
+
soft.computer_id.should == @mac.id
|
146
|
+
soft.name.should == "Call of Duty 4"
|
147
|
+
end
|
148
|
+
|
149
|
+
it "can have more than 1 reference for the same type of object" do
|
150
|
+
Computer.references_many :softwares, :as => :softs, :alias => :host, :dependent => :delete
|
151
|
+
Software.referenced_in :computer, :as => :host, :alias => :softs
|
152
|
+
iie = Computer.create(:model => "IIe")
|
153
|
+
iie.softs.create(:name => "Masquerade")
|
154
|
+
iie.softwares.create(:name => "Conan")
|
155
|
+
iie.softs.map(&:name).should == ["Masquerade"]
|
156
|
+
iie.softwares.map(&:name).should == ["Conan"]
|
157
|
+
end
|
158
|
+
|
159
|
+
it "deletes dependents when delete is set to :dependent" do
|
160
|
+
Computer.references_many :softwares, :as => :softs, :dependent => :delete
|
161
|
+
iie = Computer.create(:model => "IIe")
|
162
|
+
iie.softs.create(:name => "Castle Wolfenstein")
|
163
|
+
Software.get_by_name("Castle Wolfenstein").should_not be_nil
|
164
|
+
iie.delete
|
165
|
+
lambda {
|
166
|
+
Software.get_by_name("Castle Wolfenstein")
|
167
|
+
}.should raise_error(Ricordami::NotFound)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "sets to nil reference's referrer_id when delete is set to :nullify" do
|
171
|
+
Computer.references_many :softwares, :as => :softs, :alias => :host, :dependent => :nullify
|
172
|
+
Software.referenced_in :computer, :as => :host, :alias => :softs
|
173
|
+
iie = Computer.create(:model => "IIe")
|
174
|
+
iie.reload
|
175
|
+
iie.softs.create(:name => "Castle Wolfenstein")
|
176
|
+
Software.get_by_name("Castle Wolfenstein").host_id.should == iie.id
|
177
|
+
iie.delete
|
178
|
+
Software.get_by_name("Castle Wolfenstein").host_id.should be_empty
|
179
|
+
end
|
180
|
+
|
181
|
+
it "can build a new referrer object through a build referrer method" do
|
182
|
+
software = Software.create(:name => "Karateka")
|
183
|
+
editor = software.build_editor(:corp_name => "Brøderbund")
|
184
|
+
editor.should_not be_persisted
|
185
|
+
editor.id.should == software.editor_id
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "instance that references one..." do
|
190
|
+
before(:each) do
|
191
|
+
@aes = Editor.create(:corp_name => "American Eagle Software")
|
192
|
+
Software.create(:name => "Masquerade", :editor_id => @aes.id)
|
193
|
+
@datasoft = Editor.create(:corp_name => "Datasoft")
|
194
|
+
Software.create(:name => "Bruce Lee", :editor_id => @datasoft.id)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "has a method to access its referenced object" do
|
198
|
+
@aes.should respond_to(:software)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "can fetch the object it references with the reference method" do
|
202
|
+
@aes.software.name.should == "Masquerade"
|
203
|
+
@datasoft.software.name.should == "Bruce Lee"
|
204
|
+
end
|
205
|
+
|
206
|
+
it "can return there is no reference objects when non persisted" do
|
207
|
+
Editor.new.software.should be_nil
|
208
|
+
end
|
209
|
+
|
210
|
+
it "can build a new reference object through a build reference method" do
|
211
|
+
soft = @aes.build_software
|
212
|
+
soft.should_not be_persisted
|
213
|
+
soft.editor_id.should == @aes.id
|
214
|
+
end
|
215
|
+
|
216
|
+
it "can create a new reference object through the reference method" do
|
217
|
+
soft = @datasoft.create_software(:name => "Alternate Reality: The City")
|
218
|
+
soft.should be_persisted
|
219
|
+
soft.editor_id.should == @datasoft.id
|
220
|
+
soft.name.should == "Alternate Reality: The City"
|
221
|
+
end
|
222
|
+
|
223
|
+
it "can have more than 1 reference for the same type of object" do
|
224
|
+
Editor.references_one :software, :as => :soft, :alias => :second_editor, :dependent => :delete
|
225
|
+
Software.referenced_in :editor, :as => :second_editor, :alias => :soft
|
226
|
+
broderbund = Editor.create(:corp_name => "Brøderbund")
|
227
|
+
broderbund.create_software(:name => "Karateka")
|
228
|
+
broderbund.create_soft(:name => "Lode Runner")
|
229
|
+
broderbund.software.name.should == "Karateka"
|
230
|
+
broderbund.soft.name.should == "Lode Runner"
|
231
|
+
end
|
232
|
+
|
233
|
+
it "deletes dependents when delete is set to :dependent" do
|
234
|
+
Editor.references_one :software, :as => :soft, :dependent => :delete
|
235
|
+
broderbund = Editor.create(:corp_name => "Brøderbund")
|
236
|
+
broderbund.create_soft(:name => "Karateka")
|
237
|
+
Software.get_by_name("Karateka").should_not be_nil
|
238
|
+
broderbund.delete
|
239
|
+
lambda {
|
240
|
+
Software.get_by_name("Karateka")
|
241
|
+
}.should raise_error(Ricordami::NotFound)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "sets to nil reference's referrer_id when delete is set to :nullify" do
|
245
|
+
Editor.references_one :software, :as => :soft, :alias => :developper, :dependent => :nullify
|
246
|
+
Software.referenced_in :editor, :as => :developper, :alias => :soft
|
247
|
+
broderbund = Editor.create(:corp_name => "Brøderbund")
|
248
|
+
broderbund.reload
|
249
|
+
broderbund.create_soft(:name => "Choplifter")
|
250
|
+
Software.get_by_name("Choplifter").developper_id.should == broderbund.id
|
251
|
+
broderbund.delete
|
252
|
+
Software.get_by_name("Choplifter").developper_id.should be_empty
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ricordami::Configuration, " using #configure" do
|
4
|
+
it "raises an error of no block is given" do
|
5
|
+
lambda { Ricordami.configure }.should raise_error(ArgumentError)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "raises an error when a config attribute doesn't exist" do
|
9
|
+
lambda {
|
10
|
+
Ricordami.configuration.does_not_exist
|
11
|
+
}.should raise_error(Ricordami::AttributeNotSupported)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can configure redis host with #redis_host" do
|
15
|
+
Ricordami.configure { |config| config.redis_host = "my_host" }
|
16
|
+
Ricordami.configuration.redis_host.should == "my_host"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can configure redis port with #redis_port" do
|
20
|
+
Ricordami.configure { |config| config.redis_port = 6379 }
|
21
|
+
Ricordami.configuration.redis_port.should == 6379
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can configure redis db (0, 1, 2, ..., 8) with #redis_db" do
|
25
|
+
Ricordami.configure { |config| config.redis_db = 1 }
|
26
|
+
Ricordami.configuration.redis_db.should == 1
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can configure redis to use as thread-safe with #thread_safe" do
|
30
|
+
Ricordami.configure { |config| config.thread_safe = true }
|
31
|
+
Ricordami.configuration.thread_safe.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can configure all attributes at once using #from_hash" do
|
35
|
+
Ricordami.configure do |config|
|
36
|
+
config.from_hash(:redis_host => "serge",
|
37
|
+
:redis_port => 6380,
|
38
|
+
:redis_db => 2)
|
39
|
+
end
|
40
|
+
Ricordami.configuration.redis_host.should == "serge"
|
41
|
+
Ricordami.configuration.redis_port.should == 6380
|
42
|
+
Ricordami.configuration.redis_db.should == 2
|
43
|
+
Ricordami.configuration.thread_safe.should be_false
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rspec/mocks"
|
3
|
+
|
4
|
+
describe Ricordami::Connection do
|
5
|
+
describe "the module" do
|
6
|
+
before(:all) do
|
7
|
+
module Mixer
|
8
|
+
extend self
|
9
|
+
include Ricordami::Connection
|
10
|
+
end
|
11
|
+
RSpec::Mocks::setup(self)
|
12
|
+
@config = mock(:config)
|
13
|
+
[:redis_host, :redis_port, :redis_db, :thread_safe].each do |name|
|
14
|
+
@config.stub!(name)
|
15
|
+
end
|
16
|
+
Mixer.stub!(:configuration).and_return(@config)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has a connection to Redis" do
|
20
|
+
Mixer.driver.should be_a(Redis)
|
21
|
+
Mixer.driver.get("not_exist")
|
22
|
+
Mixer.driver.client.connection.should be_connected
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ricordami::Error do
|
4
|
+
it "has an error to notify when data was not found on the server" do
|
5
|
+
Ricordami::NotFound.new.should be_a_kind_of(Ricordami::Error)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has an error to notify when an attribute is not supported" do
|
9
|
+
Ricordami::AttributeNotSupported.new.should be_a_kind_of(Ricordami::Error)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has an error to notify an attempty to change a read-only attribute" do
|
13
|
+
Ricordami::ReadOnlyAttribute.new.should be_a_kind_of(Ricordami::Error)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "has an error to notify when an index declaration is invalid" do
|
17
|
+
Ricordami::InvalidIndexDefinition.new.should be_a_kind_of(Ricordami::Error)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "has an error to notify when a model is deleted" do
|
21
|
+
Ricordami::ModelHasBeenDeleted.new.should be_a_kind_of(Ricordami::Error)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "has an error to notify when a type is not supported" do
|
25
|
+
Ricordami::TypeNotSupported.new.should be_a_kind_of(Ricordami::Error)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "has an error to notify when an index is missing" do
|
29
|
+
Ricordami::MissingIndex.new.should be_a_kind_of(Ricordami::Error)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "has an error to notify when an event is not supported" do
|
33
|
+
Ricordami::EventNotSupported.new.should be_a_kind_of(Ricordami::Error)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "has an error to notify when an option value is invalid" do
|
37
|
+
Ricordami::OptionValueInvalid.new.should be_a_kind_of(Ricordami::Error)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "has an error to notify when mandatory arguments are missing" do
|
41
|
+
Ricordami::MissingMandatoryArgs.new.should be_a_kind_of(Ricordami::Error)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ricordami::HasAttributes do
|
4
|
+
describe "the class" do
|
5
|
+
uses_constants("Boat")
|
6
|
+
|
7
|
+
it "can declare attributes using #attribute" do
|
8
|
+
Boat.attribute :sail
|
9
|
+
Boat.attributes[:sail].should be_a(Ricordami::Attribute)
|
10
|
+
Boat.attributes[:sail].name.should == :sail
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can pass attribute options when declaring an attribute" do
|
14
|
+
Boat.attribute :color, :default => "black", :read_only => true
|
15
|
+
Boat.attributes[:color].default_value.should == "black"
|
16
|
+
Boat.attributes[:color].should be_read_only
|
17
|
+
end
|
18
|
+
|
19
|
+
it "creates an index if :indexed is set" do
|
20
|
+
Boat.attribute :size, :indexed => :value
|
21
|
+
Boat.indices.should have_key(:size)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "creates a unique index if :indexed is :unique" do
|
25
|
+
Boat.attribute :size, :indexed => :unique
|
26
|
+
Boat.indices[:size].should be_a(Ricordami::UniqueIndex)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "creates a value index if :indexed is :value" do
|
30
|
+
Boat.attribute :size, :indexed => :value
|
31
|
+
Boat.indices[:size].should be_a(Ricordami::ValueIndex)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "replaces :initial value with a generator if it's a symbol" do
|
35
|
+
Boat.attribute :id, :initial => :sequence
|
36
|
+
attribute = Boat.attributes[:id]
|
37
|
+
attribute.initial_value.should == "1"
|
38
|
+
attribute.initial_value.should == "2"
|
39
|
+
attribute.initial_value.should == "3"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "an instance" do
|
44
|
+
uses_constants("User")
|
45
|
+
|
46
|
+
it "can be initialized with a hash of attribute values" do
|
47
|
+
User.attribute :name
|
48
|
+
User.attribute :age
|
49
|
+
User.attribute :ssn
|
50
|
+
user = User.new(:name => "jean", :age => "20", :ssn => "1234567890")
|
51
|
+
user.name.should == "jean"
|
52
|
+
user.age.should == "20"
|
53
|
+
user.ssn.should == "1234567890"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "can set attributes using writers" do
|
57
|
+
User.attribute :email
|
58
|
+
user = User.new
|
59
|
+
user.email.should be_nil
|
60
|
+
user.email = "blah@toto.com"
|
61
|
+
user.email.should == "blah@toto.com"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "sets default values when initializing without argument" do
|
65
|
+
User.attribute :age, :default => "18"
|
66
|
+
User.new.age.should == "18"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "overwrites default values with arguments when initializing" do
|
70
|
+
User.attribute :age, :default => "18"
|
71
|
+
User.new(:age => "12").age.should == "12"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "can't change a read-only attribute that was initialized" do
|
75
|
+
User.attribute :name
|
76
|
+
User.attribute :ssn, :read_only => true
|
77
|
+
user = User.new(:name => "James Bond", :ssn => "007")
|
78
|
+
lambda {
|
79
|
+
user.ssn = "1234567890"
|
80
|
+
}.should raise_error(Ricordami::ReadOnlyAttribute)
|
81
|
+
lambda {
|
82
|
+
user.name = "Titi"
|
83
|
+
}.should_not raise_error(Ricordami::ReadOnlyAttribute)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can set a read-only attribute only once if it was not initialized" do
|
87
|
+
User.attribute :name
|
88
|
+
User.attribute :ssn, :read_only => true
|
89
|
+
user = User.new
|
90
|
+
lambda {
|
91
|
+
user.ssn = "1234567890"
|
92
|
+
user.name = "Titi"
|
93
|
+
user.name = "Bob Loblaw"
|
94
|
+
}.should_not raise_error(Ricordami::ReadOnlyAttribute)
|
95
|
+
lambda {
|
96
|
+
user.ssn = "0987654321"
|
97
|
+
}.should raise_error(Ricordami::ReadOnlyAttribute)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "has an 'id' attribute set by default to a sequence if not overriden when saved" do
|
101
|
+
user = User.create
|
102
|
+
user.id.should be_present
|
103
|
+
user.id.should == "1"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "overides the value of its 'id' attribute when a value is passed" do
|
107
|
+
user = User.create(:id => "foo")
|
108
|
+
user.id.should == "foo"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "defines 'id' as a read_only attribute" do
|
112
|
+
user = User.create
|
113
|
+
lambda {
|
114
|
+
user.id = "try me"
|
115
|
+
}.should raise_error(Ricordami::ReadOnlyAttribute)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "returns the name of the attributes key with #attributes_key_name" do
|
119
|
+
user = User.new(:id => "ze_id")
|
120
|
+
user.instance_eval { attributes_key_name }.should == "User:att:ze_id"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "updates the attribute values in memory with #update_mem_attributes!" do
|
124
|
+
User.attribute :age
|
125
|
+
User.attribute :sex
|
126
|
+
user = User.new(:age => "12", :sex => "male")
|
127
|
+
user.update_mem_attributes!(:age => "18", :sex => "female")
|
128
|
+
user.age.should == "18"
|
129
|
+
user.sex.should == "female"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "can't change read-only attributes with #update_mem_attributes!" do
|
133
|
+
User.attribute :name
|
134
|
+
User.attribute :ssn, :read_only => true
|
135
|
+
user = User.new(:name => "James Bond", :ssn => "007")
|
136
|
+
lambda {
|
137
|
+
user.update_mem_attributes!(:ssn => "1234567890")
|
138
|
+
}.should raise_error(Ricordami::ReadOnlyAttribute)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "updates the attribute values in memory with #update_mem_attributes" do
|
142
|
+
User.attribute :age
|
143
|
+
user = User.new(:age => "12")
|
144
|
+
user.update_mem_attributes(:age => "18")
|
145
|
+
user.age.should == "18"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "changes read-only attributes with #update_mem_attributes" do
|
149
|
+
User.attribute :ssn, :read_only => true
|
150
|
+
user = User.new(:ssn => "007")
|
151
|
+
lambda {
|
152
|
+
user.update_mem_attributes(:ssn => "1234567890")
|
153
|
+
}.should_not raise_error
|
154
|
+
end
|
155
|
+
|
156
|
+
it "can't change the attributes of a model that was deleted" do
|
157
|
+
User.attribute :age
|
158
|
+
user = User.create(:age => "42")
|
159
|
+
user.delete
|
160
|
+
lambda { user.age = "12" }.should raise_error(Ricordami::ModelHasBeenDeleted)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "keeps track of dirty attributes" do
|
165
|
+
uses_constants("Plane")
|
166
|
+
before(:each) do
|
167
|
+
Plane.attribute :brand
|
168
|
+
Plane.attribute :model
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "a new record" do
|
172
|
+
before(:each) { @plane = Plane.new }
|
173
|
+
let(:plane) { @plane }
|
174
|
+
|
175
|
+
it "was not changed if it doesn't have attributes" do
|
176
|
+
plane.should_not be_changed
|
177
|
+
plane.changed.should be_empty
|
178
|
+
plane.changes.should be_empty
|
179
|
+
end
|
180
|
+
|
181
|
+
it "was changed when initialized with attributes" do
|
182
|
+
plane = Plane.new(:brand => "Airbus", :model => "320")
|
183
|
+
plane.should be_changed
|
184
|
+
plane.changed.should =~ ["brand", "model"]
|
185
|
+
plane.changes.should == {"brand" => [nil, "Airbus"], "model" => [nil, "320"]}
|
186
|
+
end
|
187
|
+
|
188
|
+
it "knows when an attribute value changes" do
|
189
|
+
plane.brand = "Boeing"
|
190
|
+
plane.should be_changed
|
191
|
+
plane.changed.should == ["brand"]
|
192
|
+
plane.changes["brand"].should == [nil, "Boeing"]
|
193
|
+
end
|
194
|
+
|
195
|
+
it "knows when an attribute value actually didn't change" do
|
196
|
+
plane.brand = nil
|
197
|
+
plane.should_not be_changed
|
198
|
+
end
|
199
|
+
|
200
|
+
it "was not changed after it was saved" do
|
201
|
+
plane.model = "380"
|
202
|
+
plane.save
|
203
|
+
plane.should_not be_changed
|
204
|
+
end
|
205
|
+
|
206
|
+
it "knows when it was changed before being saved" do
|
207
|
+
plane.model = "380"
|
208
|
+
plane.save
|
209
|
+
plane.previous_changes["model"].should == [nil, "380"]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "a persisted record" do
|
214
|
+
before(:each) { Plane.create(:id => "A320", :brand => "Airbus", :model => "320") }
|
215
|
+
let(:plane) { Plane["A320"] }
|
216
|
+
|
217
|
+
it "was not changed when it's just loaded from the DB" do
|
218
|
+
plane.should_not be_changed
|
219
|
+
end
|
220
|
+
|
221
|
+
it "was not changed after reloading it with #reload" do
|
222
|
+
plane.brand = "Toys'R US"
|
223
|
+
plane.reload
|
224
|
+
plane.should_not be_changed
|
225
|
+
end
|
226
|
+
|
227
|
+
it "knows when an attribute value actually didn't change" do
|
228
|
+
plane.brand = "Airbus"
|
229
|
+
plane.should_not be_changed
|
230
|
+
plane.brand = "Boeing"
|
231
|
+
plane.brand = "Airbus"
|
232
|
+
plane.should_not be_changed
|
233
|
+
end
|
234
|
+
|
235
|
+
it "knows which attributes changed when running #update_attributes" do
|
236
|
+
plane.brand = "Boeing"
|
237
|
+
plane.update_attributes(:brand => "Airbus", :model => "380")
|
238
|
+
plane.should_not be_changed
|
239
|
+
plane.previous_changes.should == {"model" => ["320", "380"]}
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "attribute value typing" do
|
244
|
+
uses_constants("Person")
|
245
|
+
before(:each) do
|
246
|
+
Person.attribute :name
|
247
|
+
Person.attribute :age, :type => :integer
|
248
|
+
Person.attribute :parts, :type => :float
|
249
|
+
end
|
250
|
+
|
251
|
+
it "converts value types when initializing an object" do
|
252
|
+
person = Person.new(:name => 123, :age => "21", :parts => "5.2")
|
253
|
+
person.name.should == "123"
|
254
|
+
person.age.should == 21
|
255
|
+
person.parts.should == 5.2
|
256
|
+
end
|
257
|
+
|
258
|
+
it "doesn't convert the value type if value is nil" do
|
259
|
+
person = Person.new(:name => nil, :age => nil, :parts => nil)
|
260
|
+
person.name.should be_nil
|
261
|
+
person.age.should be_nil
|
262
|
+
person.parts.should be_nil
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|