relaton-iso-bib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # RelatonIsoBib
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/relaton_iso_bib`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'relaton_iso_bib'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install relaton_iso_bib
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/relaton_iso_bib.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "relaton_iso_bib"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RelatonIsoBib
4
+ # ISO project group.
5
+ class EditorialGroup
6
+ # @return [Array<RelatonIsoBib::IsoSubgroup>]
7
+ attr_reader :technical_committee
8
+
9
+ # @return [RelatonIsoBib::IsoSubgroup]
10
+ attr_reader :subcommittee
11
+
12
+ # @return [RelatonIsoBib::IsoSubgroup]
13
+ attr_reader :workgroup
14
+
15
+ # @return [String]
16
+ attr_reader :secretariat
17
+
18
+ # @param technical_committee [Array<Hash, RelatonIsoBib::IsoSubgroup>]
19
+ # @option technical_committee [String] :name
20
+ # @option technical_committee [String] :type
21
+ # @option technical_committee [Integer] :number
22
+ #
23
+ # @param subcommittee [Array<Hash, RelatonIsoBib::IsoSubgroup>]
24
+ # @option subcommittee [String] :name
25
+ # @option subcommittee [String] :type
26
+ # @option subcommittee [Integer] :number
27
+ #
28
+ # @param workgroup [Array<Hash, RelatonIsoBib::IsoSubgroup>]
29
+ # @option workgroup [String] :name
30
+ # @option workgroup [String] :type
31
+ # @option workgroup [Integer] :number
32
+ #
33
+ # @param secretariat [String, NilClass]
34
+ def initialize(technical_committee:, **args)
35
+ @technical_committee = technical_committee.map do |tc|
36
+ tc.is_a?(Hash) ? IsoSubgroup.new(tc) : tc
37
+ end
38
+ @subcommittee = args.fetch(:subcommittee, []).map do |sc|
39
+ sc.is_a?(Hash) ? IsoSubgroup.new(sc) : sc
40
+ end
41
+ @workgroup = args.fetch(:workgroup, []).map do |wg|
42
+ wg.is_a?(Hash) ? IsoSubgroup.new(wg) : wg
43
+ end
44
+ @secretariat = args[:secretariat]
45
+ end
46
+
47
+ # rubocop:disable Metrics/AbcSize
48
+
49
+ # @param builder [Nokogiri::XML::Builder]
50
+ def to_xml(builder)
51
+ return unless technical_committee || subcommittee || workgroup || secretariat
52
+ builder.editorialgroup do
53
+ technical_committee.each do |tc|
54
+ builder.technical_committee { tc.to_xml builder }
55
+ end
56
+ subcommittee.each do |sc|
57
+ builder.subcommittee { sc.to_xml builder }
58
+ end
59
+ workgroup.each do |wg|
60
+ builder.workgroup { wg.to_xml builder }
61
+ end
62
+ builder.secretariat secretariat if secretariat
63
+ end
64
+ end
65
+ # rubocop:enable Metrics/AbcSize
66
+ end
67
+
68
+ # ISO subgroup.
69
+ class IsoSubgroup
70
+ # @return [String, NilClass]
71
+ attr_reader :type
72
+
73
+ # @return [Integer, NilClass]
74
+ attr_reader :number
75
+
76
+ # @return [String]
77
+ attr_reader :name
78
+
79
+ # @param name [String]
80
+ # @param type [String, NilClass]
81
+ # @param number [Integer, NilClass]
82
+ def initialize(name:, type: nil, number: nil)
83
+ @name = name
84
+ @type = type
85
+ @number = number
86
+ end
87
+
88
+ # @param builder [Nokogiri::XML::Builder]
89
+ def to_xml(builder)
90
+ builder.parent[:number] = number if number
91
+ builder.parent[:type] = type if type
92
+ builder.text name
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,25 @@
1
+ module RelatonIsoBib
2
+ # Iso ICS classificator.
3
+ class Ics < Isoics::ICS
4
+ # @param code [String, NilClass]
5
+ # @param field [Integer, NilClass]
6
+ # @param group [Integer, NilClass]
7
+ # @param subgroup [Integer, NilClass]
8
+ def initialize(code = nil, field: nil, group: nil, subgroup: nil)
9
+ unless code || field
10
+ raise ArgumentError, "wrong arguments (should be string or { fieldcode: [String] }"
11
+ end
12
+
13
+ field, group, subgroup = code.split '.' if code
14
+ super fieldcode: field, groupcode: group, subgroupcode: subgroup
15
+ end
16
+
17
+ # @param builder [Nokogiri::XML::Builder]
18
+ def to_xml(builder)
19
+ builder.ics do
20
+ builder.code code
21
+ builder.text_ description
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,357 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "nokogiri"
4
+ require "isoics"
5
+ require "deep_clone"
6
+ require "relaton_bib"
7
+ require "relaton_iso_bib/typed_title_string"
8
+ require "relaton_iso_bib/editorial_group"
9
+ require "relaton_iso_bib/xml_parser"
10
+ require "relaton_iso_bib/structured_identifier"
11
+ require "relaton_iso_bib/ics"
12
+
13
+ # Add filter method to Array.
14
+ class Array
15
+ # @param type [String]
16
+ # @return [Array]
17
+ def filter(type:)
18
+ select { |e| e.type == type }
19
+ end
20
+ end
21
+
22
+ module RelatonIsoBib
23
+ # Bibliographic item.
24
+ class IsoBibliographicItem < RelatonBib::BibliographicItem
25
+ TYPES = %w[
26
+ international-standard technical-specification technical-report
27
+ publicly-available-specification international-workshop-agreement guide
28
+ ].freeze
29
+
30
+ # @return [RelatonIsoBib::StructuredIdentifier]
31
+ attr_reader :structuredidentifier
32
+
33
+ # @!attribute [r] title
34
+ # @return [Array<RelatonIsoBib::TypedTitleString>]
35
+
36
+ # @return [String, NilClass]
37
+ attr_reader :doctype
38
+
39
+ # @return [RelatonIsoBib::EditorialGroup]
40
+ attr_reader :editorialgroup
41
+
42
+ # @return [Array<RelatonIsoBib::Ics>]
43
+ attr_reader :ics
44
+
45
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
46
+ # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
47
+
48
+ # @param edition [String]
49
+ # @param docnumber [String, NilClass]
50
+ # @param language [Array<String>]
51
+ # @param script [Arrra<String>]
52
+ # @param docstatus [RelatonBib::DocumentStatus, NilClass]
53
+ # @param type [String, NilClass]
54
+ # @param formattedref [RelatonBib::FormattedRef, NilClass]
55
+ # @param version [RelatonBib::BibliographicItem::Version, NilClass]
56
+ # @param biblionote [Array<RelatonBib::BiblioNote>]
57
+ # @param series [Array<RelatonBib::Series>]
58
+ # @param medium [RelatonBib::Medium, NilClas]
59
+ # @param place [Array<String>]
60
+ # @param extent [Array<Relaton::BibItemLocality>]
61
+ # @param accesslocation [Array<String>]
62
+ # @param classification [RelatonBib::Classification, NilClass]
63
+ # @param validity [RelatonBib:Validity, NilClass]
64
+ # @param docid [Array<RelatonBib::DocumentIdentifier>]
65
+ # @param structuredidentifier [RelatonIsoBib::StructuredIdentifier]
66
+ #
67
+ # @param titles [Array<Hash>]
68
+ # @option titles [String] :title_intro
69
+ # @option titles [String] :title_main
70
+ # @option titles [String] :title_part
71
+ # @option titles [String] :language
72
+ # @option titles [String] :script
73
+ #
74
+ # @param editorialgroup [Hash, RelatonIsoBib::EditorialGroup]
75
+ # @option workgrpup [String] :name
76
+ # @option workgrpup [String] :abbreviation
77
+ # @option workgrpup [String] :url
78
+ # @option workgrpup [Hash] :technical_committee
79
+ # @option technical_committee [String] :name
80
+ # @option technical_committee [String] :type
81
+ # @option technical_committee [Integer] :number
82
+ #
83
+ # @param ics [Array<Hash>]
84
+ # @option ics [Integer] :field
85
+ # @option ics [Integer] :group
86
+ # @option ics [Integer] :subgroup
87
+ #
88
+ # @param dates [Array<Hash>]
89
+ # @option dates [String] :type
90
+ # @option dates [String] :from
91
+ # @option dates [String] :to
92
+ #
93
+ # @param abstract [Array<Hash>]
94
+ # @option abstract [String] :content
95
+ # @option abstract [String] :language
96
+ # @option abstract [String] :script
97
+ # @option abstract [String] :type
98
+ #
99
+ # @param contributors [Array<Hash>]
100
+ # @option contributors [Hash] :entity
101
+ # @option entity [String] :name
102
+ # @option entity [String] :url
103
+ # @option entity [String] :abbreviation
104
+ # @option contributors [Array<String>] :roles
105
+ #
106
+ # @param copyright [Hash]
107
+ # @option copyright [Hash] :owner
108
+ # @option owner [String] :name
109
+ # @option owner [String] :abbreviation
110
+ # @option owner [String] :url
111
+ # @option copyright [String] :from
112
+ # @option copyright [String] :to
113
+ #
114
+ # @param link [Array<Hash, RelatonIsoBib::TypedUri>]
115
+ # @option link [String] :type
116
+ # @option link [String] :content
117
+ #
118
+ # @param relations [Array<Hash>]
119
+ # @option relations [String] :type
120
+ # @option relations [RelatonIsoBib::IsoBibliographicItem] :bibitem
121
+ # @option relations [Array<RelatonBib::BibItemLocality>] :bib_locality
122
+ #
123
+ # @raise [ArgumentError]
124
+ def initialize(**args)
125
+ if args[:type] && !TYPES.include?(args[:type])
126
+ raise ArgumentError, "invalid type: #{args[:type]}"
127
+ end
128
+
129
+ args.fetch(:language, []).each do |lang|
130
+ unless %w[en fr].include? lang
131
+ raise ArgumentError, "invalid language: #{lang}"
132
+ end
133
+ end
134
+
135
+ args.fetch(:script, []).each do |scr|
136
+ raise ArgumentError, "invalid script: #{scr}" unless scr == "Latn"
137
+ end
138
+
139
+ super_args = args.select do |k|
140
+ %i[id docnumber language script docstatus dates abstract contributors
141
+ edition version relations biblionote series medium place copyright
142
+ link fetched docid formattedref extent accesslocation classification
143
+ validity].include? k
144
+ end
145
+ super(super_args)
146
+
147
+ @structuredidentifier = args[:structuredidentifier]
148
+
149
+ @title = args.fetch(:titles, []).reduce([]) do |a, t|
150
+ if t.is_a? Hash
151
+ a + typed_titles(t)
152
+ else
153
+ a << t
154
+ end
155
+ end
156
+
157
+ if args[:editorialgroup]
158
+ @editorialgroup = if args[:editorialgroup].is_a?(Hash)
159
+ EditorialGroup.new(args[:editorialgroup])
160
+ else args[:editorialgroup]
161
+ end
162
+ end
163
+
164
+ @doctype = args[:type]
165
+ @ics = args.fetch(:ics, []).map { |i| i.is_a?(Hash) ? Ics.new(i) : i }
166
+ @link = args.fetch(:link, []).map do |s|
167
+ s.is_a?(Hash) ? RelatonBib::TypedUri.new(s) : s
168
+ end
169
+ @id_attribute = true
170
+ end
171
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
172
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
173
+
174
+ def disable_id_attribute
175
+ @id_attribute = false
176
+ end
177
+
178
+ # remove title part components and abstract
179
+ def to_all_parts
180
+ me = DeepClone.clone(self)
181
+ me.disable_id_attribute
182
+ @relations << RelatonBib::DocumentRelation.new(
183
+ type: "partOf", bibitem: me,
184
+ )
185
+ @title.delete_if { |t| t.type == "title-part" }
186
+ @abstract = []
187
+ @docidentifier.each(&:remove_part)
188
+ @docidentifier.each(&:all_parts)
189
+ @structuredidentifier.remove_part
190
+ @structuredidentifier.all_parts
191
+ @all_parts = true
192
+ end
193
+
194
+ # convert ISO:yyyy reference to reference to most recent
195
+ # instance of reference, removing date-specific infomration:
196
+ # date of publication, abstracts. Make dated reference Instance relation
197
+ # of the redacated document
198
+ def to_most_recent_reference
199
+ me = DeepClone.clone(self)
200
+ me.disable_id_attribute
201
+ @relations << RelatonBib::DocumentRelation.new(type: "instance", bibitem: me)
202
+ @abstract = []
203
+ @dates = []
204
+ @docidentifier.each &:remove_date
205
+ @structuredidentifier.remove_date
206
+ @id&.sub! /-[12]\d\d\d/, ""
207
+ end
208
+
209
+ # @param lang [String] language code Iso639
210
+ # @return [Array<RelatonIsoBib::TypedTitleString>]
211
+ def title(lang: nil)
212
+ if lang
213
+ @title.select { |t| t.title.language.include? lang }
214
+ else
215
+ @title
216
+ end
217
+ end
218
+
219
+ # @param type [Symbol] type of url, can be :src/:obp/:rss
220
+ # @return [String]
221
+ def url(type = :src)
222
+ @link.detect { |s| s.type == type.to_s }.content.to_s
223
+ end
224
+
225
+ # @return [String]
226
+ def to_xml(builder = nil, **opts, &block)
227
+ if opts[:note] && !opts[:note].empty?
228
+ opts.fetch(:note, []).each do |n|
229
+ @biblionote << RelatonBib::BiblioNote.new(
230
+ content: n[:text], type: n[:type], format: "text/plain"
231
+ )
232
+ end
233
+ end
234
+ super builder, **opts do |b|
235
+ if opts[:bibdata]
236
+ b.ext do
237
+ b.doctype doctype if doctype
238
+ editorialgroup&.to_xml b
239
+ ics.each { |i| i.to_xml b }
240
+ structuredidentifier.to_xml b
241
+ end
242
+ end
243
+ end
244
+ end
245
+
246
+ private
247
+
248
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
249
+
250
+ # @param title [Hash]
251
+ # @option title [String] :title_intro
252
+ # @option title [String] :title_main
253
+ # @option title [String] :title_part
254
+ # @option title [String] :language
255
+ # @option title [String] :script
256
+ # @return [Array<RelatonIsoBib::TypedTitleStrig>]
257
+ def typed_titles(title)
258
+ titles = []
259
+ if title[:title_main]
260
+ titles << TypedTitleString.new(
261
+ type: "title-main", content: title[:title_main],
262
+ language: title[:language], script: title[:script], format: "text/plain",
263
+ )
264
+ end
265
+
266
+ if title[:title_intro]
267
+ titles << TypedTitleString.new(
268
+ type: "title-intro", content: title[:title_intro],
269
+ language: title[:language], script: title[:script], format: "text/plain",
270
+ )
271
+ end
272
+
273
+ if title[:title_part]
274
+ titles << TypedTitleString.new(
275
+ type: "title-part", content: title[:title_part],
276
+ language: title[:language], script: title[:script], format: "text/plain",
277
+ )
278
+ end
279
+
280
+ unless titles.empty?
281
+ titles << TypedTitleString.new(
282
+ type: "main", content: titles.map { |t| t.title.content }.join(" - "),
283
+ language: title[:language], script: title[:script], format: "text/plain",
284
+ )
285
+ end
286
+
287
+ titles
288
+ end
289
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
290
+
291
+ def makeid(id, attribute, _delim = '')
292
+ return nil if attribute && !@id_attribute
293
+
294
+ id ||= @docidentifier.reject { |i| i&.type == "DOI" }[0]
295
+ # contribs = publishers.map { |p| p&.entity&.abbreviation }.join '/'
296
+ # idstr = "#{contribs}#{delim}#{id.project_number}"
297
+ # idstr = id.project_number.to_s
298
+ if id
299
+ idstr = id.id
300
+ idstr = "IEV" if structuredidentifier&.project_number == "IEV"
301
+ else
302
+ idstr = formattedref&.content
303
+ end
304
+ # if id.part_number&.size&.positive? then idstr += "-#{id.part_number}"
305
+ idstr&.gsub(/:/, "-")&.gsub(/\s/, "")&.strip
306
+ end
307
+
308
+ # def xml_attrs(type)
309
+ # attrs = {}
310
+ # attrs[:type] = type if type
311
+ # # attr_id = makeid(nil, true)&.gsub(/ /, "")
312
+ # # attrs[:id] = attr_id if attr_id
313
+ # attrs
314
+ # end
315
+
316
+ # @param builder [Nokogiri::XML::Builder]
317
+ # def render_xml(builder, **opts)
318
+ # builder.send("iso-standard", xml_attrs(type)) do
319
+ # builder.fetched fetched if fetched
320
+ # formattedref.to_xml builder if formattedref
321
+ # title.each { |t| t.to_xml builder }
322
+ # link.each { |s| s.to_xml builder }
323
+ # docidentifier.each { |i| i.to_xml builder }
324
+ # builder.docnumber docnumber if docnumber
325
+ # dates.each { |d| d.to_xml builder, opts }
326
+ # contributors.each do |c|
327
+ # builder.contributor do
328
+ # c.role.each { |r| r.to_xml builder }
329
+ # c.to_xml builder
330
+ # end
331
+ # end
332
+ # builder.edition edition if edition
333
+ # version.to_xml builder if version
334
+ # if opts[:note]
335
+ # builder.note("ISO DATE: #{opts[:note]}", format: 'text/plain')
336
+ # end
337
+ # language.each { |l| builder.language l }
338
+ # script.each { |s| builder.script s }
339
+ # abstract.each { |a| builder.abstract { a.to_xml(builder) } }
340
+ # status.to_xml builder if status
341
+ # copyright.to_xml builder if copyright
342
+ # relations.each { |r| r.to_xml builder }
343
+ # series.each { |s| s.to_xml builder } if series
344
+ # medium.to_xml builder if medium
345
+ # place.each { |pl| builder.place pl }
346
+ # extent.each { |e| e.to_xml builder }
347
+ # accesslocation.each { |al| builder.accesslocation al }
348
+ # classification.to_xml builder if classification
349
+ # validity.to_xml builder if validity
350
+ # editorialgroup.to_xml builder if editorialgroup
351
+ # ics.each { |i| i.to_xml builder }
352
+ # builder.allparts 'true' if @all_parts
353
+ # yield(builder) if block_given?
354
+ # end
355
+ # end
356
+ end
357
+ end