ezid-client 1.0.1 → 1.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 +4 -4
- data/.travis.yml +1 -3
- data/VERSION +1 -1
- data/lib/ezid/client.rb +2 -2
- data/lib/ezid/configuration.rb +6 -0
- data/lib/ezid/identifier.rb +55 -42
- data/lib/ezid/metadata.rb +75 -29
- data/spec/unit/identifier_spec.rb +23 -15
- data/spec/unit/metadata_spec.rb +13 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcda4d65432df1b88c9727ca05e22a8f214f27b6
|
4
|
+
data.tar.gz: 878ccc4caf544c3fd1f1b3cedc9da7ed6a72180d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 778b583288d8bbc0bf8463ed3caadb117babfa5ef092c838367ddfbb7d6043b7186eeff4101d1fb0c51871299371e31e371cf5ace8f81e59eb168373b5f46422
|
7
|
+
data.tar.gz: 9d149efa596af0db3268522cff9deeecfcf72f235608367311adc6ee5d3c86ba087c6519cfba44c15edd30c60158423e5245d09ac4e99f1ad7501d76dd5e7990
|
data/.travis.yml
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/lib/ezid/client.rb
CHANGED
@@ -59,8 +59,8 @@ module Ezid
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def inspect
|
62
|
-
"#<#{self.class.name} connection=#{connection.inspect} " \
|
63
|
-
"user
|
62
|
+
"#<#{self.class.name} connection=#{connection.inspect}, " \
|
63
|
+
"user=#{user.inspect}, session=#{logged_in? ? 'OPEN' : 'CLOSED'}>"
|
64
64
|
end
|
65
65
|
|
66
66
|
# The client configuration
|
data/lib/ezid/configuration.rb
CHANGED
@@ -49,6 +49,12 @@ module Ezid
|
|
49
49
|
@default_shoulder = ENV["EZID_DEFAULT_SHOULDER"]
|
50
50
|
end
|
51
51
|
|
52
|
+
def inspect
|
53
|
+
ivars = instance_variables.reject { |v| v == :@password }
|
54
|
+
.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }
|
55
|
+
"#<#{self.class.name} #{ivars.join(', ')}>"
|
56
|
+
end
|
57
|
+
|
52
58
|
def logger
|
53
59
|
@logger ||= Logger.new(STDERR)
|
54
60
|
end
|
data/lib/ezid/identifier.rb
CHANGED
@@ -2,14 +2,14 @@ module Ezid
|
|
2
2
|
#
|
3
3
|
# Represents an EZID identifier as a resource.
|
4
4
|
#
|
5
|
-
# Ezid::Identifier delegates access to registered metadata elements through #method_missing.
|
6
|
-
#
|
7
5
|
# @api public
|
8
6
|
#
|
9
7
|
class Identifier
|
10
8
|
|
11
|
-
attr_reader :
|
12
|
-
attr_accessor :shoulder, :metadata
|
9
|
+
attr_reader :client
|
10
|
+
attr_accessor :id, :shoulder, :metadata, :state
|
11
|
+
|
12
|
+
private :state, :state=, :id=
|
13
13
|
|
14
14
|
# Attributes to display on inspect
|
15
15
|
INSPECT_ATTRS = %w( id status target created )
|
@@ -46,15 +46,16 @@ module Ezid
|
|
46
46
|
@client = args.delete(:client) || Client.new
|
47
47
|
@id = args.delete(:id)
|
48
48
|
@shoulder = args.delete(:shoulder)
|
49
|
-
@
|
50
|
-
|
49
|
+
@state = :new
|
50
|
+
self.metadata = Metadata.new args.delete(:metadata)
|
51
|
+
update_metadata self.class.defaults.merge(args) # deprecate?
|
51
52
|
end
|
52
53
|
|
53
54
|
def inspect
|
54
55
|
attrs = if deleted?
|
55
56
|
"id=\"#{id}\" DELETED"
|
56
57
|
else
|
57
|
-
INSPECT_ATTRS.map { |attr| "#{attr}
|
58
|
+
INSPECT_ATTRS.map { |attr| "#{attr}=#{send(attr).inspect}" }.join(", ")
|
58
59
|
end
|
59
60
|
"#<#{self.class.name} #{attrs}>"
|
60
61
|
end
|
@@ -63,6 +64,14 @@ module Ezid
|
|
63
64
|
id
|
64
65
|
end
|
65
66
|
|
67
|
+
# Returns the identifier metadata
|
68
|
+
# @param refresh [Boolean] - flag to refresh the metadata from EZID if stale (default: `true`)
|
69
|
+
# @return [Ezid::Metadata] the metadata
|
70
|
+
def metadata(refresh = true)
|
71
|
+
refresh_metadata if refresh && stale?
|
72
|
+
@metadata
|
73
|
+
end
|
74
|
+
|
66
75
|
# Persist the identifer and/or metadata to EZID.
|
67
76
|
# If the identifier is already persisted, this is an update operation;
|
68
77
|
# Otherwise, create (if it has an id) or mint (if it has a shoulder)
|
@@ -72,8 +81,8 @@ module Ezid
|
|
72
81
|
# with an error status.
|
73
82
|
def save
|
74
83
|
raise Error, "Cannot save a deleted identifier." if deleted?
|
75
|
-
|
76
|
-
|
84
|
+
persist
|
85
|
+
reset
|
77
86
|
end
|
78
87
|
|
79
88
|
# Updates the metadata
|
@@ -87,14 +96,13 @@ module Ezid
|
|
87
96
|
# Is the identifier persisted?
|
88
97
|
# @return [Boolean]
|
89
98
|
def persisted?
|
90
|
-
|
91
|
-
!!(id && created)
|
99
|
+
state == :persisted
|
92
100
|
end
|
93
101
|
|
94
102
|
# Has the identifier been deleted?
|
95
103
|
# @return [Boolean]
|
96
104
|
def deleted?
|
97
|
-
|
105
|
+
state == :deleted
|
98
106
|
end
|
99
107
|
|
100
108
|
# Updates the metadata and saves the identifier
|
@@ -128,7 +136,7 @@ module Ezid
|
|
128
136
|
def delete
|
129
137
|
raise Error, "Only persisted, reserved identifiers may be deleted: #{inspect}." unless deletable?
|
130
138
|
client.delete_identifier(id)
|
131
|
-
|
139
|
+
self.state = :deleted
|
132
140
|
reset
|
133
141
|
end
|
134
142
|
|
@@ -174,44 +182,49 @@ module Ezid
|
|
174
182
|
|
175
183
|
protected
|
176
184
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
185
|
+
def method_missing(method, *args)
|
186
|
+
metadata.send(method, *args)
|
187
|
+
rescue NoMethodError
|
188
|
+
super
|
189
|
+
end
|
182
190
|
|
183
191
|
private
|
184
192
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
193
|
+
def stale?
|
194
|
+
persisted? && metadata(false).empty?
|
195
|
+
end
|
189
196
|
|
190
|
-
|
191
|
-
|
192
|
-
|
197
|
+
def refresh_metadata
|
198
|
+
response = client.get_identifier_metadata(id)
|
199
|
+
self.metadata = Metadata.new response.metadata
|
200
|
+
self.state = :persisted
|
201
|
+
end
|
193
202
|
|
194
|
-
|
195
|
-
|
196
|
-
|
203
|
+
def clear_metadata
|
204
|
+
metadata(false).clear
|
205
|
+
end
|
197
206
|
|
198
|
-
|
199
|
-
|
200
|
-
|
207
|
+
def modify
|
208
|
+
client.modify_identifier(id, metadata)
|
209
|
+
end
|
201
210
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
211
|
+
def create_or_mint
|
212
|
+
id ? create : mint
|
213
|
+
end
|
206
214
|
|
207
|
-
|
208
|
-
|
209
|
-
|
215
|
+
def mint
|
216
|
+
response = client.mint_identifier(shoulder, metadata)
|
217
|
+
self.id = response.id
|
218
|
+
end
|
210
219
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
220
|
+
def create
|
221
|
+
client.create_identifier(id, metadata)
|
222
|
+
end
|
223
|
+
|
224
|
+
def persist
|
225
|
+
persisted? ? modify : create_or_mint
|
226
|
+
self.state = :persisted
|
227
|
+
end
|
215
228
|
|
216
229
|
end
|
217
230
|
end
|
data/lib/ezid/metadata.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "forwardable"
|
2
2
|
|
3
3
|
module Ezid
|
4
4
|
#
|
@@ -6,37 +6,49 @@ module Ezid
|
|
6
6
|
#
|
7
7
|
# @api private
|
8
8
|
#
|
9
|
-
class Metadata
|
9
|
+
class Metadata
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
attr_reader :elements
|
13
|
+
|
14
|
+
def_delegators :elements, :[], :[]=, :each, :clear, :to_h, :empty?
|
10
15
|
|
11
16
|
class << self
|
12
|
-
def metadata_reader(
|
13
|
-
define_method
|
14
|
-
|
17
|
+
def metadata_reader(element, alias_as=nil)
|
18
|
+
define_method element do
|
19
|
+
get(element)
|
15
20
|
end
|
16
21
|
if alias_as
|
17
|
-
alias_method alias_as,
|
22
|
+
alias_method alias_as, element
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
|
-
def metadata_writer(
|
22
|
-
define_method "#{
|
23
|
-
|
26
|
+
def metadata_writer(element, alias_as=nil)
|
27
|
+
define_method "#{element}=" do |value|
|
28
|
+
set(element, value)
|
24
29
|
end
|
25
30
|
if alias_as
|
26
|
-
alias_method "#{alias_as}=".to_sym, "#{
|
31
|
+
alias_method "#{alias_as}=".to_sym, "#{element}=".to_sym
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
30
|
-
def metadata_accessor(
|
31
|
-
metadata_reader
|
32
|
-
metadata_writer
|
35
|
+
def metadata_accessor(element, alias_as=nil)
|
36
|
+
metadata_reader element, alias_as
|
37
|
+
metadata_writer element, alias_as
|
33
38
|
end
|
34
39
|
|
35
|
-
def metadata_profile(profile, *
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
def metadata_profile(profile, *elements)
|
41
|
+
elements.each do |element|
|
42
|
+
profile_element = [profile, element].join(".")
|
43
|
+
method = [profile, element].join("_")
|
44
|
+
|
45
|
+
define_method method do
|
46
|
+
get(profile_element)
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method "#{method}=" do |value|
|
50
|
+
set(profile_element, value)
|
51
|
+
end
|
40
52
|
end
|
41
53
|
end
|
42
54
|
end
|
@@ -71,6 +83,20 @@ module Ezid
|
|
71
83
|
# @see http://ezid.cdlib.org/doc/apidoc.html#internal-metadata
|
72
84
|
READONLY = %w( _owner _ownergroup _shadows _shadowedby _datacenter _created _updated )
|
73
85
|
|
86
|
+
# EZID metadata profiles - a hash of (profile => elements)
|
87
|
+
# @see http://ezid.cdlib.org/doc/apidoc.html#metadata-profiles
|
88
|
+
# @note crossref is not included because it is a simple element
|
89
|
+
PROFILES = {
|
90
|
+
dc: [:creator, :title, :publisher, :date, :type],
|
91
|
+
datacite: [:creator, :title, :publisher, :publicationyear, :resourcetype],
|
92
|
+
erc: [:who, :what, :when]
|
93
|
+
}
|
94
|
+
|
95
|
+
PROFILES.each do |profile, elements|
|
96
|
+
metadata_profile profile, *elements
|
97
|
+
end
|
98
|
+
|
99
|
+
# Accessors for EZID internal metadata elements
|
74
100
|
metadata_accessor :_coowners, :coowners
|
75
101
|
metadata_accessor :_crossref
|
76
102
|
metadata_accessor :_export, :export
|
@@ -78,10 +104,7 @@ module Ezid
|
|
78
104
|
metadata_accessor :_status, :status
|
79
105
|
metadata_accessor :_target, :target
|
80
106
|
|
81
|
-
|
82
|
-
metadata_accessor :datacite
|
83
|
-
metadata_accessor :erc
|
84
|
-
|
107
|
+
# Readers for EZID read-only internal metadata elements
|
85
108
|
metadata_reader :_created
|
86
109
|
metadata_reader :_datacenter, :datacenter
|
87
110
|
metadata_reader :_owner, :owner
|
@@ -90,12 +113,13 @@ module Ezid
|
|
90
113
|
metadata_reader :_shadows, :shadows
|
91
114
|
metadata_reader :_updated
|
92
115
|
|
93
|
-
|
94
|
-
|
95
|
-
|
116
|
+
# Accessors for
|
117
|
+
metadata_accessor :crossref
|
118
|
+
metadata_accessor :datacite
|
119
|
+
metadata_accessor :erc
|
96
120
|
|
97
121
|
def initialize(data={})
|
98
|
-
|
122
|
+
@elements = coerce(data)
|
99
123
|
end
|
100
124
|
|
101
125
|
def created
|
@@ -110,19 +134,41 @@ module Ezid
|
|
110
134
|
# @see http://ezid.cdlib.org/doc/apidoc.html#request-response-bodies
|
111
135
|
# @return [String] the ANVL output
|
112
136
|
def to_anvl(include_readonly = true)
|
113
|
-
hsh =
|
137
|
+
hsh = elements.dup
|
114
138
|
hsh.reject! { |k, v| READONLY.include?(k) } unless include_readonly
|
115
|
-
|
139
|
+
lines = hsh.map do |name, value|
|
116
140
|
element = [escape(ESCAPE_NAMES_RE, name), escape(ESCAPE_VALUES_RE, value)]
|
117
141
|
element.join(ANVL_SEPARATOR)
|
118
142
|
end
|
119
|
-
|
143
|
+
lines.join("\n").force_encoding(Encoding::UTF_8)
|
144
|
+
end
|
145
|
+
|
146
|
+
def inspect
|
147
|
+
"#<#{self.class.name} elements=#{elements.inspect}>"
|
120
148
|
end
|
121
149
|
|
122
150
|
def to_s
|
123
151
|
to_anvl
|
124
152
|
end
|
125
153
|
|
154
|
+
def get(element)
|
155
|
+
self[element.to_s]
|
156
|
+
end
|
157
|
+
|
158
|
+
def set(element, value)
|
159
|
+
self[element.to_s] = value
|
160
|
+
end
|
161
|
+
|
162
|
+
protected
|
163
|
+
|
164
|
+
def method_missing(method, *args)
|
165
|
+
return get(method) if args.size == 0
|
166
|
+
if element = method.to_s[/^([^=]+)=$/, 1]
|
167
|
+
return set(element, *args)
|
168
|
+
end
|
169
|
+
super
|
170
|
+
end
|
171
|
+
|
126
172
|
private
|
127
173
|
|
128
174
|
def to_time(value)
|
@@ -78,6 +78,13 @@ module Ezid
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
describe "#update_metadata" do
|
82
|
+
it "should update the metadata" do
|
83
|
+
subject.update_metadata(:status => "public", _target: "localhost", "dc.creator" => "Me")
|
84
|
+
expect(subject.metadata.to_h).to eq({"_status"=>"public", "_target"=>"localhost", "dc.creator"=>"Me"})
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
81
88
|
describe "#reload" do
|
82
89
|
let(:metadata) { "_profile: erc" }
|
83
90
|
before { allow(subject).to receive(:id) { "id" } }
|
@@ -89,29 +96,29 @@ module Ezid
|
|
89
96
|
end
|
90
97
|
|
91
98
|
describe "#reset" do
|
99
|
+
before { subject.metadata = Metadata.new(status: "public") }
|
92
100
|
it "should clear the local metadata" do
|
93
|
-
expect
|
94
|
-
subject.reset
|
101
|
+
expect { subject.reset }.to change { subject.metadata.empty? }.from(false).to(true)
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
98
105
|
describe "#persisted?" do
|
99
|
-
|
100
|
-
|
106
|
+
describe "after initialization" do
|
107
|
+
it { is_expected.not_to be_persisted }
|
101
108
|
end
|
102
|
-
|
103
|
-
before { allow(subject).to receive(:
|
104
|
-
it "should
|
105
|
-
expect(subject).
|
109
|
+
describe "when saving an unpersisted object" do
|
110
|
+
before { allow(subject).to receive(:create_or_mint) { nil } }
|
111
|
+
it "should mark it as persisted" do
|
112
|
+
expect { subject.save }.to change(subject, :persisted?).from(false).to(true)
|
106
113
|
end
|
107
114
|
end
|
108
|
-
|
115
|
+
describe "when saving a persisted object" do
|
109
116
|
before do
|
110
|
-
allow(subject).to receive(:
|
111
|
-
subject.
|
117
|
+
allow(subject).to receive(:persisted?) { true }
|
118
|
+
allow(subject).to receive(:modify) { nil }
|
112
119
|
end
|
113
|
-
it "should
|
114
|
-
expect(subject)
|
120
|
+
it "should not change the persisted status" do
|
121
|
+
expect { subject.save }.not_to change(subject, :persisted?)
|
115
122
|
end
|
116
123
|
end
|
117
124
|
end
|
@@ -143,14 +150,15 @@ module Ezid
|
|
143
150
|
end
|
144
151
|
|
145
152
|
describe "#save" do
|
146
|
-
before { allow(subject).to receive(:reload) { double } }
|
147
153
|
context "when the identifier is persisted" do
|
154
|
+
let(:metadata) { Metadata.new }
|
148
155
|
before do
|
149
156
|
allow(subject).to receive(:id) { "id" }
|
150
157
|
allow(subject).to receive(:persisted?) { true }
|
158
|
+
allow(subject).to receive(:metadata) { metadata }
|
151
159
|
end
|
152
160
|
it "should modify the identifier" do
|
153
|
-
expect(subject.client).to receive(:modify_identifier).with("id",
|
161
|
+
expect(subject.client).to receive(:modify_identifier).with("id", metadata) { double(id: "id") }
|
154
162
|
subject.save
|
155
163
|
end
|
156
164
|
end
|
data/spec/unit/metadata_spec.rb
CHANGED
@@ -195,15 +195,15 @@ _status: public
|
|
195
195
|
EOS
|
196
196
|
end
|
197
197
|
it "should treat the string as an ANVL document, splitting into keys and values and unescaping" do
|
198
|
-
expect(subject).to eq({ "_updated" => "1416507086",
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
198
|
+
expect(subject.elements).to eq({ "_updated" => "1416507086",
|
199
|
+
"_target" => "http://example.com/path%20with%20spaces",
|
200
|
+
"_profile" => "erc",
|
201
|
+
"_erc" => "who: Proust, Marcel\nwhat: Remembrance of Things Past",
|
202
|
+
"_ownergroup" => "apitest",
|
203
|
+
"_owner" => "apitest",
|
204
|
+
"_export" => "yes",
|
205
|
+
"_created" => "1416507086",
|
206
|
+
"_status" => "public" })
|
207
207
|
end
|
208
208
|
end
|
209
209
|
context "of a hash-like object" do
|
@@ -219,14 +219,14 @@ EOS
|
|
219
219
|
end
|
220
220
|
context "which is a normal Hash" do
|
221
221
|
let(:data) { hsh }
|
222
|
-
it "should set the metadata to the hash" do
|
223
|
-
expect(subject).to eq(hsh)
|
222
|
+
it "should set the metadata elements to the hash" do
|
223
|
+
expect(subject.elements).to eq(hsh)
|
224
224
|
end
|
225
225
|
end
|
226
226
|
context "which is a Metadata instance" do
|
227
227
|
let(:data) { Metadata.new(hsh) }
|
228
|
-
it "should set the metadata to the hash" do
|
229
|
-
expect(subject).to eq(hsh)
|
228
|
+
it "should set the metadata elements to the hash" do
|
229
|
+
expect(subject.elements).to eq(hsh)
|
230
230
|
end
|
231
231
|
end
|
232
232
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ezid-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Chandek-Stark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|