scripref 0.7.1 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e65b203f6111b6313c92ed4fc32753ffcf084e0f
4
- data.tar.gz: 362dddef75cfb666e6e287428fcf2e4e911d3881
3
+ metadata.gz: 373b4b572bcb6fadc58872590bc98e75f5bebe3c
4
+ data.tar.gz: be215c400b76c7327bdeb63b1bff52917c854eca
5
5
  SHA512:
6
- metadata.gz: 705ab5f7fbbce60d4d1dcc8bf4f046a5b1e0f943dd30172a89dbede3685ca9b141b485ac01329bc51d70fa25418daa5c494bded5246a9b876256629c70d823fe
7
- data.tar.gz: 0e5de450e1a2e2d2f267e01f33476959f8cff1d9966e312ff6d01ffbb45b9a94a12df41c0a482467ef821f29edbf1453943d3545749daa6ebfee5acd16604216
6
+ metadata.gz: fc24a4742a42477c252edd1c06fb52f2b41bb6411479556921b39e2512082accc7ce9270d0d87dc6b86032ba13847f3bf9074268b18ac0cce789cd90faf8918c
7
+ data.tar.gz: 31e56ca2e1000abc2a8bdcdf6b7af0c99b6c49e604dbdd0f530dd02416b4e1d188884ff4428e466c3b367439357876c4b66d4244ca61e42e6bfb4a59de283608
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 0.8.0
2
+ Formatting of verse addons implemented.
3
+ Refactoring: Rename methods in Formatter to distinguish between format_* and process_*.
4
+ Refactoring: Move method Scripref.book_has_only_one_chapter to mixins.
5
+ New methods Parser#chapter_re and #verse_re.
6
+ New method Parser#special_abbrev_mapping to allow to parse special abbreviations, for example "Phil" to "Philipper" in German.
7
+ Some bugs fixed.
8
+
1
9
  0.7.1
2
10
  Add Psalmen as alternative German book name.
3
11
  Add E-Mail address.
@@ -37,7 +37,14 @@ module ConstReader
37
37
  consts.flatten.each do |c|
38
38
  class_exec(c.to_s, c.to_s.downcase) do |c_name, m_name|
39
39
  define_method m_name do
40
- self.singleton_class.const_get c_name
40
+ ivar = '@' << m_name
41
+ if instance_variable_defined? ivar
42
+ return instance_variable_get(ivar)
43
+ else
44
+ val = self.singleton_class.const_get c_name
45
+ instance_variable_set ivar, val
46
+ return val
47
+ end
41
48
  end
42
49
  end
43
50
  end
@@ -50,6 +50,16 @@ module Scripref
50
50
  # Regular expression to parse a reference
51
51
  REFERENCE_RE = /#{pass}(;\s*#{pass})*/o
52
52
 
53
+ # Check if book has only one chapter
54
+ # @param book book as number
55
+ def book_has_only_one_chapter? book
56
+ [31, 63, 64, 65].include?(book)
57
+ end
58
+
59
+ # Generate attr_reader methods for all constants
60
+ extend ConstReader
61
+ const_reader constants
62
+
53
63
  end
54
64
 
55
65
  end
@@ -4,16 +4,13 @@ module Scripref
4
4
 
5
5
  class Formatter
6
6
 
7
+ attr_accessor :cv_separator, :hyphen_separator, :pass_separator
8
+
9
+
7
10
  # @param mods one or more modules to include
8
11
  def initialize *mods
9
12
  @mods = mods
10
- mods.each do |m|
11
- m.class_eval do
12
- extend ConstReader
13
- const_accessor constants
14
- end
15
- extend m
16
- end
13
+ mods.each {|m| extend m}
17
14
  end
18
15
 
19
16
  # Formats a reference (array of passages)
@@ -22,56 +19,64 @@ module Scripref
22
19
  @result = ''
23
20
  reference.flatten.each do |pass|
24
21
  @pass = pass
25
- format_passage
22
+ process_passage
26
23
  end
27
24
  @result
28
25
  end
29
26
 
30
- def format_passage
31
- @changed = false
32
- format_b1
33
- end
34
-
35
27
  def format_book num
36
28
  Array(book_names[num - 1]).first
37
29
  end
38
30
 
39
- def format_b1
31
+ private
32
+
33
+ def process_passage
34
+ @changed = false
35
+ process_b1
36
+ end
37
+
38
+ def process_b1
40
39
  b1 = @pass.b1
41
40
  if @last_b != b1
42
41
  @result << format_book(b1)
43
42
  @last_b = b1
44
43
  @changed = true
45
44
  end
46
- format_c1
45
+ process_c1
47
46
  end
48
47
 
49
- def format_c1
48
+ def process_c1
50
49
  c1 = @pass.c1
51
50
  if c1 && (@changed || @last_c != c1)
52
51
  @result << ' '
53
- if ! Scripref.book_has_only_one_chapter?(@pass.b1)
52
+ if ! book_has_only_one_chapter?(@pass.b1)
54
53
  @result << c1.to_s
55
54
  end
56
55
  @last_c = c1
57
56
  @changed = true
58
57
  end
59
- format_v1
58
+ process_v1
60
59
  end
61
60
 
62
- def format_v1
61
+ def process_v1
63
62
  v1 = @pass.v1
64
63
  if v1 && (@changed || @last_v != v1)
65
- if ! Scripref.book_has_only_one_chapter?(@pass.b1)
64
+ if ! book_has_only_one_chapter?(@pass.b1)
66
65
  @result << cv_separator
67
66
  end
68
67
  @result << v1.to_s
69
68
  @last_v = v1
69
+ process_a1
70
70
  end
71
- format_b2
71
+ process_b2
72
72
  end
73
73
 
74
- def format_b2
74
+ def process_a1
75
+ a1 = @pass.a1
76
+ @result << a1.to_s if a1
77
+ end
78
+
79
+ def process_b2
75
80
  @changed = false
76
81
  @hyphen = false
77
82
  b2 = @pass.b2
@@ -82,10 +87,10 @@ module Scripref
82
87
  @changed = true
83
88
  @hyphen = true
84
89
  end
85
- format_c2
90
+ process_c2
86
91
  end
87
92
 
88
- def format_c2
93
+ def process_c2
89
94
  c2 = @pass.c2
90
95
  if c2 && (@changed || @last_c != c2)
91
96
  if @hyphen
@@ -94,20 +99,20 @@ module Scripref
94
99
  @result << hyphen_separator
95
100
  @hyphen = true
96
101
  end
97
- if ! Scripref.book_has_only_one_chapter?(@pass.b2)
102
+ if ! book_has_only_one_chapter?(@pass.b2)
98
103
  @result << c2.to_s
99
104
  end
100
105
  @last_c = c2
101
106
  @changed = true
102
107
  end
103
- format_v2
108
+ process_v2
104
109
  end
105
110
 
106
- def format_v2
111
+ def process_v2
107
112
  v2 = @pass.v2
108
113
  if v2 && (@changed || @last_v != v2)
109
114
  if @hyphen
110
- if ! Scripref.book_has_only_one_chapter?(@pass.b2)
115
+ if ! book_has_only_one_chapter?(@pass.b2)
111
116
  @result << cv_separator
112
117
  end
113
118
  else
@@ -117,9 +122,15 @@ module Scripref
117
122
  @result << v2.to_s
118
123
  @last_v = @v2
119
124
  @changed = true
125
+ process_a2
120
126
  end
121
127
  end
122
128
 
129
+ def process_a2
130
+ a2 = @pass.a2
131
+ @result << a2.to_s if a2
132
+ end
133
+
123
134
  alias << format
124
135
 
125
136
  end
@@ -47,6 +47,19 @@ module Scripref
47
47
  # Regular expression to parse a reference
48
48
  REFERENCE_RE = /#{pass}(;\s*#{pass})*/o
49
49
 
50
+ # Check if book has only one chapter
51
+ # @param book book as number
52
+ def book_has_only_one_chapter? book
53
+ [31, 63, 64, 65].include?(book)
54
+ end
55
+
56
+ # Hash with special abbreviations
57
+ SPECIAL_ABBREV_MAPPING = {'Phil' => 'Philipper'}
58
+
59
+ # Generate attr_reader methods for all constants
60
+ extend ConstReader
61
+ const_reader constants
62
+
50
63
  end
51
64
 
52
65
  end
@@ -7,18 +7,29 @@ module Scripref
7
7
 
8
8
  attr_reader :error
9
9
 
10
- NUMBER_RE = /\d+\s*/
10
+ NUMBER_RE = /\d+\s*/o
11
11
 
12
12
  # @param mods one or more modules to include
13
13
  def initialize *mods
14
14
  @mods = mods
15
- mods.each do |m|
16
- m.class_eval do
17
- extend ConstReader
18
- const_reader constants
19
- end
20
- extend m
21
- end
15
+ mods.each {|m| extend m}
16
+ end
17
+
18
+ # Regular expression to match a chapter
19
+ def chapter_re
20
+ NUMBER_RE
21
+ end
22
+
23
+ # Regular expression to match a verse
24
+ def verse_re
25
+ NUMBER_RE
26
+ end
27
+
28
+ # Hash with special abbreviations
29
+ # for example {'Phil' => 'Philipper'}
30
+ # usual overwritten in Mixins
31
+ def special_abbrev_mapping
32
+ Hash.new
22
33
  end
23
34
 
24
35
  # Parsing a string of a scripture reference
@@ -42,12 +53,12 @@ module Scripref
42
53
  @text << s
43
54
  @b1 = @b2 = abbrev2num(s)
44
55
 
45
- if check(Regexp.new(NUMBER_RE.source + cv_sep_re.source))
56
+ if check(Regexp.new(chapter_re.source + cv_sep_re.source))
46
57
  @c1 = @v1 = nil
47
58
  @c2 = @v2 = nil
48
59
  c1
49
60
  else
50
- if Scripref.book_has_only_one_chapter?(@b1)
61
+ if book_has_only_one_chapter?(@b1)
51
62
  @c1 = @c2 = 1
52
63
  epsilon or (hyphen and b2) or v1 or give_up 'EOS or hyphen and book or verse expected!'
53
64
  else
@@ -60,7 +71,7 @@ module Scripref
60
71
 
61
72
  # try parse first chapter
62
73
  def c1
63
- s = scan(NUMBER_RE) or return nil
74
+ s = scan(chapter_re) or return nil
64
75
  @text << s
65
76
  @c1 = @c2 = s.to_i
66
77
 
@@ -77,7 +88,7 @@ module Scripref
77
88
 
78
89
  # try to parse first verse
79
90
  def v1
80
- s = scan(NUMBER_RE) or return nil
91
+ s = scan(verse_re) or return nil
81
92
  @text << s
82
93
  @v1 = @v2 = s.to_i
83
94
 
@@ -92,7 +103,7 @@ module Scripref
92
103
 
93
104
  if hyphen
94
105
  b2 or (
95
- if check(Regexp.new(NUMBER_RE.source + cv_sep_re.source))
106
+ if check(Regexp.new(chapter_re.source + cv_sep_re.source))
96
107
  c2
97
108
  else
98
109
  v2 or give_up 'Chapter or verse expected!'
@@ -113,10 +124,10 @@ module Scripref
113
124
  @b2 = abbrev2num(s)
114
125
  @c2 = @v2 = nil
115
126
 
116
- if check(Regexp.new(NUMBER_RE.source + cv_sep_re.source))
127
+ if check(Regexp.new(chapter_re.source + cv_sep_re.source))
117
128
  c2
118
129
  else
119
- if Scripref.book_has_only_one_chapter?(@b2)
130
+ if book_has_only_one_chapter?(@b2)
120
131
  @c2 = 1
121
132
  epsilon or v2 or give_up 'EOS or chapter or verse expected!'
122
133
  else
@@ -127,7 +138,7 @@ module Scripref
127
138
 
128
139
  # try to parse second chapter
129
140
  def c2
130
- s = scan(NUMBER_RE) or return nil
141
+ s = scan(chapter_re) or return nil
131
142
  @text << s
132
143
  @c2 = s.to_i
133
144
 
@@ -140,7 +151,7 @@ module Scripref
140
151
 
141
152
  # try to parse second verse
142
153
  def v2
143
- s = scan(NUMBER_RE) or return nil
154
+ s = scan(verse_re) or return nil
144
155
  @text << s
145
156
  @v2 = s.to_i
146
157
 
@@ -241,11 +252,18 @@ module Scripref
241
252
  end
242
253
 
243
254
  def abbrev2book str
255
+ s = str.strip
256
+ if name = special_abbrev_mapping[s]
257
+ return name
258
+ end
244
259
  @books_str ||= ('#' << book_names.flatten.join('#') << '#')
245
- pattern = str.strip.chars.map {|c| Regexp.escape(c) << '[^#]*'}.join
260
+ pattern = s.chars.map {|c| Regexp.escape(c) << '[^#]*'}.join
246
261
  re = /(?<=#)#{pattern}(?=#)/
247
262
  names = @books_str.scan(re)
248
- give_up format("Abbreviation %s is ambiguous it matches %s!", str, names.join(', ')) unless names.size == 1
263
+ if names.size != 1
264
+ unscan
265
+ give_up format("Abbreviation %s is ambiguous it matches %s!", s, names.join(', '))
266
+ end
249
267
  names.first
250
268
  end
251
269
 
@@ -15,9 +15,7 @@ module Scripref
15
15
  def initialize text=nil, *mods
16
16
  @text = text
17
17
  @mods = mods
18
- mods.each do |m|
19
- extend m
20
- end
18
+ mods.each {|m| extend m}
21
19
  @parser = Parser.new(*mods)
22
20
  end
23
21
 
data/lib/scripref.rb CHANGED
@@ -8,7 +8,7 @@ require 'scripref/german'
8
8
 
9
9
  module Scripref
10
10
 
11
- VERSION = '0.7.1'
11
+ VERSION = '0.8.0'
12
12
 
13
13
  Passage = Struct.new(:text, :b1, :c1, :v1, :b2, :c2, :v2, :a1, :a2) do
14
14
 
@@ -39,9 +39,4 @@ module Scripref
39
39
  class PassSep < Sep; end
40
40
  class VerseSep < Sep; end
41
41
 
42
- # check if the book has only one chapter
43
- def self.book_has_only_one_chapter? book
44
- [31, 63, 64, 65].include?(book)
45
- end
46
-
47
42
  end
@@ -89,7 +89,7 @@ class TestFormatter < Test::Unit::TestCase
89
89
  check_formatting
90
90
  end
91
91
 
92
- def test_changed_hyphen_separator
92
+ def test_attr_writer_overrides_value_of_mixin
93
93
  @german = '1. Korinther 1,1 - 2. Korinther 13,13'
94
94
  @english = '1 Corinthians 1:1 - 2 Corinthians 13:13'
95
95
  @german_formatter.hyphen_separator = ' - '
@@ -102,6 +102,24 @@ class TestFormatter < Test::Unit::TestCase
102
102
  assert_equal 'Zefanja 1,8', @german_formatter.format(ast)
103
103
  end
104
104
 
105
+ def test_addon1
106
+ @german = 'Markus 2,4b'
107
+ @english = 'Mark 2:4b'
108
+ check_formatting
109
+ end
110
+
111
+ def test_addon2
112
+ @german = 'Markus 2,2-4b'
113
+ @english = 'Mark 2:2-4b'
114
+ check_formatting
115
+ end
116
+
117
+ def test_both_addons
118
+ @german = 'Markus 2,2b-4a'
119
+ @english = 'Mark 2:2b-4a'
120
+ check_formatting
121
+ end
122
+
105
123
  private
106
124
 
107
125
  def check_formatting
data/test/test_german.rb CHANGED
@@ -36,6 +36,7 @@ class TestGerman < Test::Unit::TestCase
36
36
  assert_book_num 1, '1.Mo'
37
37
  assert_book_num 1, '1M'
38
38
  assert_book_num 40, 'Mat'
39
+ assert_book_num 50, 'Phil'
39
40
  assert_book_num 66, 'Off'
40
41
  end
41
42
 
data/test/test_parser.rb CHANGED
@@ -229,4 +229,28 @@ class TestParser < Test::Unit::TestCase
229
229
  assert_equal formated_error, @parser.format_error
230
230
  end
231
231
 
232
+ def test_error_message_for_unambiguous_book
233
+ text = 'Ruth 2,4; M 3,8'
234
+ begin
235
+ @parser.parse text
236
+ rescue Scripref::ParserError
237
+ end
238
+ assert_match /^Abbreviation M is ambiguous/, @parser.error
239
+ formated_error = "Abbreviation M is ambiguous it matches Micha, Maleachi, Matthäus, Markus!\nRuth 2,4; M 3,8\n ^"
240
+ assert_equal formated_error, @parser.format_error
241
+ end
242
+
243
+ ######################################################################
244
+ # special things
245
+ ######################################################################
246
+
247
+ def test_special_book_abbrev
248
+ # Abbrev "Phil" would technical match "Philipper" and "Philemon"
249
+ # and therefore throw a ParserError because it's ambiguous,
250
+ # but in German the abbrev "Phil" is generally used for "Philipper",
251
+ # so the parser should be able to support such behaviour.
252
+ text = 'Phil 4,4'
253
+ assert_parsed_ast_for_text [pass(text, 50, 4, 4, 50, 4, 4)], text
254
+ end
255
+
232
256
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scripref
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Friedrich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-06 00:00:00.000000000 Z
11
+ date: 2016-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rim