relaton-bib 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.
@@ -0,0 +1,46 @@
1
+ module RelatonBib
2
+ # class SpecificLocalityType
3
+ # SECTION = 'section'
4
+ # CLAUSE = 'clause'
5
+ # PART = 'part'
6
+ # PARAGRAPH = 'paragraph'
7
+ # CHAPTER = 'chapter'
8
+ # PAGE = 'page'
9
+ # WHOLE = 'whole'
10
+ # TABLE = 'table'
11
+ # ANNEX = 'annex'
12
+ # FIGURE = 'figure'
13
+ # NOTE = 'note'
14
+ # EXAMPLE = 'example'
15
+ # # generic String is allowed
16
+ # end
17
+
18
+ # Bibliographic item locality.
19
+ class BibItemLocality
20
+ # @return [RelatonBib::SpecificLocalityType]
21
+ attr_reader :type
22
+
23
+ # @return [RelatonBib::LocalizedString]
24
+ attr_reader :reference_from
25
+
26
+ # @return [RelatonBib::LocalizedString]
27
+ attr_reader :reference_to
28
+
29
+ # @param type [String]
30
+ # @param referenceFrom [String]
31
+ # @param referenceTo [String]
32
+ def initialize(type, reference_from, reference_to = nil)
33
+ @type = type
34
+ @reference_from = reference_from
35
+ @reference_to = reference_to
36
+ end
37
+
38
+ # @param builder [Nokogiri::XML::Builder]
39
+ def to_xml(builder)
40
+ builder.locality(type: type) do
41
+ builder.referenceFrom reference_from # { reference_from.to_xml(builder) }
42
+ builder.referenceTo reference_to if reference_to
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ module RelatonBib
6
+ # Bibliographic date.
7
+ class BibliographicDate
8
+ TYPES = %w[published accessed created implemented obsoleted confirmed
9
+ updated issued].freeze
10
+
11
+ # @return [String]
12
+ attr_reader :type
13
+
14
+ # @return [Time]
15
+ attr_reader :from
16
+
17
+ # @return [Time]
18
+ attr_reader :to
19
+
20
+ # @return [Time]
21
+ attr_reader :on
22
+
23
+ # @param type [String] "published", "accessed", "created", "activated"
24
+ # @param from [String]
25
+ # @param to [String]
26
+ def initialize(type:, on: nil, from: nil, to: nil)
27
+ raise ArgumentError, "expected :on or :form argument" unless on || from
28
+
29
+ raise ArgumentError, %{Type "#{type}" is ivalid.} unless TYPES.include?(type)
30
+
31
+ @type = type
32
+ @on = parse_date on
33
+ @from = parse_date from
34
+ @to = parse_date to
35
+ end
36
+
37
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
38
+ # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
39
+
40
+ # @param builder [Nokogiri::XML::Builder]
41
+ # @return [Nokogiri::XML::Builder]
42
+ def to_xml(builder, **opts)
43
+ builder.date(type: type) do
44
+ if on
45
+ date = opts[:full_date] ? on.strftime("%Y-%m") : on.year
46
+ builder.on(opts[:no_year] ? "--" : date)
47
+ elsif from
48
+ if opts[:full_date]
49
+ date_form = from.strftime("%Y-%m")
50
+ date_to = to.strftime("%Y-%m") if to
51
+ else
52
+ date_form = from.year
53
+ date_to = to.year if to
54
+ end
55
+ builder.from(opts[:no_year] ? "--" : date_form)
56
+ builder.to date_to if to
57
+ end
58
+ end
59
+ end
60
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
61
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
62
+
63
+ private
64
+
65
+ # @params date [String] 'yyyy' or 'yyyy-mm'
66
+ def parse_date(date)
67
+ return unless date
68
+
69
+ if date =~ /^\d{4}$/
70
+ Time.strptime date, "%Y"
71
+ else
72
+ Time.strptime date, "%Y-%m"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,343 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "relaton_bib/typed_uri"
4
+ require "relaton_bib/document_identifier"
5
+ require "relaton_bib/copyright_association"
6
+ require "relaton_bib/formatted_string"
7
+ require "relaton_bib/contribution_info"
8
+ require "relaton_bib/bibliographic_date"
9
+ require "relaton_bib/series"
10
+ require "relaton_bib/document_status"
11
+ require "relaton_bib/organization"
12
+ require "relaton_bib/document_relation_collection"
13
+ require "relaton_bib/typed_title_string"
14
+ require "relaton_bib/formatted_ref"
15
+ require "relaton_bib/medium"
16
+ require "relaton_bib/classification"
17
+ require "relaton_bib/validity"
18
+ require "relaton_bib/document_relation"
19
+ require "relaton_bib/bib_item_locality"
20
+ require "relaton_bib/xml_parser"
21
+
22
+
23
+ module RelatonBib
24
+ # module BibItemType
25
+ # ARTICLE = 'article'
26
+ # BOOK = 'book'
27
+ # BOOKLET = 'booklet'
28
+ # CONFERENCE = 'conference'
29
+ # MANUAL = 'manual'
30
+ # PROCEEDINGS = 'proceedings'
31
+ # PRESENTATION = 'presentation'
32
+ # THESIS = 'thesis'
33
+ # TECHREPORT = 'techreport'
34
+ # STANDARD = 'standard'
35
+ # UNPUBLISHED = 'unpublished'
36
+ # end
37
+
38
+ # Bibliographic item
39
+ class BibliographicItem
40
+ class Version
41
+ # @return [String]
42
+ attr_reader :revision_date
43
+
44
+ # @return [Array<String>]
45
+ attr_reader :draft
46
+
47
+ # @oaram revision_date [String]
48
+ # @param draft [Array<String>]
49
+ def initialize(revision_date = nil, draft = [])
50
+ @revision_date = revision_date
51
+ @draft = draft
52
+ end
53
+
54
+ # @param builder [Nokogiri::XML::Builder]
55
+ def to_xml(builder)
56
+ builder.version do
57
+ builder.revision_date revision_date if revision_date
58
+ draft.each { |d| builder.draft d }
59
+ end
60
+ end
61
+ end
62
+
63
+ TYPES = %W[article book booklet conference manual proceedings presentation
64
+ thesis techreport standard unpublished map electronic\sresource
65
+ audiovisual film video broadcast graphic_work music patent
66
+ inbook incollection inproceedings journal].freeze
67
+
68
+ # @return [String]
69
+ attr_reader :id
70
+
71
+ # @return [Array<RelatonBib::TypedTitleString>]
72
+ attr_reader :title
73
+
74
+ # @return [Array<RelatonBib::TypedUri>]
75
+ attr_reader :link
76
+
77
+ # @return [String]
78
+ attr_reader :type
79
+
80
+ # @return [Array<RelatonBib::DocumentIdentifier>]
81
+ attr_reader :docidentifier
82
+
83
+ # @return [String] docnumber
84
+ attr_reader :docnumber
85
+
86
+ # @return [Array<RelatonBib::BibliographicDate>]
87
+ attr_reader :dates
88
+
89
+ # @return [Array<RelatonBib::ContributionInfo>]
90
+ attr_reader :contributors
91
+
92
+ # @return [String, NillClass]
93
+ attr_reader :edition
94
+
95
+ # @return [RelatonBib::BibliongraphicItem::Version]
96
+ attr_reader :version
97
+
98
+ # @return [Array<RelatonBib::FormattedString>, NilClass]
99
+ attr_reader :biblionote
100
+
101
+ # @return [Array<String>] language Iso639 code
102
+ attr_reader :language
103
+
104
+ # @return [Array<String>] script Iso15924 code
105
+ attr_reader :script
106
+
107
+ # @return [RelatonBib::FormattedRef]
108
+ attr_reader :formattedref
109
+
110
+ # @!attribute [r] abstract
111
+ # @return [Array<RelatonBib::FormattedString>]
112
+
113
+ # @return [RelatonBib::DocumentStatus]
114
+ attr_reader :status
115
+
116
+ # @return [RelatonBib::CopyrightAssociation]
117
+ attr_reader :copyright
118
+
119
+ # @return [RelatonBib::DocRelationCollection]
120
+ attr_reader :relations
121
+
122
+ # @return [Array<RelatonBib::Series>]
123
+ attr_reader :series
124
+
125
+ # @return [RelatonBib::Medium, NilClass]
126
+ attr_reader :medium
127
+
128
+ # @return [Array<String>]
129
+ attr_reader :place
130
+
131
+ # @return [Array<RelatonBib::BibItemLocality>]
132
+ attr_reader :extent
133
+
134
+ # @return [Array<Strig>]
135
+ attr_reader :accesslocation
136
+
137
+ # @return [Relaton::Classification, NilClass]
138
+ attr_reader :classification
139
+
140
+ # @return [RelatonBib:Validity, NilClass]
141
+ attr_reader :validity
142
+
143
+ # @return [Date]
144
+ attr_reader :fetched
145
+
146
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
147
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
148
+
149
+ # @param id [String, NilClass]
150
+ # @param title [Array<RelatonBib::TypedTitleString>]
151
+ # @param formattedref [RelatonBib::FormattedRef, NilClass]
152
+ # @param type [String, NilClass]
153
+ # @param docid [Array<RelatonBib::DocumentIdentifier>]
154
+ # @param docnumber [String, NilClass]
155
+ # @param language [Arra<String>]
156
+ # @param script [Array<String>]
157
+ # @param docstatus [RelatonBib::DocumentStatus, NilClass]
158
+ # @param edition [String, NilClass]
159
+ # @param version [RelatonBib::BibliographicItem::Version, NilClass]
160
+ # @param biblionote [Array<RelatonBib::FormattedStrong>]
161
+ # @param series [Array<RelatonBib::Series>]
162
+ # @param medium [RelatonBib::Medium, NilClas]
163
+ # @param place [Array<String>]
164
+ # @param extent [Array<Relaton::BibItemLocality>]
165
+ # @param accesslocation [Array<String>]
166
+ # @param classification [RelatonBib::Classification, NilClass]
167
+ # @param validity [RelatonBib:Validity, NilClass]
168
+ # @param fetched [Date, NilClass] default nil
169
+ #
170
+ # @param dates [Array<Hash>]
171
+ # @option dates [String] :type
172
+ # @option dates [String] :from
173
+ # @option dates [String] :to
174
+ #
175
+ # @param contributors [Array<Hash>]
176
+ # @option contributors [String] :type
177
+ # @option contributors [String] :from
178
+ # @option contributirs [String] :to
179
+ # @option contributors [String] :abbreviation
180
+ # @option contributors [Array<String>] :roles
181
+ #
182
+ # @param abstract [Array<Hash>]
183
+ # @option abstract [String] :content
184
+ # @option abstract [String] :language
185
+ # @option abstract [String] :script
186
+ # @option abstract [String] :type
187
+ #
188
+ # @param relations [Array<Hash>]
189
+ # @option relations [String] :type
190
+ # @option relations [RelatonBib::BibliographicItem] :bibitem
191
+ # @option relations [Array<RelatonBib::BibItemLocality>] :bib_locality
192
+ def initialize(**args)
193
+ if args[:type] && !TYPES.include?(args[:type])
194
+ raise ArgumentError, %{Type "#{args[:type]}" is invalid.}
195
+ end
196
+
197
+ @title = (args[:titles] || []).map do |t|
198
+ t.is_a?(Hash) ? TypedTitleString.new(t) : t
199
+ end
200
+
201
+ @dates = (args[:dates] || []).map do |d|
202
+ d.is_a?(Hash) ? BibliographicDate.new(d) : d
203
+ end
204
+
205
+ @contributors = (args[:contributors] || []).map do |c|
206
+ if c.is_a? Hash
207
+ e = c[:entity].is_a?(Hash) ? Organization.new(c[:entity]) : c[:entity]
208
+ ContributionInfo.new(entity: e, role: c[:roles])
209
+ else c
210
+ end
211
+ end
212
+
213
+ @abstract = (args[:abstract] || []).map do |a|
214
+ a.is_a?(Hash) ? FormattedString.new(a) : a
215
+ end
216
+
217
+ if args[:copyright]
218
+ @copyright = if args[:copyright].is_a?(Hash)
219
+ CopyrightAssociation.new args[:copyright]
220
+ else args[:copyright]
221
+ end
222
+ end
223
+
224
+ @id = args[:id]
225
+ @formattedref = args[:formattedref] if title.empty?
226
+ @type = args[:type]
227
+ @docidentifier = args[:docid] || []
228
+ @docnumber = args[:docnumber]
229
+ @edition = args[:edition]
230
+ @version = args[:version]
231
+ @biblionote = args.fetch :biblionote, []
232
+ @language = args.fetch :language, []
233
+ @script = args.fetch :script, []
234
+ @status = args[:docstatus]
235
+ @relations = DocRelationCollection.new(args[:relations] || [])
236
+ @link = args.fetch(:link, []).map { |s| s.is_a?(Hash) ? TypedUri.new(s) : s }
237
+ @series = args[:series]
238
+ @medium = args[:medium]
239
+ @place = args.fetch(:place, [])
240
+ @extent = args[:extent] || []
241
+ @accesslocation = args.fetch :accesslocation, []
242
+ @classification = args[:classification]
243
+ @validity = args[:validity]
244
+ @fetched = args.fetch :fetched, nil # , Date.today # we should pass the fetched arg from scrappers
245
+ end
246
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
247
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
248
+
249
+ # @param lang [String] language code Iso639
250
+ # @return [RelatonBib::FormattedString, Array<RelatonBib::FormattedString>]
251
+ def abstract(lang: nil)
252
+ if lang
253
+ @abstract.detect { |a| a.language.include? lang }
254
+ else
255
+ @abstract
256
+ end
257
+ end
258
+
259
+ def makeid(id, attribute)
260
+ return nil if attribute && !@id_attribute
261
+
262
+ id ||= @docidentifier.reject { |i| i.type == "DOI" }[0]
263
+ # contribs = publishers.map { |p| p&.entity&.abbreviation }.join '/'
264
+ # idstr = "#{contribs}#{delim}#{id.project_number}"
265
+ # idstr = id.project_number.to_s
266
+ idstr = id.id.gsub(/:/, "-")
267
+ # if id.part_number&.size&.positive? then idstr += "-#{id.part_number}"
268
+ idstr.strip
269
+ end
270
+
271
+ # @return [String]
272
+ def shortref(identifier, **opts)
273
+ pubdate = dates.select { |d| d.type == "published" }
274
+ year = if opts[:no_year] || pubdate.empty? then ""
275
+ else ":" + pubdate&.first&.on&.year.to_s
276
+ end
277
+ year += ": All Parts" if opts[:all_parts] || @all_parts
278
+
279
+ "#{makeid(identifier, false)}#{year}"
280
+ end
281
+
282
+ # @param builder [Nokogiri::XML::Builder, NillClass] (nil)
283
+ # @return [String]
284
+ def to_xml(builder = nil, root = "bibitem", &block)
285
+ if builder
286
+ render_xml builder, root, &block
287
+ else
288
+ Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
289
+ render_xml xml, root, &block
290
+ end.doc.root.to_xml
291
+ end
292
+ end
293
+
294
+ private
295
+
296
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
297
+ # rubocop:disable Metrics/CyclomaticComplexity
298
+
299
+ # @param builder [Nokogiri::XML::Builder]
300
+ # @return [String]
301
+ def render_xml(builder, root)
302
+ xml = builder.send(root) do
303
+ builder.fetched fetched if fetched
304
+ title.each { |t| builder.title { t.to_xml builder } }
305
+ formattedref.to_xml builder if formattedref
306
+ link.each { |s| s.to_xml builder }
307
+ docidentifier.each { |di| di.to_xml builder }
308
+ builder.docnumber docnumber if docnumber
309
+ dates.each { |d| d.to_xml builder, full_date: true }
310
+ contributors.each do |c|
311
+ builder.contributor do
312
+ c.role.each { |r| r.to_xml builder }
313
+ c.to_xml builder
314
+ end
315
+ end
316
+ builder.edition edition if edition
317
+ version.to_xml builder if version
318
+ biblionote.each { |n| builder.note { n.to_xml builder } }
319
+ language.each { |l| builder.language l }
320
+ script.each { |s| builder.script s }
321
+ abstract.each { |a| builder.abstract { a.to_xml(builder) } }
322
+ status.to_xml builder if status
323
+ copyright.to_xml builder if copyright
324
+ relations.each { |r| r.to_xml builder }
325
+ series.each { |s| s.to_xml builder } if series
326
+ medium.to_xml builder if medium
327
+ place.each { |pl| builder.place pl }
328
+ extent.each { |e| e.to_xml builder }
329
+ accesslocation.each { |al| builder.accesslocation al }
330
+ classification.to_xml builder if classification
331
+ validity.to_xml builder if validity
332
+ if block_given?
333
+ yield builder
334
+ end
335
+ end
336
+ xml[:id] = id if id
337
+ xml[:type] = type if type
338
+ xml
339
+ end
340
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
341
+ # rubocop:enable Metrics/CyclomaticComplexity
342
+ end
343
+ end