iev 0.3.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +3 -20
- data/.github/workflows/release.yml +25 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +0 -2
- data/README.adoc +4 -4
- data/exe/iev-glossarist +21 -0
- data/iev.gemspec +12 -3
- data/lib/iev/cli/command.rb +109 -0
- data/lib/iev/cli/command_helper.rb +83 -0
- data/lib/iev/cli/ui.rb +70 -0
- data/lib/iev/cli.rb +22 -0
- data/lib/iev/converter/mathml_to_asciimath.rb +197 -0
- data/lib/iev/converter.rb +9 -0
- data/lib/iev/data_conversions.rb +39 -0
- data/lib/iev/db.rb +3 -3
- data/lib/iev/db_cache.rb +2 -2
- data/lib/iev/db_writer.rb +81 -0
- data/lib/iev/iso_639_2.yaml +4075 -0
- data/lib/iev/iso_639_code.rb +47 -0
- data/lib/iev/profiler.rb +69 -0
- data/lib/iev/relaton_db.rb +63 -0
- data/lib/iev/source_parser.rb +350 -0
- data/lib/iev/supersession_parser.rb +70 -0
- data/lib/iev/term_attrs_parser.rb +143 -0
- data/lib/iev/term_builder.rb +313 -0
- data/lib/iev/utilities.rb +58 -0
- data/lib/iev/version.rb +2 -2
- data/lib/iev.rb +24 -2
- metadata +153 -10
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) Copyright 2020 Ribose Inc.
|
4
|
+
#
|
5
|
+
|
6
|
+
module IEV
|
7
|
+
# Parses information from the spreadsheet's TERMATTRIBUTE column and alike.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# parser = TermAttrsParser.new(cell_data_string)
|
11
|
+
# parser.gender # returns grammatical gender
|
12
|
+
# parser.plurality # returns grammatical plurality
|
13
|
+
# parser.part_of_speech # returns part of speech
|
14
|
+
class TermAttrsParser
|
15
|
+
include CLI::UI
|
16
|
+
using DataConversions
|
17
|
+
|
18
|
+
attr_reader :raw_str, :src_str
|
19
|
+
|
20
|
+
attr_reader :gender, :geographical_area, :part_of_speech, :plurality,
|
21
|
+
:prefix, :usage_info
|
22
|
+
|
23
|
+
PARTS_OF_SPEECH = {
|
24
|
+
"adj" => "adj",
|
25
|
+
"noun" => "noun",
|
26
|
+
"verb" => "verb",
|
27
|
+
"名詞" => "noun",
|
28
|
+
"動詞" => "verb",
|
29
|
+
"形容詞" => "adj",
|
30
|
+
"형용사" => "adj",
|
31
|
+
"Adjektiv" => "adj",
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
PREFIX_KEYWORDS = %w[
|
35
|
+
Präfix prefix préfixe 接尾語 접두사 przedrostek prefixo 词头
|
36
|
+
].freeze
|
37
|
+
|
38
|
+
def initialize(attr_str)
|
39
|
+
@raw_str = attr_str.dup.freeze
|
40
|
+
@src_str = decode_attrs_string(raw_str).freeze
|
41
|
+
parse
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
"<ATTRIBUTES: #{src_str}>".freeze
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def parse
|
51
|
+
curr_str = src_str.dup
|
52
|
+
|
53
|
+
extract_gender(curr_str)
|
54
|
+
extract_plurality(curr_str)
|
55
|
+
extract_geographical_area(curr_str)
|
56
|
+
extract_part_of_speech(curr_str)
|
57
|
+
extract_usage_info(curr_str)
|
58
|
+
extract_prefix(curr_str)
|
59
|
+
|
60
|
+
if /\p{Word}/ =~ curr_str
|
61
|
+
debug(
|
62
|
+
:term_attributes,
|
63
|
+
"Term attributes could not be parsed completely: '#{src_str}'",
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def extract_gender(str)
|
69
|
+
gender_rx = /\b[mfn]\b/
|
70
|
+
|
71
|
+
@gender = remove_from_string(str, gender_rx)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Must happen after #extract_gender
|
75
|
+
def extract_plurality(str)
|
76
|
+
plural_rx = /\bpl\b/
|
77
|
+
|
78
|
+
if remove_from_string(str, plural_rx)
|
79
|
+
@plurality = "plural"
|
80
|
+
elsif !gender.nil?
|
81
|
+
# TODO Really needed?
|
82
|
+
@plurality = "singular"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# TODO this is likely buggy
|
87
|
+
def extract_geographical_area(str)
|
88
|
+
ga_rx = /\b[A-Z]{2}$/
|
89
|
+
|
90
|
+
@geographical_area = remove_from_string(str, ga_rx)
|
91
|
+
end
|
92
|
+
|
93
|
+
def extract_part_of_speech(str)
|
94
|
+
pos_rx = %r{
|
95
|
+
\b
|
96
|
+
#{Regexp.union(PARTS_OF_SPEECH.keys)}
|
97
|
+
\b
|
98
|
+
}x.freeze
|
99
|
+
|
100
|
+
removed = remove_from_string(str, pos_rx)
|
101
|
+
@part_of_speech = PARTS_OF_SPEECH[removed] || removed
|
102
|
+
end
|
103
|
+
|
104
|
+
def extract_usage_info(str)
|
105
|
+
info_rx = %r{
|
106
|
+
# regular ASCII less and greater than signs
|
107
|
+
< (?<inner>.*?) >
|
108
|
+
|
|
109
|
+
# < and >, i.e. full-width less and greater than signs
|
110
|
+
# which are used instead of ASCII signs in some CJK terms
|
111
|
+
\uFF1C (?<inner>.*?) \uFF1E
|
112
|
+
}x.freeze
|
113
|
+
|
114
|
+
remove_from_string(str, info_rx) do |md|
|
115
|
+
@usage_info = md[:inner].strip
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def extract_prefix(str)
|
120
|
+
prefix_rx = %r{
|
121
|
+
\b
|
122
|
+
#{Regexp.union(PREFIX_KEYWORDS)}
|
123
|
+
\b
|
124
|
+
}x.freeze
|
125
|
+
|
126
|
+
@prefix = true if remove_from_string(str, prefix_rx)
|
127
|
+
end
|
128
|
+
|
129
|
+
def decode_attrs_string(str)
|
130
|
+
str.decode_html || ""
|
131
|
+
end
|
132
|
+
|
133
|
+
def remove_from_string(string, regexp)
|
134
|
+
string.sub!(regexp, "")
|
135
|
+
|
136
|
+
if $~ && block_given?
|
137
|
+
yield $~
|
138
|
+
else
|
139
|
+
$& # removed substring or nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) Copyright 2020 Ribose Inc.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "pp"
|
7
|
+
|
8
|
+
module IEV
|
9
|
+
class TermBuilder
|
10
|
+
include CLI::UI
|
11
|
+
include Utilities
|
12
|
+
using DataConversions
|
13
|
+
|
14
|
+
def initialize(data)
|
15
|
+
@data = data
|
16
|
+
end
|
17
|
+
|
18
|
+
def build
|
19
|
+
build_term_object
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.build_from(data)
|
23
|
+
new(data).build
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :data
|
27
|
+
|
28
|
+
def find_value_for(key)
|
29
|
+
data.fetch(key.to_sym, nil)&.sanitize
|
30
|
+
end
|
31
|
+
|
32
|
+
def flesh_date(incomplete_date)
|
33
|
+
return incomplete_date if incomplete_date.nil? || incomplete_date.empty?
|
34
|
+
|
35
|
+
year, month, day = incomplete_date.split("-")
|
36
|
+
|
37
|
+
month ||= "01"
|
38
|
+
day ||= "01"
|
39
|
+
|
40
|
+
DateTime.parse("#{year}-#{month}-#{day}").to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_term_object
|
44
|
+
set_ui_tag "#{term_id} (#{term_language})"
|
45
|
+
progress "Processing term #{term_id} (#{term_language})..."
|
46
|
+
|
47
|
+
split_definition
|
48
|
+
|
49
|
+
Glossarist::LocalizedConcept.new(term_hash)
|
50
|
+
end
|
51
|
+
|
52
|
+
def term_hash
|
53
|
+
dates = nil
|
54
|
+
|
55
|
+
if flesh_date(find_value_for("PUBLICATIONDATE"))
|
56
|
+
dates = [
|
57
|
+
{
|
58
|
+
type: :accepted,
|
59
|
+
date: flesh_date(find_value_for("PUBLICATIONDATE")),
|
60
|
+
},
|
61
|
+
{
|
62
|
+
type: :amended,
|
63
|
+
date: flesh_date(find_value_for("PUBLICATIONDATE")),
|
64
|
+
},
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
{
|
69
|
+
id: term_id,
|
70
|
+
entry_status: extract_entry_status,
|
71
|
+
classification: extract_classification,
|
72
|
+
dates: dates,
|
73
|
+
review_date: flesh_date(find_value_for("PUBLICATIONDATE")),
|
74
|
+
review_decision_date: flesh_date(find_value_for("PUBLICATIONDATE")),
|
75
|
+
review_decision_event: "published",
|
76
|
+
terms: extract_terms,
|
77
|
+
notes: extract_notes,
|
78
|
+
examples: extract_examples,
|
79
|
+
definition: [{ "content" => extract_definition_value }],
|
80
|
+
sources: extract_authoritative_source,
|
81
|
+
language_code: term_language,
|
82
|
+
related: extract_superseded_concepts,
|
83
|
+
}.compact
|
84
|
+
end
|
85
|
+
|
86
|
+
def term_id
|
87
|
+
@term_id ||= find_value_for("IEVREF")
|
88
|
+
end
|
89
|
+
|
90
|
+
def term_domain
|
91
|
+
@term_domain ||= term_id.slice(0, 3)
|
92
|
+
end
|
93
|
+
|
94
|
+
def term_language
|
95
|
+
@term_language ||= find_value_for("LANGUAGE").to_three_char_code
|
96
|
+
end
|
97
|
+
|
98
|
+
# Splits unified definition (from the spreadsheet) into separate
|
99
|
+
# definition, examples, and notes strings (for YAMLs).
|
100
|
+
#
|
101
|
+
# Sets +@definition+, +@examples+ and +@notes+ variables.
|
102
|
+
def split_definition
|
103
|
+
slicer_rx = %r{
|
104
|
+
\s*
|
105
|
+
(?:<p>\s*)?
|
106
|
+
(
|
107
|
+
(?<example>
|
108
|
+
# English example
|
109
|
+
\bEXAMPLE\b |
|
110
|
+
^\bExamples\s+are\b: |
|
111
|
+
^\bExamples\b: |
|
112
|
+
^\bExample\b: |
|
113
|
+
# French examples
|
114
|
+
\bEXEMPLE\b |
|
115
|
+
^\bExemples\b:
|
116
|
+
)
|
117
|
+
|
|
118
|
+
(?<note>
|
119
|
+
Note\s*\d+\sto\sentry: |
|
120
|
+
Note \d+\sto\sentry: |
|
121
|
+
Note\s*\d+\sto\sthe\sentry: |
|
122
|
+
Note\sto\sentry\s*\d+: |
|
123
|
+
Note\s*\d+?\sà\sl['’]article: |
|
124
|
+
<NOTE\/?>?\s*\d?\s+.*?– |
|
125
|
+
NOTE(?:\s+-)? |
|
126
|
+
Note\s+\d+\s– |
|
127
|
+
Note \d+\s
|
128
|
+
)
|
129
|
+
)
|
130
|
+
\s*
|
131
|
+
}x
|
132
|
+
|
133
|
+
@examples = []
|
134
|
+
@notes = []
|
135
|
+
definition_arr = [] # here array for consistent interface
|
136
|
+
|
137
|
+
next_part_arr = definition_arr
|
138
|
+
remaining_str = find_value_for("DEFINITION")
|
139
|
+
|
140
|
+
while md = remaining_str&.match(slicer_rx)
|
141
|
+
next_part = md.pre_match
|
142
|
+
next_part.sub!(/^\[:Ex(a|e)mple\]/, "Ex\\1mple")
|
143
|
+
next_part_arr.push(next_part)
|
144
|
+
next_part_arr = md[:example] ? @examples : @notes
|
145
|
+
# 112-03-17
|
146
|
+
# supplements the name of a quantity, especially for a component in a
|
147
|
+
# system, to indicate the quotient of that quantity by the total
|
148
|
+
# volume
|
149
|
+
# <NOTE – Examples: amount-of-substance volume concentration of
|
150
|
+
# component B (or concentration of B, in particular, ion
|
151
|
+
# concentration), molecular concentration of B, electron concentration
|
152
|
+
# (or electron density).
|
153
|
+
#
|
154
|
+
# In the above case the `Example` is part of the note but the regex
|
155
|
+
# above will capture it as an example and will add an empty `Note`
|
156
|
+
# and put the rest in an `Example`. So In this case we will replace
|
157
|
+
# the `Example` with `[:Example]` and revert it in the next iteration
|
158
|
+
# so it will not be caught by the regex.
|
159
|
+
remaining_str = md.post_match
|
160
|
+
remaining_str.sub!(/^Ex(a|e)mple/, "[:Ex\\1mple]") if md[:note]
|
161
|
+
end
|
162
|
+
|
163
|
+
remaining_str&.sub!(/^\[:Ex(a|e)mple\]/, "Ex\\1mple")
|
164
|
+
next_part_arr.push(remaining_str)
|
165
|
+
@definition = definition_arr.first
|
166
|
+
@definition = nil if @definition&.empty?
|
167
|
+
end
|
168
|
+
|
169
|
+
def extract_terms
|
170
|
+
[
|
171
|
+
extract_primary_designation,
|
172
|
+
*extract_synonymous_designations,
|
173
|
+
extract_international_symbol_designation,
|
174
|
+
].compact
|
175
|
+
end
|
176
|
+
|
177
|
+
def extract_primary_designation
|
178
|
+
raw_term = find_value_for("TERM")
|
179
|
+
raw_term = "NA" if raw_term == "....."
|
180
|
+
|
181
|
+
build_expression_designation(
|
182
|
+
raw_term,
|
183
|
+
attribute_data: find_value_for("TERMATTRIBUTE"),
|
184
|
+
status: "preferred",
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
def extract_synonymous_designations
|
189
|
+
retval = (1..3).map do |num|
|
190
|
+
designations = find_value_for("SYNONYM#{num}") || ""
|
191
|
+
|
192
|
+
# Some synonyms have more than one entry
|
193
|
+
designations.split(/<[pbr]+>/).map do |raw_term|
|
194
|
+
build_expression_designation(
|
195
|
+
raw_term,
|
196
|
+
attribute_data: find_value_for("SYNONYM#{num}ATTRIBUTE"),
|
197
|
+
status: find_value_for("SYNONYM#{num}STATUS")&.downcase,
|
198
|
+
)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
retval.flatten.compact
|
203
|
+
end
|
204
|
+
|
205
|
+
def extract_international_symbol_designation
|
206
|
+
raw_term = find_value_for("SYMBOLE")
|
207
|
+
raw_term && build_symbol_designation(raw_term)
|
208
|
+
end
|
209
|
+
|
210
|
+
def extract_definition_value
|
211
|
+
if @definition
|
212
|
+
IEV::Converter.mathml_to_asciimath(
|
213
|
+
replace_newlines(parse_anchor_tag(@definition, term_domain)),
|
214
|
+
).strip
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def extract_examples
|
219
|
+
@examples.map do |str|
|
220
|
+
IEV::Converter.mathml_to_asciimath(
|
221
|
+
replace_newlines(parse_anchor_tag(str, term_domain)),
|
222
|
+
).strip
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def extract_notes
|
227
|
+
@notes.map do |str|
|
228
|
+
IEV::Converter.mathml_to_asciimath(
|
229
|
+
replace_newlines(parse_anchor_tag(str, term_domain)),
|
230
|
+
).strip
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def extract_entry_status
|
235
|
+
case find_value_for("STATUS").downcase
|
236
|
+
when "standard" then "valid"
|
237
|
+
else nil
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def extract_classification
|
242
|
+
classification_val = find_value_for("SYNONYM1STATUS")
|
243
|
+
|
244
|
+
case classification_val
|
245
|
+
when ""
|
246
|
+
"admitted"
|
247
|
+
when "认可的", "допустимый", "admitido"
|
248
|
+
"admitted"
|
249
|
+
when "首选的", "suositettava", "suositeltava", "рекомендуемый", "preferente"
|
250
|
+
"preferred"
|
251
|
+
else
|
252
|
+
classification_val
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def extract_authoritative_source
|
257
|
+
source_val = find_value_for("SOURCE")
|
258
|
+
return nil if source_val.nil?
|
259
|
+
|
260
|
+
SourceParser.new(source_val, term_domain)
|
261
|
+
.parsed_sources
|
262
|
+
.compact
|
263
|
+
.map do |source|
|
264
|
+
source.merge({ "type" => "authoritative" })
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def extract_superseded_concepts
|
269
|
+
replaces_val = find_value_for("REPLACES")
|
270
|
+
return nil if replaces_val.nil?
|
271
|
+
|
272
|
+
SupersessionParser.new(replaces_val).supersessions
|
273
|
+
end
|
274
|
+
|
275
|
+
private
|
276
|
+
|
277
|
+
def build_expression_designation(raw_term, attribute_data:, status:)
|
278
|
+
term = IEV::Converter.mathml_to_asciimath(
|
279
|
+
parse_anchor_tag(raw_term, term_domain),
|
280
|
+
)
|
281
|
+
term_attributes = TermAttrsParser.new(attribute_data.to_s)
|
282
|
+
|
283
|
+
statuses = {
|
284
|
+
"obsoleto" => "deprecated",
|
285
|
+
"напуштен" => "deprecated",
|
286
|
+
}
|
287
|
+
|
288
|
+
{
|
289
|
+
"type" => "expression",
|
290
|
+
"prefix" => term_attributes.prefix,
|
291
|
+
"normative_status" => statuses[status] || status,
|
292
|
+
"usage_info" => term_attributes.usage_info,
|
293
|
+
"designation" => term,
|
294
|
+
"part_of_speech" => term_attributes.part_of_speech,
|
295
|
+
"geographical_area" => term_attributes.geographical_area,
|
296
|
+
"gender" => term_attributes.gender,
|
297
|
+
"plurality" => term_attributes.plurality,
|
298
|
+
}.compact
|
299
|
+
end
|
300
|
+
|
301
|
+
def build_symbol_designation(raw_term)
|
302
|
+
term = IEV::Converter.mathml_to_asciimath(
|
303
|
+
parse_anchor_tag(raw_term, term_domain),
|
304
|
+
)
|
305
|
+
|
306
|
+
{
|
307
|
+
"type" => "symbol",
|
308
|
+
"designation" => term,
|
309
|
+
"international" => true,
|
310
|
+
}.compact
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IEV
|
4
|
+
module Utilities
|
5
|
+
SIMG_PATH_REGEX = "<simg .*\\/\\$file\\/([\\d\\-\\w\.]+)>"
|
6
|
+
FIGURE_ONE_REGEX =
|
7
|
+
"<p><b>\\s*Figure\\s+(\\d)\\s+[–-]\\s+(.+)\\s*<\\/b>(<\\/p>)?"
|
8
|
+
FIGURE_TWO_REGEX = "#{FIGURE_ONE_REGEX}\\s*#{FIGURE_ONE_REGEX}"
|
9
|
+
IMAGE_PATH_PREFIX = "image::/assets/images/parts"
|
10
|
+
|
11
|
+
def parse_anchor_tag(text, term_domain)
|
12
|
+
if text
|
13
|
+
# Convert IEV term references
|
14
|
+
# Convert href links
|
15
|
+
# Need to take care of this pattern:
|
16
|
+
# `inverse de la <a href="IEV103-06-01">période<a>`
|
17
|
+
text.gsub(
|
18
|
+
/<a href="?(IEV)\s*(\d\d\d-\d\d-\d\d\d?)"?>(.*?)<\/?a>/,
|
19
|
+
'{{\3, \1:\2}}',
|
20
|
+
).gsub(
|
21
|
+
/<a href="?\s*(\d\d\d-\d\d-\d\d\d?)"?>(.*?)<\/?a>/,
|
22
|
+
'{{\3, IEV:\2}}',
|
23
|
+
).gsub(
|
24
|
+
# To handle <a> tags without ending tag like
|
25
|
+
# `Voir <a href=IEV103-05-21>IEV 103-05-21`
|
26
|
+
# for concept '702-03-11' in `fr`
|
27
|
+
/<a href="?(IEV)?\s*(\d\d\d-\d\d-\d\d\d?)"?>(.*?)$/,
|
28
|
+
'{{\3, IEV:\2}}',
|
29
|
+
).gsub(
|
30
|
+
/<a href="?([^<>]*?)"?>(.*?)<\/a>/,
|
31
|
+
'\1[\2]',
|
32
|
+
).gsub(
|
33
|
+
Regexp.new([SIMG_PATH_REGEX, "\\s*", FIGURE_TWO_REGEX].join),
|
34
|
+
"#{IMAGE_PATH_PREFIX}/#{term_domain}/\\1[Figure \\2 - \\3; \\6]",
|
35
|
+
).gsub(
|
36
|
+
Regexp.new([SIMG_PATH_REGEX, "\\s*", FIGURE_ONE_REGEX].join),
|
37
|
+
"#{IMAGE_PATH_PREFIX}/#{term_domain}/\\1[Figure \\2 - \\3]",
|
38
|
+
).gsub(
|
39
|
+
/<img\s+([^<>]+?)\s*>/,
|
40
|
+
"#{IMAGE_PATH_PREFIX}/#{term_domain}/\\1[]",
|
41
|
+
).gsub(
|
42
|
+
/<br>/,
|
43
|
+
"\n",
|
44
|
+
).gsub(
|
45
|
+
/<b>(.*?)<\/b>/,
|
46
|
+
"*\\1*",
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def replace_newlines(input)
|
52
|
+
input.gsub('\n', "\n\n")
|
53
|
+
.gsub(/<[pbr]+>/, "\n\n")
|
54
|
+
.gsub(/\s*\n[\n\s]+/, "\n\n")
|
55
|
+
.strip
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/iev/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.3.
|
1
|
+
module IEV
|
2
|
+
VERSION = "0.3.3".freeze
|
3
3
|
end
|
data/lib/iev.rb
CHANGED
@@ -3,7 +3,27 @@ require "iev/db"
|
|
3
3
|
require "open-uri"
|
4
4
|
require "nokogiri"
|
5
5
|
|
6
|
-
|
6
|
+
require "benchmark"
|
7
|
+
require "creek"
|
8
|
+
require "unitsml"
|
9
|
+
require "plurimath"
|
10
|
+
require "glossarist"
|
11
|
+
require "relaton"
|
12
|
+
require "relaton_bib"
|
13
|
+
require "sequel"
|
14
|
+
require "thor"
|
15
|
+
require "yaml"
|
16
|
+
require "zeitwerk"
|
17
|
+
|
18
|
+
loader = Zeitwerk::Loader.for_gem
|
19
|
+
loader.inflector.inflect(
|
20
|
+
"cli" => "CLI",
|
21
|
+
"iev" => "IEV",
|
22
|
+
"ui" => "UI",
|
23
|
+
)
|
24
|
+
loader.setup
|
25
|
+
|
26
|
+
module IEV
|
7
27
|
#
|
8
28
|
# Scrape Electropedia for term.
|
9
29
|
#
|
@@ -23,6 +43,8 @@ module Iev
|
|
23
43
|
a = doc&.at(xpath)&.children&.to_xml
|
24
44
|
a&.sub(%r{<br/>.*$}, "")
|
25
45
|
&.sub(%r{, <.*$}, "")
|
26
|
-
&.gsub(%r{<[
|
46
|
+
&.gsub(%r{<[^<>]*>}, "")&.strip
|
27
47
|
end
|
28
48
|
end
|
49
|
+
|
50
|
+
require "iev/cli"
|