datacite-mapping 0.2.4 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +27 -11
- data/.ruby-version +1 -1
- data/CHANGES.md +25 -0
- data/Gemfile +2 -0
- data/LICENSE.md +1 -1
- data/README.md +10 -5
- data/Rakefile +5 -3
- data/datacite-mapping.gemspec +10 -9
- data/examples/reading.rb +1 -1
- data/examples/writing.rb +1 -0
- data/lib/datacite/mapping/affiliation.rb +44 -0
- data/lib/datacite/mapping/alternate_identifier.rb +6 -2
- data/lib/datacite/mapping/contributor.rb +35 -7
- data/lib/datacite/mapping/contributor_name.rb +42 -0
- data/lib/datacite/mapping/creator.rb +43 -9
- data/lib/datacite/mapping/creator_name.rb +42 -0
- data/lib/datacite/mapping/date.rb +17 -5
- data/lib/datacite/mapping/date_value.rb +10 -2
- data/lib/datacite/mapping/description.rb +10 -4
- data/lib/datacite/mapping/empty_filtering_nodes.rb +3 -0
- data/lib/datacite/mapping/funding_reference.rb +31 -10
- data/lib/datacite/mapping/geo_location.rb +8 -1
- data/lib/datacite/mapping/geo_location_box.rb +17 -10
- data/lib/datacite/mapping/geo_location_node.rb +12 -8
- data/lib/datacite/mapping/geo_location_point.rb +11 -6
- data/lib/datacite/mapping/geo_location_polygon.rb +13 -2
- data/lib/datacite/mapping/identifier.rb +18 -14
- data/lib/datacite/mapping/module_info.rb +5 -3
- data/lib/datacite/mapping/name_identifier.rb +12 -6
- data/lib/datacite/mapping/name_type.rb +18 -0
- data/lib/datacite/mapping/namespace_extensions.rb +2 -0
- data/lib/datacite/mapping/publisher.rb +42 -0
- data/lib/datacite/mapping/read_only_nodes.rb +9 -3
- data/lib/datacite/mapping/related_identifier.rb +43 -4
- data/lib/datacite/mapping/resource.rb +37 -21
- data/lib/datacite/mapping/resource_type.rb +7 -1
- data/lib/datacite/mapping/rights.rb +35 -6
- data/lib/datacite/mapping/subject.rb +7 -4
- data/lib/datacite/mapping/title.rb +7 -4
- data/lib/datacite/mapping.rb +3 -1
- data/spec/.rubocop.yml +3 -0
- data/spec/data/datacite4/{datacite-example-Box_dateCollected_DataCollector-v4.0.xml → datacite-example-Box_dateCollected_DataCollector-v4.xml} +9 -11
- data/spec/data/datacite4/{datacite-example-GeoLocation-v4.0.xml → datacite-example-GeoLocation-v4.xml} +11 -10
- data/spec/data/datacite4/{datacite-example-HasMetadata-v4.0.xml → datacite-example-HasMetadata-v4.xml} +18 -13
- data/spec/data/datacite4/{datacite-example-ResearchGroup_Methods-v4.0.xml → datacite-example-ResearchGroup_Methods-v4.xml} +14 -12
- data/spec/data/datacite4/{datacite-example-ResourceTypeGeneral_Collection-v4.0.xml → datacite-example-ResourceTypeGeneral_Collection-v4.xml} +9 -9
- data/spec/data/datacite4/datacite-example-affiliation-v4.xml +114 -0
- data/spec/data/datacite4/{datacite-example-complicated-v4.0.xml → datacite-example-complicated-v4.xml} +14 -11
- data/spec/data/datacite4/datacite-example-datapaper-v4.xml +32 -0
- data/spec/data/datacite4/{datacite-example-dataset-v4.0.xml → datacite-example-dataset-v4.xml} +20 -14
- data/spec/data/datacite4/datacite-example-full-v4.xml +114 -0
- data/spec/data/datacite4/{datacite-example-fundingReference-v.4.0.xml → datacite-example-fundingReference-v4.xml} +16 -13
- data/spec/data/datacite4/datacite-example-polygon-advanced-v4.xml +141 -0
- data/spec/data/datacite4/datacite-example-polygon-v4.xml +161 -0
- data/spec/data/datacite4/{datacite-example-relationTypeIsIdenticalTo-v4.0.xml → datacite-example-relationTypeIsIdenticalTo-v4.xml} +17 -17
- data/spec/data/datacite4/datacite-example-software-v4.xml +66 -0
- data/spec/data/datacite4/{datacite-example-video-v4.0.xml → datacite-example-video-v4.xml} +7 -7
- data/spec/data/datacite4/{datacite-example-workflow-v4.0.xml → datacite-example-workflow-v4.xml} +13 -11
- data/spec/data/datacite4/metadata.xsd +102 -57
- data/spec/rspec_custom_matchers.rb +11 -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 +9 -1
- data/spec/unit/datacite/mapping/creator_spec.rb +11 -3
- 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 +13 -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 +34 -33
- data/spec/unit/datacite/mapping/rights_spec.rb +3 -14
- data/spec/unit/datacite/mapping/subject_spec.rb +2 -0
- data/spec/unit/datacite/mapping/title_spec.rb +2 -0
- metadata +74 -60
- data/spec/data/datacite4/datacite-example-full-v4.0.xml +0 -71
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -52,12 +54,13 @@ module Datacite
|
|
52
54
|
@nsec = datetime.to_time.nsec
|
53
55
|
@zone = datetime.zone
|
54
56
|
end
|
55
|
-
|
57
|
+
raise ArgumentError, "Unable to parse date value '#{val}'" unless @year
|
56
58
|
end
|
57
59
|
|
58
60
|
def <=>(other)
|
59
61
|
return nil unless other.class == self.class
|
60
|
-
|
62
|
+
|
63
|
+
%i[year month day hour minute sec nsec].each do |v|
|
61
64
|
order = send(v) <=> other.send(v)
|
62
65
|
return order if order.nonzero?
|
63
66
|
end
|
@@ -84,24 +87,28 @@ module Datacite
|
|
84
87
|
def to_year(val)
|
85
88
|
return val if val.is_a?(Integer)
|
86
89
|
return val.year if val.respond_to?(:year)
|
90
|
+
|
87
91
|
matchdata = val.to_s.match(/^[0-9]+/)
|
88
92
|
matchdata[0].to_i if matchdata
|
89
93
|
end
|
90
94
|
|
91
95
|
def to_month(val)
|
92
96
|
return val.month if val.respond_to?(:month)
|
97
|
+
|
93
98
|
matchdata = val.to_s.match(/^[0-9]+-([0-9]{2})(?![0-9])/)
|
94
99
|
matchdata[1].to_i if matchdata
|
95
100
|
end
|
96
101
|
|
97
102
|
def to_day(val)
|
98
103
|
return val.day if val.respond_to?(:day)
|
104
|
+
|
99
105
|
matchdata = val.to_s.match(/^[0-9]+-[0-9]{2}-([0-9]{2})(?![0-9])/)
|
100
106
|
matchdata[1].to_i if matchdata
|
101
107
|
end
|
102
108
|
|
103
109
|
def to_datetime(val)
|
104
110
|
return val if val.is_a?(DateTime)
|
111
|
+
|
105
112
|
DateTime.parse(val.to_s)
|
106
113
|
rescue ArgumentError
|
107
114
|
nil
|
@@ -110,6 +117,7 @@ module Datacite
|
|
110
117
|
def to_date(val)
|
111
118
|
return val if val.is_a?(::Date)
|
112
119
|
return ::Date.parse(val.iso8601) if val.respond_to?(:iso8601)
|
120
|
+
|
113
121
|
::Date.parse(val.to_s)
|
114
122
|
rescue ArgumentError
|
115
123
|
nil
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -17,6 +19,9 @@ module Datacite
|
|
17
19
|
# @!parse TABLE_OF_CONTENTS = TableOfContents
|
18
20
|
new :TABLE_OF_CONTENTS, 'TableOfContents'
|
19
21
|
|
22
|
+
# @!parse TECHNICAL_INFO = TechnicalInfo
|
23
|
+
new :TECHNICAL_INFO, 'TechnicalInfo'
|
24
|
+
|
20
25
|
# @!parse OTHER = Other
|
21
26
|
new :OTHER, 'Other'
|
22
27
|
|
@@ -88,12 +93,13 @@ module Datacite
|
|
88
93
|
end
|
89
94
|
|
90
95
|
def language=(value)
|
91
|
-
@language = value
|
96
|
+
@language = value&.strip
|
92
97
|
end
|
93
98
|
|
94
|
-
def value=(
|
95
|
-
new_value =
|
96
|
-
|
99
|
+
def value=(a_value)
|
100
|
+
new_value = a_value&.strip
|
101
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless new_value && !new_value.empty?
|
102
|
+
|
97
103
|
@value = new_value
|
98
104
|
end
|
99
105
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -6,6 +8,7 @@ module Datacite
|
|
6
8
|
module EmptyNodeUtils
|
7
9
|
def not_empty(element)
|
8
10
|
return unless element
|
11
|
+
|
9
12
|
text = element.text
|
10
13
|
empty = text.nil? || text.strip.empty?
|
11
14
|
warn "Ignoring empty element #{element}" if empty
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -13,6 +15,9 @@ module Datacite
|
|
13
15
|
# @!parse CROSSREF_FUNDER = 'Crossref Funder ID'
|
14
16
|
new :CROSSREF_FUNDER_ID, 'Crossref Funder ID'
|
15
17
|
|
18
|
+
# @!parse ROR = ROR
|
19
|
+
new :ROR, 'ROR'
|
20
|
+
|
16
21
|
# @!parse OTHER = Other
|
17
22
|
new :OTHER, 'Other'
|
18
23
|
end
|
@@ -22,18 +27,21 @@ module Datacite
|
|
22
27
|
|
23
28
|
# @param type [FunderIdentifierType] the identifier type. Cannot be nil.
|
24
29
|
# @param value [String] the identifier value. Cannot be nil.
|
25
|
-
def initialize(type:, value:)
|
30
|
+
def initialize(type:, scheme_uri: nil, value:)
|
26
31
|
self.type = type
|
32
|
+
self.scheme_uri = scheme_uri
|
27
33
|
self.value = value
|
28
34
|
end
|
29
35
|
|
30
36
|
def value=(value)
|
31
|
-
|
37
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless value && !value.empty?
|
38
|
+
|
32
39
|
@value = value
|
33
40
|
end
|
34
41
|
|
35
42
|
def type=(value)
|
36
|
-
|
43
|
+
raise ArgumentError, 'Type cannot be nil' unless value
|
44
|
+
|
37
45
|
@type = value
|
38
46
|
end
|
39
47
|
|
@@ -45,6 +53,10 @@ module Datacite
|
|
45
53
|
# @return [FunderIdentifierType] the identifier type. Cannot be nil.
|
46
54
|
typesafe_enum_node :type, '@funderIdentifierType', class: FunderIdentifierType
|
47
55
|
|
56
|
+
# @!attribute [rw] scheme_uri
|
57
|
+
# @return [URI, nil] the URI of the identifier scheme. Optional.
|
58
|
+
uri_node :scheme_uri, '@schemeURI', default_value: nil
|
59
|
+
|
48
60
|
# @!attribute [rw] value
|
49
61
|
# @return [String] the identifier value. Cannot be nil.
|
50
62
|
text_node :value, 'text()'
|
@@ -59,7 +71,8 @@ module Datacite
|
|
59
71
|
end
|
60
72
|
|
61
73
|
def value=(value)
|
62
|
-
|
74
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless value && !value.empty?
|
75
|
+
|
63
76
|
@value = value
|
64
77
|
end
|
65
78
|
|
@@ -89,15 +102,11 @@ module Datacite
|
|
89
102
|
end
|
90
103
|
|
91
104
|
def award_number=(value)
|
92
|
-
@award_number =
|
93
|
-
value
|
94
|
-
else
|
95
|
-
AwardNumber.new(value: value.to_s)
|
96
|
-
end
|
105
|
+
@award_number = award_number_or_nil(value)
|
97
106
|
end
|
98
107
|
|
99
108
|
def to_s
|
100
|
-
fields = [
|
109
|
+
fields = %i[name identifier award_number award_title].map { |f| "#{f}: #{send(f)}" }
|
101
110
|
"FundingReference { #{fields.join(', ')} }"
|
102
111
|
end
|
103
112
|
|
@@ -107,6 +116,18 @@ module Datacite
|
|
107
116
|
text_node :award_title, 'awardTitle', default_value: nil
|
108
117
|
|
109
118
|
fallback_mapping :datacite_3, :_default
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def award_number_or_nil(value)
|
123
|
+
return nil unless value
|
124
|
+
return value if value.is_a?(AwardNumber)
|
125
|
+
|
126
|
+
new_value = value.to_s.strip
|
127
|
+
return nil if new_value.empty?
|
128
|
+
|
129
|
+
AwardNumber.new(value: new_value)
|
130
|
+
end
|
110
131
|
end
|
111
132
|
end
|
112
133
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping_extensions'
|
2
4
|
require 'datacite/mapping/geo_location_point'
|
3
5
|
require 'datacite/mapping/geo_location_box'
|
@@ -19,11 +21,12 @@ module Datacite
|
|
19
21
|
# @param box [GeoLocationBox, nil] the latitude-longitude quadrangle containing the area where the data was gathered or about which the data is focused.
|
20
22
|
# @param place [String, nil] the spatial region or named place where the data was gathered or about which the data is focused.
|
21
23
|
# @param polygon [GeoLocationPolygon, nil] a drawn polygon area containing the area where the data was gathered or about which the data is focused.
|
22
|
-
def initialize(point: nil, box: nil, place: nil, polygon: nil)
|
24
|
+
def initialize(point: nil, box: nil, place: nil, polygon: nil, polygons: [])
|
23
25
|
self.point = point
|
24
26
|
self.box = box
|
25
27
|
self.place = place
|
26
28
|
self.polygon = polygon
|
29
|
+
self.polygons = polygons
|
27
30
|
end
|
28
31
|
|
29
32
|
def place=(value)
|
@@ -48,6 +51,10 @@ module Datacite
|
|
48
51
|
# # @return [GeoLocationPolygon] a drawn polygon area containing the area where the data was gathered or about which the data is focused.
|
49
52
|
object_node :polygon, 'geoLocationPolygon', class: GeoLocationPolygon, default_value: nil
|
50
53
|
|
54
|
+
# @!attribute [rw] polygons
|
55
|
+
# @return [Array<GeoLocationPolygon>] multiple polygons where data is contained
|
56
|
+
array_node :polygons, 'geoLocationPolygons', 'geoLocationPolygon', class: GeoLocationPolygon, default_value: []
|
57
|
+
|
51
58
|
# @!attribute [rw] place
|
52
59
|
# @return [String, nil] the spatial region or named place where the data was gathered or about which the data is focused.
|
53
60
|
text_node :place, 'geoLocationPlace', default_value: nil
|
@@ -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
|
|
@@ -53,31 +55,35 @@ module Datacite
|
|
53
55
|
when 4
|
54
56
|
init_from_array(args)
|
55
57
|
else
|
56
|
-
|
58
|
+
raise ArgumentError, "Can't construct GeoLocationBox from arguments: #{args}"
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
60
62
|
def south_latitude=(value)
|
61
|
-
|
62
|
-
|
63
|
+
raise ArgumentError, 'South latitude cannot be nil' unless value
|
64
|
+
raise ArgumentError, "#{value} is not a valid south latitude" unless value >= -90 && value <= 90
|
65
|
+
|
63
66
|
@south_latitude = value
|
64
67
|
end
|
65
68
|
|
66
69
|
def west_longitude=(value)
|
67
|
-
|
68
|
-
|
70
|
+
raise ArgumentError, 'West longitude cannot be nil' unless value
|
71
|
+
raise ArgumentError, "#{value} is not a valid west longitude" unless value >= -180 && value <= 180
|
72
|
+
|
69
73
|
@west_longitude = value
|
70
74
|
end
|
71
75
|
|
72
76
|
def north_latitude=(value)
|
73
|
-
|
74
|
-
|
77
|
+
raise ArgumentError, 'North latitude cannot be nil' unless value
|
78
|
+
raise ArgumentError, "#{value} is not a valid north latitude" unless value >= -90 && value <= 90
|
79
|
+
|
75
80
|
@north_latitude = value
|
76
81
|
end
|
77
82
|
|
78
83
|
def east_longitude=(value)
|
79
|
-
|
80
|
-
|
84
|
+
raise ArgumentError, 'East longitude cannot be nil' unless value
|
85
|
+
raise ArgumentError, "#{value} is not a valid east longitude" unless value >= -180 && value <= 180
|
86
|
+
|
81
87
|
@east_longitude = value
|
82
88
|
end
|
83
89
|
|
@@ -94,7 +100,8 @@ module Datacite
|
|
94
100
|
# {GeoLocationBox}
|
95
101
|
def <=>(other)
|
96
102
|
return nil unless other.class == self.class
|
97
|
-
|
103
|
+
|
104
|
+
%i[south_latitude west_longitude north_latitude east_longitude].each do |c|
|
98
105
|
order = send(c) <=> other.send(c)
|
99
106
|
return order if order.nonzero?
|
100
107
|
end
|
@@ -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,12 @@ module Datacite
|
|
9
11
|
attr_reader :coord_elements
|
10
12
|
|
11
13
|
def initialize(*args)
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
raise 'No geometry class provided' unless @geom_class
|
15
|
+
raise 'No coordinate elements provided' unless @coord_elements
|
16
|
+
|
17
|
+
path, *myargs = super(*args)
|
15
18
|
@path = ::XML::XXPath.new(path)
|
16
|
-
|
19
|
+
myargs # rubocop:disable Lint/Void
|
17
20
|
end
|
18
21
|
|
19
22
|
def datacite_3?
|
@@ -21,13 +24,14 @@ module Datacite
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def extract_attr_value(xml)
|
24
|
-
|
25
|
-
rescue => e
|
27
|
+
from_text(xml) || from_children(xml)
|
28
|
+
rescue StandardError => e
|
26
29
|
raise e, "#{@owner}.#{@attrname}: Can't extract #{self.class} from #{xml}: #{e.message}"
|
27
30
|
end
|
28
31
|
|
29
|
-
def set_attr_value(xml, value)
|
30
|
-
|
32
|
+
def set_attr_value(xml, value)
|
33
|
+
raise "Invalid value: expected #{geom_class} instance, was #{value || 'nil'}" unless value&.is_a?(geom_class)
|
34
|
+
|
31
35
|
element = @path.first(xml, ensure_created: true)
|
32
36
|
|
33
37
|
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,21 @@ 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
|
45
|
+
|
43
46
|
@latitude = value
|
44
47
|
end
|
45
48
|
|
46
49
|
def longitude=(value)
|
47
|
-
|
48
|
-
|
50
|
+
raise ArgumentError, 'Longitude cannot be nil' unless value
|
51
|
+
raise ArgumentError, "#{value} is not a valid longitude" unless value >= -180 && value <= 180
|
52
|
+
|
49
53
|
@longitude = value
|
50
54
|
end
|
51
55
|
|
@@ -62,7 +66,8 @@ module Datacite
|
|
62
66
|
# {GeoLocationPoint}
|
63
67
|
def <=>(other)
|
64
68
|
return nil unless other.class == self.class
|
65
|
-
|
69
|
+
|
70
|
+
%i[latitude longitude].each do |c|
|
66
71
|
order = send(c) <=> other.send(c)
|
67
72
|
return order if order.nonzero?
|
68
73
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
|
3
5
|
module Datacite
|
@@ -11,10 +13,11 @@ module Datacite
|
|
11
13
|
# @param points [Array<GeoLocationPoint>] an array of points defining the polygon area.
|
12
14
|
# Per the spec, the array should contain at least four points, the first and last being
|
13
15
|
# identical to close the polygon.
|
14
|
-
def initialize(points:) # TODO: allow simple array of point args, array of hashes
|
16
|
+
def initialize(points:, in_polygon_point: nil) # TODO: allow simple array of point args, array of hashes
|
15
17
|
self.points = points
|
18
|
+
self.in_polygon_point = in_polygon_point
|
16
19
|
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]}]"
|
20
|
+
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
21
|
end
|
19
22
|
|
20
23
|
def points=(value)
|
@@ -23,6 +26,7 @@ module Datacite
|
|
23
26
|
|
24
27
|
def <=>(other)
|
25
28
|
return nil unless other.class == self.class
|
29
|
+
|
26
30
|
points <=> other.points
|
27
31
|
end
|
28
32
|
|
@@ -42,6 +46,13 @@ module Datacite
|
|
42
46
|
marshaller: (proc { |xml, value| marshal_point(xml, value) }),
|
43
47
|
unmarshaller: (proc { |xml| unmarshal_point(xml) })
|
44
48
|
|
49
|
+
# # @!attribute [rw] in_polygon_point
|
50
|
+
# # @return [InPolygonPoint] a point within the target polygon
|
51
|
+
object_node :in_polygon_point, 'inPolygonPoint',
|
52
|
+
default_value: nil,
|
53
|
+
marshaller: (proc { |xml, value| marshal_point(xml, value) }),
|
54
|
+
unmarshaller: (proc { |xml| unmarshal_point(xml) })
|
55
|
+
|
45
56
|
use_mapping :datacite_3
|
46
57
|
|
47
58
|
# TODO: does this ever get called?
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'xml/mapping'
|
2
4
|
require 'datacite/mapping/empty_filtering_nodes'
|
3
5
|
|
4
6
|
module Datacite
|
5
7
|
module Mapping
|
6
|
-
DOI_PATTERN = %r{10\.\S+/\S+}
|
8
|
+
DOI_PATTERN = %r{10\.\S+/\S+}.freeze
|
7
9
|
|
8
10
|
# The persistent identifier that identifies the resource.
|
9
11
|
#
|
@@ -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]
|
@@ -24,19 +26,21 @@ module Datacite
|
|
24
26
|
self.value = value
|
25
27
|
end
|
26
28
|
|
27
|
-
def value=(
|
28
|
-
new_value =
|
29
|
-
|
30
|
-
|
29
|
+
def value=(new_value)
|
30
|
+
new_value = new_value&.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)
|
33
|
+
|
31
34
|
@value = new_value
|
32
35
|
end
|
33
36
|
|
34
37
|
# Sets the identifier type. Should only be called by the XML mapping engine.
|
35
|
-
# @param
|
38
|
+
# @param new_value [String]
|
36
39
|
# the identifier type (always 'DOI')
|
37
|
-
def identifier_type=(
|
38
|
-
|
39
|
-
|
40
|
+
def identifier_type=(new_value)
|
41
|
+
raise ArgumentError, "Identifier type '#{new_value}' must be 'DOI'" unless DOI == new_value
|
42
|
+
|
43
|
+
@identifier_type = new_value
|
40
44
|
end
|
41
45
|
|
42
46
|
# Gets the identifiery type.
|
@@ -48,7 +52,8 @@ module Datacite
|
|
48
52
|
# @param doi_string [String]
|
49
53
|
def self.from_doi(doi_string)
|
50
54
|
match = doi_string.match(DOI_PATTERN)
|
51
|
-
|
55
|
+
raise ArgumentError, "'#{doi_string}' does not appear to contain a valid DOI" unless match
|
56
|
+
|
52
57
|
Identifier.new(value: match[0])
|
53
58
|
end
|
54
59
|
|
@@ -58,18 +63,17 @@ module Datacite
|
|
58
63
|
fallback_mapping :datacite_3, :_default
|
59
64
|
end
|
60
65
|
|
61
|
-
# Custom node to
|
66
|
+
# Custom node to allow (but ignore) if we read an XML `<resource/>` that's
|
62
67
|
# missing its `<identifier/>`.
|
63
68
|
class IdentifierNode < XML::Mapping::ObjectNode
|
64
69
|
include EmptyNodeUtils
|
65
70
|
def xml_to_obj(_obj, xml)
|
66
71
|
return super if (element = has_element?(xml)) && not_empty(element)
|
67
|
-
warn 'Identifier not found; add a valid Identifier to the Resource before saving'
|
68
72
|
end
|
69
73
|
|
70
74
|
private
|
71
75
|
|
72
|
-
def has_element?(xml) # rubocop:disable
|
76
|
+
def has_element?(xml) # rubocop:disable Naming/PredicateName
|
73
77
|
@path.first(xml)
|
74
78
|
rescue XML::XXPathError
|
75
79
|
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.4.1'
|
8
10
|
|
9
11
|
# The copyright notice for this gem
|
10
|
-
COPYRIGHT = 'Copyright (c)
|
12
|
+
COPYRIGHT = 'Copyright (c) 2022 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
|
@@ -16,14 +18,16 @@ module Datacite
|
|
16
18
|
self.value = value
|
17
19
|
end
|
18
20
|
|
19
|
-
def scheme=(
|
20
|
-
|
21
|
-
|
21
|
+
def scheme=(new_value)
|
22
|
+
raise ArgumentError, 'Scheme cannot be empty or nil' unless new_value && !new_value.empty?
|
23
|
+
|
24
|
+
@scheme = new_value
|
22
25
|
end
|
23
26
|
|
24
|
-
def value=(
|
25
|
-
|
26
|
-
|
27
|
+
def value=(new_value)
|
28
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless new_value && !new_value.empty?
|
29
|
+
|
30
|
+
@value = new_value
|
27
31
|
end
|
28
32
|
|
29
33
|
root_element_name 'nameIdentifier'
|
@@ -31,9 +35,11 @@ module Datacite
|
|
31
35
|
# @!attribute [rw] scheme
|
32
36
|
# @return [String] the name identifier scheme. Cannot be nil.
|
33
37
|
text_node :scheme, '@nameIdentifierScheme'
|
38
|
+
|
34
39
|
# @!attribute [rw] scheme_uri
|
35
40
|
# @return [URI, nil] the URI of the identifier scheme. Optional.
|
36
41
|
uri_node :scheme_uri, '@schemeURI', default_value: nil
|
42
|
+
|
37
43
|
# @!attribute [rw] value
|
38
44
|
# @return [String] the identifier value. Cannot be nil.
|
39
45
|
text_node :value, 'text()'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xml/mapping'
|
4
|
+
require 'datacite/mapping/read_only_nodes'
|
5
|
+
|
6
|
+
module Datacite
|
7
|
+
module Mapping
|
8
|
+
|
9
|
+
# Controlled vocabulary of name types
|
10
|
+
class NameType < TypesafeEnum::Base
|
11
|
+
# @!parse ORGANIZATIONAL = Organizational
|
12
|
+
new :ORGANIZATIONAL, 'Organizational'
|
13
|
+
|
14
|
+
# @!parse PERSONAL = Personal
|
15
|
+
new :PERSONAL, 'Personal'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'xml/mapping_extensions'
|
4
|
+
|
5
|
+
module Datacite
|
6
|
+
module Mapping
|
7
|
+
|
8
|
+
# The type of the resource
|
9
|
+
class Publisher
|
10
|
+
include XML::Mapping
|
11
|
+
|
12
|
+
# Initializes a new {Publisher}
|
13
|
+
# @param language [String, nil] an IETF BCP 47, ISO 639-1 language code identifying the language.
|
14
|
+
# @param value [String] name of the publisher
|
15
|
+
def initialize(language: nil, value:)
|
16
|
+
self.language = language
|
17
|
+
self.value = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def language=(value)
|
21
|
+
@language = value&.strip
|
22
|
+
end
|
23
|
+
|
24
|
+
def value=(value)
|
25
|
+
new_value = value&.strip
|
26
|
+
raise ArgumentError, 'Value cannot be empty or nil' unless new_value && !new_value.empty?
|
27
|
+
|
28
|
+
@value = new_value.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!attribute [rw] language
|
32
|
+
# @return [String] an IETF BCP 47, ISO 639-1 language code identifying the language.
|
33
|
+
text_node :language, '@xml:lang', default_value: nil
|
34
|
+
|
35
|
+
# @!attribute [rw] value
|
36
|
+
# @return [String] the title itself.
|
37
|
+
text_node :value, 'text()'
|
38
|
+
|
39
|
+
fallback_mapping :datacite_3, :_default
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|