nanoc 4.8.10 → 4.8.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/NEWS.md +7 -0
- data/lib/nanoc.rb +11 -6
- data/lib/nanoc/base.rb +1 -0
- data/lib/nanoc/base/changes_stream.rb +53 -0
- data/lib/nanoc/base/contracts_support.rb +0 -2
- data/lib/nanoc/base/feature.rb +3 -0
- data/lib/nanoc/base/memoization.rb +0 -2
- data/lib/nanoc/base/repos/aggregate_data_source.rb +8 -0
- data/lib/nanoc/base/repos/data_source.rb +12 -0
- data/lib/nanoc/base/repos/in_mem_data_source.rb +10 -1
- data/lib/nanoc/base/repos/prefixed_data_source.rb +8 -0
- data/lib/nanoc/base/repos/site_loader.rb +11 -7
- data/lib/nanoc/base/services/compiler.rb +2 -3
- data/lib/nanoc/base/services/compiler/stages/postprocess.rb +2 -3
- data/lib/nanoc/base/services/compiler/stages/preprocess.rb +1 -1
- data/lib/nanoc/base/services/pruner.rb +0 -2
- data/lib/nanoc/base/services/temp_filename_factory.rb +0 -2
- data/lib/nanoc/checking/checks/external_links.rb +0 -5
- data/lib/nanoc/checking/checks/internal_links.rb +0 -2
- data/lib/nanoc/checking/checks/stale.rb +0 -2
- data/lib/nanoc/cli.rb +7 -1
- data/lib/nanoc/cli/commands/compile_listeners/diff_generator.rb +0 -3
- data/lib/nanoc/cli/commands/live.rb +30 -0
- data/lib/nanoc/cli/commands/view.rb +4 -5
- data/lib/nanoc/cli/error_handler.rb +52 -36
- data/lib/nanoc/cli/logger.rb +0 -2
- data/lib/nanoc/cli/stack_trace_writer.rb +50 -0
- data/lib/nanoc/data_sources/filesystem.rb +25 -0
- data/lib/nanoc/extra.rb +1 -0
- data/lib/nanoc/extra/jruby_nokogiri_warner.rb +0 -2
- data/lib/nanoc/extra/link_collector.rb +0 -2
- data/lib/nanoc/extra/live_recompiler.rb +131 -0
- data/lib/nanoc/extra/parallel_collection.rb +0 -2
- data/lib/nanoc/extra/piper.rb +0 -2
- data/lib/nanoc/filters/relativize_paths.rb +8 -7
- data/lib/nanoc/helpers/link_to.rb +0 -2
- data/lib/nanoc/rule_dsl/action_provider.rb +2 -2
- data/lib/nanoc/version.rb +1 -1
- data/nanoc.gemspec +15 -4
- data/nanoc.manifest +545 -0
- data/spec/manifest_spec.rb +22 -0
- data/spec/nanoc/base/changes_stream_spec.rb +45 -0
- data/spec/nanoc/base/checksummer_spec.rb +0 -2
- data/spec/nanoc/base/directed_graph_spec.rb +66 -0
- data/spec/nanoc/base/entities/code_snippet_spec.rb +9 -0
- data/spec/nanoc/base/entities/context_spec.rb +26 -0
- data/spec/nanoc/base/entities/identifiable_collection_spec.rb +53 -0
- data/spec/nanoc/base/repos/aggregate_data_source_spec.rb +87 -0
- data/spec/nanoc/base/repos/data_source_spec.rb +95 -0
- data/spec/nanoc/base/repos/in_mem_data_source_spec.rb +39 -0
- data/spec/nanoc/base/repos/prefixed_data_source_spec.rb +39 -0
- data/spec/nanoc/cli/error_handler_spec.rb +43 -0
- data/spec/nanoc/cli/stack_trace_writer_spec.rb +156 -0
- data/spec/nanoc/data_sources/filesystem_spec.rb +46 -0
- data/spec/nanoc/extra/live_recompiler_spec.rb +129 -0
- data/spec/nanoc/helpers/blogging_spec.rb +1 -1
- data/spec/spec_helper.rb +60 -0
- data/test/base/test_compiler.rb +11 -11
- data/test/cli/test_cli.rb +0 -1
- data/test/cli/test_error_handler.rb +4 -5
- data/test/filters/test_relativize_paths.rb +30 -0
- data/test/filters/test_sass.rb +3 -3
- data/test/rule_dsl/test_compiler_dsl.rb +2 -2
- metadata +39 -43
- data/.github/CONTRIBUTING.md +0 -17
- data/.github/ISSUE_TEMPLATE.md +0 -23
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -18
- data/.gitignore +0 -10
- data/.travis.yml +0 -27
- data/Gemfile +0 -73
- data/Guardfile +0 -5
- data/scripts/release +0 -95
- data/test/base/test_code_snippet.rb +0 -17
- data/test/base/test_context.rb +0 -35
- data/test/base/test_data_source.rb +0 -60
- data/test/base/test_directed_graph.rb +0 -56
- data/test/base/test_item_array.rb +0 -37
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe 'manifest', chdir: false do
|
4
|
+
let(:manifest_lines) do
|
5
|
+
File.readlines('nanoc.manifest').map(&:chomp).reject(&:empty?)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:gemspec_lines) do
|
9
|
+
gemspec = eval(File.read('nanoc.gemspec'), binding, 'nanoc.gemspec')
|
10
|
+
gemspec.files
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'contains all files in gemspec' do
|
14
|
+
missing_from_manifest = gemspec_lines - manifest_lines
|
15
|
+
expect(missing_from_manifest).to be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'contains no files not in gemspec' do
|
19
|
+
extra_in_manifest = manifest_lines - gemspec_lines
|
20
|
+
expect(extra_in_manifest).to be_empty
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Nanoc::ChangesStream do
|
4
|
+
let(:simple_stream) do
|
5
|
+
described_class.new do |cl|
|
6
|
+
cl.unknown
|
7
|
+
sleep
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns a stream of events generated by the listener' do
|
12
|
+
buffered_stream = DDBuffer.new(1).call(simple_stream)
|
13
|
+
expect(buffered_stream.take(1).to_a).to eq([:unknown])
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#map' do
|
17
|
+
it 'returns a new maped enum' do
|
18
|
+
stream = simple_stream.map { |e| e.to_s.upcase }
|
19
|
+
buffered_stream = DDBuffer.new(1).call(stream)
|
20
|
+
expect(buffered_stream.take(1).to_a).to eq(['UNKNOWN'])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#to_enum' do
|
25
|
+
it 'returns an enumerator corresponding to itself' do
|
26
|
+
buffered_stream = DDBuffer.new(1).call(simple_stream.to_enum)
|
27
|
+
expect(buffered_stream.take(1).to_a).to eq([:unknown])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#stop' do
|
32
|
+
let(:simple_stream) do
|
33
|
+
described_class.new do |cl|
|
34
|
+
cl.to_stop { $changes_stream_stopped = true }
|
35
|
+
sleep
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
example do
|
40
|
+
DDBuffer.new(1).call(simple_stream)
|
41
|
+
sleep 0.1
|
42
|
+
expect { simple_stream.stop }.to change { $changes_stream_stopped }.from(nil).to(true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -51,6 +51,37 @@ describe Nanoc::Int::DirectedGraph do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
it 'has correct examples' do
|
55
|
+
expect('Nanoc::Int::DirectedGraph')
|
56
|
+
.to have_correct_yard_examples
|
57
|
+
.in_file('lib/nanoc/base/entities/directed_graph.rb')
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#vertices' do
|
61
|
+
subject { graph.vertices }
|
62
|
+
|
63
|
+
it { is_expected.to include('1') }
|
64
|
+
it { is_expected.not_to include('4') }
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#add_edge' do
|
68
|
+
subject { graph.add_edge('1', '4') }
|
69
|
+
|
70
|
+
it 'adds vertex' do
|
71
|
+
expect { subject }
|
72
|
+
.to change { graph.vertices.include?('4') }
|
73
|
+
.from(false)
|
74
|
+
.to(true)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'changes direct predecessors' do
|
78
|
+
expect { subject }
|
79
|
+
.to change { graph.direct_predecessors_of('4') }
|
80
|
+
.from([])
|
81
|
+
.to(['1'])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
54
85
|
describe '#props_for' do
|
55
86
|
subject { graph.props_for('1', '2') }
|
56
87
|
|
@@ -148,6 +179,41 @@ describe Nanoc::Int::DirectedGraph do
|
|
148
179
|
end
|
149
180
|
end
|
150
181
|
|
182
|
+
describe '#delete_edges_to' do
|
183
|
+
before do
|
184
|
+
graph.add_edge('1', '2')
|
185
|
+
graph.add_edge('2', '1')
|
186
|
+
graph.add_edge('2', '3')
|
187
|
+
graph.add_edge('3', '2')
|
188
|
+
graph.add_edge('1', '3')
|
189
|
+
graph.add_edge('3', '1')
|
190
|
+
end
|
191
|
+
|
192
|
+
subject { graph.delete_edges_to('1') }
|
193
|
+
|
194
|
+
it 'deletes edges to 1' do
|
195
|
+
expect { subject }
|
196
|
+
.to change { graph.direct_predecessors_of('1') }
|
197
|
+
.from(%w[2 3])
|
198
|
+
.to([])
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'keeps edges to 2' do
|
202
|
+
expect { subject }
|
203
|
+
.not_to change { graph.direct_predecessors_of('2') }
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'keeps edges to 3' do
|
207
|
+
expect { subject }
|
208
|
+
.not_to change { graph.direct_predecessors_of('3') }
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'keeps edges to 4' do
|
212
|
+
expect { subject }
|
213
|
+
.not_to change { graph.direct_predecessors_of('4') }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
151
217
|
describe '#inspect' do
|
152
218
|
subject { graph.inspect }
|
153
219
|
|
@@ -47,5 +47,14 @@ describe Nanoc::Int::CodeSnippet do
|
|
47
47
|
.to([true, false])
|
48
48
|
end
|
49
49
|
end
|
50
|
+
|
51
|
+
it 'defines at top level' do
|
52
|
+
@foo = 'meow'
|
53
|
+
|
54
|
+
code_snippet = Nanoc::Int::CodeSnippet.new("@foo = 'woof'", 'dog.rb')
|
55
|
+
code_snippet.load
|
56
|
+
|
57
|
+
expect(@foo).to eq('meow')
|
58
|
+
end
|
50
59
|
end
|
51
60
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Nanoc::Int::Context do
|
4
|
+
let(:context) do
|
5
|
+
Nanoc::Int::Context.new(foo: 'bar', baz: 'quux')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'provides instance variables' do
|
9
|
+
expect(eval('@foo', context.get_binding)).to eq('bar')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'provides instance methods' do
|
13
|
+
expect(eval('foo', context.get_binding)).to eq('bar')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'supports #include' do
|
17
|
+
eval('include Nanoc::Helpers::HTMLEscape', context.get_binding)
|
18
|
+
expect(eval('h("<>")', context.get_binding)).to eq('<>')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has correct examples' do
|
22
|
+
expect('Nanoc::Int::Context#initialize')
|
23
|
+
.to have_correct_yard_examples
|
24
|
+
.in_file('lib/nanoc/base/entities/context.rb')
|
25
|
+
end
|
26
|
+
end
|
@@ -142,6 +142,59 @@ describe Nanoc::Int::IdentifiableCollection do
|
|
142
142
|
subject { identifiable_collection.reference }
|
143
143
|
it { is_expected.to eql(expected_reference) }
|
144
144
|
end
|
145
|
+
|
146
|
+
describe 'changing identifiers' do
|
147
|
+
let(:objects) do
|
148
|
+
[
|
149
|
+
Nanoc::Int::Item.new('Foo', {}, '/foo'),
|
150
|
+
]
|
151
|
+
end
|
152
|
+
|
153
|
+
subject { objects[0].identifier = '/bar' }
|
154
|
+
|
155
|
+
it 'makes /foo nil' do
|
156
|
+
expect { subject }
|
157
|
+
.to change { identifiable_collection['/foo'] }
|
158
|
+
.from(objects[0])
|
159
|
+
.to(nil)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'makes /bar non-nil' do
|
163
|
+
expect { subject }
|
164
|
+
.to change { identifiable_collection['/bar'] }
|
165
|
+
.from(nil)
|
166
|
+
.to(objects[0])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#each' do
|
171
|
+
let(:objects) do
|
172
|
+
[
|
173
|
+
Nanoc::Int::Item.new('Foo', {}, '/foo'),
|
174
|
+
Nanoc::Int::Item.new('Bar', {}, '/bar'),
|
175
|
+
]
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'loops' do
|
179
|
+
res = []
|
180
|
+
identifiable_collection.each { |i| res << i.identifier.to_s }
|
181
|
+
expect(res).to match_array(['/foo', '/bar'])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#map' do
|
186
|
+
let(:objects) do
|
187
|
+
[
|
188
|
+
Nanoc::Int::Item.new('Foo', {}, '/foo'),
|
189
|
+
Nanoc::Int::Item.new('Bar', {}, '/bar'),
|
190
|
+
]
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'loops' do
|
194
|
+
res = identifiable_collection.map { |i| i.identifier.to_s }
|
195
|
+
expect(res).to match_array(['/foo', '/bar'])
|
196
|
+
end
|
197
|
+
end
|
145
198
|
end
|
146
199
|
|
147
200
|
describe Nanoc::Int::ItemCollection do
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Nanoc::Int::AggregateDataSource, stdio: true do
|
4
|
+
let(:klass_1) do
|
5
|
+
Class.new(Nanoc::DataSource) do
|
6
|
+
def items
|
7
|
+
[Nanoc::Int::Item.new('One', {}, '/one.md')]
|
8
|
+
end
|
9
|
+
|
10
|
+
def item_changes
|
11
|
+
%i[one_foo one_bar]
|
12
|
+
end
|
13
|
+
|
14
|
+
def layouts
|
15
|
+
[Nanoc::Int::Layout.new('One', {}, '/one.md')]
|
16
|
+
end
|
17
|
+
|
18
|
+
def layout_changes
|
19
|
+
%i[one_foo one_bar]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:klass_2) do
|
25
|
+
Class.new(Nanoc::DataSource) do
|
26
|
+
def items
|
27
|
+
[Nanoc::Int::Item.new('Two', {}, '/two.md')]
|
28
|
+
end
|
29
|
+
|
30
|
+
def item_changes
|
31
|
+
%i[two_foo two_bar]
|
32
|
+
end
|
33
|
+
|
34
|
+
def layouts
|
35
|
+
[Nanoc::Int::Layout.new('Two', {}, '/two.md')]
|
36
|
+
end
|
37
|
+
|
38
|
+
def layout_changes
|
39
|
+
%i[two_foo two_bar]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:data_source_1) do
|
45
|
+
klass_1.new({}, nil, nil, {})
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:data_source_2) do
|
49
|
+
klass_2.new({}, nil, nil, {})
|
50
|
+
end
|
51
|
+
|
52
|
+
subject(:data_source) do
|
53
|
+
described_class.new([data_source_1, data_source_2], {})
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#items' do
|
57
|
+
subject { data_source.items }
|
58
|
+
|
59
|
+
it 'contains all items' do
|
60
|
+
expect(subject).to match_array(data_source_1.items + data_source_2.items)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#layouts' do
|
65
|
+
subject { data_source.layouts }
|
66
|
+
|
67
|
+
it 'contains all layouts' do
|
68
|
+
expect(subject).to match_array(data_source_1.layouts + data_source_2.layouts)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#item_changes' do
|
73
|
+
subject { data_source.item_changes }
|
74
|
+
|
75
|
+
it 'yields changes from both' do
|
76
|
+
expect(subject).to match_array(data_source_1.item_changes + data_source_2.item_changes)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#layout_changes' do
|
81
|
+
subject { data_source.layout_changes }
|
82
|
+
|
83
|
+
it 'yields changes from both' do
|
84
|
+
expect(subject).to match_array(data_source_1.layout_changes + data_source_2.layout_changes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Nanoc::DataSource, stdio: true do
|
4
|
+
subject(:data_source) do
|
5
|
+
described_class.new({}, nil, nil, {})
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has an empty #up implementation' do
|
9
|
+
data_source.up
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has an empty #down implementation' do
|
13
|
+
data_source.down
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns empty #items' do
|
17
|
+
expect(data_source.items).to be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns empty #layouts' do
|
21
|
+
expect(data_source.layouts).to be_empty
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#new_item' do
|
25
|
+
it 'supports checksum data' do
|
26
|
+
item = data_source.new_item('stuff', { title: 'Stuff!' }, '/asdf', checksum_data: 'abcdef')
|
27
|
+
|
28
|
+
expect(item.content.string).to eql('stuff')
|
29
|
+
expect(item.attributes[:title]).to eql('Stuff!')
|
30
|
+
expect(item.identifier).to eql(Nanoc::Identifier.new('/asdf'))
|
31
|
+
expect(item.checksum_data).to eql('abcdef')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'supports content/attributes checksum data' do
|
35
|
+
item = data_source.new_item('stuff', { title: 'Stuff!' }, '/asdf', content_checksum_data: 'con-cs', attributes_checksum_data: 'attr-cs')
|
36
|
+
|
37
|
+
expect(item.content.string).to eql('stuff')
|
38
|
+
expect(item.attributes[:title]).to eql('Stuff!')
|
39
|
+
expect(item.identifier).to eql(Nanoc::Identifier.new('/asdf'))
|
40
|
+
expect(item.content_checksum_data).to eql('con-cs')
|
41
|
+
expect(item.attributes_checksum_data).to eql('attr-cs')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#new_layout' do
|
46
|
+
it 'supports checksum data' do
|
47
|
+
layout = data_source.new_layout('stuff', { title: 'Stuff!' }, '/asdf', checksum_data: 'abcdef')
|
48
|
+
|
49
|
+
expect(layout.content.string).to eql('stuff')
|
50
|
+
expect(layout.attributes[:title]).to eql('Stuff!')
|
51
|
+
expect(layout.identifier).to eql(Nanoc::Identifier.new('/asdf'))
|
52
|
+
expect(layout.checksum_data).to eql('abcdef')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'supports content/attributes checksum data' do
|
56
|
+
layout = data_source.new_layout('stuff', { title: 'Stuff!' }, '/asdf', content_checksum_data: 'con-cs', attributes_checksum_data: 'attr-cs')
|
57
|
+
|
58
|
+
expect(layout.content.string).to eql('stuff')
|
59
|
+
expect(layout.attributes[:title]).to eql('Stuff!')
|
60
|
+
expect(layout.identifier).to eql(Nanoc::Identifier.new('/asdf'))
|
61
|
+
expect(layout.content_checksum_data).to eql('con-cs')
|
62
|
+
expect(layout.attributes_checksum_data).to eql('attr-cs')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#item_changes' do
|
67
|
+
subject { data_source.item_changes }
|
68
|
+
|
69
|
+
it 'warns' do
|
70
|
+
expect { subject }.to output("Caution: Data source nil does not implement #item_changes; live compilation will not pick up changes in this data source.\n").to_stderr
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'never yields anything' do
|
74
|
+
q = SizedQueue.new(1)
|
75
|
+
Thread.new { subject.each { |c| q << c } }
|
76
|
+
sleep 0.1
|
77
|
+
expect { q.pop(true) }.to raise_error(ThreadError)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#layout_changes' do
|
82
|
+
subject { data_source.layout_changes }
|
83
|
+
|
84
|
+
it 'warns' do
|
85
|
+
expect { subject }.to output("Caution: Data source nil does not implement #layout_changes; live compilation will not pick up changes in this data source.\n").to_stderr
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'never yields anything' do
|
89
|
+
q = SizedQueue.new(1)
|
90
|
+
Thread.new { subject.each { |c| q << c } }
|
91
|
+
sleep 0.1
|
92
|
+
expect { q.pop(true) }.to raise_error(ThreadError)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|