chordpro 0.0.1 → 1.0.0
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 +5 -5
 - data/Gemfile +3 -2
 - data/Guardfile +3 -3
 - data/README.md +32 -2
 - data/Rakefile +2 -2
 - data/chordpro.gemspec +17 -17
 - data/lib/chordpro/chord.rb +27 -0
 - data/lib/chordpro/directive.rb +37 -0
 - data/lib/chordpro/html.rb +36 -34
 - data/lib/chordpro/line.rb +18 -0
 - data/lib/chordpro/linebreak.rb +11 -0
 - data/lib/chordpro/lyric.rb +11 -0
 - data/lib/chordpro/metadata.rb +29 -0
 - data/lib/chordpro/parser.rb +14 -13
 - data/lib/chordpro/setup.rb +63 -0
 - data/lib/chordpro/song.rb +26 -0
 - data/lib/chordpro/transform.rb +17 -0
 - data/lib/chordpro/version.rb +1 -1
 - data/lib/chordpro.rb +17 -3
 - data/spec/chordpro/chord_spec.rb +37 -0
 - data/spec/chordpro/directive_spec.rb +53 -0
 - data/spec/chordpro/html_spec.rb +23 -6
 - data/spec/chordpro/line_spec.rb +17 -0
 - data/spec/chordpro/parser_spec.rb +61 -55
 - data/spec/chordpro/song_spec.rb +56 -0
 - data/spec/chordpro/transform_spec.rb +65 -0
 - data/spec/example_spec.rb +14 -9
 - data/spec/fixtures/sunshine.crd +1 -0
 - data/spec/fixtures/sunshine.html +1 -27
 - data/spec/spec_helper.rb +2 -1
 - metadata +52 -20
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: e3edc27bf8140ea8f823be328ea4bbb0445c8043bff80bb7a96282bc1620d6fc
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: c226e03871b162324c61f852b2b19b90abc7e238a2cb4e3bc8526d28b4388093
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 5411d453a8a82e400c4b89f4f5f5010d03cb921c426b52957c06d81c3e9bf6129e8f642483bb3274f921232f4cd516cc2d369640479599cea3280b142d5b22a8
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: aaa2e883a32b1942c000d2b8db0654a0078a5822ecdf592123566096bb100a67078ab74e71139dad48c6100909f5e43333562c121e1ba2144ca2f9fd1049d88d
         
     | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Guardfile
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            guard  
     | 
| 
      
 1 
     | 
    
         
            +
            guard "rspec", cmd: "bundle exec rspec" do
         
     | 
| 
       2 
2 
     | 
    
         
             
              watch(%r{^spec/.+_spec\.rb$})
         
     | 
| 
       3 
     | 
    
         
            -
              watch(%r{^spec/spec_helper.rb$}) 
     | 
| 
       4 
     | 
    
         
            -
              watch(%r{^lib/(.+)\.rb$}) 
     | 
| 
      
 3 
     | 
    
         
            +
              watch(%r{^spec/spec_helper.rb$}) { "spec" }
         
     | 
| 
      
 4 
     | 
    
         
            +
              watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
         
     | 
| 
       5 
5 
     | 
    
         
             
            end
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,6 +1,28 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Chordpro
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            A ruby parser for the [chordpro](http://tenbyten.com/software/songsgen/help/HtmlHelp/files_reference.htm) song file format.
         
     | 
| 
      
 3 
     | 
    
         
            +
            A ruby parser for the [chordpro](http://tenbyten.com/software/songsgen/help/HtmlHelp/files_reference.htm) song file format. It converts songs in the chordpro format like this…
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ```chordpro
         
     | 
| 
      
 6 
     | 
    
         
            +
            {title: You Are My Sunshine}
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            {c:Verse 1}
         
     | 
| 
      
 9 
     | 
    
         
            +
            [G]The other night dear as I lay sleeping
         
     | 
| 
      
 10 
     | 
    
         
            +
            [G7]I dreamed I [C]held you in my [G]arms
         
     | 
| 
      
 11 
     | 
    
         
            +
            [G7]But when I a[C]woke dear I was mis[G]taken
         
     | 
| 
      
 12 
     | 
    
         
            +
            So I hung my [D7]head and [G]cried
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            {c:Chorus}
         
     | 
| 
      
 15 
     | 
    
         
            +
            {soc}
         
     | 
| 
      
 16 
     | 
    
         
            +
            You are my sunshine my only sunshine
         
     | 
| 
      
 17 
     | 
    
         
            +
            [G7]You make me [C]happy when skies are [G]gray
         
     | 
| 
      
 18 
     | 
    
         
            +
            [G7]You'll never [C]know dear how much I [G]love you
         
     | 
| 
      
 19 
     | 
    
         
            +
            Please don't take [D7]my sunshine a[G]way
         
     | 
| 
      
 20 
     | 
    
         
            +
            {eoc}
         
     | 
| 
      
 21 
     | 
    
         
            +
            ```
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            …to HTML, which can be styled to look something like this…
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            
         
     | 
| 
       4 
26 
     | 
    
         | 
| 
       5 
27 
     | 
    
         
             
            ## Installation
         
     | 
| 
       6 
28 
     | 
    
         | 
| 
         @@ -19,7 +41,15 @@ Or install it yourself as: 
     | 
|
| 
       19 
41 
     | 
    
         
             
            ## Usage
         
     | 
| 
       20 
42 
     | 
    
         | 
| 
       21 
43 
     | 
    
         
             
            ```ruby
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
            contents = File.read('spec/fixtures/sunshine.crd')
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            # Generate HTML from the chordpro song
         
     | 
| 
      
 47 
     | 
    
         
            +
            File.write('sunshine.html', Chordpro.html(contents))
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            # Parse and inspect the chordpro song
         
     | 
| 
      
 50 
     | 
    
         
            +
            song = Chordpro.parse(contents)
         
     | 
| 
      
 51 
     | 
    
         
            +
            song.title # => "You Are My Sunshine"
         
     | 
| 
      
 52 
     | 
    
         
            +
            song.metadata.to_h # => {"title" => "You Are My Sunshine", "key" => "G"}
         
     | 
| 
       23 
53 
     | 
    
         
             
            ```
         
     | 
| 
       24 
54 
     | 
    
         | 
| 
       25 
55 
     | 
    
         
             
            ## Contributing
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "bundler/gem_tasks"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require  
     | 
| 
      
 3 
     | 
    
         
            +
            require "rspec/core/rake_task"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            desc "Run all specs"
         
     | 
| 
       6 
6 
     | 
    
         
             
            RSpec::Core::RakeTask.new(:spec) do |t|
         
     | 
| 
         @@ -8,4 +8,4 @@ RSpec::Core::RakeTask.new(:spec) do |t| 
     | 
|
| 
       8 
8 
     | 
    
         
             
              t.verbose = false
         
     | 
| 
       9 
9 
     | 
    
         
             
            end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
            task : 
     | 
| 
      
 11 
     | 
    
         
            +
            task default: :spec
         
     | 
    
        data/chordpro.gemspec
    CHANGED
    
    | 
         @@ -1,27 +1,27 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 1 
     | 
    
         
            +
            lib = File.expand_path("../lib", __FILE__)
         
     | 
| 
       3 
2 
     | 
    
         
             
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
       4 
     | 
    
         
            -
            require  
     | 
| 
      
 3 
     | 
    
         
            +
            require "chordpro/version"
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
5 
     | 
    
         
             
            Gem::Specification.new do |spec|
         
     | 
| 
       7 
     | 
    
         
            -
              spec.name 
     | 
| 
       8 
     | 
    
         
            -
              spec.version 
     | 
| 
       9 
     | 
    
         
            -
              spec.authors 
     | 
| 
       10 
     | 
    
         
            -
              spec.email 
     | 
| 
       11 
     | 
    
         
            -
              spec.summary 
     | 
| 
       12 
     | 
    
         
            -
              spec.description 
     | 
| 
       13 
     | 
    
         
            -
              spec.homepage 
     | 
| 
       14 
     | 
    
         
            -
              spec.license 
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name = "chordpro"
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version = Chordpro::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors = ["Brandon Keepers"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email = ["brandon@opensoul.org"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.summary = "A ruby parser for the chordpro song file format."
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.description = "A ruby parser for the chordpro song file format."
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.homepage = "https://github.com/bkeepers/chordpro"
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.license = "MIT"
         
     | 
| 
       15 
14 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
              spec.files 
     | 
| 
       17 
     | 
    
         
            -
              spec.executables 
     | 
| 
       18 
     | 
    
         
            -
              spec.test_files 
     | 
| 
      
 15 
     | 
    
         
            +
              spec.files = `git ls-files`.split($/)
         
     | 
| 
      
 16 
     | 
    
         
            +
              spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
       19 
18 
     | 
    
         
             
              spec.require_paths = ["lib"]
         
     | 
| 
       20 
19 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
              spec.add_dependency  
     | 
| 
      
 20 
     | 
    
         
            +
              spec.add_dependency "parslet"
         
     | 
| 
      
 21 
     | 
    
         
            +
              spec.add_dependency "builder"
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              spec.add_development_dependency "bundler"
         
     | 
| 
       24 
24 
     | 
    
         
             
              spec.add_development_dependency "rake"
         
     | 
| 
       25 
     | 
    
         
            -
              spec.add_development_dependency  
     | 
| 
       26 
     | 
    
         
            -
              spec.add_development_dependency  
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_development_dependency "rspec"
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.add_development_dependency "guard-rspec"
         
     | 
| 
       27 
27 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Chord < Struct.new(:name)
         
     | 
| 
      
 3 
     | 
    
         
            +
                SUBSTITUTIONS = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                  "b" => "♭",
         
     | 
| 
      
 5 
     | 
    
         
            +
                  "#" => "♯",
         
     | 
| 
      
 6 
     | 
    
         
            +
                  "aug" => "+",
         
     | 
| 
      
 7 
     | 
    
         
            +
                  "dim" => "°",
         
     | 
| 
      
 8 
     | 
    
         
            +
                  "2" => "²",
         
     | 
| 
      
 9 
     | 
    
         
            +
                  "4" => "⁴",
         
     | 
| 
      
 10 
     | 
    
         
            +
                  "5" => "⁵",
         
     | 
| 
      
 11 
     | 
    
         
            +
                  "6" => "⁶",
         
     | 
| 
      
 12 
     | 
    
         
            +
                  "7" => "⁷",
         
     | 
| 
      
 13 
     | 
    
         
            +
                  "9" => "⁹",
         
     | 
| 
      
 14 
     | 
    
         
            +
                  "sus" => "ˢᵘˢ"
         
     | 
| 
      
 15 
     | 
    
         
            +
                }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                REGEX = /(#{SUBSTITUTIONS.keys.join('|')})/
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 20 
     | 
    
         
            +
                  name.gsub(REGEX) { |match| SUBSTITUTIONS[match] }
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def accept(visitor)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  visitor.respond_to?(:chord) ? visitor.chord(self) : self
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Directive < Struct.new(:name, :value)
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Name
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :aka, :meta
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(name, aka: nil, meta: false)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @name, @aka, @meta = name, aka, meta
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @name
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def ==(other)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    to_s == other.to_s || (aka && aka == other.to_s)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                BY_NAME = {}
         
     | 
| 
      
 20 
     | 
    
         
            +
                BY_ALIAS = {}
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def self.register(name, **options)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  directive = Name.new(name, **options)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  BY_NAME[directive.to_s] = directive
         
     | 
| 
      
 26 
     | 
    
         
            +
                  BY_ALIAS[directive.aka] = directive if directive.aka
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def self.find(name)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  BY_NAME[name.to_s] || BY_ALIAS[name.to_s]
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def accept(visitor)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  visitor.respond_to?(name.to_s) ? visitor.send(name.to_s, value) : self
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/chordpro/html.rb
    CHANGED
    
    | 
         @@ -1,49 +1,41 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require  
     | 
| 
      
 1 
     | 
    
         
            +
            require "builder"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Chordpro
         
     | 
| 
       4 
4 
     | 
    
         
             
              class HTML
         
     | 
| 
       5 
     | 
    
         
            -
                def initialize( 
     | 
| 
       6 
     | 
    
         
            -
                  @song =  
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(song)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @song = song
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @html = Builder::XmlMarkup.new
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @song.accept(self)
         
     | 
| 
       7 
9 
     | 
    
         
             
                end
         
     | 
| 
       8 
10 
     | 
    
         | 
| 
       9 
11 
     | 
    
         
             
                def to_s
         
     | 
| 
       10 
     | 
    
         
            -
                  @ 
     | 
| 
      
 12 
     | 
    
         
            +
                  @html.target!
         
     | 
| 
       11 
13 
     | 
    
         
             
                end
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                def  
     | 
| 
       14 
     | 
    
         
            -
                   
     | 
| 
       15 
     | 
    
         
            -
                    send key, value
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
                end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                def directive(directive)
         
     | 
| 
       20 
     | 
    
         
            -
                  send directive[:name], directive if respond_to?(directive[:name])
         
     | 
| 
       21 
     | 
    
         
            -
                end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                def title(directive)
         
     | 
| 
       24 
     | 
    
         
            -
                  %Q|<h1 class="title">#{directive[:value]}</h1>|
         
     | 
| 
      
 15 
     | 
    
         
            +
                def title(title)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @html.h1(class: "title") { |h1| h1.text! title }
         
     | 
| 
       25 
17 
     | 
    
         
             
                end
         
     | 
| 
       26 
18 
     | 
    
         
             
                alias_method :t, :title
         
     | 
| 
       27 
19 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                def subtitle( 
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
      
 20 
     | 
    
         
            +
                def subtitle(subtitle)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @html.h2(class: "subtitle") { |h2| h2.text! subtitle }
         
     | 
| 
       30 
22 
     | 
    
         
             
                end
         
     | 
| 
       31 
23 
     | 
    
         
             
                alias_method :st, :subtitle
         
     | 
| 
       32 
24 
     | 
    
         
             
                alias_method :su, :subtitle
         
     | 
| 
       33 
25 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                def line(line)
         
     | 
| 
      
 26 
     | 
    
         
            +
                def line(line, parts)
         
     | 
| 
       35 
27 
     | 
    
         
             
                  chords = []
         
     | 
| 
       36 
28 
     | 
    
         
             
                  lyrics = []
         
     | 
| 
       37 
29 
     | 
    
         | 
| 
       38 
30 
     | 
    
         
             
                  line.each do |element|
         
     | 
| 
       39 
     | 
    
         
            -
                    if  
     | 
| 
       40 
     | 
    
         
            -
                      lyrics <<  
     | 
| 
       41 
     | 
    
         
            -
                    elsif  
     | 
| 
      
 31 
     | 
    
         
            +
                    if element.is_a?(Lyric)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      lyrics << element
         
     | 
| 
      
 33 
     | 
    
         
            +
                    elsif element.is_a?(Chord)
         
     | 
| 
       42 
34 
     | 
    
         
             
                      if chords[lyrics.size]
         
     | 
| 
       43 
     | 
    
         
            -
                         
     | 
| 
      
 35 
     | 
    
         
            +
                        chords << element
         
     | 
| 
       44 
36 
     | 
    
         
             
                        lyrics << nil
         
     | 
| 
       45 
37 
     | 
    
         
             
                      else
         
     | 
| 
       46 
     | 
    
         
            -
                        chords[lyrics.size] =  
     | 
| 
      
 38 
     | 
    
         
            +
                        chords[lyrics.size] = element
         
     | 
| 
       47 
39 
     | 
    
         
             
                      end
         
     | 
| 
       48 
40 
     | 
    
         
             
                    end
         
     | 
| 
       49 
41 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -51,21 +43,31 @@ module Chordpro 
     | 
|
| 
       51 
43 
     | 
    
         
             
                  # ensure chords has same number of cells as lyrics
         
     | 
| 
       52 
44 
     | 
    
         
             
                  chords[lyrics.size - 1] ||= nil if lyrics.size > 0
         
     | 
| 
       53 
45 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
                   
     | 
| 
       55 
     | 
    
         
            -
                    chords. 
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
      
 46 
     | 
    
         
            +
                  @html.table do |table|
         
     | 
| 
      
 47 
     | 
    
         
            +
                    if chords.any?
         
     | 
| 
      
 48 
     | 
    
         
            +
                      table.tr(class: "chords") do |tr|
         
     | 
| 
      
 49 
     | 
    
         
            +
                        chords.each do |chord|
         
     | 
| 
      
 50 
     | 
    
         
            +
                          tr.td { |td| td.text! chord.to_s }
         
     | 
| 
      
 51 
     | 
    
         
            +
                        end
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                    if lyrics.any?
         
     | 
| 
      
 55 
     | 
    
         
            +
                      table.tr do |tr|
         
     | 
| 
      
 56 
     | 
    
         
            +
                        lyrics.each do |lyric|
         
     | 
| 
      
 57 
     | 
    
         
            +
                          tr.td { |td| td.text! lyric.to_s }
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
       59 
62 
     | 
    
         
             
                end
         
     | 
| 
       60 
63 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
                def  
     | 
| 
       62 
     | 
    
         
            -
                   
     | 
| 
      
 64 
     | 
    
         
            +
                def linebreak(_)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @html.br
         
     | 
| 
       63 
66 
     | 
    
         
             
                end
         
     | 
| 
       64 
67 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                def comment( 
     | 
| 
       66 
     | 
    
         
            -
                   
     | 
| 
      
 68 
     | 
    
         
            +
                def comment(text)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @html.span(text, class: "comment")
         
     | 
| 
       67 
70 
     | 
    
         
             
                end
         
     | 
| 
       68 
71 
     | 
    
         
             
                alias_method :c, :comment
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
72 
     | 
    
         
             
              end
         
     | 
| 
       71 
73 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Line < Struct.new(:parts)
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def each(&block)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  parts.each(&block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def accept(visitor)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  parts = map { |part| part.accept(visitor) }
         
     | 
| 
      
 11 
     | 
    
         
            +
                  if visitor.respond_to?(:line)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    visitor.line(self, parts)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  else
         
     | 
| 
      
 14 
     | 
    
         
            +
                    Line.new(parts)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Metadata
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(elements)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @elements = elements
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def directives
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @elements.lazy.select { |e| e.is_a?(Directive) && e.name.meta }
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def each(&block)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  directives.each(&block)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def [](key)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  values = select { |directive| directive.name == key }.map(&:value)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  values.length > 1 ? values : values[0]
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def to_h
         
     | 
| 
      
 23 
     | 
    
         
            +
                  each_with_object({}) do |d, h|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    key = d.name.to_s
         
     | 
| 
      
 25 
     | 
    
         
            +
                    h[key] = h.has_key?(key) ? Array(h[key]).push(d.value) : d.value
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/chordpro/parser.rb
    CHANGED
    
    | 
         @@ -1,26 +1,27 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require  
     | 
| 
      
 1 
     | 
    
         
            +
            require "parslet"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Chordpro
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Parser < Parslet::Parser
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Characters
         
     | 
| 
       6 
     | 
    
         
            -
                rule(:space) 
     | 
| 
       7 
     | 
    
         
            -
                rule(:colon) 
     | 
| 
       8 
     | 
    
         
            -
                rule(:newline) 
     | 
| 
       9 
     | 
    
         
            -
                rule(:lbrace) 
     | 
| 
       10 
     | 
    
         
            -
                rule(:rbrace) 
     | 
| 
       11 
     | 
    
         
            -
                rule(:lbracket) { str( 
     | 
| 
       12 
     | 
    
         
            -
                rule(:rbracket) { str( 
     | 
| 
      
 6 
     | 
    
         
            +
                rule(:space) { match('\s').repeat }
         
     | 
| 
      
 7 
     | 
    
         
            +
                rule(:colon) { space >> str(":") >> space }
         
     | 
| 
      
 8 
     | 
    
         
            +
                rule(:newline) { str("\n") }
         
     | 
| 
      
 9 
     | 
    
         
            +
                rule(:lbrace) { str("{") }
         
     | 
| 
      
 10 
     | 
    
         
            +
                rule(:rbrace) { str("}") }
         
     | 
| 
      
 11 
     | 
    
         
            +
                rule(:lbracket) { str("[") }
         
     | 
| 
      
 12 
     | 
    
         
            +
                rule(:rbracket) { str("]") }
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                rule(:identifier) { match['a-z'].repeat(1) }
         
     | 
| 
      
 14 
     | 
    
         
            +
                rule(:identifier) { match["a-z"].repeat(1) }
         
     | 
| 
       16 
15 
     | 
    
         
             
                rule(:value) { (rbrace.absent? >> any).repeat }
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
                rule(:comment) { str("#") >> (newline.absent? >> any).repeat >> newline.maybe }
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       18 
19 
     | 
    
         
             
                rule(:directive) do
         
     | 
| 
       19 
20 
     | 
    
         
             
                  (
         
     | 
| 
       20 
21 
     | 
    
         
             
                    lbrace >> space >>
         
     | 
| 
       21 
22 
     | 
    
         
             
                    identifier.as(:name) >>
         
     | 
| 
       22 
23 
     | 
    
         
             
                    (
         
     | 
| 
       23 
     | 
    
         
            -
                       
     | 
| 
      
 24 
     | 
    
         
            +
                      colon >>
         
     | 
| 
       24 
25 
     | 
    
         
             
                      value.as(:value)
         
     | 
| 
       25 
26 
     | 
    
         
             
                    ).maybe >>
         
     | 
| 
       26 
27 
     | 
    
         
             
                    rbrace
         
     | 
| 
         @@ -28,9 +29,9 @@ module Chordpro 
     | 
|
| 
       28 
29 
     | 
    
         
             
                end
         
     | 
| 
       29 
30 
     | 
    
         
             
                rule(:chord) { lbracket >> (rbracket.absent? >> any).repeat.as(:chord) >> rbracket }
         
     | 
| 
       30 
31 
     | 
    
         
             
                rule(:lyric) { (lbracket.absent? >> newline.absent? >> any).repeat(1).as(:lyric) }
         
     | 
| 
       31 
     | 
    
         
            -
                rule(:line) 
     | 
| 
      
 32 
     | 
    
         
            +
                rule(:line) { (chord | lyric).repeat(1).as(:line) >> newline.maybe }
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                rule(:song) 
     | 
| 
      
 34 
     | 
    
         
            +
                rule(:song) { (comment | directive | newline.as(:linebreak) | line).repeat.as(:song) }
         
     | 
| 
       34 
35 
     | 
    
         | 
| 
       35 
36 
     | 
    
         
             
                root(:song)
         
     | 
| 
       36 
37 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Register documented directives
         
     | 
| 
      
 2 
     | 
    
         
            +
            # https://www.chordpro.org/chordpro/chordpro-directives/
         
     | 
| 
      
 3 
     | 
    
         
            +
            Chordpro::Directive.class_eval do
         
     | 
| 
      
 4 
     | 
    
         
            +
              # preamble
         
     | 
| 
      
 5 
     | 
    
         
            +
              register "new_song", aka: "ns"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # metadata
         
     | 
| 
      
 8 
     | 
    
         
            +
              register "title", aka: "t", meta: true
         
     | 
| 
      
 9 
     | 
    
         
            +
              register "sorttitle", meta: true
         
     | 
| 
      
 10 
     | 
    
         
            +
              register "subtitle", aka: "st", meta: true
         
     | 
| 
      
 11 
     | 
    
         
            +
              register "artist", meta: true
         
     | 
| 
      
 12 
     | 
    
         
            +
              register "composer", meta: true
         
     | 
| 
      
 13 
     | 
    
         
            +
              register "lyricist", meta: true
         
     | 
| 
      
 14 
     | 
    
         
            +
              register "copyright", meta: true
         
     | 
| 
      
 15 
     | 
    
         
            +
              register "album", meta: true
         
     | 
| 
      
 16 
     | 
    
         
            +
              register "year", meta: true
         
     | 
| 
      
 17 
     | 
    
         
            +
              register "key", meta: true
         
     | 
| 
      
 18 
     | 
    
         
            +
              register "time", meta: true
         
     | 
| 
      
 19 
     | 
    
         
            +
              register "tempo", meta: true
         
     | 
| 
      
 20 
     | 
    
         
            +
              register "duration", meta: true
         
     | 
| 
      
 21 
     | 
    
         
            +
              register "capo", meta: true
         
     | 
| 
      
 22 
     | 
    
         
            +
              register "meta", meta: true
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              # Environment directives
         
     | 
| 
      
 25 
     | 
    
         
            +
              %w[chorus verse bridge tab grid].each do |directive|
         
     | 
| 
      
 26 
     | 
    
         
            +
                letter = directive[0]
         
     | 
| 
      
 27 
     | 
    
         
            +
                register "start_of_#{directive}", aka: "so#{letter}"
         
     | 
| 
      
 28 
     | 
    
         
            +
                register "end_of_#{directive}", aka: "eo#{letter}"
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              # Chord diagrams
         
     | 
| 
      
 32 
     | 
    
         
            +
              register "define"
         
     | 
| 
      
 33 
     | 
    
         
            +
              register "chord"
         
     | 
| 
      
 34 
     | 
    
         
            +
              register "transpose"
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              register "chordfont", aka: "cf"
         
     | 
| 
      
 37 
     | 
    
         
            +
              register "chordsize", aka: "cs"
         
     | 
| 
      
 38 
     | 
    
         
            +
              register "chordcolour"
         
     | 
| 
      
 39 
     | 
    
         
            +
              register "footerfont"
         
     | 
| 
      
 40 
     | 
    
         
            +
              register "footersize"
         
     | 
| 
      
 41 
     | 
    
         
            +
              register "footercolour"
         
     | 
| 
      
 42 
     | 
    
         
            +
              register "gridfont"
         
     | 
| 
      
 43 
     | 
    
         
            +
              register "gridsize"
         
     | 
| 
      
 44 
     | 
    
         
            +
              register "gridcolour"
         
     | 
| 
      
 45 
     | 
    
         
            +
              register "tabfont"
         
     | 
| 
      
 46 
     | 
    
         
            +
              register "tabsize"
         
     | 
| 
      
 47 
     | 
    
         
            +
              register "tabcolour"
         
     | 
| 
      
 48 
     | 
    
         
            +
              register "tocfont"
         
     | 
| 
      
 49 
     | 
    
         
            +
              register "tocsize"
         
     | 
| 
      
 50 
     | 
    
         
            +
              register "toccolour"
         
     | 
| 
      
 51 
     | 
    
         
            +
              register "textfont", aka: "tf"
         
     | 
| 
      
 52 
     | 
    
         
            +
              register "textsize", aka: "ts"
         
     | 
| 
      
 53 
     | 
    
         
            +
              register "textcolour"
         
     | 
| 
      
 54 
     | 
    
         
            +
              register "titlefont"
         
     | 
| 
      
 55 
     | 
    
         
            +
              register "titlesize"
         
     | 
| 
      
 56 
     | 
    
         
            +
              register "titlecolour"
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              # Output related directives
         
     | 
| 
      
 59 
     | 
    
         
            +
              register "new_page", aka: "np"
         
     | 
| 
      
 60 
     | 
    
         
            +
              register "new_physical_page", aka: "npp"
         
     | 
| 
      
 61 
     | 
    
         
            +
              register "column_break", aka: "cb"
         
     | 
| 
      
 62 
     | 
    
         
            +
              register "pagetype"
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Song
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :elements, :metadata
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(elements = [])
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @elements = elements
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @metadata = Metadata.new(@elements)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def accept(visitor)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  elements.map { |element| element.accept(visitor) }
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def method_missing(method, *args)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if respond_to_missing?(method)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    metadata[method]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  else
         
     | 
| 
      
 18 
     | 
    
         
            +
                    super
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def respond_to_missing?(method, include_all = false)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  super || !!Directive.find(method)&.meta
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chordpro
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transform < Parslet::Transform
         
     | 
| 
      
 3 
     | 
    
         
            +
                rule(directive: {name: simple(:name), value: simple(:value)}) do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  directive_name = Directive.find(name) || Directive::Name.new(name.to_s)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  Chordpro::Directive.new(directive_name, value.to_s)
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
                rule(directive: {name: simple(:name)}) do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Chordpro::Directive.new(name.to_s)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                rule(linebreak: simple(:x)) { Chordpro::Linebreak.new }
         
     | 
| 
      
 12 
     | 
    
         
            +
                rule(chord: simple(:name)) { Chordpro::Chord.new(name.to_s) }
         
     | 
| 
      
 13 
     | 
    
         
            +
                rule(lyric: simple(:text)) { Chordpro::Lyric.new(text.to_s) }
         
     | 
| 
      
 14 
     | 
    
         
            +
                rule(line: subtree(:parts)) { Chordpro::Line.new(parts) }
         
     | 
| 
      
 15 
     | 
    
         
            +
                rule(song: subtree(:elements)) { Chordpro::Song.new(elements) }
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/chordpro/version.rb
    CHANGED
    
    
    
        data/lib/chordpro.rb
    CHANGED
    
    | 
         @@ -1,9 +1,23 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "chordpro/ 
     | 
| 
       2 
     | 
    
         
            -
            require "chordpro/ 
     | 
| 
      
 1 
     | 
    
         
            +
            require "chordpro/chord"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "chordpro/directive"
         
     | 
| 
       3 
3 
     | 
    
         
             
            require "chordpro/html"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "chordpro/line"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "chordpro/linebreak"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "chordpro/lyric"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "chordpro/metadata"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require "chordpro/parser"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "chordpro/song"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "chordpro/transform"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "chordpro/version"
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require "chordpro/setup"
         
     | 
| 
       4 
14 
     | 
    
         | 
| 
       5 
15 
     | 
    
         
             
            module Chordpro
         
     | 
| 
      
 16 
     | 
    
         
            +
              def self.parse(string)
         
     | 
| 
      
 17 
     | 
    
         
            +
                Transform.new.apply(Parser.new.parse(string))
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       6 
20 
     | 
    
         
             
              def self.html(string)
         
     | 
| 
       7 
     | 
    
         
            -
                HTML.new( 
     | 
| 
      
 21 
     | 
    
         
            +
                HTML.new(parse(string)).to_s
         
     | 
| 
       8 
22 
     | 
    
         
             
              end
         
     | 
| 
       9 
23 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec_helper"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Chordpro::Chord do
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe "to_s" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                {
         
     | 
| 
      
 6 
     | 
    
         
            +
                  "Bb" => "B♭",
         
     | 
| 
      
 7 
     | 
    
         
            +
                  "F#m" => "F♯m",
         
     | 
| 
      
 8 
     | 
    
         
            +
                  "Gaug7" => "G+⁷",
         
     | 
| 
      
 9 
     | 
    
         
            +
                  "Ddim7" => "D°⁷",
         
     | 
| 
      
 10 
     | 
    
         
            +
                  "Csus9" => "Cˢᵘˢ⁹",
         
     | 
| 
      
 11 
     | 
    
         
            +
                  "Asus2" => "Aˢᵘˢ²",
         
     | 
| 
      
 12 
     | 
    
         
            +
                  "Esus4" => "Eˢᵘˢ⁴",
         
     | 
| 
      
 13 
     | 
    
         
            +
                  "E5" => "E⁵",
         
     | 
| 
      
 14 
     | 
    
         
            +
                  "Cm6" => "Cm⁶",
         
     | 
| 
      
 15 
     | 
    
         
            +
                  "G7" => "G⁷",
         
     | 
| 
      
 16 
     | 
    
         
            +
                  "Asus9" => "Aˢᵘˢ⁹"
         
     | 
| 
      
 17 
     | 
    
         
            +
                }.each do |input, output|
         
     | 
| 
      
 18 
     | 
    
         
            +
                  it "replaces #{input.inspect} with #{output.inspect}" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                    expect(Chordpro::Chord.new(input).to_s).to eq(output)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              describe "accept" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                let(:chord) { Chordpro::Chord.new("C") }
         
     | 
| 
      
 26 
     | 
    
         
            +
                let(:visitor) { double(:visitor) }
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                it "calls chord with chord" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  expect(visitor).to receive(:chord).with(chord).and_return("result")
         
     | 
| 
      
 30 
     | 
    
         
            +
                  expect(chord.accept(visitor)).to eq("result")
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                it "does not blow up if object does not respond to chord" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  expect(chord.accept(visitor)).to be(chord)
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec_helper"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Chordpro::Directive do
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe "accept" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                let(:visitor) { double(:visitor) }
         
     | 
| 
      
 6 
     | 
    
         
            +
                let(:directive) { Chordpro::Directive.new("title", "The Visitor") }
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                it "calls method on visitor" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  expect(visitor).to receive(:title).and_return("title")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  expect(directive.accept(visitor)).to eq("title")
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                it "returns self when visitor does not respond to method" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  expect(directive.accept(visitor)).to be(directive)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            describe Chordpro::Directive::Name do
         
     | 
| 
      
 20 
     | 
    
         
            +
              describe "==" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                context "with alias" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  let(:name) { Chordpro::Directive::Name.new("title", aka: "t") }
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  it "equals string matching name" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                    expect(name).to eq("title")
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  it "equals symbol matching name" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    expect(name).to eq(:title)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  it "equals string matching alias" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                    expect(name).to eq("t")
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  it "equals symbol matching alias" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                    expect(name).to eq(:t)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  it "equals Name matching name" do
         
     | 
| 
      
 41 
     | 
    
         
            +
                    expect(name).to eq(described_class.new("title"))
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  it "does not equal other string" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    expect(name).not_to eq("nope")
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  it "does not equal other Name" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                    expect(name).not_to eq(described_class.new("comment"))
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     |