simple-navigation 3.13.0 → 4.0.5

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -3
  5. data/CHANGELOG.md +420 -0
  6. data/Guardfile +4 -2
  7. data/LICENSE +1 -1
  8. data/README.md +30 -7
  9. data/Rakefile +25 -2
  10. data/gemfiles/.bundle/config +2 -0
  11. data/gemfiles/rails-3-2-stable.gemfile +11 -0
  12. data/gemfiles/rails-4-1-stable.gemfile +7 -0
  13. data/gemfiles/rails-4-2-stable.gemfile +7 -0
  14. data/generators/navigation_config/navigation_config_generator.rb +0 -1
  15. data/generators/navigation_config/templates/config/navigation.rb +18 -15
  16. data/lib/simple_navigation.rb +25 -42
  17. data/lib/simple_navigation/adapters/padrino.rb +2 -2
  18. data/lib/simple_navigation/adapters/rails.rb +1 -24
  19. data/lib/simple_navigation/adapters/sinatra.rb +2 -11
  20. data/lib/simple_navigation/config_file.rb +36 -0
  21. data/lib/simple_navigation/config_file_finder.rb +42 -0
  22. data/lib/simple_navigation/{core/configuration.rb → configuration.rb} +7 -1
  23. data/lib/simple_navigation/{rendering/helpers.rb → helpers.rb} +0 -4
  24. data/lib/simple_navigation/{core/item.rb → item.rb} +76 -83
  25. data/lib/simple_navigation/{core/item_adapter.rb → item_adapter.rb} +3 -17
  26. data/lib/simple_navigation/{core/item_container.rb → item_container.rb} +23 -14
  27. data/lib/simple_navigation/{core/items_provider.rb → items_provider.rb} +0 -0
  28. data/lib/simple_navigation/railtie.rb +7 -0
  29. data/lib/simple_navigation/renderer.rb +12 -0
  30. data/lib/simple_navigation/{rendering/renderer → renderer}/base.rb +1 -1
  31. data/lib/simple_navigation/{rendering/renderer → renderer}/breadcrumbs.rb +0 -0
  32. data/lib/simple_navigation/{rendering/renderer → renderer}/json.rb +2 -0
  33. data/lib/simple_navigation/{rendering/renderer → renderer}/links.rb +0 -0
  34. data/lib/simple_navigation/{rendering/renderer → renderer}/list.rb +0 -0
  35. data/lib/simple_navigation/{rendering/renderer → renderer}/text.rb +0 -0
  36. data/lib/simple_navigation/version.rb +1 -1
  37. data/simple-navigation.gemspec +6 -5
  38. data/spec/fake_app/config/navigation.rb +6 -0
  39. data/spec/fake_app/rails_app.rb +35 -0
  40. data/spec/initializers/coveralls.rb +3 -0
  41. data/spec/initializers/have_css_matcher.rb +8 -3
  42. data/spec/initializers/memfs.rb +7 -0
  43. data/spec/initializers/rails.rb +4 -0
  44. data/spec/initializers/rspec.rb +7 -0
  45. data/spec/integration/rendering_navigation_spec.rb +14 -0
  46. data/spec/{lib/simple_navigation → simple_navigation}/adapters/padrino_spec.rb +0 -2
  47. data/spec/{lib/simple_navigation → simple_navigation}/adapters/rails_spec.rb +43 -94
  48. data/spec/{lib/simple_navigation → simple_navigation}/adapters/sinatra_spec.rb +4 -6
  49. data/spec/simple_navigation/config_file_finder_spec.rb +50 -0
  50. data/spec/simple_navigation/config_file_spec.rb +25 -0
  51. data/spec/{lib/simple_navigation/core → simple_navigation}/configuration_spec.rb +29 -19
  52. data/spec/{lib/simple_navigation/rendering → simple_navigation}/helpers_spec.rb +10 -13
  53. data/spec/{lib/simple_navigation/core → simple_navigation}/item_adapter_spec.rb +14 -11
  54. data/spec/{lib/simple_navigation/core → simple_navigation}/item_container_spec.rb +130 -42
  55. data/spec/simple_navigation/item_spec.rb +475 -0
  56. data/spec/{lib/simple_navigation/core → simple_navigation}/items_provider_spec.rb +1 -3
  57. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/base_spec.rb +34 -36
  58. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/breadcrumbs_spec.rb +4 -7
  59. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/json_spec.rb +5 -11
  60. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/links_spec.rb +5 -8
  61. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/list_spec.rb +4 -7
  62. data/spec/{lib/simple_navigation/rendering → simple_navigation}/renderer/text_spec.rb +4 -7
  63. data/spec/simple_navigation_spec.rb +190 -0
  64. data/spec/spec_helper.rb +29 -35
  65. metadata +128 -113
  66. data/CHANGELOG +0 -288
  67. data/lib/simple_navigation/core.rb +0 -5
  68. data/lib/simple_navigation/rails_controller_methods.rb +0 -164
  69. data/lib/simple_navigation/rendering.rb +0 -12
  70. data/rails/init.rb +0 -1
  71. data/spec/lib/simple_navigation/core/item_spec.rb +0 -703
  72. data/spec/lib/simple_navigation/rails_controller_methods_spec.rb +0 -270
  73. data/spec/lib/simple_navigation_spec.rb +0 -300
@@ -0,0 +1,475 @@
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 "but item has no url" do
250
+ let(:url) { nil }
251
+
252
+ it 'returns false' do
253
+ expect(item.selected?).to be false
254
+ end
255
+ end
256
+
257
+ context "and the current url is a sub path of the item's url" do
258
+ before do
259
+ allow(adapter).to \
260
+ receive_messages(current_page?: false, request_uri: 'url/test')
261
+ end
262
+
263
+ it 'returns true' do
264
+ expect(item.selected?).to be true
265
+ end
266
+ end
267
+
268
+ context "and the current url is not a sub path of the item's url" do
269
+ before do
270
+ allow(adapter).to \
271
+ receive_messages(current_page?: false, request_uri: 'other/test')
272
+ end
273
+
274
+ it 'returns false' do
275
+ expect(item.selected?).to be false
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
281
+
282
+ context 'when the item has a :highlights_on option' do
283
+ context 'and it is a regular expression' do
284
+ before { allow(adapter).to receive_messages(request_uri: '/test') }
285
+
286
+ context 'and the current url matches the expression' do
287
+ let(:options) {{ highlights_on: /test/ }}
288
+
289
+ it 'returns true' do
290
+ expect(item.selected?).to be true
291
+ end
292
+ end
293
+
294
+ context 'and the current url does not match the expression' do
295
+ let(:options) {{ highlights_on: /other/ }}
296
+
297
+ it 'returns false' do
298
+ expect(item.selected?).to be false
299
+ end
300
+ end
301
+ end
302
+
303
+ context 'and it is a callable object' do
304
+ context 'and the call returns true' do
305
+ let(:options) {{ highlights_on: -> { true } }}
306
+
307
+ it 'returns true' do
308
+ expect(item.selected?).to be true
309
+ end
310
+ end
311
+
312
+ context 'and the call returns false' do
313
+ let(:options) {{ highlights_on: -> { false } }}
314
+
315
+ it 'returns false' do
316
+ expect(item.selected?).to be false
317
+ end
318
+ end
319
+ end
320
+
321
+ context 'and it is the :subpath symbol' do
322
+ let(:options) {{ highlights_on: :subpath }}
323
+
324
+ context "and the current url is a sub path of the item's url" do
325
+ before do
326
+ allow(adapter).to receive_messages(request_uri: 'url/test')
327
+ end
328
+
329
+ it 'returns true' do
330
+ expect(item.selected?).to be true
331
+ end
332
+ end
333
+
334
+ context "and the current url is not a sub path of the item's url" do
335
+ before do
336
+ allow(adapter).to receive_messages(request_uri: 'other/test')
337
+ end
338
+
339
+ it 'returns false' do
340
+ expect(item.selected?).to be false
341
+ end
342
+ end
343
+ end
344
+
345
+ context 'and it is non usable' do
346
+ let(:options) {{ highlights_on: :hello }}
347
+
348
+ it 'raises an exception' do
349
+ expect{ item.selected? }.to raise_error
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ describe '#selected_class' do
356
+ context 'when the item is selected' do
357
+ before { allow(item).to receive_messages(selected?: true) }
358
+
359
+ it 'returns the default selected_class' do
360
+ expect(item.selected_class).to eq 'selected'
361
+ end
362
+
363
+ context 'and selected_class is defined in the context' do
364
+ before { allow(item_container).to receive_messages(selected_class: 'defined') }
365
+
366
+ it "returns the context's selected_class" do
367
+ expect(item.selected_class).to eq 'defined'
368
+ end
369
+ end
370
+ end
371
+
372
+ context 'when the item is not selected' do
373
+ before { allow(item).to receive_messages(selected?: false) }
374
+
375
+ it 'returns nil' do
376
+ expect(item.selected_class).to be_nil
377
+ end
378
+ end
379
+ end
380
+
381
+ describe ':html_options argument' do
382
+ let(:selected_classes) { 'selected simple-navigation-active-leaf' }
383
+
384
+ context 'when the :class option is given' do
385
+ let(:options) {{ html: { class: 'my_class' } }}
386
+
387
+ context 'and the item is selected' do
388
+ before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
389
+
390
+ it "adds the specified class to the item's html classes" do
391
+ expect(item.html_options[:class]).to include('my_class')
392
+ end
393
+
394
+ it "doesn't replace the default html classes of a selected item" do
395
+ expect(item.html_options[:class]).to include(selected_classes)
396
+ end
397
+ end
398
+
399
+ context "and the item isn't selected" do
400
+ before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
401
+
402
+ it "sets the specified class as the item's html classes" do
403
+ expect(item.html_options[:class]).to include('my_class')
404
+ end
405
+ end
406
+ end
407
+
408
+ context "when the :class option isn't given" do
409
+ context 'and the item is selected' do
410
+ before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
411
+
412
+ it "sets the default html classes of a selected item" do
413
+ expect(item.html_options[:class]).to include(selected_classes)
414
+ end
415
+ end
416
+
417
+ context "and the item isn't selected" do
418
+ before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
419
+
420
+ it "doesn't set any html class on the item" do
421
+ expect(item.html_options[:class]).to be_blank
422
+ end
423
+ end
424
+ end
425
+
426
+ shared_examples 'generating id' do |id|
427
+ it "sets the item's html id to the specified id" do
428
+ expect(item.html_options[:id]).to eq id
429
+ end
430
+ end
431
+
432
+ describe 'when the :id option is given' do
433
+ let(:options) {{ html: { id: 'my_id' } }}
434
+
435
+ before do
436
+ allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
437
+ allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
438
+ end
439
+
440
+ context 'and :autogenerate_item_ids is true' do
441
+ let(:generate_ids) { true }
442
+
443
+ it_behaves_like 'generating id', 'my_id'
444
+ end
445
+
446
+ context 'and :autogenerate_item_ids is false' do
447
+ let(:generate_ids) { false }
448
+
449
+ it_behaves_like 'generating id', 'my_id'
450
+ end
451
+ end
452
+
453
+ context "when the :id option isn't given" do
454
+ before do
455
+ allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
456
+ allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
457
+ end
458
+
459
+ context 'and :autogenerate_item_ids is true' do
460
+ let(:generate_ids) { true }
461
+
462
+ it_behaves_like 'generating id', 'my_key'
463
+ end
464
+
465
+ context 'and :autogenerate_item_ids is false' do
466
+ let(:generate_ids) { false }
467
+
468
+ it "doesn't set any html id on the item" do
469
+ expect(item.html_options[:id]).to be_blank
470
+ end
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end