super_stack 0.2.5 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f195f8d4912d140d7a3932c3d24d1a2ed4489452
4
- data.tar.gz: 8eded758dd34c83dd1ded7cbf7209919d372a8ec
3
+ metadata.gz: 54cbe4ddd3ce5e7164c09042f75841a327cd1a1c
4
+ data.tar.gz: a01f72c6e8ab135e13cf12d0f9662e1bfa6c75fc
5
5
  SHA512:
6
- metadata.gz: f6edf0b4ccdabef1b6cddf821f5db017bdb52e306cde0f01e5c88d5f2799b5f8ce40743aa8ecdda4375b24a1095c03519f1415332a345d8cbcede947fcd2c141
7
- data.tar.gz: 75881f18d92264c18dc6f6396ec703fb7a2289cd866f220bb39c013b141024acfed260890eb59c752144218ed9212065fa59cca3dea2d6196f27f2b9f0add0a5
6
+ metadata.gz: 771fcfb537611679e55a5fc36c14755ee276f71f3261190245b9299e54ec1f7fa460676f1e5a80056aa673ae9fcc9e9ab438850dd8a02c88bd3fc3aa4f64a83f
7
+ data.tar.gz: b9a855e2c8e20d9e15181ceb843da436c6b70175f96ed1deb8c0c088a67a65b6024e943e7eb265a96055ec86601195893bb262c13c68a0d81a7f5b1b66a7b64a
data/README.md CHANGED
@@ -63,11 +63,11 @@ the name conflicts with another layer already handled by the manager**.
63
63
  You can notice by the way that it gives a third way to create a layer from a hash, as when adding a hash to a manager,
64
64
  it automatically adds the `SuperStack::LayerWrapper` module to the hash.
65
65
 
66
- Layers can be populated from a file anytime using the `load` method:
66
+ Layers can be populated from a yaml file anytime using the `load` method:
67
67
 
68
68
  ```ruby
69
69
  layer = SuperStack::Layer.new.load 'a_file_somewhere'
70
- # Once loaded you can get the file name used to load the layed anytime
70
+ # Once loaded you can get the file name used to load the layer anytime
71
71
  puts layer.file_name
72
72
  # And you can load or reload the layer
73
73
  layer.has_file? # => true
@@ -89,6 +89,13 @@ manager << layer2
89
89
  manager.reload_layers
90
90
  ```
91
91
 
92
+ Layers can of course be:
93
+ * removed (using the manager's `remove_layer(layer_or_layer_name)` method).
94
+ * Enabled or disabled (using the manager's `disable_layer(layer_or_layer_name)` and `enable_layer(layer_or_layer_name)`
95
+ methods).
96
+
97
+ Of course these methods have an impact on the `write_layer` if applied to it. Check tests (run `rspec -f d`) for
98
+ more info.
92
99
 
93
100
  ### Merge policies
94
101
 
@@ -8,7 +8,8 @@ module SuperStack
8
8
 
9
9
  DEFAULT_LAYER_NAME = 'Unknown layer'
10
10
 
11
- attr_reader :file_name, :priority, :manager
11
+ attr_reader :file_name, :priority, :manager, :disabled
12
+ alias_method :disabled?, :disabled
12
13
 
13
14
  def priority=(priority)
14
15
  raise 'invalid priority' unless priority.is_a? Numeric
@@ -16,14 +16,10 @@ module SuperStack
16
16
  end
17
17
 
18
18
  def write_layer=(layer_or_layer_name)
19
- if layer_or_layer_name.is_a?(String) || layer_or_layer_name.is_a?(Symbol)
20
- layer_name = layer_or_layer_name.to_s
21
- raise 'Invalid write layer' unless layers.keys.include? layer_name
22
- layer_or_layer_name = layers[layer_name]
23
- end
24
- # At that point layer_or_layer_name can only contain a layer object
25
- raise 'Invalid write layer' unless layers.values.include? layer_or_layer_name
26
- @write_layer = layer_or_layer_name
19
+ layer = get_existing_layer layer_or_layer_name, 'Invalid write layer specified'
20
+ raise 'Cannot use a disabled layer as write layer' if layer.disabled?
21
+ @previous_write_layer = nil
22
+ @write_layer = layer
27
23
  end
28
24
 
29
25
  def []=(key,value)
@@ -37,8 +33,12 @@ module SuperStack
37
33
  return layers[0] if layers.count == 1
38
34
  first_layer = layers.shift
39
35
  res = layers.inject(first_layer) do |stack, layer|
40
- policy_to_apply = layer.merge_policy.nil? ? default_merge_policy : layer.merge_policy
41
- policy_to_apply.merge stack, layer
36
+ if layer.disabled?
37
+ stack
38
+ else
39
+ policy_to_apply = layer.merge_policy.nil? ? default_merge_policy : layer.merge_policy
40
+ policy_to_apply.merge stack, layer
41
+ end
42
42
  end
43
43
  if filter.nil?
44
44
  # Trick to return a bare hash
@@ -62,11 +62,35 @@ module SuperStack
62
62
  end
63
63
  set_valid_name_for layer if layers.keys.include? layer.name
64
64
  layer.priority = get_unused_priority if layer.priority.nil?
65
+ raise 'This layer already belongs to a manager' unless layer.manager.nil?
65
66
  layers[layer.name] = layer
66
67
  layer.instance_variable_set :@manager, self
67
68
  layer.managed if layer.respond_to? :managed
68
69
  end
69
70
 
71
+ def remove_layer(layer_or_layer_name)
72
+ layer = get_existing_layer layer_or_layer_name, 'Cannot remove unmanaged layer'
73
+ layer_name = layer.name
74
+ @write_layer = nil if layer == write_layer
75
+ layer.instance_variable_set :@manager, nil
76
+ layers.delete layer_name
77
+ end
78
+
79
+ def disable_layer(layer_or_layer_name)
80
+ layer = get_existing_layer layer_or_layer_name, 'Cannot disable unmanaged layer'
81
+ if layer == write_layer
82
+ @previous_write_layer = write_layer
83
+ @write_layer = nil
84
+ end
85
+ layer.instance_variable_set :@disabled, true
86
+ end
87
+
88
+ def enable_layer(layer_or_layer_name)
89
+ layer = get_existing_layer layer_or_layer_name, 'Cannot enable unmanaged layer'
90
+ layer.instance_variable_set :@disabled, false
91
+ @write_layer = @previous_write_layer if layer == @previous_write_layer
92
+ end
93
+
70
94
  def <<(layer)
71
95
  add_layer layer
72
96
  end
@@ -77,6 +101,15 @@ module SuperStack
77
101
 
78
102
  private
79
103
 
104
+ def get_existing_layer(layer_or_layer_name, error_message)
105
+ layer_name = layer_or_layer_name.to_s if layer_or_layer_name.is_a? Symbol
106
+ layer_name = layer_or_layer_name if layer_or_layer_name.is_a? String
107
+ layer = layers[layer_name] unless layer_name.nil?
108
+ layer = layer_or_layer_name if layer_or_layer_name.class.included_modules.include? SuperStack::LayerWrapper
109
+ raise error_message if layer.nil?
110
+ layer
111
+ end
112
+
80
113
  def get_unused_priority
81
114
  ordered = self.to_a
82
115
  return DEFAULT_PRIORITY_INTERVAL if ordered.empty?
@@ -85,6 +118,7 @@ module SuperStack
85
118
 
86
119
  def set_valid_name_for(layer)
87
120
  name_pattern = /^(?<layer_name>.+) #(?<number>\d+)\s*$/
121
+
88
122
  while layers.keys.include? layer.name
89
123
  layer.name = "#{layer.name} #1" unless layer.name =~ name_pattern
90
124
  layer.name.match(name_pattern) do |md|
@@ -1,3 +1,3 @@
1
1
  module SuperStack
2
- VERSION = '0.2.5'
2
+ VERSION = '0.3.0'
3
3
  end
data/spec/manager_spec.rb CHANGED
@@ -13,6 +13,11 @@ describe SuperStack::Manager do
13
13
  layer
14
14
  }
15
15
  end
16
+ let(:override) {
17
+ override = SuperStack::Layer.new
18
+ override.name = :override
19
+ override
20
+ }
16
21
 
17
22
 
18
23
  it 'should contain layers' do
@@ -71,16 +76,6 @@ describe SuperStack::Manager do
71
76
  expect(subject.layers.keys[1] == "#{SuperStack::Layer::DEFAULT_LAYER_NAME} #2").to be_truthy
72
77
  end
73
78
 
74
- it 'should allow the same layer to be added multiple times, automatically changing names' do
75
- expect {subject.add_layer(layer1) }.not_to raise_error
76
- expect {subject.add_layer(layer1) }.not_to raise_error
77
- expect {subject.add_layer(layer1) }.not_to raise_error
78
- expect(subject.layers.keys.count == 3).to be_truthy
79
- expect(subject.layers.keys[0] == 'layer1').to be_truthy
80
- expect(subject.layers.keys[1] == 'layer1 #2').to be_truthy
81
- expect(subject.layers.keys[2] == 'layer1 #3').to be_truthy
82
- end
83
-
84
79
  it 'should allow to reload all layers at once' do
85
80
  subject.add_layer layer1
86
81
  subject << {bar: :foo}
@@ -95,47 +90,53 @@ describe SuperStack::Manager do
95
90
  expect(subject[:bar] == :foo).to be_truthy
96
91
  end
97
92
 
98
- it 'should be possible to specify a write layer using its name or itself' do
99
- override = SuperStack::Layer.new
100
- override.name = :override
101
- subject << override
102
- subject << layer1
103
- expect {subject.write_layer = :override}.not_to raise_error
104
- expect {subject.write_layer = 'override'}.not_to raise_error
105
- expect {subject.write_layer = override}.not_to raise_error
106
- end
107
-
108
- it 'should not be possible to modify if no write layer has been specified' do
93
+ it 'should not be possible to modify the manager if no write layer has been specified' do
109
94
  subject << layer1
110
95
  subject << layer2
111
96
  expect {subject[:foo] = :bar}.to raise_error
112
97
  end
113
98
 
114
- it 'should push all modifications to the write layer' do
115
- override = SuperStack::Layer.new
116
- override.name = :override
117
- subject << override
118
- subject << layer1
119
- subject.write_layer = override
120
- expect {subject[:foo] = :bar}.not_to raise_error
121
- expect(subject.layers['override'][:foo] == :bar).to be_truthy
122
- expect(subject[:foo] == :bar).to be_truthy
123
- end
99
+ context 'when specifying a write layer' do
124
100
 
101
+ it 'should be possible using its name or itself' do
102
+ subject << override
103
+ subject << layer1
104
+ expect {subject.write_layer = :override}.not_to raise_error
105
+ expect {subject.write_layer = 'override'}.not_to raise_error
106
+ expect {subject.write_layer = override}.not_to raise_error
107
+ end
108
+
109
+ it 'should push all modifications to the write layer' do
110
+ subject << override
111
+ subject << layer1
112
+ subject.write_layer = override
113
+ expect {subject[:foo] = :bar}.not_to raise_error
114
+ expect(subject.layers['override'][:foo] == :bar).to be_truthy
115
+ expect(subject[:foo] == :bar).to be_truthy
116
+ end
117
+
118
+
119
+ it 'should be possible to clear modifications' do
120
+ subject << layer1
121
+ subject << override
122
+ subject.write_layer = override
123
+ subject[:something_modified] = :modified
124
+ expect(subject[:something_modified]).not_to be_nil
125
+ subject.reset
126
+ expect(subject[:something_modified]).to be_nil
127
+ end
128
+
129
+ it 'should not be possible to specify a disabled layer' do
130
+ subject << override
131
+ subject.write_layer = override
132
+ subject.disable_layer override
133
+ expect {subject.write_layer = override}.to raise_error
134
+ end
125
135
 
126
- it 'should be possible to clear modifications' do
127
- subject << layer1
128
- override = SuperStack::Layer.new
129
- override.name = :override
130
- subject << override
131
- subject.write_layer = override
132
- subject[:something_modified] = :modified
133
- expect(subject[:something_modified]).not_to be_nil
134
- subject.reset
135
- expect(subject[:something_modified]).to be_nil
136
136
  end
137
137
 
138
138
 
139
+
139
140
  SuperStack::MergePolicies.list.each do |policy|
140
141
  it "should provide a merged view of the layers according to the merge policy: #{policy}" do
141
142
  subject.add_layer layer1
@@ -164,4 +165,114 @@ describe SuperStack::Manager do
164
165
 
165
166
  end
166
167
 
168
+ context 'when removing a layer' do
169
+
170
+ subject {
171
+ s = SuperStack::Manager.new
172
+ s.add_layer layer1
173
+ s.add_layer layer2
174
+ s.add_layer layer3
175
+ s.add_layer layer4
176
+ s
177
+ }
178
+
179
+
180
+ it 'should not accept an incorrect layer' do
181
+ expect {subject.remove_layer :layer12}.to raise_error
182
+ expect {subject.remove_layer nil}.to raise_error
183
+ end
184
+
185
+ it 'should accept a symbol' do
186
+ expect {subject.remove_layer :layer3}.not_to raise_error
187
+ end
188
+ it 'should accept a string' do
189
+ expect {subject.remove_layer 'layer3'}.not_to raise_error
190
+ end
191
+ it 'should accept a layer itself' do
192
+ expect {subject.remove_layer layer3}.not_to raise_error
193
+ end
194
+ it 'should not manage the layer anymore' do
195
+ subject.remove_layer :layer3
196
+ expect(layer3.manager).to be_nil
197
+ end
198
+
199
+ it 'should remain consistent in terms of merged view' do
200
+ subject.remove_layer :layer3
201
+ expect(subject[:from_layer_3]).to be_nil
202
+ expect(subject[:from_layer_1]).not_to be_nil
203
+ expect(subject[:from_layer_2]).not_to be_nil
204
+ expect(subject[:from_layer_4]).not_to be_nil
205
+ end
206
+
207
+ it 'should remain consistent regarding the write level' do
208
+ subject.write_layer = :layer3
209
+ expect(subject.write_layer == layer3).to be_truthy
210
+ subject[:foo] = :bar
211
+ expect(layer3[:foo] == :bar).to be_truthy
212
+ subject.remove_layer :layer3
213
+ expect(subject[:foo] == :bar).to be_falsey
214
+ expect(subject.write_layer).to be_nil
215
+ end
216
+
217
+ end
218
+
219
+ context 'when disabling a layer' do
220
+
221
+ subject {
222
+ s = SuperStack::Manager.new
223
+ s.add_layer layer1
224
+ s.add_layer layer2
225
+ s.add_layer layer3
226
+ s.add_layer layer4
227
+ s
228
+ }
229
+
230
+ it 'should not been taken in account in the merge' do
231
+ subject.disable_layer :layer3
232
+ expect(subject[:from_layer_3]).to be_nil
233
+ expect(subject[:from_layer_1]).not_to be_nil
234
+ expect(subject[:from_layer_2]).not_to be_nil
235
+ expect(subject[:from_layer_4]).not_to be_nil
236
+ end
237
+
238
+ it 'could be reactivated' do
239
+ subject.disable_layer :layer3
240
+ subject.enable_layer :layer3
241
+ expect(subject[:from_layer_3]).not_to be_nil
242
+ expect(subject[:from_layer_1]).not_to be_nil
243
+ expect(subject[:from_layer_2]).not_to be_nil
244
+ expect(subject[:from_layer_4]).not_to be_nil
245
+ end
246
+
247
+ context 'when enabling/disabling a layer which is the write layer' do
248
+ subject {
249
+ s = SuperStack::Manager.new
250
+ s.add_layer layer1
251
+ s.add_layer layer2
252
+ s.add_layer layer3
253
+ s.add_layer layer4
254
+ s.write_layer = :layer3
255
+ s
256
+ }
257
+ it 'should restore it as the write layer if re-enabled' do
258
+ subject.disable_layer :layer3
259
+ expect(subject.write_layer).to be_nil
260
+ subject.enable_layer :layer3
261
+ expect(subject.write_layer).to be layer3
262
+ expect {subject[:foo] = :bar}.not_to raise_error
263
+ end
264
+
265
+ it 'should not restore it as the write layer if another write layer has been set in between' do
266
+ subject.disable_layer :layer3
267
+ expect(subject.write_layer).to be_nil
268
+ subject.write_layer = :layer2
269
+ subject.enable_layer :layer3
270
+ expect(subject.write_layer).to be layer2
271
+ expect {subject[:foo] = :bar}.not_to raise_error
272
+ end
273
+ end
274
+
275
+
276
+ end
277
+
167
278
  end
data/super_stack.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'pry'
26
26
  spec.add_development_dependency 'rspec', '~> 3.0'
27
27
 
28
- spec.add_dependency 'deep_merge'
28
+ spec.add_dependency 'deep_merge', '~> 1.0'
29
29
 
30
30
 
31
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: super_stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent B.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-24 00:00:00.000000000 Z
11
+ date: 2015-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: deep_merge
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '1.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '1.0'
83
83
  description: The purpose of this gem is to provide a simple way to manage the merge
84
84
  of different hashes (layers) according to priority and several merge policies.
85
85
  email: