simple-navigation 3.14.0 → 4.0.0

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