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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 03f518ed64fd17a4aa282f1e11c82f1ea127de1231919ad2f22f419f3a95d942
4
+ data.tar.gz: 8225e9fd20e2be85d2be52781a01d65de431313399d7313d754e416f78148c6c
5
+ SHA512:
6
+ metadata.gz: 48f09dbd1c6101a2ff2d13500690f72efee15bfc7b33cc647ecf050de11f082de1bc195a16fa56d52958b7605c362cf7a21258498f0cce8c51015436261056c5
7
+ data.tar.gz: 0b51587b3ff6e62de63486833c9269bd961d025d047770431adcb8b7fb0c98207eb6798efee19ee6e175e7a705d4811216395004290f7fe223755552dac9788c
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ spec/dest
2
+ *.gem
3
+ *.rbc
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "jekyll"
4
+ gem "minima"
5
+
6
+ group :development, :test do
7
+ gem "rspec"
8
+ gem 'simplecov', require: false, group: :test
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.7.0)
5
+ public_suffix (>= 2.0.2, < 5.0)
6
+ colorator (1.1.0)
7
+ concurrent-ruby (1.1.7)
8
+ diff-lcs (1.4.4)
9
+ docile (1.3.5)
10
+ em-websocket (0.5.2)
11
+ eventmachine (>= 0.12.9)
12
+ http_parser.rb (~> 0.6.0)
13
+ eventmachine (1.2.7)
14
+ ffi (1.14.2)
15
+ forwardable-extended (2.6.0)
16
+ http_parser.rb (0.6.0)
17
+ i18n (1.8.7)
18
+ concurrent-ruby (~> 1.0)
19
+ jekyll (4.2.0)
20
+ addressable (~> 2.4)
21
+ colorator (~> 1.0)
22
+ em-websocket (~> 0.5)
23
+ i18n (~> 1.0)
24
+ jekyll-sass-converter (~> 2.0)
25
+ jekyll-watch (~> 2.0)
26
+ kramdown (~> 2.3)
27
+ kramdown-parser-gfm (~> 1.0)
28
+ liquid (~> 4.0)
29
+ mercenary (~> 0.4.0)
30
+ pathutil (~> 0.9)
31
+ rouge (~> 3.0)
32
+ safe_yaml (~> 1.0)
33
+ terminal-table (~> 2.0)
34
+ jekyll-feed (0.15.1)
35
+ jekyll (>= 3.7, < 5.0)
36
+ jekyll-sass-converter (2.1.0)
37
+ sassc (> 2.0.1, < 3.0)
38
+ jekyll-seo-tag (2.7.1)
39
+ jekyll (>= 3.8, < 5.0)
40
+ jekyll-watch (2.2.1)
41
+ listen (~> 3.0)
42
+ kramdown (2.3.0)
43
+ rexml
44
+ kramdown-parser-gfm (1.1.0)
45
+ kramdown (~> 2.0)
46
+ liquid (4.0.3)
47
+ listen (3.4.1)
48
+ rb-fsevent (~> 0.10, >= 0.10.3)
49
+ rb-inotify (~> 0.9, >= 0.9.10)
50
+ mercenary (0.4.0)
51
+ minima (2.5.1)
52
+ jekyll (>= 3.5, < 5.0)
53
+ jekyll-feed (~> 0.9)
54
+ jekyll-seo-tag (~> 2.1)
55
+ pathutil (0.16.2)
56
+ forwardable-extended (~> 2.6)
57
+ public_suffix (4.0.6)
58
+ rb-fsevent (0.10.4)
59
+ rb-inotify (0.10.1)
60
+ ffi (~> 1.0)
61
+ rexml (3.2.4)
62
+ rouge (3.26.0)
63
+ rspec (3.10.0)
64
+ rspec-core (~> 3.10.0)
65
+ rspec-expectations (~> 3.10.0)
66
+ rspec-mocks (~> 3.10.0)
67
+ rspec-core (3.10.1)
68
+ rspec-support (~> 3.10.0)
69
+ rspec-expectations (3.10.1)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.10.0)
72
+ rspec-mocks (3.10.1)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.10.0)
75
+ rspec-support (3.10.1)
76
+ safe_yaml (1.0.5)
77
+ sassc (2.4.0)
78
+ ffi (~> 1.9)
79
+ simplecov (0.21.2)
80
+ docile (~> 1.1)
81
+ simplecov-html (~> 0.11)
82
+ simplecov_json_formatter (~> 0.1)
83
+ simplecov-html (0.12.3)
84
+ simplecov_json_formatter (0.1.2)
85
+ terminal-table (2.0.0)
86
+ unicode-display_width (~> 1.1, >= 1.1.1)
87
+ unicode-display_width (1.7.0)
88
+
89
+ PLATFORMS
90
+ universal-darwin-19
91
+
92
+ DEPENDENCIES
93
+ jekyll
94
+ minima
95
+ rspec
96
+ simplecov
97
+
98
+ BUNDLED WITH
99
+ 2.2.5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Leah Velleman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # jekyll-lilypond
2
+
3
+ <p align="center">
4
+ <img src="files/rite.png" width="75%"/>
5
+ </p>
6
+
7
+ Automatically generate sheet music images by adding Lilypond blocks to your markdown files. Customize their
8
+ appearance using Liquid attributes. The plugin caches the images it generates, making auto-regeneration fast.
9
+
10
+ For complete documentation, see [the plugin website](https://www.velleman.org/jekyll-lilypond).
11
+
12
+
13
+ ## Installation
14
+
15
+ The plugin requires Lilypond and Inkscape. To use it in a Jekyll site,
16
+ add
17
+
18
+ ```ruby
19
+ gem 'jekyll-lilypond'
20
+ ```
21
+
22
+ to your Gemfile and
23
+
24
+ ```yaml
25
+ plugins:
26
+ - jekyll-lilypond
27
+ ```
28
+
29
+ to your `_config.yml`.
30
+
31
+ ## Quick start
32
+
33
+ Inside the block, write a Lilypond music expression.
34
+ ```
35
+ {% lilypond alt: "Five notes of the A-minor scale" %}
36
+ a b c d e
37
+ {% endlilypond %}
38
+ ```
39
+ The expression can include multiple staves, expressive marks, time and key signature changes, and any of the other notation Lilypond supports within a music
40
+ expression. For details, see [this brief summary](https://lilypond.org/doc/v2.20/Documentation/learning/score-is-a-_0028single_0029-compound-musical-expression) in the Lilypond teaching manual or [Wikipedia's list of common music expression details](https://en.wikipedia.org/wiki/Help:Score#Syntax).
41
+
42
+ To make customizations that can't be make within a music expression — for instance, to change the width or height of the score or specify a custom font —
43
+ use attributes on the `{% lilypond %}` tag. For more information on attributes, see [the plugin documentation](http://127.0.0.1:4000/jekyll-lilypond#attributes).
44
+
45
+ ## Approach
46
+
47
+ ### Caching
48
+
49
+ Lilypond runs more slowly than Jekyll, and regenerating every score would create a noticeable lag. This would be especially painful in auto-regenerate mode,
50
+ which is normally very responsive. To solve this, I cache images. Each Lilypond source file, and each resulting image, has a filename derived from the MD5 hash
51
+ of the source code. The plugin only compiles a Lilypond source file when the corresponding image does not yet exist.
52
+
53
+ To force the plugin to regenerate all of the score images for a site, which is sometimes useful for debugging, empty the `lilypond_files` directory.
54
+
55
+ To keep upload size to a minimum, you can also empty the `lilypond_files` directory and regenerate the site before deploying. This removes "stale" images
56
+ that are no longer in use.
57
+
58
+ ### Templates
59
+
60
+ The plugin generates two kinds of code: Lilypond source files, which it uses to generate images, and HTML includes, which appear in the finished page
61
+ and contain the `img` element and surrounding markup.
62
+
63
+ To generate both kinds of source code, it uses Liquid templates. Liquid is the native templating language of Jekyll. Just as Jekyll users can write their own
64
+ templates to create new page layouts, users of this plugin can write their own templates to add simple features and customizations.
65
+
66
+ As well as allowing customization, using a template to generate Lilypond source avoids the need to repeat boilerplate. For instance, the default Lilypond
67
+ template begins like this:
68
+ ```
69
+ \version "2.20.0"
70
+ \paper {
71
+ indent = 0\mm
72
+ short-indent = 0\mm
73
+ bottom-margin = 4\mm
74
+ oddHeaderMarkup = ##f
75
+ evenHeaderMarkup = ##f
76
+ oddFooterMarkup = ##f
77
+ evenFooterMarkup = ##f
78
+ ...
79
+ }
80
+ ```
81
+ These settings produce clean output without extraneous marks, headers, footers, or whitespace, but it would be a hassle to retype them in every Lilypond block.
82
+ Later parts of the template include correct code for setting the page width, font, and so on, which saves the user from needing to remember the somewhat
83
+ arbitrary syntax for doing those things.
84
+
85
+ ### Future plans
86
+
87
+ The next thing on my agenda is to generate assets other than images. For instance, Lilypond can generate MIDI files and software synthesizers can generate
88
+ mp3 audio from MIDI. It would be nice to support those — and, beyond that, to support other workflows that users might think of. (Maybe someone will want to
89
+ generate video? Or do musical analysis on MIDI files?)
90
+
91
+ The most flexible way to do all this would be to let users specify workflow steps in a sitewide Rakefile, alongside whatever other deployment and
92
+ asset-processing tasks they may have specified there. Templates could then specify what sorts of generated files they require, and the plugin could call on
93
+ Rake to generate those that don't exist.
94
+
95
+ ## Testing
96
+
97
+ `bundle exec rspec` runs tests. A minimal sample Jekyll site for tests to call on is in `spec/fixtures`,
98
+ with the interesting details being the sample templates in `spec/fixtures/layouts`.
data/files/rite.png ADDED
Binary file
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "jekyll-lilypond/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.version = "0.1.1"
8
+ spec.authors = "Leah Velleman"
9
+ spec.name = "jekyll-lilypond"
10
+ spec.summary = "Lilypond music snippets in Jekyll"
11
+ spec.homepage = "https://www.velleman.org/jekyll-lilypond.html"
12
+ spec.license = "MIT"
13
+ spec.files = `git ls-files -z`.split("\x0")
14
+ spec.metadata = {
15
+ "documentation_uri" => "https://www.velleman.org/jekyll-lilypond.html",
16
+ "source_code_uri" => "https://github.com/leahvelleman/jekyll-lilypond"
17
+ }
18
+ spec.require_paths = ["lib"]
19
+ spec.add_dependency "jekyll", ">= 3.0", "< 5.0"
20
+ spec.add_development_dependency "rspec", "~> 3.5"
21
+ end
22
+
23
+
@@ -0,0 +1,67 @@
1
+ require "digest"
2
+
3
+ module Jekyll
4
+ module Lilypond
5
+ class FileProcessor
6
+ def initialize(working_dir, hash, source)
7
+ @hash = hash
8
+ @source = source
9
+ @working_dir = working_dir
10
+ end
11
+
12
+ def filepath
13
+ "#{@working_dir}/#{@hash}"
14
+ end
15
+
16
+ def write
17
+ unless File.directory?(@working_dir)
18
+ FileUtils.mkdir_p(@working_dir)
19
+ end
20
+ unless File.exist?("#{filepath}.ly")
21
+ File.open("#{filepath}.ly", "w") do |f|
22
+ f.write(@source)
23
+ end
24
+ end
25
+ end
26
+
27
+ def compile
28
+ unless File.exist?("#{filepath}.svg")
29
+ puts "Jekyll-lilypond: making #{@hash}.svg"
30
+ Kernel.system("lilypond", "-lERROR",
31
+ "-dbackend=svg",
32
+ "--output=#{filepath}",
33
+ "#{filepath}.ly")
34
+ end
35
+ end
36
+
37
+ def trim_svg
38
+ unless File.exist?("#{filepath}-trimmed.svg")
39
+ if File.exist?("#{filepath}.svg")
40
+ puts "Jekyll-lilypond: making #{@hash}-trimmed.svg"
41
+ Kernel.system("inkscape",
42
+ "#{filepath}.svg",
43
+ "--export-area-drawing",
44
+ "--export-type=svg",
45
+ "--export-filename=#{filepath}-trimmed.svg")
46
+ else
47
+ raise RuntimeError.new(
48
+ "Cannot trim SVG: expected SVG file #{filepath}.svg does not exist")
49
+ end
50
+ end
51
+ end
52
+
53
+ def make_mp3
54
+ unless File.exist?("#{filepath}.mp3")
55
+ if File.exist?("#{filepath}.midi")
56
+ puts "Jekyll-lilypond: making #{@hash}.mp3"
57
+ Kernel.system("timidity #{filepath}.midi -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k #{filepath}.mp3", [:out, :err] => "/dev/null")
58
+ else
59
+ raise RuntimeError.new(
60
+ "Cannot generate mp3: expected MIDI file #{filepath}.midi does not exist.")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,34 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class LilypondTag < Liquid::Block
4
+ def initialize(_, argtext, _)
5
+ super
6
+ @attributes = parse_attributes(argtext)
7
+ end
8
+
9
+ def parse_attributes(text)
10
+ attributes = {}
11
+ text.scan(Liquid::TagAttributes) do |key, value|
12
+ value=value.delete_prefix('"').delete_prefix("'")
13
+ value=value.delete_suffix('"').delete_suffix("'")
14
+ attributes[key] = value
15
+ end
16
+ attributes["attr_text"] = text
17
+ attributes
18
+ end
19
+
20
+ def render(context)
21
+ content = super.strip
22
+ site = context.registers[:site]
23
+
24
+ tag = Tag.new(@attributes, content)
25
+ tp = TagProcessor.new(site, tag)
26
+ tp.run!
27
+ tp.include
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Liquid::Template.register_tag("lilypond", Jekyll::Lilypond::LilypondTag)
34
+
@@ -0,0 +1,17 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class Tag
4
+ attr_accessor :attrs, :template_names, :template_code
5
+
6
+ def initialize(attrs, content)
7
+ @attrs = attrs
8
+ @attrs["content"] = content
9
+ @template_names = { source: @attrs.delete("source_template"),
10
+ include: @attrs.delete("include_template") }
11
+ @template_code = { source: @attrs.delete("source_template_code"),
12
+ include: @attrs.delete("include_template_code") }
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,56 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class TagProcessor
4
+ attr_accessor :site
5
+
6
+ def initialize(site, tag)
7
+ @site = site
8
+ @tag = tag
9
+ end
10
+
11
+ def source
12
+ source_template_obj.render(@tag)
13
+ end
14
+
15
+ def source_template_obj
16
+ Template.new(@site, @tag, :source)
17
+ end
18
+
19
+ def hash
20
+ Digest::MD5.hexdigest(source)
21
+ end
22
+
23
+ def include
24
+ @tag.attrs.update("filename" => hash)
25
+ include_template_obj.render(@tag)
26
+ end
27
+
28
+ def include_template_obj
29
+ Template.new(@site, @tag, :include)
30
+ end
31
+
32
+ def file_processor
33
+ FileProcessor.new("#{site.source}/lilypond_files", hash, source)
34
+ end
35
+
36
+ def run!
37
+ fp = file_processor
38
+ fp.write
39
+ fp.compile
40
+ fp.trim_svg
41
+ fp.make_mp3 if @tag.attrs["mp3"] == "true"
42
+
43
+ @site.static_files << StaticFile.new(site,
44
+ site.source,
45
+ "lilypond_files",
46
+ "#{hash}-trimmed.svg")
47
+
48
+ @site.static_files << StaticFile.new(site,
49
+ site.source,
50
+ "lilypond_files",
51
+ "#{hash}.mp3") if @tag.attrs["mp3"] == "true"
52
+ end
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,45 @@
1
+ \version "2.20.0"
2
+ \include "articulate.ly"
3
+ \paper {
4
+ indent = 0\mm
5
+ short-indent = 0\mm
6
+ {% if width %}
7
+ paper-width = {{ width }}\in
8
+ {% if height %}
9
+ paper-height = {{ height }}\in
10
+ {% else %}
11
+ page-breaking = #ly:one-page-breaking
12
+ {% endif %}
13
+ {% else %}
14
+ page-breaking = #ly:one-line-breaking
15
+ {% endif %}
16
+ left-margin = 4\mm
17
+ right-margin = 4\mm
18
+ top-margin = 4\mm
19
+ bottom-margin = 4\mm
20
+ oddHeaderMarkup = ##f
21
+ evenHeaderMarkup = ##f
22
+ oddFooterMarkup = ##f
23
+ evenFooterMarkup = ##f
24
+ }
25
+ \score {
26
+ \unfoldRepeats \articulate
27
+ <<
28
+ {{ content }}
29
+ >>
30
+ \layout {
31
+ #(layout-set-staff-size 16)
32
+ \context {
33
+ \Lyrics
34
+ {% if lyricfont %}
35
+ \override LyricText #'font-name = #"{{ lyricfont }}"
36
+ {% endif %}
37
+ {% if lyricsize %}
38
+ \override LyricText #'font-size = #{{ lyricsize }}
39
+ {% endif %}
40
+ }
41
+ }
42
+ \midi {
43
+ \tempo 4 = {{ tempo | default: "120" }}
44
+ }
45
+ }
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1,25 @@
1
+ <figure>
2
+ <img
3
+ src="lilypond_files/{{ filename }}-trimmed.svg"
4
+ {%- if style %}
5
+ style="{{ style }}"
6
+ {% endif -%}
7
+ {%- if class %}
8
+ class="{{ class }}"
9
+ {% endif -%}
10
+ {%- if alt %}
11
+ alt="{{ alt }}"
12
+ title="{{ alt }}"
13
+ {% endif -%}
14
+ />
15
+ {%- if mp3 %}
16
+ <audio controls>
17
+ <source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
18
+ Your browser does not support the <code>audio</code> element.
19
+ </audio>
20
+ {% endif -%}
21
+ {%- if caption %}
22
+ <figcaption>{{ caption }}</figcaption>
23
+ {% endif -%}
24
+ </figure>
25
+
@@ -0,0 +1,4 @@
1
+ <img src="lilypond_files/{{ filename }}-trimmed.svg"
2
+ alt="{{ alt }}"
3
+ class="{{ class }}"
4
+ style="{{ style }}"/>
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1,36 @@
1
+ <figure
2
+ {%- if style %}
3
+ style="{{ style }}"
4
+ {% endif -%}
5
+ {%- if class %}
6
+ class="{{ class }}"
7
+ {% endif -%}
8
+ >
9
+ <img src="lilypond_files/{{ filename }}-trimmed.svg"
10
+ {%- if alt %}
11
+ alt="{{ alt }}"
12
+ title="{{ alt }}"
13
+ {% endif -%}
14
+ />
15
+ {%- if mp3 %}
16
+ <audio controls>
17
+ <source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
18
+ Your browser does not support the <code>audio</code> element.
19
+ </audio>
20
+ {% endif -%}
21
+ {%- if caption %}
22
+ <figcaption>{{ caption }}</figcaption>
23
+ {% endif -%}
24
+ <details>
25
+ <summary>Show source</summary>
26
+ <pre>
27
+ {%- raw -%}{% {% endraw %}
28
+ lilypond {{ attr_text -}}
29
+ {%- raw %}%}{% endraw %}
30
+ {{ content | escape -}}
31
+ {%- raw -%}
32
+ {% endlilypond %}
33
+ {% endraw %}
34
+ </pre>
35
+ </details>
36
+ </figure>
@@ -0,0 +1,60 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class Template
4
+ def initialize(site, tag, type)
5
+ @site = site
6
+ @type = type
7
+ @tag_template_names = tag.template_names
8
+ @tag_template_code = tag.template_code
9
+ end
10
+
11
+ def render(tag)
12
+ Liquid::Template.parse(template_code).render(tag.attrs)
13
+ end
14
+
15
+ def template_name
16
+ @tag_template_names[@type] || sitewide_template_names[@type] || plugin_template_names[@type]
17
+ end
18
+
19
+ def template_code
20
+ @tag_template_code[@type] or
21
+ fetch_site_template(template_name) or
22
+ fetch_plugin_template(template_name) or
23
+ raise LoadError.new("No template named #{template_name}.#{extension}")
24
+ end
25
+
26
+
27
+ private
28
+ def sitewide_template_names
29
+ if @site.respond_to? :lilypond and @site.lilypond.respond_to? :template_names
30
+ @site.lilypond.template_names
31
+ else
32
+ { source: nil, include: nil }
33
+ end
34
+ end
35
+
36
+ def plugin_template_names
37
+ { source: "basic", include: "img" }
38
+ end
39
+
40
+ def fetch_site_template(name)
41
+ if @site.layouts[name]
42
+ @site.layouts[name].content.strip
43
+ end
44
+ end
45
+
46
+ def fetch_plugin_template(name)
47
+ dir = File.join(File.dirname(__dir__), "/jekyll-lilypond/templates/")
48
+ filename = File.join(dir, "#{name}.#{extension}")
49
+ if File.exists?(filename)
50
+ File.read(filename).strip
51
+ end
52
+ end
53
+
54
+ def extension
55
+ if @type == :source then "ly" else "html" end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ VERSION = "0.0.0"
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ require "jekyll"
2
+ require "jekyll-lilypond/tag.rb"
3
+ require "jekyll-lilypond/file_processor.rb"
4
+ require "jekyll-lilypond/templates.rb"
5
+ require "jekyll-lilypond/tag_processor.rb"
6
+ require "jekyll-lilypond/lilypond_tag.rb"
7
+
8
+ module Jekyll
9
+ module Lilypond
10
+ end
11
+ end