nanoc 4.7.10 → 4.7.11
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.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +17 -0
- data/.github/ISSUE_TEMPLATE.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +18 -0
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +174 -0
- data/.travis.yml +27 -0
- data/Gemfile +4 -3
- data/NEWS.md +11 -0
- data/Rakefile +5 -2
- data/lib/nanoc/base/entities/dependency.rb +5 -3
- data/lib/nanoc/base/entities/layout.rb +1 -1
- data/lib/nanoc/base/repos/dependency_store.rb +64 -28
- data/lib/nanoc/base/services/dependency_tracker.rb +1 -1
- data/lib/nanoc/base/views/config_view.rb +4 -0
- data/lib/nanoc/checking/checks/external_links.rb +3 -6
- data/lib/nanoc/cli.rb +0 -2
- data/lib/nanoc/cli/commands/shell.rb +2 -3
- data/lib/nanoc/filters/colorize_syntax/colorizers.rb +4 -1
- data/lib/nanoc/telemetry/table.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- data/nanoc.gemspec +1 -5
- data/scripts/release +95 -0
- data/{test → spec/nanoc}/base/core_ext/array_spec.rb +5 -14
- data/{test → spec/nanoc}/base/core_ext/hash_spec.rb +6 -15
- data/{test → spec/nanoc}/base/core_ext/pathname_spec.rb +0 -0
- data/spec/nanoc/base/core_ext/string_spec.rb +23 -0
- data/spec/nanoc/base/directed_graph_spec.rb +291 -0
- data/spec/nanoc/base/entities/identifiable_collection_spec.rb +56 -0
- data/spec/nanoc/base/entities/item_spec.rb +8 -0
- data/spec/nanoc/base/entities/layout_spec.rb +8 -0
- data/spec/nanoc/base/repos/dependency_store_spec.rb +166 -21
- data/spec/nanoc/base/views/config_view_spec.rb +29 -1
- data/spec/nanoc/cli/commands/shell_spec.rb +23 -8
- data/spec/nanoc/filters/less_spec.rb +1 -1
- data/spec/nanoc/regressions/gh_1185_spec.rb +22 -0
- data/spec/nanoc/telemetry/table_spec.rb +22 -0
- data/spec/spec_helper.rb +5 -6
- data/test/base/test_item_array.rb +0 -35
- data/test/checking/checks/test_external_links.rb +0 -14
- data/test/filters/test_coffeescript.rb +0 -2
- data/test/filters/test_handlebars.rb +0 -4
- data/test/filters/test_uglify_js.rb +0 -4
- data/test/helper.rb +0 -6
- data/test/helpers/test_blogging.rb +66 -26
- data/test/helpers/test_xml_sitemap.rb +23 -7
- metadata +16 -9
- data/Gemfile.lock +0 -433
- data/test/base/core_ext/string_spec.rb +0 -25
- data/test/base/test_item.rb +0 -40
- data/test/base/test_layout.rb +0 -16
@@ -5,7 +5,7 @@ module Nanoc::Int
|
|
5
5
|
class DependencyTracker
|
6
6
|
include Nanoc::Int::ContractsSupport
|
7
7
|
|
8
|
-
C_OBJ = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]
|
8
|
+
C_OBJ = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration]
|
9
9
|
C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
|
10
10
|
C_ARGS = C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]
|
11
11
|
|
@@ -18,6 +18,7 @@ module Nanoc
|
|
18
18
|
|
19
19
|
# @see Hash#fetch
|
20
20
|
def fetch(key, fallback = NONE, &_block)
|
21
|
+
@context.dependency_tracker.bounce(unwrap, attributes: [key])
|
21
22
|
@config.fetch(key) do
|
22
23
|
if !fallback.equal?(NONE)
|
23
24
|
fallback
|
@@ -31,16 +32,19 @@ module Nanoc
|
|
31
32
|
|
32
33
|
# @see Hash#key?
|
33
34
|
def key?(key)
|
35
|
+
@context.dependency_tracker.bounce(unwrap, attributes: [key])
|
34
36
|
@config.key?(key)
|
35
37
|
end
|
36
38
|
|
37
39
|
# @see Hash#[]
|
38
40
|
def [](key)
|
41
|
+
@context.dependency_tracker.bounce(unwrap, attributes: [key])
|
39
42
|
@config[key]
|
40
43
|
end
|
41
44
|
|
42
45
|
# @see Hash#each
|
43
46
|
def each(&block)
|
47
|
+
@context.dependency_tracker.bounce(unwrap, attributes: true)
|
44
48
|
@config.each(&block)
|
45
49
|
end
|
46
50
|
end
|
@@ -69,13 +69,10 @@ module ::Nanoc::Checking::Checks
|
|
69
69
|
begin
|
70
70
|
Timeout.timeout(timeouts[i]) do
|
71
71
|
res = request_url_once(url)
|
72
|
-
if res.code == '405'
|
73
|
-
res = request_url_once(url, Net::HTTP::Get)
|
74
|
-
end
|
75
72
|
end
|
76
73
|
rescue => e
|
77
74
|
last_err = e
|
78
|
-
next
|
75
|
+
next
|
79
76
|
end
|
80
77
|
|
81
78
|
if res.code =~ /^3..$/
|
@@ -122,8 +119,8 @@ module ::Nanoc::Checking::Checks
|
|
122
119
|
path
|
123
120
|
end
|
124
121
|
|
125
|
-
def request_url_once(url
|
126
|
-
req =
|
122
|
+
def request_url_once(url)
|
123
|
+
req = Net::HTTP::Get.new(path_for_url(url))
|
127
124
|
http = Net::HTTP.new(url.host, url.port)
|
128
125
|
if url.instance_of? URI::HTTPS
|
129
126
|
http.use_ssl = true
|
data/lib/nanoc/cli.rb
CHANGED
@@ -6,19 +6,18 @@ aliases 'console'
|
|
6
6
|
description "
|
7
7
|
Open an IRB shell on a context that contains @items, @layouts, and @config.
|
8
8
|
"
|
9
|
+
flag :p, :preprocess, 'run preprocessor'
|
9
10
|
|
10
11
|
module Nanoc::CLI::Commands
|
11
12
|
class Shell < ::Nanoc::CLI::CommandRunner
|
12
13
|
def run
|
13
14
|
require 'pry'
|
14
15
|
|
15
|
-
load_site
|
16
|
+
load_site(preprocess: options[:preprocess])
|
16
17
|
|
17
18
|
Nanoc::Int::Context.new(env).pry
|
18
19
|
end
|
19
20
|
|
20
|
-
protected
|
21
|
-
|
22
21
|
def env
|
23
22
|
self.class.env_for_site(site)
|
24
23
|
end
|
@@ -166,7 +166,10 @@ module Nanoc::Filters::ColorizeSyntax::Colorizers
|
|
166
166
|
code1 = element.xpath('code').first
|
167
167
|
return if code1.nil?
|
168
168
|
|
169
|
-
|
169
|
+
div = code1.xpath('div').first
|
170
|
+
|
171
|
+
# For Rouge 2.x and 1.x, respectively
|
172
|
+
pre = (div || code1).xpath('pre').first
|
170
173
|
return if pre.nil?
|
171
174
|
|
172
175
|
code2 = pre.xpath('code').first
|
@@ -13,7 +13,7 @@ module Nanoc::Telemetry
|
|
13
13
|
[].tap do |lines|
|
14
14
|
lines << row_to_s(@rows[0], column_lengths)
|
15
15
|
lines << separator(column_lengths)
|
16
|
-
lines.concat(@rows.map { |r| row_to_s(r, column_lengths) })
|
16
|
+
lines.concat(@rows.drop(1).map { |r| row_to_s(r, column_lengths) })
|
17
17
|
end.join("\n")
|
18
18
|
end
|
19
19
|
|
data/lib/nanoc/version.rb
CHANGED
data/nanoc.gemspec
CHANGED
@@ -13,11 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.email = 'denis.defreyne@stoneship.org'
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
16
|
-
s.files
|
17
|
-
Dir['[A-Z]*'] +
|
18
|
-
Dir['doc/yardoc_{templates,handlers}/**/*'] +
|
19
|
-
Dir['{bin,lib,tasks,test,spec}/**/*'] +
|
20
|
-
['nanoc.gemspec']
|
16
|
+
s.files = `git ls-files -z`.split("\x0")
|
21
17
|
s.executables = ['nanoc']
|
22
18
|
s.require_paths = ['lib']
|
23
19
|
|
data/scripts/release
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'octokit'
|
6
|
+
|
7
|
+
def run(*args)
|
8
|
+
puts 'I will execute the following:'
|
9
|
+
puts ' ' + args.map { |a| a =~ /\s/ ? a.inspect : a }.join(' ')
|
10
|
+
print 'Is this correct? [y/N] '
|
11
|
+
res = gets
|
12
|
+
unless res.strip.casecmp('y').zero?
|
13
|
+
$stderr.puts 'Answer was not Y; release aborted.'
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
system('echo', *args)
|
18
|
+
system(*args)
|
19
|
+
|
20
|
+
print 'Continue? [y/N] '
|
21
|
+
res = gets
|
22
|
+
unless res.strip.casecmp('y').zero?
|
23
|
+
$stderr.puts 'Answer was not Y; release aborted.'
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
puts '=== Logging in to GitHub’s API…'
|
29
|
+
client = Octokit::Client.new(netrc: true)
|
30
|
+
puts
|
31
|
+
|
32
|
+
puts '=== Deleting old *.gem files…'
|
33
|
+
Dir['*.gem'].each do |fn|
|
34
|
+
puts " #{fn}…"
|
35
|
+
FileUtils.rm_f(fn)
|
36
|
+
end
|
37
|
+
puts
|
38
|
+
|
39
|
+
puts '=== Verifying presence of release date…'
|
40
|
+
unless File.readlines('NEWS.md').drop(2).first =~ / \(\d{4}-\d{2}-\d{2}\)$/
|
41
|
+
$stderr.puts 'No proper release date found!'
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
puts
|
45
|
+
|
46
|
+
puts '=== Building new gem…'
|
47
|
+
run('gem', 'build', 'nanoc.gemspec')
|
48
|
+
puts
|
49
|
+
|
50
|
+
puts '=== Reading version…'
|
51
|
+
require './lib/nanoc/version'
|
52
|
+
puts "Version = #{Nanoc::VERSION}"
|
53
|
+
puts
|
54
|
+
|
55
|
+
puts '=== Verifying that release does not yet exist…'
|
56
|
+
releases = client.releases('nanoc/nanoc')
|
57
|
+
release = releases.find { |r| r.tag_name == Nanoc::VERSION }
|
58
|
+
if release
|
59
|
+
$stderr.puts 'Release already exists!'
|
60
|
+
$stderr.puts 'ABORTED!'
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
puts
|
64
|
+
|
65
|
+
puts '=== Creating Git tag…'
|
66
|
+
run('git', 'tag', '--sign', '--annotate', Nanoc::VERSION, '--message', "Version #{Nanoc::VERSION}")
|
67
|
+
puts
|
68
|
+
|
69
|
+
puts '=== Pushing Git data…'
|
70
|
+
run('git', 'push', 'origin', '--tags')
|
71
|
+
puts
|
72
|
+
|
73
|
+
puts '=== Pushing gem…'
|
74
|
+
run('gem', 'push', "nanoc-#{Nanoc::VERSION}.gem")
|
75
|
+
puts
|
76
|
+
|
77
|
+
puts '=== Reading release notes…'
|
78
|
+
release_notes =
|
79
|
+
File.readlines('NEWS.md')
|
80
|
+
.drop(4)
|
81
|
+
.take_while { |l| l !~ /^## / }
|
82
|
+
.join
|
83
|
+
puts
|
84
|
+
|
85
|
+
puts '=== Creating release on GitHub…'
|
86
|
+
sleep 3 # Give GitHub some time to detect the new tag
|
87
|
+
is_prerelease = Nanoc::VERSION =~ /a|b|rc/ || Nanoc::VERSION =~ /^0/
|
88
|
+
client.create_release(
|
89
|
+
'nanoc/nanoc', Nanoc::VERSION,
|
90
|
+
prerelease: !is_prerelease.nil?,
|
91
|
+
body: release_notes
|
92
|
+
)
|
93
|
+
puts
|
94
|
+
|
95
|
+
puts 'DONE!'
|
@@ -1,34 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'helper'
|
4
|
-
|
5
3
|
describe 'Array#__nanoc_symbolize_keys_recursively' do
|
6
4
|
it 'should convert keys to symbols' do
|
7
5
|
array_old = [:abc, 'xyz', { 'foo' => 'bar', :baz => :qux }]
|
8
6
|
array_new = [:abc, 'xyz', { foo: 'bar', baz: :qux }]
|
9
|
-
array_old.__nanoc_symbolize_keys_recursively.
|
7
|
+
expect(array_old.__nanoc_symbolize_keys_recursively).to eql(array_new)
|
10
8
|
end
|
11
9
|
end
|
12
10
|
|
13
11
|
describe 'Array#__nanoc_freeze_recursively' do
|
14
|
-
include Nanoc::TestHelpers
|
15
|
-
|
16
12
|
it 'should prevent first-level elements from being modified' do
|
17
13
|
array = [:a, %i[b c], :d]
|
18
14
|
array.__nanoc_freeze_recursively
|
19
15
|
|
20
|
-
|
21
|
-
array[0] = 123
|
22
|
-
end
|
16
|
+
expect { array[0] = 123 }.to raise_frozen_error
|
23
17
|
end
|
24
18
|
|
25
19
|
it 'should prevent second-level elements from being modified' do
|
26
20
|
array = [:a, %i[b c], :d]
|
27
21
|
array.__nanoc_freeze_recursively
|
28
22
|
|
29
|
-
|
30
|
-
array[1][0] = 123
|
31
|
-
end
|
23
|
+
expect { array[1][0] = 123 }.to raise_frozen_error
|
32
24
|
end
|
33
25
|
|
34
26
|
it 'should not freeze infinitely' do
|
@@ -37,8 +29,7 @@ describe 'Array#__nanoc_freeze_recursively' do
|
|
37
29
|
|
38
30
|
a.__nanoc_freeze_recursively
|
39
31
|
|
40
|
-
|
41
|
-
|
42
|
-
assert_equal a, a[0]
|
32
|
+
expect(a).to be_frozen
|
33
|
+
expect(a[0]).to be_frozen
|
43
34
|
end
|
44
35
|
end
|
@@ -1,40 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'helper'
|
4
|
-
|
5
3
|
describe 'Hash#__nanoc_symbolize_keys_recursively' do
|
6
4
|
it 'should convert keys to symbols' do
|
7
5
|
hash_old = { 'foo' => 'bar' }
|
8
6
|
hash_new = { foo: 'bar' }
|
9
|
-
hash_old.__nanoc_symbolize_keys_recursively.
|
7
|
+
expect(hash_old.__nanoc_symbolize_keys_recursively).to eql(hash_new)
|
10
8
|
end
|
11
9
|
|
12
10
|
it 'should not require string keys' do
|
13
11
|
hash_old = { Time.now => 'abc' }
|
14
12
|
hash_new = hash_old
|
15
|
-
hash_old.__nanoc_symbolize_keys_recursively.
|
13
|
+
expect(hash_old.__nanoc_symbolize_keys_recursively).to eql(hash_new)
|
16
14
|
end
|
17
15
|
end
|
18
16
|
|
19
17
|
describe 'Hash#__nanoc_freeze_recursively' do
|
20
|
-
include Nanoc::TestHelpers
|
21
|
-
|
22
18
|
it 'should prevent first-level elements from being modified' do
|
23
19
|
hash = { a: { b: :c } }
|
24
20
|
hash.__nanoc_freeze_recursively
|
25
21
|
|
26
|
-
|
27
|
-
hash[:a] = 123
|
28
|
-
end
|
22
|
+
expect { hash[:a] = 123 }.to raise_frozen_error
|
29
23
|
end
|
30
24
|
|
31
25
|
it 'should prevent second-level elements from being modified' do
|
32
26
|
hash = { a: { b: :c } }
|
33
27
|
hash.__nanoc_freeze_recursively
|
34
28
|
|
35
|
-
|
36
|
-
hash[:a][:b] = 123
|
37
|
-
end
|
29
|
+
expect { hash[:a][:b] = 123 }.to raise_frozen_error
|
38
30
|
end
|
39
31
|
|
40
32
|
it 'should not freeze infinitely' do
|
@@ -43,8 +35,7 @@ describe 'Hash#__nanoc_freeze_recursively' do
|
|
43
35
|
|
44
36
|
a.__nanoc_freeze_recursively
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
assert_equal a, a[:x]
|
38
|
+
expect(a).to be_frozen
|
39
|
+
expect(a[0]).to be_frozen
|
49
40
|
end
|
50
41
|
end
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe 'String#__nanoc_cleaned_identifier' do
|
4
|
+
it 'should not convert already clean paths' do
|
5
|
+
expect('/foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should prepend slash if necessary' do
|
9
|
+
expect('foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should append slash if necessary' do
|
13
|
+
expect('/foo/bar'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should remove double slashes at start' do
|
17
|
+
expect('//foo/bar/'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should remove double slashes at end' do
|
21
|
+
expect('/foo/bar//'.__nanoc_cleaned_identifier).to eql('/foo/bar/')
|
22
|
+
end
|
23
|
+
end
|
@@ -65,4 +65,295 @@ describe Nanoc::Int::DirectedGraph do
|
|
65
65
|
it { is_expected.to eq([2, 3, 4, 5]) }
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
describe '#all_paths' do
|
70
|
+
subject { graph.all_paths.to_a }
|
71
|
+
|
72
|
+
context 'no cycles' do
|
73
|
+
example do
|
74
|
+
expect(subject).to contain_exactly(
|
75
|
+
[1],
|
76
|
+
[2],
|
77
|
+
[3],
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'one cycle without head' do
|
83
|
+
before do
|
84
|
+
graph.add_edge(1, 2)
|
85
|
+
graph.add_edge(2, 1)
|
86
|
+
end
|
87
|
+
|
88
|
+
example do
|
89
|
+
expect(subject).to contain_exactly(
|
90
|
+
[1],
|
91
|
+
[1, 2],
|
92
|
+
[1, 2, 1],
|
93
|
+
[2],
|
94
|
+
[2, 1],
|
95
|
+
[2, 1, 2],
|
96
|
+
[3],
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'one cycle with head' do
|
102
|
+
before do
|
103
|
+
graph.add_edge(1, 2)
|
104
|
+
graph.add_edge(2, 3)
|
105
|
+
graph.add_edge(3, 2)
|
106
|
+
end
|
107
|
+
|
108
|
+
example do
|
109
|
+
expect(subject).to contain_exactly(
|
110
|
+
[1],
|
111
|
+
[1, 2],
|
112
|
+
[1, 2, 3],
|
113
|
+
[1, 2, 3, 2],
|
114
|
+
[2],
|
115
|
+
[2, 3],
|
116
|
+
[2, 3, 2],
|
117
|
+
[3],
|
118
|
+
[3, 2],
|
119
|
+
[3, 2, 3],
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'one cycle with tail' do
|
125
|
+
before do
|
126
|
+
graph.add_edge(1, 2)
|
127
|
+
graph.add_edge(2, 20)
|
128
|
+
graph.add_edge(20, 21)
|
129
|
+
graph.add_edge(2, 3)
|
130
|
+
graph.add_edge(3, 1)
|
131
|
+
end
|
132
|
+
|
133
|
+
example do
|
134
|
+
expect(subject).to contain_exactly(
|
135
|
+
[1],
|
136
|
+
[1, 2],
|
137
|
+
[1, 2, 20],
|
138
|
+
[1, 2, 20, 21],
|
139
|
+
[1, 2, 3],
|
140
|
+
[1, 2, 3, 1],
|
141
|
+
[2],
|
142
|
+
[2, 20],
|
143
|
+
[2, 20, 21],
|
144
|
+
[2, 3],
|
145
|
+
[2, 3, 1],
|
146
|
+
[2, 3, 1, 2],
|
147
|
+
[3],
|
148
|
+
[3, 1],
|
149
|
+
[3, 1, 2],
|
150
|
+
[3, 1, 2, 20],
|
151
|
+
[3, 1, 2, 20, 21],
|
152
|
+
[3, 1, 2, 3],
|
153
|
+
[20],
|
154
|
+
[20, 21],
|
155
|
+
[21],
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'large cycle' do
|
161
|
+
before do
|
162
|
+
graph.add_edge(1, 2)
|
163
|
+
graph.add_edge(2, 3)
|
164
|
+
graph.add_edge(3, 4)
|
165
|
+
graph.add_edge(4, 5)
|
166
|
+
graph.add_edge(5, 1)
|
167
|
+
end
|
168
|
+
|
169
|
+
example do
|
170
|
+
expect(subject).to contain_exactly(
|
171
|
+
[1],
|
172
|
+
[1, 2],
|
173
|
+
[1, 2, 3],
|
174
|
+
[1, 2, 3, 4],
|
175
|
+
[1, 2, 3, 4, 5],
|
176
|
+
[1, 2, 3, 4, 5, 1],
|
177
|
+
[2],
|
178
|
+
[2, 3],
|
179
|
+
[2, 3, 4],
|
180
|
+
[2, 3, 4, 5],
|
181
|
+
[2, 3, 4, 5, 1],
|
182
|
+
[2, 3, 4, 5, 1, 2],
|
183
|
+
[3],
|
184
|
+
[3, 4],
|
185
|
+
[3, 4, 5],
|
186
|
+
[3, 4, 5, 1],
|
187
|
+
[3, 4, 5, 1, 2],
|
188
|
+
[3, 4, 5, 1, 2, 3],
|
189
|
+
[4],
|
190
|
+
[4, 5],
|
191
|
+
[4, 5, 1],
|
192
|
+
[4, 5, 1, 2],
|
193
|
+
[4, 5, 1, 2, 3],
|
194
|
+
[4, 5, 1, 2, 3, 4],
|
195
|
+
[5],
|
196
|
+
[5, 1],
|
197
|
+
[5, 1, 2],
|
198
|
+
[5, 1, 2, 3],
|
199
|
+
[5, 1, 2, 3, 4],
|
200
|
+
[5, 1, 2, 3, 4, 5],
|
201
|
+
)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'large cycle with head' do
|
206
|
+
before do
|
207
|
+
graph.add_edge(1, 2)
|
208
|
+
graph.add_edge(2, 3)
|
209
|
+
graph.add_edge(3, 4)
|
210
|
+
graph.add_edge(4, 5)
|
211
|
+
graph.add_edge(5, 2)
|
212
|
+
end
|
213
|
+
|
214
|
+
example do
|
215
|
+
expect(subject).to contain_exactly(
|
216
|
+
[1],
|
217
|
+
[1, 2],
|
218
|
+
[1, 2, 3],
|
219
|
+
[1, 2, 3, 4],
|
220
|
+
[1, 2, 3, 4, 5],
|
221
|
+
[1, 2, 3, 4, 5, 2],
|
222
|
+
[2],
|
223
|
+
[2, 3],
|
224
|
+
[2, 3, 4],
|
225
|
+
[2, 3, 4, 5],
|
226
|
+
[2, 3, 4, 5, 2],
|
227
|
+
[3],
|
228
|
+
[3, 4],
|
229
|
+
[3, 4, 5],
|
230
|
+
[3, 4, 5, 2],
|
231
|
+
[3, 4, 5, 2, 3],
|
232
|
+
[4],
|
233
|
+
[4, 5],
|
234
|
+
[4, 5, 2],
|
235
|
+
[4, 5, 2, 3],
|
236
|
+
[4, 5, 2, 3, 4],
|
237
|
+
[5],
|
238
|
+
[5, 2],
|
239
|
+
[5, 2, 3],
|
240
|
+
[5, 2, 3, 4],
|
241
|
+
[5, 2, 3, 4, 5],
|
242
|
+
)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#dfs_from' do
|
248
|
+
subject do
|
249
|
+
[].tap do |ps|
|
250
|
+
graph.dfs_from(1) do |p|
|
251
|
+
ps << p
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context 'no cycles' do
|
257
|
+
example do
|
258
|
+
expect(subject).to contain_exactly(
|
259
|
+
[1],
|
260
|
+
)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'one cycle without head' do
|
265
|
+
before do
|
266
|
+
graph.add_edge(1, 2)
|
267
|
+
graph.add_edge(2, 1)
|
268
|
+
end
|
269
|
+
|
270
|
+
example do
|
271
|
+
expect(subject).to contain_exactly(
|
272
|
+
[1],
|
273
|
+
[1, 2],
|
274
|
+
[1, 2, 1],
|
275
|
+
)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'one cycle with head' do
|
280
|
+
before do
|
281
|
+
graph.add_edge(1, 2)
|
282
|
+
graph.add_edge(2, 3)
|
283
|
+
graph.add_edge(3, 2)
|
284
|
+
end
|
285
|
+
|
286
|
+
example do
|
287
|
+
expect(subject).to contain_exactly(
|
288
|
+
[1],
|
289
|
+
[1, 2],
|
290
|
+
[1, 2, 3],
|
291
|
+
[1, 2, 3, 2],
|
292
|
+
)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'one cycle with tail' do
|
297
|
+
before do
|
298
|
+
graph.add_edge(1, 2)
|
299
|
+
graph.add_edge(2, 20)
|
300
|
+
graph.add_edge(20, 21)
|
301
|
+
graph.add_edge(2, 3)
|
302
|
+
graph.add_edge(3, 1)
|
303
|
+
end
|
304
|
+
|
305
|
+
example do
|
306
|
+
expect(subject).to contain_exactly(
|
307
|
+
[1],
|
308
|
+
[1, 2],
|
309
|
+
[1, 2, 20],
|
310
|
+
[1, 2, 20, 21],
|
311
|
+
[1, 2, 3],
|
312
|
+
[1, 2, 3, 1],
|
313
|
+
)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'large cycle' do
|
318
|
+
before do
|
319
|
+
graph.add_edge(1, 2)
|
320
|
+
graph.add_edge(2, 3)
|
321
|
+
graph.add_edge(3, 4)
|
322
|
+
graph.add_edge(4, 5)
|
323
|
+
graph.add_edge(5, 1)
|
324
|
+
end
|
325
|
+
|
326
|
+
example do
|
327
|
+
expect(subject).to contain_exactly(
|
328
|
+
[1],
|
329
|
+
[1, 2],
|
330
|
+
[1, 2, 3],
|
331
|
+
[1, 2, 3, 4],
|
332
|
+
[1, 2, 3, 4, 5],
|
333
|
+
[1, 2, 3, 4, 5, 1],
|
334
|
+
)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context 'large cycle with head' do
|
339
|
+
before do
|
340
|
+
graph.add_edge(1, 2)
|
341
|
+
graph.add_edge(2, 3)
|
342
|
+
graph.add_edge(3, 4)
|
343
|
+
graph.add_edge(4, 5)
|
344
|
+
graph.add_edge(5, 2)
|
345
|
+
end
|
346
|
+
|
347
|
+
example do
|
348
|
+
expect(subject).to contain_exactly(
|
349
|
+
[1],
|
350
|
+
[1, 2],
|
351
|
+
[1, 2, 3],
|
352
|
+
[1, 2, 3, 4],
|
353
|
+
[1, 2, 3, 4, 5],
|
354
|
+
[1, 2, 3, 4, 5, 2],
|
355
|
+
)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
68
359
|
end
|