simple-navigation 3.13.0 → 4.0.5

Sign up to get free protection for your applications and to get access to all the features.
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