simple-navigation 3.14.0 → 4.0.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -2
  5. data/CHANGELOG.md +400 -0
  6. data/Guardfile +4 -2
  7. data/README.md +1 -1
  8. data/gemfiles/.bundle/config +2 -0
  9. data/gemfiles/rails-3-2-stable.gemfile +10 -0
  10. data/gemfiles/rails-4-1-stable.gemfile +6 -0
  11. data/gemfiles/rails-4-2-stable.gemfile +7 -0
  12. data/generators/navigation_config/navigation_config_generator.rb +0 -1
  13. data/generators/navigation_config/templates/config/navigation.rb +18 -15
  14. data/lib/simple_navigation.rb +25 -42
  15. data/lib/simple_navigation/adapters/rails.rb +1 -24
  16. data/lib/simple_navigation/adapters/sinatra.rb +2 -11
  17. data/lib/simple_navigation/config_file.rb +36 -0
  18. data/lib/simple_navigation/config_file_finder.rb +42 -0
  19. data/lib/simple_navigation/{core/configuration.rb → configuration.rb} +7 -1
  20. data/lib/simple_navigation/{rendering/helpers.rb → helpers.rb} +0 -4
  21. data/lib/simple_navigation/{core/item.rb → item.rb} +76 -85
  22. data/lib/simple_navigation/{core/item_adapter.rb → item_adapter.rb} +3 -17
  23. data/lib/simple_navigation/{core/item_container.rb → item_container.rb} +23 -14
  24. data/lib/simple_navigation/{core/items_provider.rb → items_provider.rb} +0 -0
  25. data/lib/simple_navigation/railtie.rb +7 -0
  26. data/lib/simple_navigation/renderer.rb +12 -0
  27. data/lib/simple_navigation/{rendering/renderer → renderer}/base.rb +1 -1
  28. data/lib/simple_navigation/{rendering/renderer → renderer}/breadcrumbs.rb +0 -0
  29. data/lib/simple_navigation/{rendering/renderer → renderer}/json.rb +2 -0
  30. data/lib/simple_navigation/{rendering/renderer → renderer}/links.rb +0 -0
  31. data/lib/simple_navigation/{rendering/renderer → renderer}/list.rb +0 -0
  32. data/lib/simple_navigation/{rendering/renderer → renderer}/text.rb +0 -0
  33. data/lib/simple_navigation/version.rb +1 -1
  34. data/simple-navigation.gemspec +5 -4
  35. data/spec/fake_app/config/navigation.rb +6 -0
  36. data/spec/fake_app/rails_app.rb +35 -0
  37. data/spec/initializers/coveralls.rb +3 -0
  38. data/spec/initializers/have_css_matcher.rb +8 -3
  39. data/spec/initializers/memfs.rb +7 -0
  40. data/spec/initializers/rails.rb +4 -0
  41. data/spec/initializers/rspec.rb +7 -0
  42. data/spec/integration/rendering_navigation_spec.rb +12 -0
  43. data/spec/{lib/simple_navigation → simple_navigation}/adapters/padrino_spec.rb +0 -2
  44. data/spec/{lib/simple_navigation → simple_navigation}/adapters/rails_spec.rb +36 -93
  45. data/spec/{lib/simple_navigation → simple_navigation}/adapters/sinatra_spec.rb +4 -6
  46. data/spec/simple_navigation/config_file_finder_spec.rb +50 -0
  47. data/spec/simple_navigation/config_file_spec.rb +25 -0
  48. data/spec/{lib/simple_navigation/core → simple_navigation}/configuration_spec.rb +29 -19
  49. data/spec/{lib/simple_navigation/rendering → simple_navigation}/helpers_spec.rb +10 -13
  50. data/spec/{lib/simple_navigation/core → simple_navigation}/item_adapter_spec.rb +14 -11
  51. data/spec/{lib/simple_navigation/core → simple_navigation}/item_container_spec.rb +130 -42
  52. data/spec/simple_navigation/item_spec.rb +467 -0
  53. data/spec/{lib/simple_navigation/core → simple_navigation}/items_provider_spec.rb +1 -3
  54. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/base_spec.rb +34 -36
  55. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/breadcrumbs_spec.rb +4 -7
  56. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/json_spec.rb +5 -11
  57. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/links_spec.rb +5 -8
  58. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/list_spec.rb +4 -7
  59. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/text_spec.rb +4 -7
  60. data/spec/simple_navigation_spec.rb +190 -0
  61. data/spec/spec_helper.rb +29 -35
  62. metadata +103 -68
  63. data/CHANGELOG +0 -292
  64. data/lib/simple_navigation/core.rb +0 -5
  65. data/lib/simple_navigation/rails_controller_methods.rb +0 -164
  66. data/lib/simple_navigation/rendering.rb +0 -12
  67. data/rails/init.rb +0 -1
  68. data/spec/lib/simple_navigation/core/item_spec.rb +0 -703
  69. data/spec/lib/simple_navigation/rails_controller_methods_spec.rb +0 -270
  70. data/spec/lib/simple_navigation_spec.rb +0 -300
@@ -0,0 +1,467 @@
1
+ module SimpleNavigation
2
+ describe Item do
3
+ let!(:item_container) { ItemContainer.new }
4
+
5
+ let(:adapter) { double(:adapter) }
6
+ let(:item_args) { [item_container, :my_key, 'name', url, options] }
7
+ let(:item) { Item.new(*item_args) }
8
+ let(:options) { Hash.new }
9
+ let(:url) { 'url' }
10
+
11
+ before { allow(SimpleNavigation).to receive_messages(adapter: adapter) }
12
+
13
+ describe '#highlights_on' do
14
+ let(:options) {{ highlights_on: :test }}
15
+
16
+ it "returns the item's highlights_on option" do
17
+ expect(item.highlights_on).to eq :test
18
+ end
19
+ end
20
+
21
+ describe '#initialize' do
22
+ context 'when there is a sub_navigation' do
23
+ let(:subnav_container) { double(:subnav_container).as_null_object }
24
+
25
+ shared_examples 'creating sub navigation container' do
26
+ it 'creates a sub navigation container with a level+1' do
27
+ expect(item.sub_navigation.level).to eq 2
28
+ end
29
+ end
30
+
31
+ context 'when a block is given' do
32
+ it_behaves_like 'creating sub navigation container' do
33
+ let(:item) { Item.new(*item_args) {} }
34
+ end
35
+
36
+ it 'calls the block' do
37
+ allow(ItemContainer).to receive_messages(new: subnav_container)
38
+
39
+ expect{ |blk|
40
+ Item.new(*item_args, &blk)
41
+ }.to yield_with_args(subnav_container)
42
+ end
43
+ end
44
+
45
+ context 'when no block is given' do
46
+ context 'and items are given' do
47
+ let(:items) { [] }
48
+ let(:options) {{ items: items }}
49
+
50
+ it_behaves_like 'creating sub navigation container'
51
+
52
+ it "sets the items on the subnav_container" do
53
+ expect(item.sub_navigation.items).to eq items
54
+ end
55
+ end
56
+
57
+ context 'and no items are given' do
58
+ it "doesn't create a new ItemContainer" do
59
+ item = Item.new(*item_args)
60
+ expect(item.sub_navigation).to be_nil
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'when a :method option is given' do
67
+ let(:options) {{ method: :delete }}
68
+
69
+ it "sets the item's method" do
70
+ expect(item.method).to eq :delete
71
+ end
72
+ end
73
+
74
+ context 'when no :method option is given' do
75
+ it "sets the item's method to nil" do
76
+ expect(item.method).to be_nil
77
+ end
78
+ end
79
+
80
+ context 'when an :highlights_on option is given' do
81
+ let(:highlights_on) { double(:highlights_on) }
82
+ let(:options) {{ highlights_on: highlights_on }}
83
+
84
+ it "sets the item's highlights_on" do
85
+ expect(item.highlights_on).to eq highlights_on
86
+ end
87
+ end
88
+
89
+ context 'when no :highlights_on option is given' do
90
+ it "sets the item's highlights_on to nil" do
91
+ expect(item.highlights_on).to be_nil
92
+ end
93
+ end
94
+
95
+ context 'when a url is given' do
96
+ context 'and it is a string' do
97
+ it "sets the item's url accordingly" do
98
+ expect(item.url).to eq 'url'
99
+ end
100
+ end
101
+
102
+ context 'and it is a proc' do
103
+ let(:url) { proc{ "my_" + "url" } }
104
+
105
+ it "sets the item's url accordingly" do
106
+ expect(item.url).to eq 'my_url'
107
+ end
108
+ end
109
+
110
+ context 'and it is nil' do
111
+ let(:url) { nil }
112
+
113
+ it "sets the item's url accordingly" do
114
+ expect(item.url).to be_nil
115
+ end
116
+ end
117
+ end
118
+
119
+ context 'when no url nor options is specified' do
120
+ let(:item_args) { [item_container, :my_key, 'name'] }
121
+
122
+ it "sets the item's url to nil" do
123
+ expect(item.url).to be_nil
124
+ end
125
+ end
126
+
127
+ context 'when only a url is given' do
128
+ let(:item_args) { [item_container, :my_key, 'name', 'url'] }
129
+
130
+ it "set the item's url accordingly" do
131
+ expect(item.url).to eq 'url'
132
+ end
133
+ end
134
+
135
+ context 'when url and options are given' do
136
+ let(:options) {{ html: { option: true } }}
137
+
138
+ before { allow(adapter).to receive_messages(current_page?: false) }
139
+
140
+ it "set the item's url accordingly" do
141
+ expect(item.url).to eq 'url'
142
+ end
143
+
144
+ it "sets the item's html_options accordingly" do
145
+ allow(item).to \
146
+ receive_messages(selected_by_subnav?: false,
147
+ selected_by_condition?: false)
148
+ expect(item.html_options).to include(option: true)
149
+ end
150
+ end
151
+ end
152
+
153
+ describe '#link_html_options' do
154
+ let(:options) {{ link_html: :test }}
155
+
156
+ it "returns the item's link_html option" do
157
+ expect(item.link_html_options).to eq :test
158
+ end
159
+ end
160
+
161
+ describe '#method' do
162
+ let(:options) {{ method: :test }}
163
+
164
+ it "returns the item's method option" do
165
+ expect(item.method).to eq :test
166
+ end
167
+ end
168
+
169
+ describe '#name' do
170
+ before do
171
+ allow(SimpleNavigation.config).to \
172
+ receive_messages(name_generator: proc{ |name| "<span>#{name}</span>" })
173
+ end
174
+
175
+ context 'when no option is given' do
176
+ context 'and the name_generator uses only the name' do
177
+ it 'uses the default name_generator' do
178
+ expect(item.name).to eq '<span>name</span>'
179
+ end
180
+ end
181
+
182
+ context 'and the name_generator uses only the item itself' do
183
+ before do
184
+ allow(SimpleNavigation.config).to \
185
+ receive_messages(name_generator: proc{ |name, item| "<span>#{item.key}</span>" })
186
+ end
187
+
188
+ it 'uses the default name_generator' do
189
+ expect(item.name).to eq '<span>my_key</span>'
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'when the :apply_generator is false' do
195
+ it "returns the item's name" do
196
+ expect(item.name(apply_generator: false)).to eq 'name'
197
+ end
198
+ end
199
+
200
+ context 'when a block is given' do
201
+ let(:item_args) { [item_container, :my_key, -> { 'Name in block' }, url, options] }
202
+
203
+ it "returns the item's name that is defined in the block" do
204
+ expect(item.name).to include 'Name in block'
205
+ end
206
+ end
207
+ end
208
+
209
+ describe '#selected?' do
210
+ context 'when the item has no :highlights_on option' do
211
+ before { allow(SimpleNavigation).to receive_messages(config: config) }
212
+
213
+ context 'and auto highlighting is off' do
214
+ let(:config) { double(:config, auto_highlight: false) }
215
+
216
+ it 'returns false' do
217
+ expect(item.selected?).to be false
218
+ end
219
+ end
220
+
221
+ context 'and auto highlighting is on' do
222
+ let(:config) { double(:config, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true, auto_highlight: true) }
223
+
224
+ context "and the current url matches the item's url" do
225
+ before { allow(adapter).to receive_messages(current_page?: true) }
226
+
227
+ it 'returns true' do
228
+ expect(item.selected?).to be true
229
+ end
230
+ end
231
+
232
+ context "and the current url does not match the item's url" do
233
+ let(:config) do
234
+ double(:config, auto_highlight: false, highlight_on_subpath: false)
235
+ end
236
+
237
+ before { allow(adapter).to receive_messages(current_page?: false) }
238
+
239
+ it 'returns false' do
240
+ expect(item.selected?).to be false
241
+ end
242
+ end
243
+
244
+ context 'and highlights_on_subpath is on' do
245
+ let(:config) do
246
+ double(:config, auto_highlight: true, highlight_on_subpath: true, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true)
247
+ end
248
+
249
+ context "and the current url is a sub path of the item's url" do
250
+ before do
251
+ allow(adapter).to \
252
+ receive_messages(current_page?: false, request_uri: 'url/test')
253
+ end
254
+
255
+ it 'returns true' do
256
+ expect(item.selected?).to be true
257
+ end
258
+ end
259
+
260
+ context "and the current url is not a sub path of the item's url" do
261
+ before do
262
+ allow(adapter).to \
263
+ receive_messages(current_page?: false, request_uri: 'other/test')
264
+ end
265
+
266
+ it 'returns false' do
267
+ expect(item.selected?).to be false
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ context 'when the item has a :highlights_on option' do
275
+ context 'and it is a regular expression' do
276
+ before { allow(adapter).to receive_messages(request_uri: '/test') }
277
+
278
+ context 'and the current url matches the expression' do
279
+ let(:options) {{ highlights_on: /test/ }}
280
+
281
+ it 'returns true' do
282
+ expect(item.selected?).to be true
283
+ end
284
+ end
285
+
286
+ context 'and the current url does not match the expression' do
287
+ let(:options) {{ highlights_on: /other/ }}
288
+
289
+ it 'returns false' do
290
+ expect(item.selected?).to be false
291
+ end
292
+ end
293
+ end
294
+
295
+ context 'and it is a callable object' do
296
+ context 'and the call returns true' do
297
+ let(:options) {{ highlights_on: -> { true } }}
298
+
299
+ it 'returns true' do
300
+ expect(item.selected?).to be true
301
+ end
302
+ end
303
+
304
+ context 'and the call returns false' do
305
+ let(:options) {{ highlights_on: -> { false } }}
306
+
307
+ it 'returns false' do
308
+ expect(item.selected?).to be false
309
+ end
310
+ end
311
+ end
312
+
313
+ context 'and it is the :subpath symbol' do
314
+ let(:options) {{ highlights_on: :subpath }}
315
+
316
+ context "and the current url is a sub path of the item's url" do
317
+ before do
318
+ allow(adapter).to receive_messages(request_uri: 'url/test')
319
+ end
320
+
321
+ it 'returns true' do
322
+ expect(item.selected?).to be true
323
+ end
324
+ end
325
+
326
+ context "and the current url is not a sub path of the item's url" do
327
+ before do
328
+ allow(adapter).to receive_messages(request_uri: 'other/test')
329
+ end
330
+
331
+ it 'returns false' do
332
+ expect(item.selected?).to be false
333
+ end
334
+ end
335
+ end
336
+
337
+ context 'and it is non usable' do
338
+ let(:options) {{ highlights_on: :hello }}
339
+
340
+ it 'raises an exception' do
341
+ expect{ item.selected? }.to raise_error
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ describe '#selected_class' do
348
+ context 'when the item is selected' do
349
+ before { allow(item).to receive_messages(selected?: true) }
350
+
351
+ it 'returns the default selected_class' do
352
+ expect(item.selected_class).to eq 'selected'
353
+ end
354
+
355
+ context 'and selected_class is defined in the context' do
356
+ before { allow(item_container).to receive_messages(selected_class: 'defined') }
357
+
358
+ it "returns the context's selected_class" do
359
+ expect(item.selected_class).to eq 'defined'
360
+ end
361
+ end
362
+ end
363
+
364
+ context 'when the item is not selected' do
365
+ before { allow(item).to receive_messages(selected?: false) }
366
+
367
+ it 'returns nil' do
368
+ expect(item.selected_class).to be_nil
369
+ end
370
+ end
371
+ end
372
+
373
+ describe ':html_options argument' do
374
+ let(:selected_classes) { 'selected simple-navigation-active-leaf' }
375
+
376
+ context 'when the :class option is given' do
377
+ let(:options) {{ html: { class: 'my_class' } }}
378
+
379
+ context 'and the item is selected' do
380
+ before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
381
+
382
+ it "adds the specified class to the item's html classes" do
383
+ expect(item.html_options[:class]).to include('my_class')
384
+ end
385
+
386
+ it "doesn't replace the default html classes of a selected item" do
387
+ expect(item.html_options[:class]).to include(selected_classes)
388
+ end
389
+ end
390
+
391
+ context "and the item isn't selected" do
392
+ before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
393
+
394
+ it "sets the specified class as the item's html classes" do
395
+ expect(item.html_options[:class]).to include('my_class')
396
+ end
397
+ end
398
+ end
399
+
400
+ context "when the :class option isn't given" do
401
+ context 'and the item is selected' do
402
+ before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
403
+
404
+ it "sets the default html classes of a selected item" do
405
+ expect(item.html_options[:class]).to include(selected_classes)
406
+ end
407
+ end
408
+
409
+ context "and the item isn't selected" do
410
+ before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
411
+
412
+ it "doesn't set any html class on the item" do
413
+ expect(item.html_options[:class]).to be_blank
414
+ end
415
+ end
416
+ end
417
+
418
+ shared_examples 'generating id' do |id|
419
+ it "sets the item's html id to the specified id" do
420
+ expect(item.html_options[:id]).to eq id
421
+ end
422
+ end
423
+
424
+ describe 'when the :id option is given' do
425
+ let(:options) {{ html: { id: 'my_id' } }}
426
+
427
+ before do
428
+ allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
429
+ allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
430
+ end
431
+
432
+ context 'and :autogenerate_item_ids is true' do
433
+ let(:generate_ids) { true }
434
+
435
+ it_behaves_like 'generating id', 'my_id'
436
+ end
437
+
438
+ context 'and :autogenerate_item_ids is false' do
439
+ let(:generate_ids) { false }
440
+
441
+ it_behaves_like 'generating id', 'my_id'
442
+ end
443
+ end
444
+
445
+ context "when the :id option isn't given" do
446
+ before do
447
+ allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
448
+ allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
449
+ end
450
+
451
+ context 'and :autogenerate_item_ids is true' do
452
+ let(:generate_ids) { true }
453
+
454
+ it_behaves_like 'generating id', 'my_key'
455
+ end
456
+
457
+ context 'and :autogenerate_item_ids is false' do
458
+ let(:generate_ids) { false }
459
+
460
+ it "doesn't set any html id on the item" do
461
+ expect(item.html_options[:id]).to be_blank
462
+ end
463
+ end
464
+ end
465
+ end
466
+ end
467
+ end