wcc-pericope 1.1.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 +7 -0
- data/README.mdown +70 -0
- data/bin/console +14 -0
- data/bin/pericope +9 -0
- data/data/chapter_verse_count.txt +1189 -0
- data/lib/cli/base.rb +18 -0
- data/lib/cli/command.rb +15 -0
- data/lib/pericope/cli.rb +87 -0
- data/lib/pericope/data.rb +4 -0
- data/lib/pericope/parsing.rb +289 -0
- data/lib/pericope/range.rb +58 -0
- data/lib/pericope/verse.rb +75 -0
- data/lib/pericope/version.rb +3 -0
- data/lib/pericope.rb +247 -0
- metadata +171 -0
data/lib/pericope.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
require "pericope/version"
|
2
|
+
require "pericope/data"
|
3
|
+
require "pericope/parsing"
|
4
|
+
|
5
|
+
class Pericope
|
6
|
+
extend Pericope::Parsing
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
attr_reader :book, :original_string, :ranges
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(arg)
|
13
|
+
case arg
|
14
|
+
when String
|
15
|
+
attributes = Pericope.match_one(arg)
|
16
|
+
raise ArgumentError, "no pericope found in #{arg}" if attributes.nil?
|
17
|
+
|
18
|
+
@original_string = attributes[:original_string]
|
19
|
+
@book = attributes[:book]
|
20
|
+
@ranges = attributes[:ranges]
|
21
|
+
|
22
|
+
when Array
|
23
|
+
@ranges = group_array_into_ranges(arg)
|
24
|
+
@book = @ranges.first.begin.book
|
25
|
+
|
26
|
+
else
|
27
|
+
@original_string = arg[:original_string]
|
28
|
+
@book = arg[:book]
|
29
|
+
@ranges = arg[:ranges]
|
30
|
+
|
31
|
+
end
|
32
|
+
raise ArgumentError, "must specify book" unless @book
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def book_has_chapters?
|
37
|
+
book_chapter_count > 1
|
38
|
+
end
|
39
|
+
|
40
|
+
def book_name
|
41
|
+
@book_name ||= Pericope::BOOK_NAMES[@book]
|
42
|
+
end
|
43
|
+
|
44
|
+
def book_chapter_count
|
45
|
+
@book_chapter_count ||= Pericope::BOOK_CHAPTER_COUNTS[@book]
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def to_s(options={})
|
50
|
+
["#{book_name}", well_formatted_reference(options)].compact.join(" ")
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
"Pericope(#{to_s})"
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def ==(other)
|
59
|
+
other.is_a?(self.class) && [book, ranges] == [other.book, other.ranges]
|
60
|
+
end
|
61
|
+
|
62
|
+
def hash
|
63
|
+
[book, ranges].hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def <=>(other)
|
67
|
+
to_a <=> other.to_a
|
68
|
+
end
|
69
|
+
|
70
|
+
def intersects?(other)
|
71
|
+
return false unless other.is_a?(Pericope)
|
72
|
+
return false unless book == other.book
|
73
|
+
|
74
|
+
ranges.each do |self_range|
|
75
|
+
other.ranges.each do |other_range|
|
76
|
+
return true if (self_range.end >= other_range.begin) and (self_range.begin <= other_range.end)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def each
|
85
|
+
return to_enum unless block_given?
|
86
|
+
|
87
|
+
ranges.each do |range|
|
88
|
+
range.each do |verse|
|
89
|
+
yield verse
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
class << self
|
98
|
+
attr_reader :max_letter
|
99
|
+
|
100
|
+
def max_letter=(value)
|
101
|
+
unless @max_letter == value
|
102
|
+
@max_letter = value.freeze
|
103
|
+
@_letters = nil
|
104
|
+
@_regexp = nil
|
105
|
+
@_normalizations = nil
|
106
|
+
@_letter_regexp = nil
|
107
|
+
@_fragment_regexp = nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def book_has_chapters?(book)
|
112
|
+
BOOK_CHAPTER_COUNTS[book] > 1
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_max_verse(book, chapter)
|
116
|
+
id = (book * 1000000) + (chapter * 1000)
|
117
|
+
CHAPTER_VERSE_COUNTS[id]
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_max_chapter(book)
|
121
|
+
BOOK_CHAPTER_COUNTS[book]
|
122
|
+
end
|
123
|
+
|
124
|
+
def regexp
|
125
|
+
@_regexp ||= /#{book_pattern}\.?\s*(#{reference_pattern})/i
|
126
|
+
end
|
127
|
+
|
128
|
+
def normalizations
|
129
|
+
@_normalizations ||= [
|
130
|
+
[/(\d+)\s*[".]\s*(\d+)/, '\1:\2'], # 12"5 and 12.5 -> 12:5
|
131
|
+
[/[–—]/, '-'], # convert em dash and en dash to -
|
132
|
+
[/[^0-9,:;\-–—#{letters}]/, ''] ] # remove everything but recognized symbols
|
133
|
+
end
|
134
|
+
|
135
|
+
def letter_regexp
|
136
|
+
@_letter_regexp ||= /[#{letters}]$/
|
137
|
+
end
|
138
|
+
|
139
|
+
def fragment_regexp
|
140
|
+
@_fragment_regexp ||= /^(?:(?<chapter>\d{1,3}):)?(?<verse>\d{1,3})?(?<letter>[#{letters}])?$/
|
141
|
+
end
|
142
|
+
|
143
|
+
def book_regexp
|
144
|
+
@_book_regexp ||= /#{book_pattern}/i
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def book_pattern
|
150
|
+
BOOK_PATTERN.source.gsub(/[ \n]/, "")
|
151
|
+
end
|
152
|
+
|
153
|
+
def reference_pattern
|
154
|
+
number = '\d{1,3}'
|
155
|
+
verse = "#{number}[#{letters}]?"
|
156
|
+
chapter_verse_separator = '\s*[:"\.]\s*'
|
157
|
+
list_or_range_separator = '\s*[\-–—,;]\s*'
|
158
|
+
chapter_and_verse = "(?:#{number + chapter_verse_separator})?" + verse + '\b'
|
159
|
+
chapter_and_verse_or_letter = "(?:#{chapter_and_verse}|[#{letters}]\\b)"
|
160
|
+
chapter_and_verse + "(?:#{list_or_range_separator + chapter_and_verse_or_letter})*"
|
161
|
+
end
|
162
|
+
|
163
|
+
def letters
|
164
|
+
@_letters ||= ("a"..max_letter).to_a.join
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def well_formatted_reference(options={})
|
173
|
+
return nil if ranges.empty?
|
174
|
+
|
175
|
+
verse_range_separator = options.fetch(:verse_range_separator, "–") # en-dash
|
176
|
+
chapter_range_separator = options.fetch(:chapter_range_separator, "—") # em-dash
|
177
|
+
verse_list_separator = options.fetch(:verse_list_separator, ", ")
|
178
|
+
chapter_list_separator = options.fetch(:chapter_list_separator, "; ")
|
179
|
+
always_print_verse_range = options.fetch(:always_print_verse_range, false)
|
180
|
+
always_print_verse_range = true unless book_has_chapters?
|
181
|
+
|
182
|
+
recent_chapter = nil # e.g. in 12:1-8, remember that 12 is the chapter when we parse the 8
|
183
|
+
recent_chapter = 1 unless book_has_chapters?
|
184
|
+
recent_verse = nil
|
185
|
+
|
186
|
+
touched_chapters = [ recent_chapter ].compact
|
187
|
+
|
188
|
+
ranges.each_with_index.each_with_object("") do |(range, i), s|
|
189
|
+
if i > 0
|
190
|
+
if recent_chapter == range.begin.chapter
|
191
|
+
s << verse_list_separator
|
192
|
+
else
|
193
|
+
s << chapter_list_separator
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
last_verse = Pericope.get_max_verse(book, range.end.chapter)
|
198
|
+
if !always_print_verse_range && range.begin.verse == 1 && range.begin.whole? && (range.end.verse > last_verse || range.end.whole? && range.end.verse == last_verse) && (touched_chapters - [range.begin.chapter]).none?
|
199
|
+
s << range.begin.chapter.to_s
|
200
|
+
s << "#{chapter_range_separator}#{range.end.chapter}" if range.end.chapter > range.begin.chapter
|
201
|
+
else
|
202
|
+
if range.begin.partial? && range.begin.verse == recent_verse
|
203
|
+
s << range.begin.letter
|
204
|
+
else
|
205
|
+
s << range.begin.to_s(with_chapter: recent_chapter != range.begin.chapter)
|
206
|
+
end
|
207
|
+
|
208
|
+
if range.begin != range.end
|
209
|
+
if range.begin.chapter == range.end.chapter
|
210
|
+
s << "#{verse_range_separator}#{range.end}"
|
211
|
+
else
|
212
|
+
s << "#{chapter_range_separator}#{range.end.to_s(with_chapter: true)}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
recent_chapter = range.end.chapter
|
217
|
+
recent_verse = range.end.verse if range.end.partial?
|
218
|
+
touched_chapters |= [range.begin.chapter, range.end.chapter].uniq
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def group_array_into_ranges(verses)
|
224
|
+
return [] if verses.nil? or verses.empty?
|
225
|
+
|
226
|
+
verses = verses.flatten.compact.sort.map { |verse| Verse.parse(verse) }
|
227
|
+
|
228
|
+
ranges = []
|
229
|
+
range_begin = verses.shift
|
230
|
+
range_end = range_begin
|
231
|
+
while verse = verses.shift
|
232
|
+
if verse > range_end.next
|
233
|
+
ranges << Range.new(range_begin, range_end)
|
234
|
+
range_begin = range_end = verse
|
235
|
+
elsif verse > range_end
|
236
|
+
range_end = verse
|
237
|
+
end
|
238
|
+
|
239
|
+
break if range_end.next.nil? # end of book
|
240
|
+
end
|
241
|
+
|
242
|
+
ranges << Range.new(range_begin, range_end)
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
Pericope.max_letter = "d"
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wcc-pericope
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Watermark Community Church
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: shoulda-context
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-focus
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest-reporters
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest-reporters-turn_reporter
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: It recognizes common abbreviations and misspellings for names of the
|
126
|
+
books of the Bible and a variety of ways of denoting ranges of chapters and verses.
|
127
|
+
It can parse pericopes singly or out of a block of text. It's useful for comparing
|
128
|
+
two pericopes for intersection and normalizing them into a well-formatted string.
|
129
|
+
email:
|
130
|
+
- dev@watermark.org
|
131
|
+
executables:
|
132
|
+
- pericope
|
133
|
+
extensions: []
|
134
|
+
extra_rdoc_files: []
|
135
|
+
files:
|
136
|
+
- README.mdown
|
137
|
+
- bin/console
|
138
|
+
- bin/pericope
|
139
|
+
- data/chapter_verse_count.txt
|
140
|
+
- lib/cli/base.rb
|
141
|
+
- lib/cli/command.rb
|
142
|
+
- lib/pericope.rb
|
143
|
+
- lib/pericope/cli.rb
|
144
|
+
- lib/pericope/data.rb
|
145
|
+
- lib/pericope/parsing.rb
|
146
|
+
- lib/pericope/range.rb
|
147
|
+
- lib/pericope/verse.rb
|
148
|
+
- lib/pericope/version.rb
|
149
|
+
homepage: https://github.com/watermarkchurch/wcc-pericope
|
150
|
+
licenses: []
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubygems_version: 3.4.8
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: Pericope is a gem for parsing Bible references.
|
171
|
+
test_files: []
|