datacite-mapping 0.2.5 → 0.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +23 -11
- data/.ruby-version +1 -1
- data/CHANGES.md +5 -0
- data/Gemfile +2 -0
- data/LICENSE.md +1 -1
- data/README.md +2 -2
- data/Rakefile +5 -3
- data/datacite-mapping.gemspec +9 -7
- data/examples/reading.rb +1 -1
- data/examples/writing.rb +1 -0
- data/lib/datacite/mapping.rb +2 -0
- data/lib/datacite/mapping/alternate_identifier.rb +4 -2
- data/lib/datacite/mapping/contributor.rb +5 -3
- data/lib/datacite/mapping/creator.rb +6 -4
- data/lib/datacite/mapping/date.rb +5 -5
- data/lib/datacite/mapping/date_value.rb +4 -2
- data/lib/datacite/mapping/description.rb +5 -3
- data/lib/datacite/mapping/empty_filtering_nodes.rb +2 -0
- data/lib/datacite/mapping/funding_reference.rb +6 -4
- data/lib/datacite/mapping/geo_location.rb +2 -0
- data/lib/datacite/mapping/geo_location_box.rb +12 -10
- data/lib/datacite/mapping/geo_location_node.rb +9 -7
- data/lib/datacite/mapping/geo_location_point.rb +8 -6
- data/lib/datacite/mapping/geo_location_polygon.rb +3 -1
- data/lib/datacite/mapping/identifier.rb +9 -7
- data/lib/datacite/mapping/module_info.rb +5 -3
- data/lib/datacite/mapping/name_identifier.rb +4 -2
- data/lib/datacite/mapping/namespace_extensions.rb +2 -0
- data/lib/datacite/mapping/read_only_nodes.rb +5 -3
- data/lib/datacite/mapping/related_identifier.rb +5 -3
- data/lib/datacite/mapping/resource.rb +15 -13
- data/lib/datacite/mapping/resource_type.rb +3 -1
- data/lib/datacite/mapping/rights.rb +3 -1
- data/lib/datacite/mapping/subject.rb +5 -3
- data/lib/datacite/mapping/title.rb +5 -3
- data/spec/.rubocop.yml +3 -0
- data/spec/rspec_custom_matchers.rb +8 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/datacite/mapping/alternate_identifier_spec.rb +2 -0
- data/spec/unit/datacite/mapping/contributor_spec.rb +2 -0
- data/spec/unit/datacite/mapping/creator_spec.rb +2 -0
- data/spec/unit/datacite/mapping/date_spec.rb +2 -0
- data/spec/unit/datacite/mapping/date_value_spec.rb +2 -0
- data/spec/unit/datacite/mapping/description_spec.rb +2 -0
- data/spec/unit/datacite/mapping/funding_reference_spec.rb +3 -1
- data/spec/unit/datacite/mapping/geo_location_box_spec.rb +2 -0
- data/spec/unit/datacite/mapping/geo_location_point_spec.rb +2 -0
- data/spec/unit/datacite/mapping/geo_location_polygon_spec.rb +22 -20
- data/spec/unit/datacite/mapping/geo_location_spec.rb +24 -22
- data/spec/unit/datacite/mapping/identifier_spec.rb +8 -6
- data/spec/unit/datacite/mapping/name_identifier_spec.rb +2 -0
- data/spec/unit/datacite/mapping/related_identifier_spec.rb +2 -0
- data/spec/unit/datacite/mapping/resource_spec.rb +22 -18
- data/spec/unit/datacite/mapping/rights_spec.rb +3 -1
- data/spec/unit/datacite/mapping/subject_spec.rb +2 -0
- data/spec/unit/datacite/mapping/title_spec.rb +2 -0
- metadata +26 -26
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -9,11 +11,11 @@ module Datacite
|
|
9
11
|
attr_reader :coord_elements
|
10
12
|
|
11
13
|
def initialize(*args)
|
12
|
-
|
13
|
-
|
14
|
-
path, *
|
14
|
+
raise 'No geometry class provided' unless @geom_class
|
15
|
+
raise 'No coordinate elements provided' unless @coord_elements
|
16
|
+
path, *myargs = super(*args)
|
15
17
|
@path = ::XML::XXPath.new(path)
|
16
|
-
|
18
|
+
myargs # rubocop:disable Lint/Void
|
17
19
|
end
|
18
20
|
|
19
21
|
def datacite_3?
|
@@ -22,12 +24,12 @@ module Datacite
|
|
22
24
|
|
23
25
|
def extract_attr_value(xml)
|
24
26
|
return from_text(xml) || from_children(xml)
|
25
|
-
rescue => e
|
27
|
+
rescue StandardError => e
|
26
28
|
raise e, "#{@owner}.#{@attrname}: Can't extract #{self.class} from #{xml}: #{e.message}"
|
27
29
|
end
|
28
30
|
|
29
|
-
def set_attr_value(xml, value)
|
30
|
-
|
31
|
+
def set_attr_value(xml, value)
|
32
|
+
raise "Invalid value: expected #{geom_class} instance, was #{value || 'nil'}" unless value && value.is_a?(geom_class)
|
31
33
|
element = @path.first(xml, ensure_created: true)
|
32
34
|
|
33
35
|
if datacite_3?
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
require 'datacite/mapping/geo_location_node'
|
3
5
|
|
@@ -33,19 +35,19 @@ module Datacite
|
|
33
35
|
when 2
|
34
36
|
init_from_array(args)
|
35
37
|
else
|
36
|
-
|
38
|
+
raise ArgumentError, "Can't construct GeoLocationPoint from arguments: #{args}"
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
42
|
def latitude=(value)
|
41
|
-
|
42
|
-
|
43
|
+
raise ArgumentError, 'Latitude cannot be nil' unless value
|
44
|
+
raise ArgumentError, "#{value} is not a valid latitude" unless value >= -90 && value <= 90
|
43
45
|
@latitude = value
|
44
46
|
end
|
45
47
|
|
46
48
|
def longitude=(value)
|
47
|
-
|
48
|
-
|
49
|
+
raise ArgumentError, 'Longitude cannot be nil' unless value
|
50
|
+
raise ArgumentError, "#{value} is not a valid longitude" unless value >= -180 && value <= 180
|
49
51
|
@longitude = value
|
50
52
|
end
|
51
53
|
|
@@ -62,7 +64,7 @@ module Datacite
|
|
62
64
|
# {GeoLocationPoint}
|
63
65
|
def <=>(other)
|
64
66
|
return nil unless other.class == self.class
|
65
|
-
[
|
67
|
+
%i[latitude longitude].each do |c|
|
66
68
|
order = send(c) <=> other.send(c)
|
67
69
|
return order if order.nonzero?
|
68
70
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -14,7 +16,7 @@ module Datacite
|
|
14
16
|
def initialize(points:) # TODO: allow simple array of point args, array of hashes
|
15
17
|
self.points = points
|
16
18
|
warn "Polygon should contain at least 4 points, but has #{points.size}" if points.size < 4
|
17
|
-
warn "Polygon is not closed; last and first point should be identical, but were: [#{points[0]}], [#{points[-1]}]"
|
19
|
+
warn "Polygon is not closed; last and first point should be identical, but were: [#{points[0]}], [#{points[-1]}]" unless points[0] == points[-1] || points.size <= 1
|
18
20
|
end
|
19
21
|
|
20
22
|
def points=(value)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
require 'datacite/mapping/empty_filtering_nodes'
|
3
5
|
|
@@ -14,7 +16,7 @@ module Datacite
|
|
14
16
|
class Identifier
|
15
17
|
include XML::Mapping
|
16
18
|
|
17
|
-
DOI = 'DOI'
|
19
|
+
DOI = 'DOI'
|
18
20
|
|
19
21
|
# Initializes a new {Identifier}
|
20
22
|
# @param value [String]
|
@@ -25,9 +27,9 @@ module Datacite
|
|
25
27
|
end
|
26
28
|
|
27
29
|
def value=(v)
|
28
|
-
new_value = v
|
29
|
-
|
30
|
-
|
30
|
+
new_value = v&.strip
|
31
|
+
raise ArgumentError, 'Identifier must have a non-nil value' unless new_value
|
32
|
+
raise ArgumentError, "Identifier value '#{new_value}' is not a valid DOI" unless new_value.match?(DOI_PATTERN)
|
31
33
|
@value = new_value
|
32
34
|
end
|
33
35
|
|
@@ -35,7 +37,7 @@ module Datacite
|
|
35
37
|
# @param v [String]
|
36
38
|
# the identifier type (always 'DOI')
|
37
39
|
def identifier_type=(v)
|
38
|
-
|
40
|
+
raise ArgumentError, "Identifier type '#{v}' must be 'DOI'" unless DOI == v
|
39
41
|
@identifier_type = v
|
40
42
|
end
|
41
43
|
|
@@ -48,7 +50,7 @@ module Datacite
|
|
48
50
|
# @param doi_string [String]
|
49
51
|
def self.from_doi(doi_string)
|
50
52
|
match = doi_string.match(DOI_PATTERN)
|
51
|
-
|
53
|
+
raise ArgumentError, "'#{doi_string}' does not appear to contain a valid DOI" unless match
|
52
54
|
Identifier.new(value: match[0])
|
53
55
|
end
|
54
56
|
|
@@ -69,7 +71,7 @@ module Datacite
|
|
69
71
|
|
70
72
|
private
|
71
73
|
|
72
|
-
def has_element?(xml) # rubocop:disable
|
74
|
+
def has_element?(xml) # rubocop:disable Naming/PredicateName
|
73
75
|
@path.first(xml)
|
74
76
|
rescue XML::XXPathError
|
75
77
|
false
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Datacite
|
2
4
|
module Mapping
|
3
5
|
# The name of this gem
|
4
|
-
NAME = 'datacite-mapping'
|
6
|
+
NAME = 'datacite-mapping'
|
5
7
|
|
6
8
|
# The version of this gem
|
7
|
-
VERSION = '0.
|
9
|
+
VERSION = '0.3.0'
|
8
10
|
|
9
11
|
# The copyright notice for this gem
|
10
|
-
COPYRIGHT = 'Copyright (c) 2016 The Regents of the University of California'
|
12
|
+
COPYRIGHT = 'Copyright (c) 2016 The Regents of the University of California'
|
11
13
|
end
|
12
14
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -17,12 +19,12 @@ module Datacite
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def scheme=(v)
|
20
|
-
|
22
|
+
raise ArgumentError, 'Scheme cannot be empty or nil' unless v && !v.empty?
|
21
23
|
@scheme = v
|
22
24
|
end
|
23
25
|
|
24
26
|
def value=(v)
|
25
|
-
|
27
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless v && !v.empty?
|
26
28
|
@value = v
|
27
29
|
end
|
28
30
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
|
3
5
|
module XML
|
@@ -31,7 +33,7 @@ module Datacite
|
|
31
33
|
|
32
34
|
def warn_ignored(val)
|
33
35
|
warning = "ignoring #{@attrname} #{value_str(val)}"
|
34
|
-
warning
|
36
|
+
warning = "#{warn_reason}; #{warning}" if warn_reason
|
35
37
|
ReadOnlyNodes.warn(warning)
|
36
38
|
end
|
37
39
|
|
@@ -43,7 +45,7 @@ module Datacite
|
|
43
45
|
|
44
46
|
class ReadOnlyTextNode < XML::Mapping::TextNode
|
45
47
|
def warn_ignored(val)
|
46
|
-
|
48
|
+
raise ArgumentError, "Expected string, got #{val}" unless val.respond_to?(:strip)
|
47
49
|
return if val.strip.empty?
|
48
50
|
super
|
49
51
|
end
|
@@ -53,7 +55,7 @@ module Datacite
|
|
53
55
|
|
54
56
|
class ReadOnlyArrayNode < XML::Mapping::ArrayNode
|
55
57
|
def warn_ignored(val)
|
56
|
-
|
58
|
+
raise ArgumentError, "Expected array, got #{val}" unless val.respond_to?(:empty?)
|
57
59
|
return if val.empty?
|
58
60
|
super
|
59
61
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -181,17 +183,17 @@ module Datacite
|
|
181
183
|
end
|
182
184
|
|
183
185
|
def value=(value)
|
184
|
-
|
186
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless value && !value.empty?
|
185
187
|
@value = value
|
186
188
|
end
|
187
189
|
|
188
190
|
def identifier_type=(value)
|
189
|
-
|
191
|
+
raise ArgumentError, 'Identifier type cannot be empty or nil' unless value
|
190
192
|
@identifier_type = value
|
191
193
|
end
|
192
194
|
|
193
195
|
def relation_type=(value)
|
194
|
-
|
196
|
+
raise ArgumentError, 'Relation type cannot be nil' unless value
|
195
197
|
@relation_type = value
|
196
198
|
end
|
197
199
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
require 'datacite/mapping/identifier'
|
@@ -91,33 +93,33 @@ module Datacite
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def identifier=(value)
|
94
|
-
|
96
|
+
raise ArgumentError, 'Resource must have an identifier' unless value
|
95
97
|
@identifier = value
|
96
98
|
end
|
97
99
|
|
98
100
|
def creators=(value)
|
99
|
-
|
101
|
+
raise ArgumentError, 'Resource must have at least one creator' unless value && !value.empty?
|
100
102
|
@creators = value
|
101
103
|
end
|
102
104
|
|
103
105
|
def titles=(value)
|
104
|
-
|
106
|
+
raise ArgumentError, 'Resource must have at least one title' unless value && !value.empty?
|
105
107
|
@titles = value
|
106
108
|
end
|
107
109
|
|
108
110
|
def publisher=(value)
|
109
|
-
new_value = value
|
110
|
-
|
111
|
+
new_value = value&.strip
|
112
|
+
raise ArgumentError, 'Resource must have a publisher' unless new_value && !new_value.empty?
|
111
113
|
@publisher = new_value.strip
|
112
114
|
end
|
113
115
|
|
114
116
|
def publication_year=(value)
|
115
|
-
|
117
|
+
raise ArgumentError, 'Resource must have a four-digit publication year' unless value && value.to_i.between?(1000, 9999)
|
116
118
|
@publication_year = value.to_i
|
117
119
|
end
|
118
120
|
|
119
121
|
def subjects=(value)
|
120
|
-
@subjects = (value
|
122
|
+
@subjects = (value&.select(&:value)) || []
|
121
123
|
end
|
122
124
|
|
123
125
|
def contributors=(value)
|
@@ -150,7 +152,7 @@ module Datacite
|
|
150
152
|
|
151
153
|
def version=(value)
|
152
154
|
new_value = value && value.to_s
|
153
|
-
@version = new_value
|
155
|
+
@version = new_value&.strip
|
154
156
|
end
|
155
157
|
|
156
158
|
def rights_list=(value)
|
@@ -158,11 +160,11 @@ module Datacite
|
|
158
160
|
end
|
159
161
|
|
160
162
|
def descriptions=(value)
|
161
|
-
@descriptions = (value
|
163
|
+
@descriptions = (value&.select(&:value)) || []
|
162
164
|
end
|
163
165
|
|
164
166
|
def geo_locations=(value)
|
165
|
-
@geo_locations = (value
|
167
|
+
@geo_locations = (value&.select(&:location?)) || []
|
166
168
|
end
|
167
169
|
|
168
170
|
# @!attribute [rw] identifier
|
@@ -264,19 +266,19 @@ module Datacite
|
|
264
266
|
# @deprecated contributor type 'funder' is deprecated. Use {FundingReference} instead.
|
265
267
|
# @return [String, nil] the name of the funding contributor, if any.
|
266
268
|
def funder_name
|
267
|
-
funder_contrib
|
269
|
+
funder_contrib&.name
|
268
270
|
end
|
269
271
|
|
270
272
|
# Convenience method to get the funding contributor identifier.
|
271
273
|
# @return [NameIdentifier, nil] the identifier of the funding contributor, if any.
|
272
274
|
def funder_id
|
273
|
-
funder_contrib
|
275
|
+
funder_contrib&.identifier
|
274
276
|
end
|
275
277
|
|
276
278
|
# Convenience method to get the funding contributor identifier as a string.
|
277
279
|
# @return [String, nil] the string value of the funding contributor's identifier, if any.
|
278
280
|
def funder_id_value
|
279
|
-
funder_id
|
281
|
+
funder_id&.value
|
280
282
|
end
|
281
283
|
|
282
284
|
extend Gem::Deprecate
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -62,7 +64,7 @@ module Datacite
|
|
62
64
|
end
|
63
65
|
|
64
66
|
def resource_type_general=(val)
|
65
|
-
|
67
|
+
raise ArgumentError, 'General resource type cannot be nil' unless val
|
66
68
|
@resource_type_general = val
|
67
69
|
end
|
68
70
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -17,7 +19,7 @@ module Datacite
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def value=(v)
|
20
|
-
|
22
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless v && !v.empty?
|
21
23
|
@value = v.strip
|
22
24
|
end
|
23
25
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -20,12 +22,12 @@ module Datacite
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def language=(value)
|
23
|
-
@language = value
|
25
|
+
@language = value&.strip
|
24
26
|
end
|
25
27
|
|
26
28
|
def value=(v)
|
27
|
-
new_value = v
|
28
|
-
|
29
|
+
new_value = v&.strip
|
30
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless new_value && !new_value.empty?
|
29
31
|
@value = new_value
|
30
32
|
end
|
31
33
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -31,12 +33,12 @@ module Datacite
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def language=(value)
|
34
|
-
@language = value
|
36
|
+
@language = value&.strip
|
35
37
|
end
|
36
38
|
|
37
39
|
def value=(v)
|
38
|
-
new_value = v
|
39
|
-
|
40
|
+
new_value = v&.strip
|
41
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless new_value && !new_value.empty?
|
40
42
|
@value = new_value.strip
|
41
43
|
end
|
42
44
|
|
data/spec/.rubocop.yml
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rspec/expectations'
|
2
4
|
require 'equivalent-xml'
|
3
5
|
|
@@ -15,7 +17,7 @@ RSpec::Matchers.define :be_xml do |expected|
|
|
15
17
|
when REXML::Element
|
16
18
|
to_nokogiri(xml.to_s)
|
17
19
|
else
|
18
|
-
|
20
|
+
raise "be_xml() expected XML, got #{xml.class}"
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -28,7 +30,7 @@ RSpec::Matchers.define :be_xml do |expected|
|
|
28
30
|
end
|
29
31
|
|
30
32
|
match do |actual|
|
31
|
-
expected_xml = to_nokogiri(expected) ||
|
33
|
+
expected_xml = to_nokogiri(expected) || raise("expected value #{expected || 'nil'} does not appear to be XML")
|
32
34
|
actual_xml = to_nokogiri(actual)
|
33
35
|
|
34
36
|
EquivalentXml.equivalent?(expected_xml, actual_xml, element_order: false, normalize_whitespace: true)
|
@@ -57,12 +59,10 @@ RSpec::Matchers.define :be_time do |expected|
|
|
57
59
|
end
|
58
60
|
|
59
61
|
match do |actual|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
return actual.nil?
|
65
|
-
end
|
62
|
+
return actual.nil? unless expected
|
63
|
+
|
64
|
+
raise "Expected value #{expected} is not a Time" unless expected.is_a?(Time)
|
65
|
+
actual.is_a?(Time) && (to_string(expected) == to_string(actual))
|
66
66
|
end
|
67
67
|
|
68
68
|
failure_message do |actual|
|