relaton-bib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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