datacite-mapping 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.
- checksums.yaml +7 -0
- data/.gitignore +42 -0
- data/.rubocop.yml +28 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -0
- data/.yardopts +2 -0
- data/CHANGES.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE.md +22 -0
- data/README.md +168 -0
- data/Rakefile +49 -0
- data/datacite-mapping.gemspec +37 -0
- data/examples/reading.rb +75 -0
- data/examples/writing.rb +49 -0
- data/lib/datacite/mapping.rb +36 -0
- data/lib/datacite/mapping/alternate_identifier.rb +45 -0
- data/lib/datacite/mapping/contributor.rb +125 -0
- data/lib/datacite/mapping/creator.rb +48 -0
- data/lib/datacite/mapping/date.rb +153 -0
- data/lib/datacite/mapping/description.rb +121 -0
- data/lib/datacite/mapping/geo_location.rb +49 -0
- data/lib/datacite/mapping/geo_location_box.rb +137 -0
- data/lib/datacite/mapping/geo_location_point.rb +102 -0
- data/lib/datacite/mapping/identifier.rb +45 -0
- data/lib/datacite/mapping/module_info.rb +12 -0
- data/lib/datacite/mapping/name_identifier.rb +48 -0
- data/lib/datacite/mapping/related_identifier.rb +209 -0
- data/lib/datacite/mapping/resource.rb +201 -0
- data/lib/datacite/mapping/resource_type.rb +83 -0
- data/lib/datacite/mapping/rights.rb +36 -0
- data/lib/datacite/mapping/subject.rb +55 -0
- data/lib/datacite/mapping/title.rb +69 -0
- data/spec/.rubocop.yml +7 -0
- data/spec/data/resource.xml +61 -0
- data/spec/rspec_custom_matchers.rb +69 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/datacite/mapping/alternate_identifier_spec.rb +60 -0
- data/spec/unit/datacite/mapping/contributor_spec.rb +129 -0
- data/spec/unit/datacite/mapping/creator_spec.rb +125 -0
- data/spec/unit/datacite/mapping/date_spec.rb +246 -0
- data/spec/unit/datacite/mapping/description_spec.rb +89 -0
- data/spec/unit/datacite/mapping/geo_location_box_spec.rb +241 -0
- data/spec/unit/datacite/mapping/geo_location_point_spec.rb +148 -0
- data/spec/unit/datacite/mapping/geo_location_spec.rb +116 -0
- data/spec/unit/datacite/mapping/identifier_spec.rb +75 -0
- data/spec/unit/datacite/mapping/name_identifier_spec.rb +89 -0
- data/spec/unit/datacite/mapping/related_identifier_spec.rb +157 -0
- data/spec/unit/datacite/mapping/resource_spec.rb +727 -0
- data/spec/unit/datacite/mapping/resource_type_spec.rb +69 -0
- data/spec/unit/datacite/mapping/rights_spec.rb +78 -0
- data/spec/unit/datacite/mapping/subject_spec.rb +108 -0
- data/spec/unit/datacite/mapping/title_spec.rb +113 -0
- metadata +262 -0
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'xml/mapping_extensions'
|
2
|
+
|
3
|
+
module Datacite
|
4
|
+
module Mapping
|
5
|
+
|
6
|
+
# Controlled vocabulary of description types.
|
7
|
+
class DescriptionType < TypesafeEnum::Base
|
8
|
+
# @!parse ABSTRACT = Abstract
|
9
|
+
new :ABSTRACT, 'Abstract'
|
10
|
+
|
11
|
+
# @!parse METHODS = Methods
|
12
|
+
new :METHODS, 'Methods'
|
13
|
+
|
14
|
+
# @!parse SERIES_INFORMATION = SeriesInformation
|
15
|
+
new :SERIES_INFORMATION, 'SeriesInformation'
|
16
|
+
|
17
|
+
# @!parse TABLE_OF_CONTENTS = TableOfContents
|
18
|
+
new :TABLE_OF_CONTENTS, 'TableOfContents'
|
19
|
+
|
20
|
+
# @!parse OTHER = Other
|
21
|
+
new :OTHER, 'Other'
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# XML mapping class preserving `<br/>` tags in description values
|
26
|
+
class BreakPreservingValueNode < XML::Mapping::SingleAttributeNode
|
27
|
+
# Collapses a sequence of text nodes and `<br/>` tags into a single string value.
|
28
|
+
# Implements `SingleAttributeNode#xml_to_obj`.
|
29
|
+
# @param obj [Description] the object being created
|
30
|
+
# @param xml [REXML::Element] the XML being read
|
31
|
+
def xml_to_obj(obj, xml)
|
32
|
+
value_str = xml.children.map { |c| c.respond_to?(:value) ? c.value : c.to_s }.join
|
33
|
+
obj.value = value_str.strip
|
34
|
+
end
|
35
|
+
|
36
|
+
# Converts a string value to a sequence of text nodes and `<br/>` tags.
|
37
|
+
# Implements `SingleAttributeNode#obj_to_xml`.
|
38
|
+
# @param obj [Description] the object being serialized
|
39
|
+
# @param xml [REXML::Element] the XML being written
|
40
|
+
def obj_to_xml(obj, xml)
|
41
|
+
value_str = obj.value || ''
|
42
|
+
values = value_str.split(%r{<br[^/]?/>|<br>[^<]*</br>})
|
43
|
+
values.each_with_index do |v, i|
|
44
|
+
xml.add_text(v)
|
45
|
+
xml.add_element('br') unless i + 1 >= values.size
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
XML::Mapping.add_node_class BreakPreservingValueNode
|
50
|
+
|
51
|
+
# A additional information that does not fit in the other more specific {Resource}
|
52
|
+
# attributes.
|
53
|
+
#
|
54
|
+
# Note: In accordance with the DataCite spec, description text can be separated by
|
55
|
+
# HTML `<br/>` tags. The {Description} class will preserve these, but at the expense
|
56
|
+
# of converting escaped `<br/>` in text values to actual `<br/>` tags. For example,
|
57
|
+
# when reading the following tag:
|
58
|
+
#
|
59
|
+
# <description xml:lang="en-us" descriptionType="Abstract">
|
60
|
+
# Line 1<br/>Line 2 containing escaped <br/> tag<br/>Line 3
|
61
|
+
# </description>
|
62
|
+
#
|
63
|
+
# the value will be returned as the string
|
64
|
+
#
|
65
|
+
# "Line 1<br/>Line 2 containing escaped <br/> tag<br/>Line 3"
|
66
|
+
#
|
67
|
+
# in which it is impossible to distinguish the escaped an un-escaped `<br/>`s. The
|
68
|
+
# value would thus be written back to XML as:
|
69
|
+
#
|
70
|
+
# <description xml:lang="en-us" descriptionType="Abstract">
|
71
|
+
# Line 1<br/>Line 2 containing escaped <br/> tag<br/>Line 3
|
72
|
+
# </description>
|
73
|
+
#
|
74
|
+
# Other escaped HTML or XML tags will still be escaped when written back, and other
|
75
|
+
# un-escaped HTML and XML tags are of course not allowed.
|
76
|
+
class Description
|
77
|
+
include XML::Mapping
|
78
|
+
|
79
|
+
# @!attribute [rw] language
|
80
|
+
# @return [String] an IETF BCP 47, ISO 639-1 language code identifying the language.
|
81
|
+
# It's unclear from the spec whether language is required; to play it safe, if it's missing, we default to 'en'.
|
82
|
+
text_node :language, '@xml:lang', default_value: nil
|
83
|
+
|
84
|
+
# @!attribute [rw] type
|
85
|
+
# @return [DescriptionType] the description type.
|
86
|
+
typesafe_enum_node :type, '@descriptionType', class: DescriptionType
|
87
|
+
|
88
|
+
# @!attribute [rw] value
|
89
|
+
# @return [String] the description itself. See {Description} for notes on special
|
90
|
+
# handling of `<br/>` tags.
|
91
|
+
break_preserving_value_node :value, 'node()'
|
92
|
+
|
93
|
+
alias_method :_language, :language
|
94
|
+
private :_language
|
95
|
+
|
96
|
+
alias_method :_language=, :language=
|
97
|
+
private :_language=
|
98
|
+
|
99
|
+
# Initializes a new {Description}
|
100
|
+
# @param language [String] an IETF BCP 47, ISO 639-1 language code identifying the language.
|
101
|
+
# It's unclear from the spec whether language is required; to play it safe, if it's missing, we default to 'en'.
|
102
|
+
# @param type [DescriptionType] the description type.
|
103
|
+
# @param value [String] the description itself. See {Description} for notes on special
|
104
|
+
# handling of `<br/>` tags.
|
105
|
+
def initialize(language: 'en', type:, value:)
|
106
|
+
self.language = language
|
107
|
+
self.type = type
|
108
|
+
self.value = value
|
109
|
+
end
|
110
|
+
|
111
|
+
def language
|
112
|
+
_language || 'en'
|
113
|
+
end
|
114
|
+
|
115
|
+
def language=(value)
|
116
|
+
self._language = value.strip if value
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'xml/mapping_extensions'
|
2
|
+
require_relative 'geo_location_point'
|
3
|
+
require_relative 'geo_location_box'
|
4
|
+
|
5
|
+
module Datacite
|
6
|
+
module Mapping
|
7
|
+
|
8
|
+
# A location at which the data was gathered or about which the data is focused, in the
|
9
|
+
# form of a latitude-longitude point, a latitude-longitude quadrangle, and/or a place name.
|
10
|
+
#
|
11
|
+
# *Note:* Due to a quirk of the DataCite spec, it is possible for a {GeoLocation} to be empty, with
|
12
|
+
# none of these present.
|
13
|
+
class GeoLocation
|
14
|
+
include XML::Mapping
|
15
|
+
|
16
|
+
root_element_name 'geoLocation'
|
17
|
+
|
18
|
+
# @!attribute [rw] point
|
19
|
+
# @return [GeoLocationPoint, nil] the latitude and longitude at which the data was gathered or about which the data is focused.
|
20
|
+
geo_location_point_node :point, 'geoLocationPoint', default_value: nil
|
21
|
+
|
22
|
+
# @!attribute [rw] box
|
23
|
+
# @return [GeoLocationBox, nil] the latitude-longitude quadrangle containing the area where the data was gathered or about which the data is focused.
|
24
|
+
geo_location_box_node :box, 'geoLocationBox', default_value: nil
|
25
|
+
|
26
|
+
# @!attribute [rw] place
|
27
|
+
# @return [String, nil] the spatial region or named place where the data was gathered or about which the data is focused.
|
28
|
+
text_node :place, 'geoLocationPlace', default_value: nil
|
29
|
+
|
30
|
+
# Initializes a new {GeoLocation}
|
31
|
+
# @param point [GeoLocationPoint, nil] the latitude and longitude at which the data was gathered or about which the data is focused.
|
32
|
+
# @param box [GeoLocationBox, nil] the latitude-longitude quadrangle containing the area where the data was gathered or about which the data is focused.
|
33
|
+
# @param place [String, nil] the spatial region or named place where the data was gathered or about which the data is focused.
|
34
|
+
def initialize(point: nil, box: nil, place: nil)
|
35
|
+
self.point = point
|
36
|
+
self.box = box
|
37
|
+
self.place = place
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :_place=, :place=
|
41
|
+
private :_place=
|
42
|
+
|
43
|
+
def place=(value)
|
44
|
+
self._place = value.respond_to?(:strip) ? value.strip : value
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'xml/mapping'
|
2
|
+
|
3
|
+
module Datacite
|
4
|
+
module Mapping
|
5
|
+
# A latitude-longitude quadrangle containing the area where the data was gathered or about
|
6
|
+
# which the data is focused.
|
7
|
+
#
|
8
|
+
# @!attribute [rw] south_latitude
|
9
|
+
# @return [Numeric] the latitude of the south edge of the box
|
10
|
+
# @!attribute [rw] west_longitude
|
11
|
+
# @return [Numeric] the longitude of the west edge of the box
|
12
|
+
# @!attribute [rw] north_latitude
|
13
|
+
# @return [Numeric] the latitude of the north edge of the box
|
14
|
+
# @!attribute [rw] east_longitude
|
15
|
+
# @return [Numeric] the longitude of the east edge of the box
|
16
|
+
class GeoLocationBox
|
17
|
+
include Comparable
|
18
|
+
|
19
|
+
attr_reader :south_latitude
|
20
|
+
attr_reader :west_longitude
|
21
|
+
attr_reader :north_latitude
|
22
|
+
attr_reader :east_longitude
|
23
|
+
|
24
|
+
# Initializes a new {GeoLocationBox}. The arguments can be provided
|
25
|
+
# either as a named-parameter hash, or as a list of four coordinates
|
26
|
+
# in the form `lat, long, lat, long` (typically
|
27
|
+
# `south_latitude, west_longitude, north_latitude, east_longitude`
|
28
|
+
# but not necessarily; north/south and east/west will be flipped if
|
29
|
+
# need be). That is, the following forms are equivalent:
|
30
|
+
#
|
31
|
+
# GeoLocationBox.new(
|
32
|
+
# south_latitude: -33.45,
|
33
|
+
# west_longitude: -122.33,
|
34
|
+
# north_latitude: 47.61,
|
35
|
+
# east_longitude: -70.67
|
36
|
+
# )
|
37
|
+
#
|
38
|
+
# GeoLocationBox.new(-33.45, -122.33, 47.61, -70.67)
|
39
|
+
#
|
40
|
+
# @param south_latitude [Numeric]
|
41
|
+
# the latitude of the south edge of the box
|
42
|
+
# @param west_longitude [Numeric]
|
43
|
+
# the longitude of the west edge of the box
|
44
|
+
# @param north_latitude [Numeric]
|
45
|
+
# the latitude of the north edge of the box
|
46
|
+
# @param east_longitude [Numeric]
|
47
|
+
# the longitude of the east edge of the box
|
48
|
+
def initialize(*args)
|
49
|
+
case args.length
|
50
|
+
when 1
|
51
|
+
init_from_hash(args[0])
|
52
|
+
when 4
|
53
|
+
init_from_array(args)
|
54
|
+
else
|
55
|
+
fail ArgumentError, "Can't construct GeoLocationBox from arguments: #{args}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def south_latitude=(value)
|
60
|
+
fail ArgumentError, 'South latitude cannot be nil' unless value
|
61
|
+
fail ArgumentError, "#{value} is not a valid south latitude" unless value >= -90 && value <= 90
|
62
|
+
@south_latitude = value
|
63
|
+
end
|
64
|
+
|
65
|
+
def west_longitude=(value)
|
66
|
+
fail ArgumentError, 'West longitude cannot be nil' unless value
|
67
|
+
fail ArgumentError, "#{value} is not a valid west longitude" unless value >= -180 && value <= 180
|
68
|
+
@west_longitude = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def north_latitude=(value)
|
72
|
+
fail ArgumentError, 'North latitude cannot be nil' unless value
|
73
|
+
fail ArgumentError, "#{value} is not a valid north latitude" unless value >= -90 && value <= 90
|
74
|
+
@north_latitude = value
|
75
|
+
end
|
76
|
+
|
77
|
+
def east_longitude=(value)
|
78
|
+
fail ArgumentError, 'East longitude cannot be nil' unless value
|
79
|
+
fail ArgumentError, "#{value} is not a valid east longitude" unless value >= -180 && value <= 180
|
80
|
+
@east_longitude = value
|
81
|
+
end
|
82
|
+
|
83
|
+
# Gets the box coordinates as a string.
|
84
|
+
# @return [String] the coordinates of the box as a sequence of four numbers, in the order S W N E.
|
85
|
+
def to_s
|
86
|
+
"#{south_latitude} #{west_longitude} #{north_latitude} #{east_longitude}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Sorts boxes from north to south and east to west, first by south edge, then west
|
90
|
+
# edge, then north edge, then east edge, and compares them for equality.
|
91
|
+
# @param other [GeoLocationBox] the box to compare
|
92
|
+
# @return [Fixnum, nil] the sort order (-1, 0, or 1), or nil if `other` is not a
|
93
|
+
# {GeoLocationBox}
|
94
|
+
def <=>(other)
|
95
|
+
return nil unless other.class == self.class
|
96
|
+
[:south_latitude, :west_longitude, :north_latitude, :east_longitude].each do |c|
|
97
|
+
order = send(c) <=> other.send(c)
|
98
|
+
return order if order != 0
|
99
|
+
end
|
100
|
+
0
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a hash code consistent with {GeoLocationBox#<=>}
|
104
|
+
# @return [Integer] the hash code
|
105
|
+
def hash
|
106
|
+
[south_latitude, west_longitude, north_latitude, east_longitude].hash
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def init_from_hash(south_latitude:, west_longitude:, north_latitude:, east_longitude:)
|
112
|
+
self.south_latitude = south_latitude
|
113
|
+
self.west_longitude = west_longitude
|
114
|
+
self.north_latitude = north_latitude
|
115
|
+
self.east_longitude = east_longitude
|
116
|
+
end
|
117
|
+
|
118
|
+
def init_from_array(coordinates)
|
119
|
+
self.south_latitude, self.north_latitude = [coordinates[0], coordinates[2]].sort
|
120
|
+
self.west_longitude, self.east_longitude = [coordinates[1], coordinates[3]].sort
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# XML mapping node for `<geoLocationBox/>`
|
125
|
+
class GeoLocationBoxNode < XML::MappingExtensions::NodeBase
|
126
|
+
# Converts a whitespace-separated list of coordinates to a {GeoLocationBox}.
|
127
|
+
# @param xml_text [String] the coordinates, in the order `lat long lat long`.
|
128
|
+
def to_value(xml_text)
|
129
|
+
stripped = xml_text.strip
|
130
|
+
coords = stripped.split(/\s+/).map(&:to_f)
|
131
|
+
GeoLocationBox.new(*coords)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
XML::Mapping.add_node_class GeoLocationBoxNode
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'xml/mapping'
|
2
|
+
|
3
|
+
module Datacite
|
4
|
+
module Mapping
|
5
|
+
# A latitude-longitude point at which the data was gathered or about
|
6
|
+
# which the data is focused.
|
7
|
+
#
|
8
|
+
# @!attribute [rw] latitude
|
9
|
+
# @return [Numeric] the latitude
|
10
|
+
# @!attribute [rw] longitude
|
11
|
+
# @return [Numeric] the longitude
|
12
|
+
class GeoLocationPoint
|
13
|
+
include Comparable
|
14
|
+
|
15
|
+
attr_reader :latitude
|
16
|
+
attr_reader :longitude
|
17
|
+
|
18
|
+
# Initializes a new {GeoLocationPoint}. The arguments can be provided
|
19
|
+
# either as a named-parameter hash, or as a pair of coordinates in the
|
20
|
+
# form `lat, long`. That is, the following forms are equivalent:
|
21
|
+
#
|
22
|
+
# GeoLocationPoint.new(latitude: 47.61, longitude: -122.33)
|
23
|
+
#
|
24
|
+
# GeoLocationPoint.new(47.61, -122.33)
|
25
|
+
#
|
26
|
+
# @param latitude [Numeric] the latitude
|
27
|
+
# @param longitude [Numeric] the longitude
|
28
|
+
def initialize(*args)
|
29
|
+
case args.length
|
30
|
+
when 1
|
31
|
+
init_from_hash(args[0])
|
32
|
+
when 2
|
33
|
+
init_from_array(args)
|
34
|
+
else
|
35
|
+
fail ArgumentError, "Can't construct GeoLocationPoint from arguments: #{args}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def latitude=(value)
|
40
|
+
fail ArgumentError, 'Latitude cannot be nil' unless value
|
41
|
+
fail ArgumentError, "#{value} is not a valid latitude" unless value >= -90 && value <= 90
|
42
|
+
@latitude = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def longitude=(value)
|
46
|
+
fail ArgumentError, 'Longitude cannot be nil' unless value
|
47
|
+
fail ArgumentError, "#{value} is not a valid longitude" unless value >= -180 && value <= 180
|
48
|
+
@longitude = value
|
49
|
+
end
|
50
|
+
|
51
|
+
# Gets the coordinates as a string.
|
52
|
+
# @return [String] the coordinates as a pair of numbers separated by a space, in the
|
53
|
+
# order `lat` `long`.
|
54
|
+
def to_s
|
55
|
+
"#{latitude} #{longitude}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sorts points from north to south and from east to west, and compares them for equality.
|
59
|
+
# @param other [GeoLocationPoint] the point to compare
|
60
|
+
# @return [Fixnum, nil] the sort order (-1, 0, or 1), or nil if `other` is not a
|
61
|
+
# {GeoLocationPoint}
|
62
|
+
def <=>(other)
|
63
|
+
return nil unless other.class == self.class
|
64
|
+
[:latitude, :longitude].each do |c|
|
65
|
+
order = send(c) <=> other.send(c)
|
66
|
+
return order if order != 0
|
67
|
+
end
|
68
|
+
0
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns a hash code consistent with {GeoLocationPoint#<=>}
|
72
|
+
# @return [Integer] the hash code
|
73
|
+
def hash
|
74
|
+
[latitude, longitude].hash
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def init_from_hash(latitude:, longitude:)
|
80
|
+
self.latitude = latitude
|
81
|
+
self.longitude = longitude
|
82
|
+
end
|
83
|
+
|
84
|
+
def init_from_array(args)
|
85
|
+
self.latitude, self.longitude = args
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# XML mapping node for `<geoLocationPoint/>`
|
90
|
+
class GeoLocationPointNode < XML::MappingExtensions::NodeBase
|
91
|
+
# Converts a whitespace-separated pair of coordinates to a {GeoLocationPoint}.
|
92
|
+
# @param xml_text [String] the coordinates, in the order `lat` `long`.
|
93
|
+
def to_value(xml_text)
|
94
|
+
stripped = xml_text.strip
|
95
|
+
coords = stripped.split(/\s+/).map(&:to_f)
|
96
|
+
GeoLocationPoint.new(*coords)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
XML::Mapping.add_node_class GeoLocationPointNode
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'xml/mapping'
|
2
|
+
|
3
|
+
module Datacite
|
4
|
+
module Mapping
|
5
|
+
# The persistent identifier that identifies the resource.
|
6
|
+
#
|
7
|
+
# @!attribute [r] identifier_type
|
8
|
+
# @return [String] the identifier type (always 'DOI')
|
9
|
+
# @!attribute [rw] value
|
10
|
+
# @return [String] the identifier value. Must be a valid DOI value (`10.`_registrant code_`/`_suffix_)
|
11
|
+
class Identifier
|
12
|
+
include XML::Mapping
|
13
|
+
|
14
|
+
text_node :identifier_type, '@identifierType'
|
15
|
+
text_node :value, 'text()'
|
16
|
+
|
17
|
+
# Initializes a new {Identifier}
|
18
|
+
# @param value [String]
|
19
|
+
# the identifier value. Must be a valid DOI value (`10.`_registrant code_`/`_suffix_)
|
20
|
+
def initialize(value:)
|
21
|
+
self.identifier_type = 'DOI'
|
22
|
+
self.value = value
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method :_value=, :value=
|
26
|
+
private :_value=
|
27
|
+
|
28
|
+
alias_method :_identifier_type=, :identifier_type=
|
29
|
+
private :_identifier_type=
|
30
|
+
|
31
|
+
def value=(v)
|
32
|
+
fail ArgumentError, "Identifier value '#{v}' is not a valid DOI" unless v.match(%r{10\..+/.+})
|
33
|
+
self._value = v
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sets the identifier type. Should only be called by the XML mapping engine.
|
37
|
+
# @param v [String]
|
38
|
+
# the identifier type (always 'DOI')
|
39
|
+
def identifier_type=(v)
|
40
|
+
fail ArgumentError, "Identifier type '#{v}' must be 'DOI'" unless 'DOI' == v
|
41
|
+
self._identifier_type = v
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|