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