wcc-scripture 0.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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +13 -0
  3. data/Gemfile +17 -0
  4. data/README.md +1 -0
  5. data/Rakefile +10 -0
  6. data/data/esv/1 Chronicles.xml +2414 -0
  7. data/data/esv/1 Corinthians.xml +1162 -0
  8. data/data/esv/1 John.xml +306 -0
  9. data/data/esv/1 Kings.xml +2087 -0
  10. data/data/esv/1 Peter.xml +356 -0
  11. data/data/esv/1 Samuel.xml +2175 -0
  12. data/data/esv/1 Thessalonians.xml +246 -0
  13. data/data/esv/1 Timothy.xml +320 -0
  14. data/data/esv/2 Chronicles.xml +2168 -0
  15. data/data/esv/2 Corinthians.xml +715 -0
  16. data/data/esv/2 John.xml +47 -0
  17. data/data/esv/2 Kings.xml +1955 -0
  18. data/data/esv/2 Peter.xml +170 -0
  19. data/data/esv/2 Samuel.xml +2069 -0
  20. data/data/esv/2 Thessalonians.xml +141 -0
  21. data/data/esv/2 Timothy.xml +239 -0
  22. data/data/esv/3 John.xml +55 -0
  23. data/data/esv/Acts.xml +2717 -0
  24. data/data/esv/Amos.xml +1156 -0
  25. data/data/esv/Colossians.xml +261 -0
  26. data/data/esv/Daniel.xml +1054 -0
  27. data/data/esv/Deuteronomy.xml +2864 -0
  28. data/data/esv/Ecclesiastes.xml +835 -0
  29. data/data/esv/Ephesians.xml +411 -0
  30. data/data/esv/Esther.xml +439 -0
  31. data/data/esv/Exodus.xml +3186 -0
  32. data/data/esv/Ezekiel.xml +3862 -0
  33. data/data/esv/Ezra.xml +723 -0
  34. data/data/esv/Galatians.xml +410 -0
  35. data/data/esv/Genesis.xml +4195 -0
  36. data/data/esv/Habakkuk.xml +430 -0
  37. data/data/esv/Haggai.xml +103 -0
  38. data/data/esv/Hebrews.xml +1075 -0
  39. data/data/esv/Hosea.xml +1420 -0
  40. data/data/esv/Isaiah.xml +8953 -0
  41. data/data/esv/James.xml +298 -0
  42. data/data/esv/Jeremiah.xml +6691 -0
  43. data/data/esv/Job.xml +5792 -0
  44. data/data/esv/Joel.xml +575 -0
  45. data/data/esv/John.xml +2207 -0
  46. data/data/esv/Jonah.xml +184 -0
  47. data/data/esv/Joshua.xml +1721 -0
  48. data/data/esv/Jude.xml +81 -0
  49. data/data/esv/Judges.xml +1781 -0
  50. data/data/esv/Lamentations.xml +1203 -0
  51. data/data/esv/Leviticus.xml +2179 -0
  52. data/data/esv/Luke.xml +3131 -0
  53. data/data/esv/Malachi.xml +162 -0
  54. data/data/esv/Mark.xml +1771 -0
  55. data/data/esv/Matthew.xml +2979 -0
  56. data/data/esv/Micah.xml +854 -0
  57. data/data/esv/Nahum.xml +380 -0
  58. data/data/esv/Nehemiah.xml +1034 -0
  59. data/data/esv/Numbers.xml +3420 -0
  60. data/data/esv/Obadiah.xml +181 -0
  61. data/data/esv/Philemon.xml +81 -0
  62. data/data/esv/Philippians.xml +286 -0
  63. data/data/esv/Proverbs.xml +4931 -0
  64. data/data/esv/Psalms.xml +15591 -0
  65. data/data/esv/Revelation.xml +1453 -0
  66. data/data/esv/Romans.xml +1317 -0
  67. data/data/esv/Ruth.xml +224 -0
  68. data/data/esv/Song of Solomon.xml +948 -0
  69. data/data/esv/Titus.xml +135 -0
  70. data/data/esv/Zechariah.xml +789 -0
  71. data/data/esv/Zephaniah.xml +460 -0
  72. data/data/esv/_notes.text.xml +3983 -0
  73. data/lib/wcc/scripture/esv.rb +326 -0
  74. data/lib/wcc/scripture/exceptions.rb +4 -0
  75. data/lib/wcc/scripture/version.rb +5 -0
  76. data/lib/wcc/scripture.rb +4 -0
  77. data/lib/wcc-scripture.rb +2 -0
  78. data/wcc-scripture.gemspec +29 -0
  79. metadata +162 -0
@@ -0,0 +1,326 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nokogiri'
4
+ require 'pericope'
5
+ require 'forwardable'
6
+ require 'rails-html-sanitizer'
7
+
8
+ class WCC::Scripture::Esv # rubocop:disable Metrics/ClassLength
9
+ attr_reader :parsed_ref
10
+
11
+ DATA_LIB = File.join(__dir__, '../../../data/esv')
12
+
13
+ class Reference
14
+ extend Forwardable
15
+
16
+ SINGLE_CHAPTER_BOOK_REGEX = /^(obadiah|philemon|2 john|3 john|jude)$/i.freeze
17
+
18
+ attr_reader :pericope
19
+ def_delegators :pericope, :ranges, :book_name
20
+
21
+ def initialize(pericope, book_only = false)
22
+ @pericope = pericope
23
+ @book_only = book_only
24
+ end
25
+
26
+ def self.parse(ref)
27
+ if match = SINGLE_CHAPTER_BOOK_REGEX.match(ref)
28
+ # Pericope will resolve the upper range to the actual when 100 is used
29
+ new(Pericope.parse_one("#{match[0]} 1-100"), true)
30
+ elsif pericope = Pericope.parse_one(ref)
31
+ new(pericope)
32
+ end
33
+ end
34
+
35
+ def to_s
36
+ return book_name if @book_only
37
+
38
+ result = pericope.to_s(
39
+ verse_range_separator: '–',
40
+ chapter_range_separator: '–'
41
+ )
42
+
43
+ return result unless book_name == 'Psalm' && range_spans_multiple_chapters?
44
+
45
+ result.gsub('Psalm', 'Psalms')
46
+ end
47
+
48
+ private
49
+
50
+ def range_spans_multiple_chapters?
51
+ range = ranges.first
52
+
53
+ range.begin.chapter != range.end.chapter
54
+ end
55
+ end
56
+
57
+ def initialize(
58
+ reference,
59
+ footnotes: true,
60
+ data_lib: DATA_LIB
61
+ )
62
+ raise WCC::Scripture::ScriptureNotFoundError unless @parsed_ref = Reference.parse(reference)
63
+
64
+ @data_lib = data_lib
65
+ @body_nodes = []
66
+ @footnote_nodes = []
67
+ @display_options = { footnotes: footnotes }
68
+ end
69
+
70
+ def render_html
71
+ parse_nodes
72
+ [
73
+ render_body,
74
+ render_footnotes
75
+ ].join
76
+ end
77
+
78
+ # rubocop:disable Metrics/MethodLength
79
+ # rubocop:disable Metrics/CyclomaticComplexity
80
+ # rubocop:disable Metrics/AbcSize
81
+ def render_body
82
+ marker = nil
83
+ body = []
84
+ para_open = false
85
+
86
+ @body_nodes.each do |node|
87
+ marker = node if verse_marker?(node)
88
+ if node.name == 'heading'
89
+ body.push process_heading(marker, node)
90
+ elsif node.name == 'subheading'
91
+ body.push process_heading(marker, node)
92
+ elsif node.name == 'begin-paragraph'
93
+ if node.attributes['class']&.value == 'line-group'
94
+ body.push('<p class="block-indent">')
95
+ else
96
+ body.push '<p>'
97
+ end
98
+ para_open = true
99
+ elsif node.name == 'end-paragraph'
100
+ body.push '</p>'
101
+ para_open = false
102
+ elsif node.name == 'verse'
103
+ unless para_open
104
+ body.push '<p>'
105
+ para_open = true
106
+ end
107
+ body.push process_verse(marker, node)
108
+ end
109
+ end
110
+
111
+ # In case verse range didn't include end-paragraph
112
+ body.push('</p>') if para_open
113
+
114
+ body.compact.join
115
+ end
116
+ # rubocop:enable Metrics/MethodLength
117
+ # rubocop:enable Metrics/CyclomaticComplexity
118
+ # rubocop:enable Metrics/AbcSize
119
+
120
+ def render_footnotes
121
+ return '' if @footnote_nodes.empty? || !@display_options[:footnotes]
122
+
123
+ <<~HTML
124
+ <div class="footnotes extra_text">
125
+ <h3>Footnotes</h3>
126
+ #{@footnote_nodes.join('<br/>')}
127
+ </div>
128
+ HTML
129
+ end
130
+
131
+ def convert_node(node, name, css = nil)
132
+ Nokogiri::XML::Node.new(name, book_xml).tap do |heading|
133
+ heading['class'] = css || node['class'] if css || node['class']
134
+ heading.children = node.children
135
+ end
136
+ end
137
+
138
+ def parse_nodes
139
+ @parsed_ref.ranges.each do |range|
140
+ first, *_, last = range.to_a
141
+
142
+ link_traverse(last || first, book_xml.at_css("marker.begin-verse[mid*=\"#{first.to_id}\"]"))
143
+ end
144
+ end
145
+
146
+ def link_traverse(bounds, node = nil)
147
+ return unless node
148
+ return if out_of_bounds?(bounds, node)
149
+
150
+ @body_nodes.push(node) if node.name =~ /marker|heading|paragraph|verse/
151
+
152
+ link_traverse(bounds, node.first_element_child) if node.name == 'chapter'
153
+ link_traverse(bounds, node.next)
154
+ end
155
+
156
+ def process_heading(marker, node)
157
+ heading = convert_node(node, node.name == 'heading' ? 'h3' : 'h4')
158
+
159
+ preprocess(heading)
160
+
161
+ parse_footnotes(marker, heading)
162
+
163
+ postprocess(heading.to_xml)
164
+ end
165
+
166
+ def process_verse(marker_node, verse_node)
167
+ preprocess(verse_node)
168
+ parse_footnotes(marker_node, verse_node)
169
+
170
+ [
171
+ %(<b class="verse-num">#{verse_node.attributes['num'].value}&nbsp;</b>),
172
+ # We have to replace these strings in this fashion instead of using Nokogiri because the source markup
173
+ # is not well-formed. The nodes do not encapsulate the text and children they are intending to designate as children,
174
+ # but instead self-closing which presents a parsing nightmare. In an ideal world, we would be able to replace the
175
+ # pseudo-html markup with real html and be done, but alas. So, for now, this post-processing step is acheived by
176
+ # string replacement.
177
+ #
178
+ # Nokogiri HTML Serialization Options
179
+ # 2 - exclude XML Declaration tag
180
+ # 32 - output XML - prevents Nokogiri from closing our tags for us
181
+ #
182
+ # No option passed would assume HTML options, and disrupt our markup scheme, producing something like:
183
+ # '<begin-line/>' => '<begin-line></begin-line>'
184
+ postprocess(verse_node.inner_html(save_with: 2 | 32)),
185
+ ' '
186
+ ].join
187
+ end
188
+
189
+ def preprocess(node)
190
+ node.tap do |n|
191
+ n.search('crossref, crossrefs, begin-block-indent, end-block-indent, q.continue-double').remove
192
+ translate_quotes(n)
193
+ n.search('heading, subheading').each { |h| h.replace(convert_node(h, node.name == 'heading' ? 'h3' : 'h4')) }
194
+ n.search('span.divine-name').each { |q| q.replace('LORD') }
195
+ n.search('woc, selah').each { |span| span.replace(convert_node(span, 'span', span.name)) }
196
+ end
197
+ end
198
+
199
+ # (
200
+ # begin-double|continue-double|end-double
201
+ # begin-inner-double|continue-inner-double|end-inner-double
202
+ # begin-single|continue-single|end-single
203
+ # begin-inner-single|end-inner-single
204
+ # )
205
+ def translate_quotes(node)
206
+ node.tap do |n|
207
+ n.search('q.begin-double, q.continue-double, q.begin-inner-double, q.continue-inner-double')
208
+ .each { |q| q.replace('&#x201C;') }
209
+ n.search('q.end-double, q.end-inner-double').each { |q| q.replace('&#x201D;') }
210
+ n.search('q.begin-single, q.continue-single, q.begin-inner-single').each { |q| q.replace('&#x2018;') }
211
+ n.search('q.end-single, q.end-inner-single').each { |q| q.replace('&#x2019;') }
212
+ end
213
+ end
214
+
215
+ def postprocess(markup)
216
+ translate_entities(
217
+ translate_pseudo_markup(
218
+ markup
219
+ )
220
+ )
221
+ end
222
+
223
+ def translate_pseudo_markup(markup)
224
+ markup
225
+ .gsub(%r{<begin-paragraph class="line-group"/>}, '<p class="block-indent">')
226
+ .gsub(%r{<begin-paragraph(?:\s+class=".+")?/>}, '<p>')
227
+ .gsub(%r{<end-paragraph/>}, '</p>')
228
+ .gsub(%r{<end-line(?:\s+class=".+")?/>}, '</span><br/>')
229
+ .gsub(%r{<begin-line\s?/>}, '<span class="line">')
230
+ .gsub(%r{<begin-line\s+class="(.+)"/>}, '<span class="line \1">&nbsp;&nbsp;&nbsp;&nbsp;')
231
+ end
232
+
233
+ def translate_entities(markup)
234
+ markup
235
+ .gsub('&ldblquot;', '&#8220;')
236
+ .gsub('&rdblquot;', '&#8221;')
237
+ .gsub('&lquot;', '&#8216;')
238
+ .gsub('&rquot;', '&#8217;')
239
+ .gsub('&apos;', '&#8217;')
240
+ .gsub('&emdash;', '&#8212;')
241
+ .gsub('&endash;', '&#8211;')
242
+ .gsub('&ellipsis;', '&nbsp;.&nbsp;.&nbsp;.')
243
+ .gsub('&ellipsis4;', '.&nbsp;.&nbsp;.&nbsp;.')
244
+ end
245
+
246
+ def parse_footnotes(marker, node)
247
+ notes = node.search('note')
248
+
249
+ return if notes.empty?
250
+ return notes.remove unless @display_options[:footnotes]
251
+
252
+ notes.each do |note|
253
+ footnote_node = note_xml.at_css("note[id=\"#{note.attributes['nid'].value}\"]")
254
+
255
+ if footnote_node
256
+ footnote_id = @footnote_nodes.size + 1
257
+ @footnote_nodes.push(
258
+ footnote(marker, footnote_node, footnote_id)
259
+ )
260
+ note.replace(
261
+ footnote_anchor(footnote_node, footnote_id)
262
+ )
263
+ else
264
+ note.remove
265
+ end
266
+ end
267
+ end
268
+
269
+ FULL_SANITIZER = Rails::Html::FullSanitizer.new
270
+
271
+ def footnote_anchor(note_node, id)
272
+ <<~HTML
273
+ <sup class="footnote">
274
+ <a class="fn" href="#f#{id}-1" id="fb#{id}-1" title="#{FULL_SANITIZER.sanitize(note_node.inner_html)}">#{id}</a>
275
+ </sup>
276
+ HTML
277
+ end
278
+
279
+ def footnote(marker, note_node, id)
280
+ preprocess(note_node)
281
+
282
+ verse_ref = Pericope::Verse.parse(marker_numeric_value(marker))
283
+
284
+ postprocess(<<~HTML)
285
+ <span class="footnote">
286
+ <a href="#fb#{id}-1" id="f#{id}-1">[#{id}]</a>
287
+ </span>
288
+ <span class="footnote-ref">#{verse_ref.to_s(with_chapter: true)}</span>
289
+ #{note_node}
290
+ HTML
291
+ end
292
+
293
+ def out_of_bounds?(bounds, node)
294
+ return unless verse_marker?(node)
295
+
296
+ bounds.to_i < marker_numeric_value(node)
297
+ end
298
+
299
+ def verse_marker?(node)
300
+ node.name == 'marker' && node.attributes['class'].value == 'begin-verse'
301
+ end
302
+
303
+ def marker_numeric_value(node)
304
+ node.attributes['mid'].value.sub(/^v/, '').to_i
305
+ end
306
+
307
+ XML_LOOKUP = {
308
+ 'Psalm' => 'Psalms'
309
+ }.freeze
310
+
311
+ def self.lookup_xml(book_name, data_lib = DATA_LIB)
312
+ Nokogiri::XML(
313
+ File.open(File.join(data_lib, "#{XML_LOOKUP.fetch(book_name, book_name)}.xml")),
314
+ &:huge
315
+ )
316
+ end
317
+
318
+ def book_xml
319
+ @book_xml ||= self.class.lookup_xml(@parsed_ref.book_name, @data_lib)
320
+ end
321
+
322
+ def note_xml
323
+ @note_xml ||=
324
+ Nokogiri::XML(File.open(File.join(@data_lib, '_notes.text.xml')), &:huge)
325
+ end
326
+ end
@@ -0,0 +1,4 @@
1
+ module WCC::Scripture
2
+ class ScriptureNotFoundError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module WCC
2
+ module Scripture
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+
2
+ require_relative './scripture/version'
3
+ require_relative './scripture/exceptions'
4
+ require_relative './scripture/esv'
@@ -0,0 +1,2 @@
1
+
2
+ require_relative './wcc/scripture'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'wcc/scripture/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'wcc-scripture'
9
+ spec.version = WCC::Scripture::VERSION
10
+ spec.authors = ['Watermark Dev']
11
+ spec.email = ['dev@watermark.org']
12
+
13
+ spec.summary = File.readlines(File.expand_path('README.md', __dir__)).join
14
+ spec.description = ''
15
+ spec.license = 'Not licensed for external use'
16
+
17
+ spec.required_ruby_version = '>= 2.3'
18
+
19
+ spec.files =
20
+ `git ls-files -z`.split("\x0").reject do |f|
21
+ f.match(%r{^(test|spec|features)/})
22
+ end
23
+
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_runtime_dependency 'nokogiri', '>= 1.0'
27
+ spec.add_runtime_dependency 'pericope', '>= 1.0'
28
+ spec.add_runtime_dependency 'rails-html-sanitizer', '>= 1.0'
29
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wcc-scripture
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Watermark Dev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pericope
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails-html-sanitizer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ description: ''
56
+ email:
57
+ - dev@watermark.org
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rubocop.yml"
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - data/esv/1 Chronicles.xml
67
+ - data/esv/1 Corinthians.xml
68
+ - data/esv/1 John.xml
69
+ - data/esv/1 Kings.xml
70
+ - data/esv/1 Peter.xml
71
+ - data/esv/1 Samuel.xml
72
+ - data/esv/1 Thessalonians.xml
73
+ - data/esv/1 Timothy.xml
74
+ - data/esv/2 Chronicles.xml
75
+ - data/esv/2 Corinthians.xml
76
+ - data/esv/2 John.xml
77
+ - data/esv/2 Kings.xml
78
+ - data/esv/2 Peter.xml
79
+ - data/esv/2 Samuel.xml
80
+ - data/esv/2 Thessalonians.xml
81
+ - data/esv/2 Timothy.xml
82
+ - data/esv/3 John.xml
83
+ - data/esv/Acts.xml
84
+ - data/esv/Amos.xml
85
+ - data/esv/Colossians.xml
86
+ - data/esv/Daniel.xml
87
+ - data/esv/Deuteronomy.xml
88
+ - data/esv/Ecclesiastes.xml
89
+ - data/esv/Ephesians.xml
90
+ - data/esv/Esther.xml
91
+ - data/esv/Exodus.xml
92
+ - data/esv/Ezekiel.xml
93
+ - data/esv/Ezra.xml
94
+ - data/esv/Galatians.xml
95
+ - data/esv/Genesis.xml
96
+ - data/esv/Habakkuk.xml
97
+ - data/esv/Haggai.xml
98
+ - data/esv/Hebrews.xml
99
+ - data/esv/Hosea.xml
100
+ - data/esv/Isaiah.xml
101
+ - data/esv/James.xml
102
+ - data/esv/Jeremiah.xml
103
+ - data/esv/Job.xml
104
+ - data/esv/Joel.xml
105
+ - data/esv/John.xml
106
+ - data/esv/Jonah.xml
107
+ - data/esv/Joshua.xml
108
+ - data/esv/Jude.xml
109
+ - data/esv/Judges.xml
110
+ - data/esv/Lamentations.xml
111
+ - data/esv/Leviticus.xml
112
+ - data/esv/Luke.xml
113
+ - data/esv/Malachi.xml
114
+ - data/esv/Mark.xml
115
+ - data/esv/Matthew.xml
116
+ - data/esv/Micah.xml
117
+ - data/esv/Nahum.xml
118
+ - data/esv/Nehemiah.xml
119
+ - data/esv/Numbers.xml
120
+ - data/esv/Obadiah.xml
121
+ - data/esv/Philemon.xml
122
+ - data/esv/Philippians.xml
123
+ - data/esv/Proverbs.xml
124
+ - data/esv/Psalms.xml
125
+ - data/esv/Revelation.xml
126
+ - data/esv/Romans.xml
127
+ - data/esv/Ruth.xml
128
+ - data/esv/Song of Solomon.xml
129
+ - data/esv/Titus.xml
130
+ - data/esv/Zechariah.xml
131
+ - data/esv/Zephaniah.xml
132
+ - data/esv/_notes.text.xml
133
+ - lib/wcc-scripture.rb
134
+ - lib/wcc/scripture.rb
135
+ - lib/wcc/scripture/esv.rb
136
+ - lib/wcc/scripture/exceptions.rb
137
+ - lib/wcc/scripture/version.rb
138
+ - wcc-scripture.gemspec
139
+ homepage:
140
+ licenses:
141
+ - Not licensed for external use
142
+ metadata: {}
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '2.3'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubygems_version: 3.0.3
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: Internal Watermark.org gem, not licensed for external use.
162
+ test_files: []