guard-jekyll-plus 2.0.0 → 2.0.1
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/.rspec +2 -0
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +32 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +6 -2
- data/Gemfile +12 -2
- data/Guardfile +30 -0
- data/README.md +5 -5
- data/Rakefile +9 -1
- data/guard-jekyll-plus.gemspec +20 -15
- data/lib/guard/jekyll_plus.rb +54 -0
- data/lib/guard/jekyll_plus/builder.rb +46 -0
- data/lib/guard/jekyll_plus/builder/action.rb +126 -0
- data/lib/guard/jekyll_plus/builder/adder.rb +23 -0
- data/lib/guard/jekyll_plus/builder/modifier.rb +23 -0
- data/lib/guard/jekyll_plus/builder/rebuilder.rb +37 -0
- data/lib/guard/jekyll_plus/builder/remover.rb +24 -0
- data/lib/guard/jekyll_plus/config.rb +131 -0
- data/lib/guard/jekyll_plus/server.rb +111 -0
- data/lib/guard/jekyll_plus/templates/Guardfile +4 -0
- data/lib/guard/{jekyll-plus → jekyll_plus}/version.rb +1 -1
- data/spec/lib/guard/jekyll-plus/builder/adder_spec.rb +94 -0
- data/spec/lib/guard/jekyll-plus/builder/modifier_spec.rb +113 -0
- data/spec/lib/guard/jekyll-plus/builder/rebuilder_spec.rb +76 -0
- data/spec/lib/guard/jekyll-plus/builder/remover_spec.rb +97 -0
- data/spec/lib/guard/jekyll-plus/builder_spec.rb +57 -0
- data/spec/lib/guard/jekyll-plus/config_spec.rb +138 -0
- data/spec/lib/guard/jekyll-plus/server_spec.rb +79 -0
- data/spec/lib/guard/jekyll-plus_spec.rb +114 -0
- data/spec/spec_helper.rb +44 -0
- data/test/Guardfile +3 -4
- metadata +70 -14
- data/lib/guard/jekyll-plus.rb +0 -300
- data/lib/guard/jekyll-plus/templates/Guardfile +0 -5
- data/test/Gemfile +0 -3
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'guard/jekyll_plus/builder/modifier'
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
RSpec.describe JekyllPlus::Builder::Modifier do
|
5
|
+
let(:site) { instance_double(Jekyll::Site) }
|
6
|
+
let(:config) { instance_double(JekyllPlus::Config) }
|
7
|
+
subject { described_class.new(config, site) }
|
8
|
+
|
9
|
+
describe '#update' do
|
10
|
+
let(:extensions) { /\.haml$/i }
|
11
|
+
|
12
|
+
before do
|
13
|
+
# for build
|
14
|
+
allow(config).to receive(:info)
|
15
|
+
allow(config).to receive(:source)
|
16
|
+
allow(config).to receive(:destination)
|
17
|
+
|
18
|
+
allow(config).to receive(:extensions).and_return(extensions)
|
19
|
+
allow(FileUtils).to receive(:mkdir_p)
|
20
|
+
allow(FileUtils).to receive(:cp)
|
21
|
+
allow($stdout).to receive(:puts)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when source files change' do
|
25
|
+
it 'builds' do
|
26
|
+
expect(site).to receive(:process)
|
27
|
+
subject.update(%w(foo.haml))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when assets change' do
|
32
|
+
before do
|
33
|
+
allow(config).to receive(:destination).and_return('bar/')
|
34
|
+
allow(config).to receive(:excluded?).with('foo.jpg').and_return(false)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'copies files' do
|
38
|
+
expect(FileUtils).to receive(:cp).with('foo.jpg', 'bar/foo.jpg')
|
39
|
+
subject.update(%w(foo.jpg))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when excluded file changes' do
|
44
|
+
before do
|
45
|
+
allow(config).to receive(:destination).and_return('bar/')
|
46
|
+
allow(config).to receive(:excluded?).with('foo.jpg').and_return(true)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not copy anything' do
|
50
|
+
expect(FileUtils).to_not receive(:cp)
|
51
|
+
subject.update(%w(foo.jpg))
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'shows which files were excluded' do
|
55
|
+
expect($stdout).to receive(:puts)
|
56
|
+
.with(/Ignoring excluded file: foo\.jpg/)
|
57
|
+
subject.update(%w(foo.jpg))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# NOTE: Jekyll just shows a message and passes the plugin,
|
62
|
+
# so it can fail with almost any possible exception.
|
63
|
+
#
|
64
|
+
# We catch StandardError to at least be somewhat reasonable
|
65
|
+
context 'when an Jekyll conversion error happens' do
|
66
|
+
before do
|
67
|
+
allow(site).to receive(:process)
|
68
|
+
.and_raise(NoMethodError, 'error evaluating Haml file')
|
69
|
+
|
70
|
+
allow(config).to receive(:error)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'shows an error' do
|
74
|
+
expect(config).to receive(:error).with('build has failed')
|
75
|
+
expect(config).to receive(:error).with(/error evaluating Haml file/)
|
76
|
+
|
77
|
+
catch(:task_has_failed) do
|
78
|
+
subject.update(%w(foo.haml))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'throws task_has_failed symbol' do
|
83
|
+
expect do
|
84
|
+
subject.update(%w(foo.haml))
|
85
|
+
end.to throw_symbol(:task_has_failed)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when an error happens' do
|
90
|
+
before do
|
91
|
+
allow(config).to receive(:destination).and_return('bar/')
|
92
|
+
allow(FileUtils).to receive(:cp).and_raise(Errno::ENOENT, 'foo')
|
93
|
+
allow(config).to receive(:error)
|
94
|
+
allow(config).to receive(:excluded?).with('foo').and_return(false)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'shows an error' do
|
98
|
+
expect(config).to receive(:error).with('update has failed')
|
99
|
+
expect(config).to receive(:error).with(/No such file.* - foo/)
|
100
|
+
catch(:task_has_failed) do
|
101
|
+
subject.update(%w(foo))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'throws task_has_failed symbol' do
|
106
|
+
expect do
|
107
|
+
subject.update(%w(foo))
|
108
|
+
end.to throw_symbol(:task_has_failed)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'guard/jekyll_plus/builder/rebuilder'
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
RSpec.describe JekyllPlus::Builder::Rebuilder do
|
5
|
+
let(:site) { instance_double(Jekyll::Site) }
|
6
|
+
let(:config) { instance_double(JekyllPlus::Config) }
|
7
|
+
subject { described_class.new(config, site) }
|
8
|
+
|
9
|
+
describe '#update' do
|
10
|
+
before do
|
11
|
+
allow(site).to receive(:process)
|
12
|
+
allow($stdout).to receive(:puts)
|
13
|
+
allow(config).to receive(:info)
|
14
|
+
allow(config).to receive(:source)
|
15
|
+
allow(config).to receive(:destination)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'processes all the files' do
|
19
|
+
expect(site).to receive(:process)
|
20
|
+
subject.update
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'shows header' do
|
24
|
+
expect(config).to receive(:info).with(/building\.\.\./)
|
25
|
+
subject.update
|
26
|
+
end
|
27
|
+
|
28
|
+
# NOTE: Jekyll just shows a message and passes the plugin,
|
29
|
+
# so it can fail with almost any possible exception.
|
30
|
+
#
|
31
|
+
# We catch StandardError to at least be somewhat reasonable
|
32
|
+
context 'when an Jekyll conversion error happens' do
|
33
|
+
before do
|
34
|
+
allow(config).to receive(:error)
|
35
|
+
allow(site).to receive(:process)
|
36
|
+
.and_raise(NoMethodError, 'something in Haml template failed')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'shows an error' do
|
40
|
+
expect(config).to receive(:error).with('build has failed')
|
41
|
+
expect(config).to receive(:error).with(/something in Haml template/)
|
42
|
+
catch(:task_has_failed) do
|
43
|
+
subject.update
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'throws task_has_failed symbol' do
|
48
|
+
expect do
|
49
|
+
subject.update
|
50
|
+
end.to throw_symbol(:task_has_failed)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when a system error happens' do
|
55
|
+
before do
|
56
|
+
allow(config).to receive(:error)
|
57
|
+
allow(site).to receive(:process).and_raise(RuntimeError, 'big error')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'shows an error' do
|
61
|
+
expect(config).to receive(:error).with('build has failed')
|
62
|
+
expect(config).to receive(:error).with(/big error/)
|
63
|
+
catch(:task_has_failed) do
|
64
|
+
subject.update
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'throws task_has_failed symbol' do
|
69
|
+
expect do
|
70
|
+
subject.update
|
71
|
+
end.to throw_symbol(:task_has_failed)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'guard/jekyll_plus/builder/remover'
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
RSpec.describe JekyllPlus::Builder::Remover do
|
5
|
+
let(:site) { instance_double(Jekyll::Site) }
|
6
|
+
let(:config) { instance_double(JekyllPlus::Config) }
|
7
|
+
subject { described_class.new(config, site) }
|
8
|
+
|
9
|
+
describe '#update' do
|
10
|
+
let(:extensions) { /\.haml$/i }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(config).to receive(:extensions).and_return(extensions)
|
14
|
+
|
15
|
+
# for build
|
16
|
+
allow(config).to receive(:info)
|
17
|
+
allow(config).to receive(:source)
|
18
|
+
allow(config).to receive(:destination)
|
19
|
+
|
20
|
+
allow($stdout).to receive(:puts)
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when asset files are deleted' do
|
24
|
+
before do
|
25
|
+
allow(config).to receive(:destination).and_return('bar/')
|
26
|
+
|
27
|
+
# non existing src file
|
28
|
+
allow(File).to receive(:exist?).with('foo.jpg').and_return(false)
|
29
|
+
|
30
|
+
# Make one file exist so removing dst files can happen.
|
31
|
+
# I'm not sure why this is necessary
|
32
|
+
allow(File).to receive(:exist?).with('logo.png').and_return(true)
|
33
|
+
|
34
|
+
# existing destination file
|
35
|
+
allow(File).to receive(:exist?).with('bar/foo.jpg').and_return(true)
|
36
|
+
|
37
|
+
# the removing of the file
|
38
|
+
allow(FileUtils).to receive(:rm).with('bar/foo.jpg')
|
39
|
+
allow(FileUtils).to receive(:rm).with('bar/logo.png')
|
40
|
+
|
41
|
+
# checking for empty dirs to clear
|
42
|
+
allow(Dir).to receive(:[]).with('bar/*').and_return(%w(logo.png))
|
43
|
+
allow(File).to receive(:exist?).with('bar/logo.png').and_return(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'removes delete files from destination' do
|
47
|
+
expect(FileUtils).to receive(:rm).with('bar/foo.jpg')
|
48
|
+
subject.update(%w(foo.jpg logo.png))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when sources files are removed' do
|
53
|
+
it 'builds' do
|
54
|
+
expect(site).to receive(:process)
|
55
|
+
subject.update(%w(foo.haml))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when an error happens' do
|
60
|
+
before do
|
61
|
+
allow(config).to receive(:destination).and_return('bar/')
|
62
|
+
allow(config).to receive(:error)
|
63
|
+
allow(File).to receive(:exist?).with('foo').and_return(false)
|
64
|
+
|
65
|
+
# just so the removing is triggered (don't know why)
|
66
|
+
allow(File).to receive(:exist?).with('baz').and_return(true)
|
67
|
+
|
68
|
+
# file to be deleted
|
69
|
+
allow(File).to receive(:exist?).with('bar/foo').and_return(true)
|
70
|
+
|
71
|
+
# file we don't care about
|
72
|
+
allow(File).to receive(:exist?).with('bar/baz').and_return(false)
|
73
|
+
|
74
|
+
allow(Dir).to receive(:[]).with('bar/*').and_return(%w(logo.png))
|
75
|
+
|
76
|
+
# simulate failure
|
77
|
+
allow(FileUtils).to receive(:rm).with('bar/foo')
|
78
|
+
.and_raise(Errno::ENOENT, 'foo')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'shows an error' do
|
82
|
+
expect(config).to receive(:error).with('remove has failed')
|
83
|
+
expect(config).to receive(:error).with(/No such file.* - foo/)
|
84
|
+
catch(:task_has_failed) do
|
85
|
+
subject.update(%w(foo baz))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'throws task_has_failed symbol' do
|
90
|
+
expect do
|
91
|
+
subject.update(%w(foo baz))
|
92
|
+
end.to throw_symbol(:task_has_failed)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'guard/compat/test/helper'
|
2
|
+
|
3
|
+
require 'guard/jekyll_plus/builder'
|
4
|
+
|
5
|
+
module Guard
|
6
|
+
RSpec.describe JekyllPlus::Builder do
|
7
|
+
let(:config) { instance_double(JekyllPlus::Config) }
|
8
|
+
let(:site) { instance_double(Jekyll::Site) }
|
9
|
+
let(:rebuilder) { instance_double(JekyllPlus::Builder::Rebuilder) }
|
10
|
+
let(:modifier) { instance_double(JekyllPlus::Builder::Modifier) }
|
11
|
+
let(:adder) { instance_double(JekyllPlus::Builder::Adder) }
|
12
|
+
let(:remover) { instance_double(JekyllPlus::Builder::Remover) }
|
13
|
+
|
14
|
+
subject { described_class.new(config) }
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(Jekyll::Site).to receive(:new).and_return(site)
|
18
|
+
|
19
|
+
allow(JekyllPlus::Config).to receive(:new).and_return(config)
|
20
|
+
allow(config).to receive(:jekyll_config)
|
21
|
+
|
22
|
+
allow(JekyllPlus::Builder::Adder).to receive(:new).and_return(adder)
|
23
|
+
allow(JekyllPlus::Builder::Remover).to receive(:new).and_return(remover)
|
24
|
+
allow(JekyllPlus::Builder::Modifier).to receive(:new).and_return(modifier)
|
25
|
+
allow(JekyllPlus::Builder::Rebuilder).to receive(:new)
|
26
|
+
.and_return(rebuilder)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#build' do
|
30
|
+
it 'rebuilds the site' do
|
31
|
+
expect(rebuilder).to receive(:update)
|
32
|
+
subject.build
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#added' do
|
37
|
+
it 'builds if needed' do
|
38
|
+
expect(adder).to receive(:update)
|
39
|
+
subject.added(%w(foo))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#modified' do
|
44
|
+
it 'builds if needed' do
|
45
|
+
expect(modifier).to receive(:update)
|
46
|
+
subject.modified(%w(foo))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#removed' do
|
51
|
+
it 'builds if needed' do
|
52
|
+
expect(remover).to receive(:update)
|
53
|
+
subject.removed(%w(foo))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'guard/compat/test/helper'
|
2
|
+
|
3
|
+
require 'guard/jekyll_plus/config'
|
4
|
+
|
5
|
+
RSpec.describe Guard::JekyllPlus::Config do
|
6
|
+
let(:options) { {} }
|
7
|
+
subject { described_class.new(options) }
|
8
|
+
|
9
|
+
let(:valid_jekyll_options) do
|
10
|
+
{
|
11
|
+
'source' => 'foo',
|
12
|
+
'destination' => 'bar'
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:jekyll_config) { valid_jekyll_options }
|
17
|
+
|
18
|
+
before do
|
19
|
+
allow(Jekyll).to receive(:configuration).and_return(jekyll_config)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#source' do
|
23
|
+
context 'with a relative path' do
|
24
|
+
let(:jekyll_config) { valid_jekyll_options.merge('source' => 'foo') }
|
25
|
+
|
26
|
+
it 'returns source from Jekyll config' do
|
27
|
+
expect(subject.source).to eq('foo')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#serve?' do
|
33
|
+
context 'when option is not configured' do
|
34
|
+
let(:options) { {} }
|
35
|
+
it { is_expected.to_not be_serve }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when configured as false' do
|
39
|
+
let(:options) { { serve: false } }
|
40
|
+
it { is_expected.to_not be_serve }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when configuerd as true' do
|
44
|
+
let(:options) { { serve: true } }
|
45
|
+
it { is_expected.to be_serve }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
%w(host baseurl port).each do |option|
|
50
|
+
describe "#{option}" do
|
51
|
+
let(:value) { double('value') }
|
52
|
+
let(:jekyll_config) { valid_jekyll_options.merge(option.to_s => value) }
|
53
|
+
|
54
|
+
it 'returns value from Jekyll config' do
|
55
|
+
expect(subject.send(option)).to be(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#jekyll_serve_options' do
|
61
|
+
it 'returns all jekyll options'do
|
62
|
+
expect(subject.jekyll_serve_options).to be(jekyll_config)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#server_root' do
|
67
|
+
let(:path) { File.join(Dir.pwd, 'foo') }
|
68
|
+
let(:jekyll_config) { valid_jekyll_options.merge('destination' => path) }
|
69
|
+
|
70
|
+
it 'returns destination dir'do
|
71
|
+
expect(subject.server_root).to eq('foo')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#rack_config' do
|
76
|
+
context 'when option is not configured' do
|
77
|
+
let(:options) { {} }
|
78
|
+
it 'returns nil' do
|
79
|
+
expect(subject.rack_config).to be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when configured' do
|
84
|
+
let(:rack_options) { double('rack options') }
|
85
|
+
let(:options) { { rack_config: rack_options } }
|
86
|
+
|
87
|
+
it 'returns value from options' do
|
88
|
+
expect(subject.rack_config).to be(rack_options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#extensions' do
|
94
|
+
let(:options) { { extensions: %w(foo) } }
|
95
|
+
let(:exts) do
|
96
|
+
'foo|md|mkd|mkdn|markdown|textile|html|haml|slim|xml|yml|sass|scss'
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns configured extensions' do
|
100
|
+
expect(subject.extensions).to eq(/\.(?:#{exts})$/i)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'matches .slim files' do
|
104
|
+
expect(subject.extensions).to match('foo.slim')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# We need this basically to turn off logging
|
109
|
+
describe '#rack_environment' do
|
110
|
+
context 'when silent is true' do
|
111
|
+
let(:options) { { silent: true } }
|
112
|
+
it 'uses nil to prevent loading Rack default middleware' do
|
113
|
+
expect(subject.rack_environment).to eq(nil)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when silent is false' do
|
118
|
+
let(:options) { { silent: false } }
|
119
|
+
it 'uses development for full Rack default middleware' do
|
120
|
+
expect(subject.rack_environment).to eq('development')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#excluded?' do
|
126
|
+
context 'with excludes in Jekyll' do
|
127
|
+
let(:jekyll_config) do
|
128
|
+
valid_jekyll_options.merge('exclude' => ['f*', 'b*z'])
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'matches files excluded in Jekyll' do
|
132
|
+
expect(subject.excluded?('foo')).to be_truthy
|
133
|
+
expect(subject.excluded?('bar')).to be_falsey
|
134
|
+
expect(subject.excluded?('baz')).to be_truthy
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|