nanoc 4.4.5 → 4.4.6

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 (233) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -2
  3. data/Gemfile.lock +37 -18
  4. data/NEWS.md +6 -0
  5. data/Rakefile +8 -20
  6. data/lib/nanoc/base/entities/code_snippet.rb +0 -2
  7. data/lib/nanoc/base/entities/item_rep.rb +4 -22
  8. data/lib/nanoc/base/entities/processing_actions/snapshot.rb +9 -7
  9. data/lib/nanoc/base/entities/rule_memory.rb +15 -7
  10. data/lib/nanoc/base/entities/snapshot_def.rb +2 -8
  11. data/lib/nanoc/base/repos/store.rb +2 -28
  12. data/lib/nanoc/base/services/checksummer.rb +9 -10
  13. data/lib/nanoc/base/services/compiler.rb +14 -16
  14. data/lib/nanoc/base/services/executor.rb +2 -13
  15. data/lib/nanoc/base/views/mixins/with_reps_view_mixin.rb +1 -1
  16. data/lib/nanoc/checking/checks/external_links.rb +2 -1
  17. data/lib/nanoc/cli/commands/compile.rb +8 -14
  18. data/lib/nanoc/extra/parallel_collection.rb +57 -0
  19. data/lib/nanoc/extra.rb +1 -0
  20. data/lib/nanoc/filters/mustache.rb +1 -1
  21. data/lib/nanoc/rule_dsl/recording_executor.rb +6 -34
  22. data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +42 -12
  23. data/lib/nanoc/spec.rb +1 -1
  24. data/lib/nanoc/version.rb +1 -1
  25. data/nanoc.gemspec +1 -2
  26. data/spec/contributors_spec.rb +18 -0
  27. data/spec/nanoc/base/checksummer_spec.rb +381 -0
  28. data/spec/nanoc/base/compiler_spec.rb +181 -0
  29. data/spec/nanoc/base/entities/configuration_spec.rb +49 -0
  30. data/spec/nanoc/base/entities/content_spec.rb +193 -0
  31. data/spec/nanoc/base/entities/document_spec.rb +206 -0
  32. data/spec/nanoc/base/entities/identifier_spec.rb +460 -0
  33. data/spec/nanoc/base/entities/item_rep_spec.rb +226 -0
  34. data/spec/nanoc/base/entities/item_spec.rb +3 -0
  35. data/spec/nanoc/base/entities/layout_spec.rb +3 -0
  36. data/spec/nanoc/base/entities/lazy_value_spec.rb +106 -0
  37. data/spec/nanoc/base/entities/outdatedness_status_spec.rb +113 -0
  38. data/spec/nanoc/base/entities/pattern_spec.rb +125 -0
  39. data/spec/nanoc/base/entities/processing_action_spec.rb +9 -0
  40. data/spec/nanoc/base/entities/processing_actions/filter_spec.rb +18 -0
  41. data/spec/nanoc/base/entities/processing_actions/layout_spec.rb +18 -0
  42. data/spec/nanoc/base/entities/processing_actions/snapshot_spec.rb +32 -0
  43. data/spec/nanoc/base/entities/props_spec.rb +195 -0
  44. data/spec/nanoc/base/entities/rule_memory_spec.rb +131 -0
  45. data/spec/nanoc/base/entities/site_spec.rb +73 -0
  46. data/spec/nanoc/base/feature_spec.rb +107 -0
  47. data/spec/nanoc/base/filter_spec.rb +99 -0
  48. data/spec/nanoc/base/item_rep_writer_spec.rb +131 -0
  49. data/spec/nanoc/base/plugin_registry_spec.rb +29 -0
  50. data/spec/nanoc/base/repos/checksum_store_spec.rb +133 -0
  51. data/spec/nanoc/base/repos/compiled_content_cache_spec.rb +55 -0
  52. data/spec/nanoc/base/repos/config_loader_spec.rb +243 -0
  53. data/spec/nanoc/base/repos/dependency_store_spec.rb +195 -0
  54. data/spec/nanoc/base/repos/site_loader_spec.rb +214 -0
  55. data/spec/nanoc/base/services/dependency_tracker_spec.rb +238 -0
  56. data/spec/nanoc/base/services/executor_spec.rb +495 -0
  57. data/spec/nanoc/base/services/item_rep_router_spec.rb +134 -0
  58. data/spec/nanoc/base/services/item_rep_selector_spec.rb +169 -0
  59. data/spec/nanoc/base/services/outdatedness_checker_spec.rb +370 -0
  60. data/spec/nanoc/base/services/outdatedness_rules_spec.rb +432 -0
  61. data/spec/nanoc/base/services/pruner_spec.rb +105 -0
  62. data/spec/nanoc/base/services/temp_filename_factory_spec.rb +87 -0
  63. data/spec/nanoc/base/views/config_view_spec.rb +96 -0
  64. data/spec/nanoc/base/views/document_view_spec.rb +332 -0
  65. data/spec/nanoc/base/views/identifiable_collection_view_spec.rb +190 -0
  66. data/spec/nanoc/base/views/item_collection_with_reps_view_spec.rb +18 -0
  67. data/spec/nanoc/base/views/item_collection_without_reps_view_spec.rb +18 -0
  68. data/spec/nanoc/base/views/item_rep_collection_view_spec.rb +143 -0
  69. data/spec/nanoc/base/views/item_rep_view_spec.rb +265 -0
  70. data/spec/nanoc/base/views/item_view_spec.rb +341 -0
  71. data/spec/nanoc/base/views/layout_collection_view_spec.rb +18 -0
  72. data/spec/nanoc/base/views/layout_view_spec.rb +14 -0
  73. data/spec/nanoc/base/views/mutable_config_view_spec.rb +16 -0
  74. data/spec/nanoc/base/views/mutable_document_view_spec.rb +92 -0
  75. data/spec/nanoc/base/views/mutable_identifiable_collection_view_spec.rb +36 -0
  76. data/spec/nanoc/base/views/mutable_item_collection_view_spec.rb +49 -0
  77. data/spec/nanoc/base/views/mutable_item_view_spec.rb +22 -0
  78. data/spec/nanoc/base/views/mutable_layout_collection_view_spec.rb +49 -0
  79. data/spec/nanoc/base/views/mutable_layout_view_spec.rb +13 -0
  80. data/spec/nanoc/base/views/post_compile_item_rep_collection_view_spec.rb +4 -0
  81. data/spec/nanoc/base/views/post_compile_item_rep_view_spec.rb +137 -0
  82. data/spec/nanoc/base/views/post_compile_item_view_spec.rb +56 -0
  83. data/spec/nanoc/cli/commands/compile/file_action_printer_spec.rb +76 -0
  84. data/spec/nanoc/cli/commands/compile/timing_recorder_spec.rb +66 -0
  85. data/spec/nanoc/cli/commands/compile_spec.rb +64 -0
  86. data/spec/nanoc/cli/commands/deploy_spec.rb +327 -0
  87. data/spec/nanoc/cli/commands/shell_spec.rb +54 -0
  88. data/spec/nanoc/cli/commands/show_data_spec.rb +126 -0
  89. data/spec/nanoc/cli/commands/show_rules_spec.rb +112 -0
  90. data/spec/nanoc/cli/commands/view_spec.rb +58 -0
  91. data/spec/nanoc/data_sources/filesystem_spec.rb +56 -0
  92. data/spec/nanoc/deploying/fog_spec.rb +193 -0
  93. data/spec/nanoc/extra/parallel_collection_spec.rb +108 -0
  94. data/spec/nanoc/filters/colorize_syntax/rouge_spec.rb +195 -0
  95. data/spec/nanoc/filters/less_spec.rb +120 -0
  96. data/spec/nanoc/helpers/blogging_spec.rb +216 -0
  97. data/spec/nanoc/helpers/breadcrumbs_spec.rb +133 -0
  98. data/spec/nanoc/helpers/capturing_spec.rb +181 -0
  99. data/spec/nanoc/helpers/child_parent_spec.rb +105 -0
  100. data/spec/nanoc/helpers/filtering_spec.rb +72 -0
  101. data/spec/nanoc/helpers/html_escape_spec.rb +35 -0
  102. data/spec/nanoc/helpers/link_to_spec.rb +275 -0
  103. data/spec/nanoc/helpers/rendering_spec.rb +141 -0
  104. data/spec/nanoc/helpers/tagging_spec.rb +104 -0
  105. data/spec/nanoc/helpers/text_spec.rb +58 -0
  106. data/spec/nanoc/integration/outdatedness_integration_spec.rb +208 -0
  107. data/spec/nanoc/regressions/gh_1015_spec.rb +17 -0
  108. data/spec/nanoc/regressions/gh_1031_spec.rb +54 -0
  109. data/spec/nanoc/regressions/gh_1035_spec.rb +33 -0
  110. data/spec/nanoc/regressions/gh_1040_spec.rb +22 -0
  111. data/spec/nanoc/regressions/gh_761_spec.rb +23 -0
  112. data/spec/nanoc/regressions/gh_767_spec.rb +19 -0
  113. data/spec/nanoc/regressions/gh_769_spec.rb +30 -0
  114. data/spec/nanoc/regressions/gh_776_spec.rb +43 -0
  115. data/spec/nanoc/regressions/gh_787_spec.rb +19 -0
  116. data/spec/nanoc/regressions/gh_795_spec.rb +19 -0
  117. data/spec/nanoc/regressions/gh_804_spec.rb +26 -0
  118. data/spec/nanoc/regressions/gh_807_spec.rb +17 -0
  119. data/spec/nanoc/regressions/gh_809_spec.rb +17 -0
  120. data/spec/nanoc/regressions/gh_813_spec.rb +22 -0
  121. data/spec/nanoc/regressions/gh_815_spec.rb +18 -0
  122. data/spec/nanoc/regressions/gh_828_spec.rb +23 -0
  123. data/spec/nanoc/regressions/gh_833_spec.rb +14 -0
  124. data/spec/nanoc/regressions/gh_841_spec.rb +15 -0
  125. data/spec/nanoc/regressions/gh_867_spec.rb +15 -0
  126. data/spec/nanoc/regressions/gh_882_spec.rb +29 -0
  127. data/spec/nanoc/regressions/gh_885_spec.rb +30 -0
  128. data/spec/nanoc/regressions/gh_891_spec.rb +26 -0
  129. data/spec/nanoc/regressions/gh_913_spec.rb +24 -0
  130. data/spec/nanoc/regressions/gh_928_spec.rb +5 -0
  131. data/spec/nanoc/regressions/gh_937_spec.rb +25 -0
  132. data/spec/nanoc/regressions/gh_942_spec.rb +21 -0
  133. data/spec/nanoc/regressions/gh_947_spec.rb +21 -0
  134. data/spec/nanoc/regressions/gh_948_spec.rb +16 -0
  135. data/spec/nanoc/regressions/gh_951_spec.rb +19 -0
  136. data/spec/nanoc/regressions/gh_954_spec.rb +33 -0
  137. data/spec/nanoc/regressions/gh_970a_spec.rb +17 -0
  138. data/spec/nanoc/regressions/gh_970b_spec.rb +50 -0
  139. data/spec/nanoc/regressions/gh_974_spec.rb +17 -0
  140. data/spec/nanoc/regressions/gh_981_spec.rb +21 -0
  141. data/spec/nanoc/rule_dsl/recording_executor_spec.rb +142 -0
  142. data/spec/nanoc/rule_dsl/rule_context_spec.rb +177 -0
  143. data/spec/nanoc/rule_dsl/rule_memory_calculator_spec.rb +233 -0
  144. data/spec/nanoc/rule_dsl/rules_collection_spec.rb +299 -0
  145. data/spec/regression_filenames_spec.rb +16 -0
  146. data/spec/spec_helper.rb +173 -0
  147. data/test/base/core_ext/array_spec.rb +2 -0
  148. data/test/base/core_ext/hash_spec.rb +2 -0
  149. data/test/base/core_ext/string_spec.rb +2 -0
  150. data/test/base/test_code_snippet.rb +2 -0
  151. data/test/base/test_compiler.rb +2 -0
  152. data/test/base/test_context.rb +4 -2
  153. data/test/base/test_data_source.rb +2 -0
  154. data/test/base/test_dependency_tracker.rb +2 -0
  155. data/test/base/test_directed_graph.rb +2 -0
  156. data/test/base/test_filter.rb +7 -5
  157. data/test/base/test_item.rb +2 -0
  158. data/test/base/test_item_array.rb +3 -1
  159. data/test/base/test_layout.rb +2 -0
  160. data/test/base/test_memoization.rb +2 -0
  161. data/test/base/test_notification_center.rb +2 -0
  162. data/test/base/test_outdatedness_checker.rb +2 -0
  163. data/test/base/test_plugin.rb +2 -0
  164. data/test/base/test_site.rb +2 -0
  165. data/test/base/test_store.rb +2 -0
  166. data/test/checking/checks/test_css.rb +2 -0
  167. data/test/checking/checks/test_external_links.rb +4 -2
  168. data/test/checking/checks/test_html.rb +2 -0
  169. data/test/checking/checks/test_internal_links.rb +5 -3
  170. data/test/checking/checks/test_mixed_content.rb +2 -0
  171. data/test/checking/checks/test_stale.rb +2 -0
  172. data/test/checking/test_check.rb +2 -0
  173. data/test/checking/test_dsl.rb +2 -0
  174. data/test/checking/test_runner.rb +2 -0
  175. data/test/cli/commands/test_check.rb +2 -0
  176. data/test/cli/commands/test_compile.rb +2 -0
  177. data/test/cli/commands/test_create_site.rb +2 -0
  178. data/test/cli/commands/test_help.rb +2 -0
  179. data/test/cli/commands/test_info.rb +2 -0
  180. data/test/cli/commands/test_prune.rb +2 -0
  181. data/test/cli/test_cleaning_stream.rb +2 -0
  182. data/test/cli/test_cli.rb +11 -9
  183. data/test/cli/test_error_handler.rb +2 -0
  184. data/test/cli/test_logger.rb +2 -0
  185. data/test/data_sources/test_filesystem.rb +8 -6
  186. data/test/data_sources/test_filesystem_tools.rb +2 -0
  187. data/test/deploying/test_fog.rb +2 -0
  188. data/test/deploying/test_rsync.rb +4 -2
  189. data/test/extra/core_ext/test_pathname.rb +2 -0
  190. data/test/extra/core_ext/test_time.rb +2 -0
  191. data/test/extra/test_link_collector.rb +2 -0
  192. data/test/extra/test_piper.rb +2 -0
  193. data/test/filters/colorize_syntax/test_coderay.rb +2 -0
  194. data/test/filters/colorize_syntax/test_common.rb +2 -0
  195. data/test/filters/colorize_syntax/test_pygmentize.rb +2 -0
  196. data/test/filters/colorize_syntax/test_pygments.rb +2 -0
  197. data/test/filters/colorize_syntax/test_simon.rb +2 -0
  198. data/test/filters/test_asciidoc.rb +2 -0
  199. data/test/filters/test_bluecloth.rb +2 -0
  200. data/test/filters/test_coffeescript.rb +2 -0
  201. data/test/filters/test_erb.rb +7 -5
  202. data/test/filters/test_erubis.rb +6 -4
  203. data/test/filters/test_haml.rb +7 -5
  204. data/test/filters/test_handlebars.rb +2 -0
  205. data/test/filters/test_kramdown.rb +2 -0
  206. data/test/filters/test_markaby.rb +2 -0
  207. data/test/filters/test_maruku.rb +2 -0
  208. data/test/filters/test_mustache.rb +4 -2
  209. data/test/filters/test_pandoc.rb +2 -0
  210. data/test/filters/test_rainpress.rb +2 -0
  211. data/test/filters/test_rdiscount.rb +2 -0
  212. data/test/filters/test_rdoc.rb +2 -0
  213. data/test/filters/test_redcarpet.rb +2 -0
  214. data/test/filters/test_redcloth.rb +2 -0
  215. data/test/filters/test_relativize_paths.rb +2 -0
  216. data/test/filters/test_rubypants.rb +2 -0
  217. data/test/filters/test_sass.rb +4 -2
  218. data/test/filters/test_slim.rb +4 -2
  219. data/test/filters/test_typogruby.rb +2 -0
  220. data/test/filters/test_uglify_js.rb +2 -0
  221. data/test/filters/test_xsl.rb +2 -0
  222. data/test/filters/test_yui_compressor.rb +5 -3
  223. data/test/helpers/test_blogging.rb +2 -0
  224. data/test/helpers/test_capturing.rb +2 -0
  225. data/test/helpers/test_link_to.rb +2 -0
  226. data/test/helpers/test_xml_sitemap.rb +2 -0
  227. data/test/rule_dsl/test_action_provider.rb +2 -0
  228. data/test/rule_dsl/test_compiler_dsl.rb +6 -4
  229. data/test/rule_dsl/test_rule.rb +2 -0
  230. data/test/rule_dsl/test_rules_collection.rb +2 -0
  231. data/test/test_gem.rb +2 -0
  232. metadata +124 -17
  233. data/test/base/test_item_rep.rb +0 -156
@@ -0,0 +1,72 @@
1
+ describe Nanoc::Helpers::Filtering, helper: true do
2
+ describe '#filter' do
3
+ before do
4
+ ctx.item = ctx.create_item('some content', { title: 'Hello!' }, '/about.md')
5
+ ctx.item_rep = ctx.create_rep(ctx.item, '/about.html')
6
+ end
7
+
8
+ let(:content) do
9
+ "A<% filter :erb do %><%%= 'X' %><% end %>B"
10
+ end
11
+
12
+ subject { ::ERB.new(content).result(helper.get_binding) }
13
+
14
+ context 'basic case' do
15
+ it { is_expected.to eql('AXB') }
16
+
17
+ it 'notifies' do
18
+ ns = Set.new
19
+ Nanoc::Int::NotificationCenter.on(:filtering_started) { ns << :filtering_started }
20
+ Nanoc::Int::NotificationCenter.on(:filtering_ended) { ns << :filtering_ended }
21
+
22
+ subject
23
+
24
+ expect(ns).to include(:filtering_started)
25
+ expect(ns).to include(:filtering_ended)
26
+ end
27
+ end
28
+
29
+ context 'with assigns' do
30
+ let(:content) do
31
+ 'A<% filter :erb do %><%%= @item[:title] %><% end %>B'
32
+ end
33
+
34
+ it { is_expected.to eql('AHello!B') }
35
+ end
36
+
37
+ context 'unknonwn filter name' do
38
+ let(:content) do
39
+ 'A<% filter :donkey do %>X<% end %>B'
40
+ end
41
+
42
+ it 'errors' do
43
+ expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownFilter)
44
+ end
45
+ end
46
+
47
+ context 'with locals' do
48
+ let(:content) do
49
+ "A<% filter :erb, locals: { sheep: 'baah' } do %><%%= @sheep %><% end %>B"
50
+ end
51
+
52
+ it { is_expected.to eql('AbaahB') }
53
+ end
54
+
55
+ context 'with Haml' do
56
+ let(:content) do
57
+ "%p Foo.\n" \
58
+ "- filter(:erb) do\n" \
59
+ " <%= 'abc' + 'xyz' %>\n" \
60
+ "%p Bar.\n"
61
+ end
62
+
63
+ before do
64
+ require 'haml'
65
+ end
66
+
67
+ subject { ::Haml::Engine.new(content).render(helper.get_binding) }
68
+
69
+ it { is_expected.to match(%r{^<p>Foo.</p>\s*abcxyz\s*<p>Bar.</p>$}) }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ describe Nanoc::Helpers::HTMLEscape, helper: true do
2
+ describe '#html_escape' do
3
+ subject { helper.html_escape(string) }
4
+
5
+ context 'given strings to escape' do
6
+ let(:string) { '< > & "' }
7
+ it { is_expected.to eql('&lt; &gt; &amp; &quot;') }
8
+ end
9
+
10
+ context 'given a block' do
11
+ let!(:_erbout) { 'moo' }
12
+
13
+ it 'adds escaped content to _erbout' do
14
+ helper.html_escape { _erbout << '<h1>Stuff!</h1>' }
15
+ expect(_erbout).to eql('moo&lt;h1&gt;Stuff!&lt;/h1&gt;')
16
+ end
17
+ end
18
+
19
+ context 'given no argument nor block' do
20
+ subject { helper.html_escape }
21
+
22
+ it 'raises' do
23
+ expect { subject }.to raise_error(RuntimeError)
24
+ end
25
+ end
26
+
27
+ context 'given argument that is not a string' do
28
+ let(:string) { 1 }
29
+
30
+ it 'raises an ArgumentError' do
31
+ expect { subject }.to raise_error(ArgumentError)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,275 @@
1
+ describe Nanoc::Helpers::LinkTo, helper: true do
2
+ describe '#link_to' do
3
+ subject { helper.link_to(text, target, attributes) }
4
+
5
+ let(:text) { 'Text' }
6
+ let(:target) { raise 'override me' }
7
+ let(:attributes) { {} }
8
+
9
+ context 'with string path' do
10
+ let(:target) { '/foo/' }
11
+ it { is_expected.to eql('<a href="/foo/">Text</a>') }
12
+
13
+ context 'with attributes' do
14
+ let(:attributes) { { title: 'Donkey' } }
15
+ it { is_expected.to eql('<a title="Donkey" href="/foo/">Text</a>') }
16
+ end
17
+
18
+ context 'special HTML characters in text' do
19
+ let(:text) { 'Foo &amp; Bar' }
20
+ it { is_expected.to eql('<a href="/foo/">Foo &amp; Bar</a>') }
21
+ # Not escaped!
22
+ end
23
+
24
+ context 'special HTML characters in URL' do
25
+ let(:target) { '/r&d/' }
26
+ it { is_expected.to eql('<a href="/r&amp;d/">Text</a>') }
27
+ end
28
+
29
+ context 'special HTML characters in attribute' do
30
+ let(:attributes) { { title: 'Research & Development' } }
31
+ it { is_expected.to eql('<a title="Research &amp; Development" href="/foo/">Text</a>') }
32
+ end
33
+ end
34
+
35
+ context 'with rep' do
36
+ let(:item) { ctx.create_item('content', {}, '/target/') }
37
+ let(:target) { ctx.create_rep(item, '/target.html') }
38
+
39
+ it { is_expected.to eql('<a href="/target.html">Text</a>') }
40
+ end
41
+
42
+ context 'with item' do
43
+ let(:target) { ctx.create_item('content', {}, '/target/') }
44
+
45
+ before do
46
+ ctx.create_rep(target, '/target.html')
47
+ end
48
+
49
+ it { is_expected.to eql('<a href="/target.html">Text</a>') }
50
+ end
51
+
52
+ context 'with nil' do
53
+ let(:target) { nil }
54
+
55
+ it 'raises' do
56
+ expect { subject }.to raise_error(ArgumentError)
57
+ end
58
+ end
59
+
60
+ context 'with something else' do
61
+ let(:target) { :donkey }
62
+
63
+ it 'raises' do
64
+ expect { subject }.to raise_error(ArgumentError)
65
+ end
66
+ end
67
+
68
+ context 'with nil path' do
69
+ let(:item) { ctx.create_item('content', {}, '/target/') }
70
+ let(:target) { ctx.create_rep(item, nil) }
71
+
72
+ it 'raises' do
73
+ expect { subject }.to raise_error(RuntimeError)
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#link_to_unless_current' do
79
+ subject { helper.link_to_unless_current(text, target, attributes) }
80
+
81
+ let(:text) { 'Text' }
82
+ let(:target) { raise 'override me' }
83
+ let(:attributes) { {} }
84
+
85
+ context 'with string path' do
86
+ let(:target) { '/target.html' }
87
+
88
+ context 'current' do
89
+ before do
90
+ ctx.item = ctx.create_item('content', {}, '/target.md')
91
+ ctx.item_rep = ctx.create_rep(ctx.item, '/target.html')
92
+ end
93
+
94
+ it { is_expected.to eql('<span class="active">Text</span>') }
95
+ end
96
+
97
+ context 'no item rep present' do
98
+ it { is_expected.to eql('<a href="/target.html">Text</a>') }
99
+ end
100
+
101
+ context 'item rep present, but not current' do
102
+ before do
103
+ ctx.item = ctx.create_item('content', {}, '/other.md')
104
+ ctx.item_rep = ctx.create_rep(ctx.item, '/other.html')
105
+ end
106
+
107
+ it { is_expected.to eql('<a href="/target.html">Text</a>') }
108
+ end
109
+ end
110
+
111
+ context 'with rep' do
112
+ before do
113
+ ctx.item = ctx.create_item('content', {}, '/target.md')
114
+ ctx.item_rep = ctx.create_rep(ctx.item, '/target.html')
115
+ end
116
+
117
+ let(:some_item) { ctx.create_item('content', {}, '/other.md') }
118
+ let(:some_item_rep) { ctx.create_rep(some_item, '/other.html') }
119
+
120
+ context 'current' do
121
+ let(:target) { ctx.item_rep }
122
+ it { is_expected.to eql('<span class="active">Text</span>') }
123
+ end
124
+
125
+ context 'no item rep present' do
126
+ let(:target) { some_item_rep }
127
+
128
+ before do
129
+ ctx.item = nil
130
+ ctx.item_rep = nil
131
+ end
132
+
133
+ it { is_expected.to eql('<a href="/other.html">Text</a>') }
134
+ end
135
+
136
+ context 'item rep present, but not current' do
137
+ let(:target) { some_item_rep }
138
+ it { is_expected.to eql('<a href="/other.html">Text</a>') }
139
+ end
140
+ end
141
+
142
+ context 'with item' do
143
+ before do
144
+ ctx.item = ctx.create_item('content', {}, '/target.md')
145
+ ctx.item_rep = ctx.create_rep(ctx.item, '/target.html')
146
+ end
147
+
148
+ let!(:some_item) { ctx.create_item('content', {}, '/other.md') }
149
+ let!(:some_item_rep) { ctx.create_rep(some_item, '/other.html') }
150
+
151
+ context 'current' do
152
+ let(:target) { ctx.item }
153
+ it { is_expected.to eql('<span class="active">Text</span>') }
154
+ end
155
+
156
+ context 'no item rep present' do
157
+ let(:target) { some_item }
158
+
159
+ before do
160
+ ctx.item = nil
161
+ ctx.item_rep = nil
162
+ end
163
+
164
+ it { is_expected.to eql('<a href="/other.html">Text</a>') }
165
+ end
166
+
167
+ context 'item rep present, but not current' do
168
+ let(:target) { some_item }
169
+ it { is_expected.to eql('<a href="/other.html">Text</a>') }
170
+ end
171
+ end
172
+ end
173
+
174
+ describe '#relative_path_to' do
175
+ subject { helper.relative_path_to(target) }
176
+
177
+ before do
178
+ ctx.item = ctx.create_item('content', {}, '/foo/self.md')
179
+ ctx.item_rep = ctx.create_rep(ctx.item, self_path)
180
+ end
181
+
182
+ context 'current item rep has non-nil path' do
183
+ let(:self_path) { '/foo/self.html' }
184
+
185
+ context 'to string path' do
186
+ context 'to relative path' do
187
+ let(:target) { 'bar/target.html' }
188
+
189
+ it 'errors' do
190
+ # TODO: Might make sense to allow this case (and return the path itself)
191
+ expect { subject }.to raise_error(ArgumentError)
192
+ end
193
+ end
194
+
195
+ context 'to path without trailing slash' do
196
+ let(:target) { '/bar/target.html' }
197
+ it { is_expected.to eql('../bar/target.html') }
198
+ end
199
+
200
+ context 'to path with trailing slash' do
201
+ let(:target) { '/bar/target/' }
202
+ it { is_expected.to eql('../bar/target/') }
203
+ end
204
+
205
+ context 'to Windows/UNC path (forward slashes)' do
206
+ let(:target) { '//foo' }
207
+ it { is_expected.to eql('//foo') }
208
+ end
209
+
210
+ context 'to Windows/UNC path (backslashes)' do
211
+ let(:target) { '\\\\foo' }
212
+ it { is_expected.to eql('\\\\foo') }
213
+ end
214
+ end
215
+
216
+ context 'to rep' do
217
+ let(:target) { ctx.create_rep(ctx.item, '/bar/target.html') }
218
+ it { is_expected.to eql('../bar/target.html') }
219
+
220
+ context 'to self' do
221
+ let(:target) { ctx.item_rep }
222
+
223
+ context 'self is a filename' do
224
+ it { is_expected.to eql('self.html') }
225
+ end
226
+
227
+ context 'self is a directory' do
228
+ let(:self_path) { '/foo/self/' }
229
+ it { is_expected.to eql('./') }
230
+ end
231
+ end
232
+ end
233
+
234
+ context 'to item' do
235
+ let(:target) { ctx.create_item('content', {}, '/bar/target.md') }
236
+
237
+ before do
238
+ ctx.create_rep(target, '/bar/target.html')
239
+ end
240
+
241
+ it { is_expected.to eql('../bar/target.html') }
242
+
243
+ context 'to self' do
244
+ let(:target) { ctx.item }
245
+
246
+ context 'self is a filename' do
247
+ it { is_expected.to eql('self.html') }
248
+ end
249
+
250
+ context 'self is a directory' do
251
+ let(:self_path) { '/foo/self/' }
252
+ it { is_expected.to eql('./') }
253
+ end
254
+ end
255
+ end
256
+
257
+ context 'to nil path' do
258
+ let(:target) { ctx.create_rep(ctx.item, nil) }
259
+
260
+ it 'raises' do
261
+ expect { subject }.to raise_error(RuntimeError)
262
+ end
263
+ end
264
+ end
265
+
266
+ context 'current item rep has nil path' do
267
+ let(:self_path) { nil }
268
+ let(:target) { '/bar/target.html' }
269
+
270
+ it 'errors' do
271
+ expect { subject }.to raise_error(RuntimeError)
272
+ end
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,141 @@
1
+ describe Nanoc::Helpers::Rendering, helper: true do
2
+ describe '#render' do
3
+ subject { helper.instance_eval { render('/partial.erb') } }
4
+
5
+ let(:rule_memory_for_layout) do
6
+ [Nanoc::Int::ProcessingActions::Filter.new(:erb, {})]
7
+ end
8
+
9
+ let(:layout_view) do
10
+ ctx.create_layout(layout_content, {}, layout_identifier)
11
+ end
12
+
13
+ let(:layout) do
14
+ layout_view.unwrap
15
+ end
16
+
17
+ before do
18
+ ctx.update_rule_memory(layout, rule_memory_for_layout)
19
+ end
20
+
21
+ context 'legacy identifier' do
22
+ let(:layout_identifier) { Nanoc::Identifier.new('/partial/', type: :legacy) }
23
+
24
+ context 'cleaned identifier' do
25
+ subject { helper.instance_eval { render('/partial/') } }
26
+
27
+ context 'layout without instructions' do
28
+ let(:layout_content) { 'blah' }
29
+
30
+ it { is_expected.to eql('blah') }
31
+
32
+ it 'tracks proper dependencies' do
33
+ expect(ctx.dependency_tracker).to receive(:enter)
34
+ .with(layout, raw_content: true, attributes: false, compiled_content: false, path: false)
35
+ subject
36
+ end
37
+ end
38
+
39
+ context 'layout with instructions' do
40
+ let(:layout_content) { 'blah <%= @layout.identifier %>' }
41
+ it { is_expected.to eql('blah /partial/') }
42
+ end
43
+ end
44
+
45
+ context 'non-cleaned identifier' do
46
+ subject { helper.instance_eval { render('/partial') } }
47
+
48
+ context 'layout without instructions' do
49
+ let(:layout_content) { 'blah' }
50
+ it { is_expected.to eql('blah') }
51
+ end
52
+
53
+ context 'layout with instructions' do
54
+ let(:layout_content) { 'blah <%= @layout.identifier %>' }
55
+ it { is_expected.to eql('blah /partial/') }
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'full-style identifier' do
61
+ let(:layout_identifier) { Nanoc::Identifier.new('/partial.erb') }
62
+
63
+ context 'layout without instructions' do
64
+ let(:layout_content) { 'blah' }
65
+ it { is_expected.to eql('blah') }
66
+ end
67
+
68
+ context 'layout with instructions' do
69
+ let(:layout_content) { 'blah <%= @layout.identifier %>' }
70
+ it { is_expected.to eql('blah /partial.erb') }
71
+ end
72
+
73
+ context 'printing wrapped layout class' do
74
+ let(:layout_content) { 'blah <%= @layout.class %>' }
75
+ it { is_expected.to eql('blah Nanoc::LayoutView') }
76
+ end
77
+
78
+ context 'printing unwrapped layout class' do
79
+ let(:layout_content) { 'blah <%= @layout.unwrap.class %>' }
80
+ it { is_expected.to eql('blah Nanoc::Int::Layout') }
81
+ end
82
+
83
+ context 'unknown layout' do
84
+ subject { helper.instance_eval { render('/unknown.erb') } }
85
+
86
+ let(:layout_content) { 'blah' }
87
+
88
+ it 'raises' do
89
+ expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownLayout)
90
+ end
91
+ end
92
+
93
+ context 'layout with unknown filter' do
94
+ let(:rule_memory_for_layout) do
95
+ [Nanoc::Int::ProcessingActions::Filter.new(:donkey, {})]
96
+ end
97
+
98
+ let(:layout_content) { 'blah' }
99
+
100
+ it 'raises' do
101
+ expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownFilter)
102
+ end
103
+ end
104
+
105
+ context 'layout without filter' do
106
+ let(:rule_memory_for_layout) do
107
+ [Nanoc::Int::ProcessingActions::Filter.new(nil, {})]
108
+ end
109
+
110
+ let(:layout_content) { 'blah' }
111
+
112
+ it 'raises' do
113
+ expect { subject }.to raise_error(Nanoc::Int::Errors::CannotDetermineFilter)
114
+ end
115
+ end
116
+
117
+ context 'with block' do
118
+ subject do
119
+ helper.instance_eval do
120
+ render('/partial.erb') { _erbout << 'extra content' }
121
+ end
122
+ end
123
+
124
+ before do
125
+ ctx.erbout << '[erbout-before]'
126
+ end
127
+
128
+ let(:layout_content) { '[partial-before]<%= yield %>[partial-after]' }
129
+
130
+ it 'returns an empty string' do
131
+ expect(subject).to eql('')
132
+ end
133
+
134
+ it 'modifies erbout' do
135
+ subject
136
+ expect(ctx.erbout).to eql('[erbout-before][partial-before]extra content[partial-after]')
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,104 @@
1
+ describe Nanoc::Helpers::Tagging, helper: true do
2
+ describe '#tags_for' do
3
+ subject { helper.tags_for(item, params) }
4
+
5
+ let(:item) { ctx.items['/me.*'] }
6
+ let(:params) { {} }
7
+ let(:item_attributes) { {} }
8
+
9
+ before do
10
+ ctx.create_item('content', item_attributes, '/me.md')
11
+ end
12
+
13
+ context 'no tags' do
14
+ let(:item_attributes) { {} }
15
+ it { is_expected.to eql('(none)') }
16
+ end
17
+
18
+ context 'nil tag list' do
19
+ let(:item_attributes) { { tags: nil } }
20
+ it { is_expected.to eql('(none)') }
21
+ end
22
+
23
+ context 'empty tag list' do
24
+ let(:item_attributes) { { tags: [] } }
25
+ it { is_expected.to eql('(none)') }
26
+ end
27
+
28
+ context 'no tags, and custom none text' do
29
+ let(:item_attributes) { {} }
30
+ let(:params) { { none_text: 'no tags for you, fool' } }
31
+ it { is_expected.to eql('no tags for you, fool') }
32
+ end
33
+
34
+ context 'one tag' do
35
+ let(:item_attributes) { { tags: %w(donkey) } }
36
+
37
+ context 'implicit base_url' do
38
+ it { is_expected.to eql('donkey') }
39
+ end
40
+
41
+ context 'explicit nil base_url' do
42
+ let(:params) { { base_url: nil } }
43
+ it { is_expected.to eql('donkey') }
44
+ end
45
+
46
+ context 'explicit other base_url' do
47
+ let(:params) { { base_url: 'http://nanoc.ws/tag/' } }
48
+ it { is_expected.to eql('<a href="http://nanoc.ws/tag/donkey" rel="tag">donkey</a>') }
49
+ end
50
+ end
51
+
52
+ context 'two tags' do
53
+ let(:item_attributes) { { tags: %w(donkey giraffe) } }
54
+ it { is_expected.to eql('donkey, giraffe') }
55
+ end
56
+
57
+ context 'three tags' do
58
+ let(:item_attributes) { { tags: %w(donkey giraffe zebra) } }
59
+ it { is_expected.to eql('donkey, giraffe, zebra') }
60
+
61
+ context 'custom separator' do
62
+ let(:item_attributes) { { tags: %w(donkey giraffe zebra) } }
63
+ let(:params) { { separator: ' / ' } }
64
+ it { is_expected.to eql('donkey / giraffe / zebra') }
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#items_with_tag' do
70
+ subject { helper.items_with_tag(tag) }
71
+
72
+ before do
73
+ ctx.create_item('item 1', { tags: [:foo] }, '/item1.md')
74
+ ctx.create_item('item 2', { tags: [:bar] }, '/item2.md')
75
+ ctx.create_item('item 3', { tags: [:foo, :bar] }, '/item3.md')
76
+ ctx.create_item('item 4', { tags: nil }, '/item4.md')
77
+ ctx.create_item('item 5', {}, '/item5.md')
78
+ end
79
+
80
+ context 'tag that exists' do
81
+ let(:tag) { :foo }
82
+ it { is_expected.to contain_exactly(ctx.items['/item1.md'], ctx.items['/item3.md']) }
83
+ end
84
+
85
+ context 'tag that does not exists' do
86
+ let(:tag) { :other }
87
+ it { is_expected.to be_empty }
88
+ end
89
+ end
90
+
91
+ describe '#link_for_tag' do
92
+ subject { helper.link_for_tag(tag, base_url) }
93
+
94
+ let(:tag) { 'foo' }
95
+ let(:base_url) { 'http://nanoc.ws/tag/' }
96
+
97
+ it { is_expected.to eql('<a href="http://nanoc.ws/tag/foo" rel="tag">foo</a>') }
98
+
99
+ context 'tag with special HTML characters' do
100
+ let(:tag) { 'R&D' }
101
+ it { is_expected.to eql('<a href="http://nanoc.ws/tag/R&amp;D" rel="tag">R&amp;D</a>') }
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,58 @@
1
+ describe Nanoc::Helpers::Text, helper: true do
2
+ describe '#excerptize' do
3
+ subject { helper.excerptize(string, params) }
4
+
5
+ let(:string) { 'Foo bar baz quux meow woof' }
6
+ let(:params) { {} }
7
+
8
+ context 'no params' do
9
+ it 'takes 25 characters' do
10
+ expect(subject).to eql('Foo bar baz quux meow ...')
11
+ end
12
+ end
13
+
14
+ context 'perfect fit' do
15
+ let(:params) { { length: 26 } }
16
+
17
+ it 'does not truncate' do
18
+ expect(subject).to eql('Foo bar baz quux meow woof')
19
+ end
20
+ end
21
+
22
+ context 'long length' do
23
+ let(:params) { { length: 27 } }
24
+
25
+ it 'does not truncate' do
26
+ expect(subject).to eql('Foo bar baz quux meow woof')
27
+ end
28
+ end
29
+
30
+ context 'short length' do
31
+ let(:params) { { length: 3 } }
32
+
33
+ it 'truncates' do
34
+ expect(subject).to eql('...')
35
+ end
36
+ end
37
+
38
+ context 'length shorter than omission' do
39
+ let(:params) { { length: 2 } }
40
+
41
+ it 'truncates, disregarding length' do
42
+ expect(subject).to eql('...')
43
+ end
44
+ end
45
+
46
+ context 'custom omission' do
47
+ let(:params) { { omission: '[continued]' } }
48
+
49
+ it 'uses custom omission string' do
50
+ expect(subject).to eql('Foo bar baz qu[continued]')
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#strip_html' do
56
+ # TODO: test this… or get rid of it (it’s bad!)
57
+ end
58
+ end