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 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