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,55 @@
1
+ describe Nanoc::Int::CompiledContentCache do
2
+ let(:cache) { described_class.new(items: items) }
3
+
4
+ let(:items) { [item] }
5
+
6
+ let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
7
+ let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
8
+
9
+ let(:other_item) { Nanoc::Int::Item.new('asdf', {}, '/sneaky.md') }
10
+ let(:other_item_rep) { Nanoc::Int::ItemRep.new(other_item, :default) }
11
+
12
+ let(:content) { Nanoc::Int::Content.create('omg') }
13
+
14
+ it 'has no content by default' do
15
+ expect(cache[item_rep]).to be_nil
16
+ end
17
+
18
+ context 'setting content on known item' do
19
+ before { cache[item_rep] = { last: content } }
20
+
21
+ it 'has content' do
22
+ expect(cache[item_rep][:last].string).to eql('omg')
23
+ end
24
+
25
+ context 'after storing and loading' do
26
+ before do
27
+ cache.store
28
+ cache.load
29
+ end
30
+
31
+ it 'has content' do
32
+ expect(cache[item_rep][:last].string).to eql('omg')
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'setting content on unknown item' do
38
+ before { cache[other_item_rep] = { last: content } }
39
+
40
+ it 'has content' do
41
+ expect(cache[other_item_rep][:last].string).to eql('omg')
42
+ end
43
+
44
+ context 'after storing and loading' do
45
+ before do
46
+ cache.store
47
+ cache.load
48
+ end
49
+
50
+ it 'has no content' do
51
+ expect(cache[other_item_rep]).to be_nil
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,243 @@
1
+ describe Nanoc::Int::ConfigLoader do
2
+ let(:loader) { described_class.new }
3
+
4
+ describe '#new_from_cwd' do
5
+ subject { loader.new_from_cwd }
6
+
7
+ context 'no config file present' do
8
+ it 'errors' do
9
+ expect { subject }.to raise_error(
10
+ Nanoc::Int::ConfigLoader::NoConfigFileFoundError,
11
+ )
12
+ end
13
+ end
14
+
15
+ context 'config file present' do
16
+ before do
17
+ File.write('nanoc.yaml', YAML.dump(foo: 'bar'))
18
+ end
19
+
20
+ it 'returns a configuration' do
21
+ expect(subject).to be_a(Nanoc::Int::Configuration)
22
+ end
23
+
24
+ it 'has the defaults' do
25
+ expect(subject[:output_dir]).to eq('output')
26
+ end
27
+
28
+ it 'has the custom option' do
29
+ expect(subject[:foo]).to eq('bar')
30
+ end
31
+ end
32
+
33
+ context 'config file and parent present' do
34
+ before do
35
+ File.write('nanoc.yaml', YAML.dump(parent_config_file: 'parent.yaml'))
36
+ File.write('parent.yaml', YAML.dump(foo: 'bar'))
37
+ end
38
+
39
+ it 'returns the configuration' do
40
+ expect(subject).to be_a(Nanoc::Int::Configuration)
41
+ end
42
+
43
+ it 'has the defaults' do
44
+ expect(subject[:output_dir]).to eq('output')
45
+ end
46
+
47
+ it 'has the custom option' do
48
+ expect(subject[:foo]).to eq('bar')
49
+ end
50
+
51
+ it 'does not include parent config option' do
52
+ expect(subject[:parent_config_file]).to be_nil
53
+ end
54
+ end
55
+
56
+ context 'config file present, environment defined' do
57
+ let(:active_env_name) { 'default' }
58
+
59
+ let(:config) do
60
+ {
61
+ foo: 'bar',
62
+ tofoo: 'bar',
63
+ environments: {
64
+ test: { foo: 'test-bar' },
65
+ default: { foo: 'default-bar' },
66
+ },
67
+ }
68
+ end
69
+
70
+ before do
71
+ File.write('nanoc.yaml', YAML.dump(config))
72
+ end
73
+
74
+ before do
75
+ expect(ENV).to receive(:fetch).with('NANOC_ENV', 'default').and_return(active_env_name)
76
+ end
77
+
78
+ it 'returns the configuration' do
79
+ expect(subject).to be_a(Nanoc::Int::Configuration)
80
+ end
81
+
82
+ it 'has option defined not within environments' do
83
+ expect(subject[:tofoo]).to eq('bar')
84
+ end
85
+
86
+ context 'current env is test' do
87
+ let(:active_env_name) { 'test' }
88
+
89
+ it 'has the test environment custom option' do
90
+ expect(subject[:foo]).to eq('test-bar')
91
+ end
92
+ end
93
+
94
+ it 'has the default environment custom option' do
95
+ expect(subject[:foo]).to eq('default-bar')
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '.cwd_is_nanoc_site? + .config_filename_for_cwd' do
101
+ context 'no config files' do
102
+ it 'is not considered a nanoc site dir' do
103
+ expect(described_class.cwd_is_nanoc_site?).to eq(false)
104
+ expect(described_class.config_filename_for_cwd).to be_nil
105
+ end
106
+ end
107
+
108
+ context 'nanoc.yaml config file' do
109
+ before do
110
+ File.write('nanoc.yaml', 'stuff')
111
+ end
112
+
113
+ it 'is considered a nanoc site dir' do
114
+ expect(described_class.cwd_is_nanoc_site?).to eq(true)
115
+ expect(described_class.config_filename_for_cwd).to eq(File.expand_path('nanoc.yaml'))
116
+ end
117
+ end
118
+
119
+ context 'config.yaml config file' do
120
+ before do
121
+ File.write('config.yaml', 'stuff')
122
+ end
123
+
124
+ it 'is considered a nanoc site dir' do
125
+ expect(described_class.cwd_is_nanoc_site?).to eq(true)
126
+ expect(described_class.config_filename_for_cwd).to eq(File.expand_path('config.yaml'))
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#apply_parent_config' do
132
+ subject { loader.apply_parent_config(config, processed_paths) }
133
+
134
+ let(:config) { Nanoc::Int::Configuration.new(hash: { foo: 'bar' }) }
135
+
136
+ let(:processed_paths) { ['nanoc.yaml'] }
137
+
138
+ context 'no parent_config_file' do
139
+ it 'returns self' do
140
+ expect(subject).to eq(config)
141
+ end
142
+ end
143
+
144
+ context 'parent config file is set' do
145
+ let(:config) do
146
+ Nanoc::Int::Configuration.new(hash: { parent_config_file: 'foo.yaml', foo: 'bar' })
147
+ end
148
+
149
+ context 'parent config file is not present' do
150
+ it 'errors' do
151
+ expect { subject }.to raise_error(
152
+ Nanoc::Int::ConfigLoader::NoParentConfigFileFoundError,
153
+ )
154
+ end
155
+ end
156
+
157
+ context 'parent config file is present' do
158
+ context 'parent-child cycle' do
159
+ before do
160
+ File.write('foo.yaml', 'parent_config_file: bar.yaml')
161
+ File.write('bar.yaml', 'parent_config_file: foo.yaml')
162
+ end
163
+
164
+ it 'errors' do
165
+ expect { subject }.to raise_error(
166
+ Nanoc::Int::ConfigLoader::CyclicalConfigFileError,
167
+ )
168
+ end
169
+ end
170
+
171
+ context 'self parent-child cycle' do
172
+ before do
173
+ File.write('foo.yaml', 'parent_config_file: foo.yaml')
174
+ end
175
+
176
+ it 'errors' do
177
+ expect { subject }.to raise_error(
178
+ Nanoc::Int::ConfigLoader::CyclicalConfigFileError,
179
+ )
180
+ end
181
+ end
182
+
183
+ context 'no parent-child cycle' do
184
+ before do
185
+ File.write('foo.yaml', 'animal: giraffe')
186
+ end
187
+
188
+ it 'returns a configuration' do
189
+ expect(subject).to be_a(Nanoc::Int::Configuration)
190
+ end
191
+
192
+ it 'has no defaults (added in #new_from_cwd only)' do
193
+ expect(subject[:output_dir]).to be_nil
194
+ end
195
+
196
+ it 'inherits options from parent' do
197
+ expect(subject[:animal]).to eq('giraffe')
198
+ end
199
+
200
+ it 'takes options from child' do
201
+ expect(subject[:foo]).to eq('bar')
202
+ end
203
+
204
+ it 'does not include parent config option' do
205
+ expect(subject[:parent_config_file]).to be_nil
206
+ end
207
+ end
208
+
209
+ context 'long parent chain' do
210
+ before do
211
+ File.write('foo.yaml', "parrots: 43\nparent_config_file: bar.yaml\n")
212
+ File.write('bar.yaml', "day_one: lasers\nslugs: false\n")
213
+ end
214
+
215
+ it 'returns a configuration' do
216
+ expect(subject).to be_a(Nanoc::Int::Configuration)
217
+ end
218
+
219
+ it 'has no defaults (added in #new_from_cwd only)' do
220
+ expect(subject[:output_dir]).to be_nil
221
+ end
222
+
223
+ it 'inherits options from grandparent' do
224
+ expect(subject[:day_one]).to eq('lasers')
225
+ expect(subject[:slugs]).to eq(false)
226
+ end
227
+
228
+ it 'inherits options from parent' do
229
+ expect(subject[:parrots]).to eq(43)
230
+ end
231
+
232
+ it 'takes options from child' do
233
+ expect(subject[:foo]).to eq('bar')
234
+ end
235
+
236
+ it 'does not include parent config option' do
237
+ expect(subject[:parent_config_file]).to be_nil
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,195 @@
1
+ describe Nanoc::Int::DependencyStore do
2
+ let(:store) { described_class.new(objects) }
3
+
4
+ let(:objects) do
5
+ [obj_a, obj_b, obj_c]
6
+ end
7
+
8
+ let(:obj_a) { Nanoc::Int::Item.new('a', {}, '/a.md') }
9
+ let(:obj_b) { Nanoc::Int::Item.new('b', {}, '/b.md') }
10
+ let(:obj_c) { Nanoc::Int::Item.new('c', {}, '/c.md') }
11
+
12
+ describe '#dependencies_causing_outdatedness_of' do
13
+ context 'no dependencies' do
14
+ it 'returns nothing for each' do
15
+ expect(store.dependencies_causing_outdatedness_of(obj_a)).to be_empty
16
+ expect(store.dependencies_causing_outdatedness_of(obj_b)).to be_empty
17
+ expect(store.dependencies_causing_outdatedness_of(obj_c)).to be_empty
18
+ end
19
+ end
20
+
21
+ context 'one dependency' do
22
+ context 'no props' do
23
+ before do
24
+ # FIXME: weird argument order (obj_b depends on obj_a, not th other way around)
25
+ store.record_dependency(obj_a, obj_b)
26
+ end
27
+
28
+ it 'returns one dependency' do
29
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
30
+ expect(deps.size).to eql(1)
31
+ end
32
+
33
+ it 'returns dependency from b to a' do
34
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
35
+ expect(deps[0].from).to eql(obj_b)
36
+ expect(deps[0].to).to eql(obj_a)
37
+ end
38
+
39
+ it 'returns true for all props by default' do
40
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
41
+ expect(deps[0].props.raw_content?).to eq(true)
42
+ expect(deps[0].props.attributes?).to eq(true)
43
+ expect(deps[0].props.compiled_content?).to eq(true)
44
+ expect(deps[0].props.path?).to eq(true)
45
+ end
46
+
47
+ it 'returns nothing for the others' do
48
+ expect(store.dependencies_causing_outdatedness_of(obj_b)).to be_empty
49
+ expect(store.dependencies_causing_outdatedness_of(obj_c)).to be_empty
50
+ end
51
+ end
52
+
53
+ context 'one prop' do
54
+ before do
55
+ # FIXME: weird argument order (obj_b depends on obj_a, not th other way around)
56
+ store.record_dependency(obj_a, obj_b, compiled_content: true)
57
+ end
58
+
59
+ it 'returns false for all unspecified props' do
60
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
61
+ expect(deps[0].props.raw_content?).to eq(false)
62
+ expect(deps[0].props.attributes?).to eq(false)
63
+ expect(deps[0].props.path?).to eq(false)
64
+ end
65
+
66
+ it 'returns the specified props' do
67
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
68
+ expect(deps[0].props.compiled_content?).to eq(true)
69
+ end
70
+ end
71
+
72
+ context 'two props' do
73
+ before do
74
+ # FIXME: weird argument order (obj_b depends on obj_a, not th other way around)
75
+ store.record_dependency(obj_a, obj_b, compiled_content: true)
76
+ store.record_dependency(obj_a, obj_b, attributes: true)
77
+ end
78
+
79
+ it 'returns false for all unspecified props' do
80
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
81
+ expect(deps[0].props.raw_content?).to eq(false)
82
+ expect(deps[0].props.path?).to eq(false)
83
+ end
84
+
85
+ it 'returns the specified props' do
86
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
87
+ expect(deps[0].props.attributes?).to eq(true)
88
+ expect(deps[0].props.compiled_content?).to eq(true)
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'two dependency in a chain' do
94
+ before do
95
+ # FIXME: weird argument order (obj_b depends on obj_a, not th other way around)
96
+ store.record_dependency(obj_a, obj_b)
97
+ store.record_dependency(obj_b, obj_c)
98
+ end
99
+
100
+ it 'returns one dependency for object A' do
101
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
102
+ expect(deps.size).to eql(1)
103
+ expect(deps[0].from).to eql(obj_b)
104
+ end
105
+
106
+ it 'returns one dependency for object B' do
107
+ deps = store.dependencies_causing_outdatedness_of(obj_b)
108
+ expect(deps.size).to eql(1)
109
+ expect(deps[0].from).to eql(obj_c)
110
+ end
111
+
112
+ it 'returns nothing for the others' do
113
+ expect(store.dependencies_causing_outdatedness_of(obj_c)).to be_empty
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'reloading' do
119
+ before do
120
+ store.record_dependency(obj_a, obj_b, compiled_content: true)
121
+ store.record_dependency(obj_a, obj_b, attributes: true)
122
+
123
+ store.store
124
+ store.objects = objects_after
125
+ store.load
126
+ end
127
+
128
+ context 'no new objects' do
129
+ let(:objects_after) { objects }
130
+
131
+ it 'has the right dependencies for item A' do
132
+ deps = store.dependencies_causing_outdatedness_of(obj_a)
133
+ expect(deps.size).to eql(1)
134
+
135
+ expect(deps[0].from).to eql(obj_b)
136
+ expect(deps[0].to).to eql(obj_a)
137
+
138
+ expect(deps[0].props.raw_content?).to eq(false)
139
+ expect(deps[0].props.attributes?).to eq(true)
140
+ expect(deps[0].props.compiled_content?).to eq(true)
141
+ expect(deps[0].props.path?).to eq(false)
142
+ end
143
+
144
+ it 'has the right dependencies for item B' do
145
+ deps = store.dependencies_causing_outdatedness_of(obj_b)
146
+ expect(deps).to be_empty
147
+ end
148
+
149
+ it 'has the right dependencies for item C' do
150
+ deps = store.dependencies_causing_outdatedness_of(obj_c)
151
+ expect(deps).to be_empty
152
+ end
153
+ end
154
+
155
+ context 'one new object' do
156
+ let(:objects_after) do
157
+ [obj_a, obj_b, obj_c, obj_d]
158
+ end
159
+
160
+ let(:obj_d) { Nanoc::Int::Item.new('d', {}, '/d.md') }
161
+
162
+ it 'marks existing items as outdated' do
163
+ expect(store.objects_causing_outdatedness_of(obj_a)).to eq([obj_d])
164
+ expect(store.objects_causing_outdatedness_of(obj_b)).to eq([obj_d])
165
+ expect(store.objects_causing_outdatedness_of(obj_c)).to eq([obj_d])
166
+ end
167
+
168
+ it 'marks new items as outdated' do
169
+ expect(store.objects_causing_outdatedness_of(obj_d)).to eq([obj_d])
170
+ end
171
+ end
172
+
173
+ context 'two new objects' do
174
+ let(:objects_after) do
175
+ [obj_a, obj_b, obj_c, obj_d, obj_e]
176
+ end
177
+
178
+ let(:obj_d) { Nanoc::Int::Item.new('d', {}, '/d.md') }
179
+ let(:obj_e) { Nanoc::Int::Item.new('e', {}, '/e.md') }
180
+
181
+ it 'marks existing items as outdated' do
182
+ # Only one of obj D or E needed!
183
+ expect(store.objects_causing_outdatedness_of(obj_a)).to eq([obj_d]).or eq([obj_e])
184
+ expect(store.objects_causing_outdatedness_of(obj_b)).to eq([obj_d]).or eq([obj_e])
185
+ expect(store.objects_causing_outdatedness_of(obj_c)).to eq([obj_d]).or eq([obj_e])
186
+ end
187
+
188
+ it 'marks new items as outdated' do
189
+ # Only one of obj D or E needed!
190
+ expect(store.objects_causing_outdatedness_of(obj_d)).to eq([obj_d]).or eq([obj_e])
191
+ expect(store.objects_causing_outdatedness_of(obj_e)).to eq([obj_d]).or eq([obj_e])
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,214 @@
1
+ describe Nanoc::Int::SiteLoader do
2
+ let(:loader) { described_class.new }
3
+
4
+ describe '#new_empty' do
5
+ subject { loader.new_empty }
6
+
7
+ it 'has the default configuration' do
8
+ expect(subject.config).to be_a(Nanoc::Int::Configuration)
9
+ expect(subject.config[:index_filenames]).to eq(['index.html'])
10
+ end
11
+
12
+ it 'has no code snippets' do
13
+ expect(subject.code_snippets).to be_empty
14
+ end
15
+
16
+ it 'has no items' do
17
+ expect(subject.items).to be_empty
18
+ end
19
+
20
+ it 'has no layouts' do
21
+ expect(subject.layouts).to be_empty
22
+ end
23
+ end
24
+
25
+ describe '#new_with_config' do
26
+ subject { loader.new_with_config(arg) }
27
+
28
+ let(:arg) { { foo: 'bar' } }
29
+
30
+ it 'has a slightly modified configuration' do
31
+ expect(subject.config).to be_a(Nanoc::Int::Configuration)
32
+ expect(subject.config[:index_filenames]).to eq(['index.html'])
33
+ expect(subject.config[:foo]).to eq('bar')
34
+ end
35
+
36
+ it 'has no code snippets' do
37
+ expect(subject.code_snippets).to be_empty
38
+ end
39
+
40
+ it 'has no items' do
41
+ expect(subject.items).to be_empty
42
+ end
43
+
44
+ it 'has no layouts' do
45
+ expect(subject.layouts).to be_empty
46
+ end
47
+ end
48
+
49
+ describe '#new_from_cwd' do
50
+ subject { loader.new_from_cwd }
51
+
52
+ context 'no config file' do
53
+ it 'errors' do
54
+ expect { subject }.to raise_error(
55
+ Nanoc::Int::ConfigLoader::NoConfigFileFoundError,
56
+ )
57
+ end
58
+ end
59
+
60
+ shared_examples 'a directory with a config file' do
61
+ it 'has the default configuration' do
62
+ expect(subject.config).to be_a(Nanoc::Int::Configuration)
63
+ expect(subject.config[:index_filenames]).to eq(['index.html'])
64
+ expect(subject.config[:foo]).to eq('bar')
65
+ end
66
+
67
+ it 'has no code snippets' do
68
+ expect(subject.code_snippets).to be_empty
69
+ end
70
+
71
+ it 'has no items' do
72
+ expect(subject.items).to be_empty
73
+ end
74
+
75
+ it 'has no layouts' do
76
+ expect(subject.layouts).to be_empty
77
+ end
78
+
79
+ context 'some items, layouts, and code snippets' do
80
+ before do
81
+ FileUtils.mkdir_p('lib')
82
+ File.write('lib/foo.rb', '$spirit_animal = :donkey')
83
+
84
+ FileUtils.mkdir_p('content')
85
+ File.write('content/about.md', 'I am Denis!')
86
+
87
+ FileUtils.mkdir_p('layouts')
88
+ File.write('layouts/page.erb', '<html><%= yield %></html>')
89
+ end
90
+
91
+ it 'has a code snippet' do
92
+ expect(subject.code_snippets.size).to eq(1)
93
+ expect(subject.code_snippets[0].data).to eq('$spirit_animal = :donkey')
94
+ end
95
+
96
+ it 'has an item' do
97
+ expect(subject.items.size).to eq(1)
98
+ expect(subject.items['/about.md'].content).to be_a(Nanoc::Int::TextualContent)
99
+ expect(subject.items['/about.md'].content.string).to eq('I am Denis!')
100
+ expect(subject.items['/about.md'].attributes[:content_filename])
101
+ .to eq('content/about.md')
102
+ expect(subject.items['/about.md'].attributes[:extension])
103
+ .to eq('md')
104
+ expect(subject.items['/about.md'].attributes[:filename])
105
+ .to eq('content/about.md')
106
+ expect(subject.items['/about.md'].attributes[:meta_filename])
107
+ .to be_nil
108
+ expect(subject.items['/about.md'].attributes[:mtime])
109
+ .to be > Time.now - 5
110
+ expect(subject.items['/about.md'].identifier.to_s).to eq('/about.md')
111
+ end
112
+
113
+ it 'has a layout' do
114
+ expect(subject.layouts.size).to eq(1)
115
+ expect(subject.layouts['/page.erb'].content).to be_a(Nanoc::Int::TextualContent)
116
+ expect(subject.layouts['/page.erb'].content.string).to eq('<html><%= yield %></html>')
117
+ expect(subject.layouts['/page.erb'].attributes[:content_filename])
118
+ .to eq('layouts/page.erb')
119
+ expect(subject.layouts['/page.erb'].attributes[:extension])
120
+ .to eq('erb')
121
+ expect(subject.layouts['/page.erb'].attributes[:filename])
122
+ .to eq('layouts/page.erb')
123
+ expect(subject.layouts['/page.erb'].attributes[:meta_filename])
124
+ .to be_nil
125
+ expect(subject.layouts['/page.erb'].attributes[:mtime])
126
+ .to be > Time.now - 5
127
+ expect(subject.layouts['/page.erb'].identifier.to_s).to eq('/page.erb')
128
+ end
129
+ end
130
+ end
131
+
132
+ context 'nanoc.yaml config file' do
133
+ before do
134
+ File.write('nanoc.yaml', "---\nfoo: bar\n")
135
+ end
136
+
137
+ it_behaves_like 'a directory with a config file'
138
+ end
139
+
140
+ context 'config.yaml config file' do
141
+ before do
142
+ File.write('config.yaml', "---\nfoo: bar\n")
143
+ end
144
+
145
+ it_behaves_like 'a directory with a config file'
146
+ end
147
+
148
+ context 'configuration has non-existant data source' do
149
+ before do
150
+ File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
151
+ data_sources:
152
+ - type: eenvaleed
153
+ EOS
154
+ end
155
+
156
+ it 'raises an error' do
157
+ expect { subject }.to raise_error(Nanoc::Int::Errors::UnknownDataSource)
158
+ end
159
+ end
160
+
161
+ context 'environments defined' do
162
+ before do
163
+ File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
164
+ animal: donkey
165
+ environments:
166
+ staging:
167
+ animal: giraffe
168
+ EOS
169
+ end
170
+
171
+ before do
172
+ expect(ENV).to receive(:fetch).with('NANOC_ENV', 'default').and_return('staging')
173
+ end
174
+
175
+ it 'does not load environment' do
176
+ expect(subject.config[:animal]).to eq('giraffe')
177
+ end
178
+ end
179
+
180
+ context 'code snippet with data source implementation' do
181
+ before do
182
+ FileUtils.mkdir_p('lib')
183
+ File.write('lib/foo_data_source.rb', <<-EOS.gsub(/^ {10}/, ''))
184
+ class FooDataSource < Nanoc::DataSource
185
+ identifier :site_loader_spec_sample
186
+
187
+ def items
188
+ [
189
+ Nanoc::Int::Item.new(
190
+ 'Generated content!',
191
+ { generated: true },
192
+ '/generated.txt',
193
+ )
194
+ ]
195
+ end
196
+ end
197
+ EOS
198
+
199
+ File.write('nanoc.yaml', <<-EOS.gsub(/^ {10}/, ''))
200
+ data_sources:
201
+ - type: site_loader_spec_sample
202
+ EOS
203
+ end
204
+
205
+ it 'loads code snippets before items/layouts' do
206
+ expect(subject.items.size).to eq(1)
207
+ expect(subject.items['/generated.txt'].content).to be_a(Nanoc::Int::TextualContent)
208
+ expect(subject.items['/generated.txt'].content.string).to eq('Generated content!')
209
+ expect(subject.items['/generated.txt'].attributes).to eq(generated: true)
210
+ expect(subject.items['/generated.txt'].identifier.to_s).to eq('/generated.txt')
211
+ end
212
+ end
213
+ end
214
+ end