Class: HeadMusic::Notation::ABC::BookParser
- Inherits:
-
Object
- Object
- HeadMusic::Notation::ABC::BookParser
- Defined in:
- lib/head_music/notation/abc/book_parser.rb
Overview
Interprets an ABC tune book — one or more tunes separated by blank lines, each beginning with an X: field — as an array of compositions.
Parsing is all-or-nothing: any invalid tune raises, so callers never receive a partial array. Each tune is delegated to Parser with its book-relative start line, so errors point into the book.
Defined Under Namespace
Classes: Segment
Instance Method Summary collapse
-
#build_segment(lines, start_line) ⇒ Object
private
-
#compositions ⇒ Object
-
#ensure_input_present ⇒ Object
private
-
#ensure_tunes_found(segments) ⇒ Object
private
-
#initialize(book_string) ⇒ BookParser
constructor
A new instance of BookParser.
-
#parse_segments ⇒ Object
private
-
#split_into_segments ⇒ Object
private
Groups lines into blank-line-separated paragraphs, dropping paragraphs that contain only comments.
Constructor Details
#initialize(book_string) ⇒ BookParser
Returns a new instance of BookParser.
10 11 12 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 10 def initialize(book_string) @book_string = book_string.to_s end |
Instance Method Details
#build_segment(lines, start_line) ⇒ Object (private)
63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 63 def build_segment(lines, start_line) first_content_index = lines.find_index { |line| !line.strip.start_with?("%") } return nil unless first_content_index unless lines[first_content_index].strip.start_with?("X:") raise HeadMusic::Notation::ABC::ParseError.new( "Expected a tune to begin with an X: field", line_number: start_line + first_content_index, snippet: lines[first_content_index].strip[0, HeadMusic::Notation::ABC::BodyLexer::SNIPPET_LENGTH] ) end Segment.new(text: lines.join, start_line: start_line) end |
#compositions ⇒ Object
14 15 16 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 14 def compositions @compositions ||= parse_segments end |
#ensure_input_present ⇒ Object (private)
29 30 31 32 33 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 29 def ensure_input_present return unless @book_string.strip.empty? raise HeadMusic::Notation::ABC::ParseError, "ABC input is blank" end |
#ensure_tunes_found(segments) ⇒ Object (private)
35 36 37 38 39 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 35 def ensure_tunes_found(segments) return if segments.any? raise HeadMusic::Notation::ABC::ParseError, "No tunes found in ABC input" end |
#parse_segments ⇒ Object (private)
20 21 22 23 24 25 26 27 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 20 def parse_segments ensure_input_present segments = split_into_segments ensure_tunes_found(segments) segments.map do |segment| HeadMusic::Notation::ABC::Parser.new(segment.text, start_line: segment.start_line).composition end end |
#split_into_segments ⇒ Object (private)
Groups lines into blank-line-separated paragraphs, dropping paragraphs that contain only comments.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/head_music/notation/abc/book_parser.rb', line 43 def split_into_segments segments = [] current_lines = nil current_start = nil @book_string.lines.each_with_index do |line, index| if line.strip.empty? segments << build_segment(current_lines, current_start) if current_lines current_lines = nil next end if current_lines.nil? current_lines = [] current_start = index + 1 end current_lines << line end segments << build_segment(current_lines, current_start) if current_lines segments.compact end |