From f45ff6ce8af9005e919ee4a57270686ea9137cde Mon Sep 17 00:00:00 2001 From: Daniel Senff Date: Tue, 4 Feb 2025 16:19:55 +0100 Subject: [PATCH 1/3] raise ruby version to 3.2 --- .ruby-version | 2 +- .travis.yml | 4 ++-- Gemfile | 5 +---- song_pro.gemspec | 8 ++++---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.ruby-version b/.ruby-version index 24ba9a3..351227f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.0 +3.2.4 diff --git a/.travis.yml b/.travis.yml index 19b74e0..27965c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false language: ruby rvm: - - 2.5.1 -before_install: gem install bundler -v 1.16.1 + - 3.2.4 +before_install: gem install bundler -v 2.6.2 diff --git a/Gemfile b/Gemfile index 6c88c31..be173b2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,5 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" -git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } - -# Specify your gem's dependencies in song_pro.gemspec gemspec diff --git a/song_pro.gemspec b/song_pro.gemspec index 009057f..219dd5f 100644 --- a/song_pro.gemspec +++ b/song_pro.gemspec @@ -32,8 +32,8 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'markaby' - spec.add_development_dependency 'bundler', '~> 1.16' - spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rubocop' + spec.add_development_dependency "bundler" + spec.add_development_dependency "rake" + spec.add_development_dependency "rspec" + spec.add_development_dependency "rubocop" end From 6b18bdae7724f9c7d9995956cc2e6d8d3f91af1f Mon Sep 17 00:00:00 2001 From: Daniel Senff Date: Tue, 4 Feb 2025 16:50:55 +0100 Subject: [PATCH 2/3] add github actions for linting and rspec --- .github/workflows/main.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..837d297 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,32 @@ +name: CI + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Install Ruby and gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: 3.2.4 + - name: Setup DB, Run tests + run: | + bundle exec rspec + + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Install Ruby and gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: 3.2.4 + - name: Standard Ruby + uses: standardrb/standard-ruby-action@v1 + \ No newline at end of file From 1ea755f7b4a6cf13f3f2ddd11c5771786d80cdee Mon Sep 17 00:00:00 2001 From: Daniel Senff Date: Tue, 4 Feb 2025 17:07:03 +0100 Subject: [PATCH 3/3] fix linting using standardrb --- Rakefile | 4 +- lib/chord_pro.rb | 195 ++++++++++++++++++++------------------- lib/chord_pro/section.rb | 2 +- lib/chord_pro/song.rb | 80 ++++++++-------- lib/chord_pro/version.rb | 2 +- song_pro.gemspec | 36 ++++---- spec/lib/line_spec.rb | 36 ++++---- spec/lib/song_spec.rb | 12 +-- spec/song_pro_spec.rb | 148 ++++++++++++++--------------- 9 files changed, 258 insertions(+), 257 deletions(-) diff --git a/Rakefile b/Rakefile index 82bb534..b6ae734 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'bundler/gem_tasks' -require 'rspec/core/rake_task' +require "bundler/gem_tasks" +require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) diff --git a/lib/chord_pro.rb b/lib/chord_pro.rb index e381cbe..14f6935 100644 --- a/lib/chord_pro.rb +++ b/lib/chord_pro.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'chord_pro/version' -require 'chord_pro/song' -require 'chord_pro/section' -require 'chord_pro/line' -require 'chord_pro/part' -require 'chord_pro/measure' +require "chord_pro/version" +require "chord_pro/song" +require "chord_pro/section" +require "chord_pro/line" +require "chord_pro/part" +require "chord_pro/measure" module ChordPro SECTION_REGEX = /\{(?:chorus|soc|sov|start_of_verse|start_of_chorus|sob|start_of_bridge|start_of_tab|sot|start_of_grid|sog):?\n?(.*)\}/m @@ -18,121 +18,122 @@ module ChordPro COMMENT_REGEX = /\{(?:c|comment|comment_italic|ci|comment_box|cb):([^$]*)\}/ SANITIZE_REGEX = /\{end_of_chorus|eoc|end_of_verse|eov|end_of_tab|eot|end_of_tab|eog|end_of_grid|colb\}/ - def self.parse(lines) - song = Song.new - current_section = nil - - lines.split("\n").each do |text| - if text.start_with?('{meta:') - process_custom_attribute(song, text) - elsif section_start?(text) - current_section = process_section(song, text) - elsif !comment_starts?(text) && attribute_start?(text) - process_attribute(song, text) - elsif text.match(SANITIZE_REGEX) - # ignore - else - process_lyrics_and_chords(song, current_section, text) + class << self + def parse(lines) + song = Song.new + current_section = nil + + lines.split("\n").each do |text| + if text.start_with?("{meta:") + process_custom_attribute(song, text) + elsif section_start?(text) + current_section = process_section(song, text) + elsif !comment_starts?(text) && attribute_start?(text) + process_attribute(song, text) + elsif text.match(SANITIZE_REGEX) + # ignore + else + process_lyrics_and_chords(song, current_section, text) + end end + + song end - song - end + def process_section(song, text) + matches = SECTION_REGEX.match(text) + name = (!matches[1].empty?) ? matches[1].strip : section_name_by_directive(text) - def self.process_section(song, text) - matches = SECTION_REGEX.match(text) - name = !matches[1].empty? ? matches[1].strip : section_name_by_directive(text) + current_section = Section.new(name: name) + song.sections << current_section - current_section = Section.new(name: name) - song.sections << current_section + current_section + end - current_section - end + def process_attribute(song, text) + matches = ATTRIBUTE_REGEX.match(text) + key = matches[1] + value = matches[2].strip + + if song.respond_to?(:"#{key}=") + song.send(:"#{key}=", value) + else + puts "WARNING: Unknown attribute '#{key}'" + end + end - def self.process_attribute(song, text) - matches = ATTRIBUTE_REGEX.match(text) - key = matches[1] - value = matches[2].strip + def process_custom_attribute(song, text) + matches = CUSTOM_ATTRIBUTE_REGEX.match(text) + key = matches[1] + value = matches[2].strip - if song.respond_to?("#{key}=".to_sym) - song.send("#{key}=", value) - else - puts "WARNING: Unknown attribute '#{key}'" + song.set_custom(key, value) end - end - def self.process_custom_attribute(song, text) - matches = CUSTOM_ATTRIBUTE_REGEX.match(text) - key = matches[1] - value = matches[2].strip + def process_lyrics_and_chords(song, current_section, text) + return if text == "" - song.set_custom(key, value) - end + if current_section.nil? + current_section = Section.new(name: "") + song.sections << current_section + end - def self.process_lyrics_and_chords(song, current_section, text) - return if text == '' + line = Line.new - if current_section.nil? - current_section = Section.new(name: '') - song.sections << current_section - end + if text.start_with?("|-") + line.tablature = text + elsif text.start_with?("| ") + captures = text.scan(MEASURES_REGEX).flatten - line = Line.new + measures = [] - if text.start_with?('|-') - line.tablature = text - elsif text.start_with?('| ') - captures = text.scan(MEASURES_REGEX).flatten + captures.each do |capture| + chords = capture.scan(CHORDS_REGEX).flatten + measure = Measure.new + measure.chords = chords + measures << measure + end - measures = [] + line.measures = measures + elsif comment_starts?(text) + matches = COMMENT_REGEX.match(text) + comment = matches[1].strip + line.comment = comment + else + captures = text.scan(CHORDS_AND_LYRICS_REGEX).flatten - captures.each do |capture| - chords = capture.scan(CHORDS_REGEX).flatten - measure = Measure.new - measure.chords = chords - measures << measure - end + captures.each_slice(2) do |pair| + part = Part.new + chord = pair[0]&.strip || "" + part.chord = chord.delete("[").delete("]") + part.lyric = pair[1] || "" - line.measures = measures - elsif comment_starts?(text) - matches = COMMENT_REGEX.match(text) - comment = matches[1].strip - line.comment = comment - else - captures = text.scan(CHORDS_AND_LYRICS_REGEX).flatten - - captures.each_slice(2) do |pair| - part = Part.new - chord = pair[0]&.strip || '' - part.chord = chord.delete('[').delete(']') - part.lyric = pair[1] || '' - - line.parts << part unless (part.chord == '') && (part.lyric == '') + line.parts << part unless (part.chord == "") && (part.lyric == "") + end end - end - current_section.lines << line unless line.empty? - end + current_section.lines << line unless line.empty? + end - private + private - def self.attribute_start?(text) - text.match(/\{(.+):(.*)\}/) - end + def attribute_start?(text) + text.match(/\{(.+):(.*)\}/) + end - def self.section_start?(text) - text.match(SECTION_REGEX) - end + def section_start?(text) + text.match(SECTION_REGEX) + end - def self.comment_starts?(text) - text.match(/\{(?:c|comment|comment_italic|ci|comment_box|cb):/) - end + def comment_starts?(text) + text.match(/\{(?:c|comment|comment_italic|ci|comment_box|cb):/) + end - def self.section_name_by_directive(text) - return 'Chorus' if text.match(/soc|start_of_chorus|chorus/) - return 'Verse' if text.match(/sov|start_of_verse/) - return 'Tab' if text.match(/sot|start_of_tab/) - return 'Grid' if text.match(/sot|start_of_grid/) + def section_name_by_directive(text) + return "Chorus" if /soc|start_of_chorus|chorus/.match?(text) + return "Verse" if /sov|start_of_verse/.match?(text) + return "Tab" if /sot|start_of_tab/.match?(text) + "Grid" if /sot|start_of_grid/.match?(text) + end end - end diff --git a/lib/chord_pro/section.rb b/lib/chord_pro/section.rb index 6844808..1700c5f 100644 --- a/lib/chord_pro/section.rb +++ b/lib/chord_pro/section.rb @@ -4,7 +4,7 @@ module ChordPro class Section attr_accessor :name, :lines - def initialize(name: '') + def initialize(name: "") @name = name @lines = [] end diff --git a/lib/chord_pro/song.rb b/lib/chord_pro/song.rb index bac72c5..e9cb9e3 100644 --- a/lib/chord_pro/song.rb +++ b/lib/chord_pro/song.rb @@ -1,20 +1,20 @@ # frozen_string_literal: true -require 'markaby' +require "markaby" module ChordPro class Song attr_accessor :title, - :artist, - :capo, - :key, - :tempo, - :year, - :copyright, - :album, - :tuning, - :sections, - :custom + :artist, + :capo, + :key, + :tempo, + :year, + :copyright, + :album, + :tuning, + :sections, + :custom def initialize @sections = [] @@ -45,27 +45,27 @@ def to_html dl.information do if song.tuning - dt.tuning 'Tuning' + dt.tuning "Tuning" dd.tuning song.tuning end if song.capo - dt.capo 'Capo' + dt.capo "Capo" dd.capo song.capo end if song.key - dt.key 'Key' + dt.key "Key" dd.key song.key end if song.tempo - dt.tempo 'Tempo' + dt.tempo "Tempo" dd.tempo song.tempo end if song.year - dt.year 'Year' + dt.year "Year" dd.year song.year end if song.album - dt.album 'Album' + dt.album "Album" dd.album song.album end end @@ -73,34 +73,36 @@ def to_html song.sections.each do |section| div.section do div.name section.name - div.lines do - section.lines.each do |line| - if line.tablature? - div.tablature do - line.tablature - end - elsif line.measures? - div.measures do - line.measures.each do |measure| - div.measure do - measure.chords.each do |chord| - div.chord chord + unless section.lines.empty? + div.lines do + section.lines.each do |line| + if line.tablature? + div.tablature do + line.tablature + end + elsif line.measures? + div.measures do + line.measures.each do |measure| + div.measure do + measure.chords.each do |chord| + div.chord chord + end end end end - end - else - div.line do - line.parts.each do |part| - div.part do - div.chord part.chord - div.lyric part.lyric + else + div.line do + line.parts.each do |part| + div.part do + div.chord part.chord + div.lyric part.lyric + end end end end end end - end unless section.lines.empty? + end end end end @@ -108,9 +110,7 @@ def to_html mab.to_s end - def comment=(value) - @comment = value - end + attr_writer :comment alias_method :ci=, :comment= alias_method :comment_italic=, :comment= diff --git a/lib/chord_pro/version.rb b/lib/chord_pro/version.rb index 1e0ff23..bde1509 100644 --- a/lib/chord_pro/version.rb +++ b/lib/chord_pro/version.rb @@ -1,3 +1,3 @@ module ChordPro - VERSION = '0.1.7'.freeze + VERSION = "0.1.8".freeze end diff --git a/song_pro.gemspec b/song_pro.gemspec index 219dd5f..ec59891 100644 --- a/song_pro.gemspec +++ b/song_pro.gemspec @@ -1,39 +1,39 @@ # frozen_string_literal: true -lib = File.expand_path('lib', __dir__) +lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'chord_pro/version' +require "chord_pro/version" Gem::Specification.new do |spec| - spec.name = 'chord_pro' - spec.version = ChordPro::VERSION - spec.authors = ['Daniel Senff', 'Brian Kelly'] - spec.email = ['mail@danielsenff.de'] + spec.name = "chord_pro" + spec.version = ChordPro::VERSION + spec.authors = ["Daniel Senff", "Brian Kelly"] + spec.email = ["mail@danielsenff.de"] - spec.summary = 'Converts ChordPro files to HTML' - spec.description = 'Provides classes for creating, parsing and rendering SongPro files' - spec.homepage = 'https://songpro.org' - spec.license = 'MIT' + spec.summary = "Converts ChordPro files to HTML" + spec.description = "Provides classes for creating, parsing and rendering SongPro files" + spec.homepage = "https://songpro.org" + spec.license = "MIT" # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' # to allow pushing to a single host or delete this section to allow pushing to any host. if spec.respond_to?(:metadata) - spec.metadata['allowed_push_host'] = 'https://rubygems.org' + spec.metadata["allowed_push_host"] = "https://rubygems.org" else - raise 'RubyGems 2.0 or newer is required to protect against ' \ - 'public gem pushes.' + raise "RubyGems 2.0 or newer is required to protect against " \ + "public gem pushes." end spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match(%r{^(test|spec|features)/}) end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ['lib'] + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] - spec.add_dependency 'markaby' + spec.add_dependency "markaby" spec.add_development_dependency "bundler" spec.add_development_dependency "rake" spec.add_development_dependency "rspec" - spec.add_development_dependency "rubocop" + spec.add_development_dependency "standard" end diff --git a/spec/lib/line_spec.rb b/spec/lib/line_spec.rb index 9422370..a8809a6 100644 --- a/spec/lib/line_spec.rb +++ b/spec/lib/line_spec.rb @@ -3,84 +3,84 @@ RSpec.describe ChordPro::Line do let(:line) { ChordPro::Line.new } - describe '#tablature?' do + describe "#tablature?" do subject { line.tablature? } - context 'tablature set' do - before { line.tablature = 'abc' } + context "tablature set" do + before { line.tablature = "abc" } it { is_expected.to be_truthy } end - context 'tablature not set' do + context "tablature not set" do it { is_expected.to be_falsey } end end - describe '#measures?' do + describe "#measures?" do subject { line.measures? } - context 'measures set' do + context "measures set" do before { line.measures = [double] } it { is_expected.to be_truthy } end - context 'measures not set' do + context "measures not set" do it { is_expected.to be_falsey } end end - describe '#comment?' do + describe "#comment?" do subject { line.comment? } - context 'comment set' do + context "comment set" do before { line.comment = double } it { is_expected.to be_truthy } end - context 'comment not set' do + context "comment not set" do it { is_expected.to be_falsey } end end - describe '#parts?' do + describe "#parts?" do subject { line.parts? } - context 'parts has values' do + context "parts has values" do before { line.parts = [double] } it { is_expected.to be_truthy } end - context 'parts not set' do + context "parts not set" do it { is_expected.to be_falsey } end end - describe '#empty?' do + describe "#empty?" do subject { line.empty? } - context 'has parts' do + context "has parts" do before { line.parts = [double] } it { is_expected.to be_falsey } end - context 'is tablature' do + context "is tablature" do before { line.tablature = double } it { is_expected.to be_falsey } end - context 'is comment' do + context "is comment" do before { line.comment = double } it { is_expected.to be_falsey } end - context 'is measures' do + context "is measures" do before { line.measures = [double] } it { is_expected.to be_falsey } diff --git a/spec/lib/song_spec.rb b/spec/lib/song_spec.rb index 4f30e7d..3bd24df 100644 --- a/spec/lib/song_spec.rb +++ b/spec/lib/song_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true RSpec.describe ChordPro::Song do - context '#chord' do - it 'returns all chords through the song' do + context "#chord" do + it "returns all chords through the song" do song = ChordPro.parse(' {soc} Some [D] chord [A] @@ -14,10 +14,10 @@ end end - context '#to_html' do - it 'generates divs' do - infile = File.read('spec/fixtures/bad-moon-rising.pro') - outfile = File.read('spec/fixtures/bad-moon-rising.html') + context "#to_html" do + it "generates divs" do + infile = File.read("spec/fixtures/bad-moon-rising.pro") + outfile = File.read("spec/fixtures/bad-moon-rising.html") song = ChordPro.parse(infile) html = song.to_html + "\n" diff --git a/spec/song_pro_spec.rb b/spec/song_pro_spec.rb index b0948bf..372e320 100644 --- a/spec/song_pro_spec.rb +++ b/spec/song_pro_spec.rb @@ -1,20 +1,20 @@ # frozen_string_literal: true RSpec.describe ChordPro do - context 'custom attributes' do - it 'parses custom attributes' do + context "custom attributes" do + it "parses custom attributes" do song = ChordPro.parse(' {meta: difficulty Easy} {meta: spotify_url https://open.spotify.com/track/5zADxJhJEzuOstzcUtXlXv?si=SN6U1oveQ7KNfhtD2NHf9A} ') - expect(song.custom[:difficulty]).to eq('Easy') - expect(song.custom[:spotify_url]).to eq('https://open.spotify.com/track/5zADxJhJEzuOstzcUtXlXv?si=SN6U1oveQ7KNfhtD2NHf9A') + expect(song.custom[:difficulty]).to eq("Easy") + expect(song.custom[:spotify_url]).to eq("https://open.spotify.com/track/5zADxJhJEzuOstzcUtXlXv?si=SN6U1oveQ7KNfhtD2NHf9A") end end - context 'attributes' do - it 'parses attributes' do + context "attributes" do + it "parses attributes" do song = ChordPro.parse(' {title:Bad Moon Rising} {artist:Creedence Clearwater Revival} @@ -27,26 +27,26 @@ {tuning:Eb Standard} ') - expect(song.title).to eq('Bad Moon Rising') - expect(song.artist).to eq('Creedence Clearwater Revival') - expect(song.capo).to eq('1st Fret') - expect(song.key).to eq('C# Minor') - expect(song.tempo).to eq('120') - expect(song.year).to eq('1975') - expect(song.album).to eq('Foo Bar Baz') - expect(song.tuning).to eq('Eb Standard') + expect(song.title).to eq("Bad Moon Rising") + expect(song.artist).to eq("Creedence Clearwater Revival") + expect(song.capo).to eq("1st Fret") + expect(song.key).to eq("C# Minor") + expect(song.tempo).to eq("120") + expect(song.year).to eq("1975") + expect(song.album).to eq("Foo Bar Baz") + expect(song.tuning).to eq("Eb Standard") end end - context 'sections' do - it 'parses section names' do - song = ChordPro.parse('{start_of_verse: Verse 1}') + context "sections" do + it "parses section names" do + song = ChordPro.parse("{start_of_verse: Verse 1}") expect(song.sections.size).to eq 1 - expect(song.sections[0].name).to eq 'Verse 1' + expect(song.sections[0].name).to eq "Verse 1" end - it 'parses multiple section names' do + it "parses multiple section names" do song = ChordPro.parse(' {start_of_verse: Verse 1} {start_of_verse} @@ -56,17 +56,17 @@ {chorus:Final} ') expect(song.sections.size).to eq 6 - expect(song.sections[0].name).to eq 'Verse 1' - expect(song.sections[1].name).to eq 'Verse' - expect(song.sections[2].name).to eq 'Chorus 1' - expect(song.sections[3].name).to eq 'Chorus' - expect(song.sections[4].name).to eq 'Chorus' - expect(song.sections[5].name).to eq 'Final' + expect(song.sections[0].name).to eq "Verse 1" + expect(song.sections[1].name).to eq "Verse" + expect(song.sections[2].name).to eq "Chorus 1" + expect(song.sections[3].name).to eq "Chorus" + expect(song.sections[4].name).to eq "Chorus" + expect(song.sections[5].name).to eq "Final" end end - context 'lyrics' do - it 'parses lyrics' do + context "lyrics" do + it "parses lyrics" do song = ChordPro.parse("I don't see! a bad, moon a-rising. (a-rising)") expect(song.sections.size).to eq 1 @@ -75,83 +75,83 @@ expect(song.sections[0].lines[0].parts[0].lyric).to eq "I don't see! a bad, moon a-rising. (a-rising)" end - it 'handles parenthesis in lyics' do - song = ChordPro.parse('singing something (something else)') + it "handles parenthesis in lyics" do + song = ChordPro.parse("singing something (something else)") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 1 expect(song.sections[0].lines[0].parts[0].lyric) - .to eq 'singing something (something else)' + .to eq "singing something (something else)" end - it 'handles special characters' do - song = ChordPro.parse('singing sömething with Röck dots') + it "handles special characters" do + song = ChordPro.parse("singing sömething with Röck dots") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 1 expect(song.sections[0].lines[0].parts[0].lyric) - .to eq 'singing sömething with Röck dots' + .to eq "singing sömething with Röck dots" end end - context 'chords' do - it 'parses chords' do - song = ChordPro.parse('[D] [D/F#] [C] [A7]') + context "chords" do + it "parses chords" do + song = ChordPro.parse("[D] [D/F#] [C] [A7]") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 4 - expect(song.sections[0].lines[0].parts[0].chord).to eq 'D' - expect(song.sections[0].lines[0].parts[0].lyric).to eq ' ' - expect(song.sections[0].lines[0].parts[1].chord).to eq 'D/F#' - expect(song.sections[0].lines[0].parts[1].lyric).to eq ' ' - expect(song.sections[0].lines[0].parts[2].chord).to eq 'C' - expect(song.sections[0].lines[0].parts[2].lyric).to eq ' ' - expect(song.sections[0].lines[0].parts[3].chord).to eq 'A7' - expect(song.sections[0].lines[0].parts[3].lyric).to eq '' + expect(song.sections[0].lines[0].parts[0].chord).to eq "D" + expect(song.sections[0].lines[0].parts[0].lyric).to eq " " + expect(song.sections[0].lines[0].parts[1].chord).to eq "D/F#" + expect(song.sections[0].lines[0].parts[1].lyric).to eq " " + expect(song.sections[0].lines[0].parts[2].chord).to eq "C" + expect(song.sections[0].lines[0].parts[2].lyric).to eq " " + expect(song.sections[0].lines[0].parts[3].chord).to eq "A7" + expect(song.sections[0].lines[0].parts[3].lyric).to eq "" end end - context 'chords and lyrics' do - it 'parses chords and lyrics' do + context "chords and lyrics" do + it "parses chords and lyrics" do song = ChordPro.parse("[G]Don't go 'round tonight") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 1 - expect(song.sections[0].lines[0].parts[0].chord).to eq 'G' + expect(song.sections[0].lines[0].parts[0].chord).to eq "G" expect(song.sections[0].lines[0].parts[0].lyric) .to eq "Don't go 'round tonight" end - it 'parses lyrics before chords' do + it "parses lyrics before chords" do song = ChordPro.parse("It's [D]bound to take your life") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 2 - expect(song.sections[0].lines[0].parts[0].chord).to eq '' + expect(song.sections[0].lines[0].parts[0].chord).to eq "" expect(song.sections[0].lines[0].parts[0].lyric).to eq "It's " - expect(song.sections[0].lines[0].parts[1].chord).to eq 'D' + expect(song.sections[0].lines[0].parts[1].chord).to eq "D" expect(song.sections[0].lines[0].parts[1].lyric) - .to eq 'bound to take your life' + .to eq "bound to take your life" end - it 'parses lyrics before chords' do + it "parses lyrics before chords" do song = ChordPro.parse("It's a[D]bout a [E]boy") expect(song.sections.size).to eq 1 expect(song.sections[0].lines.size).to eq 1 expect(song.sections[0].lines[0].parts.size).to eq 3 - expect(song.sections[0].lines[0].parts[0].chord).to eq '' + expect(song.sections[0].lines[0].parts[0].chord).to eq "" expect(song.sections[0].lines[0].parts[0].lyric).to eq "It's a" - expect(song.sections[0].lines[0].parts[1].chord).to eq 'D' - expect(song.sections[0].lines[0].parts[1].lyric).to eq 'bout a ' - expect(song.sections[0].lines[0].parts[2].chord).to eq 'E' - expect(song.sections[0].lines[0].parts[2].lyric).to eq 'boy' + expect(song.sections[0].lines[0].parts[1].chord).to eq "D" + expect(song.sections[0].lines[0].parts[1].lyric).to eq "bout a " + expect(song.sections[0].lines[0].parts[2].chord).to eq "E" + expect(song.sections[0].lines[0].parts[2].lyric).to eq "boy" end end - context 'measures' do - it 'parses chord-only measures' do + context "measures" do + it "parses chord-only measures" do song = ChordPro.parse(' | [A] [B] | [C] | [D] [E] [F] [G] | ') @@ -165,8 +165,8 @@ end end - context 'tablature' do - it 'parses tablature' do + context "tablature" do + it "parses tablature" do song = ChordPro.parse(' {start_of_tab} |-3---5-| @@ -175,14 +175,14 @@ ') expect(song.sections.size).to eq 1 expect(song.sections[0].lines[0].tablature?).to eq true - expect(song.sections[0].lines[0].tablature).to eq '|-3---5-|' + expect(song.sections[0].lines[0].tablature).to eq "|-3---5-|" expect(song.sections[0].lines[1].tablature?).to eq true - expect(song.sections[0].lines[1].tablature).to eq '|---4---|' + expect(song.sections[0].lines[1].tablature).to eq "|---4---|" end end - context 'comments' do - it 'parses comments' do + context "comments" do + it "parses comments" do song = ChordPro.parse(' {c:This is a comment.} {comment:This is a comment.} @@ -197,21 +197,21 @@ expect(song.sections.size).to eq 6 expect(song.sections[0].lines[0].comment?).to eq true - expect(song.sections[0].lines[0].comment).to eq 'This is a comment.' + expect(song.sections[0].lines[0].comment).to eq "This is a comment." end end - context 'full song' do - it 'parses the whole song' do - bmr = File.read('spec/fixtures/bad-moon-rising.pro') + context "full song" do + it "parses the whole song" do + bmr = File.read("spec/fixtures/bad-moon-rising.pro") song = ChordPro.parse(bmr) - expect(song.title).to eq 'Bad Moon Rising' - expect(song.artist).to eq 'Creedence Clearwater Revival' - expect(song.capo).to eq '1' + expect(song.title).to eq "Bad Moon Rising" + expect(song.artist).to eq "Creedence Clearwater Revival" + expect(song.capo).to eq "1" expect(song.sections.size).to eq 9 - expect(song.custom[:difficulty]).to eq 'Easy' + expect(song.custom[:difficulty]).to eq "Easy" expect(song.custom[:spotify_url]) - .to eq 'https://open.spotify.com/track/20OFwXhEXf12DzwXmaV7fj?si=cE76lY5TT26fyoNmXEjNpA' + .to eq "https://open.spotify.com/track/20OFwXhEXf12DzwXmaV7fj?si=cE76lY5TT26fyoNmXEjNpA" end end end