gly 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 341817505f45deff8e6c9815061fa6cffa571858
4
- data.tar.gz: 64ff6cb093190e69c37ed874af5c9b34e1499c3f
3
+ metadata.gz: a1be7280dd39aa6117888f6779c409359202d8bb
4
+ data.tar.gz: b5bc60c05106a3472b4fa296cc0787f1c804ab8f
5
5
  SHA512:
6
- metadata.gz: 41ba343096d37f095b7e9ca1724a8692d7bf4ca6dfcac689e681e9c61c1c95067ec42ba18f6fa8de259f6bf70b1960e5108f1f2503be1044e8df64bb0ec6fa96
7
- data.tar.gz: a14a88215832854321ecadff5fd0f0c01a057d3ad991873aede7d91b879da35edfe197bca214144a55a4ad4ff893d0a365505849ce62020b9da7361a5fe9a2e8
6
+ metadata.gz: d695541f34baae56918b864e062387426889b55dbed9e1636688157c1b4eadec906556be053de0b4da8f3a588c1fe415a12104ae844a5045471bfd91dfcec32c
7
+ data.tar.gz: 8aab9514701279b9e4ab1f00282e323902924c5f9b38fcf2ab1aa2fd9e534759a8a62220a38fa72d08ec0711eb78fb78c499760b97ea901458bcf93c326d7415
data/lib/gly.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  module Gly; end
2
2
 
3
- %w(parser gabc_convertor parsed_score headers lyrics document string_helpers).each do |mod|
3
+ %w(parser
4
+ gabc_convertor
5
+ parsed_score
6
+ headers
7
+ lyrics
8
+ document
9
+ document_gabc_convertor
10
+ preview_generator
11
+ lister
12
+ string_helpers).each do |mod|
4
13
  require "gly/#{mod}"
5
14
  end
@@ -5,90 +5,37 @@ module Gly
5
5
  class CLI < Thor
6
6
  desc 'gabc FILE ...', 'convert gly to gabc'
7
7
  def gabc(*files)
8
- files.each {|f| gabc_convert(parse(f)) }
8
+ files.each {|f| DocumentGabcConvertor.new(Parser.new.parse(f)).convert }
9
9
  end
10
10
 
11
11
  desc 'preview FILE ...', 'convert to gabc AND generate pdf preview'
12
12
  def preview(*files)
13
- files.each {|f| make_preview f }
13
+ files.each {|f| PreviewGenerator.new.process(Parser.new.parse(f)) }
14
14
  end
15
15
 
16
- private
17
-
18
- def parse(gly_file)
19
- document = File.open(gly_file) do |fr|
20
- Parser.new.parse(fr)
21
- end
22
- end
23
-
24
- def gabc_convert(doc)
25
- doc.scores.each_with_index do |score, si|
26
- score_id = score.headers['id'] || si.to_s
27
- out_fname = File.basename(doc.path)
28
- .sub(/\.gly\Z/i, "_#{score_id}.gabc")
29
- File.open(out_fname, 'w') do |fw|
30
- GabcConvertor.new.convert score, fw
31
- end
32
- yield score, out_fname if block_given?
16
+ desc 'list FILE ...', 'list scores contained in files'
17
+ option :recursive, type: :boolean, aliases: :r, banner: 'recursively traverse directories', default: false
18
+ def list(*files)
19
+ if files.empty?
20
+ STDERR.puts 'No file specified.'
21
+ exit 1
33
22
  end
34
- end
35
-
36
- def make_preview(gly_file)
37
- doc = parse(gly_file)
38
-
39
- tex_header = <<EOS
40
- % LuaLaTeX
41
-
42
- \\documentclass[a4paper, 12pt]{article}
43
- \\usepackage[latin]{babel}
44
- \\usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
45
-
46
- \\usepackage{fontspec}
47
23
 
48
- % for gregorio
49
- \\usepackage{luatextra}
50
- \\usepackage{graphicx}
51
- \\usepackage{gregoriotex}
52
-
53
- \\title{#{doc.header['title']}}
54
-
55
- \\begin{document}
56
-
57
- #{doc.header['title'] && '\\maketitle'}
58
-
59
- EOS
60
-
61
- tex_fname = File.basename(gly_file).sub(/\.gly\Z/i, '.tex')
62
- File.open(tex_fname, 'w') do |fw|
63
- fw.puts tex_header
64
-
65
- gabc_convert(doc) do |score, gabc_fname|
66
- system "gregorio #{gabc_fname}"
67
- gtex_fname = gabc_fname.sub /\.gabc/i, ''
68
- piece_title = %w(book manuscript arranger author).collect do |m|
69
- score.headers[m]
70
- end.delete_if(&:nil?).join ', '
71
- fw.puts "\\commentary{\\footnotesize{#{piece_title}}}\n" unless piece_title.empty?
72
-
73
- annotations = score.headers.each_value('annotation')
74
- begin
75
- fw.puts "\\setfirstannotation{#{annotations.next}}"
76
- fw.puts "\\setsecondannotation{#{annotations.next}}"
77
- rescue StopIteration
78
- # ok, no more annotations
24
+ if options[:recursive]
25
+ files = files.collect do |f|
26
+ if File.directory?(f)
27
+ Dir[File.join(f, '**/*.gly')]
28
+ else
29
+ f
79
30
  end
80
-
81
- fw.puts "\\includescore{#{gtex_fname}}\n\\vspace{1cm}"
82
31
  end
83
-
84
- # tagline
85
- fw.puts "\n\\vfill\n\\begin{center}"
86
- fw.puts "\\texttt{gly preview https://github.com/igneus/gly}"
87
- fw.puts "\\end{center}\n"
88
- fw.puts "\n\\end{document}"
32
+ files.flatten!
89
33
  end
90
34
 
91
- system "lualatex #{tex_fname}"
35
+ lister = Lister.new(files)
36
+ lister.list(STDOUT, STDERR)
37
+
38
+ exit(lister.error? ? 1 : 0)
92
39
  end
93
40
  end
94
41
  end
@@ -0,0 +1,34 @@
1
+ module Gly
2
+ class DocumentGabcConvertor
3
+ def initialize(document)
4
+ @doc = document
5
+ end
6
+
7
+ def convert
8
+ each_score_with_gabcname do |score, out_fname|
9
+ File.open(out_fname, 'w') do |fw|
10
+ GabcConvertor.new.convert score, fw
11
+ end
12
+ yield score, out_fname if block_given?
13
+ end
14
+ end
15
+
16
+ # iterates over document scores,
17
+ # yields score and filename of it's generated gabc file
18
+ def each_score_with_gabcname
19
+ @doc.scores.each_with_index do |score, si|
20
+ yield score, output_fname(score, si)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def output_fname(score, score_index=nil)
27
+ score_id = score.headers['id'] || score_index.to_s
28
+ score_id = '_' + score_id unless score_id.empty?
29
+
30
+ File.basename(@doc.path)
31
+ .sub(/\.gly\Z/i, "#{score_id}.gabc")
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module Gly
2
+ class DocumentGabcConvertor
3
+ def initialize(document)
4
+ @doc = document
5
+ end
6
+
7
+ def convert
8
+ @doc.scores.each_with_index do |score, si|
9
+ score_id = score.headers['id'] || si.to_s
10
+ out_fname = File.basename(doc.path)
11
+ .sub(/\.gly\Z/i, "_#{score_id}.gabc")
12
+ File.open(out_fname, 'w') do |fw|
13
+ GabcConvertor.new.convert score, fw
14
+ end
15
+ yield score, out_fname if block_given?
16
+ end
17
+ end
18
+
19
+ def output_fname(input_fname, score_id=nil)
20
+
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,7 @@
1
+ require 'stringio'
2
+
1
3
  module Gly
2
- # converts parsed gly to gabc
4
+ # takes ParsedScore, translates it to gabc
3
5
  class GabcConvertor
4
6
  def convert(score, out=StringIO.new)
5
7
  score.headers.each_pair do |key,value|
@@ -41,7 +43,7 @@ module Gly
41
43
  end
42
44
 
43
45
  def differentia?(chunk)
44
- chunk =~ /\A*[,;:]+\Z/ # differentia
46
+ chunk =~ /\A*[,;:`]+\Z/ # differentia
45
47
  end
46
48
 
47
49
  # is the given music chunk capable of bearing lyrics?
@@ -0,0 +1,32 @@
1
+ module Gly
2
+ class Lister
3
+ def initialize(files)
4
+ @files = files
5
+ @error = false
6
+ end
7
+
8
+ def list(io, errio)
9
+ @files.each do |f|
10
+ begin
11
+ document = Parser.new.parse(f)
12
+ rescue SystemCallError => err # Errno::WHATEVER
13
+ errio.puts "Cannot read file '#{f}': #{err.message}"
14
+ @error = true
15
+ next
16
+ end
17
+
18
+ io.puts
19
+ io.puts "== #{f}"
20
+
21
+ document.scores.each do |s|
22
+ l = s.lyrics.readable
23
+ io.puts l unless l.empty?
24
+ end
25
+ end
26
+ end
27
+
28
+ def error?
29
+ @error
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Gly
2
+ class Lister
3
+ def initialize(files)
4
+ @files = files
5
+ end
6
+
7
+ def list(io, errio)
8
+ was_error = false
9
+
10
+ files.each do |f|
11
+ begin
12
+ document = parse(f)
13
+ rescue SystemCallError => err # Errno::WHATEVER
14
+ errio.puts "Cannot read file '#{f}': #{err.message}"
15
+ was_error = true
16
+ next
17
+ end
18
+
19
+ puts
20
+ puts "== #{f}"
21
+
22
+ document.scores.each do |s|
23
+ l = s.lyrics.readable
24
+ puts l unless l.empty?
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -23,7 +23,11 @@ module Gly
23
23
  end
24
24
 
25
25
  def_delegator :@words, :each, :each_word
26
- def_delegators :@words, :empty?, :<<
26
+ def_delegators :@words, :<<, :empty?
27
+
28
+ def readable
29
+ @words.collect(&:readable).join ' '
30
+ end
27
31
  end
28
32
 
29
33
  class Word
@@ -35,5 +39,12 @@ module Gly
35
39
 
36
40
  def_delegators :@syllables, :<<, :push
37
41
  def_delegator :@syllables, :each, :each_syllable
42
+
43
+ def readable
44
+ without_directives = @syllables.collect do |s|
45
+ s.start_with?('!') ? s[1..-1] : s
46
+ end
47
+ without_directives.join
48
+ end
38
49
  end
39
50
  end
@@ -1,9 +1,37 @@
1
+ require 'stringio'
2
+
1
3
  module Gly
2
4
  # parses gly source
3
5
  class Parser
4
- SYLLABLE_SEP = '--'
6
+ def initialize(syllable_separator='--')
7
+ @syllable_separator = syllable_separator
8
+ end
9
+
10
+ def parse(source)
11
+ if source.is_a? String
12
+ if File.file? source
13
+ parse_fname source
14
+ elsif source == '-'
15
+ parse_io STDIN
16
+ else
17
+ parse_str source
18
+ end
19
+ else
20
+ parse_io source
21
+ end
22
+ end
23
+
24
+ def parse_fname(str)
25
+ File.open(str) do |fr|
26
+ parse_io fr
27
+ end
28
+ end
29
+
30
+ def parse_str(str)
31
+ parse_io(StringIO.new(source))
32
+ end
5
33
 
6
- def parse(io)
34
+ def parse_io(io)
7
35
  @doc = Document.new
8
36
  @score = ParsedScore.new
9
37
 
@@ -61,7 +89,7 @@ module Gly
61
89
  EXPLICIT_LYRICS_RE = /\A\\l(yrics)?\s+/
62
90
 
63
91
  def lyrics_line?(str)
64
- str =~ EXPLICIT_LYRICS_RE || str.include?(SYLLABLE_SEP) || contains_unmusical_letters?(str)
92
+ str =~ EXPLICIT_LYRICS_RE || str.include?(@syllable_separator) || contains_unmusical_letters?(str)
65
93
  end
66
94
 
67
95
  def in_header_block?
@@ -83,16 +111,15 @@ module Gly
83
111
  # separator
84
112
  str
85
113
  .sub(EXPLICIT_LYRICS_RE, '')
86
- .split(/(?<!#{SYLLABLE_SEP})\s+(?!#{SYLLABLE_SEP})/)
114
+ .split(/(?<!#{@syllable_separator})\s+(?!#{@syllable_separator})/)
87
115
  .each do |word|
88
- @score.lyrics << Word.new(word.split(/\s*#{SYLLABLE_SEP}\s*/))
116
+ @score.lyrics << Word.new(word.split(/\s*#{@syllable_separator}\s*/))
89
117
  end
90
118
  end
91
119
 
92
120
  def parse_music(str)
93
121
  # music chunks: split by whitespace out of brackets
94
- str.split(/\s+/).each do |chunk|
95
- chunk.sub!(/\A\((.*?)\)\Z/, '\1') # unparenthesize
122
+ StringHelpers.music_split(str).each do |chunk|
96
123
  @score.music << chunk
97
124
  end
98
125
  end
@@ -0,0 +1,48 @@
1
+ require 'stringio'
2
+
3
+ module Gly
4
+ # Takes Gly::Document, builds a pdf preview
5
+ # (or at least generates all necessary assets)
6
+ class PreviewGenerator
7
+ def process(document)
8
+ tpl_name = File.join(File.dirname(__FILE__), 'templates/lualatex_document.tex')
9
+ template = File.read(tpl_name)
10
+
11
+ doc_body = fw = StringIO.new
12
+
13
+ convertor = DocumentGabcConvertor.new(document)
14
+ convertor.each_score_with_gabcname do |score, gabc_fname|
15
+ system "gregorio #{gabc_fname}"
16
+ gtex_fname = gabc_fname.sub /\.gabc/i, ''
17
+ piece_title = %w(book manuscript arranger author).collect do |m|
18
+ score.headers[m]
19
+ end.delete_if(&:nil?).join ', '
20
+ fw.puts "\\commentary{\\footnotesize{#{piece_title}}}\n" unless piece_title.empty?
21
+
22
+ annotations = score.headers.each_value('annotation')
23
+ begin
24
+ fw.puts "\\setfirstannotation{#{annotations.next}}"
25
+ fw.puts "\\setsecondannotation{#{annotations.next}}"
26
+ rescue StopIteration
27
+ # ok, no more annotations
28
+ end
29
+
30
+ fw.puts "\\includescore{#{gtex_fname}}\n\\vspace{1cm}"
31
+ end
32
+
33
+ replacements = {
34
+ title: document.header['title'],
35
+ maketitle: (document.header['title'] && '\maketitle'),
36
+ body: doc_body.string
37
+ }
38
+ tex = template % replacements
39
+
40
+ out_fname = File.basename(document.path).sub(/\.gly\Z/i, '.tex')
41
+ File.open(out_fname, 'w') do |fw|
42
+ fw.puts tex
43
+ end
44
+
45
+ system "lualatex #{out_fname}"
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ module Gly
2
+ # Takes Gly::Document, builds a pdf preview
3
+ # (or at least generates all necessary assets)
4
+ class PreviewGenerator
5
+
6
+ end
7
+ end
@@ -1,7 +1,7 @@
1
1
  module Gly
2
2
  module StringHelpers
3
3
  extend self
4
-
4
+
5
5
  # splits string by whitespace that is not enclosed
6
6
  # in brackets.
7
7
  # At the same time removes brackets.
@@ -12,10 +12,16 @@ module Gly
12
12
  in_brackets = false
13
13
  str.chars.each_with_index do |char, chi|
14
14
  if in_brackets
15
- next if char != ')'
16
-
15
+ if char == ')'
16
+ in_brackets = false
17
+ chunks << str[chunk_start .. chi-1]
18
+ chunk_start = chi + 1
19
+ end
17
20
  else
18
- if char =~ /^\s$/
21
+ if char == '('
22
+ in_brackets = true
23
+ chunk_start = chi + 1
24
+ elsif char =~ /^\s$/
19
25
  if chunk_start != chi
20
26
  chunks << str[chunk_start .. chi-1]
21
27
  end
@@ -24,7 +30,9 @@ module Gly
24
30
  end
25
31
  end
26
32
 
27
- chunks << str[chunk_start .. -1]
33
+ if chunk_start < str.size
34
+ chunks << str[chunk_start .. -1]
35
+ end
28
36
 
29
37
  chunks
30
38
  end
@@ -24,9 +24,7 @@ module Gly
24
24
  end
25
25
  end
26
26
 
27
- if chunk_start != chi
28
- chunks << str[chunk_start .. chi-1]
29
- end
27
+ chunks << str[chunk_start .. -1]
30
28
 
31
29
  chunks
32
30
  end
@@ -0,0 +1,27 @@
1
+ %% LuaLaTeX
2
+
3
+ \documentclass[a4paper, 12pt]{article}
4
+ \usepackage[latin]{babel}
5
+ \usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
6
+
7
+ \usepackage{fontspec}
8
+
9
+ %% for gregorio
10
+ \usepackage{luatextra}
11
+ \usepackage{graphicx}
12
+ \usepackage{gregoriotex}
13
+
14
+ \title{%{title}}
15
+
16
+ \begin{document}
17
+
18
+ %{maketitle}
19
+
20
+ %{body}
21
+
22
+ %% tagline
23
+ \vfill
24
+ \begin{center}
25
+ \texttt{gly preview https://github.com/igneus/gly}
26
+ \end{center}
27
+ \end{document}
@@ -0,0 +1,27 @@
1
+ % LuaLaTeX
2
+
3
+ \documentclass[a4paper, 12pt]{article}
4
+ \usepackage[latin]{babel}
5
+ \usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
6
+
7
+ \usepackage{fontspec}
8
+
9
+ % for gregorio
10
+ \usepackage{luatextra}
11
+ \usepackage{graphicx}
12
+ \usepackage{gregoriotex}
13
+
14
+ \title{#{doc.header['title']}}
15
+
16
+ \begin{document}
17
+
18
+ %{maketitle}
19
+
20
+ %{body}
21
+
22
+ % tagline
23
+ \vfill
24
+ \begin{center}
25
+ \texttt{gly preview https://github.com/igneus/gly}
26
+ \end{center}
27
+ \end{document}
@@ -8,8 +8,9 @@ class StringHelpersTest < GlyTest
8
8
  ['simple_whitespace', 'aa aa', ['aa', 'aa']],
9
9
  ['leading_trailing_whitespace', ' a a ', ['a', 'a']],
10
10
  ['bracketted', '(a)', ['a']],
11
+ ['empty', '()', ['']]
11
12
  ]
12
-
13
+
13
14
  examples.each do |e|
14
15
  name, given, expected = e
15
16
  define_method "test_#{name}" do
@@ -2,8 +2,18 @@ require_relative 'test_helper'
2
2
 
3
3
  class StringHelpersTest < GlyTest
4
4
  SH = Gly::StringHelpers
5
+
6
+ examples = [
7
+ ['single_chunk', 'a', ['a']],
8
+ ['simple_whitespace', 'aa aa', ['aa', 'aa']],
9
+ ['leading_trailing_whitespace', ' a a ', ['a', 'a']],
10
+ ['bracketted', '(a)', ['a']],
11
+ ]
5
12
 
6
- def test_simple_whitespace_split
7
- assert_equal ['aa', 'aa'], SH.music_split('aa aa')
13
+ examples.each do |e|
14
+ name, given, expected = e
15
+ define_method "test_#{name}" do
16
+ assert_equal expected, SH.music_split(given)
17
+ end
8
18
  end
9
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Pavlík
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-15 00:00:00.000000000 Z
11
+ date: 2015-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -49,23 +49,26 @@ description: "# gly\n\nWriter-friendly Gregorian notation format compiling to ga
49
49
  or\n lyrics alone is possible (useful for a composer)\n * syllabified lyrics
50
50
  entered in a format inspired by LilyPond\n* music and lyrics can be interspersed
51
51
  as needed\n* no semicolons in the header\n* custom header fields supported (commented
52
- out in the GABC output;\n as gregorio crashes on headers it doesn't know)\n* several
53
- scores per file (when compiled to gabc, each becomes\n a separate file)\n* compile
54
- pdf preview by a single command, without writing any (La)TeX\n\n## Examples\n\nTypical
55
- GABC source of an antiphon looks like this:\n\n name: Nativitas gloriosae;\n
56
- \ office-part: laudes, 1. ant.;\n occasion: In Nativitate B. Mariae Virginis;\n
57
- \ book: Antiphonale Romanum 1912, pg. 704;\n mode: 8;\n initial-style: 1;\n
58
- \ %%\n \n (c4) NA(g)TI(g)VI(g)TAS(gd) glo(f)ri(gh)ó(g)sae(g) * (,)\n Vír(g)gi(g)nis(hi)
59
- Ma(gh)rí(gf)ae,(f) (;)\n ex(f) (g)mi(h)ne(h) A(hiwji)bra(hg)hae,(g) (;)\n or(gh~)tae(g)
60
- de(g) tri(g)bu(fe/fgf) Ju(d)da,(d) (;)\n cla(df!gh)ra(g) ex(f) stir(hg~)pe(hi)
61
- Da(h)vid.(g) (::)\n\nCorresponding GLY may look like this:\n\n name: Nativitas
62
- gloriosae\n office-part: laudes, 1. ant.\n occasion: In Nativitate B. Mariae
63
- Virginis\n book: Antiphonale Romanum 1912, pg. 704\n mode: 8\n initial-style:
64
- 1\n \n c4 g g g gd f gh g g ,\n g g hi gh gf f ;\n f g h h hiwji hg
65
- g ;\n gh~ g g g fe/fgf d d ;\n df!gh g f hg~ hi h g ::\n \n NA -- TI
66
- -- VI -- TAS glo -- ri -- ósae *\n Vír -- gi -- nis Ma -- rí -- ae,\n ex sé
67
- -- mi -- ne A -- bra -- hae,\n or -- tae de tri -- bu Ju -- da,\n cla -- ra
68
- ex stir -- pe Da -- vid.\n\nOr, with music and lyrics interlaced:\n\n name: Nativitas
52
+ out in the GABC output,\n as gregorio doesn't tolerate headers it doesn't know)\n*
53
+ several scores per file (when compiled to gabc, each becomes\n a separate file)\n*
54
+ compile pdf preview by a single command, without writing any (La)TeX\n\n## Real
55
+ world examples\n\n* [Proper Divine Office chants of Bohemian Premonstratensian houses][opraem_boh]\n\n##
56
+ Basic examples\n\nTypical GABC source of an antiphon looks like this:\n\n name:
57
+ Nativitas gloriosae;\n office-part: laudes, 1. ant.;\n occasion: In Nativitate
58
+ B. Mariae Virginis;\n book: Antiphonale Romanum 1912, pg. 704;\n mode: 8;\n
59
+ \ initial-style: 1;\n %%\n \n (c4) NA(g)TI(g)VI(g)TAS(gd) glo(f)ri(gh)ó(g)sae(g)
60
+ * (,)\n Vír(g)gi(g)nis(hi) Ma(gh)rí(gf)ae,(f) (;)\n ex(f)(g)mi(h)ne(h)
61
+ A(hiwji)bra(hg)hae,(g) (;)\n or(gh~)tae(g) de(g) tri(g)bu(fe/fgf) Ju(d)da,(d)
62
+ (;)\n cla(df!gh)ra(g) ex(f) stir(hg~)pe(hi) Da(h)vid.(g) (::)\n\nCorresponding
63
+ GLY may look like this:\n\n name: Nativitas gloriosae\n office-part: laudes,
64
+ 1. ant.\n occasion: In Nativitate B. Mariae Virginis\n book: Antiphonale Romanum
65
+ 1912, pg. 704\n mode: 8\n initial-style: 1\n \n c4 g g g gd f gh g g
66
+ ,\n g g hi gh gf f ;\n f g h h hiwji hg g ;\n gh~ g g g fe/fgf d d ;\n
67
+ \ df!gh g f hg~ hi h g ::\n \n NA -- TI -- VI -- TAS glo -- ri -- ósae *\n
68
+ \ Vír -- gi -- nis Ma -- rí -- ae,\n ex -- mi -- ne A -- bra -- hae,\n or
69
+ -- tae de tri -- bu Ju -- da,\n cla -- ra ex stir -- pe Da -- vid.\n\nOr, with
70
+ music and lyrics interlaced\n(this arrangement may be handy for larger scores,\nlike
71
+ full-notated hymns, sequences or nocturnal responsories):\n\n name: Nativitas
69
72
  gloriosae\n office-part: laudes, 1. ant.\n occasion: In Nativitate B. Mariae
70
73
  Virginis\n book: Antiphonale Romanum 1912, pg. 704\n mode: 8\n initial-style:
71
74
  1\n \n c4 g g g gd f gh g g ,\n NA -- TI -- VI -- TAS glo -- ri -- ósae
@@ -73,16 +76,70 @@ description: "# gly\n\nWriter-friendly Gregorian notation format compiling to ga
73
76
  g h h hiwji hg g ;\n ex sé -- mi -- ne A -- bra -- hae,\n \n gh~ g g g
74
77
  fe/fgf d d ;\n or -- tae de tri -- bu Ju -- da,\n \n df!gh g f hg~ hi h
75
78
  g ::\n cla -- ra ex stir -- pe Da -- vid.\n\nOther arrangements are also possible.
76
- Order of music and lyrics\nis actually ignored during processing.\n\n## Usage\n\nThis
77
- gem provides executable `gly`. Run `gly help` for full list\nof subcommands. The
78
- most important ones are:\n\n`gly gabc FILE1 ...`\n\nconverts given gly file(s) to
79
- one or more gabc files (one per score,\ni.e. one gly may spawn a bunch of gabcs).\n\n`gly
79
+ Order of music and lyrics\nis actually ignored during processing.\n\n## Installation\n\nInstall
80
+ Ruby (some 2.x version) runtime. Then install as any ruby gem:\n\n`gem install gly`\n\n##
81
+ Usage\n\nThis gem provides executable `gly`. Run `gly help` for full list\nof subcommands.
82
+ The most important ones are:\n\n`gly gabc FILE1 ...`\n\nconverts given gly file(s)
83
+ to one or more gabc files (one per score,\ni.e. one gly may spawn a bunch of gabcs).\n\n`gly
80
84
  preview FILE1 ...`\n\nAttempts to create a pdf document with all scores contained
81
- in each\ngly file. Expects gregorio and lualatex to be in PATH\nand gregoriotex
82
- to be installed and accessible by lualatex.\n\n## Tools\n\n[Emacs mode with syntax
85
+ in each\ngly file. Expects `gregorio` and `lualatex` to be in PATH\nand `gregoriotex`
86
+ to be installed and accessible by `lualatex`.\n\n## Tools\n\n[Emacs mode with syntax
83
87
  highlighting for gly][elisp]\n\n![Editing gly in emacs](/doc/img/gly_emacs_scr.png)\n\n##
84
- Run tests\n\nby executing `tests/run.rb`\n\n## License\n\nMIT\n\n[gregorio]: https://github.com/gregorio-project/gregorio\n[elisp]:
85
- /tree/master/elisp\n"
88
+ Syntax reference\n\nGly syntax is line-based.\nThe interpreter reads the input line
89
+ by line,\nand depending on context it interprets each line as\ne.g. music, lyrics
90
+ or header field.\n\nThe syntax is quite permissive, not requiring a lot of delimiters\nor
91
+ hints for the parser concerning what each line means.\nMostly the parser guesses
92
+ the meaning correctly.\nWhere not, meaning of each line can be stated explicitly.\n\n###
93
+ 1. Comments\n\nWhen a `%` sign is encountered, everything until the end of line\nis
94
+ considered a comment and not interpreted.\n(Comment syntax is the same as in gabc.)\n\nPlease
95
+ note, that when compiling to gabc, comments are dropped\nand don't appear in the
96
+ resulting gabc file.\n\n### 2. Whitespace\n\nEmpty lines are ignored.\n\n### 3.
97
+ Scores\n\nA new score begins at the beginning of a file or at a line containing\na
98
+ single keyword '\\score'.\n\nIt consists of\na header (optional, only permitted
99
+ at the beginning of a score)\nand music- and lyrics-lines.\nLines with music and
100
+ lyrics may appear in any order.\n\nScore ends with end of file or with explicit
101
+ beginning of a new score\nor another top-level element.\n\n#### 3.1 Score header\n\nScore
102
+ header consists of fields.\n\nEach header field is on it's own (one) line and consists
103
+ of\nidentifier, colon and value:\n\n`mode: 8`\n\nHeader field identifier may only
104
+ consist of alphanumeric characters,\nminus-sign and underscore. Value can contain
105
+ anything.\n\nScore header ends with first non-empty line identified by the parser\nas
106
+ music or lyrics.\n\nHeader field 'id' is special: if present, it is used as suffix\nof
107
+ the generated gabc file (instead of the default, which is\nnumeric position of the
108
+ score in the source document).\n\n#### 3.2 Lyrics\n\nSyntax of lyrics is inspired
109
+ by LilyPond.\nLyrics have to be manually syllabified. Default syllable delimiter\nis
110
+ double dash (minus) `--` with optional whitespace around.\n\n`cla -- ra ex stir
111
+ -- pe Da -- vid.`\n\nThe parser guesses meaning of the line by attempting to find\nsyllable
112
+ separator in it and by looking if it's alphanumeric\ncharacters contains something
113
+ that cannot be interpreted as music.\nIf any of these conditions is met, the line
114
+ is interpreted as lyrics.\n\nIf gly fails to guess your lyrics line correctly and
115
+ interprets\nit as music, place `\\lyrics` or short `\\l` at the beginning\nof the
116
+ unhappy line:\n\n`\\l a a a`\n\n#### 3.3 Music\n\nAny line appearing in a score
117
+ and not identified as header field\nor lyrics is music by default.\n\nMusic line
118
+ contains one or more music chunks separated by whitespace.\nFor music syntax see
119
+ [official gabc documentation][gabc] -\ngly doesn't change anything in this respect.\n\nMusic
120
+ chunks may be enclosed in parentheses as in gabc.\n(Of course you don't like the
121
+ parentheses and are happy that gly\nlet's you leave them out. But in some special
122
+ cases they come handy.)\n\n#### 3.4 Matching lyrics to music\n\nWhen processing
123
+ the gly source and producing gabc, music chunks\nare matched to lyric syllables.\n\nThere
124
+ are, however, a few special cases, to make it work conveniently:\n\nThese special
125
+ cases of music chunks don't get lyric syllable:\n\n* clef\n* music chunk containing
126
+ only a division - i.e. music chunk containing\n one of `,` , `;` , `:` , `::` alone\n\nException
127
+ to this rule are 'nonlyrical lyrics chunks'.\nCurrently there is only one built-in
128
+ nonlyrical lyric chunk:\nasterisk `*`.\nNormally it is treated as any other syllable,\nbut
129
+ if it meets a division, it is set as it's lyrics, while\na normal syllable wouldn't
130
+ be.\n\nIf you need to set some other syllable under a division,\nmake it 'nonlyrical'
131
+ by placing\nan exclamation mark at it's beginning, e.g. `!<i>Ps.</i>`\n\nIn the
132
+ other direction it is sometimes necessary to set a syllable\nnot matching any music
133
+ at all. In such cases empty music chunk\n`()` is what you need.\n\n### 4. Document
134
+ header\n\nEach gly document may optinally contain a document header.\nIt may appear
135
+ anywhere in the document, but best practice is to place\nit at the very beginning.\n\nDocument
136
+ header starts with keyword `\\header` and ends\nat the end of file or at the beginning
137
+ of another top-level element.\nThe syntax of it's content is the same\nas for [Score
138
+ header][].\n\nField 'title' in the document header is, if present,\nused by `gly
139
+ preview` as title of the generated pdf.\n\n## Run tests\n\nby executing `tests/run.rb`\n\n##
140
+ License\n\nMIT\n\n[gregorio]: https://github.com/gregorio-project/gregorio\n[gabc]:
141
+ http://gregorio-project.github.io/gabc/index.html\n[elisp]: /tree/master/elisp\n\n[opraem_boh]:
142
+ https://gist.github.com/igneus/1aed0b36e9b23b51526d\n"
86
143
  email: jkb.pavlik@gmail.com
87
144
  executables:
88
145
  - gly
@@ -97,18 +154,26 @@ files:
97
154
  - lib/gly/cli.rb~
98
155
  - lib/gly/document.rb
99
156
  - lib/gly/document.rb~
157
+ - lib/gly/document_gabc_convertor.rb
158
+ - lib/gly/document_gabc_convertor.rb~
100
159
  - lib/gly/gabc_convertor.rb
101
160
  - lib/gly/gabc_convertor.rb~
102
161
  - lib/gly/headers.rb
103
162
  - lib/gly/headers.rb~
163
+ - lib/gly/lister.rb
164
+ - lib/gly/lister.rb~
104
165
  - lib/gly/lyrics.rb
105
166
  - lib/gly/lyrics.rb~
106
167
  - lib/gly/parsed_score.rb
107
168
  - lib/gly/parsed_score.rb~
108
169
  - lib/gly/parser.rb
109
170
  - lib/gly/parser.rb~
171
+ - lib/gly/preview_generator.rb
172
+ - lib/gly/preview_generator.rb~
110
173
  - lib/gly/string_helpers.rb
111
174
  - lib/gly/string_helpers.rb~
175
+ - lib/gly/templates/lualatex_document.tex
176
+ - lib/gly/templates/lualatex_document.tex~
112
177
  - tests/examples.rb
113
178
  - tests/examples.rb~
114
179
  - tests/examples/gly/expected/block_lyrics.gabc