dirt-core 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
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,53 @@
1
+ require 'active_support/all'
2
+
3
+ # Tests for whether the property referenced by an id is saved in the appropriate persister.
4
+ # This validator is stateful. #error_message returns the errors from the most recent run of #valid?.
5
+ #
6
+ # For more about validation, see Validating
7
+ class ExistenceValidator
8
+ # Takes the symbol name of the property to validate, and an options hash.
9
+ #
10
+ # Options include:
11
+ # * +as+:: The class of the type to search under
12
+ # * +list+:: If set, will treat +property+ as an id list, checking existence of all.
13
+ #
14
+ def initialize(property, opts)
15
+ @property = property
16
+ @type = opts[:as] || raise(ArgumentError.new('ExistenceValidator requires as: be provided with a type.'))
17
+ @list = opts[:list] || false
18
+ @bad_ids = []
19
+ end
20
+
21
+ def valid?(validated)
22
+ return false unless validated
23
+
24
+ if @list
25
+ ids = validated.send(@property) || []
26
+ else
27
+ ids = [validated.send(property_id)]
28
+ end
29
+
30
+ persister = Persister.for(@type)
31
+
32
+ @bad_ids = ids.select do |id|
33
+ not persister.exists?(id)
34
+ end
35
+
36
+ @bad_ids.empty?
37
+ end
38
+
39
+ def error_message(validated)
40
+ unless @bad_ids.empty?
41
+ if @list
42
+ "Those #{@type.to_s.demodulize.pluralize} (ids: #{@bad_ids.join(", ")}) do not exist."
43
+ else
44
+ "That #{@type.to_s.demodulize} (id: #{@bad_ids.first || "nil"}) does not exist."
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+ def property_id
51
+ "#{@property}_id".to_sym
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ # Tests whether the given property is set (ie non-nil)
2
+ #
3
+ # For more about validation, see Validating
4
+ class PresenceValidator
5
+ # Takes the property name as symbol
6
+ def initialize(property)
7
+ @property = property
8
+ end
9
+
10
+ def valid?(validated)
11
+ return false unless validated
12
+
13
+ value = validated.send(@property)
14
+
15
+ value.present? && !(value =~ /\A\s*\Z/)
16
+ end
17
+
18
+ def error_message(validated)
19
+ "#{validated.class.to_s.demodulize} #{@property.to_s.gsub('_', ' ').downcase} must be provided."
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # Tests for the existence of the given id in the persister.
2
+ #
3
+ # For more about validation, see Validating
4
+ class SelfExistenceValidator
5
+ def initialize(type, id)
6
+ @type = type
7
+ @id = id
8
+ end
9
+
10
+ # +true+ if the validated object exists in the persister.
11
+ def valid?(validated)
12
+ Persister.for(@type).exists?(@id)
13
+ end
14
+
15
+ def error_message(validated)
16
+ "That #{@type.to_s.demodulize.downcase} (id: #{ @id || "nil" }) does not exist."
17
+ end
18
+ end
@@ -0,0 +1,57 @@
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
+ describe ClosureValidator do
27
+ let(:expected_validity) { double('validity') }
28
+ let(:expected_error) { double('error') }
29
+
30
+ describe 'closure use' do
31
+ subject do
32
+ ClosureValidator.new(lambda { |val| expected_validity }, lambda { |err| expected_error })
33
+ end
34
+
35
+ it 'should use the block to determines validity' do
36
+ subject.valid?(expected_validity).should be expected_validity
37
+ end
38
+
39
+ it 'should use the second block to determine the error' do
40
+ subject.error_message(expected_error).should be expected_error
41
+ end
42
+ end
43
+
44
+ describe 'parameters' do
45
+ subject do
46
+ ClosureValidator.new(lambda { |val| val }, lambda { |err| err })
47
+ end
48
+
49
+ it 'should pass the validated object into the valid? closure' do
50
+ subject.valid?(expected_validity).should be expected_validity
51
+ end
52
+
53
+ it 'should pass the validated object into the error closure' do
54
+ subject.error_message(expected_error).should be expected_error
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,54 @@
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
+ describe Dirt::Context do
27
+ describe '#run' do
28
+ it 'should create an instance and call #call on it' do
29
+ Dirt::Context.any_instance.should_receive(:call)
30
+
31
+ Dirt::Context.run(double('params'))
32
+ end
33
+
34
+ it 'should pass forward params to #new' do
35
+ args = double('params')
36
+
37
+ Dirt::Context.should_receive(:new).with(args).and_call_original
38
+
39
+ Dirt::Context.run(args)
40
+ end
41
+ end
42
+
43
+ describe '#initialize' do
44
+ it 'should accept no param' do
45
+ Dirt::Context.new()
46
+ end
47
+
48
+ it 'should accept params' do
49
+ args = double('params')
50
+
51
+ Dirt::Context.new(args)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,151 @@
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
+ describe ExistenceValidator do
27
+ let(:persister) { double('persister') }
28
+ let(:decorated) { double('decorated') }
29
+ let(:is_list) { false }
30
+
31
+ subject { ExistenceValidator.new(:some_reference, {as: :some_class, list: is_list}) }
32
+
33
+ before(:each) do
34
+ Persister.for(:some_class, persister)
35
+ end
36
+
37
+ after(:each) do
38
+ Persister.clear
39
+ end
40
+
41
+ describe '#initialize' do
42
+ it 'should explode when as: is not supplied' do
43
+ expect { ExistenceValidator.new(decorated, {}) }.to raise_error(ArgumentError)
44
+ end
45
+ end
46
+
47
+ describe '#valid?' do
48
+ it 'should return false if given nil' do
49
+ subject.valid?(nil).should be false
50
+ end
51
+
52
+ context 'single' do
53
+ before(:each) do
54
+ decorated.stub(:some_reference_id).and_return(double('id'))
55
+ end
56
+
57
+ it 'should return true when persister has something by the id' do
58
+ persister.stub(:exists?).and_return(true)
59
+
60
+ subject.valid?(decorated).should be true
61
+ end
62
+
63
+ it 'should return false when persister has nothing by the id' do
64
+ persister.stub(:exists?).and_return(false)
65
+
66
+ subject.valid?(decorated).should be false
67
+ end
68
+ end
69
+
70
+ context 'list' do
71
+ subject { ExistenceValidator.new(:some_reference_ids, {as: :some_class, list: true}) }
72
+
73
+ before(:each) do
74
+ decorated.stub(:some_reference_ids).and_return([double('id1'), double('id2'), double('id3')])
75
+ end
76
+
77
+ it 'should return true when persister has something for every id' do
78
+ persister.stub(:exists?).and_return(true, true, true)
79
+
80
+ subject.valid?(decorated).should be true
81
+ end
82
+
83
+ it 'should return false when persister has nothing for an id' do
84
+ persister.stub(:exists?).and_return(true, false, true)
85
+
86
+ subject.valid?(decorated).should be false
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#errors' do
92
+ context 'valid? not called previously' do
93
+ it 'should return nil' do
94
+ subject.error_message(decorated).should be nil
95
+ end
96
+ end
97
+
98
+ context 'single' do
99
+ let(:id) { double('id') }
100
+ before(:each) do
101
+ decorated.stub(:some_reference_id).and_return(id)
102
+ end
103
+
104
+ it 'should return nil when persister has something for the id' do
105
+ persister.stub(:exists?).and_return(true)
106
+ subject.valid?(decorated)
107
+
108
+ subject.error_message(decorated).should be nil
109
+ end
110
+
111
+ it 'should return an error when persister has nothing for the id' do
112
+ persister.stub(:exists?).and_return(false)
113
+ subject.valid?(decorated)
114
+
115
+ subject.error_message(decorated).should == "That some_class (id: #{id}) does not exist."
116
+ end
117
+ end
118
+
119
+ context 'list' do
120
+ subject { ExistenceValidator.new(:some_reference_ids, {as: :some_class, list: true}) }
121
+ let(:id1) { double('id1') }
122
+ let(:id2) { double('id2') }
123
+ let(:id3) { double('id3') }
124
+
125
+ before(:each) do
126
+ decorated.stub(:some_reference_ids).and_return([id1, id2, id3])
127
+ end
128
+
129
+ it 'should return nil when persister has something for every id' do
130
+ persister.stub(:exists?).and_return(true, true, true)
131
+ subject.valid?(decorated)
132
+
133
+ subject.error_message(decorated).should be nil
134
+ end
135
+
136
+ it 'should return an error when persister has nothing for an id' do
137
+ persister.stub(:exists?).and_return(false, false, false)
138
+ subject.valid?(decorated)
139
+
140
+ subject.error_message(decorated).should == "Those some_classes (ids: #{[id1, id2, id3].join(", ")}) do not exist."
141
+ end
142
+
143
+ it 'should return include only the failed when persister has nothing for an id' do
144
+ persister.stub(:exists?).and_return(true, false, false)
145
+ subject.valid?(decorated)
146
+
147
+ subject.error_message(decorated).should == "Those some_classes (ids: #{[id2, id3].join(", ")}) do not exist."
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,175 @@
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 'dirt/bdd/persister_spec_helper'
25
+ require './spec/isolations/spec_helper'
26
+
27
+ module Dirt
28
+ describe MemoryPersister do
29
+ let(:type) { :test }
30
+ subject do
31
+ MemoryPersister.new(:Mock) do |*args|
32
+ double('Persisting', *args)
33
+ end
34
+ end
35
+
36
+ it_behaves_like(:persister) do
37
+ let(:persisted) { double('persisted object', attr1: 5, to_hash: {attr1: 5}) }
38
+ let(:persisted2) { double('persisted object 2', attr1: 5, to_hash: {attr1: 5}) }
39
+ let(:different_persisted) { double('different persisted object', attr1: 28, to_hash: {attr1: 28}) }
40
+
41
+ let(:where_params) { {attr1: 5} }
42
+ end
43
+
44
+ describe '#new' do
45
+ it 'should explode when not given a block' do
46
+ expect { MemoryPersister.new(:some_type).new }.to raise_error(RuntimeError, 'Cannot create a new instance without a block given to init.')
47
+ end
48
+
49
+ it 'should return an object' do
50
+ subject.new.should_not be_nil
51
+ end
52
+
53
+ context 'called with args' do
54
+ it 'should populate the new object with args data' do
55
+ subject.new(arg1: 'val1').arg1.should == 'val1'
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#save' do
61
+ let(:data) { double('data', to_hash: {some: 'data'}) }
62
+
63
+ it 'should return the id + data as struct on success' do
64
+ result = subject.save(data)
65
+
66
+ result.should == OpenStruct.new(data.to_hash.merge(id: result.id))
67
+ end
68
+
69
+ it 'should remember the data by the given id' do
70
+ id = 3
71
+
72
+ fake1 = double('other data', to_hash: {})
73
+ fake2 = double('another data', to_hash: {})
74
+
75
+ subject.save(fake1)
76
+ subject.save(fake2)
77
+ subject.save(double('replaced', to_hash: {}))
78
+ subject.save(data, id)
79
+
80
+ subject.instance_variable_get(:@records).should == {1 => fake1, 2 => fake2, id => data}
81
+ end
82
+
83
+ it 'should remember the data by a made up id when none given' do
84
+ subject.save(data, nil)
85
+
86
+ subject.instance_variable_get(:@records).should == {1 => data}
87
+ end
88
+ end
89
+
90
+ describe '#load' do
91
+ let(:data) { double('data', to_hash: {some: 'data'}) }
92
+
93
+ it 'should return only the appropriate id and data' do
94
+ id = double('id')
95
+
96
+ subject.instance_variable_set(:@records, {id => data, double('id2') => double('data2')})
97
+
98
+ subject.load(id).should == OpenStruct.new(data.to_hash.merge(id: id))
99
+ end
100
+ end
101
+
102
+ describe '#exists?' do
103
+ it 'should return only the appropriate id and data' do
104
+ id = double('id')
105
+ data = double('data')
106
+
107
+ subject.instance_variable_set(:@records, {id => data})
108
+
109
+ subject.exists?(id).should be true
110
+ end
111
+
112
+ it 'should raise exception when given an invalid id' do
113
+ id = double('id3')
114
+
115
+ subject.instance_variable_set(:@records, {double('id') => double('data'), double('id2') => double('data2')})
116
+
117
+ subject.exists?(id).should be false
118
+ end
119
+ end
120
+
121
+ describe '#all' do
122
+ it 'should return all of the appropriate id and data' do
123
+ records = {double('id1') => double('data1', to_hash: {attr1: double}),
124
+ double('id2') => double('data2', to_hash: {attr1: double}),
125
+ double('id3') => double('data3', to_hash: {attr1: double})}
126
+
127
+ subject.instance_variable_set(:@records, records)
128
+
129
+ subject.all.should == records.collect { |id, r| OpenStruct.new(r.to_hash.merge(id: id)) }
130
+ end
131
+ end
132
+
133
+ describe '#delete' do
134
+ let(:data) { double('data', to_hash: {some: 'data'}) }
135
+
136
+ it 'should return the deleted id and data as a struct' do
137
+ id = double('id')
138
+
139
+ subject.instance_variable_set(:@records, {id => data})
140
+
141
+ subject.delete(id).should == OpenStruct.new(data.to_hash.merge(id: id))
142
+ end
143
+
144
+ it 'should delete the given id and data' do
145
+ id = double('id')
146
+
147
+ subject.instance_variable_set(:@records, {id => data})
148
+
149
+ subject.delete(id)
150
+
151
+ subject.instance_variable_get(:@records).should == {}
152
+ end
153
+
154
+ it 'should delete only the appropriate id and data' do
155
+ id1 = double('id1')
156
+ id2 = double('id2')
157
+ data2 = double('data2')
158
+
159
+ subject.instance_variable_set(:@records, {id1 => data, id2 => data2})
160
+
161
+ subject.delete(id1)
162
+
163
+ subject.instance_variable_get(:@records).should == {id2 => data2}
164
+ end
165
+
166
+ it 'should return nil when given an invalid id' do
167
+ id = double('id3')
168
+
169
+ subject.instance_variable_set(:@records, {double('id') => double('data'), double('id2') => double('data2')})
170
+
171
+ subject.delete(id).should == nil
172
+ end
173
+ end
174
+ end
175
+ end