nanoc 4.4.6 → 4.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +11 -13
- data/LICENSE +1 -1
- data/NEWS.md +11 -0
- data/README.md +1 -1
- data/lib/nanoc.rb +1 -1
- data/lib/nanoc/base/repos.rb +1 -0
- data/lib/nanoc/base/repos/outdatedness_store.rb +49 -0
- data/lib/nanoc/base/services/compiler.rb +286 -152
- data/lib/nanoc/base/services/compiler_loader.rb +4 -0
- data/lib/nanoc/base/services/outdatedness_checker.rb +2 -6
- data/lib/nanoc/checking/checks/external_links.rb +0 -2
- data/lib/nanoc/data_sources/filesystem.rb +13 -4
- data/lib/nanoc/version.rb +1 -1
- data/spec/nanoc/base/compiler_spec.rb +54 -14
- data/spec/nanoc/base/repos/outdatedness_store_spec.rb +100 -0
- data/spec/nanoc/base/services/outdatedness_checker_spec.rb +15 -6
- data/spec/nanoc/base/services/outdatedness_rules_spec.rb +12 -4
- data/spec/nanoc/cli/commands/view_spec.rb +2 -0
- data/spec/nanoc/data_sources/filesystem_spec.rb +13 -1
- data/spec/nanoc/extra/parallel_collection_spec.rb +2 -2
- data/spec/nanoc/integration/outdatedness_integration_spec.rb +8 -0
- data/spec/nanoc/integration/partial_recompilation_spec.rb +48 -0
- data/spec/nanoc/regressions/gh_1045_spec.rb +48 -0
- data/spec/nanoc/regressions/gh_1047_spec.rb +28 -0
- data/test/base/test_compiler.rb +1 -0
- metadata +7 -2
@@ -16,6 +16,9 @@ module Nanoc::Int
|
|
16
16
|
|
17
17
|
action_provider ||= Nanoc::Int::ActionProvider.named(:rule_dsl).for(site)
|
18
18
|
|
19
|
+
outdatedness_store =
|
20
|
+
Nanoc::Int::OutdatednessStore.new(site: site, reps: item_rep_repo)
|
21
|
+
|
19
22
|
outdatedness_checker =
|
20
23
|
Nanoc::Int::OutdatednessChecker.new(
|
21
24
|
site: site,
|
@@ -40,6 +43,7 @@ module Nanoc::Int
|
|
40
43
|
outdatedness_checker: outdatedness_checker,
|
41
44
|
reps: item_rep_repo,
|
42
45
|
action_provider: action_provider,
|
46
|
+
outdatedness_store: outdatedness_store,
|
43
47
|
}
|
44
48
|
|
45
49
|
Nanoc::Int::Compiler.new(site, params)
|
@@ -82,12 +82,8 @@ module Nanoc::Int
|
|
82
82
|
|
83
83
|
Reasons = Nanoc::Int::OutdatednessReasons
|
84
84
|
|
85
|
-
#
|
86
|
-
|
87
|
-
# @param [Nanoc::Int::DependencyStore] dependency_store
|
88
|
-
# @param [Nanoc::Int::RuleMemoryStore] rule_memory_store
|
89
|
-
# @param [Nanoc::Int::ActionProvider] action_provider
|
90
|
-
# @param [Nanoc::Int::ItemRepRepo] reps
|
85
|
+
# FIXME: Replace C::Any with proper types
|
86
|
+
contract C::KeywordArgs[site: Nanoc::Int::Site, checksum_store: Nanoc::Int::ChecksumStore, dependency_store: Nanoc::Int::DependencyStore, rule_memory_store: Nanoc::Int::RuleMemoryStore, action_provider: C::Any, reps: Nanoc::Int::ItemRepRepo] => C::Any
|
91
87
|
def initialize(site:, checksum_store:, dependency_store:, rule_memory_store:, action_provider:, reps:)
|
92
88
|
@site = site
|
93
89
|
@checksum_store = checksum_store
|
@@ -12,8 +12,6 @@ module ::Nanoc::Checking::Checks
|
|
12
12
|
identifiers :external_links, :elinks
|
13
13
|
|
14
14
|
def run
|
15
|
-
require 'parallel'
|
16
|
-
|
17
15
|
# Find all broken external hrefs
|
18
16
|
# TODO: de-duplicate this (duplicated in internal links check)
|
19
17
|
filenames = output_filenames.select { |f| File.extname(f) == '.html' && !excluded_file?(f) }
|
@@ -163,7 +163,7 @@ module Nanoc::DataSources
|
|
163
163
|
attributes,
|
164
164
|
identifier,
|
165
165
|
content_checksum_data: proto_doc.content_checksum_data,
|
166
|
-
attributes_checksum_data: proto_doc
|
166
|
+
attributes_checksum_data: attributes_checksum_data_for(proto_doc, content_filename, meta_filename),
|
167
167
|
)
|
168
168
|
end
|
169
169
|
end
|
@@ -171,16 +171,25 @@ module Nanoc::DataSources
|
|
171
171
|
res
|
172
172
|
end
|
173
173
|
|
174
|
-
def
|
175
|
-
|
174
|
+
def attributes_checksum_data_for(proto_doc, content_filename, meta_filename)
|
175
|
+
YAML.dump(
|
176
|
+
attributes: proto_doc.attributes_checksum_data,
|
177
|
+
extra_attributes: extra_attributes_for(content_filename, meta_filename),
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
def extra_attributes_for(content_filename, meta_filename)
|
182
|
+
{
|
176
183
|
filename: content_filename,
|
177
184
|
content_filename: content_filename,
|
178
185
|
meta_filename: meta_filename,
|
179
186
|
extension: content_filename ? ext_of(content_filename)[1..-1] : nil,
|
180
187
|
mtime: mtime_of(content_filename, meta_filename),
|
181
188
|
}
|
189
|
+
end
|
182
190
|
|
183
|
-
|
191
|
+
def attributes_for(proto_doc, content_filename, meta_filename)
|
192
|
+
extra_attributes_for(content_filename, meta_filename).merge(proto_doc.attributes)
|
184
193
|
end
|
185
194
|
|
186
195
|
def identifier_for(content_filename, meta_filename, dir_name)
|
data/lib/nanoc/version.rb
CHANGED
@@ -9,16 +9,18 @@ describe Nanoc::Int::Compiler do
|
|
9
9
|
dependency_store: dependency_store,
|
10
10
|
outdatedness_checker: outdatedness_checker,
|
11
11
|
reps: reps,
|
12
|
+
outdatedness_store: outdatedness_store,
|
12
13
|
)
|
13
14
|
end
|
14
15
|
|
15
|
-
let(:checksum_store)
|
16
|
-
let(:rule_memory_store)
|
16
|
+
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(objects: items) }
|
17
|
+
let(:rule_memory_store) { Nanoc::Int::RuleMemoryStore.new }
|
17
18
|
|
18
19
|
let(:dependency_store) { Nanoc::Int::DependencyStore.new(items.to_a) }
|
19
20
|
let(:reps) { Nanoc::Int::ItemRepRepo.new }
|
20
21
|
|
21
22
|
let(:outdatedness_checker) { double(:outdatedness_checker) }
|
23
|
+
let(:outdatedness_store) { Nanoc::Int::OutdatednessStore.new(site: site, reps: reps) }
|
22
24
|
let(:action_provider) { double(:action_provider) }
|
23
25
|
|
24
26
|
let(:compiled_content_cache) { Nanoc::Int::CompiledContentCache.new(items: items) }
|
@@ -50,10 +52,13 @@ describe Nanoc::Int::Compiler do
|
|
50
52
|
end
|
51
53
|
|
52
54
|
let(:memory) do
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
actions =
|
56
|
+
[
|
57
|
+
Nanoc::Int::ProcessingActions::Filter.new(:erb, {}),
|
58
|
+
Nanoc::Int::ProcessingActions::Snapshot.new(:last, nil),
|
59
|
+
]
|
60
|
+
|
61
|
+
Nanoc::Int::RuleMemory.new(nil, actions: actions)
|
57
62
|
end
|
58
63
|
|
59
64
|
before do
|
@@ -72,7 +77,10 @@ describe Nanoc::Int::Compiler do
|
|
72
77
|
end
|
73
78
|
|
74
79
|
describe '#compile_reps' do
|
75
|
-
subject
|
80
|
+
subject do
|
81
|
+
compiler.send(:determine_outdatedness)
|
82
|
+
compiler.send(:compile_reps)
|
83
|
+
end
|
76
84
|
|
77
85
|
before do
|
78
86
|
allow(action_provider).to receive(:snapshots_defs_for).with(rep).and_return(snapshot_defs_for_rep)
|
@@ -93,6 +101,21 @@ describe Nanoc::Int::Compiler do
|
|
93
101
|
.to('3')
|
94
102
|
end
|
95
103
|
|
104
|
+
it 'removes the item rep from the outdatedness store' do
|
105
|
+
expect(compiler.outdatedness_store.include?(rep)).not_to be
|
106
|
+
expect { subject }.not_to change { compiler.outdatedness_store.include?(rep) }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'rep in outdatedness store' do
|
110
|
+
before do
|
111
|
+
compiler.outdatedness_store.add(rep)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'removes the item rep from the outdatedness store' do
|
115
|
+
expect { subject }.to change { compiler.outdatedness_store.include?(rep) }.from(true).to(false)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
96
119
|
context 'exception' do
|
97
120
|
let(:item) { Nanoc::Int::Item.new('<%= raise "lol" %>', {}, '/hi.md') }
|
98
121
|
|
@@ -112,11 +135,28 @@ describe Nanoc::Int::Compiler do
|
|
112
135
|
expect(err.unwrap.message).to eq('lol')
|
113
136
|
end
|
114
137
|
end
|
138
|
+
|
139
|
+
it 'adds the item rep to the outdatedness store' do
|
140
|
+
expect { subject rescue nil }.to change { compiler.outdatedness_store.include?(rep) }.from(false).to(true)
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'rep in outdatedness store' do
|
144
|
+
before do
|
145
|
+
compiler.outdatedness_store.add(rep)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'keeps the item rep in the outdatedness store' do
|
149
|
+
expect(compiler.outdatedness_store.include?(rep)).to be
|
150
|
+
expect { subject rescue nil }.not_to change { compiler.outdatedness_store.include?(rep) }
|
151
|
+
end
|
152
|
+
end
|
115
153
|
end
|
116
154
|
end
|
117
155
|
|
118
156
|
describe '#compile_rep' do
|
119
|
-
|
157
|
+
let(:stage) { compiler.send(:compile_reps_stage) }
|
158
|
+
|
159
|
+
subject { stage.send(:compile_rep, rep, is_outdated: is_outdated) }
|
120
160
|
|
121
161
|
let(:is_outdated) { true }
|
122
162
|
|
@@ -145,10 +185,10 @@ describe Nanoc::Int::Compiler do
|
|
145
185
|
it 'generates expected output' do
|
146
186
|
expect(rep.snapshot_contents[:last].string).to eql(item.content.string)
|
147
187
|
|
148
|
-
expect {
|
188
|
+
expect { stage.send(:compile_rep, rep, is_outdated: true) }
|
149
189
|
.to raise_error(Nanoc::Int::Errors::UnmetDependency)
|
150
|
-
|
151
|
-
|
190
|
+
stage.send(:compile_rep, other_rep, is_outdated: true)
|
191
|
+
stage.send(:compile_rep, rep, is_outdated: true)
|
152
192
|
|
153
193
|
expect(rep.snapshot_contents[:last].string).to eql('other=other content')
|
154
194
|
end
|
@@ -171,10 +211,10 @@ describe Nanoc::Int::Compiler do
|
|
171
211
|
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:filtering_ended, rep, :erb).ordered
|
172
212
|
expect(Nanoc::Int::NotificationCenter).to receive(:post).with(:compilation_ended, rep).ordered
|
173
213
|
|
174
|
-
expect {
|
214
|
+
expect { stage.send(:compile_rep, rep, is_outdated: true) }
|
175
215
|
.to raise_error(Nanoc::Int::Errors::UnmetDependency)
|
176
|
-
|
177
|
-
|
216
|
+
stage.send(:compile_rep, other_rep, is_outdated: true)
|
217
|
+
stage.send(:compile_rep, rep, is_outdated: true)
|
178
218
|
end
|
179
219
|
end
|
180
220
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
describe Nanoc::Int::OutdatednessStore do
|
2
|
+
subject(:store) { described_class.new(site: site, reps: reps) }
|
3
|
+
|
4
|
+
let(:site) { double(:site) }
|
5
|
+
let(:reps) { Nanoc::Int::ItemRepRepo.new }
|
6
|
+
|
7
|
+
let(:item) { Nanoc::Int::Item.new('foo', {}, '/foo.md') }
|
8
|
+
let(:rep) { Nanoc::Int::ItemRep.new(item, :foo) }
|
9
|
+
|
10
|
+
let(:site) do
|
11
|
+
Nanoc::Int::Site.new(
|
12
|
+
config: config,
|
13
|
+
code_snippets: code_snippets,
|
14
|
+
items: items,
|
15
|
+
layouts: layouts,
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:config) { Nanoc::Int::Configuration.new.with_defaults }
|
20
|
+
let(:items) { [] }
|
21
|
+
let(:layouts) { [] }
|
22
|
+
let(:code_snippets) { [] }
|
23
|
+
|
24
|
+
describe '#include?, #add and #remove' do
|
25
|
+
subject { store.include?(rep) }
|
26
|
+
|
27
|
+
context 'nothing added' do
|
28
|
+
it { is_expected.not_to be }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'rep added' do
|
32
|
+
before { store.add(rep) }
|
33
|
+
it { is_expected.to be }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'rep added and removed' do
|
37
|
+
before do
|
38
|
+
store.add(rep)
|
39
|
+
store.remove(rep)
|
40
|
+
end
|
41
|
+
|
42
|
+
it { is_expected.not_to be }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'rep added, removed, and added again' do
|
46
|
+
before do
|
47
|
+
store.add(rep)
|
48
|
+
store.remove(rep)
|
49
|
+
store.add(rep)
|
50
|
+
end
|
51
|
+
|
52
|
+
it { is_expected.to be }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#to_a' do
|
57
|
+
subject { store.to_a }
|
58
|
+
|
59
|
+
context 'nothing added' do
|
60
|
+
it { is_expected.to be_empty }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'one rep added' do
|
64
|
+
before { store.add(rep) }
|
65
|
+
it { is_expected.to eql([rep]) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'reloading' do
|
70
|
+
subject do
|
71
|
+
store.store
|
72
|
+
store.load
|
73
|
+
store.include?(rep)
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'not added' do
|
77
|
+
context 'rep part of new reps' do
|
78
|
+
before { reps << rep }
|
79
|
+
it { is_expected.not_to be }
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'rep not part of new reps' do
|
83
|
+
it { is_expected.not_to be }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'added' do
|
88
|
+
before { store.add(rep) }
|
89
|
+
|
90
|
+
context 'rep part of new reps' do
|
91
|
+
before { reps << rep }
|
92
|
+
it { is_expected.to be }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'rep not part of new reps' do
|
96
|
+
it { is_expected.not_to be }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -10,9 +10,22 @@ describe Nanoc::Int::OutdatednessChecker do
|
|
10
10
|
)
|
11
11
|
end
|
12
12
|
|
13
|
-
let(:site) { double(:site) }
|
14
13
|
let(:checksum_store) { double(:checksum_store) }
|
15
|
-
|
14
|
+
|
15
|
+
let(:dependency_store) do
|
16
|
+
Nanoc::Int::DependencyStore.new(objects)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:objects) { [item] }
|
20
|
+
|
21
|
+
let(:site) do
|
22
|
+
Nanoc::Int::Site.new(
|
23
|
+
config: config,
|
24
|
+
items: [],
|
25
|
+
layouts: [],
|
26
|
+
code_snippets: [],
|
27
|
+
)
|
28
|
+
end
|
16
29
|
|
17
30
|
let(:rule_memory_store) do
|
18
31
|
Nanoc::Int::RuleMemoryStore.new
|
@@ -102,10 +115,6 @@ describe Nanoc::Int::OutdatednessChecker do
|
|
102
115
|
describe '#outdated_due_to_dependencies?' do
|
103
116
|
subject { outdatedness_checker.send(:outdated_due_to_dependencies?, item) }
|
104
117
|
|
105
|
-
let(:dependency_store) do
|
106
|
-
Nanoc::Int::DependencyStore.new(objects)
|
107
|
-
end
|
108
|
-
|
109
118
|
let(:checksum_store) { Nanoc::Int::ChecksumStore.new(objects: objects) }
|
110
119
|
|
111
120
|
let(:other_item) { Nanoc::Int::Item.new('other stuff', {}, '/other.md') }
|
@@ -18,11 +18,19 @@ describe Nanoc::Int::OutdatednessRules do
|
|
18
18
|
let(:item_rep) { Nanoc::Int::ItemRep.new(item, :default) }
|
19
19
|
let(:item) { Nanoc::Int::Item.new('stuff', {}, '/foo.md') }
|
20
20
|
|
21
|
-
let(:site) { double(:site) }
|
22
21
|
let(:config) { Nanoc::Int::Configuration.new }
|
23
22
|
let(:code_snippets) { [] }
|
24
23
|
let(:objects) { [config] + code_snippets + [item] }
|
25
24
|
|
25
|
+
let(:site) do
|
26
|
+
Nanoc::Int::Site.new(
|
27
|
+
config: config,
|
28
|
+
items: [],
|
29
|
+
layouts: [],
|
30
|
+
code_snippets: code_snippets,
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
26
34
|
let(:action_provider) { double(:action_provider) }
|
27
35
|
let(:reps) { Nanoc::Int::ItemRepRepo.new }
|
28
36
|
let(:dependency_store) { Nanoc::Int::DependencyStore.new(dependency_store_objects) }
|
@@ -67,15 +75,15 @@ describe Nanoc::Int::OutdatednessRules do
|
|
67
75
|
context 'ConfigurationModified' do
|
68
76
|
let(:rule_class) { Nanoc::Int::OutdatednessRules::ConfigurationModified }
|
69
77
|
|
70
|
-
context '
|
71
|
-
let(:config) { Nanoc::Int::
|
78
|
+
context 'non-outdated' do
|
79
|
+
let(:config) { Nanoc::Int::Configuration.new }
|
72
80
|
|
73
81
|
before { checksum_store.add(config) }
|
74
82
|
|
75
83
|
it { is_expected.not_to be }
|
76
84
|
end
|
77
85
|
|
78
|
-
context '
|
86
|
+
context 'outdated' do
|
79
87
|
let(:config) { Nanoc::Int::Configuration.new }
|
80
88
|
let(:config_old) { Nanoc::Int::Configuration.new(hash: { foo: 125 }) }
|
81
89
|
|
@@ -48,7 +48,19 @@ describe Nanoc::DataSources::Filesystem do
|
|
48
48
|
expect(subject[0].identifier).to eq(Nanoc::Identifier.new('/bar/'))
|
49
49
|
expect(subject[0].checksum_data).to be_nil
|
50
50
|
expect(subject[0].content_checksum_data).to eq('test 1')
|
51
|
-
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'has the right attributes checksum data' do
|
54
|
+
cs = YAML.load(subject[0].attributes_checksum_data)
|
55
|
+
|
56
|
+
expect(cs[:attributes]).to eq("num: 1\n")
|
57
|
+
expect(cs[:extra_attributes]).to eq(
|
58
|
+
filename: 'foo/bar.html',
|
59
|
+
content_filename: 'foo/bar.html',
|
60
|
+
meta_filename: nil,
|
61
|
+
extension: 'html',
|
62
|
+
mtime: now,
|
63
|
+
)
|
52
64
|
end
|
53
65
|
end
|
54
66
|
end
|
@@ -13,7 +13,7 @@ describe Nanoc::Extra::ParallelCollection do
|
|
13
13
|
let!(:out) { [] }
|
14
14
|
|
15
15
|
it 'is fast' do
|
16
|
-
expect { subject }.to finish_in_under(0.
|
16
|
+
expect { subject }.to finish_in_under(0.25).seconds
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'is correct' do
|
@@ -66,7 +66,7 @@ describe Nanoc::Extra::ParallelCollection do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'is fast' do
|
69
|
-
expect { subject }.to finish_in_under(0.
|
69
|
+
expect { subject }.to finish_in_under(0.25).seconds
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'does not leave threads lingering' do
|
@@ -1,9 +1,14 @@
|
|
1
1
|
describe 'Outdatedness integration', site: true, stdio: true do
|
2
2
|
context 'only attribute dependency' do
|
3
|
+
let(:time) { Time.now }
|
4
|
+
|
3
5
|
before do
|
4
6
|
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoo")
|
5
7
|
File.write('content/bar.md', '<%= @items["/foo.*"][:title] %>')
|
6
8
|
|
9
|
+
FileUtils.touch('content/foo.md', mtime: time)
|
10
|
+
FileUtils.touch('content/bar.md', mtime: time)
|
11
|
+
|
7
12
|
File.write('Rules', <<EOS)
|
8
13
|
compile '/foo.*' do
|
9
14
|
write '/foo.html'
|
@@ -29,6 +34,7 @@ EOS
|
|
29
34
|
|
30
35
|
it 'shows file as outdated after modification' do
|
31
36
|
File.write('content/bar.md', 'JUST BAR!')
|
37
|
+
FileUtils.touch('content/bar.md', mtime: time)
|
32
38
|
|
33
39
|
expect { Nanoc::CLI.run(%w(show-data --no-color)) }.to(
|
34
40
|
output(/^item \/foo\.md, rep default:\n is not outdated/).to_stdout,
|
@@ -40,6 +46,7 @@ EOS
|
|
40
46
|
|
41
47
|
it 'shows file and dependencies as not outdated after content modification' do
|
42
48
|
File.write('content/foo.md', "---\ntitle: hello\n---\n\nfoooOoooOOoooOooo")
|
49
|
+
FileUtils.touch('content/foo.md', mtime: time)
|
43
50
|
|
44
51
|
expect { Nanoc::CLI.run(%w(show-data --no-color)) }.to(
|
45
52
|
output(/^item \/foo\.md, rep default:\n is outdated: /).to_stdout,
|
@@ -51,6 +58,7 @@ EOS
|
|
51
58
|
|
52
59
|
it 'shows file and dependencies as outdated after title modification' do
|
53
60
|
File.write('content/foo.md', "---\ntitle: bye\n---\n\nfoo")
|
61
|
+
FileUtils.touch('content/foo.md', mtime: time)
|
54
62
|
|
55
63
|
expect { Nanoc::CLI.run(%w(show-data --no-color)) }.to(
|
56
64
|
output(/^item \/foo\.md, rep default:\n is outdated: /).to_stdout,
|