Module: Pericope::Parsing

Included in:
Pericope
Defined in:
lib/pericope/parsing.rb

Defined Under Namespace

Classes: ReferenceFragment

Instance Method Summary collapse

Instance Method Details

#coerce_to_range(number, range) ⇒ Object



165
166
167
168
169
# File 'lib/pericope/parsing.rb', line 165

def coerce_to_range(number, range)
  return range.begin if number < range.begin
  return range.end if number > range.end
  number
end

#match_all(text) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/pericope/parsing.rb', line 64

def match_all(text)
  text.scan(Pericope.regexp) do
    match = Regexp.last_match
    book = BOOK_IDS[match.captures.find_index(&:itself)]

    ranges = parse_reference(book, match[67])
    next if ranges.empty?

    attributes = {
      :original_string => match.to_s,
      :book => book,
      :ranges => ranges
    }

    yield attributes, match
  end
end

#match_one(text) ⇒ Object



57
58
59
60
61
62
# File 'lib/pericope/parsing.rb', line 57

def match_one(text)
  match_all(text) do |attributes|
    return attributes
  end
  nil
end

#normalize_reference(reference) ⇒ Object



86
87
88
# File 'lib/pericope/parsing.rb', line 86

def normalize_reference(reference)
  normalizations.reduce(reference.to_s) { |reference, (regex, replacement)| reference.gsub(regex, replacement) }
end

#parse(text) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/pericope/parsing.rb', line 16

def parse(text)
  pericopes = []
  match_all(text) do |attributes|
    pericope = Pericope.new(attributes)
    if block_given?
      yield pericope
    else
      pericopes << pericope
    end
  end
  block_given? ? text : pericopes
end

#parse_one(text) ⇒ Object

Differs from Pericope.new in that it won’t raise an exception if text does not contain a pericope but will return nil instead.



9
10
11
12
13
14
# File 'lib/pericope/parsing.rb', line 9

def parse_one(text)
  parse(text) do |pericope|
    return pericope
  end
  nil
end

#parse_ranges(book, ranges) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/pericope/parsing.rb', line 90

def parse_ranges(book, ranges)
  default_chapter = nil
  default_chapter = 1 unless book_has_chapters?(book)
  default_verse = nil

  ranges.map do |range|
    range_begin_string, range_end_string = range.split("-")

    # treat 12:4 as 12:4-12:4
    range_end_string ||= range_begin_string

    range_begin = parse_reference_fragment(range_begin_string, default_chapter: default_chapter, default_verse: default_verse)

    # no verse specified; this is a range of chapters, start with verse 1
    chapter_range = false
    if range_begin.needs_verse?
      range_begin.verse = 1
      chapter_range = true
    end

    range_begin.chapter = to_valid_chapter(book, range_begin.chapter)
    range_begin.verse = to_valid_verse(book, range_begin.chapter, range_begin.verse)

    if range_begin_string == range_end_string && !chapter_range
      range_end = range_begin.dup
    else
      range_end = parse_reference_fragment(range_end_string, default_chapter: (range_begin.chapter unless chapter_range))
      range_end.chapter = to_valid_chapter(book, range_end.chapter)

      # treat Mark 3-1 as Mark 3-3 and, eventually, Mark 3:1-35
      range_end.chapter = range_begin.chapter if range_end.chapter < range_begin.chapter

      # this is a range of chapters, end with the last verse
      if range_end.needs_verse?
        range_end.verse = get_max_verse(book, range_end.chapter)
      else
        range_end.verse = to_valid_verse(book, range_end.chapter, range_end.verse)
      end
    end

    # e.g. parsing 11 in 12:1-8,11 => remember that 12 is the chapter
    default_chapter = range_end.chapter

    # e.g. parsing c in 9:12a, c => remember that 12 is the verse
    default_verse = range_end.verse

    range = Range.new(range_begin.to_verse(book: book), range_end.to_verse(book: book))

    # an 'a' at the beginning of a range is redundant
    range.begin.letter = nil if range.begin.letter == "a" && range.end.to_i > range.begin.to_i

    # a 'c' at the end of a range is redundant
    range.end.letter = nil if range.end.letter == max_letter && range.end.to_i > range.begin.to_i

    range
  end
end

#parse_reference(book, reference) ⇒ Object



82
83
84
# File 'lib/pericope/parsing.rb', line 82

def parse_reference(book, reference)
  parse_ranges(book, normalize_reference(reference).split(/[,;]/))
end

#parse_reference_fragment(input, default_chapter: nil, default_verse: nil) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/pericope/parsing.rb', line 148

def parse_reference_fragment(input, default_chapter: nil, default_verse: nil)
  chapter, verse, letter = input.match(Pericope.fragment_regexp).captures
  chapter = default_chapter unless chapter
  chapter, verse = [verse, nil] unless chapter
  verse = default_verse unless verse
  letter = nil unless verse
  ReferenceFragment.new(chapter.to_i, verse&.to_i, letter)
end

#split(text) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/pericope/parsing.rb', line 29

def split(text)
  segments = []
  start = 0

  match_all(text) do |attributes, match|

    pretext = text.slice(start...match.begin(0))
    if pretext.length > 0
      segments << pretext
      yield pretext if block_given?
    end

    pericope = Pericope.new(attributes)
    segments << pericope
    yield pericope if block_given?

    start = match.end(0)
  end

  pretext = text.slice(start...text.length)
  if pretext.length > 0
    segments << pretext
    yield pretext if block_given?
  end

  segments
end

#to_valid_chapter(book, chapter) ⇒ Object



157
158
159
# File 'lib/pericope/parsing.rb', line 157

def to_valid_chapter(book, chapter)
  coerce_to_range(chapter, 1..get_max_chapter(book))
end

#to_valid_verse(book, chapter, verse) ⇒ Object



161
162
163
# File 'lib/pericope/parsing.rb', line 161

def to_valid_verse(book, chapter, verse)
  coerce_to_range(verse, 1..get_max_verse(book, chapter))
end