jekyll-lilypond 0.1.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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +99 -0
  5. data/LICENSE +21 -0
  6. data/README.md +98 -0
  7. data/files/rite.png +0 -0
  8. data/jekyll-lilypond.gemspec +23 -0
  9. data/lib/jekyll-lilypond/file_processor.rb +67 -0
  10. data/lib/jekyll-lilypond/lilypond_tag.rb +34 -0
  11. data/lib/jekyll-lilypond/tag.rb +17 -0
  12. data/lib/jekyll-lilypond/tag_processor.rb +56 -0
  13. data/lib/jekyll-lilypond/templates/basic.ly +45 -0
  14. data/lib/jekyll-lilypond/templates/empty.ly +1 -0
  15. data/lib/jekyll-lilypond/templates/figure.html +25 -0
  16. data/lib/jekyll-lilypond/templates/img.html +4 -0
  17. data/lib/jekyll-lilypond/templates/raw.html +1 -0
  18. data/lib/jekyll-lilypond/templates/raw.ly +1 -0
  19. data/lib/jekyll-lilypond/templates/showsource.html +36 -0
  20. data/lib/jekyll-lilypond/templates.rb +60 -0
  21. data/lib/jekyll-lilypond/version.rb +5 -0
  22. data/lib/jekyll-lilypond.rb +11 -0
  23. data/spec/file_processor_spec.rb +167 -0
  24. data/spec/fixtures/.gitignore +5 -0
  25. data/spec/fixtures/404.html +25 -0
  26. data/spec/fixtures/Gemfile +31 -0
  27. data/spec/fixtures/_config.yml +56 -0
  28. data/spec/fixtures/_layouts/basic_html.html +1 -0
  29. data/spec/fixtures/_layouts/vacuous_html.html +1 -0
  30. data/spec/fixtures/_layouts/vacuous_ly.ly +1 -0
  31. data/spec/fixtures/_layouts/variables_html.html +1 -0
  32. data/spec/fixtures/_layouts/variables_ly.ly +1 -0
  33. data/spec/fixtures/_posts/2021-01-16-welcome-to-jekyll.markdown +29 -0
  34. data/spec/fixtures/about.markdown +18 -0
  35. data/spec/fixtures/index.markdown +6 -0
  36. data/spec/fixtures/page.md +8 -0
  37. data/spec/integration_spec.rb +115 -0
  38. data/spec/spec_helper.rb +88 -0
  39. data/spec/tag_processor_spec.rb +135 -0
  40. data/spec/tag_spec.rb +51 -0
  41. data/spec/templates_spec.rb +175 -0
  42. metadata +118 -0
@@ -0,0 +1,135 @@
1
+ require "jekyll-lilypond"
2
+ require "spec_helper"
3
+ require "tmpdir"
4
+ include Liquid
5
+
6
+ RSpec.describe(Jekyll::Lilypond::TagProcessor) do
7
+ let(:site) { double("source" => "/some/directory", "static_files" => []) }
8
+ let(:tag) { double("Tag", template_names: { source: "NiftyTemplateName", include: nil},
9
+ template_code: { source: nil, include: "{{ filename }} abcde" },
10
+ attrs: {}) }
11
+ let(:subject) { described_class.new(site, tag) }
12
+
13
+ context "generating source code" do
14
+ it "creates a Template using the tag data when you ask for a source template" do
15
+ expect(Jekyll::Lilypond::Template).to receive(:new).with(site, tag, :source)
16
+ subject.source_template_obj
17
+ end
18
+ end
19
+
20
+ context "generating include code" do
21
+ it "creates a Template using the tag data when you ask for an include template" do
22
+ expect(Jekyll::Lilypond::Template).to receive(:new).with(site, tag, :include)
23
+ subject.include_template_obj
24
+ end
25
+ end
26
+
27
+ context "generating filename" do
28
+ let(:source) { "abcde" }
29
+ let(:hash) { "ab56b4d92b40713acc5af89985d4b786" }
30
+
31
+ it "generates a filename as the hash of the source" do
32
+ allow(subject).to receive(:source).and_return(source)
33
+ expect(subject.hash).to eq(hash)
34
+ end
35
+ it "makes the filename available to the include template" do
36
+ allow(subject).to receive(:source).and_return(source)
37
+ expect(subject.include).to eq("#{hash} abcde")
38
+ end
39
+ it "provides the filename to the file processor" do
40
+ allow(subject).to receive(:source).and_return(source)
41
+ expect(Jekyll::Lilypond::FileProcessor).to \
42
+ receive(:new).with("/some/directory/lilypond_files", hash, source)
43
+ subject.file_processor
44
+ end
45
+ end
46
+
47
+ context "running" do
48
+ let(:source) { "abcde" }
49
+ let(:hash) { "ab56b4d92b40713acc5af89985d4b786" }
50
+ before do
51
+ allow(subject).to receive(:source).and_return(source)
52
+ allow_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:write)
53
+ allow_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:compile)
54
+ allow_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:trim_svg)
55
+ end
56
+
57
+ it "calls write" do
58
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:write)
59
+ subject.run!
60
+ end
61
+ it "calls compile" do
62
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:compile)
63
+ subject.run!
64
+ end
65
+ it "doesn't call trim_svg by default" do
66
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).not_to receive(:trim_svg)
67
+ subject.run!
68
+ end
69
+ it "calls trim_svg if the tag asks it to" do
70
+ tag.attrs["trim"] = "true"
71
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:trim_svg)
72
+ subject.run!
73
+ end
74
+ it "doesn't call make_mp3 by default" do
75
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).not_to receive(:make_mp3)
76
+ subject.run!
77
+ end
78
+ it "calls make_mp3 if the tag asks it to" do
79
+ tag.attrs["mp3"] = "true"
80
+ expect_any_instance_of(Jekyll::Lilypond::FileProcessor).to receive(:make_mp3)
81
+ subject.run!
82
+ end
83
+ end
84
+ end
85
+
86
+ RSpec.describe(Jekyll::Lilypond::TagProcessor) do
87
+ let(:overrides) { {} }
88
+ let(:config) do
89
+ Jekyll.configuration(Jekyll::Utils.deep_merge_hashes({
90
+ "full_rebuild" => true,
91
+ "source" => source_dir,
92
+ "destination" => dest_dir,
93
+ "show_drafts" => false,
94
+ "url" => "http://example.org",
95
+ "name" => "My awesome site",
96
+ "author" => {
97
+ "name" => "Dr. Jekyll",
98
+ },
99
+ "collections" => {
100
+ "my_collection" => { "output" => true },
101
+ "other_things" => { "output" => false },
102
+ },
103
+ }, overrides))
104
+ end
105
+ let(:site) { Jekyll::Site.new(config) }
106
+ let(:context) { make_context(:site => site) }
107
+ before(:each) do
108
+ FileUtils.rm_r Dir.glob(dest_dir("*"))
109
+ site.process
110
+ end
111
+ after(:each) do
112
+ FileUtils.rm_r Dir.glob(source_dir("lilypond_files/*"))
113
+ end
114
+
115
+ context "integration tests" do
116
+ let(:code_tag) { Jekyll::Lilypond::Tag.new({ "source_template_code" => '\version "2.20.0" { {{ content }} }',
117
+ "include_template_code" => '<img src="{{ filename }}.svg" />' },
118
+ "a b c d e") }
119
+ let(:subject) { described_class.new(site, code_tag) }
120
+ let(:target_hash) { "bfcae429ec31cea750c3ab8167526c7c" }
121
+ let(:target_include) { '<img src="bfcae429ec31cea750c3ab8167526c7c.svg" />' }
122
+ let(:target_path) { "#{source_dir}/lilypond_files/bfcae429ec31cea750c3ab8167526c7c.svg" }
123
+
124
+ it "Generates the correct hash from a real tag with explicit code" do
125
+ expect(subject.hash).to eq(target_hash)
126
+ end
127
+ it "Produces an SVG file at the expected location in the source tree" do
128
+ subject.run!
129
+ expect(File).to exist(target_path)
130
+ end
131
+ it "Includes the filename in the include code" do
132
+ expect(subject.include).to eq(target_include)
133
+ end
134
+ end
135
+ end
data/spec/tag_spec.rb ADDED
@@ -0,0 +1,51 @@
1
+ require "jekyll-lilypond"
2
+ require "spec_helper"
3
+ include Liquid
4
+
5
+ RSpec.describe(Jekyll::Lilypond::Tag) do
6
+ context "initialization" do
7
+ it "stores attribute values" do
8
+ t = described_class.new({"foo" => "bar"}, "text")
9
+ expect(t.attrs["foo"]).to eq("bar")
10
+ end
11
+ it "stores content" do
12
+ t = described_class.new({"foo" => "bar"}, "text")
13
+ expect(t.attrs["content"]).to eq("text")
14
+ end
15
+ it "stores source template addresses separately" do
16
+ t = described_class.new({"foo" => "bar", "source_template" => "filename.ly"}, "text")
17
+ expect(t.attrs["source_template"]).to eq(nil)
18
+ end
19
+ it "stores source template addresses in template_names" do
20
+ t = described_class.new({"foo" => "bar", "source_template" => "filename.ly"}, "text")
21
+ expect(t.template_names[:source]).to eq("filename.ly")
22
+ end
23
+ it "stores source template code in template_code" do
24
+ t = described_class.new({"foo" => "bar", "source_template_code" => "foo"}, "text")
25
+ expect(t.template_code[:source]).to eq("foo")
26
+ end
27
+ it "stores include template addresses separately" do
28
+ t = described_class.new({"foo" => "bar", "include_template" => "filename.ly"}, "text")
29
+ expect(t.attrs["include_template"]).to eq(nil)
30
+ end
31
+ it "stores include template addresses in template_names" do
32
+ t = described_class.new({"foo" => "bar", "include_template" => "filename.ly"}, "text")
33
+ expect(t.template_names[:include]).to eq("filename.ly")
34
+ end
35
+ it "stores include template code in template_code" do
36
+ t = described_class.new({"foo" => "bar", "include_template_code" => "foo"}, "text")
37
+ expect(t.template_code[:include]).to eq("foo")
38
+ end
39
+ it "copes with missing text" do
40
+ expect { described_class.new({"foo" => "bar"}, "") }.to_not raise_error()
41
+ end
42
+ it "creates template_names and template_code even when no values are provided" do
43
+ t = described_class.new({"foo" => "bar"}, "")
44
+ expect(t.template_names).to eq({source: nil, include: nil})
45
+ expect(t.template_code).to eq({source: nil, include: nil})
46
+ end
47
+ it "copes with empty attrs" do
48
+ expect { described_class.new({}, "text") }.to_not raise_error()
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,175 @@
1
+ require "jekyll-lilypond"
2
+ require "spec_helper"
3
+ include Liquid
4
+
5
+ long_content =<<-CONTENT
6
+ thing thing thing
7
+ stuff stuff stuff
8
+ (╯°□°)╯︵ ┻━┻)
9
+ ❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙
10
+ stuff stuff stuff
11
+ thing
12
+ CONTENT
13
+
14
+ RSpec.describe(Jekyll::Lilypond::Template) do
15
+ let(:site) { double("Site", layouts: { "name_a" => layout_a,
16
+ "name_b" => layout_b },
17
+ lilypond: double(template_names:
18
+ { source: "name_a",
19
+ include: "name_b" } )) }
20
+ let(:site_without_defaults) { double("Site", layouts: { "name_a" => layout_a,
21
+ "name_b" => layout_b }) }
22
+ let(:template_a) { "{{ content }}" }
23
+ let(:template_b) { "{{ content }}{{ a }}{{ b }}" }
24
+ let(:template_c) { "{{ content }}{{ a }}{{ b }}{{ c }}{{ d }}" }
25
+ let(:layout_a) { double(content: template_a) }
26
+ let(:layout_b) { double(content: template_b) }
27
+ let(:layout_c) { double(content: template_c) }
28
+
29
+ context "getting template names" do
30
+ context "when they are given by the tag" do
31
+ let(:tag) { double("Tag", attrs: {},
32
+ template_code: {source: nil, include: nil },
33
+ template_names: { source: "foo", include: "bar" }) }
34
+ it "returns the given source template name" do
35
+ subject = described_class.new(site, tag, :source)
36
+ expect(subject.template_name).to eq("foo")
37
+ end
38
+ it "returns the given include template name" do
39
+ subject = described_class.new(site, tag, :include)
40
+ expect(subject.template_name).to eq("bar")
41
+ end
42
+ end
43
+ context "when they are not given by the tag" do
44
+ let(:tag) { double("Tag", attrs: {},
45
+ template_code: {source: nil, include: nil },
46
+ template_names: { source: nil, include: nil }) }
47
+ it "returns the sitewide source template name" do
48
+ subject = described_class.new(site, tag, :source)
49
+ expect(subject.template_name).to eq("name_a")
50
+ end
51
+ it "returns the sitewide include template name" do
52
+ subject = described_class.new(site, tag, :include)
53
+ expect(subject.template_name).to eq("name_b")
54
+ end
55
+ it "won't error when there is no sitewide template name" do
56
+ subject = described_class.new(site_without_defaults, tag, :source)
57
+ expect { subject.template_name }.not_to raise_exception
58
+ end
59
+ end
60
+ context "when they are not given by the tag or the site" do
61
+ let(:tag) { double("Tag", attrs: {},
62
+ template_code: {source: nil, include: nil },
63
+ template_names: { source: nil, include: nil }) }
64
+ it "returns the pluginwide source template name" do
65
+ subject = described_class.new(site_without_defaults, tag, :source)
66
+ expect(subject.template_name).to eq("basic")
67
+ end
68
+ it "returns the pluginwide include template name" do
69
+ subject = described_class.new(site_without_defaults, tag, :include)
70
+ expect(subject.template_name).to eq("img")
71
+ end
72
+ end
73
+ end
74
+
75
+ context "when fetching templates" do
76
+ context "literal template code" do
77
+ let(:tag) { double("Tag", attrs: {},
78
+ template_names: { source: nil, include: nil },
79
+ template_code: { source: "foo", include: "bar" }) }
80
+ it "is used verbatim for source" do
81
+ subject = described_class.new(site, tag, :source)
82
+ expect(subject.template_code).to eq("foo")
83
+ end
84
+ it "is used verbatim for includes" do
85
+ subject = described_class.new(site, tag, :include)
86
+ expect(subject.template_code).to eq("bar")
87
+ end
88
+ end
89
+ context "a valid template name" do
90
+ let(:tag) { double("Tag",
91
+ attrs: {},
92
+ template_names: { source: "name_a", include: "name_b" },
93
+ template_code: { source: nil, include: nil }) }
94
+ it "loads the corresponding source template" do
95
+ subject = described_class.new(site, tag, :source)
96
+ expect(subject.template_code).to eq(template_a)
97
+ end
98
+ it "loads the corresponding include template" do
99
+ subject = described_class.new(site, tag, :include)
100
+ expect(subject.template_code).to eq(template_b)
101
+ end
102
+ end
103
+ context "a template name that the plugin defines but the site doesn't" do
104
+ let(:tag) { double("Tag",
105
+ attrs: {},
106
+ template_names: { source: "raw", include: "raw" },
107
+ template_code: { source: nil, include: nil }) }
108
+ it "loads the corresponding plugin source template" do
109
+ subject = described_class.new(site, tag, :source)
110
+ expect(subject.template_code).to eq("{{ content }}")
111
+ end
112
+ it "loads the corresponding plugin include template" do
113
+ subject = described_class.new(site, tag, :include)
114
+ expect(subject.template_code).to eq("{{ content }}")
115
+ end
116
+ end
117
+ context "a template name that the plugin and the site both define" do
118
+ let(:differentsite) { double("Site", layouts: { "raw" => layout_a }) }
119
+ let(:tag) { double("Tag",
120
+ attrs: {},
121
+ template_names: { source: "raw", include: "raw" },
122
+ template_code: { source: nil, include: nil }) }
123
+ it "gives the site version of the source template precedence" do
124
+ subject = described_class.new(differentsite, tag, :source)
125
+ expect(subject.template_code).to eq(template_a)
126
+ end
127
+ it "gives the site version of the include template precedence" do
128
+ subject = described_class.new(differentsite, tag, :include)
129
+ expect(subject.template_code).to eq(template_a)
130
+ end
131
+ end
132
+ context "an invalid template name" do
133
+ let(:tag) { double("Tag",
134
+ attrs: {},
135
+ template_names: { source: "i_do_not_exist", include: "i_do_not_exist" },
136
+ template_code: { source: nil, include: nil }) }
137
+ it "raises an error when it's a source template name" do
138
+ subject = described_class.new(site, tag, :source)
139
+ expect { subject.template_code }.to raise_exception(LoadError)
140
+ end
141
+ it "raises an error when it's an include template name" do
142
+ subject = described_class.new(site, tag, :include)
143
+ expect { subject.template_code }.to raise_exception(LoadError)
144
+ end
145
+ end
146
+ end
147
+
148
+ context "rendering" do
149
+ let(:tag) { double("Tag",
150
+ attrs: {"content" => "text",
151
+ "a" => "1",
152
+ "b" => "2"},
153
+ template_code: { source: template_a, include: template_b },
154
+ template_names: { source: nil, include: nil }) }
155
+ let(:long_tag) { double("Tag",
156
+ attrs: {"content" => long_content,
157
+ "a" => "1",
158
+ "b" => "2"},
159
+ template_code: { source: template_a, include: template_b },
160
+ template_names: { source: nil, include: nil }) }
161
+ it "renders a template without variables" do
162
+ subject = described_class.new(site, tag, :source)
163
+ expect(subject.render(tag)).to eq("text")
164
+ end
165
+ it "renders a template with variables" do
166
+ subject = described_class.new(site, tag, :include)
167
+ expect(subject.render(tag)).to eq("text12")
168
+ end
169
+ it "handles multiline content" do
170
+ subject = described_class.new(site, long_tag, :include)
171
+ expect(subject.render(long_tag)).to eq("#{long_content}12")
172
+ end
173
+ end
174
+ end
175
+
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-lilypond
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Leah Velleman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-04-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.5'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.5'
47
+ description:
48
+ email:
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - ".gitignore"
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - LICENSE
57
+ - README.md
58
+ - files/rite.png
59
+ - jekyll-lilypond.gemspec
60
+ - lib/jekyll-lilypond.rb
61
+ - lib/jekyll-lilypond/file_processor.rb
62
+ - lib/jekyll-lilypond/lilypond_tag.rb
63
+ - lib/jekyll-lilypond/tag.rb
64
+ - lib/jekyll-lilypond/tag_processor.rb
65
+ - lib/jekyll-lilypond/templates.rb
66
+ - lib/jekyll-lilypond/templates/basic.ly
67
+ - lib/jekyll-lilypond/templates/empty.ly
68
+ - lib/jekyll-lilypond/templates/figure.html
69
+ - lib/jekyll-lilypond/templates/img.html
70
+ - lib/jekyll-lilypond/templates/raw.html
71
+ - lib/jekyll-lilypond/templates/raw.ly
72
+ - lib/jekyll-lilypond/templates/showsource.html
73
+ - lib/jekyll-lilypond/version.rb
74
+ - spec/file_processor_spec.rb
75
+ - spec/fixtures/.gitignore
76
+ - spec/fixtures/404.html
77
+ - spec/fixtures/Gemfile
78
+ - spec/fixtures/_config.yml
79
+ - spec/fixtures/_layouts/basic_html.html
80
+ - spec/fixtures/_layouts/vacuous_html.html
81
+ - spec/fixtures/_layouts/vacuous_ly.ly
82
+ - spec/fixtures/_layouts/variables_html.html
83
+ - spec/fixtures/_layouts/variables_ly.ly
84
+ - spec/fixtures/_posts/2021-01-16-welcome-to-jekyll.markdown
85
+ - spec/fixtures/about.markdown
86
+ - spec/fixtures/index.markdown
87
+ - spec/fixtures/page.md
88
+ - spec/integration_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/tag_processor_spec.rb
91
+ - spec/tag_spec.rb
92
+ - spec/templates_spec.rb
93
+ homepage: https://www.velleman.org/jekyll-lilypond.html
94
+ licenses:
95
+ - MIT
96
+ metadata:
97
+ documentation_uri: https://www.velleman.org/jekyll-lilypond.html
98
+ source_code_uri: https://github.com/leahvelleman/jekyll-lilypond
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.0.3
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Lilypond music snippets in Jekyll
118
+ test_files: []