ezid-client 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85849ced129850092f56b21b4fd53a7e0284f1f6
4
- data.tar.gz: c47cb2ea503377f50c1aef3d903b90d7a25ec5aa
3
+ metadata.gz: dcda4d65432df1b88c9727ca05e22a8f214f27b6
4
+ data.tar.gz: 878ccc4caf544c3fd1f1b3cedc9da7ed6a72180d
5
5
  SHA512:
6
- metadata.gz: 4a6c2d5c5424fd659d6934255f2920a1d632eb23834e6584fb989b6e555c276b45ad22246f3fa9646d690be99baf7e578714e1039c91643dd7003c00bbf24c7a
7
- data.tar.gz: 12271321bc4b2863133a4241f7187d07b9f19a0c7cab48a4c4da84bd55cc1532efddd628e939e478d5664bb7df7a8bd58f1dc68e8855c62a4dd284dde7648d4d
6
+ metadata.gz: 778b583288d8bbc0bf8463ed3caadb117babfa5ef092c838367ddfbb7d6043b7186eeff4101d1fb0c51871299371e31e371cf5ace8f81e59eb168373b5f46422
7
+ data.tar.gz: 9d149efa596af0db3268522cff9deeecfcf72f235608367311adc6ee5d3c86ba087c6519cfba44c15edd30c60158423e5245d09ac4e99f1ad7501d76dd5e7990
@@ -1,10 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.2
3
4
  - 2.1
4
5
  - 2.0.0
5
6
  cache:
6
7
  - bundler
7
8
  script: "bundle exec rake ci"
8
- notifications:
9
- email:
10
- - lib-drs@duke.edu
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.1.0
@@ -59,8 +59,8 @@ module Ezid
59
59
  end
60
60
 
61
61
  def inspect
62
- "#<#{self.class.name} connection=#{connection.inspect} " \
63
- "user=\"#{user}\" session=#{logged_in? ? 'OPEN' : 'CLOSED'}>"
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
@@ -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
@@ -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 :id, :client
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
- @deleted = false
50
- init_metadata(args)
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}=\"#{send(attr)}\"" }.join(" ")
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
- persisted? ? modify : create_or_mint
76
- reload
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
- return false if deleted?
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
- @deleted
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
- @deleted = true
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
- def method_missing(method, *args)
178
- metadata.send(method, *args)
179
- rescue NoMethodError
180
- super
181
- end
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
- def refresh_metadata
186
- response = client.get_identifier_metadata(id)
187
- @metadata = Metadata.new(response.metadata)
188
- end
193
+ def stale?
194
+ persisted? && metadata(false).empty?
195
+ end
189
196
 
190
- def clear_metadata
191
- @metadata.clear
192
- end
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
- def modify
195
- client.modify_identifier(id, metadata)
196
- end
203
+ def clear_metadata
204
+ metadata(false).clear
205
+ end
197
206
 
198
- def create_or_mint
199
- id ? create : mint
200
- end
207
+ def modify
208
+ client.modify_identifier(id, metadata)
209
+ end
201
210
 
202
- def mint
203
- response = client.mint_identifier(shoulder, metadata)
204
- @id = response.id
205
- end
211
+ def create_or_mint
212
+ id ? create : mint
213
+ end
206
214
 
207
- def create
208
- client.create_identifier(id, metadata)
209
- end
215
+ def mint
216
+ response = client.mint_identifier(shoulder, metadata)
217
+ self.id = response.id
218
+ end
210
219
 
211
- def init_metadata(args)
212
- @metadata = Metadata.new(args.delete(:metadata))
213
- update_metadata(self.class.defaults.merge(args))
214
- end
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
@@ -1,4 +1,4 @@
1
- require "delegate"
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 < SimpleDelegator
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(method, alias_as=nil)
13
- define_method method do
14
- self[method.to_s]
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, method
22
+ alias_method alias_as, element
18
23
  end
19
24
  end
20
25
 
21
- def metadata_writer(method, alias_as=nil)
22
- define_method "#{method}=" do |value|
23
- self[method.to_s] = value
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, "#{method}=".to_sym
31
+ alias_method "#{alias_as}=".to_sym, "#{element}=".to_sym
27
32
  end
28
33
  end
29
34
 
30
- def metadata_accessor(method, alias_as=nil)
31
- metadata_reader method, alias_as
32
- metadata_writer method, alias_as
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, *methods)
36
- methods.each do |method|
37
- element = [profile, method].join(".")
38
- alias_as = [profile, method].join("_")
39
- metadata_accessor element, alias_as
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
- metadata_accessor :crossref
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
- metadata_profile :dc, :creator, :title, :publisher, :date, :type
94
- metadata_profile :datacite, :creator, :title, :publisher, :publicationyear, :resourcetype
95
- metadata_profile :erc, :who, :what, :when
116
+ # Accessors for
117
+ metadata_accessor :crossref
118
+ metadata_accessor :datacite
119
+ metadata_accessor :erc
96
120
 
97
121
  def initialize(data={})
98
- super coerce(data)
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 = __getobj__.dup
137
+ hsh = elements.dup
114
138
  hsh.reject! { |k, v| READONLY.include?(k) } unless include_readonly
115
- elements = hsh.map do |name, value|
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
- elements.join("\n").force_encoding(Encoding::UTF_8)
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(subject.metadata).to receive(:clear)
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
- it "should be false if id is nil" do
100
- expect(subject).not_to be_persisted
106
+ describe "after initialization" do
107
+ it { is_expected.not_to be_persisted }
101
108
  end
102
- context "when `created' is nil" do
103
- before { allow(subject).to receive(:id) { "ark:/99999/fk4fn19h88" } }
104
- it "should be false" do
105
- expect(subject).not_to be_persisted
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
- context "when id and `created' are present" do
115
+ describe "when saving a persisted object" do
109
116
  before do
110
- allow(subject).to receive(:id) { "ark:/99999/fk4fn19h88" }
111
- subject.metadata["_created"] = "1416507086"
117
+ allow(subject).to receive(:persisted?) { true }
118
+ allow(subject).to receive(:modify) { nil }
112
119
  end
113
- it "should be true" do
114
- expect(subject).to be_persisted
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", subject.metadata) { double(id: "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
@@ -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
- "_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" })
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.1
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-02-26 00:00:00.000000000 Z
11
+ date: 2015-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler