relaton-bib 2.0.0.pre.alpha.1 → 2.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rubocop.yml +1 -1
  4. data/CLAUDE.md +96 -0
  5. data/Gemfile +1 -0
  6. data/README.adoc +14 -2
  7. data/grammars/basicdoc.rng +75 -45
  8. data/grammars/biblio-standoc.rng +37 -56
  9. data/grammars/biblio.rng +68 -36
  10. data/grammars/versions.json +25 -25
  11. data/lib/relaton/bib/converter/asciibib/to_asciibib.rb +663 -0
  12. data/lib/relaton/bib/converter/asciibib.rb +13 -0
  13. data/lib/relaton/bib/converter/bibtex/from_bibtex.rb +245 -0
  14. data/lib/relaton/bib/converter/bibtex/to_bibtex.rb +341 -0
  15. data/lib/relaton/bib/converter/bibtex.rb +23 -0
  16. data/lib/relaton/bib/converter/bibxml/from_rfcxml.rb +383 -0
  17. data/lib/relaton/bib/converter/bibxml/from_rfcxml_referencegroup.rb +71 -0
  18. data/lib/relaton/bib/{renderer/rfc.rb → converter/bibxml/to_rfcxml.rb} +100 -92
  19. data/lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup.rb +52 -0
  20. data/lib/relaton/bib/converter/bibxml.rb +51 -0
  21. data/lib/relaton/bib/hash_parser_v1.rb +121 -78
  22. data/lib/relaton/bib/item_data.rb +83 -22
  23. data/lib/relaton/bib/model/abstract.rb +16 -0
  24. data/lib/relaton/bib/model/date.rb +6 -4
  25. data/lib/relaton/bib/model/depiction.rb +2 -0
  26. data/lib/relaton/bib/model/ext.rb +0 -3
  27. data/lib/relaton/bib/model/formattedref.rb +43 -0
  28. data/lib/relaton/bib/model/ics.rb +9 -0
  29. data/lib/relaton/bib/model/item.rb +12 -4
  30. data/lib/relaton/bib/model/item_base.rb +17 -9
  31. data/lib/relaton/bib/model/keyword.rb +3 -3
  32. data/lib/relaton/bib/model/logo.rb +2 -0
  33. data/lib/relaton/bib/model/organization_type.rb +1 -1
  34. data/lib/relaton/bib/model/relation.rb +2 -2
  35. data/lib/relaton/bib/model/series.rb +5 -3
  36. data/lib/relaton/bib/model/subdivision.rb +2 -0
  37. data/lib/relaton/bib/model/title.rb +38 -0
  38. data/lib/relaton/bib/model/type/string_date.rb +48 -0
  39. data/lib/relaton/bib/model/validity.rb +3 -3
  40. data/lib/relaton/bib/namespace_helper.rb +21 -0
  41. data/lib/relaton/bib/version.rb +1 -1
  42. data/lib/relaton/bib.rb +5 -82
  43. data/relaton-bib.gemspec +5 -2
  44. metadata +63 -29
  45. data/lib/relaton/bib/model/editorial_group.rb +0 -14
  46. data/lib/relaton/bib/model/technical_committee.rb +0 -14
  47. data/lib/relaton/bib/model/workgroup.rb +0 -20
  48. data/lib/relaton/bib/parser/rfc_address.rb +0 -60
  49. data/lib/relaton/bib/parser/rfc_contacts.rb +0 -35
  50. data/lib/relaton/bib/parser/rfc_docidentifier.rb +0 -70
  51. data/lib/relaton/bib/parser/rfc_organization.rb +0 -31
  52. data/lib/relaton/bib/parser/rfc_person.rb +0 -42
  53. data/lib/relaton/bib/parser/rfc_reference.rb +0 -143
  54. data/lib/relaton/bib/parser/rfc_referencegroup.rb +0 -45
  55. data/lib/relaton/bib/parser/rfc_shared.rb +0 -23
  56. data/lib/relaton/bib/renderer/bibtex_builder.rb +0 -348
  57. data/lib/relaton/bibtex_parser.rb +0 -243
  58. data/lib/relaton/bibxml_parser.rb +0 -419
  59. data/lib/relaton/deep_dup.rb +0 -30
  60. data/lib/relaton/hit.rb +0 -52
  61. data/lib/relaton/hit_collection.rb +0 -105
  62. data/lib/relaton/workers_pool.rb +0 -43
  63. data/lib/relaton/xml_parser.rb +0 -716
@@ -1,243 +0,0 @@
1
- module Relaton
2
- # @todo: move this class to the Relaton::Bib::Bibtex module
3
- class BibtexParser
4
- class << self
5
- # @param bibtex [String]
6
- # @return [Hash{String=>Relaton::Bib::Item}]
7
- def from_bibtex(bibtex) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
8
- BibTeX.parse(bibtex).reduce({}) do |h, bt|
9
- h[bt.key] = Item.new(
10
- id: bt.key,
11
- docid: fetch_docid(bt),
12
- fetched: fetch_fetched(bt),
13
- type: fetch_type(bt),
14
- title: fetch_title(bt),
15
- contributor: fetch_contributor(bt),
16
- date: fetch_date(bt),
17
- place: fetch_place(bt),
18
- biblionote: fetch_note(bt),
19
- relation: fetch_relation(bt),
20
- extent: fetch_extent(bt),
21
- edition: bt["edition"]&.to_s,
22
- series: fetch_series(bt),
23
- link: fetch_link(bt),
24
- language: fetch_language(bt),
25
- classification: fetch_classification(bt),
26
- keyword: fetch_keyword(bt),
27
- )
28
- h
29
- end
30
- end
31
-
32
- private
33
-
34
- # @param bibtex [BibTeX::Entry]
35
- # @return [Array<Relaton::Bib::Docidentifier>]
36
- def fetch_docid(bibtex) # rubocop:disable Metrics/AbcSize
37
- docid = []
38
- docid << Docidentifier.new(id: bibtex.isbn.to_s, type: "isbn") if bibtex["isbn"]
39
- docid << Docidentifier.new(id: bibtex.lccn.to_s, type: "lccn") if bibtex["lccn"]
40
- docid << Docidentifier.new(id: bibtex.issn.to_s, type: "issn") if bibtex["issn"]
41
- docid
42
- end
43
-
44
- # @param bibtex [BibTeX::Entry]
45
- # @return [String, nil]
46
- def fetch_fetched(bibtex)
47
- Date.parse(bibtex.timestamp.to_s) if bibtex["timestamp"]
48
- end
49
-
50
- # @param bibtex [BibTeX::Entry]
51
- # @return [String]
52
- def fetch_type(bibtex)
53
- case bibtex.type
54
- when :mastersthesis, :phdthesis then "thesis"
55
- when :conference then "inproceedings"
56
- when :misc then "standard"
57
- else bibtex.type.to_s
58
- end
59
- end
60
-
61
- # @param bibtex [BibTeX::Entry]
62
- # @return [Array<Hash>]
63
- def fetch_place(bibtex)
64
- bibtex["address"] ? [bibtex.address.to_s] : []
65
- end
66
-
67
- # @param bibtex [BibTeX::Entry]
68
- # @return [Relaton::Bib::TitleCollection]
69
- def fetch_title(bibtex)
70
- title = []
71
- title << { type: "main", content: bibtex.convert(:latex).title.to_s } if bibtex["title"]
72
- title << { type: "main", content: bibtex.convert(:latex).subtitle.to_s } if bibtex["subtitle"]
73
- TitleCollection.new title
74
- end
75
-
76
- # @param bibtex [BibTeX::Entry]
77
- # @return [Array<Hash>]
78
- def fetch_contributor(bibtex) # rubocop:disable Metrics/AbcSize
79
- contribs = []
80
- fetch_person(bibtex, "author") { |author| contribs << author }
81
- fetch_person(bibtex, "editor") { |editor| contribs << editor }
82
-
83
- fetch_org(bibtex["publisher"], "publisher") { |pub| contribs << pub }
84
- fetch_org(bibtex["institution"], "distributor", "sponsor") { |distr| contribs << distr }
85
- fetch_org(bibtex["organization"], "distributor", "sponsor") { |org| contribs << org }
86
- fetch_org(bibtex["school"], "distributor", "sponsor") { |school| contribs << school }
87
-
88
- fetch_howpublished(bibtex) { |pub| contribs << pub }
89
-
90
- contribs
91
- end
92
-
93
- def fetch_howpublished(bibtex, &_)
94
- return unless bibtex["howpublished"]
95
-
96
- /\\publisher\{(?<name>.+)\},\\url\{(?<url>.+)\}/ =~ bibtex.howpublished.to_s
97
- return unless name && url
98
-
99
- name.gsub!(/\{\\?([^\\]+)\}/, '\1')
100
- org = Organization.new(name: name, url: url)
101
- yield entity: org, role: [{ type: "publisher" }]
102
- end
103
-
104
- def fetch_org(org, type, desc = nil, &_)
105
- return unless org
106
-
107
- role = { type: type }
108
- role[:description] = [desc] if desc
109
- yield entity: Organization.new(name: org.to_s), role: [role]
110
- end
111
-
112
- # @param bibtex [BibTeX::Entry]
113
- # @return [Array<Relaton::Bib::Person>]
114
- def fetch_person(bibtex, role, &_) # rubocop:disable Metrics/AbcSize
115
- bibtex[role]&.each do |name|
116
- parts = name.split ", "
117
- surname = LocalizedString.new parts.first
118
- fname = parts.size > 1 ? parts[1].split : []
119
- forename = fname.map { |fn| Forename.new content: fn }
120
- name = FullName.new(surname: surname, forename: forename)
121
- yield entity: Person.new(name: name), role: [{ type: role }]
122
- end
123
- end
124
-
125
- # @param bibtex [BibTeX::Entry]
126
- # @return [Array<Hash>]
127
- def fetch_date(bibtex)
128
- date = []
129
- if bibtex["year"]
130
- on = Date.new(bibtex.year.to_i, bibtex["month_numeric"]&.to_i || 1).to_s
131
- date << { type: "published", on: on }
132
- end
133
-
134
- if bibtex["urldate"]
135
- date << { type: "accessed", on: Date.parse(bibtex.urldate.to_s).to_s }
136
- end
137
-
138
- date
139
- end
140
-
141
- # @param bibtex [BibTeX::Entry]
142
- # @return [Relaton::Bib::BiblioNoteCollection]
143
- def fetch_note(bibtex) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
144
- bibtex.select do |k, _v|
145
- %i[annote howpublished comment note content].include? k
146
- end.reduce(BiblioNoteCollection.new([])) do |mem, note|
147
- type = case note[0]
148
- when :note then nil
149
- when :content then "tableOfContents"
150
- else note[0].to_s
151
- end
152
- next mem if type == "howpublished" && note[1].to_s.match?(/^\\publisher\{.+\},\\url\{.+\}$/)
153
-
154
- mem << BiblioNote.new(type: type, content: note[1].to_s)
155
- end
156
- end
157
-
158
- # @param bibtex [BibTeX::Entry]
159
- # @return [Array<Hash>]
160
- def fetch_relation(bibtex)
161
- return [] unless bibtex["booktitle"]
162
-
163
- ttl = Title.new(type: "main", content: bibtex.booktitle.to_s)
164
- title = TitleCollection.new [ttl]
165
- [{ type: "partOf", bibitem: Item.new(title: title) }]
166
- end
167
-
168
- # @param bibtex [BibTeX::Entry]
169
- # @return [Array<RelatonBib::Extent>]
170
- def fetch_extent(bibtex) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
171
- locs = bibtex.select do |k, _v|
172
- %i[chapter pages volume].include? k
173
- end.reduce([]) do |mem, loc|
174
- if loc[0] == :pages
175
- type = "page"
176
- from, to = loc[1].to_s.split "-"
177
- else
178
- type = loc[0].to_s
179
- from = loc[1].to_s
180
- to = nil
181
- end
182
- mem << Locality.new(type, from, to)
183
- end
184
- [RelatonBib::Extent.new(locs)]
185
- end
186
-
187
- # @param bibtex [BibTeX::Entry]
188
- # @return [Array<Relaton::Bib::Series>]
189
- def fetch_series(bibtex) # rubocop:disable Metrics/MethodLength
190
- series = []
191
- if bibtex["journal"]
192
- series << Series.new(
193
- type: "journal",
194
- title: Title.new(content: bibtex.journal.to_s),
195
- number: bibtex["number"]&.to_s,
196
- )
197
- end
198
-
199
- if bibtex["series"]
200
- title = Title.new content: bibtex.series.to_s
201
- series << Series.new(title: title)
202
- end
203
- series
204
- end
205
-
206
- # @param bibtex [BibTeX::Entry]
207
- # @return [Array<Relaton::Bib::Bsource>]
208
- def fetch_link(bibtex) # rubocop:disable Metrics/AbcSize
209
- link = []
210
- link << Bsource.new(type: "src", content: bibtex.url.to_s) if bibtex["url"]
211
- link << Bsource.new(type: "doi", content: bibtex.doi.to_s) if bibtex["doi"]
212
- link << Bsource.new(type: "file", content: bibtex.file2.to_s) if bibtex["file2"]
213
- link
214
- end
215
-
216
- # @param bibtex [BibTeX::Entry]
217
- # @return [Array<String>]
218
- def fetch_language(bibtex)
219
- return [] unless bibtex["language"]
220
-
221
- [Iso639[bibtex.language.to_s].alpha2]
222
- end
223
-
224
- # @param bibtex [BibTeX::Entry]
225
- # @return [Relaton::Bib::Classification, nil]
226
- def fetch_classification(bibtex)
227
- cls = []
228
- cls << Classification.new(type: "type", value: bibtex["type"].to_s) if bibtex["type"]
229
- # cls << Classification.new(type: "keyword", value: bibtex.keywords.to_s) if bibtex["keywords"]
230
- if bibtex["mendeley-tags"]
231
- cls << Classification.new(type: "mendeley", value: bibtex["mendeley-tags"].to_s)
232
- end
233
- cls
234
- end
235
-
236
- # @param bibtex [BibTeX::Entry]
237
- # @return [Array<String>]
238
- def fetch_keyword(bibtex)
239
- bibtex["keywords"]&.split(/,\s?/) || []
240
- end
241
- end
242
- end
243
- end
@@ -1,419 +0,0 @@
1
- module Relaton
2
- module BibXMLParser
3
- # SeriesInfo what should be saved as docidentifiers in the Relaton model.
4
- SERIESINFONAMES = ["DOI"].freeze
5
- RFCPREFIXES = %w[RFC BCP FYI STD].freeze
6
-
7
- FLAVOR = nil
8
-
9
- ORGNAMES = {
10
- "IEEE" => "Institute of Electrical and Electronics Engineers",
11
- "W3C" => "World Wide Web Consortium",
12
- "3GPP" => "3rd Generation Partnership Project",
13
- }.freeze
14
-
15
- #
16
- # Parse BibXML content
17
- #
18
- # @param [String] bibxml content
19
- # @param [String, nil] url source URL
20
- # @param [Boolean] is_relation true if the content is relation item
21
- # @param [String, nil] ver version
22
- #
23
- # @return [<Type>] <description>
24
- #
25
- def parse(bibxml, url: nil, is_relation: false, ver: nil)
26
- doc = Nokogiri::XML bibxml
27
- fetch_rfc doc.at("/referencegroup", "/reference"), url: url, is_relation: is_relation, ver: ver
28
- end
29
-
30
- # @param reference [Nokogiri::XML::Element, nil]
31
- # @param is_relation [Boolean] don't add fetched date for relation if true
32
- # @param url [String, nil]
33
- # @param ver [String, nil] Internet Draft version
34
- # @return [Relaton::Bib::Item]
35
- def fetch_rfc(reference, is_relation: false, url: nil, ver: nil) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
36
- return unless reference
37
-
38
- hash = {
39
- is_relation: is_relation,
40
- docnumber: docnumber(reference),
41
- type: "standard",
42
- docid: docids(reference, ver),
43
- status: status(reference),
44
- language: [language(reference)],
45
- script: ["Latn"],
46
- link: link(reference, url, ver),
47
- title: titles(reference),
48
- formattedref: formattedref(reference),
49
- abstract: abstracts(reference),
50
- contributor: contributors(reference),
51
- relation: relations(reference),
52
- date: dates(reference),
53
- editorialgroup: editorialgroup(reference),
54
- series: series(reference),
55
- keyword: reference.xpath("front/keyword").map(&:text),
56
- doctype: doctype(reference[:anchor]),
57
- }
58
- # hash[:fetched] = Date.today.to_s unless is_relation
59
- bib_item(**hash)
60
- end
61
-
62
- def docnumber(reference)
63
- reference[:anchor]&.sub(/^\w+\./, "")
64
- end
65
-
66
- # @param attrs [Hash]
67
- # @return [Relaton::Bib::Item]
68
- def bib_item(**attrs)
69
- # attrs[:place] = ["Fremont, CA"]
70
- Item.new(**attrs)
71
- end
72
-
73
- # @param reference [Nokogiri::XML::Element]
74
- # @return [String]
75
- def language(reference)
76
- reference[:lang] || "en"
77
- end
78
-
79
- #
80
- # Extract document identifiers from reference
81
- #
82
- # @param reference [Nokogiri::XML::Element]
83
- # @param ver [String, nil] Internet Draft version
84
- #
85
- # @return [Array<Relaton::Bib::Docidentifier>]
86
- #
87
- def docids(reference, ver) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
88
- ret = []
89
- si = reference.at("./seriesInfo[@name='Internet-Draft']",
90
- "./front/seriesInfo[@name='Internet-Draft']")
91
- if si
92
- id = si[:value]
93
- id.sub!(/(?<=-)\d{2}$/, ver) if ver
94
- ret << Bib::Docidentifier.new(type: "Internet-Draft", id: id, primary: true)
95
- else
96
- id = reference[:anchor] || reference[:docName] || reference[:number]
97
- ret << create_docid(id, ver) if id
98
- end
99
-
100
- %w[anchor docName number].each do |atr|
101
- if reference[atr]
102
- pref, num = id_to_pref_num reference[atr]
103
- atrid = if atr == "anchor" && RFCPREFIXES.include?(pref)
104
- "#{pref}#{num.sub(/^-?0+/, '')}"
105
- else
106
- reference[atr]
107
- end
108
- type = pubid_type id
109
- ret << Bib::Docidentifier.new(id: atrid, type: type, scope: atr)
110
- end
111
- end
112
-
113
- ret + reference.xpath("./seriesInfo", "./front/seriesInfo").map do |si|
114
- next unless SERIESINFONAMES.include? si[:name]
115
-
116
- id = si[:value]
117
- # id.sub!(/(?<=-)\d{2}$/, ver) if ver && si[:name] == "Internet-Draft"
118
- Bib::Docidentifier.new(id: id, type: si[:name])
119
- end.compact
120
- end
121
-
122
- def create_docid(id, ver) # rubocop:disable Metrics/MethodLength
123
- pref, num = id_to_pref_num(id)
124
- if RFCPREFIXES.include?(pref)
125
- pid = "#{pref} #{num.sub(/^-?0+/, '')}"
126
- type = pubid_type id
127
- elsif %w[I-D draft].include?(pref)
128
- pid = "draft-#{num}"
129
- pid.sub!(/(?<=-)\d{2}$/, ver) if ver
130
- type = "Internet-Draft"
131
- else
132
- pid = pref ? "#{pref} #{num}" : id
133
- type = pubid_type id
134
- end
135
- Docidentifier.new(type: type, id: pid, primary: true)
136
- end
137
-
138
- def id_to_pref_num(id)
139
- tn = /^(?<pref>I-D|draft|3GPP|W3C|[A-Z]{2,})[._-]?(?<num>.+)/.match id
140
- tn && tn.to_a[1..2]
141
- end
142
-
143
- #
144
- # Extract document identifier type from identifier
145
- #
146
- # @param [String] id identifier
147
- #
148
- # @return [String]
149
- #
150
- def pubid_type(id)
151
- id_to_pref_num(id)&.first
152
- end
153
-
154
- #
155
- # extract status
156
- # @param reference [Nokogiri::XML::Element]
157
- #
158
- # @return [Relaton::Bib::DocumentStatus]
159
- #
160
- def status(reference)
161
- st = reference.at("./seriesinfo[@status]")
162
- DocumentStatus.new(stage: st[:status]) if st
163
- end
164
-
165
- # @param reference [Nokogiri::XML::Element]
166
- # @param url [String]
167
- # @param ver [String, nil] Internet Draft version
168
- # @return [Array<Hash>]
169
- def link(reference, url, ver)
170
- l = []
171
- l << { type: "xml", content: url } if url
172
- l << { type: "src", content: reference[:target] } if reference[:target]
173
- if /^I-D/.match? reference[:anchor]
174
- reference.xpath("format").each do |f|
175
- c = ver ? f[:target].sub(/(?<=-)\d{2}(?=\.)/, ver) : f[:target]
176
- l << { type: f[:type], content: c }
177
- end
178
- end
179
- l
180
- end
181
-
182
- # @param reference [Nokogiri::XML::Element]
183
- # @return [Array<Hash>]
184
- def titles(reference)
185
- reference.xpath("./front/title").map do |title|
186
- { content: title.text, language: language(reference), script: "Latn" }
187
- end
188
- end
189
-
190
- # @param reference [Nokogiri::XML::Element]
191
- # @return [Relaton::Bib::Formattedref, nil]
192
- def formattedref(reference)
193
- return if reference.at "./front/title"
194
-
195
- cont = reference[:anchor] || reference[:docName] || reference[:number]
196
- if cont
197
- Formattedref.new(
198
- content: cont, language: language(reference), script: "Latn",
199
- )
200
- end
201
- end
202
-
203
- # @param reference [Nokogiri::XML::Element]
204
- # @return [Array<Relaton::Bib::FormattedString>]
205
- def abstracts(ref)
206
- ref.xpath("./front/abstract").map do |a|
207
- c = a.inner_html.gsub(/\s*(<\/?)t(>)\s*/, '\1p\2').gsub(/[\t\n]/, " ").squeeze " "
208
- Bib::FormattedString.new(content: c, language: language(ref), script: "Latn", format: "text/html")
209
- end
210
- end
211
-
212
- # @param reference [Nokogiri::XML::Element]
213
- # @return [Array<Hash>]
214
- def contributors(reference)
215
- lang = language reference
216
- reference.xpath("./front/author").map do |contrib|
217
- entity = person(contrib, lang) || organization(contrib)
218
- next unless entity
219
-
220
- { entity: entity, role: [contributor_role(contrib)] }
221
- end.compact
222
- end
223
-
224
- # @param author [Nokogiri::XML::Element]
225
- # @param lang [String]
226
- # @return [Relaton::Bib::Person, nil]
227
- def person(author, lang)
228
- return unless author[:fullname] || author[:surname]
229
-
230
- name = full_name(author[:fullname], author[:surname], author[:initials], lang)
231
- Bib::Person.new(name: name, affiliation: affiliation(author), contact: contacts(author.at("./address")))
232
- end
233
-
234
- # @param contrib [Nokogiri::XML::Element]
235
- # @return [Relaton::Bib::Organization, nil]
236
- def organization(contrib)
237
- org = contrib.at("./organization")
238
- return unless org
239
-
240
- orgname = org.text.strip
241
- return if orgname.empty?
242
-
243
- name = ORGNAMES[orgname] || orgname
244
- new_org name, org[:abbrev]
245
- end
246
-
247
- # @param fname [String] full name
248
- # @param sname [String] surname
249
- # @param inits [String] initials
250
- # @param lang [String] language
251
- # @return [Relaton::Bib::FullName]
252
- def full_name(fname, sname, inits, lang)
253
- initials = localized_string(inits, lang) if inits
254
- Bib::FullName.new(
255
- completename: localized_string(fname, lang), initials: initials,
256
- forename: forename(inits, lang), surname: localized_string(sname, lang)
257
- )
258
- end
259
-
260
- #
261
- # Create forenames with initials
262
- #
263
- # @param [String] initials initials
264
- # @param [String] lang language
265
- #
266
- # @return [Array<Relaton::Bib::Forename>] forenames
267
- #
268
- def forename(initials, lang = nil, script = nil)
269
- return [] unless initials
270
-
271
- initials.split(/\.-?\s?|\s/).map do |i|
272
- Bib::Forename.new(initial: i, language: lang, script: script)
273
- end
274
- end
275
-
276
- # @param author [Nokogiri::XML::Element]
277
- # @return [Array<Relaton::Bib::Affiliation>]
278
- def affiliation(author)
279
- o = author.at("./organization")
280
- return [] if o.nil? || o.text.empty?
281
-
282
- org = new_org o.text, o[:abbrev]
283
- [Bib::Affiliation.new(organization: org)]
284
- end
285
-
286
- # @param name [String]
287
- # @param abbr [String, nil]
288
- # @return [Relaton::Bib::Organization]
289
- def new_org(name, abbr = nil)
290
- Bib::Organization.new name: name, abbreviation: abbr
291
- end
292
-
293
- # @param content [String, nil]
294
- # @param lang [String, nil]
295
- # @param script [String, nil]
296
- # @return [Relaton::Bib::LocalizedString, nil]
297
- def localized_string(content, lang, script = nil)
298
- Bib::LocalizedString.new(content: content, laguage: lang, script: script) if content
299
- end
300
-
301
- # @param postal [Nokogiri::XML::Element]
302
- # @return [Array<Relaton::Bib::Address, Relaton::Bib::Phone>]
303
- def contacts(addr)
304
- conts = []
305
- return conts unless addr
306
-
307
- postal = addr.at("./postal")
308
- conts << address(postal) if postal&.at("./city") && postal&.at("./country")
309
- add_contact(conts, "phone", addr.at("./phone"))
310
- add_contact(conts, "email", addr.at("./email"))
311
- add_contact(conts, "uri", addr.at("./uri"))
312
- conts
313
- end
314
-
315
- # @param postal [Nokogiri::XML::Element]
316
- # @return [Relaton::Bib::Address]
317
- def address(postal) # rubocop:disable Metrics/CyclomaticComplexity
318
- street = [postal.at("./postalLine | ./street")&.text].compact
319
- Bib::Address.new(
320
- street: street,
321
- city: postal.at("./city")&.text,
322
- postcode: postal.at("./code")&.text,
323
- country: postal.at("./country")&.text,
324
- state: postal.at("./region")&.text,
325
- )
326
- end
327
-
328
- # @param conts [Array<Relaton::Bib::Address, Relaton::Bib::Contact>]
329
- # @param type [String] allowed "phone", "email" or "uri"
330
- # @param value [String]
331
- def add_contact(conts, type, value)
332
- conts << Bib::Contact.new(type: type, value: value.text) if value
333
- end
334
-
335
- # @param author [Nokogiri::XML::Document]
336
- # @return [Hash]
337
- def contributor_role(author)
338
- { type: author[:role] || "author" }
339
- end
340
-
341
- # @param reference [Nokogiri::XML::Element]
342
- # @return [Hash]
343
- def relations(reference)
344
- reference.xpath("reference").map do |ref|
345
- { type: "includes", bibitem: fetch_rfc(ref, is_relation: true) }
346
- end
347
- end
348
-
349
- #
350
- # Extract date from reference.
351
- #
352
- # @param reference [Nokogiri::XML::Element]
353
- # @return [Array<Relaton::Bib::Bdate>] published data.
354
- #
355
- def dates(reference) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
356
- date = reference.at "./front/date"
357
- return [] if date.nil? || date[:year].nil? || date[:year].empty?
358
-
359
- d = date[:year]
360
- d += "-#{month(date[:month])}" if date[:month] && !date[:month].empty?
361
- d += "-#{date[:day]}" if date[:day]
362
- # date = Time.parse(d).strftime "%Y-%m-%d"
363
- [Bib::Date.new(type: "published", on: d)]
364
- end
365
-
366
- # @param reference [Nokogiri::XML::Element]
367
- # @return [Relaton::Bib::EditorialGroup, nil]
368
- def editorialgroup(reference)
369
- tc = reference.xpath("./front/workgroup").map do |ed|
370
- wg = Bib::WorkGroup.new name: ed.text
371
- committee wg
372
- end
373
- EditorialGroup.new tc if tc.any?
374
- end
375
-
376
- # @param [Relaton::Bib::WorkGroup]
377
- # @return [Relaton::Bib::TechnicalCommittee]
378
- def committee(wgr)
379
- Bib::TechnicalCommittee.new wgr
380
- end
381
-
382
- def month(mon)
383
- # return 1 if !mon || mon.empty?
384
- return mon if /^\d+$/.match? mon
385
-
386
- Date::MONTHNAMES.index { |m| m&.include? mon }.to_s.rjust 2, "0"
387
- end
388
-
389
- #
390
- # Extract series form reference
391
- # @param reference [Nokogiri::XML::Element]
392
- #
393
- # @return [Array<Relaton::Bib::Series>]
394
- #
395
- def series(reference)
396
- reference.xpath("./seriesInfo", "./front/seriesInfo").map do |si|
397
- next if SERIESINFONAMES.include?(si[:name]) || si[:stream] || si[:status]
398
-
399
- t = Title.new(
400
- content: si[:name], language: language(reference), script: "Latn",
401
- )
402
- Series.new(title: t, number: si[:value], type: "main")
403
- end.compact
404
- end
405
-
406
- # @param anchor [String]
407
- # @return [String]
408
- def doctype(anchor)
409
- type = case anchor
410
- when /I-D/ then "internet-draft"
411
- when /IEEE/ then "ieee"
412
- else "rfc"
413
- end
414
- DocumentType.new type: type
415
- end
416
-
417
- extend BibXMLParser
418
- end
419
- end
@@ -1,30 +0,0 @@
1
- class Object
2
- def duplicable?
3
- true
4
- end
5
-
6
- def deep_dup
7
- duplicable? ? dup : self
8
- end
9
- end
10
-
11
- class Array
12
- def deep_dup
13
- map(&:deep_dup)
14
- end
15
- end
16
-
17
- # class Hash
18
- # def deep_dup
19
- # hash = dup
20
- # each_pair do |key, value|
21
- # if key.frozen? && ::String === key
22
- # hash[key] = value.deep_dup
23
- # else
24
- # hash.delete(key)
25
- # hash[key.deep_dup] = value.deep_dup
26
- # end
27
- # end
28
- # hash
29
- # end
30
- # end