scripref 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/LICENSE +20 -0
- data/Rakefile +17 -0
- data/lib/scripref/const_reader.rb +46 -0
- data/lib/scripref/english.rb +59 -0
- data/lib/scripref/german.rb +56 -0
- data/lib/scripref/parser.rb +198 -0
- data/lib/scripref/processor.rb +60 -0
- data/lib/scripref.rb +17 -0
- data/test/test_english.rb +43 -0
- data/test/test_german.rb +40 -0
- data/test/test_parser.rb +166 -0
- data/test/test_processor.rb +41 -0
- metadata +66 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010-2012 Jan Friedrich
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rim'
|
2
|
+
require 'rim/check_version'
|
3
|
+
require 'rim/gem'
|
4
|
+
require 'rim/git'
|
5
|
+
require 'rim/rimrc'
|
6
|
+
require 'rim/test'
|
7
|
+
|
8
|
+
$:.unshift File.dirname(__FILE__) + '/lib'
|
9
|
+
require 'scripref'
|
10
|
+
|
11
|
+
Rim.setup do
|
12
|
+
name 'scripref'
|
13
|
+
authors 'Jan Friedrich'
|
14
|
+
homepage 'http://gitorious.org/scripref'
|
15
|
+
version Scripref::VERSION
|
16
|
+
summary 'Library for parsing scripture references in real texts.'
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
|
3
|
+
# Mixin to generate instance methods to access of mixin constants.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
# module M
|
7
|
+
# A = :a
|
8
|
+
# B = :b
|
9
|
+
# extend ConstReader
|
10
|
+
# const_reader constants
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # Include in class
|
14
|
+
# class C
|
15
|
+
# include M
|
16
|
+
# end
|
17
|
+
# c = C.new
|
18
|
+
# c.a # => :a
|
19
|
+
# c.b # => :b
|
20
|
+
#
|
21
|
+
# # Extend an instance
|
22
|
+
# o = Object.new
|
23
|
+
# o.extend M
|
24
|
+
# o.a # => :a
|
25
|
+
# o.b # => :b
|
26
|
+
module ConstReader
|
27
|
+
|
28
|
+
# Define a getter method for one or more constants.
|
29
|
+
#
|
30
|
+
# Example:
|
31
|
+
# # all defined constants
|
32
|
+
# const_reader constants
|
33
|
+
#
|
34
|
+
# # constants A and B
|
35
|
+
# const_reader :A, :B
|
36
|
+
def const_reader *consts
|
37
|
+
consts.flatten.each do |c|
|
38
|
+
class_exec(c.to_s, c.to_s.downcase) do |c_name, m_name|
|
39
|
+
define_method m_name do
|
40
|
+
self.singleton_class.const_get c_name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'scripref/const_reader'
|
3
|
+
|
4
|
+
module Scripref
|
5
|
+
|
6
|
+
# Mixin for parsing references in English.
|
7
|
+
module English
|
8
|
+
|
9
|
+
# Array of book names.
|
10
|
+
BOOK_NAMES = <<-END.strip.split(/,\s*/)
|
11
|
+
Genesis, Exodus, Leviticus, Numbers, Deuteronomy, Joshua, Judges,
|
12
|
+
Ruth, 1 Samuel, 2 Samuel, 1 Kings, 2 Kings, 1 Chronicles,
|
13
|
+
2 Chronicles, Ezra, Nehemiah, Esther, Job, Psalms, Proverbs,
|
14
|
+
Ecclesiastes, Song of Songs, Isaiah, Jeremiah, Lamentations,
|
15
|
+
Ezekiel, Daniel, Hosea, Joel, Amos, Obadiah, Jonah, Micah, Nahum,
|
16
|
+
Habakkuk, Zephaniah, Haggai, Zechariah, Malachi,
|
17
|
+
Matthew, Mark, Luke, John, Acts, Romans, 1 Corinthians,
|
18
|
+
2 Corinthians, Galatians, Ephesians, Philippians, Colossians,
|
19
|
+
1 Thessalonians, 2 Thessalonians, 1 Timothy, 2 Timothy, Titus,
|
20
|
+
Philemon, Hebrews, James, 1 Peter, 2 Peter, 1 John, 2 John, 3 John,
|
21
|
+
Jude, Revelation
|
22
|
+
END
|
23
|
+
|
24
|
+
# Array of regular expressions to match book names.
|
25
|
+
BOOKS_RES = BOOK_NAMES.map do |bn|
|
26
|
+
Regexp.new(bn.gsub(/([^1-3A-Z])/, '\1?').gsub('.', '\.') << '\b\s*')
|
27
|
+
end
|
28
|
+
|
29
|
+
# Regular expression to match a book.
|
30
|
+
BOOK_RE = Regexp.new(BOOKS_RES.map {|re| '(^' << re.to_s << ')' }.join('|'))
|
31
|
+
|
32
|
+
# Regular expression to match a separator between chapter and verse.
|
33
|
+
CV_SEP_RE = /:\s*/o
|
34
|
+
|
35
|
+
# Regular expression to match a hyphen.
|
36
|
+
HYPHEN_RE = /\s*-\s*/o
|
37
|
+
|
38
|
+
# Regular expression to match a separator between passages.
|
39
|
+
PASS_SEP_RE = /;\s*/o
|
40
|
+
|
41
|
+
# Regular expression to match a separator between verses.
|
42
|
+
VERSE_SEP_RE = /,\s*/o
|
43
|
+
|
44
|
+
# Regular expression to match addons for a verse.
|
45
|
+
VERSE_ADDON_RE = /([ab]|ff?)\s*/o
|
46
|
+
|
47
|
+
pass = '([1-3]\s*)?[A-Z][a-z]+\.?\s*(\d+\s*[,.\-]\s*)*\d+\s*'
|
48
|
+
|
49
|
+
# Regular expression to parse a reference
|
50
|
+
REFERENCE_RE = /#{pass}(;\s*#{pass})*/o
|
51
|
+
|
52
|
+
# Define instance methods for the mixin.
|
53
|
+
|
54
|
+
extend ConstReader
|
55
|
+
const_reader constants
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'scripref/const_reader'
|
3
|
+
|
4
|
+
module Scripref
|
5
|
+
|
6
|
+
# Mixin for parsing references in German.
|
7
|
+
module German
|
8
|
+
|
9
|
+
# Array of book names.
|
10
|
+
BOOK_NAMES = <<-END.strip.split(/,\s*/)
|
11
|
+
1. Mose, 2. Mose, 3. Mose, 4. Mose, 5. Mose, Josua, Richter, Ruth, 1. Samuel, 2. Samuel,
|
12
|
+
1. Könige, 2.Könige, 1. Chronika, 2. Chronika, Esra, Nehemia, Esther, Hiob, Psalm,
|
13
|
+
Sprüche, Prediger, Hohelied, Jesaja, Jeremia, Klagelieder, Hesekiel, Daniel, Hosea, Joel,
|
14
|
+
Amos, Obadja, Jona, Micha, Nahum, Habakuk, Zephanja, Haggai, Sacharja, Maleachi,
|
15
|
+
Matthäus, Markus, Lukas, Johannes, Apostelgeschichte, Römer, 1. Korinther, 2. Korinther,
|
16
|
+
Galater, Epheser, Philipper, Kolosser, 1. Thessalonicher, 2. Thessalonicher, 1. Timotheus,
|
17
|
+
2. Timotheus, Titus, Philemon, Hebräer, Jakobus, 1. Petrus, 2. Petrus, 1. Johannes,
|
18
|
+
2. Johannes, 3. Johannes, Judas, Offenbarung
|
19
|
+
END
|
20
|
+
|
21
|
+
# Array of regular expressions to match book names.
|
22
|
+
BOOKS_RES = BOOK_NAMES.map do |bn|
|
23
|
+
Regexp.new(bn.gsub(/([^1-5A-Z])/, '\1?').gsub('.', '\.') << '\b\s*')
|
24
|
+
end
|
25
|
+
|
26
|
+
# Regular expression to match a book.
|
27
|
+
BOOK_RE = Regexp.new(BOOKS_RES.map {|re| '(^' << re.to_s << ')' }.join('|'))
|
28
|
+
|
29
|
+
# Regular expression to match a separator between chapter and verse.
|
30
|
+
CV_SEP_RE = /,\s*/o
|
31
|
+
|
32
|
+
# Regular expression to match a hyphen.
|
33
|
+
HYPHEN_RE = /\s*-\s*/o
|
34
|
+
|
35
|
+
# Regular expression to match a separator between passages.
|
36
|
+
PASS_SEP_RE = /;\s*/o
|
37
|
+
|
38
|
+
# Regular expression to match a separator between verses.
|
39
|
+
VERSE_SEP_RE = /\.\s*/o
|
40
|
+
|
41
|
+
# Regular expression to match addons for a verse.
|
42
|
+
VERSE_ADDON_RE = /([ab]|ff?)\s*/o
|
43
|
+
|
44
|
+
pass = '([1-5]\.?\s*)?[A-Z][a-zäöü]+\.?\s*(\d+\s*[,.\-]\s*)*\d+\s*'
|
45
|
+
|
46
|
+
# Regular expression to parse a reference
|
47
|
+
REFERENCE_RE = /#{pass}(;\s*#{pass})*/o
|
48
|
+
|
49
|
+
# Define instance methods for the mixin.
|
50
|
+
|
51
|
+
extend ConstReader
|
52
|
+
const_reader constants
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'strscan'
|
3
|
+
|
4
|
+
module Scripref
|
5
|
+
|
6
|
+
class Parser < StringScanner
|
7
|
+
|
8
|
+
NUMBER_RE = /\d+\s*/
|
9
|
+
|
10
|
+
# @param mods on ore more modules to include
|
11
|
+
def initialize *mods
|
12
|
+
@mods = mods
|
13
|
+
mods.each do |m|
|
14
|
+
extend m
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parsing a string of a scripture reference
|
19
|
+
# @param str string to parse
|
20
|
+
def parse str
|
21
|
+
self.string = str
|
22
|
+
@result = []
|
23
|
+
start
|
24
|
+
end
|
25
|
+
|
26
|
+
# start of parsing grammer
|
27
|
+
def start
|
28
|
+
@text = ''
|
29
|
+
b1 or []
|
30
|
+
end
|
31
|
+
|
32
|
+
# try to parse first book
|
33
|
+
def b1
|
34
|
+
s = scan(book_re) or return nil
|
35
|
+
@text << s
|
36
|
+
@b1 = @b2 = book2num(s)
|
37
|
+
@c1 = @v1 = 1
|
38
|
+
@c2 = @v2 = :max
|
39
|
+
|
40
|
+
epsilon or c1 or nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# try parse first chapter
|
44
|
+
def c1
|
45
|
+
s = scan(NUMBER_RE) or return nil
|
46
|
+
@text << s
|
47
|
+
@c1 = @c2 = s.to_i
|
48
|
+
|
49
|
+
if cv_sep
|
50
|
+
v1 or nil
|
51
|
+
elsif hyphen
|
52
|
+
c2 or nil
|
53
|
+
elsif pass_sep
|
54
|
+
b1 or c1
|
55
|
+
else
|
56
|
+
epsilon or nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# try to parse first verse
|
61
|
+
def v1
|
62
|
+
s = scan(NUMBER_RE) or return nil
|
63
|
+
@text << s
|
64
|
+
@v1 = @v2 = s.to_i
|
65
|
+
|
66
|
+
if addon = verse_addon
|
67
|
+
case addon
|
68
|
+
when :f, :ff
|
69
|
+
@v2 = addon
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if hyphen
|
74
|
+
if check(Regexp.new(NUMBER_RE.source + cv_sep_re.source))
|
75
|
+
c2
|
76
|
+
else
|
77
|
+
v2 or nil
|
78
|
+
end
|
79
|
+
elsif pass_sep
|
80
|
+
b1 or c1
|
81
|
+
elsif verse_sep
|
82
|
+
v1
|
83
|
+
else
|
84
|
+
epsilon or nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# try to parse second chapter
|
89
|
+
def c2
|
90
|
+
s = scan(NUMBER_RE) or return nil
|
91
|
+
@text << s
|
92
|
+
@c2 = s.to_i
|
93
|
+
|
94
|
+
if cv_sep
|
95
|
+
v2 or nil
|
96
|
+
else
|
97
|
+
epsilon or nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# try to parse second verse
|
102
|
+
def v2
|
103
|
+
s = scan(NUMBER_RE) or return nil
|
104
|
+
@text << s
|
105
|
+
@v2 = s.to_i
|
106
|
+
|
107
|
+
if verse_sep
|
108
|
+
v1
|
109
|
+
elsif pass_sep
|
110
|
+
b1 or c1
|
111
|
+
else
|
112
|
+
epsilon or nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# try to parse <tt>end of string</tt>
|
117
|
+
def epsilon
|
118
|
+
if eos?
|
119
|
+
push_passage
|
120
|
+
return @result
|
121
|
+
end
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# try to parse separator or chapter and verse
|
126
|
+
def cv_sep
|
127
|
+
if s = scan(cv_sep_re)
|
128
|
+
@text << s
|
129
|
+
s
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# try to parse hyphen
|
136
|
+
def hyphen
|
137
|
+
if s = scan(hyphen_re)
|
138
|
+
@text << s
|
139
|
+
s
|
140
|
+
else
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# try to parse separator between passages
|
146
|
+
def pass_sep
|
147
|
+
if s = scan(pass_sep_re)
|
148
|
+
push_passage
|
149
|
+
@result << s
|
150
|
+
s
|
151
|
+
else
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# try to parse verse separator
|
157
|
+
def verse_sep
|
158
|
+
if s = scan(verse_sep_re)
|
159
|
+
push_passage
|
160
|
+
@result << s
|
161
|
+
s
|
162
|
+
else
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# try to parse addons for verses
|
168
|
+
def verse_addon
|
169
|
+
if s = scan(verse_addon_re)
|
170
|
+
@text << s
|
171
|
+
s.to_sym
|
172
|
+
else
|
173
|
+
nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def push_passage
|
178
|
+
@result << Passage.new(@text, @b1, @c1, @v1, @b2, @c2, @v2)
|
179
|
+
@text = ''
|
180
|
+
end
|
181
|
+
|
182
|
+
def book2num str
|
183
|
+
return nil unless book_re =~str
|
184
|
+
books_res.each_with_index do |re, i|
|
185
|
+
if str =~ Regexp.new('^' << re.to_s << '$')
|
186
|
+
num = i + 1
|
187
|
+
return num
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def inspect
|
193
|
+
"#<#{self.class} #{@mods.inspect}>"
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'strscan'
|
3
|
+
require 'scripref/parser'
|
4
|
+
|
5
|
+
module Scripref
|
6
|
+
|
7
|
+
class Processor
|
8
|
+
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_accessor :text
|
12
|
+
|
13
|
+
# @param text text to parse
|
14
|
+
# @param mods on ore more modules to include in processor and parser
|
15
|
+
def initialize text=nil, *mods
|
16
|
+
@text = text
|
17
|
+
@mods = mods
|
18
|
+
mods.each do |m|
|
19
|
+
extend m
|
20
|
+
end
|
21
|
+
@parser = Parser.new(*mods)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Iterate over each parsed reference if block given, gets an iterator
|
25
|
+
# over each parsed reference otherwise.
|
26
|
+
def each_ref
|
27
|
+
if block_given?
|
28
|
+
scanner = StringScanner.new(text)
|
29
|
+
while scanner.scan_until(reference_re)
|
30
|
+
yield @parser.parse(scanner.matched)
|
31
|
+
end
|
32
|
+
self
|
33
|
+
else
|
34
|
+
enum_for :each_ref
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Iterate over each piece of <tt>str</tt> (text and parsed references)
|
39
|
+
# if block given, gets an iterator over the pieces otherwise.
|
40
|
+
def each
|
41
|
+
if block_given?
|
42
|
+
scanner = StringScanner.new(text)
|
43
|
+
while scanner.scan(/(.*?)(#{Regexp.new(reference_re.to_s)})/)
|
44
|
+
yield scanner[1]
|
45
|
+
yield @parser.parse(scanner[2])
|
46
|
+
end
|
47
|
+
yield scanner.rest if scanner.rest
|
48
|
+
self
|
49
|
+
else
|
50
|
+
enum_for :each
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"#<#{self.class} #{@mods.inspect}>"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/scripref.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'scripref/parser'
|
3
|
+
require 'scripref/processor'
|
4
|
+
require 'scripref/english'
|
5
|
+
require 'scripref/german'
|
6
|
+
|
7
|
+
module Scripref
|
8
|
+
|
9
|
+
VERSION = '0.2.0'
|
10
|
+
|
11
|
+
Passage = Struct.new(:text, :b1, :c1, :v1, :b2, :c2, :v2)
|
12
|
+
|
13
|
+
class Passage
|
14
|
+
alias to_s text
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'test/unit'
|
3
|
+
require 'scripref/english'
|
4
|
+
|
5
|
+
class TestEnglish < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Scripref::English
|
8
|
+
|
9
|
+
def test_book_re
|
10
|
+
assert_match 'Genesis', book_re
|
11
|
+
assert_match 'Exodus', book_re
|
12
|
+
assert_match 'Matthew', book_re
|
13
|
+
assert_match '2 Timothy', book_re
|
14
|
+
assert_not_match '2 2 Timothy', book_re
|
15
|
+
assert_match 'Revelation', book_re
|
16
|
+
assert_not_match 'something', book_re
|
17
|
+
assert_match 'Gen', book_re
|
18
|
+
assert_match 'Ex', book_re
|
19
|
+
assert_match 'Mat', book_re
|
20
|
+
assert_match '2 Tim', book_re
|
21
|
+
assert_match 'Rev', book_re
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_book2num
|
25
|
+
assert_book_num 1, 'Genesis'
|
26
|
+
assert_book_num 40, 'Matthew'
|
27
|
+
assert_book_num 66, 'Revelation'
|
28
|
+
assert_book_num 1, 'Gen'
|
29
|
+
assert_book_num 1, 'Ge'
|
30
|
+
assert_book_num 1, 'G'
|
31
|
+
assert_book_num 55, '2 Tim'
|
32
|
+
assert_book_num 55, '2Tim'
|
33
|
+
assert_book_num 55, '2Tm'
|
34
|
+
assert_book_num 40, 'Mat'
|
35
|
+
assert_book_num 66, 'Rev'
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert_book_num num, str
|
39
|
+
@parser ||= Scripref::Parser.new(Scripref::English)
|
40
|
+
assert_equal num, @parser.parse(str).first.b1
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/test/test_german.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'test/unit'
|
3
|
+
require 'scripref/german'
|
4
|
+
|
5
|
+
class TestGerman < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Scripref::German
|
8
|
+
|
9
|
+
def test_book_re
|
10
|
+
assert_match '1. Mose', book_re
|
11
|
+
assert_match '2. Mose', book_re
|
12
|
+
assert_match 'Matthäus', book_re
|
13
|
+
assert_match '2. Timotheus', book_re
|
14
|
+
assert_not_match '2. 2. Timotheus', book_re
|
15
|
+
assert_match 'Offenbarung', book_re
|
16
|
+
assert_not_match 'something', book_re
|
17
|
+
assert_match '1. Mo', book_re
|
18
|
+
assert_match '2.Mo', book_re
|
19
|
+
assert_match 'Mat', book_re
|
20
|
+
assert_match '2. Tim', book_re
|
21
|
+
assert_match 'Off', book_re
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_book2num
|
25
|
+
assert_book_num 1, '1. Mose'
|
26
|
+
assert_book_num 40, 'Matthäus'
|
27
|
+
assert_book_num 66, 'Offenbarung'
|
28
|
+
assert_book_num 1, '1. Mo'
|
29
|
+
assert_book_num 1, '1.Mo'
|
30
|
+
assert_book_num 1, '1M'
|
31
|
+
assert_book_num 40, 'Mat'
|
32
|
+
assert_book_num 66, 'Off'
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_book_num num, str
|
36
|
+
@parser ||= Scripref::Parser.new(Scripref::German)
|
37
|
+
assert_equal num, @parser.parse(str).first.b1
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/test/test_parser.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'test/unit'
|
3
|
+
require 'scripref'
|
4
|
+
|
5
|
+
class TestParser < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@parser = Scripref::Parser.new(Scripref::German)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_only_book
|
12
|
+
text = 'Ruth'
|
13
|
+
assert_parsed_ast_for_text [pass(text, 8, 1, 1, 8, :max, :max)], text
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_book_and_chapter
|
17
|
+
text = 'Ruth 2'
|
18
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 1, 8, 2, :max)], text
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_book_chapter_and_verse
|
22
|
+
text = 'Ruth 2,5'
|
23
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 5, 8, 2, 5)], text
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_verse_range
|
27
|
+
text = 'Ruth 2,5-11'
|
28
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 5, 8, 2, 11)], text
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_chapter_verse_range
|
32
|
+
text = 'Ruth 2,5-3,7'
|
33
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 5, 8, 3, 7)], text
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_chapter_range
|
37
|
+
text = 'Ruth 2-3'
|
38
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 1, 8, 3, :max)], text
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_one_following_verse
|
42
|
+
text = 'Ruth 2,5f'
|
43
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 5, 8, 2, :f)], text
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_more_following_verse
|
47
|
+
text = 'Ruth 2,5ff'
|
48
|
+
assert_parsed_ast_for_text [pass(text, 8, 2, 5, 8, 2, :ff)], text
|
49
|
+
end
|
50
|
+
|
51
|
+
######################################################################
|
52
|
+
# more than one reference
|
53
|
+
######################################################################
|
54
|
+
|
55
|
+
def test_two_complete_refs
|
56
|
+
text = 'Ruth 2,1; Markus 4,8'
|
57
|
+
t1, t2 = text.split('; ')
|
58
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 1), '; ', pass(t2, 41, 4, 8, 41, 4, 8)], text
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_two_refs_same_book
|
62
|
+
text = 'Ruth 2,1; 5,4'
|
63
|
+
t1, t2 = text.split('; ')
|
64
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 1), '; ', pass(t2, 8, 5, 4, 8, 5, 4)], text
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_two_chapters_same_book
|
68
|
+
text = 'Ruth 2; 5'
|
69
|
+
t1, t2 = text.split('; ')
|
70
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, :max), '; ', pass(t2, 8, 5, 1, 8, 5, :max)], text
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_two_chapters_different_book
|
74
|
+
text = 'Ruth 2; Markus 4'
|
75
|
+
t1, t2 = text.split('; ')
|
76
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, :max), '; ', pass(t2, 41, 4, 1, 41, 4, :max)], text
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_two_verses
|
80
|
+
text = 'Ruth 2,5.11'
|
81
|
+
t1, t2 = text.split('.')
|
82
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 5, 8, 2, 5), '.', pass(t2, 8, 2, 11, 8, 2, 11)], text
|
83
|
+
end
|
84
|
+
|
85
|
+
######################################################################
|
86
|
+
# mixed variants of more than one reference
|
87
|
+
######################################################################
|
88
|
+
|
89
|
+
def test_verse_range_and_separated_verse
|
90
|
+
text = 'Ruth 2,1-3.11'
|
91
|
+
t1, t2 = text.split('.')
|
92
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 3), '.', pass(t2, 8, 2, 11, 8, 2, 11)], text
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_separate_verse_and_verse_range
|
96
|
+
text = 'Ruth 2,1.3-11'
|
97
|
+
t1, t2 = text.split('.')
|
98
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 1), '.', pass(t2, 8, 2, 3, 8, 2, 11)], text
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_two_verse_ranges
|
102
|
+
text = 'Ruth 2,1-3.7-11'
|
103
|
+
t1, t2 = text.split('.')
|
104
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 3), '.', pass(t2, 8, 2, 7, 8, 2, 11)], text
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_two_verse_range_different_books
|
108
|
+
text = 'Ruth 2,1-11; Markus 4,3-7'
|
109
|
+
t1, t2 = text.split('; ')
|
110
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 11), '; ', pass(t2, 41, 4, 3,41, 4, 7)], text
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_two_verse_range_different_chapters
|
114
|
+
text = 'Ruth 2,1-11; 3,10-19'
|
115
|
+
t1, t2 = text.split('; ')
|
116
|
+
assert_parsed_ast_for_text [pass(t1, 8, 2, 1, 8, 2, 11), '; ', pass(t2, 8, 3, 10, 8, 3, 19)], text
|
117
|
+
end
|
118
|
+
|
119
|
+
######################################################################
|
120
|
+
# complex variants of references
|
121
|
+
######################################################################
|
122
|
+
|
123
|
+
def test_complex_example
|
124
|
+
text = 'Ruth 2,1-11.15; 3,7.9-12; Markus 4; 5,3.18-21'
|
125
|
+
t1, t2, t3, t4, t5, t6, t7 = text.split(/; |\./)
|
126
|
+
ast = [
|
127
|
+
pass(t1, 8, 2, 1, 8, 2, 11), '.',
|
128
|
+
pass(t2, 8, 2, 15, 8, 2, 15), '; ',
|
129
|
+
pass(t3, 8, 3, 7, 8, 3, 7), '.',
|
130
|
+
pass(t4, 8, 3, 9, 8, 3, 12), '; ',
|
131
|
+
pass(t5, 41, 4, 1, 41, 4, :max), '; ',
|
132
|
+
pass(t6, 41, 5, 3, 41, 5, 3), '.',
|
133
|
+
pass(t7, 41, 5, 18, 41, 5, 21)
|
134
|
+
]
|
135
|
+
assert_parsed_ast_for_text ast, text
|
136
|
+
end
|
137
|
+
|
138
|
+
protected
|
139
|
+
|
140
|
+
def pass *args
|
141
|
+
Scripref::Passage.new(*args)
|
142
|
+
end
|
143
|
+
|
144
|
+
def assert_equal_passage expected, actual
|
145
|
+
assert_equal expected.text, actual.text, 'Parsed text'
|
146
|
+
assert_equal expected.b1, actual.b1, 'First book'
|
147
|
+
assert_equal expected.c1, actual.c1, 'First chapter'
|
148
|
+
assert_equal expected.v1, actual.v1, 'First verse'
|
149
|
+
assert_equal expected.b2, actual.b2, 'Second book'
|
150
|
+
assert_equal expected.c2, actual.c2, 'Second chapter'
|
151
|
+
assert_equal expected.v2, actual.v2, 'Second verse'
|
152
|
+
end
|
153
|
+
|
154
|
+
def assert_parsed_ast_for_text expected_ast, text
|
155
|
+
res = @parser.parse(text)
|
156
|
+
assert_equal expected_ast.size, res.size, 'Array size of AST'
|
157
|
+
expected_ast.zip(res) do |expected_elem, actual_elem|
|
158
|
+
if !expected_elem.kind_of?(String)
|
159
|
+
assert_equal_passage expected_elem, actual_elem
|
160
|
+
else
|
161
|
+
assert_equal expected_elem, actual_elem
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# - encoding: utf-8 -
|
2
|
+
require 'test/unit'
|
3
|
+
require 'scripref'
|
4
|
+
|
5
|
+
class TestProcessor < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@text = 'Some text Mt 1,1 and Mr 2 and so on ...'
|
9
|
+
@mt = [Scripref::Passage.new('Mt 1,1 ', 40, 1, 1, 40, 1, 1)]
|
10
|
+
@mr = [Scripref::Passage.new('Mr 2 ', 41, 2, 1, 41, 2, :max)]
|
11
|
+
@processor = Scripref::Processor.new(@text, Scripref::German)
|
12
|
+
@chunks = ['Some text ', @mt, 'and ', @mr, 'and so on ...']
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_each_with_block
|
16
|
+
@processor.each do |chunk|
|
17
|
+
assert_equal @chunks.shift, chunk
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_each_without_block
|
22
|
+
enum = @processor.each
|
23
|
+
assert_kind_of Enumerator, enum
|
24
|
+
assert_equal @chunks, enum.to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_each_ref_with_block
|
28
|
+
refs = @chunks.select {|c| c.kind_of? Array}
|
29
|
+
@processor.each_ref do |ref|
|
30
|
+
assert_equal refs.shift, ref
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_each_ref_without_block
|
35
|
+
enum = @processor.each_ref
|
36
|
+
refs = @chunks.select {|c| c.kind_of? Array}
|
37
|
+
assert_kind_of Enumerator, enum
|
38
|
+
assert_equal refs, enum.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scripref
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jan Friedrich
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-03-28 00:00:00 Z
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: ""
|
17
|
+
email:
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- CHANGELOG
|
26
|
+
- LICENSE
|
27
|
+
- Rakefile
|
28
|
+
- lib/scripref/const_reader.rb
|
29
|
+
- lib/scripref/english.rb
|
30
|
+
- lib/scripref/german.rb
|
31
|
+
- lib/scripref/parser.rb
|
32
|
+
- lib/scripref/processor.rb
|
33
|
+
- lib/scripref.rb
|
34
|
+
- test/test_english.rb
|
35
|
+
- test/test_german.rb
|
36
|
+
- test/test_parser.rb
|
37
|
+
- test/test_processor.rb
|
38
|
+
homepage: http://gitorious.org/scripref
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.8.19
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Library for parsing scripture references in real texts.
|
65
|
+
test_files: []
|
66
|
+
|