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.
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