nanoc 4.7.7 → 4.7.8

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +6 -5
  3. data/NEWS.md +12 -0
  4. data/lib/nanoc/base/entities.rb +1 -0
  5. data/lib/nanoc/base/entities/action_sequence.rb +8 -36
  6. data/lib/nanoc/base/entities/checksum_collection.rb +31 -0
  7. data/lib/nanoc/base/entities/directed_graph.rb +35 -11
  8. data/lib/nanoc/base/errors.rb +3 -1
  9. data/lib/nanoc/base/repos/checksum_store.rb +1 -0
  10. data/lib/nanoc/base/services.rb +1 -0
  11. data/lib/nanoc/base/services/action_sequence_builder.rb +45 -0
  12. data/lib/nanoc/base/services/compiler.rb +34 -14
  13. data/lib/nanoc/base/services/compiler/stages.rb +1 -0
  14. data/lib/nanoc/base/services/compiler/stages/calculate_checksums.rb +31 -0
  15. data/lib/nanoc/base/services/compiler/stages/store_pre_compilation_state.rb +6 -13
  16. data/lib/nanoc/base/services/outdatedness_checker.rb +4 -2
  17. data/lib/nanoc/base/services/outdatedness_rules/attributes_modified.rb +1 -1
  18. data/lib/nanoc/base/services/outdatedness_rules/code_snippets_modified.rb +1 -1
  19. data/lib/nanoc/base/services/outdatedness_rules/configuration_modified.rb +1 -1
  20. data/lib/nanoc/base/services/outdatedness_rules/content_modified.rb +1 -1
  21. data/lib/nanoc/cli/cleaning_stream.rb +1 -1
  22. data/lib/nanoc/cli/commands/show-data.rb +1 -0
  23. data/lib/nanoc/rule_dsl/action_sequence_calculator.rb +7 -14
  24. data/lib/nanoc/rule_dsl/recording_executor.rb +40 -7
  25. data/lib/nanoc/version.rb +1 -1
  26. data/spec/nanoc/base/compiler_spec.rb +5 -5
  27. data/spec/nanoc/base/directed_graph_spec.rb +12 -0
  28. data/spec/nanoc/base/entities/action_sequence_spec.rb +132 -79
  29. data/spec/nanoc/base/errors/dependency_cycle_spec.rb +4 -4
  30. data/spec/nanoc/base/services/compiler/stages/calculate_checksums_spec.rb +69 -0
  31. data/spec/nanoc/base/services/executor_spec.rb +2 -2
  32. data/spec/nanoc/base/services/item_rep_router_spec.rb +4 -4
  33. data/spec/nanoc/base/services/outdatedness_checker_spec.rb +40 -24
  34. data/spec/nanoc/base/services/outdatedness_rules_spec.rb +27 -15
  35. data/spec/nanoc/cli/commands/show_data_spec.rb +2 -0
  36. data/spec/nanoc/rule_dsl/action_sequence_calculator_spec.rb +15 -13
  37. data/spec/nanoc/rule_dsl/recording_executor_spec.rb +4 -3
  38. data/test/cli/test_cleaning_stream.rb +8 -0
  39. metadata +6 -2
@@ -21,10 +21,10 @@ describe Nanoc::Int::Errors::DependencyCycle do
21
21
  expected = <<EOS
22
22
  The site cannot be compiled because there is a dependency cycle:
23
23
 
24
- (1) item /b.md, rep :default, depends on
25
- (2) item /c.md, rep :default, depends on
26
- (3) item /d.md, rep :default, depends on
27
- (4) item /e.md, rep :default, depends on (1)
24
+ (1) item /e.md, rep :default, uses compiled content of
25
+ (2) item /d.md, rep :default, uses compiled content of
26
+ (3) item /c.md, rep :default, uses compiled content of
27
+ (4) item /b.md, rep :default, uses compiled content of (1)
28
28
  EOS
29
29
 
30
30
  expect(error.message).to eql(expected)
@@ -0,0 +1,69 @@
1
+ describe Nanoc::Int::Compiler::Stages::CalculateChecksums do
2
+ let(:stage) do
3
+ described_class.new(items: items, layouts: layouts, code_snippets: code_snippets, config: config)
4
+ end
5
+
6
+ let(:config) do
7
+ Nanoc::Int::Configuration.new.with_defaults
8
+ end
9
+
10
+ let(:code_snippets) do
11
+ [code_snippet]
12
+ end
13
+
14
+ let(:items) do
15
+ Nanoc::Int::IdentifiableCollection.new(config, [item])
16
+ end
17
+
18
+ let(:layouts) do
19
+ Nanoc::Int::IdentifiableCollection.new(config, [layout])
20
+ end
21
+
22
+ let(:code_snippet) do
23
+ Nanoc::Int::CodeSnippet.new('woof!', 'dog.rb')
24
+ end
25
+
26
+ let(:item) do
27
+ Nanoc::Int::Item.new('hello there', {}, '/hi.md')
28
+ end
29
+
30
+ let(:layout) do
31
+ Nanoc::Int::Layout.new('t3mpl4t3', {}, '/page.erb')
32
+ end
33
+
34
+ describe '#run' do
35
+ subject { stage.run }
36
+
37
+ it 'checksums items' do
38
+ expect(subject.checksum_for(item))
39
+ .to eq(Nanoc::Int::Checksummer.calc(item))
40
+
41
+ expect(subject.content_checksum_for(item))
42
+ .to eq(Nanoc::Int::Checksummer.calc_for_content_of(item))
43
+
44
+ expect(subject.attributes_checksum_for(item))
45
+ .to eq(Nanoc::Int::Checksummer.calc_for_each_attribute_of(item))
46
+ end
47
+
48
+ it 'checksums layouts' do
49
+ expect(subject.checksum_for(layout))
50
+ .to eq(Nanoc::Int::Checksummer.calc(layout))
51
+
52
+ expect(subject.content_checksum_for(layout))
53
+ .to eq(Nanoc::Int::Checksummer.calc_for_content_of(layout))
54
+
55
+ expect(subject.attributes_checksum_for(layout))
56
+ .to eq(Nanoc::Int::Checksummer.calc_for_each_attribute_of(layout))
57
+ end
58
+
59
+ it 'checksums config' do
60
+ expect(subject.checksum_for(config))
61
+ .to eq(Nanoc::Int::Checksummer.calc(config))
62
+ end
63
+
64
+ it 'checksums code snippets' do
65
+ expect(subject.checksum_for(code_snippet))
66
+ .to eq(Nanoc::Int::Checksummer.calc(code_snippet))
67
+ end
68
+ end
69
+ end
@@ -408,8 +408,8 @@ describe Nanoc::Int::Executor do
408
408
  end
409
409
 
410
410
  let(:action_sequence) do
411
- Nanoc::Int::ActionSequence.new(rep).tap do |seq|
412
- seq.add_filter(:erb, {})
411
+ Nanoc::Int::ActionSequence.build(rep) do |b|
412
+ b.add_filter(:erb, {})
413
413
  end
414
414
  end
415
415
 
@@ -62,10 +62,10 @@ describe(Nanoc::Int::ItemRepRouter) do
62
62
  end
63
63
 
64
64
  it 'picks the paths last returned' do
65
- allow(action_provider).to receive(:action_sequence_for).with(reps[0])
66
- .and_return(memory_without_paths, action_sequence_for_default)
67
- allow(action_provider).to receive(:action_sequence_for).with(reps[1])
68
- .and_return(memory_without_paths, action_sequence_for_csv)
65
+ allow(action_provider).to receive(:action_sequence_for)
66
+ .with(reps[0]).and_return(memory_without_paths, action_sequence_for_default)
67
+ allow(action_provider).to receive(:action_sequence_for)
68
+ .with(reps[1]).and_return(memory_without_paths, action_sequence_for_csv)
69
69
 
70
70
  subject
71
71
 
@@ -3,6 +3,7 @@ describe Nanoc::Int::OutdatednessChecker do
3
3
  described_class.new(
4
4
  site: site,
5
5
  checksum_store: checksum_store,
6
+ checksums: checksums,
6
7
  dependency_store: dependency_store,
7
8
  action_sequence_store: action_sequence_store,
8
9
  action_sequences: action_sequences,
@@ -12,6 +13,15 @@ describe Nanoc::Int::OutdatednessChecker do
12
13
 
13
14
  let(:checksum_store) { double(:checksum_store) }
14
15
 
16
+ let(:checksums) do
17
+ Nanoc::Int::Compiler::Stages::CalculateChecksums.new(
18
+ items: items,
19
+ layouts: layouts,
20
+ code_snippets: code_snippets,
21
+ config: config,
22
+ ).run
23
+ end
24
+
15
25
  let(:dependency_store) do
16
26
  Nanoc::Int::DependencyStore.new(items, layouts)
17
27
  end
@@ -19,10 +29,12 @@ describe Nanoc::Int::OutdatednessChecker do
19
29
  let(:items) { Nanoc::Int::IdentifiableCollection.new(config, [item]) }
20
30
  let(:layouts) { Nanoc::Int::IdentifiableCollection.new(config) }
21
31
 
32
+ let(:code_snippets) { [] }
33
+
22
34
  let(:site) do
23
35
  Nanoc::Int::Site.new(
24
36
  config: config,
25
- code_snippets: [],
37
+ code_snippets: code_snippets,
26
38
  data_source: Nanoc::Int::InMemDataSource.new([], []),
27
39
  )
28
40
  end
@@ -32,8 +44,8 @@ describe Nanoc::Int::OutdatednessChecker do
32
44
  end
33
45
 
34
46
  let(:old_action_sequence_for_item_rep) do
35
- Nanoc::Int::ActionSequence.new(item_rep).tap do |seq|
36
- seq.add_filter(:erb, {})
47
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
48
+ b.add_filter(:erb, {})
37
49
  end
38
50
  end
39
51
 
@@ -74,8 +86,8 @@ describe Nanoc::Int::OutdatednessChecker do
74
86
 
75
87
  context 'action sequence differs' do
76
88
  let(:new_action_sequence_for_item_rep) do
77
- Nanoc::Int::ActionSequence.new(item_rep).tap do |seq|
78
- seq.add_filter(:super_erb, {})
89
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
90
+ b.add_filter(:super_erb, {})
79
91
  end
80
92
  end
81
93
 
@@ -92,8 +104,8 @@ describe Nanoc::Int::OutdatednessChecker do
92
104
 
93
105
  context 'action sequence differs' do
94
106
  let(:new_action_sequence_for_item_rep) do
95
- Nanoc::Int::ActionSequence.new(item_rep).tap do |seq|
96
- seq.add_filter(:super_erb, {})
107
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
108
+ b.add_filter(:super_erb, {})
97
109
  end
98
110
  end
99
111
 
@@ -123,8 +135,8 @@ describe Nanoc::Int::OutdatednessChecker do
123
135
  let(:items) { Nanoc::Int::IdentifiableCollection.new(config, [item, other_item]) }
124
136
 
125
137
  let(:old_action_sequence_for_other_item_rep) do
126
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
127
- seq.add_filter(:erb, {})
138
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
139
+ b.add_filter(:erb, {})
128
140
  end
129
141
  end
130
142
 
@@ -152,6 +164,10 @@ describe Nanoc::Int::OutdatednessChecker do
152
164
  let(:distant_item) { Nanoc::Int::Item.new('distant stuff', {}, '/distant.md') }
153
165
  let(:distant_item_rep) { Nanoc::Int::ItemRep.new(distant_item, :default) }
154
166
 
167
+ let(:items) do
168
+ Nanoc::Int::IdentifiableCollection.new(config, [item, other_item, distant_item])
169
+ end
170
+
155
171
  let(:action_sequences) do
156
172
  {
157
173
  item_rep => new_action_sequence_for_item_rep,
@@ -252,9 +268,9 @@ describe Nanoc::Int::OutdatednessChecker do
252
268
 
253
269
  context 'path changed' do
254
270
  let(:new_action_sequence_for_other_item_rep) do
255
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
256
- seq.add_filter(:erb, {})
257
- seq.add_snapshot(:donkey, '/giraffe.txt')
271
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
272
+ b.add_filter(:erb, {})
273
+ b.add_snapshot(:donkey, '/giraffe.txt')
258
274
  end
259
275
  end
260
276
 
@@ -296,9 +312,9 @@ describe Nanoc::Int::OutdatednessChecker do
296
312
 
297
313
  context 'path changed' do
298
314
  let(:new_action_sequence_for_other_item_rep) do
299
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
300
- seq.add_filter(:erb, {})
301
- seq.add_snapshot(:donkey, '/giraffe.txt')
315
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
316
+ b.add_filter(:erb, {})
317
+ b.add_snapshot(:donkey, '/giraffe.txt')
302
318
  end
303
319
  end
304
320
 
@@ -329,9 +345,9 @@ describe Nanoc::Int::OutdatednessChecker do
329
345
 
330
346
  context 'path changed' do
331
347
  let(:new_action_sequence_for_other_item_rep) do
332
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
333
- seq.add_filter(:erb, {})
334
- seq.add_snapshot(:donkey, '/giraffe.txt')
348
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
349
+ b.add_filter(:erb, {})
350
+ b.add_snapshot(:donkey, '/giraffe.txt')
335
351
  end
336
352
  end
337
353
 
@@ -356,9 +372,9 @@ describe Nanoc::Int::OutdatednessChecker do
356
372
 
357
373
  context 'path changed' do
358
374
  let(:new_action_sequence_for_other_item_rep) do
359
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
360
- seq.add_filter(:erb, {})
361
- seq.add_snapshot(:donkey, '/giraffe.txt')
375
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
376
+ b.add_filter(:erb, {})
377
+ b.add_snapshot(:donkey, '/giraffe.txt')
362
378
  end
363
379
  end
364
380
 
@@ -389,9 +405,9 @@ describe Nanoc::Int::OutdatednessChecker do
389
405
 
390
406
  context 'rules changed' do
391
407
  let(:new_action_sequence_for_other_item_rep) do
392
- Nanoc::Int::ActionSequence.new(other_item_rep).tap do |seq|
393
- seq.add_filter(:erb, {})
394
- seq.add_filter(:donkey, {})
408
+ Nanoc::Int::ActionSequence.build(other_item_rep) do |b|
409
+ b.add_filter(:erb, {})
410
+ b.add_filter(:donkey, {})
395
411
  end
396
412
  end
397
413
 
@@ -8,6 +8,7 @@ describe Nanoc::Int::OutdatednessRules do
8
8
  Nanoc::Int::OutdatednessChecker.new(
9
9
  site: site,
10
10
  checksum_store: checksum_store,
11
+ checksums: checksums,
11
12
  dependency_store: dependency_store,
12
13
  action_sequence_store: action_sequence_store,
13
14
  action_sequences: action_sequences,
@@ -36,6 +37,15 @@ describe Nanoc::Int::OutdatednessRules do
36
37
  let(:action_sequence_store) { Nanoc::Int::ActionSequenceStore.new }
37
38
  let(:checksum_store) { Nanoc::Int::ChecksumStore.new(objects: objects) }
38
39
 
40
+ let(:checksums) do
41
+ Nanoc::Int::Compiler::Stages::CalculateChecksums.new(
42
+ items: items,
43
+ layouts: layouts,
44
+ code_snippets: code_snippets,
45
+ config: config,
46
+ ).run
47
+ end
48
+
39
49
  let(:items) { Nanoc::Int::IdentifiableCollection.new(config, [item]) }
40
50
  let(:layouts) { Nanoc::Int::IdentifiableCollection.new(config) }
41
51
 
@@ -61,7 +71,7 @@ describe Nanoc::Int::OutdatednessRules do
61
71
  it { is_expected.not_to be }
62
72
  end
63
73
 
64
- context 'only non-outdated snippets' do
74
+ context 'only outdated snippets' do
65
75
  let(:code_snippet) { Nanoc::Int::CodeSnippet.new('asdf', 'lib/foo.md') }
66
76
  let(:code_snippet_old) { Nanoc::Int::CodeSnippet.new('aaaaaaaa', 'lib/foo.md') }
67
77
  let(:code_snippets) { [code_snippet] }
@@ -305,8 +315,8 @@ describe Nanoc::Int::OutdatednessRules do
305
315
  let(:rule_class) { Nanoc::Int::OutdatednessRules::RulesModified }
306
316
 
307
317
  let(:old_mem) do
308
- Nanoc::Int::ActionSequence.new(item_rep).tap do |mem|
309
- mem.add_filter(:erb, {})
318
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
319
+ b.add_filter(:erb, {})
310
320
  end
311
321
  end
312
322
 
@@ -323,9 +333,9 @@ describe Nanoc::Int::OutdatednessRules do
323
333
 
324
334
  context 'memory is different' do
325
335
  let(:new_mem) do
326
- Nanoc::Int::ActionSequence.new(item_rep).tap do |mem|
327
- mem.add_filter(:erb, {})
328
- mem.add_filter(:donkey, {})
336
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
337
+ b.add_filter(:erb, {})
338
+ b.add_filter(:donkey, {})
329
339
  end
330
340
  end
331
341
 
@@ -344,6 +354,8 @@ describe Nanoc::Int::OutdatednessRules do
344
354
  let(:stored_obj) { raise 'override me' }
345
355
  let(:new_obj) { raise 'override me' }
346
356
 
357
+ let(:items) { [new_obj] }
358
+
347
359
  shared_examples 'a document' do
348
360
  let(:stored_obj) { klass.new('a', {}, '/foo.md') }
349
361
  let(:new_obj) { stored_obj }
@@ -463,9 +475,9 @@ describe Nanoc::Int::OutdatednessRules do
463
475
 
464
476
  context 'unknown filter' do
465
477
  let(:mem) do
466
- Nanoc::Int::ActionSequence.new(item_rep).tap do |mem|
467
- mem.add_snapshot(:donkey, '/foo.md')
468
- mem.add_filter(:asdf, {})
478
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
479
+ b.add_snapshot(:donkey, '/foo.md')
480
+ b.add_filter(:asdf, {})
469
481
  end
470
482
  end
471
483
 
@@ -474,9 +486,9 @@ describe Nanoc::Int::OutdatednessRules do
474
486
 
475
487
  context 'known filter, not always outdated' do
476
488
  let(:mem) do
477
- Nanoc::Int::ActionSequence.new(item_rep).tap do |mem|
478
- mem.add_snapshot(:donkey, '/foo.md')
479
- mem.add_filter(:erb, {})
489
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
490
+ b.add_snapshot(:donkey, '/foo.md')
491
+ b.add_filter(:erb, {})
480
492
  end
481
493
  end
482
494
 
@@ -485,9 +497,9 @@ describe Nanoc::Int::OutdatednessRules do
485
497
 
486
498
  context 'known filter, always outdated' do
487
499
  let(:mem) do
488
- Nanoc::Int::ActionSequence.new(item_rep).tap do |mem|
489
- mem.add_snapshot(:donkey, '/foo.md')
490
- mem.add_filter(:xsl, {})
500
+ Nanoc::Int::ActionSequence.build(item_rep) do |b|
501
+ b.add_snapshot(:donkey, '/foo.md')
502
+ b.add_filter(:xsl, {})
491
503
  end
492
504
  end
493
505
 
@@ -167,6 +167,7 @@ describe Nanoc::CLI::Commands::ShowData, stdio: true do
167
167
  allow(site).to receive(:compiler).and_return(compiler)
168
168
  allow(compiler).to receive(:create_outdatedness_checker).and_return(outdatedness_checker)
169
169
  allow(compiler).to receive(:reps).and_return(reps)
170
+ allow(compiler).to receive(:calculate_checksums)
170
171
  end
171
172
 
172
173
  context 'not outdated' do
@@ -239,6 +240,7 @@ describe Nanoc::CLI::Commands::ShowData, stdio: true do
239
240
  allow(runner).to receive(:site).and_return(site)
240
241
  allow(site).to receive(:compiler).and_return(compiler)
241
242
  allow(compiler).to receive(:create_outdatedness_checker).and_return(outdatedness_checker)
243
+ allow(compiler).to receive(:calculate_checksums)
242
244
  end
243
245
 
244
246
  context 'not outdated' do
@@ -175,21 +175,23 @@ describe(Nanoc::RuleDSL::ActionSequenceCalculator) do
175
175
  describe '#compact_snapshots' do
176
176
  subject { action_sequence_calculator.compact_snapshots(action_sequence) }
177
177
 
178
- let(:action_sequence) { Nanoc::Int::ActionSequence.new(rep) }
179
- let(:rep) { double(:rep) }
180
-
181
- before do
182
- action_sequence.add_snapshot(:a1, nil)
183
- action_sequence.add_snapshot(:a2, '/a2.md')
184
- action_sequence.add_snapshot(:a3, nil)
185
- action_sequence.add_filter(:erb, awesomeness: 'high')
186
- action_sequence.add_snapshot(:b1, '/b1.md')
187
- action_sequence.add_snapshot(:b2, nil)
188
- action_sequence.add_snapshot(:b3, '/b3.md')
189
- action_sequence.add_filter(:erb, awesomeness: 'high')
190
- action_sequence.add_snapshot(:c, nil)
178
+ let(:action_sequence) do
179
+ Nanoc::Int::ActionSequence.build(rep) do |b|
180
+ b.add_snapshot(:a1, nil)
181
+ b.add_snapshot(:a2, '/a2.md')
182
+ b.add_snapshot(:a3, nil)
183
+ b.add_filter(:erb, awesomeness: 'high')
184
+ b.add_snapshot(:b1, '/b1.md')
185
+ b.add_snapshot(:b2, nil)
186
+ b.add_snapshot(:b3, '/b3.md')
187
+ b.add_filter(:erb, awesomeness: 'high')
188
+ b.add_snapshot(:c, nil)
189
+ end
191
190
  end
192
191
 
192
+ let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
193
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
194
+
193
195
  example do
194
196
  expect(subject[0]).to be_a(Nanoc::Int::ProcessingActions::Snapshot)
195
197
  expect(subject[0].snapshot_names).to eql(%i[a1 a2 a3])
@@ -1,8 +1,9 @@
1
1
  describe Nanoc::RuleDSL::RecordingExecutor do
2
- let(:executor) { described_class.new(action_sequence) }
2
+ let(:executor) { described_class.new(rep) }
3
3
 
4
- let(:action_sequence) { Nanoc::Int::ActionSequence.new(rep) }
5
- let(:rep) { double(:rep) }
4
+ let(:action_sequence) { executor.action_sequence }
5
+ let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
6
+ let(:rep) { Nanoc::Int::ItemRep.new(item, :default) }
6
7
 
7
8
  describe '#filter' do
8
9
  it 'records filter call without arguments' do
@@ -84,4 +84,12 @@ class Nanoc::CLI::CleaningStreamTest < Nanoc::TestCase
84
84
  cleaning_stream << obj
85
85
  assert_equal 'Hello… world!', stream.string
86
86
  end
87
+
88
+ def test_invalid_string
89
+ s = "\x80"
90
+ stream = StringIO.new
91
+ cleaning_stream = Nanoc::CLI::CleaningStream.new(stream)
92
+ cleaning_stream << s
93
+ assert_equal "\xef\xbf\xbd", stream.string
94
+ end
87
95
  end