simple-navigation 4.4.1 → 4.5.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 +4 -4
- data/.github/workflows/ci.yml +84 -0
- data/.rspec +1 -2
- data/.rubocop.yml +49 -0
- data/.rubocop_todo.yml +38 -0
- data/Appraisals +55 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +21 -0
- data/Guardfile +4 -2
- data/README.md +11 -23
- data/Rakefile +2 -27
- data/bin/_guard-core +16 -0
- data/bin/appraisal +16 -0
- data/bin/guard +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/bin/rubocop +16 -0
- data/gemfiles/rails_6.1.gemfile +35 -0
- data/gemfiles/rails_7.0.gemfile +23 -0
- data/gemfiles/rails_7.1.gemfile +23 -0
- data/gemfiles/rails_7.2.gemfile +23 -0
- data/gemfiles/rails_8.0.gemfile +23 -0
- data/gemfiles/rails_8.1.gemfile +23 -0
- data/generators/navigation_config/navigation_config_generator.rb +2 -0
- data/generators/navigation_config/templates/config/navigation.rb +30 -26
- data/lib/generators/navigation_config/navigation_config_generator.rb +2 -0
- data/lib/simple-navigation.rb +3 -1
- data/lib/simple_navigation/adapters/base.rb +2 -0
- data/lib/simple_navigation/adapters/nanoc.rb +8 -3
- data/lib/simple_navigation/adapters/padrino.rb +3 -1
- data/lib/simple_navigation/adapters/rails.rb +12 -14
- data/lib/simple_navigation/adapters/sinatra.rb +4 -6
- data/lib/simple_navigation/config_file.rb +1 -1
- data/lib/simple_navigation/config_file_finder.rb +3 -3
- data/lib/simple_navigation/configuration.rb +5 -5
- data/lib/simple_navigation/helpers.rb +9 -11
- data/lib/simple_navigation/item.rb +26 -20
- data/lib/simple_navigation/item_adapter.rb +16 -5
- data/lib/simple_navigation/item_container.rb +13 -7
- data/lib/simple_navigation/items_provider.rb +6 -4
- data/lib/simple_navigation/railtie.rb +3 -1
- data/lib/simple_navigation/renderer/base.rb +5 -5
- data/lib/simple_navigation/renderer/breadcrumbs.rb +4 -3
- data/lib/simple_navigation/renderer/json.rb +1 -1
- data/lib/simple_navigation/renderer/links.rb +2 -0
- data/lib/simple_navigation/renderer/list.rb +5 -5
- data/lib/simple_navigation/renderer/text.rb +3 -1
- data/lib/simple_navigation/version.rb +3 -1
- data/lib/simple_navigation.rb +32 -24
- data/simple-navigation.gemspec +16 -27
- data/spec/fake_app/config/navigation.rb +4 -2
- data/spec/fake_app/rails_app.rb +5 -3
- data/spec/integration/rendering_navigation_spec.rb +7 -5
- data/spec/simple_navigation/adapters/nanoc_spec.rb +97 -0
- data/spec/simple_navigation/adapters/padrino_spec.rb +41 -22
- data/spec/simple_navigation/adapters/rails_spec.rb +199 -206
- data/spec/simple_navigation/adapters/sinatra_spec.rb +21 -5
- data/spec/simple_navigation/config_file_finder_spec.rb +32 -28
- data/spec/simple_navigation/config_file_spec.rb +14 -14
- data/spec/simple_navigation/configuration_spec.rb +128 -121
- data/spec/simple_navigation/helpers_spec.rb +282 -284
- data/spec/simple_navigation/item_adapter_spec.rb +109 -122
- data/spec/simple_navigation/item_container_spec.rb +407 -408
- data/spec/simple_navigation/item_spec.rb +333 -301
- data/spec/simple_navigation/items_provider_spec.rb +30 -27
- data/spec/simple_navigation/renderer/base_spec.rb +166 -168
- data/spec/simple_navigation/renderer/breadcrumbs_spec.rb +81 -83
- data/spec/simple_navigation/renderer/json_spec.rb +49 -56
- data/spec/simple_navigation/renderer/links_spec.rb +81 -83
- data/spec/simple_navigation/renderer/list_spec.rb +111 -91
- data/spec/simple_navigation/renderer/text_spec.rb +37 -39
- data/spec/simple_navigation_spec.rb +54 -47
- data/spec/spec_helper.rb +146 -53
- metadata +25 -164
- data/.travis.yml +0 -23
- data/gemfiles/rails-3-2-stable.gemfile +0 -11
- data/gemfiles/rails-4-1-stable.gemfile +0 -7
- data/gemfiles/rails-4-2-stable.gemfile +0 -7
- data/gemfiles/rails-5-2-stable.gemfile +0 -7
- data/gemfiles/rails-6-0-stable.gemfile +0 -9
- data/gemfiles/rails-6-1-stable.gemfile +0 -9
- data/init.rb +0 -1
- data/install.rb +0 -5
- data/lib/simple_navigation/adapters.rb +0 -10
- data/lib/simple_navigation/renderer.rb +0 -12
- data/spec/initializers/coveralls.rb +0 -3
- data/spec/initializers/have_css_matcher.rb +0 -19
- data/spec/initializers/memfs.rb +0 -7
- data/spec/initializers/rails.rb +0 -4
- data/spec/initializers/rspec.rb +0 -7
- data/uninstall.rb +0 -1
|
@@ -1,599 +1,598 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe SimpleNavigation::ItemContainer do
|
|
4
|
+
subject(:item_container) { described_class.new }
|
|
5
|
+
|
|
6
|
+
shared_examples 'adding the item to the list' do
|
|
7
|
+
it 'adds the item to the list' do
|
|
8
|
+
allow(SimpleNavigation::Item).to receive_messages(new: item)
|
|
9
|
+
item_container.item(*args)
|
|
10
|
+
expect(item_container.items).to include(item)
|
|
11
11
|
end
|
|
12
|
+
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
14
|
+
shared_examples 'not adding the item to the list' do
|
|
15
|
+
it "doesn't add the item to the list" do
|
|
16
|
+
allow(SimpleNavigation::Item).to receive_messages(new: item)
|
|
17
|
+
item_container.item(*args)
|
|
18
|
+
expect(item_container.items).not_to include(item)
|
|
19
19
|
end
|
|
20
|
+
end
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
22
|
+
describe '#initialize' do
|
|
23
|
+
it 'sets an empty items array' do
|
|
24
|
+
expect(item_container.items).to be_empty
|
|
25
25
|
end
|
|
26
|
+
end
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
describe '#dom_attributes' do
|
|
29
|
+
let(:dom_attributes) { { id: 'test_id', class: 'test_class' } }
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
before { item_container.dom_attributes = dom_attributes }
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
it "returns the container's dom_attributes" do
|
|
34
|
+
expect(item_container.dom_attributes).to eq dom_attributes
|
|
35
|
+
end
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
context 'when the dom_attributes do not contain any id or class' do
|
|
38
|
+
let(:dom_attributes) { { test: 'test' } }
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
end
|
|
40
|
+
context "when the container hasn't any dom_id" do
|
|
41
|
+
it "returns the contaier's dom_attributes without any id" do
|
|
42
|
+
expect(item_container.dom_attributes).not_to include(:id)
|
|
43
43
|
end
|
|
44
|
+
end
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
context 'when the container has a dom_id' do
|
|
47
|
+
before { item_container.dom_id = 'test_id' }
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
49
|
+
it "returns the contaier's dom_attributes including the #dom_id" do
|
|
50
|
+
expect(item_container.dom_attributes).to include(id: 'test_id')
|
|
51
51
|
end
|
|
52
|
+
end
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
54
|
+
context "when the container hasn't any dom_class" do
|
|
55
|
+
it "returns the contaier's dom_attributes without any class" do
|
|
56
|
+
expect(item_container.dom_attributes).not_to include(:class)
|
|
57
57
|
end
|
|
58
|
+
end
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
context 'when the container has a dom_class' do
|
|
61
|
+
before { item_container.dom_class = 'test_class' }
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
63
|
+
it "returns the contaier's dom_attributes including the #dom_class" do
|
|
64
|
+
expect(item_container.dom_attributes).to include(class: 'test_class')
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
|
+
end
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
describe '#items=' do
|
|
71
|
+
let(:item) { { key: :my_key, name: 'test', url: '/' } }
|
|
72
|
+
let(:items) { [item] }
|
|
73
|
+
let(:item_adapter) { double(:item_adapter).as_null_object }
|
|
74
|
+
let(:real_item) { double(:real_item) }
|
|
75
|
+
|
|
76
|
+
before do
|
|
77
|
+
allow(SimpleNavigation::ItemAdapter).to receive_messages(new: item_adapter)
|
|
78
|
+
allow(item_adapter).to receive(:to_simple_navigation_item)
|
|
79
|
+
.with(item_container)
|
|
80
|
+
.and_return(real_item)
|
|
81
|
+
end
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
context 'when the item should be added' do
|
|
84
|
+
before { allow(item_container).to receive_messages(should_add_item?: true) }
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
end
|
|
86
|
+
it 'converts it to an Item and adds it to the items collection' do
|
|
87
|
+
item_container.items = items
|
|
88
|
+
expect(item_container.items).to include(real_item)
|
|
89
89
|
end
|
|
90
|
+
end
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
context 'when the item should not be added' do
|
|
93
|
+
before { allow(item_container).to receive_messages(should_add_item?: false) }
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
end
|
|
95
|
+
it "doesn't add it to the items collection" do
|
|
96
|
+
item_container.items = items
|
|
97
|
+
expect(item_container.items).not_to include(real_item)
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
|
+
end
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
describe '#selected?' do
|
|
103
|
+
let(:first_item) { double(:item, selected?: false) }
|
|
104
|
+
let(:second_item) { double(:item, selected?: false) }
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
before do
|
|
107
|
+
item_container.instance_variable_set(:@items, [first_item, second_item])
|
|
108
|
+
end
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
end
|
|
110
|
+
context 'when no item is selected' do
|
|
111
|
+
it 'returns nil' do
|
|
112
|
+
expect(item_container).not_to be_selected
|
|
113
113
|
end
|
|
114
|
+
end
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
end
|
|
116
|
+
context 'when an item is selected' do
|
|
117
|
+
it 'returns true' do
|
|
118
|
+
allow(first_item).to receive_messages(selected?: true)
|
|
119
|
+
expect(item_container).to be_selected
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
|
+
end
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
describe '#selected_item' do
|
|
125
|
+
let(:first_item) { double(:item, selected?: false) }
|
|
126
|
+
let(:second_item) { double(:item, selected?: false) }
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
before do
|
|
129
|
+
allow(SimpleNavigation).to receive_messages(current_navigation_for: :nav)
|
|
130
|
+
allow(item_container).to receive_messages(:[] => nil)
|
|
131
|
+
item_container.instance_variable_set(:@items, [first_item, second_item])
|
|
132
|
+
end
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
end
|
|
134
|
+
context "when navigation isn't explicitely set" do
|
|
135
|
+
context 'when no item is selected' do
|
|
136
|
+
it 'returns nil' do
|
|
137
|
+
expect(item_container.selected_item).to be_nil
|
|
138
138
|
end
|
|
139
|
+
end
|
|
139
140
|
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
context 'when an item is selected' do
|
|
142
|
+
before { allow(first_item).to receive_messages(selected?: true) }
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
end
|
|
144
|
+
it 'returns the selected item' do
|
|
145
|
+
expect(item_container.selected_item).to be first_item
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
end
|
|
149
|
+
end
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
end
|
|
151
|
+
describe '#active_item_container_for' do
|
|
152
|
+
context "when the desired level is the same as the container's" do
|
|
153
|
+
it 'returns the container itself' do
|
|
154
|
+
expect(item_container.active_item_container_for(1)).to be item_container
|
|
155
155
|
end
|
|
156
|
+
end
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
it 'returns nil' do
|
|
162
|
-
expect(item_container.active_item_container_for(2)).to be_nil
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
context 'and a subnavigation is selected' do
|
|
167
|
-
let(:sub_navigation) { double(:sub_navigation) }
|
|
168
|
-
let(:selected_item) { double(:selected_item) }
|
|
169
|
-
|
|
170
|
-
before do
|
|
171
|
-
allow(item_container).to \
|
|
172
|
-
receive_messages(selected_sub_navigation?: true, selected_item: selected_item)
|
|
173
|
-
allow(selected_item).to receive_messages(sub_navigation: sub_navigation)
|
|
174
|
-
end
|
|
158
|
+
context "when the desired level is different than the container's" do
|
|
159
|
+
context 'when no subnavigation is selected' do
|
|
160
|
+
before { allow(item_container).to receive_messages(selected_sub_navigation?: false) }
|
|
175
161
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
.with(2)
|
|
179
|
-
item_container.active_item_container_for(2)
|
|
180
|
-
end
|
|
162
|
+
it 'returns nil' do
|
|
163
|
+
expect(item_container.active_item_container_for(2)).to be_nil
|
|
181
164
|
end
|
|
182
165
|
end
|
|
183
|
-
end
|
|
184
166
|
|
|
185
|
-
|
|
186
|
-
context 'when the current container has a selected subnavigation' do
|
|
167
|
+
context 'when a subnavigation is selected' do
|
|
187
168
|
let(:sub_navigation) { double(:sub_navigation) }
|
|
188
169
|
let(:selected_item) { double(:selected_item) }
|
|
189
170
|
|
|
190
171
|
before do
|
|
191
|
-
allow(item_container).to
|
|
192
|
-
|
|
172
|
+
allow(item_container).to \
|
|
173
|
+
receive_messages(selected_sub_navigation?: true, selected_item: selected_item)
|
|
193
174
|
allow(selected_item).to receive_messages(sub_navigation: sub_navigation)
|
|
194
175
|
end
|
|
195
176
|
|
|
196
177
|
it 'calls recursively on the sub_navigation' do
|
|
197
|
-
expect(sub_navigation).to receive(:
|
|
198
|
-
|
|
178
|
+
expect(sub_navigation).to receive(:active_item_container_for)
|
|
179
|
+
.with(2)
|
|
180
|
+
item_container.active_item_container_for(2)
|
|
199
181
|
end
|
|
200
182
|
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
201
185
|
|
|
202
|
-
|
|
203
|
-
|
|
186
|
+
describe '#active_leaf_container' do
|
|
187
|
+
context 'when the current container has a selected subnavigation' do
|
|
188
|
+
let(:sub_navigation) { double(:sub_navigation) }
|
|
189
|
+
let(:selected_item) { double(:selected_item) }
|
|
204
190
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
191
|
+
before do
|
|
192
|
+
allow(item_container).to receive_messages(selected_sub_navigation?: true,
|
|
193
|
+
selected_item: selected_item)
|
|
194
|
+
allow(selected_item).to receive_messages(sub_navigation: sub_navigation)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'calls recursively on the sub_navigation' do
|
|
198
|
+
expect(sub_navigation).to receive(:active_leaf_container)
|
|
199
|
+
item_container.active_leaf_container
|
|
208
200
|
end
|
|
209
201
|
end
|
|
210
202
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
let(:item) { double(:item) }
|
|
203
|
+
context 'when the current container is the leaf already' do
|
|
204
|
+
before { allow(item_container).to receive_messages(selected_sub_navigation?: false) }
|
|
214
205
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
206
|
+
it 'returns itsself' do
|
|
207
|
+
expect(item_container.active_leaf_container).to be item_container
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
218
211
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
212
|
+
describe '#item' do
|
|
213
|
+
let(:options) { {} }
|
|
214
|
+
let(:item) { double(:item) }
|
|
222
215
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
end
|
|
216
|
+
context 'when a block is given' do
|
|
217
|
+
let(:block) { proc {} }
|
|
218
|
+
let(:sub_container) { double(:sub_container) }
|
|
227
219
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
.with(item_container, 'key', 'name', 'url', options, &block)
|
|
231
|
-
.and_return(item)
|
|
232
|
-
item_container.item('key', 'name', 'url', options, &block)
|
|
233
|
-
expect(item_container.items).to include(item)
|
|
234
|
-
end
|
|
220
|
+
it 'yields a new ItemContainer' do
|
|
221
|
+
allow_any_instance_of(SimpleNavigation::Item).to receive_messages(sub_navigation: sub_container) # rubocop:disable RSpec/AnyInstance
|
|
235
222
|
|
|
236
|
-
|
|
237
|
-
item_container.item('key', 'name', 'url', options)
|
|
238
|
-
|
|
239
|
-
end
|
|
223
|
+
expect do |blk|
|
|
224
|
+
item_container.item('key', 'name', 'url', options, &blk)
|
|
225
|
+
end.to yield_with_args(sub_container)
|
|
240
226
|
end
|
|
241
227
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
228
|
+
it 'creates a new Item with the given params and block' do
|
|
229
|
+
allow(SimpleNavigation::Item).to receive(:new)
|
|
230
|
+
.with(item_container, 'key', 'name', 'url', options, &block)
|
|
231
|
+
.and_return(item)
|
|
232
|
+
item_container.item('key', 'name', 'url', options, &block)
|
|
233
|
+
expect(item_container.items).to include(item)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it 'adds the created item to the list of items' do
|
|
237
|
+
item_container.item('key', 'name', 'url', options) {} # rubocop:disable Lint/EmptyBlock
|
|
238
|
+
expect(item_container.items).not_to include(item)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context 'when no block is given' do
|
|
243
|
+
it 'creates a new Item with the given params and no sub navigation' do
|
|
244
|
+
allow(SimpleNavigation::Item).to receive(:new)
|
|
245
|
+
.with(item_container, 'key', 'name', 'url', options)
|
|
246
|
+
.and_return(item)
|
|
247
|
+
item_container.item('key', 'name', 'url', options)
|
|
248
|
+
expect(item_container.items).to include(item)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it 'adds the created item to the list of items' do
|
|
252
|
+
allow(SimpleNavigation::Item).to receive_messages(new: item)
|
|
253
|
+
item_container.item('key', 'name', 'url', options) {} # rubocop:disable Lint/EmptyBlock
|
|
254
|
+
expect(item_container.items).to include(item)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
250
257
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
258
|
+
describe 'Optional url and optional options' do
|
|
259
|
+
context 'when item specifed without url or options' do
|
|
260
|
+
it_behaves_like 'adding the item to the list' do
|
|
261
|
+
let(:args) { %w[key name] }
|
|
255
262
|
end
|
|
256
263
|
end
|
|
257
264
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
let(:args) { ['key', 'name'] }
|
|
262
|
-
end
|
|
265
|
+
context 'when item is specified with only a url' do
|
|
266
|
+
it_behaves_like 'adding the item to the list' do
|
|
267
|
+
let(:args) { %w[key name url] }
|
|
263
268
|
end
|
|
269
|
+
end
|
|
264
270
|
|
|
265
|
-
|
|
271
|
+
context 'when item is specified with only options' do
|
|
272
|
+
context 'when options do not contain any condition' do
|
|
266
273
|
it_behaves_like 'adding the item to the list' do
|
|
267
|
-
let(:args) { ['key', 'name',
|
|
274
|
+
let(:args) { ['key', 'name', { option: true }] }
|
|
268
275
|
end
|
|
269
276
|
end
|
|
270
277
|
|
|
271
|
-
context 'when
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
let(:args) { ['key', 'name', { option: true }] }
|
|
275
|
-
end
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
context 'and options contains a negative condition' do
|
|
279
|
-
it_behaves_like 'not adding the item to the list' do
|
|
280
|
-
let(:args) { ['key', 'name', nil, { if: ->{ false }, option: true }] }
|
|
281
|
-
end
|
|
278
|
+
context 'when options contains a negative condition' do
|
|
279
|
+
it_behaves_like 'not adding the item to the list' do
|
|
280
|
+
let(:args) { ['key', 'name', nil, { if: -> { false }, option: true }] }
|
|
282
281
|
end
|
|
282
|
+
end
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
end
|
|
284
|
+
context 'when options contains a positive condition' do
|
|
285
|
+
it_behaves_like 'adding the item to the list' do
|
|
286
|
+
let(:args) { ['key', 'name', nil, { if: -> { true }, option: true }] }
|
|
288
287
|
end
|
|
289
288
|
end
|
|
289
|
+
end
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
end
|
|
291
|
+
context 'when item is specified with a url and options' do
|
|
292
|
+
context 'when options do not contain any condition' do
|
|
293
|
+
it_behaves_like 'adding the item to the list' do
|
|
294
|
+
let(:args) { ['key', 'name', 'url', { option: true }] }
|
|
296
295
|
end
|
|
296
|
+
end
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
end
|
|
298
|
+
context 'when options contains a negative condition' do
|
|
299
|
+
it_behaves_like 'not adding the item to the list' do
|
|
300
|
+
let(:args) { ['key', 'name', 'url', { if: -> { false }, option: true }] }
|
|
302
301
|
end
|
|
302
|
+
end
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
end
|
|
304
|
+
context 'when options contains a positive condition' do
|
|
305
|
+
it_behaves_like 'adding the item to the list' do
|
|
306
|
+
let(:args) { ['key', 'name', 'url', { if: -> { true }, option: true }] }
|
|
308
307
|
end
|
|
309
308
|
end
|
|
309
|
+
end
|
|
310
310
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
context 'when a frozen options hash is given' do
|
|
312
|
+
let(:options) do
|
|
313
|
+
{ html: { id: 'test' } }.freeze
|
|
314
|
+
end
|
|
315
315
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
end
|
|
316
|
+
it 'does not raise an exception' do
|
|
317
|
+
expect do
|
|
318
|
+
item_container.item('key', 'name', 'url', options)
|
|
319
|
+
end.not_to raise_error
|
|
321
320
|
end
|
|
321
|
+
end
|
|
322
322
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
323
|
+
describe 'container options' do
|
|
324
|
+
before do
|
|
325
|
+
allow(item_container).to receive_messages(should_add_item?: add_item)
|
|
326
|
+
item_container.item :key, 'name', 'url', options
|
|
327
|
+
end
|
|
328
328
|
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
context 'when the container :id option is specified' do
|
|
330
|
+
let(:options) { { container: { id: 'c_id' } } }
|
|
331
331
|
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
context 'when the item should be added' do
|
|
333
|
+
let(:add_item) { true }
|
|
334
334
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
end
|
|
335
|
+
it 'changes its dom_id' do
|
|
336
|
+
expect(item_container.dom_id).to eq 'c_id'
|
|
338
337
|
end
|
|
338
|
+
end
|
|
339
339
|
|
|
340
|
-
|
|
341
|
-
|
|
340
|
+
context "when the item shouldn't be added" do
|
|
341
|
+
let(:add_item) { false }
|
|
342
342
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
end
|
|
343
|
+
it "doesn't change its dom_id" do
|
|
344
|
+
expect(item_container.dom_id).to be_nil
|
|
346
345
|
end
|
|
347
346
|
end
|
|
347
|
+
end
|
|
348
348
|
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
context 'when the container :class option is specified' do
|
|
350
|
+
let(:options) { { container: { class: 'c_class' } } }
|
|
351
351
|
|
|
352
|
-
|
|
353
|
-
|
|
352
|
+
context 'when the item should be added' do
|
|
353
|
+
let(:add_item) { true }
|
|
354
354
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
end
|
|
355
|
+
it 'changes its dom_class' do
|
|
356
|
+
expect(item_container.dom_class).to eq 'c_class'
|
|
358
357
|
end
|
|
358
|
+
end
|
|
359
359
|
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
context "when the item shouldn't be added" do
|
|
361
|
+
let(:add_item) { false }
|
|
362
362
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
end
|
|
363
|
+
it "doesn't change its dom_class" do
|
|
364
|
+
expect(item_container.dom_class).to be_nil
|
|
366
365
|
end
|
|
367
366
|
end
|
|
367
|
+
end
|
|
368
368
|
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
context 'when the container :attributes option is specified' do
|
|
370
|
+
let(:options) { { container: { attributes: { option: true } } } }
|
|
371
371
|
|
|
372
|
-
|
|
373
|
-
|
|
372
|
+
context 'when the item should be added' do
|
|
373
|
+
let(:add_item) { true }
|
|
374
374
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
end
|
|
375
|
+
it 'changes its dom_attributes' do
|
|
376
|
+
expect(item_container.dom_attributes).to eq(option: true)
|
|
378
377
|
end
|
|
378
|
+
end
|
|
379
379
|
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
context "when the item shouldn't be added" do
|
|
381
|
+
let(:add_item) { false }
|
|
382
382
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
end
|
|
383
|
+
it "doesn't change its dom_attributes" do
|
|
384
|
+
expect(item_container.dom_attributes).to eq({})
|
|
386
385
|
end
|
|
387
386
|
end
|
|
387
|
+
end
|
|
388
388
|
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
context 'when the container :selected_class option is specified' do
|
|
390
|
+
let(:options) { { container: { selected_class: 'sel_class' } } }
|
|
391
391
|
|
|
392
|
-
|
|
393
|
-
|
|
392
|
+
context 'when the item should be added' do
|
|
393
|
+
let(:add_item) { true }
|
|
394
394
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
end
|
|
395
|
+
it 'changes its selected_class' do
|
|
396
|
+
expect(item_container.selected_class).to eq 'sel_class'
|
|
398
397
|
end
|
|
398
|
+
end
|
|
399
399
|
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
context "when the item shouldn't be added" do
|
|
401
|
+
let(:add_item) { false }
|
|
402
402
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
end
|
|
403
|
+
it "doesn't change its selected_class" do
|
|
404
|
+
expect(item_container.selected_class).to be_nil
|
|
406
405
|
end
|
|
407
406
|
end
|
|
408
407
|
end
|
|
409
408
|
end
|
|
409
|
+
end
|
|
410
410
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
411
|
+
describe 'Conditions' do
|
|
412
|
+
context 'when an :if option is given' do
|
|
413
|
+
let(:options) { { if: proc { condition } } }
|
|
414
|
+
let(:condition) { nil }
|
|
415
415
|
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
context 'when it evals to true' do
|
|
417
|
+
let(:condition) { true }
|
|
418
418
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
end
|
|
419
|
+
it 'creates a new Item' do
|
|
420
|
+
expect(SimpleNavigation::Item).to receive(:new)
|
|
421
|
+
item_container.item('key', 'name', 'url', options)
|
|
423
422
|
end
|
|
423
|
+
end
|
|
424
424
|
|
|
425
|
-
|
|
426
|
-
|
|
425
|
+
context 'when it evals to false' do
|
|
426
|
+
let(:condition) { false }
|
|
427
427
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
end
|
|
428
|
+
it "doesn't create a new Item" do
|
|
429
|
+
expect(SimpleNavigation::Item).not_to receive(:new)
|
|
430
|
+
item_container.item('key', 'name', 'url', options)
|
|
432
431
|
end
|
|
432
|
+
end
|
|
433
433
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
end
|
|
434
|
+
context 'when it is not a proc or a method' do
|
|
435
|
+
it 'raises an error' do
|
|
436
|
+
expect do
|
|
437
|
+
item_container.item('key', 'name', 'url', { if: 'text' })
|
|
438
|
+
end.to raise_error(ArgumentError, ':if or :unless must be procs or lambdas')
|
|
440
439
|
end
|
|
441
440
|
end
|
|
441
|
+
end
|
|
442
442
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
context 'when an :unless option is given' do
|
|
444
|
+
let(:options) { { unless: proc { condition } } }
|
|
445
|
+
let(:condition) { nil }
|
|
446
446
|
|
|
447
|
-
|
|
448
|
-
|
|
447
|
+
context 'when it evals to false' do
|
|
448
|
+
let(:condition) { false }
|
|
449
449
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
end
|
|
450
|
+
it 'creates a new Navigation-Item' do
|
|
451
|
+
expect(SimpleNavigation::Item).to receive(:new)
|
|
452
|
+
item_container.item('key', 'name', 'url', options)
|
|
454
453
|
end
|
|
454
|
+
end
|
|
455
455
|
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
context 'when it evals to true' do
|
|
457
|
+
let(:condition) { true }
|
|
458
458
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
end
|
|
459
|
+
it "doesn't create a new Navigation-Item" do
|
|
460
|
+
expect(SimpleNavigation::Item).not_to receive(:new)
|
|
461
|
+
item_container.item('key', 'name', 'url', options)
|
|
463
462
|
end
|
|
464
463
|
end
|
|
465
464
|
end
|
|
466
465
|
end
|
|
466
|
+
end
|
|
467
467
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
468
|
+
describe '#[]' do
|
|
469
|
+
before do
|
|
470
|
+
item_container.item(:first, 'first', 'bla')
|
|
471
|
+
item_container.item(:second, 'second', 'bla')
|
|
472
|
+
item_container.item(:third, 'third', 'bla')
|
|
473
|
+
end
|
|
474
474
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
475
|
+
it 'returns the item with the specified navi_key' do
|
|
476
|
+
expect(item_container[:second].name).to eq 'second'
|
|
477
|
+
end
|
|
478
478
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
end
|
|
479
|
+
context 'when no item exists for the specified navi_key' do
|
|
480
|
+
it 'returns nil' do
|
|
481
|
+
expect(item_container[:invalid]).to be_nil
|
|
483
482
|
end
|
|
484
483
|
end
|
|
484
|
+
end
|
|
485
485
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
context 'when renderer is specified as an option' do
|
|
492
|
-
context 'and is specified as a class' do
|
|
493
|
-
it 'instantiates the passed renderer_class with the options' do
|
|
494
|
-
expect(renderer_class).to receive(:new)
|
|
495
|
-
.with(renderer: renderer_class)
|
|
496
|
-
item_container.render(renderer: renderer_class)
|
|
497
|
-
end
|
|
486
|
+
describe '#render' do
|
|
487
|
+
# TODO
|
|
488
|
+
let(:renderer_instance) { double(:renderer).as_null_object }
|
|
489
|
+
let(:renderer_class) { double(:renderer_class, new: renderer_instance) }
|
|
498
490
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
491
|
+
context 'when renderer is specified as an option' do
|
|
492
|
+
context 'when it is specified as a class' do
|
|
493
|
+
it 'instantiates the passed renderer_class with the options' do
|
|
494
|
+
expect(renderer_class).to receive(:new)
|
|
495
|
+
.with({ renderer: renderer_class })
|
|
496
|
+
item_container.render(renderer: renderer_class)
|
|
503
497
|
end
|
|
504
498
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
my_renderer: renderer_class
|
|
509
|
-
}
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
it "instantiates the passed renderer_class with the options" do
|
|
513
|
-
expect(renderer_class).to receive(:new).with(renderer: :my_renderer)
|
|
514
|
-
item_container.render(renderer: :my_renderer)
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
it 'calls render on the renderer and passes self' do
|
|
518
|
-
expect(renderer_instance).to receive(:render).with(item_container)
|
|
519
|
-
item_container.render(renderer: :my_renderer)
|
|
520
|
-
end
|
|
499
|
+
it 'calls render on the renderer and passes self' do
|
|
500
|
+
expect(renderer_instance).to receive(:render).with(item_container)
|
|
501
|
+
item_container.render(renderer: renderer_class)
|
|
521
502
|
end
|
|
522
503
|
end
|
|
523
504
|
|
|
524
|
-
context 'when
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
505
|
+
context 'when it is specified as a symbol' do
|
|
506
|
+
before do
|
|
507
|
+
SimpleNavigation.registered_renderers = {
|
|
508
|
+
my_renderer: renderer_class
|
|
509
|
+
}
|
|
510
|
+
end
|
|
528
511
|
|
|
529
|
-
it
|
|
530
|
-
expect(renderer_class).to receive(:new).with(
|
|
531
|
-
item_container.render(
|
|
512
|
+
it 'instantiates the passed renderer_class with the options' do
|
|
513
|
+
expect(renderer_class).to receive(:new).with({ renderer: :my_renderer })
|
|
514
|
+
item_container.render(renderer: :my_renderer)
|
|
532
515
|
end
|
|
533
516
|
|
|
534
517
|
it 'calls render on the renderer and passes self' do
|
|
535
518
|
expect(renderer_instance).to receive(:render).with(item_container)
|
|
536
|
-
item_container.render(
|
|
519
|
+
item_container.render(renderer: :my_renderer)
|
|
537
520
|
end
|
|
538
521
|
end
|
|
539
522
|
end
|
|
540
523
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
it 'returns globally-configured renderer' do
|
|
544
|
-
expect(item_container.renderer).to be Configuration.instance.renderer
|
|
545
|
-
end
|
|
546
|
-
end
|
|
524
|
+
context 'when no renderer is specified' do
|
|
525
|
+
let(:options) { {} }
|
|
547
526
|
|
|
548
|
-
|
|
549
|
-
let(:renderer) { double(:renderer) }
|
|
527
|
+
before { allow(item_container).to receive_messages(renderer: renderer_class) }
|
|
550
528
|
|
|
551
|
-
|
|
529
|
+
it "instantiates the container's renderer with the options" do
|
|
530
|
+
expect(renderer_class).to receive(:new).with(options)
|
|
531
|
+
item_container.render(options)
|
|
532
|
+
end
|
|
552
533
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
534
|
+
it 'calls render on the renderer and passes self' do
|
|
535
|
+
expect(renderer_instance).to receive(:render).with(item_container)
|
|
536
|
+
item_container.render(options)
|
|
556
537
|
end
|
|
557
538
|
end
|
|
539
|
+
end
|
|
558
540
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
item_container.
|
|
563
|
-
p2.item(:s1, 's1', 's1')
|
|
564
|
-
p2.item(:s2, 's2', 's2') do |s2|
|
|
565
|
-
s2.item(:ss1, 'ss1', 'ss1')
|
|
566
|
-
s2.item(:ss2, 'ss2', 'ss2')
|
|
567
|
-
end
|
|
568
|
-
p2.item(:s3, 's3', 's3')
|
|
569
|
-
end
|
|
570
|
-
item_container.item(:p3, 'p3', 'p3')
|
|
541
|
+
describe '#renderer' do
|
|
542
|
+
context 'when no renderer is set explicitly' do
|
|
543
|
+
it 'returns globally-configured renderer' do
|
|
544
|
+
expect(item_container.renderer).to be SimpleNavigation::Configuration.instance.renderer
|
|
571
545
|
end
|
|
546
|
+
end
|
|
572
547
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
end
|
|
548
|
+
context 'when a renderer is set explicitly' do
|
|
549
|
+
let(:renderer) { double(:renderer) }
|
|
576
550
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
551
|
+
before { item_container.renderer = renderer }
|
|
552
|
+
|
|
553
|
+
it 'returns the specified renderer' do
|
|
554
|
+
expect(item_container.renderer).to be renderer
|
|
555
|
+
end
|
|
582
556
|
end
|
|
557
|
+
end
|
|
583
558
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
559
|
+
describe '#level_for_item' do
|
|
560
|
+
before do
|
|
561
|
+
item_container.item(:p1, 'p1', 'p1')
|
|
562
|
+
item_container.item(:p2, 'p2', 'p2') do |p2|
|
|
563
|
+
p2.item(:s1, 's1', 's1')
|
|
564
|
+
p2.item(:s2, 's2', 's2') do |s2|
|
|
565
|
+
s2.item(:ss1, 'ss1', 'ss1')
|
|
566
|
+
s2.item(:ss2, 'ss2', 'ss2')
|
|
589
567
|
end
|
|
568
|
+
p2.item(:s3, 's3', 's3')
|
|
590
569
|
end
|
|
570
|
+
item_container.item(:p3, 'p3', 'p3')
|
|
571
|
+
end
|
|
591
572
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
573
|
+
shared_examples 'returning the level of an item' do |item, level|
|
|
574
|
+
specify { expect(item_container.level_for_item(item)).to eq level }
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it_behaves_like 'returning the level of an item', :p1, 1
|
|
578
|
+
it_behaves_like 'returning the level of an item', :p3, 1
|
|
579
|
+
it_behaves_like 'returning the level of an item', :s1, 2
|
|
580
|
+
it_behaves_like 'returning the level of an item', :ss1, 3
|
|
581
|
+
it_behaves_like 'returning the level of an item', :x, nil
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
describe '#empty?' do
|
|
585
|
+
context 'when there are no items' do
|
|
586
|
+
it 'returns true' do
|
|
587
|
+
item_container.instance_variable_set(:@items, [])
|
|
588
|
+
expect(item_container).to be_empty
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
context 'when there are some items' do
|
|
593
|
+
it 'returns false' do
|
|
594
|
+
item_container.instance_variable_set(:@items, [double(:item)])
|
|
595
|
+
expect(item_container).not_to be_empty
|
|
597
596
|
end
|
|
598
597
|
end
|
|
599
598
|
end
|