guard-jekyll-plus 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +10 -0
  4. data/.rubocop_todo.yml +32 -0
  5. data/.ruby-gemset +1 -0
  6. data/.travis.yml +6 -0
  7. data/CHANGELOG.md +6 -2
  8. data/Gemfile +12 -2
  9. data/Guardfile +30 -0
  10. data/README.md +5 -5
  11. data/Rakefile +9 -1
  12. data/guard-jekyll-plus.gemspec +20 -15
  13. data/lib/guard/jekyll_plus.rb +54 -0
  14. data/lib/guard/jekyll_plus/builder.rb +46 -0
  15. data/lib/guard/jekyll_plus/builder/action.rb +126 -0
  16. data/lib/guard/jekyll_plus/builder/adder.rb +23 -0
  17. data/lib/guard/jekyll_plus/builder/modifier.rb +23 -0
  18. data/lib/guard/jekyll_plus/builder/rebuilder.rb +37 -0
  19. data/lib/guard/jekyll_plus/builder/remover.rb +24 -0
  20. data/lib/guard/jekyll_plus/config.rb +131 -0
  21. data/lib/guard/jekyll_plus/server.rb +111 -0
  22. data/lib/guard/jekyll_plus/templates/Guardfile +4 -0
  23. data/lib/guard/{jekyll-plus → jekyll_plus}/version.rb +1 -1
  24. data/spec/lib/guard/jekyll-plus/builder/adder_spec.rb +94 -0
  25. data/spec/lib/guard/jekyll-plus/builder/modifier_spec.rb +113 -0
  26. data/spec/lib/guard/jekyll-plus/builder/rebuilder_spec.rb +76 -0
  27. data/spec/lib/guard/jekyll-plus/builder/remover_spec.rb +97 -0
  28. data/spec/lib/guard/jekyll-plus/builder_spec.rb +57 -0
  29. data/spec/lib/guard/jekyll-plus/config_spec.rb +138 -0
  30. data/spec/lib/guard/jekyll-plus/server_spec.rb +79 -0
  31. data/spec/lib/guard/jekyll-plus_spec.rb +114 -0
  32. data/spec/spec_helper.rb +44 -0
  33. data/test/Guardfile +3 -4
  34. metadata +70 -14
  35. data/lib/guard/jekyll-plus.rb +0 -300
  36. data/lib/guard/jekyll-plus/templates/Guardfile +0 -5
  37. 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