nanoc 4.5.2 → 4.5.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -7
  3. data/NEWS.md +7 -0
  4. data/lib/nanoc/base/entities/item_rep.rb +0 -46
  5. data/lib/nanoc/base/repos.rb +1 -0
  6. data/lib/nanoc/base/repos/snapshot_repo.rb +60 -0
  7. data/lib/nanoc/base/services/compiler.rb +30 -17
  8. data/lib/nanoc/base/services/executor.rb +17 -8
  9. data/lib/nanoc/base/services/item_rep_writer.rb +3 -3
  10. data/lib/nanoc/base/views/item_rep_collection_view.rb +1 -1
  11. data/lib/nanoc/base/views/item_rep_view.rb +2 -2
  12. data/lib/nanoc/base/views/post_compile_item_rep_view.rb +9 -7
  13. data/lib/nanoc/base/views/view_context.rb +3 -1
  14. data/lib/nanoc/cli/commands/compile.rb +3 -3
  15. data/lib/nanoc/cli/commands/shell.rb +1 -0
  16. data/lib/nanoc/extra/parallel_collection.rb +1 -1
  17. data/lib/nanoc/helpers/capturing.rb +9 -5
  18. data/lib/nanoc/rule_dsl/action_provider.rb +2 -0
  19. data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +4 -1
  20. data/lib/nanoc/spec.rb +17 -18
  21. data/lib/nanoc/version.rb +1 -1
  22. data/spec/nanoc/base/compiler_spec.rb +9 -8
  23. data/spec/nanoc/base/entities/item_rep_spec.rb +0 -222
  24. data/spec/nanoc/base/filter_spec.rb +1 -0
  25. data/spec/nanoc/base/item_rep_writer_spec.rb +9 -4
  26. data/spec/nanoc/base/repos/snapshot_repo_spec.rb +314 -0
  27. data/spec/nanoc/base/services/compiler/phases/cache_spec.rb +107 -0
  28. data/spec/nanoc/base/services/executor_spec.rb +230 -44
  29. data/spec/nanoc/base/views/document_view_spec.rb +1 -0
  30. data/spec/nanoc/base/views/item_rep_view_spec.rb +18 -5
  31. data/spec/nanoc/base/views/item_view_spec.rb +18 -7
  32. data/spec/nanoc/base/views/mutable_document_view_spec.rb +6 -5
  33. data/spec/nanoc/base/views/post_compile_item_rep_view_spec.rb +8 -3
  34. data/spec/nanoc/cli/commands/compile/file_action_printer_spec.rb +3 -3
  35. data/spec/nanoc/helpers/capturing_spec.rb +8 -5
  36. data/spec/nanoc/regressions/gh_1064_spec.rb +18 -0
  37. data/spec/nanoc/rule_dsl/rule_context_spec.rb +2 -1
  38. data/spec/nanoc/rule_dsl/rule_memory_calculator_spec.rb +15 -3
  39. data/spec/spec_helper.rb +43 -0
  40. data/test/cli/commands/test_compile.rb +1 -1
  41. data/test/filters/test_xsl.rb +1 -0
  42. data/test/helpers/test_capturing.rb +9 -2
  43. data/test/helpers/test_xml_sitemap.rb +1 -1
  44. metadata +6 -2
@@ -53,6 +53,7 @@ describe Nanoc::Filter do
53
53
  items: double(:items),
54
54
  dependency_tracker: dependency_tracker,
55
55
  compilation_context: double(:compilation_context),
56
+ snapshot_repo: double(:snapshot_repo),
56
57
  )
57
58
  end
58
59
 
@@ -6,7 +6,6 @@ describe Nanoc::Int::ItemRepWriter do
6
6
 
7
7
  let(:item_rep) do
8
8
  Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
9
- ir.snapshot_contents = snapshot_contents
10
9
  ir.raw_paths = raw_paths
11
10
  end
12
11
  end
@@ -24,10 +23,16 @@ describe Nanoc::Int::ItemRepWriter do
24
23
  { snapshot_name => raw_path }
25
24
  end
26
25
 
27
- subject { described_class.new.write(item_rep, snapshot_name) }
26
+ let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
27
+
28
+ subject { described_class.new.write(item_rep, snapshot_repo, snapshot_name) }
28
29
 
29
30
  before do
30
31
  expect(File.directory?('output')).to be_falsy
32
+
33
+ snapshot_contents.each_pair do |key, value|
34
+ snapshot_repo.set(item_rep, key, value)
35
+ end
31
36
  end
32
37
 
33
38
  context 'binary item rep' do
@@ -49,7 +54,7 @@ describe Nanoc::Int::ItemRepWriter do
49
54
  expect(Nanoc::Int::NotificationCenter).to receive(:post)
50
55
  .with(:will_write_rep, item_rep, 'output/blah.dat')
51
56
  expect(Nanoc::Int::NotificationCenter).to receive(:post)
52
- .with(:rep_written, item_rep, 'output/blah.dat', true, true)
57
+ .with(:rep_written, item_rep, true, 'output/blah.dat', true, true)
53
58
 
54
59
  subject
55
60
 
@@ -92,7 +97,7 @@ describe Nanoc::Int::ItemRepWriter do
92
97
  expect(Nanoc::Int::NotificationCenter).to receive(:post)
93
98
  .with(:will_write_rep, item_rep, 'output/blah.dat')
94
99
  expect(Nanoc::Int::NotificationCenter).to receive(:post)
95
- .with(:rep_written, item_rep, 'output/blah.dat', true, true)
100
+ .with(:rep_written, item_rep, false, 'output/blah.dat', true, true)
96
101
 
97
102
  subject
98
103
 
@@ -0,0 +1,314 @@
1
+ describe Nanoc::Int::SnapshotRepo do
2
+ subject(:repo) { described_class.new }
3
+
4
+ describe '#get' do
5
+ subject { repo.get(rep, snapshot_name) }
6
+
7
+ let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
8
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
9
+ let(:snapshot_name) { :donkey }
10
+
11
+ context 'rep does not exist in repo' do
12
+ it { is_expected.to be_nil }
13
+ end
14
+
15
+ context 'rep exists in repo' do
16
+ before { repo.set(rep, :foobar, Nanoc::Int::TextualContent.new('other content')) }
17
+
18
+ context 'snapshot does not exist in repo' do
19
+ it { is_expected.to be_nil }
20
+ end
21
+
22
+ context 'snapshot exists in repo' do
23
+ before { repo.set(rep, :donkey, Nanoc::Int::TextualContent.new('donkey')) }
24
+ it { is_expected.to be_some_textual_content('donkey') }
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#get_all' do
30
+ subject { repo.get_all(rep) }
31
+
32
+ let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
33
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
34
+
35
+ context 'rep does not exist in repo' do
36
+ it { is_expected.to eq({}) }
37
+ end
38
+
39
+ context 'rep exists in repo' do
40
+ before { repo.set(rep, :foobar, Nanoc::Int::TextualContent.new('donkey')) }
41
+ it { is_expected.to match(foobar: some_textual_content('donkey')) }
42
+ end
43
+ end
44
+
45
+ describe '#set' do
46
+ subject { repo.set(rep, snapshot_name, contents) }
47
+
48
+ let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
49
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
50
+ let(:snapshot_name) { :donkey }
51
+ let(:contents) { Nanoc::Int::TextualContent.new('donkey') }
52
+
53
+ it 'changes the given rep+snapshot' do
54
+ expect { subject }
55
+ .to change { repo.get(rep, snapshot_name) }
56
+ .from(nil)
57
+ .to(some_textual_content('donkey'))
58
+ end
59
+ end
60
+
61
+ describe '#set_all' do
62
+ subject { repo.set_all(rep, contents_by_snapshot) }
63
+
64
+ let(:other_item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
65
+ let(:other_rep) { Nanoc::Int::ItemRep.new(other_item, :foo) }
66
+
67
+ let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
68
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
69
+ let(:contents_by_snapshot) { { donkey: Nanoc::Int::TextualContent.new('donkey') } }
70
+
71
+ it 'changes the given rep+snapshot' do
72
+ expect { subject }
73
+ .to change { repo.get(rep, :donkey) }
74
+ .from(nil)
75
+ .to(some_textual_content('donkey'))
76
+ end
77
+
78
+ it 'leaves other reps intact' do
79
+ expect { subject }
80
+ .not_to change { repo.get(other_rep, :donkey) }
81
+ end
82
+
83
+ it 'leaves other snapshots intact' do
84
+ expect { subject }
85
+ .not_to change { repo.get(rep, :giraffe) }
86
+ end
87
+ end
88
+
89
+ describe '#compiled_content' do
90
+ subject { repo.compiled_content(rep: rep, snapshot: snapshot_name) }
91
+
92
+ let(:snapshot_name) { raise 'override me' }
93
+
94
+ let(:item) { Nanoc::Int::Item.new('contentz', {}, '/foo.md') }
95
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
96
+
97
+ shared_examples 'a non-moving snapshot with content' do
98
+ context 'no snapshot def' do
99
+ it 'raises' do
100
+ expect { subject }.to raise_error(Nanoc::Int::Errors::NoSuchSnapshot)
101
+ end
102
+ end
103
+
104
+ context 'snapshot def exists' do
105
+ before do
106
+ rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name)]
107
+ repo.set_all(rep, snapshot_name => content)
108
+ end
109
+
110
+ context 'content is textual' do
111
+ let(:content) { Nanoc::Int::TextualContent.new('hellos') }
112
+ it { is_expected.to eql('hellos') }
113
+ end
114
+
115
+ context 'content is binary' do
116
+ before { File.write('donkey.dat', 'binary data') }
117
+ let(:content) { Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')) }
118
+
119
+ it 'raises' do
120
+ expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ shared_examples 'a non-moving snapshot' do
127
+ include_examples 'a non-moving snapshot with content'
128
+
129
+ context 'snapshot def exists, but not content' do
130
+ before do
131
+ rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name)]
132
+ repo.set_all(rep, {})
133
+ end
134
+
135
+ it 'errors' do
136
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
137
+ end
138
+ end
139
+ end
140
+
141
+ shared_examples 'snapshot :last' do
142
+ context 'no snapshot def' do
143
+ it 'errors' do
144
+ expect { subject }.to raise_error(Nanoc::Int::Errors::NoSuchSnapshot)
145
+ end
146
+ end
147
+
148
+ context 'snapshot exists' do
149
+ context 'snapshot is not final' do
150
+ before do
151
+ rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name)]
152
+ end
153
+
154
+ context 'snapshot content does not exist' do
155
+ before do
156
+ repo.set_all(rep, {})
157
+ end
158
+
159
+ it 'errors' do
160
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
161
+ end
162
+ end
163
+
164
+ context 'snapshot content exists' do
165
+ context 'content is textual' do
166
+ before do
167
+ repo.set(rep, snapshot_name, Nanoc::Int::TextualContent.new('hellos'))
168
+ end
169
+
170
+ context 'not compiled' do
171
+ before { rep.compiled = false }
172
+
173
+ it 'raises' do
174
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
175
+ end
176
+ end
177
+
178
+ context 'compiled' do
179
+ before { rep.compiled = true }
180
+
181
+ it { is_expected.to eql('hellos') }
182
+ end
183
+ end
184
+
185
+ context 'content is binary' do
186
+ before do
187
+ File.write('donkey.dat', 'binary data')
188
+ repo.set(rep, snapshot_name, Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')))
189
+ end
190
+
191
+ context 'not compiled' do
192
+ before { rep.compiled = false }
193
+
194
+ it 'raises' do
195
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
196
+ end
197
+ end
198
+
199
+ context 'compiled' do
200
+ before { rep.compiled = true }
201
+
202
+ it 'raises' do
203
+ expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem)
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ context 'snapshot is final' do
211
+ before do
212
+ rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(snapshot_name)]
213
+ end
214
+
215
+ context 'snapshot content does not exist' do
216
+ before do
217
+ repo.set_all(rep, {})
218
+ end
219
+
220
+ it 'errors' do
221
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
222
+ end
223
+ end
224
+
225
+ context 'snapshot content exists' do
226
+ context 'content is textual' do
227
+ before do
228
+ repo.set(rep, snapshot_name, Nanoc::Int::TextualContent.new('hellos'))
229
+ end
230
+
231
+ context 'not compiled' do
232
+ before { rep.compiled = false }
233
+
234
+ it 'errors' do
235
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
236
+ end
237
+ end
238
+
239
+ context 'compiled' do
240
+ before { rep.compiled = true }
241
+
242
+ it { is_expected.to eql('hellos') }
243
+ end
244
+ end
245
+
246
+ context 'content is binary' do
247
+ before do
248
+ File.write('donkey.dat', 'binary data')
249
+ repo.set(rep, snapshot_name, Nanoc::Int::BinaryContent.new(File.expand_path('donkey.dat')))
250
+ end
251
+
252
+ context 'not compiled' do
253
+ before { rep.compiled = false }
254
+
255
+ it 'raises' do
256
+ expect { subject }.to yield_from_fiber(an_instance_of(Nanoc::Int::Errors::UnmetDependency))
257
+ end
258
+ end
259
+
260
+ context 'compiled' do
261
+ before { rep.compiled = true }
262
+
263
+ it 'raises' do
264
+ expect { subject }.to raise_error(Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem)
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
271
+ end
272
+
273
+ context 'snapshot nil' do
274
+ let(:snapshot_name) { :last }
275
+ subject { repo.compiled_content(rep: rep, snapshot: nil) }
276
+ include_examples 'snapshot :last'
277
+ end
278
+
279
+ context 'snapshot not specified' do
280
+ subject { repo.compiled_content(rep: rep) }
281
+
282
+ context 'pre exists' do
283
+ before { repo.set(rep, :pre, Nanoc::Int::TextualContent.new('omg')) }
284
+ let(:snapshot_name) { :pre }
285
+ include_examples 'a non-moving snapshot with content'
286
+ end
287
+
288
+ context 'pre does not exist' do
289
+ let(:snapshot_name) { :last }
290
+ include_examples 'snapshot :last'
291
+ end
292
+ end
293
+
294
+ context 'snapshot :pre specified' do
295
+ let(:snapshot_name) { :pre }
296
+ include_examples 'a non-moving snapshot'
297
+ end
298
+
299
+ context 'snapshot :post specified' do
300
+ let(:snapshot_name) { :post }
301
+ include_examples 'a non-moving snapshot'
302
+ end
303
+
304
+ context 'snapshot :last specified' do
305
+ let(:snapshot_name) { :last }
306
+ include_examples 'snapshot :last'
307
+ end
308
+
309
+ context 'snapshot :donkey specified' do
310
+ let(:snapshot_name) { :donkey }
311
+ include_examples 'a non-moving snapshot'
312
+ end
313
+ end
314
+ end
@@ -0,0 +1,107 @@
1
+ describe Nanoc::Int::Compiler::Phases::Cache do
2
+ subject(:phase) do
3
+ described_class.new(
4
+ compiled_content_cache: compiled_content_cache,
5
+ snapshot_repo: snapshot_repo,
6
+ wrapped: wrapped,
7
+ )
8
+ end
9
+
10
+ let(:compiled_content_cache) do
11
+ Nanoc::Int::CompiledContentCache.new(env_name: nil, items: [item])
12
+ end
13
+
14
+ let(:snapshot_repo) { Nanoc::Int::SnapshotRepo.new }
15
+
16
+ let(:wrapped_class) do
17
+ Class.new do
18
+ def initialize(snapshot_repo)
19
+ @snapshot_repo = snapshot_repo
20
+ end
21
+
22
+ def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
23
+ @snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('wrapped content'))
24
+ end
25
+ end
26
+ end
27
+
28
+ let(:wrapped) { wrapped_class.new(snapshot_repo) }
29
+
30
+ let(:item) { Nanoc::Int::Item.new('item content', {}, '/donkey.md') }
31
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :latex) }
32
+
33
+ describe '#run' do
34
+ subject { phase.run(rep, is_outdated: is_outdated) }
35
+
36
+ let(:is_outdated) { raise 'override me' }
37
+
38
+ shared_examples 'calls wrapped' do
39
+ it 'delegates to wrapped' do
40
+ expect(wrapped).to receive(:run).with(rep, is_outdated: is_outdated)
41
+ subject
42
+ end
43
+
44
+ it 'marks rep as compiled' do
45
+ expect { subject }
46
+ .to change { rep.compiled? }
47
+ .from(false)
48
+ .to(true)
49
+ end
50
+
51
+ it 'sends no notifications' do
52
+ expect(Nanoc::Int::NotificationCenter).not_to receive(:post)
53
+ subject
54
+ end
55
+
56
+ it 'updates compiled content cache' do
57
+ expect { subject }
58
+ .to change { compiled_content_cache[rep] }
59
+ .from(nil)
60
+ .to(last: some_textual_content('wrapped content'))
61
+ end
62
+ end
63
+
64
+ context 'outdated' do
65
+ let(:is_outdated) { true }
66
+ include_examples 'calls wrapped'
67
+ end
68
+
69
+ context 'not outdated' do
70
+ let(:is_outdated) { false }
71
+
72
+ context 'cached compiled content available' do
73
+ before do
74
+ compiled_content_cache[rep] = { last: Nanoc::Int::TextualContent.new('cached') }
75
+ end
76
+
77
+ it 'reuses content from cache' do
78
+ expect { subject }
79
+ .to change { snapshot_repo.get(rep, :last) }
80
+ .from(nil)
81
+ .to(some_textual_content('cached'))
82
+ end
83
+
84
+ it 'marks rep as compiled' do
85
+ expect { subject }
86
+ .to change { rep.compiled? }
87
+ .from(false)
88
+ .to(true)
89
+ end
90
+
91
+ it 'does not change compiled content cache' do
92
+ expect { subject }
93
+ .not_to change { compiled_content_cache[rep] }
94
+ end
95
+
96
+ it 'sends notification' do
97
+ expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:cached_content_used, rep)
98
+ subject
99
+ end
100
+ end
101
+
102
+ context 'no cached compiled content available' do
103
+ include_examples 'calls wrapped'
104
+ end
105
+ end
106
+ end
107
+ end