dirt-core 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +46 -0
  3. data/MIT-LICENSE +23 -0
  4. data/README +14 -0
  5. data/doc/BlockValidator.html +272 -0
  6. data/doc/ClosureValidator.html +276 -0
  7. data/doc/Dirt.html +158 -0
  8. data/doc/Dirt/FooBar.html +167 -0
  9. data/doc/Dirt/HerpZerp.html +161 -0
  10. data/doc/Dirt/HerpZerp/DerpGerp.html +161 -0
  11. data/doc/Dirt/HerpZerp/DerpGerp/FooBar.html +167 -0
  12. data/doc/Dirt/MemoryPersister.html +453 -0
  13. data/doc/Dirt/MemoryRecord.html +157 -0
  14. data/doc/Dirt/MissingRecordError.html +157 -0
  15. data/doc/Dirt/Model.html +320 -0
  16. data/doc/Dirt/NoPersisterError.html +157 -0
  17. data/doc/Dirt/Relation.html +338 -0
  18. data/doc/Dirt/Role.html +345 -0
  19. data/doc/Dirt/TooManyRecordsError.html +157 -0
  20. data/doc/Dirt/TransactionError.html +157 -0
  21. data/doc/ExistenceValidator.html +316 -0
  22. data/doc/FooBar.html +153 -0
  23. data/doc/Gemfile.html +131 -0
  24. data/doc/HerpZerp.html +147 -0
  25. data/doc/HerpZerp/DerpGerp.html +147 -0
  26. data/doc/HerpZerp/DerpGerp/FooBar.html +153 -0
  27. data/doc/Persister.html +311 -0
  28. data/doc/Persisting.html +413 -0
  29. data/doc/PresenceValidator.html +281 -0
  30. data/doc/README.html +132 -0
  31. data/doc/Role.html +309 -0
  32. data/doc/Scheduler.html +147 -0
  33. data/doc/SelfExistenceValidator.html +278 -0
  34. data/doc/TestPersister.html +411 -0
  35. data/doc/Validating.html +293 -0
  36. data/doc/created.rid +18 -0
  37. data/doc/images/add.png +0 -0
  38. data/doc/images/brick.png +0 -0
  39. data/doc/images/brick_link.png +0 -0
  40. data/doc/images/bug.png +0 -0
  41. data/doc/images/bullet_black.png +0 -0
  42. data/doc/images/bullet_toggle_minus.png +0 -0
  43. data/doc/images/bullet_toggle_plus.png +0 -0
  44. data/doc/images/date.png +0 -0
  45. data/doc/images/delete.png +0 -0
  46. data/doc/images/find.png +0 -0
  47. data/doc/images/loadingAnimation.gif +0 -0
  48. data/doc/images/macFFBgHack.png +0 -0
  49. data/doc/images/package.png +0 -0
  50. data/doc/images/page_green.png +0 -0
  51. data/doc/images/page_white_text.png +0 -0
  52. data/doc/images/page_white_width.png +0 -0
  53. data/doc/images/plugin.png +0 -0
  54. data/doc/images/ruby.png +0 -0
  55. data/doc/images/tag_blue.png +0 -0
  56. data/doc/images/tag_green.png +0 -0
  57. data/doc/images/transparent.png +0 -0
  58. data/doc/images/wrench.png +0 -0
  59. data/doc/images/wrench_orange.png +0 -0
  60. data/doc/images/zoom.png +0 -0
  61. data/doc/index.html +110 -0
  62. data/doc/js/darkfish.js +155 -0
  63. data/doc/js/jquery.js +18 -0
  64. data/doc/js/navigation.js +142 -0
  65. data/doc/js/search.js +94 -0
  66. data/doc/js/search_index.js +1 -0
  67. data/doc/js/searcher.js +228 -0
  68. data/doc/rdoc.css +543 -0
  69. data/doc/table_of_contents.html +203 -0
  70. data/lib/dirt/bdd/matchers.rb +10 -0
  71. data/lib/dirt/bdd/persister_spec_helper.rb +213 -0
  72. data/lib/dirt/bdd/shared_examples.rb +29 -0
  73. data/lib/dirt/contexts/context.rb +15 -0
  74. data/lib/dirt/core.rb +36 -0
  75. data/lib/dirt/errors/missing_record_error.rb +4 -0
  76. data/lib/dirt/errors/no_persister_error.rb +4 -0
  77. data/lib/dirt/errors/too_many_records_error.rb +4 -0
  78. data/lib/dirt/errors/transaction_error.rb +4 -0
  79. data/lib/dirt/models/model_behaviour.rb +47 -0
  80. data/lib/dirt/persisters/memory_persister.rb +86 -0
  81. data/lib/dirt/persisters/persister.rb +54 -0
  82. data/lib/dirt/persisters/relation.rb +38 -0
  83. data/lib/dirt/roles/persisting.rb +73 -0
  84. data/lib/dirt/roles/role.rb +32 -0
  85. data/lib/dirt/roles/validating.rb +27 -0
  86. data/lib/dirt/roles/validation/closure_validator.rb +15 -0
  87. data/lib/dirt/roles/validation/existence_validator.rb +53 -0
  88. data/lib/dirt/roles/validation/presence_validator.rb +21 -0
  89. data/lib/dirt/roles/validation/self_existence_validator.rb +18 -0
  90. data/spec/isolations/closure_validator_spec.rb +57 -0
  91. data/spec/isolations/context_spec.rb +54 -0
  92. data/spec/isolations/existence_validator_spec.rb +151 -0
  93. data/spec/isolations/memory_persister_spec.rb +175 -0
  94. data/spec/isolations/model_spec.rb +91 -0
  95. data/spec/isolations/persister_spec.rb +113 -0
  96. data/spec/isolations/persisting_spec.rb +266 -0
  97. data/spec/isolations/presence_validator_spec.rb +63 -0
  98. data/spec/isolations/role_spec.rb +116 -0
  99. data/spec/isolations/self_existence_validator_spec.rb +64 -0
  100. data/spec/isolations/spec_helper.rb +26 -0
  101. data/spec/isolations/validating_spec.rb +88 -0
  102. metadata +161 -0
@@ -0,0 +1,91 @@
1
+ #--
2
+ # Copyright (c) 2014 Tenjin Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require './spec/isolations/spec_helper'
25
+
26
+ module Dirt
27
+ describe ModelBehaviour do
28
+ # Need to give it a attributes for testing
29
+ class Model
30
+ include ModelBehaviour
31
+ attr_accessor :test_variable1, :test_variable2
32
+ end
33
+
34
+ let(:expected_value1) { double('a variable') }
35
+ let(:expected_value2) { double('something else') }
36
+
37
+ subject { Model.new(test_variable1: expected_value1, test_variable2: expected_value2) }
38
+
39
+ context '#initialize' do
40
+ it 'should save the given params from the hash' do
41
+ subject.test_variable1.should == expected_value1
42
+ subject.test_variable2.should == expected_value2
43
+ end
44
+ end
45
+
46
+ context '#update' do
47
+ subject { Model.new() }
48
+
49
+ it 'should save the given params from the hash' do
50
+ subject.update(test_variable1: expected_value1, test_variable2: expected_value2)
51
+
52
+ subject.test_variable1.should == expected_value1
53
+ subject.test_variable2.should == expected_value2
54
+ end
55
+ end
56
+
57
+ context '#to_hash' do
58
+ it 'should return the model data as a hash' do
59
+ subject.to_hash.should == {test_variable1: expected_value1, test_variable2: expected_value2}
60
+ end
61
+ end
62
+
63
+ context '#==' do
64
+ it 'should return false vs nil' do
65
+ subject.==(nil).should be false
66
+ end
67
+
68
+ it 'should return false vs a different object' do
69
+ subject.==(double('different thingy')).should be false
70
+ end
71
+
72
+ it 'should return true vs itself' do
73
+ subject.==(subject).should be true
74
+ end
75
+
76
+ it 'should return true vs another object with equivalent values' do
77
+ other = double('different thingy')
78
+
79
+ other.stub(:instance_variable_get).and_return do |*args|
80
+ if args.first == :@test_variable1
81
+ expected_value1
82
+ elsif args.first == :@test_variable2
83
+ expected_value2
84
+ end
85
+ end
86
+
87
+ subject.==(other).should == true
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,113 @@
1
+ #--
2
+ # Copyright (c) 2014 Tenjin Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require './spec/isolations/spec_helper'
25
+
26
+ module Dirt
27
+ describe Persister do
28
+ let(:fake_persister) { double 'Fake Persister' }
29
+
30
+ describe '#for' do
31
+ class FooBar
32
+ end
33
+
34
+ module HerpZerp
35
+ module DerpGerp
36
+ class FooBar
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ [FooBar, HerpZerp::DerpGerp::FooBar, :foo_bar].each do |arg|
43
+ context "#{arg} is passed in" do
44
+ let(:expected_persister) { double('Peristathingy') }
45
+
46
+ it 'should save using the given argument and return the expected persister with the appropriate symbol' do
47
+ Persister.for(arg, expected_persister)
48
+ Persister.for(:foo_bar).should be expected_persister
49
+ end
50
+
51
+ after(:each) { Persister.clear }
52
+ end
53
+ end
54
+
55
+ context 'no persister for type' do
56
+ it 'should throw an exception' do
57
+ expect { Persister.for(:bogus_type) }.to raise_error(NoPersisterError, 'There is no persister for "bogus_types".')
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#clear' do
63
+ it 'should empty the persisters hash' do
64
+ Persister.clear
65
+
66
+ Persister.class_variable_get(:@@persisters).should == nil
67
+ end
68
+ end
69
+
70
+ describe "#transaction" do
71
+ it "should return errors when a Transaction error is raised" do
72
+ Persister.stub(:for).and_return(fake_persister)
73
+ expect(fake_persister).to receive(:transaction) do |&block|
74
+ block.call
75
+ end
76
+
77
+ Persister.transaction([fake_persister]) do
78
+ raise TransactionError, "The Error"
79
+ end.should == {errors: ["The Error"]}
80
+ end
81
+
82
+ it "should not rescue non-transaction errors" do
83
+ Persister.stub(:for).and_return(fake_persister)
84
+ expect(fake_persister).to receive(:transaction) do |&block|
85
+ block.call
86
+ end
87
+
88
+ expect { Persister.transaction([fake_persister]) do
89
+ raise StandardError, "Different Error"
90
+ end }.to raise_error(StandardError, "Different Error")
91
+ end
92
+
93
+ it "should trigger the block within the transactions of all persisters" do
94
+ p1, p2, p3 = double('persister'), double('persister'), double('persister')
95
+ p1.stub(:transaction) do |&block|
96
+ ">#{block.call}<"
97
+ end
98
+
99
+ p2.stub(:transaction) do |&block|
100
+ ">#{block.call}<"
101
+ end
102
+
103
+ p3.stub(:transaction) do |&block|
104
+ ">#{block.call}<"
105
+ end
106
+
107
+ Persister.transaction([p1, p2, p3]) do
108
+ "Trigger Block"
109
+ end.should == ">>>Trigger Block<<<"
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,266 @@
1
+ #--
2
+ # Copyright (c) 2014 Tenjin Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require './spec/isolations/spec_helper'
25
+
26
+ module Dirt
27
+
28
+ describe Persisting do
29
+ let(:decorated) { double('decorated', to_hash: {some: 'data'}) }
30
+
31
+ subject do
32
+ Persisting.new(decorated)
33
+ end
34
+
35
+ let(:persister) { MemoryPersister.new(:some_type) }
36
+
37
+ before(:each) do
38
+ Persister.for(:mock, persister)
39
+ end
40
+
41
+ after(:each) do
42
+ Persister.clear
43
+ end
44
+
45
+ describe '#initialize' do
46
+ it 'should save the given id' do
47
+ id = 5
48
+ p = Persisting.new(decorated, id)
49
+ p.id.should == id
50
+ end
51
+ end
52
+
53
+ describe '#==' do
54
+ context 'same id' do
55
+ let(:decorated) { [5] }
56
+
57
+ it 'should be equal with equivalent contents' do
58
+ clone = [5]
59
+ decorated.should == clone
60
+ subject.should == Persisting.new(clone)
61
+ end
62
+ end
63
+
64
+ context 'different id' do
65
+ it 'should not be equal' do
66
+ other = Persisting.new(decorated)
67
+
68
+ subject.instance_variable_set(:@id, 1)
69
+ other.instance_variable_set(:@id, 2)
70
+
71
+ subject.should_not == other
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '#save' do
77
+ let(:id) { double('id') }
78
+
79
+ context 'persistence completes' do
80
+ it 'should call persister save with nil id' do
81
+ persister.should_receive(:save).with(decorated, nil)
82
+
83
+ subject.save()
84
+ end
85
+
86
+ it 'should remember the id assinged by persister' do
87
+ persister.stub(:save).and_return(OpenStruct.new(id: id, data: decorated))
88
+
89
+ subject.save()
90
+
91
+ subject.id.should == id
92
+ end
93
+
94
+ it 'should return itself' do
95
+ subject.save().should be subject
96
+ end
97
+ end
98
+
99
+ context 'persistence fails' do
100
+ before(:each) do
101
+ persister.stub(:save).and_return(nil)
102
+ end
103
+
104
+ it 'should call persister save with nil id' do
105
+ persister.should_receive(:save).with(decorated, nil)
106
+
107
+ subject.save()
108
+ end
109
+
110
+ it 'should not remember an id' do
111
+ subject.save()
112
+
113
+ subject.id.should == nil
114
+ end
115
+
116
+ it 'should return nil' do
117
+ subject.save().should be nil
118
+ end
119
+ end
120
+ end
121
+
122
+ context '#load' do
123
+ context 'there is a record by that id' do
124
+ let(:id) { persister.save(decorated).id }
125
+ let(:decorated_hash) { {some: 'data and things'} }
126
+
127
+ before(:each) do
128
+ decorated.stub(:to_hash).and_return(decorated_hash)
129
+ end
130
+
131
+ it 'should load the persisted object into itself' do
132
+ decorated.should_receive(:update).with(decorated_hash)
133
+
134
+ subject.load(id)
135
+ end
136
+
137
+ it 'should keep the id' do
138
+ decorated.stub(:update)
139
+
140
+ subject.load(id).id.should == id
141
+ end
142
+
143
+ it 'should return itself' do
144
+ decorated.stub(:update)
145
+
146
+ subject.load(id).should be subject
147
+ end
148
+ end
149
+
150
+ context 'no record has that id' do
151
+ it 'should explode' do
152
+ expect { subject.load(double('id')) }.to raise_error(MissingRecordError)
153
+ end
154
+ end
155
+ end
156
+
157
+ context '#load_by' do
158
+ let(:attr) { :test_attr }
159
+ let(:value) { double('test value') }
160
+
161
+ let(:record1) { double('record1', to_hash: {some: 'data1'}) }
162
+ let(:record2) { double('record2', to_hash: {some: 'data2'}) }
163
+ let(:record3) { double('record3', to_hash: {some: 'data3'}) }
164
+
165
+ before(:each) do
166
+ persister.save(record1)
167
+ persister.save(record2)
168
+ persister.save(record3)
169
+ end
170
+
171
+ context 'there is a record by that attribute' do
172
+ let(:record_hash) { {attr => 'record2\'s hash'} }
173
+
174
+ before(:each) do
175
+ record1.stub(attr).and_return(double('something else'))
176
+ record2.stub(attr).and_return(double('something else'))
177
+ record3.stub(attr).and_return(value)
178
+
179
+ record3.stub(:to_hash).and_return(record_hash)
180
+ end
181
+
182
+ it 'should load the persisted object into itself' do
183
+ decorated.should_receive(:update).with(record_hash)
184
+
185
+ subject.load_by(attr => value)
186
+ end
187
+
188
+ it 'should return itself' do
189
+ decorated.stub(:update)
190
+
191
+ subject.load_by(attr => value).should be subject
192
+ end
193
+
194
+ it 'should keep the found id' do
195
+ decorated.stub(:update)
196
+
197
+ subject.load_by(attr => value).id.should == 3
198
+ end
199
+ end
200
+
201
+ context 'multiple records have that attribute' do
202
+ let(:record_hash) { {record_attr: 'and a value'} }
203
+
204
+ before(:each) do
205
+ record1.stub(attr).and_return(double('something else'))
206
+ record2.stub(attr).and_return(value)
207
+ record3.stub(attr).and_return(value)
208
+
209
+ record2.stub(:to_hash).and_return(record_hash)
210
+ end
211
+
212
+ it 'should load the first matching persisted object into itself' do
213
+ decorated.should_receive(:update).with(record_hash)
214
+
215
+ subject.load_by(attr => value)
216
+ end
217
+
218
+ it 'should return itself' do
219
+ decorated.stub(:update)
220
+
221
+ subject.load_by(attr => value).should be subject
222
+ end
223
+
224
+ it 'should keep the found id' do
225
+ decorated.stub(:update)
226
+
227
+ subject.load_by(attr => value).id.should == 2
228
+ end
229
+ end
230
+
231
+ context 'no record has that attribute' do
232
+ before(:each) do
233
+ record1.stub(attr).and_return(double('something else'))
234
+ record2.stub(attr).and_return(double('something else'))
235
+ record3.stub(attr).and_return(double('something else'))
236
+ end
237
+
238
+ it 'should NOT load the persisted object but explode' do
239
+ decorated.should_not_receive(:update)
240
+
241
+ expect { subject.load_by(attr => value) }.to raise_error(MissingRecordError, "No record matches #{attr} == #{value}.")
242
+ end
243
+ end
244
+ end
245
+
246
+ context '#delete' do
247
+ context 'there is a record by that id' do
248
+ let(:id) { persister.save(decorated).id }
249
+ it 'should return the persisting-wrapped deleted object' do
250
+ deleted = Persisting.new(decorated)
251
+
252
+ persister.stub(:delete).and_return(deleted)
253
+ subject.delete(id).should == deleted
254
+ end
255
+ end
256
+
257
+ context 'no record has that id' do
258
+ it 'should return nil' do
259
+ persister.stub(:delete).and_return(nil)
260
+
261
+ expect { subject.delete(double('an_id')) }.to raise_error(MissingRecordError)
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end