kalimba 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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +132 -0
- data/Rakefile +8 -0
- data/kalimba-redlander.gemspec +19 -0
- data/kalimba.gemspec +22 -0
- data/lib/kalimba.rb +24 -0
- data/lib/kalimba/attribute_assignment.rb +148 -0
- data/lib/kalimba/callbacks.rb +30 -0
- data/lib/kalimba/exceptions.rb +18 -0
- data/lib/kalimba/localized_attributes.rb +36 -0
- data/lib/kalimba/persistence.rb +225 -0
- data/lib/kalimba/railtie.rb +11 -0
- data/lib/kalimba/railties/repository.rake +7 -0
- data/lib/kalimba/reflection.rb +54 -0
- data/lib/kalimba/resource.rb +266 -0
- data/lib/kalimba/validations.rb +69 -0
- data/lib/kalimba/version.rb +3 -0
- data/spec/lib/kalimba/attributes_spec.rb +145 -0
- data/spec/lib/kalimba/callbacks_spec.rb +90 -0
- data/spec/lib/kalimba/persistence_spec.rb +344 -0
- data/spec/lib/kalimba/resource_spec.rb +130 -0
- data/spec/lib/kalimba/validations_spec.rb +25 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/resource_ext.rb +45 -0
- metadata +133 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module Kalimba
|
4
|
+
# Raised by <tt>save!</tt> and <tt>create!</tt> when the record is invalid. Use the
|
5
|
+
# +record+ method to retrieve the record which did not validate.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# begin
|
9
|
+
# complex_operation_that_calls_save!_internally
|
10
|
+
# rescue Kalimba::RecordInvalid => invalid
|
11
|
+
# puts invalid.record.errors
|
12
|
+
# end
|
13
|
+
class RecordInvalid < KalimbaError
|
14
|
+
attr_reader :record
|
15
|
+
def initialize(record)
|
16
|
+
@record = record
|
17
|
+
errors = @record.errors.full_messages.join(", ")
|
18
|
+
# TODO: use I18n later
|
19
|
+
# super I18n.t("activerecord.errors.messages.record_invalid", :errors => errors)
|
20
|
+
super "invalid record"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Validations
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
include ActiveModel::Validations
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Creates an object just like Persistence.create but calls <tt>save!</tt> instead of +save+
|
30
|
+
# so an exception is raised if the record is invalid.
|
31
|
+
def create!(attributes = {}, &block)
|
32
|
+
if attributes.is_a?(Array)
|
33
|
+
attributes.each { |attr| create!(attr, &block) }
|
34
|
+
else
|
35
|
+
create(attributes, &block) || (raise RecordInvalid, self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def save(options = {})
|
41
|
+
perform_validations(options) ? super : false
|
42
|
+
end
|
43
|
+
|
44
|
+
def save!(options = {})
|
45
|
+
save || (raise RecordInvalid, self)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Runs all the validations within the specified context. Returns true if no errors are found,
|
49
|
+
# false otherwise.
|
50
|
+
#
|
51
|
+
# If the argument is false (default is +nil+), the context is set to <tt>:create</tt> if
|
52
|
+
# <tt>new_record?</tt> is true, and to <tt>:update</tt> if it is not.
|
53
|
+
#
|
54
|
+
# Validations with no <tt>:on</tt> option will run no matter the context. Validations with
|
55
|
+
# some <tt>:on</tt> option will only run in the specified context.
|
56
|
+
def valid?(context = nil)
|
57
|
+
context ||= (new_record? ? :create : :update)
|
58
|
+
output = super(context)
|
59
|
+
errors.empty? && output
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def perform_validations(options={})
|
65
|
+
perform_validation = options[:validate] != false
|
66
|
+
perform_validation ? valid?(options[:context]) : true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "attribute handling" do
|
4
|
+
before :all do
|
5
|
+
class AttributeTestOilRig < Kalimba::Resource
|
6
|
+
type "http://schema.org/OilRig"
|
7
|
+
base_uri "http://example.org/oil_rigs"
|
8
|
+
|
9
|
+
property :safe, :predicate => "http://example.org/safe", :datatype => NS::XMLSchema["boolean"]
|
10
|
+
property :name, :predicate => "http://example.org/name", :datatype => NS::XMLSchema["string"]
|
11
|
+
property :local_time, :predicate => "http://example.org/time", :datatype => NS::XMLSchema["time"]
|
12
|
+
property :created_at, :predicate => "http://example.org/date", :datatype => NS::XMLSchema["date"]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:rig) { AttributeTestOilRig.for("bp1") }
|
17
|
+
|
18
|
+
describe "boolean value" do
|
19
|
+
subject { rig.safe }
|
20
|
+
|
21
|
+
context "when not set" do
|
22
|
+
it { should be_a NilClass }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when set to 'false'" do
|
26
|
+
before { rig.safe = false }
|
27
|
+
|
28
|
+
it { should be_a FalseClass }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "localized string" do
|
33
|
+
before do
|
34
|
+
# populate the storage with literals in different locales
|
35
|
+
{ en: "Quarter Pounder with Cheese",
|
36
|
+
fr: "Le Big Mac" }.each do |lang, text|
|
37
|
+
Kalimba.repository.statements.create(subject: rig.subject,
|
38
|
+
predicate: rig.class.properties["name"][:predicate],
|
39
|
+
object: text.with_lang(lang))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
subject { rig.name }
|
44
|
+
|
45
|
+
context "when retrieved" do
|
46
|
+
describe "string language" do
|
47
|
+
subject { rig.name.lang }
|
48
|
+
|
49
|
+
context "in :fr locale" do
|
50
|
+
around do |example|
|
51
|
+
I18n.with_locale(:fr) { example.call }
|
52
|
+
end
|
53
|
+
|
54
|
+
it { should eql :fr }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "in :en locale" do
|
58
|
+
around do |example|
|
59
|
+
I18n.with_locale(:en) { example.call }
|
60
|
+
end
|
61
|
+
|
62
|
+
it { should eql :en }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when stored" do
|
68
|
+
it "should not be overwritten by a localized string in another language" do
|
69
|
+
rig.update_attributes(name: "Burger")
|
70
|
+
|
71
|
+
s1 = Redlander::Statement.new(subject: rig.subject,
|
72
|
+
predicate: rig.class.properties["name"][:predicate],
|
73
|
+
object: "Quarter Pounder with Cheese".with_lang(:en))
|
74
|
+
s2 = Redlander::Statement.new(subject: rig.subject,
|
75
|
+
predicate: rig.class.properties["name"][:predicate],
|
76
|
+
object: "Le Big Mac".with_lang(:fr))
|
77
|
+
s3 = Redlander::Statement.new(subject: rig.subject,
|
78
|
+
predicate: rig.class.properties["name"][:predicate],
|
79
|
+
object: "Burger")
|
80
|
+
|
81
|
+
Kalimba.repository.statements.to_a.should include s1
|
82
|
+
Kalimba.repository.statements.to_a.should include s2
|
83
|
+
Kalimba.repository.statements.to_a.should include s3
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "multiparameter attribute" do
|
89
|
+
describe "localized string" do
|
90
|
+
subject { rig.name }
|
91
|
+
|
92
|
+
context "when assigned" do
|
93
|
+
before { rig.assign_attributes("name(1)" => "Oil Rig", "name(2)" => "en") }
|
94
|
+
|
95
|
+
it { should be_a LocalizedString }
|
96
|
+
it { should eql "Oil Rig" }
|
97
|
+
it "should have language set to 'en'" do
|
98
|
+
expect(rig.name.lang).to eql "en"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "time" do
|
104
|
+
subject { rig.local_time }
|
105
|
+
|
106
|
+
context "when assigned from two parameters" do
|
107
|
+
before do
|
108
|
+
rig.assign_attributes("local_time(1)" => "2013-03-08",
|
109
|
+
"local_time(2)" => "18:14")
|
110
|
+
end
|
111
|
+
|
112
|
+
it { should be_a Time }
|
113
|
+
it { should eql Time.new(2013, 3, 8, 18, 14) }
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when assigned from many parameters" do
|
117
|
+
before do
|
118
|
+
rig.assign_attributes("local_time(1i)" => "2013",
|
119
|
+
"local_time(2i)" => "03",
|
120
|
+
"local_time(3i)" => "08",
|
121
|
+
"local_time(4i)" => "18",
|
122
|
+
"local_time(5i)" => "14")
|
123
|
+
end
|
124
|
+
|
125
|
+
it { should be_a Time }
|
126
|
+
it { should eql Time.new(2013, 3, 8, 18, 14) }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "date" do
|
131
|
+
subject { rig.created_at }
|
132
|
+
|
133
|
+
context "when assigned" do
|
134
|
+
before do
|
135
|
+
rig.assign_attributes("created_at(1i)" => "2013",
|
136
|
+
"created_at(2i)" => "03",
|
137
|
+
"created_at(3i)" => "08")
|
138
|
+
end
|
139
|
+
|
140
|
+
it { should be_a Date }
|
141
|
+
it { should eql Date.new(2013, 3, 8) }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "callbacks" do
|
4
|
+
before :all do
|
5
|
+
class CallbacksTestPerson < Human
|
6
|
+
attr_accessor :triggers
|
7
|
+
|
8
|
+
type "http://schema.org/CallbacksTestPerson"
|
9
|
+
base_uri "http://example.com/people/"
|
10
|
+
|
11
|
+
before_create :trigger_1
|
12
|
+
before_update :trigger_2
|
13
|
+
before_save :trigger_3
|
14
|
+
before_destroy :trigger_4
|
15
|
+
|
16
|
+
def initialize(*args)
|
17
|
+
@triggers = []
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def trigger_1
|
24
|
+
@triggers << 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def trigger_2
|
28
|
+
@triggers << 2
|
29
|
+
end
|
30
|
+
|
31
|
+
def trigger_3
|
32
|
+
@triggers << 3
|
33
|
+
end
|
34
|
+
|
35
|
+
def trigger_4
|
36
|
+
@triggers << 4
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:person) { CallbacksTestPerson.create }
|
42
|
+
|
43
|
+
context "when creating a resource" do
|
44
|
+
it "should trigger 2 callbacks" do
|
45
|
+
expect(person.triggers.size).to eql 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it "before_create callback should be triggered" do
|
49
|
+
expect(person.triggers).to include 1
|
50
|
+
end
|
51
|
+
|
52
|
+
it "before_save callback should be triggered" do
|
53
|
+
expect(person.triggers).to include 3
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when destroying a resource" do
|
58
|
+
before do
|
59
|
+
person.triggers = []
|
60
|
+
person.destroy
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should trigger 1 callback" do
|
64
|
+
expect(person.triggers.size).to eql 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "before_destroy callback should be triggered" do
|
68
|
+
expect(person.triggers).to include 4
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when updating a resource" do
|
73
|
+
before do
|
74
|
+
person.triggers = []
|
75
|
+
person.update_attributes(name: "Vasya")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should trigger 2 callbacks" do
|
79
|
+
expect(person.triggers.size).to eql 2
|
80
|
+
end
|
81
|
+
|
82
|
+
it "before_update callback should be triggered" do
|
83
|
+
expect(person.triggers).to include 2
|
84
|
+
end
|
85
|
+
|
86
|
+
it "before_save callback should be triggered" do
|
87
|
+
expect(person.triggers).to include 3
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,344 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Kalimba::Persistence do
|
4
|
+
before :all do
|
5
|
+
class PersistenceTestPerson < Engineer
|
6
|
+
type "http://schema.org/PersistenceTestPerson"
|
7
|
+
base_uri "http://example.org/people"
|
8
|
+
end
|
9
|
+
|
10
|
+
class PersistenceTestOilRig < Kalimba::Resource
|
11
|
+
type "http://schema.org/OilRig"
|
12
|
+
base_uri "http://example.org/oil_rigs"
|
13
|
+
|
14
|
+
property :safe, :predicate => "http://example.org/safe", :datatype => NS::XMLSchema["boolean"]
|
15
|
+
property :operator, :predicate => "http://example.org/operator", :datatype => :PersistenceTestPerson
|
16
|
+
has_many :saboteurs, :predicate => "http://example.org/saboteur", :datatype => "http://schema.org/Saboteur"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "associations" do
|
21
|
+
before { PersistenceTestOilRig.create }
|
22
|
+
let(:rig) { PersistenceTestOilRig.first }
|
23
|
+
|
24
|
+
describe "instantiation" do
|
25
|
+
context "of existing Kalimba resources" do
|
26
|
+
before do
|
27
|
+
Kalimba.repository.statements.create(:subject => rig.subject,
|
28
|
+
:predicate => PersistenceTestOilRig.properties["operator"][:predicate],
|
29
|
+
:object => PersistenceTestPerson.create.subject)
|
30
|
+
end
|
31
|
+
|
32
|
+
subject { rig.operator }
|
33
|
+
|
34
|
+
it { should be_an_instance_of(PersistenceTestPerson) }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "of unknown Kalimba resources" do
|
38
|
+
before do
|
39
|
+
Kalimba.repository.statements.create(:subject => rig.subject,
|
40
|
+
:predicate => PersistenceTestOilRig.properties["saboteurs"][:predicate],
|
41
|
+
:object => URI("http://schema.org/Saboteur#Karen_Knight"))
|
42
|
+
Kalimba.repository.statements.create(:subject => rig.subject,
|
43
|
+
:predicate => PersistenceTestOilRig.properties["saboteurs"][:predicate],
|
44
|
+
:object => URI("http://schema.org/Saboteur#Lee_Knight"))
|
45
|
+
end
|
46
|
+
|
47
|
+
subject { rig.saboteurs }
|
48
|
+
|
49
|
+
it { should be_a(Enumerable) }
|
50
|
+
|
51
|
+
it "should yield anonymous class instances" do
|
52
|
+
expect(subject.first.class).to be_anonymous
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should add the anonymous class to RDFSClass repository" do
|
56
|
+
subject
|
57
|
+
expect(Kalimba::Resource.descendants).to include(subject.first.class)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not create more than one anonymous class for homogenious objects" do
|
61
|
+
expect(subject.first.class).to eql subject.last.class
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set class type to the declared datatype" do
|
65
|
+
expect(subject.first.class.type).to eql PersistenceTestOilRig.properties["saboteurs"][:datatype]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should set class base_uri to the URI of the instance (without the fragment)" do
|
69
|
+
expect(subject.first.class.base_uri).to eql URI("http://schema.org/Saboteur/")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "count" do
|
76
|
+
subject { PersistenceTestPerson.count }
|
77
|
+
|
78
|
+
before do
|
79
|
+
3.times { PersistenceTestPerson.create }
|
80
|
+
end
|
81
|
+
|
82
|
+
it { should eql 3 }
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "find" do
|
86
|
+
let(:options) { {:conditions => {:rank => 4}} }
|
87
|
+
|
88
|
+
context "when records are found" do
|
89
|
+
before do
|
90
|
+
PersistenceTestPerson.create(:rank => 4, :duties => %w(sex sleep eat drink dream))
|
91
|
+
end
|
92
|
+
|
93
|
+
describe ":first" do
|
94
|
+
subject { PersistenceTestPerson.find(:first, options) }
|
95
|
+
|
96
|
+
it { should be_a PersistenceTestPerson }
|
97
|
+
end
|
98
|
+
|
99
|
+
describe ":all" do
|
100
|
+
subject { PersistenceTestPerson.find(:all, options) }
|
101
|
+
|
102
|
+
it { should be_a Enumerable }
|
103
|
+
it "should return an array of found entries" do
|
104
|
+
subject.size.should eql 1
|
105
|
+
subject.first.should be_a PersistenceTestPerson
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when records are not found" do
|
111
|
+
before do
|
112
|
+
PersistenceTestPerson.create(:rank => 0, :duties => %w(sex sleep eat drink dream))
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ":first" do
|
116
|
+
subject { PersistenceTestPerson.find(:first, options) }
|
117
|
+
|
118
|
+
it { should be_nil }
|
119
|
+
end
|
120
|
+
|
121
|
+
describe ":all" do
|
122
|
+
subject { PersistenceTestPerson.find(:all, options) }
|
123
|
+
|
124
|
+
it { should be_empty }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "create" do
|
130
|
+
let(:person) { PersistenceTestPerson.create }
|
131
|
+
subject { person }
|
132
|
+
|
133
|
+
it { should be_a Kalimba::Resource }
|
134
|
+
|
135
|
+
it "should persist the instance" do
|
136
|
+
subject.should be_persisted
|
137
|
+
subject.should_not be_new_record
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "destroy_all" do
|
142
|
+
before do
|
143
|
+
2.times { PersistenceTestPerson.create }
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should destroy all instances of the given RDFS class" do
|
147
|
+
expect { PersistenceTestPerson.destroy_all }.to change(Kalimba.repository, :size).by(-2)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should not destroy instances of other RDFS classes" do
|
151
|
+
rig = PersistenceTestOilRig.create
|
152
|
+
PersistenceTestPerson.destroy_all
|
153
|
+
expect(PersistenceTestOilRig.exist?).to be_true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "exist?" do
|
158
|
+
subject { PersistenceTestPerson.exist? }
|
159
|
+
|
160
|
+
context "when there are no RDFS class instances in the repository" do
|
161
|
+
before { PersistenceTestPerson.new }
|
162
|
+
|
163
|
+
it { should be_false }
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when there are RDFS class instances in the repository" do
|
167
|
+
before { PersistenceTestPerson.create }
|
168
|
+
|
169
|
+
it { should be_true }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "new record" do
|
174
|
+
let(:person) { PersistenceTestPerson.new }
|
175
|
+
subject { person }
|
176
|
+
|
177
|
+
it { should be_new_record }
|
178
|
+
it { should_not be_persisted }
|
179
|
+
|
180
|
+
describe "subject" do
|
181
|
+
subject { person.subject }
|
182
|
+
|
183
|
+
it { should be_nil }
|
184
|
+
|
185
|
+
context "after save" do
|
186
|
+
before { person.save }
|
187
|
+
|
188
|
+
it { should be_a URI }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "save" do
|
193
|
+
it "should return true" do
|
194
|
+
expect(person.save).to be_true
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should persist the record" do
|
198
|
+
person.save
|
199
|
+
person.should_not be_new_record
|
200
|
+
person.should_not be_changed
|
201
|
+
person.should be_persisted
|
202
|
+
end
|
203
|
+
|
204
|
+
context "when failed halfway" do
|
205
|
+
# TODO: need a more "natural" method of causing an error on save
|
206
|
+
before { person.stub(store_type: false) }
|
207
|
+
|
208
|
+
it "should not leave remains in the repository" do
|
209
|
+
person.save
|
210
|
+
Kalimba.repository.statements.exist?(subject: person.subject).should be_false
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "with changes" do
|
216
|
+
context "when saved" do
|
217
|
+
it "should have values type cast" do
|
218
|
+
person.rank = "2"
|
219
|
+
expect {
|
220
|
+
person.save && person.reload
|
221
|
+
}.to change(person, :rank).from("2").to(2)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should not persist non-castable values" do
|
225
|
+
person.retired = true
|
226
|
+
expect(person.save).to be_true
|
227
|
+
|
228
|
+
person.reload
|
229
|
+
expect(person.retired).to be_nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context "to a single value" do
|
234
|
+
before { person.rank = 1 }
|
235
|
+
|
236
|
+
context "when saved" do
|
237
|
+
before { subject.save }
|
238
|
+
|
239
|
+
it "should be added statements with changed attributes (type + rank)" do
|
240
|
+
expect(Kalimba.repository.size).to eql 2
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context "to an association" do
|
246
|
+
let(:charlie) { PersistenceTestPerson.for("charlie") }
|
247
|
+
before do
|
248
|
+
charlie.rank = 99
|
249
|
+
person.boss = charlie
|
250
|
+
end
|
251
|
+
|
252
|
+
context "when saved" do
|
253
|
+
before { subject.save }
|
254
|
+
|
255
|
+
it "should persist the association" do
|
256
|
+
charlie.should_not be_new_record
|
257
|
+
charlie.should be_persisted
|
258
|
+
charlie.should_not be_changed
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context "to collections" do
|
264
|
+
before { person.duties = %w(building designing) }
|
265
|
+
|
266
|
+
context "when saved" do
|
267
|
+
before { person.save }
|
268
|
+
|
269
|
+
it "should be added statements with changed attributes (type + duties*2)" do
|
270
|
+
expect(Kalimba.repository.size).to eql 3
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "reload" do
|
277
|
+
subject { PersistenceTestPerson.for(person.id) }
|
278
|
+
|
279
|
+
context "with related data in the storage" do
|
280
|
+
before { person.update_attributes(:rank => 7, :duties => %w(idling procrastinating)) }
|
281
|
+
|
282
|
+
it "should assign attributes the values from the storage" do
|
283
|
+
expect { subject.reload }.to change { subject.attributes["rank"] }.from(nil).to(7)
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should assign attributes the collections from the storage" do
|
287
|
+
expect { subject.reload }.to change { subject.attributes["duties"] }.from([]).to(%w(idling procrastinating))
|
288
|
+
end
|
289
|
+
|
290
|
+
context "when accessing an attribute" do
|
291
|
+
it "should retrieve it from the storage" do
|
292
|
+
expect { subject.rank }.to change { subject.attributes["rank"] }.from(nil).to(7)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "already persisted record" do
|
300
|
+
let(:person) { PersistenceTestPerson.create }
|
301
|
+
subject { person }
|
302
|
+
|
303
|
+
it { should_not be_new_record }
|
304
|
+
it { should be_persisted }
|
305
|
+
|
306
|
+
describe "subject" do
|
307
|
+
subject { person.subject }
|
308
|
+
|
309
|
+
it { should be_a URI }
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "destroy" do
|
313
|
+
before { @another = PersistenceTestPerson.create }
|
314
|
+
|
315
|
+
it "should remove the record from the storage" do
|
316
|
+
subject # create subject
|
317
|
+
expect { subject.destroy }.to change(Kalimba.repository, :size).by(-1)
|
318
|
+
subject.should_not be_new_record
|
319
|
+
subject.should_not be_persisted
|
320
|
+
subject.should be_destroyed
|
321
|
+
subject.should be_frozen
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should not remove other records from the storage" do
|
325
|
+
subject.destroy
|
326
|
+
expect(Kalimba.repository.statements.exist?(:subject => @another.subject)).to be_true
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "update_attributes" do
|
331
|
+
subject { person.update_attributes(:rank => 9) }
|
332
|
+
|
333
|
+
it { should be_true }
|
334
|
+
|
335
|
+
it "should assign the given attributes" do
|
336
|
+
expect { person.update_attributes(:rank => 0) }.to change(person, :rank).to(0)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should have no changes" do
|
340
|
+
expect(person.changes).to be_empty
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|