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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +84 -0
  3. data/.rspec +1 -2
  4. data/.rubocop.yml +49 -0
  5. data/.rubocop_todo.yml +38 -0
  6. data/Appraisals +55 -0
  7. data/CHANGELOG.md +7 -0
  8. data/Gemfile +21 -0
  9. data/Guardfile +4 -2
  10. data/README.md +11 -23
  11. data/Rakefile +2 -27
  12. data/bin/_guard-core +16 -0
  13. data/bin/appraisal +16 -0
  14. data/bin/guard +16 -0
  15. data/bin/rake +16 -0
  16. data/bin/rspec +16 -0
  17. data/bin/rubocop +16 -0
  18. data/gemfiles/rails_6.1.gemfile +35 -0
  19. data/gemfiles/rails_7.0.gemfile +23 -0
  20. data/gemfiles/rails_7.1.gemfile +23 -0
  21. data/gemfiles/rails_7.2.gemfile +23 -0
  22. data/gemfiles/rails_8.0.gemfile +23 -0
  23. data/gemfiles/rails_8.1.gemfile +23 -0
  24. data/generators/navigation_config/navigation_config_generator.rb +2 -0
  25. data/generators/navigation_config/templates/config/navigation.rb +30 -26
  26. data/lib/generators/navigation_config/navigation_config_generator.rb +2 -0
  27. data/lib/simple-navigation.rb +3 -1
  28. data/lib/simple_navigation/adapters/base.rb +2 -0
  29. data/lib/simple_navigation/adapters/nanoc.rb +8 -3
  30. data/lib/simple_navigation/adapters/padrino.rb +3 -1
  31. data/lib/simple_navigation/adapters/rails.rb +12 -14
  32. data/lib/simple_navigation/adapters/sinatra.rb +4 -6
  33. data/lib/simple_navigation/config_file.rb +1 -1
  34. data/lib/simple_navigation/config_file_finder.rb +3 -3
  35. data/lib/simple_navigation/configuration.rb +5 -5
  36. data/lib/simple_navigation/helpers.rb +9 -11
  37. data/lib/simple_navigation/item.rb +26 -20
  38. data/lib/simple_navigation/item_adapter.rb +16 -5
  39. data/lib/simple_navigation/item_container.rb +13 -7
  40. data/lib/simple_navigation/items_provider.rb +6 -4
  41. data/lib/simple_navigation/railtie.rb +3 -1
  42. data/lib/simple_navigation/renderer/base.rb +5 -5
  43. data/lib/simple_navigation/renderer/breadcrumbs.rb +4 -3
  44. data/lib/simple_navigation/renderer/json.rb +1 -1
  45. data/lib/simple_navigation/renderer/links.rb +2 -0
  46. data/lib/simple_navigation/renderer/list.rb +5 -5
  47. data/lib/simple_navigation/renderer/text.rb +3 -1
  48. data/lib/simple_navigation/version.rb +3 -1
  49. data/lib/simple_navigation.rb +32 -24
  50. data/simple-navigation.gemspec +16 -27
  51. data/spec/fake_app/config/navigation.rb +4 -2
  52. data/spec/fake_app/rails_app.rb +5 -3
  53. data/spec/integration/rendering_navigation_spec.rb +7 -5
  54. data/spec/simple_navigation/adapters/nanoc_spec.rb +97 -0
  55. data/spec/simple_navigation/adapters/padrino_spec.rb +41 -22
  56. data/spec/simple_navigation/adapters/rails_spec.rb +199 -206
  57. data/spec/simple_navigation/adapters/sinatra_spec.rb +21 -5
  58. data/spec/simple_navigation/config_file_finder_spec.rb +32 -28
  59. data/spec/simple_navigation/config_file_spec.rb +14 -14
  60. data/spec/simple_navigation/configuration_spec.rb +128 -121
  61. data/spec/simple_navigation/helpers_spec.rb +282 -284
  62. data/spec/simple_navigation/item_adapter_spec.rb +109 -122
  63. data/spec/simple_navigation/item_container_spec.rb +407 -408
  64. data/spec/simple_navigation/item_spec.rb +333 -301
  65. data/spec/simple_navigation/items_provider_spec.rb +30 -27
  66. data/spec/simple_navigation/renderer/base_spec.rb +166 -168
  67. data/spec/simple_navigation/renderer/breadcrumbs_spec.rb +81 -83
  68. data/spec/simple_navigation/renderer/json_spec.rb +49 -56
  69. data/spec/simple_navigation/renderer/links_spec.rb +81 -83
  70. data/spec/simple_navigation/renderer/list_spec.rb +111 -91
  71. data/spec/simple_navigation/renderer/text_spec.rb +37 -39
  72. data/spec/simple_navigation_spec.rb +54 -47
  73. data/spec/spec_helper.rb +146 -53
  74. metadata +25 -164
  75. data/.travis.yml +0 -23
  76. data/gemfiles/rails-3-2-stable.gemfile +0 -11
  77. data/gemfiles/rails-4-1-stable.gemfile +0 -7
  78. data/gemfiles/rails-4-2-stable.gemfile +0 -7
  79. data/gemfiles/rails-5-2-stable.gemfile +0 -7
  80. data/gemfiles/rails-6-0-stable.gemfile +0 -9
  81. data/gemfiles/rails-6-1-stable.gemfile +0 -9
  82. data/init.rb +0 -1
  83. data/install.rb +0 -5
  84. data/lib/simple_navigation/adapters.rb +0 -10
  85. data/lib/simple_navigation/renderer.rb +0 -12
  86. data/spec/initializers/coveralls.rb +0 -3
  87. data/spec/initializers/have_css_matcher.rb +0 -19
  88. data/spec/initializers/memfs.rb +0 -7
  89. data/spec/initializers/rails.rb +0 -4
  90. data/spec/initializers/rspec.rb +0 -7
  91. data/uninstall.rb +0 -1
@@ -1,115 +1,113 @@
1
- module SimpleNavigation
2
- module Renderer
3
- describe Breadcrumbs do
4
- let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
1
+ # frozen_string_literal: true
5
2
 
6
- let(:item) { nil }
7
- let(:options) {{ level: :all }}
8
- let(:output) { renderer.render(navigation) }
9
- let(:renderer) { Breadcrumbs.new(options) }
3
+ RSpec.describe SimpleNavigation::Renderer::Breadcrumbs do
4
+ let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
10
5
 
11
- before { select_an_item(navigation[item]) if item }
6
+ let(:item) { nil }
7
+ let(:options) { { level: :all } }
8
+ let(:output) { renderer.render(navigation) }
9
+ let(:renderer) { described_class.new(options) }
12
10
 
13
- describe '#render' do
14
- it "renders a 'div' tag for the navigation" do
15
- expect(output).to have_css('div')
16
- end
11
+ before { select_an_item(navigation[item]) if item }
17
12
 
18
- it "sets the right html id on the rendered 'div' tag" do
19
- expect(output).to have_css('div#nav_id')
20
- end
13
+ describe '#render' do
14
+ it "renders a 'div' tag for the navigation" do
15
+ expect(output).to have_css('div')
16
+ end
21
17
 
22
- it "sets the right html classes on the rendered 'div' tag" do
23
- expect(output).to have_css('div.nav_class')
24
- end
18
+ it "sets the right html id on the rendered 'div' tag" do
19
+ expect(output).to have_css('div#nav_id')
20
+ end
25
21
 
26
- context 'when no item is selected' do
27
- it "doesn't render any 'a' tag in the 'div' tag" do
28
- expect(output).not_to have_css('div a')
29
- end
30
- end
22
+ it "sets the right html classes on the rendered 'div' tag" do
23
+ expect(output).to have_css('div.nav_class')
24
+ end
31
25
 
32
- context 'when an item is selected' do
33
- let(:item) { :invoices }
26
+ context 'when no item is selected' do
27
+ it "doesn't render any 'a' tag in the 'div' tag" do
28
+ expect(output).to have_no_css('div a')
29
+ end
30
+ end
34
31
 
35
- it "renders the selected 'a' tag" do
36
- expect(output).to have_css('div a')
37
- end
32
+ context 'when an item is selected' do
33
+ let(:item) { :invoices }
38
34
 
39
- it "remders the 'a' tag without any html id" do
40
- expect(output).not_to have_css('div a[id]')
41
- end
35
+ it "renders the selected 'a' tag" do
36
+ expect(output).to have_css('div a')
37
+ end
42
38
 
43
- it "renders the 'a' tag without any html class" do
44
- expect(output).not_to have_css('div a[class]')
45
- end
39
+ it "remders the 'a' tag without any html id" do
40
+ expect(output).to have_no_css('div a[id]')
41
+ end
42
+
43
+ it "renders the 'a' tag without any html class" do
44
+ expect(output).to have_no_css('div a[class]')
45
+ end
46
46
 
47
- context 'and the :allow_classes_and_ids option is true' do
48
- let(:options) {{ level: :all, allow_classes_and_ids: true }}
47
+ context 'when the :allow_classes_and_ids option is true' do
48
+ let(:options) { { level: :all, allow_classes_and_ids: true } }
49
49
 
50
- it "renders the 'a' tag with the selected class" do
51
- expect(output).to have_css('div a.selected')
52
- end
50
+ it "renders the 'a' tag with the selected class" do
51
+ expect(output).to have_css('div a.selected')
52
+ end
53
53
 
54
- context "and the item hasn't any id explicitly set" do
55
- it "renders the 'a' tag without any html id" do
56
- expect(output).not_to have_css('div a[id]')
57
- end
58
- end
54
+ context "when the item hasn't any id explicitly set" do
55
+ it "renders the 'a' tag without any html id" do
56
+ expect(output).to have_no_css('div a[id]')
57
+ end
58
+ end
59
59
 
60
- context 'and the item has an explicitly set id' do
61
- let(:item) { :users }
60
+ context 'when the item has an explicitly set id' do
61
+ let(:item) { :users }
62
62
 
63
- it "renders the 'a' tag with an html id" do
64
- expect(output).to have_css('div a#breadcrumb_users_link_id')
65
- end
66
- end
63
+ it "renders the 'a' tag with an html id" do
64
+ expect(output).to have_css('div a#breadcrumb_users_link_id')
67
65
  end
68
66
  end
67
+ end
68
+ end
69
69
 
70
- context 'and the :prefix option is set' do
71
- let(:options) {{ prefix: 'You are here: ' }}
70
+ context 'when the :prefix option is set' do
71
+ let(:options) { { prefix: 'You are here: ' } }
72
72
 
73
- context 'and there are no items to render' do
74
- let(:item) { nil }
73
+ context 'when there are no items to render' do
74
+ let(:item) { nil }
75
75
 
76
- it "doesn't render the prefix before the breadcrumbs" do
77
- expect(output).not_to match(/^<div.+>You are here: /)
78
- end
79
- end
76
+ it "doesn't render the prefix before the breadcrumbs" do
77
+ expect(output).not_to match(/^<div.+>You are here: /)
78
+ end
79
+ end
80
80
 
81
- context 'and there are items to render' do
82
- let(:item) { :invoices }
81
+ context 'when there are items to render' do
82
+ let(:item) { :invoices }
83
83
 
84
- it 'renders the prefix before the breadcrumbs' do
85
- expect(output).to match(/^<div.+>You are here: /)
86
- end
87
- end
84
+ it 'renders the prefix before the breadcrumbs' do
85
+ expect(output).to match(/^<div.+>You are here: /)
88
86
  end
87
+ end
88
+ end
89
89
 
90
- context 'when a sub navigation item is selected' do
91
- before do
92
- allow(navigation[:invoices]).to receive_messages(selected?: true)
90
+ context 'when a sub navigation item is selected' do
91
+ before do
92
+ allow(navigation[:invoices]).to receive_messages(selected?: true)
93
93
 
94
- allow(navigation[:invoices].sub_navigation[:unpaid]).to \
95
- receive_messages(selected?: true, selected_by_condition?: true)
96
- end
94
+ allow(navigation[:invoices].sub_navigation[:unpaid]).to \
95
+ receive_messages(selected?: true, selected_by_condition?: true)
96
+ end
97
97
 
98
- it 'renders all items as links' do
99
- expect(output).to have_css('div a', 2)
100
- end
98
+ it 'renders all items as links' do
99
+ expect(output).to have_css('div a', 2)
100
+ end
101
101
 
102
- context 'when the :static_leaf option is true' do
103
- let(:options) {{ level: :all, static_leaf: true }}
102
+ context 'when the :static_leaf option is true' do
103
+ let(:options) { { level: :all, static_leaf: true } }
104
104
 
105
- it 'renders the items as links' do
106
- expect(output).to have_css('div a')
107
- end
105
+ it 'renders the items as links' do
106
+ expect(output).to have_css('div a')
107
+ end
108
108
 
109
- it 'renders the last item as simple text' do
110
- expect(output).to have_css('div span')
111
- end
112
- end
109
+ it 'renders the last item as simple text' do
110
+ expect(output).to have_css('div span')
113
111
  end
114
112
  end
115
113
  end
@@ -1,73 +1,66 @@
1
- module SimpleNavigation
2
- module Renderer
3
- describe Json do
4
- describe '#render' do
5
- let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
1
+ # frozen_string_literal: true
6
2
 
7
- let(:item) { :invoices }
8
- let(:options) {{ level: :all }}
9
- let(:output) { renderer.render(navigation) }
10
- let(:parsed_output) { JSON.parse(output) }
11
- let(:renderer) { Json.new(options) }
3
+ RSpec.describe SimpleNavigation::Renderer::Json do
4
+ describe '#render' do
5
+ let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
12
6
 
13
- before { select_an_item(navigation[item]) if item }
7
+ let(:item) { :invoices }
8
+ let(:options) { { level: :all } }
9
+ let(:output) { renderer.render(navigation) }
10
+ let(:parsed_output) { JSON.parse(output) }
11
+ let(:renderer) { described_class.new(options) }
14
12
 
15
- context 'when an item is selected' do
13
+ before { select_an_item(navigation[item]) if item }
16
14
 
17
- it 'renders the selected page' do
18
- invoices_item = parsed_output.find { |item| item['name'] == 'Invoices' }
19
- expect(invoices_item).to include('selected' => true)
20
- end
21
- end
15
+ context 'when an item is selected' do
16
+ it 'renders the selected page' do
17
+ invoices_item = parsed_output.find { |item| item['name'] == 'Invoices' }
18
+ expect(invoices_item).to include('selected' => true)
19
+ end
20
+ end
22
21
 
23
- context 'when the :as_hash option is true' do
24
- let(:options) {{ level: :all, as_hash: true }}
22
+ context 'when the :as_hash option is true' do
23
+ let(:options) { { level: :all, as_hash: true } }
25
24
 
26
- it 'returns every item as a hash' do
27
- expect(output).to be_an Array
25
+ it 'returns every item as a hash' do # rubocop:disable RSpec/MultipleExpectations
26
+ expect(output).to be_an Array
28
27
 
29
- output.each do |item|
30
- expect(item).to be_an Hash
31
- end
32
- end
28
+ expect(output).to all(be_an Hash)
29
+ end
33
30
 
34
- it 'renders the selected page' do
35
- invoices_item = output.find { |item| item[:name] == 'Invoices' }
36
- expect(invoices_item).to include(selected: true)
37
- end
38
- end
31
+ it 'renders the selected page' do
32
+ invoices_item = output.find { |item| item[:name] == 'Invoices' }
33
+ expect(invoices_item).to include(selected: true)
34
+ end
35
+ end
39
36
 
40
- context 'with options' do
41
- it 'should render options for each item' do
42
- parsed_output.each do |item|
43
- expect(item).to have_key('options')
44
- end
45
- end
46
- end
37
+ context 'with options' do
38
+ it 'renders options for each item' do
39
+ expect(parsed_output).to all(have_key('options'))
40
+ end
41
+ end
47
42
 
48
- context 'when a sub navigation item is selected' do
49
- let(:invoices_item) do
50
- parsed_output.find { |item| item['name'] == 'Invoices' }
51
- end
52
- let(:unpaid_item) do
53
- invoices_item['items'].find { |item| item['name'] == 'Unpaid' }
54
- end
43
+ context 'when a sub navigation item is selected' do
44
+ let(:invoices_item) do
45
+ parsed_output.find { |item| item['name'] == 'Invoices' }
46
+ end
47
+ let(:unpaid_item) do
48
+ invoices_item['items'].find { |item| item['name'] == 'Unpaid' }
49
+ end
55
50
 
56
- before do
57
- allow(navigation[:invoices]).to receive_messages(selected?: true)
51
+ before do
52
+ allow(navigation[:invoices]).to receive_messages(selected?: true)
58
53
 
59
- allow(navigation[:invoices].sub_navigation[:unpaid]).to \
60
- receive_messages(selected?: true, selected_by_condition?: true)
61
- end
54
+ allow(navigation[:invoices].sub_navigation[:unpaid]).to \
55
+ receive_messages(selected?: true, selected_by_condition?: true)
56
+ end
62
57
 
63
- it 'marks all the parent items as selected' do
64
- expect(invoices_item).to include('selected' => true)
65
- end
58
+ it 'marks all the parent items as selected' do
59
+ expect(invoices_item).to include('selected' => true)
60
+ end
66
61
 
67
- it 'marks the item as selected' do
68
- expect(unpaid_item).to include('selected' => true)
69
- end
70
- end
62
+ it 'marks the item as selected' do
63
+ expect(unpaid_item).to include('selected' => true)
71
64
  end
72
65
  end
73
66
  end
@@ -1,86 +1,84 @@
1
- module SimpleNavigation
2
- module Renderer
3
- describe Links do
4
- describe '#render' do
5
- let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
6
-
7
- let(:item) { nil }
8
- let(:options) { { level: :all } }
9
- let(:output) { renderer.render(navigation) }
10
- let(:renderer) { Links.new(options) }
11
-
12
- before { select_an_item(navigation[item]) if item }
13
-
14
- it "renders a 'div' tag for the navigation" do
15
- expect(output).to have_css('div')
16
- end
17
-
18
- it "sets the right html id on the rendered 'div' tag" do
19
- expect(output).to have_css('div#nav_id')
20
- end
21
-
22
- it "sets the right html classes on the rendered 'div' tag" do
23
- expect(output).to have_css('div.nav_class')
24
- end
25
-
26
- it "renders an 'a' tag for each item" do
27
- expect(output).to have_css('a', 3)
28
- end
29
-
30
- it "renders the 'a' tags with the corresponding item's :html_options" do
31
- expect(output).to have_css('a[style="float:right"]')
32
- end
33
-
34
- context 'when an item has a specified id' do
35
- it "renders the 'a' tags with the specified id" do
36
- expect(output).to have_css('a#users_id')
37
- end
38
- end
39
-
40
- context 'when an item has no specified id' do
41
- it "uses a default id by stringifying the item's key" do
42
- expect(output).to have_css('a#invoices')
43
- end
44
- end
45
-
46
- context 'when no item is selected' do
47
- it "renders items without the 'selected' class" do
48
- expect(output).not_to have_css('a.selected')
49
- end
50
- end
51
-
52
- context 'when an item is selected' do
53
- let(:item) { :invoices }
54
-
55
- it "renders the selected item with the 'selected' class" do
56
- expect(output).to have_css('a#invoices.selected')
57
- end
58
- end
59
-
60
- context "when the :join_with option is set" do
61
- let(:options) {{ level: :all, join_with: ' | ' }}
62
-
63
- it 'separates the items with the specified separator' do
64
- expect(output.scan(' | ').size).to eq 3
65
- end
66
- end
67
-
68
- context 'when a sub navigation item is selected' do
69
- before do
70
- allow(navigation[:invoices]).to receive_messages(selected?: true)
71
-
72
- allow(navigation[:invoices].sub_navigation[:unpaid]).to \
73
- receive_messages(selected?: true, selected_by_condition?: true)
74
- end
75
-
76
- it 'renders the main parent as selected' do
77
- expect(output).to have_css('a#invoices.selected')
78
- end
79
-
80
- it "doesn't render the nested item's link" do
81
- expect(output).not_to have_css('a#unpaid')
82
- end
83
- end
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe SimpleNavigation::Renderer::Links do
4
+ describe '#render' do
5
+ let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
6
+
7
+ let(:item) { nil }
8
+ let(:options) { { level: :all } }
9
+ let(:output) { renderer.render(navigation) }
10
+ let(:renderer) { described_class.new(options) }
11
+
12
+ before { select_an_item(navigation[item]) if item }
13
+
14
+ it "renders a 'div' tag for the navigation" do
15
+ expect(output).to have_css('div')
16
+ end
17
+
18
+ it "sets the right html id on the rendered 'div' tag" do
19
+ expect(output).to have_css('div#nav_id')
20
+ end
21
+
22
+ it "sets the right html classes on the rendered 'div' tag" do
23
+ expect(output).to have_css('div.nav_class')
24
+ end
25
+
26
+ it "renders an 'a' tag for each item" do
27
+ expect(output).to have_css('a', 3)
28
+ end
29
+
30
+ it "renders the 'a' tags with the corresponding item's :html_options" do
31
+ expect(output).to have_css('a[style="float:right"]')
32
+ end
33
+
34
+ context 'when an item has a specified id' do
35
+ it "renders the 'a' tags with the specified id" do
36
+ expect(output).to have_css('a#users_id')
37
+ end
38
+ end
39
+
40
+ context 'when an item has no specified id' do
41
+ it "uses a default id by stringifying the item's key" do
42
+ expect(output).to have_css('a#invoices')
43
+ end
44
+ end
45
+
46
+ context 'when no item is selected' do
47
+ it "renders items without the 'selected' class" do
48
+ expect(output).to have_no_css('a.selected')
49
+ end
50
+ end
51
+
52
+ context 'when an item is selected' do
53
+ let(:item) { :invoices }
54
+
55
+ it "renders the selected item with the 'selected' class" do
56
+ expect(output).to have_css('a#invoices.selected')
57
+ end
58
+ end
59
+
60
+ context 'when the :join_with option is set' do
61
+ let(:options) { { level: :all, join_with: ' | ' } }
62
+
63
+ it 'separates the items with the specified separator' do
64
+ expect(output.scan(' | ').size).to eq 3
65
+ end
66
+ end
67
+
68
+ context 'when a sub navigation item is selected' do
69
+ before do
70
+ allow(navigation[:invoices]).to receive_messages(selected?: true)
71
+
72
+ allow(navigation[:invoices].sub_navigation[:unpaid]).to \
73
+ receive_messages(selected?: true, selected_by_condition?: true)
74
+ end
75
+
76
+ it 'renders the main parent as selected' do
77
+ expect(output).to have_css('a#invoices.selected')
78
+ end
79
+
80
+ it "doesn't render the nested item's link" do
81
+ expect(output).to have_no_css('a#unpaid')
84
82
  end
85
83
  end
86
84
  end