Skip to content

Commit

Permalink
Merge branch 'release-1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
dchandekstark committed Mar 25, 2015
2 parents 6a30203 + 8c8dd87 commit 3ac81cc
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 105 deletions.
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
language: ruby
rvm:
- 2.2
- 2.1
- 2.0.0
cache:
- bundler
script: "bundle exec rake ci"
notifications:
email:
- [email protected]
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.1
1.1.0
4 changes: 2 additions & 2 deletions lib/ezid/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def initialize(opts = {})
end

def inspect
"#<#{self.class.name} connection=#{connection.inspect} " \
"user=\"#{user}\" session=#{logged_in? ? 'OPEN' : 'CLOSED'}>"
"#<#{self.class.name} connection=#{connection.inspect}, " \
"user=#{user.inspect}, session=#{logged_in? ? 'OPEN' : 'CLOSED'}>"
end

# The client configuration
Expand Down
6 changes: 6 additions & 0 deletions lib/ezid/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def initialize
@default_shoulder = ENV["EZID_DEFAULT_SHOULDER"]
end

def inspect
ivars = instance_variables.reject { |v| v == :@password }
.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }
"#<#{self.class.name} #{ivars.join(', ')}>"
end

def logger
@logger ||= Logger.new(STDERR)
end
Expand Down
97 changes: 55 additions & 42 deletions lib/ezid/identifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ module Ezid
#
# Represents an EZID identifier as a resource.
#
# Ezid::Identifier delegates access to registered metadata elements through #method_missing.
#
# @api public
#
class Identifier

attr_reader :id, :client
attr_accessor :shoulder, :metadata
attr_reader :client
attr_accessor :id, :shoulder, :metadata, :state

private :state, :state=, :id=

# Attributes to display on inspect
INSPECT_ATTRS = %w( id status target created )
Expand Down Expand Up @@ -46,15 +46,16 @@ def initialize(args={})
@client = args.delete(:client) || Client.new
@id = args.delete(:id)
@shoulder = args.delete(:shoulder)
@deleted = false
init_metadata(args)
@state = :new
self.metadata = Metadata.new args.delete(:metadata)
update_metadata self.class.defaults.merge(args) # deprecate?
end

def inspect
attrs = if deleted?
"id=\"#{id}\" DELETED"
else
INSPECT_ATTRS.map { |attr| "#{attr}=\"#{send(attr)}\"" }.join(" ")
INSPECT_ATTRS.map { |attr| "#{attr}=#{send(attr).inspect}" }.join(", ")
end
"#<#{self.class.name} #{attrs}>"
end
Expand All @@ -63,6 +64,14 @@ def to_s
id
end

# Returns the identifier metadata
# @param refresh [Boolean] - flag to refresh the metadata from EZID if stale (default: `true`)
# @return [Ezid::Metadata] the metadata
def metadata(refresh = true)
refresh_metadata if refresh && stale?
@metadata
end

# Persist the identifer and/or metadata to EZID.
# If the identifier is already persisted, this is an update operation;
# Otherwise, create (if it has an id) or mint (if it has a shoulder)
Expand All @@ -72,8 +81,8 @@ def to_s
# with an error status.
def save
raise Error, "Cannot save a deleted identifier." if deleted?
persisted? ? modify : create_or_mint
reload
persist
reset
end

# Updates the metadata
Expand All @@ -87,14 +96,13 @@ def update_metadata(attrs={})
# Is the identifier persisted?
# @return [Boolean]
def persisted?
return false if deleted?
!!(id && created)
state == :persisted
end

# Has the identifier been deleted?
# @return [Boolean]
def deleted?
@deleted
state == :deleted
end

# Updates the metadata and saves the identifier
Expand Down Expand Up @@ -128,7 +136,7 @@ def reset
def delete
raise Error, "Only persisted, reserved identifiers may be deleted: #{inspect}." unless deletable?
client.delete_identifier(id)
@deleted = true
self.state = :deleted
reset
end

Expand Down Expand Up @@ -174,44 +182,49 @@ def public!

protected

def method_missing(method, *args)
metadata.send(method, *args)
rescue NoMethodError
super
end
def method_missing(method, *args)
metadata.send(method, *args)
rescue NoMethodError
super
end

private

def refresh_metadata
response = client.get_identifier_metadata(id)
@metadata = Metadata.new(response.metadata)
end
def stale?
persisted? && metadata(false).empty?
end

def clear_metadata
@metadata.clear
end
def refresh_metadata
response = client.get_identifier_metadata(id)
self.metadata = Metadata.new response.metadata
self.state = :persisted
end

def modify
client.modify_identifier(id, metadata)
end
def clear_metadata
metadata(false).clear
end

def create_or_mint
id ? create : mint
end
def modify
client.modify_identifier(id, metadata)
end

def mint
response = client.mint_identifier(shoulder, metadata)
@id = response.id
end
def create_or_mint
id ? create : mint
end

def create
client.create_identifier(id, metadata)
end
def mint
response = client.mint_identifier(shoulder, metadata)
self.id = response.id
end

def init_metadata(args)
@metadata = Metadata.new(args.delete(:metadata))
update_metadata(self.class.defaults.merge(args))
end
def create
client.create_identifier(id, metadata)
end

def persist
persisted? ? modify : create_or_mint
self.state = :persisted
end

end
end
104 changes: 75 additions & 29 deletions lib/ezid/metadata.rb
Original file line number Diff line number Diff line change
@@ -1,42 +1,54 @@
require "delegate"
require "forwardable"

module Ezid
#
# EZID metadata collection for an identifier.
#
# @api private
#
class Metadata < SimpleDelegator
class Metadata
extend Forwardable

attr_reader :elements

def_delegators :elements, :[], :[]=, :each, :clear, :to_h, :empty?

class << self
def metadata_reader(method, alias_as=nil)
define_method method do
self[method.to_s]
def metadata_reader(element, alias_as=nil)
define_method element do
get(element)
end
if alias_as
alias_method alias_as, method
alias_method alias_as, element
end
end

def metadata_writer(method, alias_as=nil)
define_method "#{method}=" do |value|
self[method.to_s] = value
def metadata_writer(element, alias_as=nil)
define_method "#{element}=" do |value|
set(element, value)
end
if alias_as
alias_method "#{alias_as}=".to_sym, "#{method}=".to_sym
alias_method "#{alias_as}=".to_sym, "#{element}=".to_sym
end
end

def metadata_accessor(method, alias_as=nil)
metadata_reader method, alias_as
metadata_writer method, alias_as
def metadata_accessor(element, alias_as=nil)
metadata_reader element, alias_as
metadata_writer element, alias_as
end

def metadata_profile(profile, *methods)
methods.each do |method|
element = [profile, method].join(".")
alias_as = [profile, method].join("_")
metadata_accessor element, alias_as
def metadata_profile(profile, *elements)
elements.each do |element|
profile_element = [profile, element].join(".")
method = [profile, element].join("_")

define_method method do
get(profile_element)
end

define_method "#{method}=" do |value|
set(profile_element, value)
end
end
end
end
Expand Down Expand Up @@ -71,17 +83,28 @@ def metadata_profile(profile, *methods)
# @see http://ezid.cdlib.org/doc/apidoc.html#internal-metadata
READONLY = %w( _owner _ownergroup _shadows _shadowedby _datacenter _created _updated )

# EZID metadata profiles - a hash of (profile => elements)
# @see http://ezid.cdlib.org/doc/apidoc.html#metadata-profiles
# @note crossref is not included because it is a simple element
PROFILES = {
dc: [:creator, :title, :publisher, :date, :type],
datacite: [:creator, :title, :publisher, :publicationyear, :resourcetype],
erc: [:who, :what, :when]
}

PROFILES.each do |profile, elements|
metadata_profile profile, *elements
end

# Accessors for EZID internal metadata elements
metadata_accessor :_coowners, :coowners
metadata_accessor :_crossref
metadata_accessor :_export, :export
metadata_accessor :_profile, :profile
metadata_accessor :_status, :status
metadata_accessor :_target, :target

metadata_accessor :crossref
metadata_accessor :datacite
metadata_accessor :erc

# Readers for EZID read-only internal metadata elements
metadata_reader :_created
metadata_reader :_datacenter, :datacenter
metadata_reader :_owner, :owner
Expand All @@ -90,12 +113,13 @@ def metadata_profile(profile, *methods)
metadata_reader :_shadows, :shadows
metadata_reader :_updated

metadata_profile :dc, :creator, :title, :publisher, :date, :type
metadata_profile :datacite, :creator, :title, :publisher, :publicationyear, :resourcetype
metadata_profile :erc, :who, :what, :when
# Accessors for
metadata_accessor :crossref
metadata_accessor :datacite
metadata_accessor :erc

def initialize(data={})
super coerce(data)
@elements = coerce(data)
end

def created
Expand All @@ -110,19 +134,41 @@ def updated
# @see http://ezid.cdlib.org/doc/apidoc.html#request-response-bodies
# @return [String] the ANVL output
def to_anvl(include_readonly = true)
hsh = __getobj__.dup
hsh = elements.dup
hsh.reject! { |k, v| READONLY.include?(k) } unless include_readonly
elements = hsh.map do |name, value|
lines = hsh.map do |name, value|
element = [escape(ESCAPE_NAMES_RE, name), escape(ESCAPE_VALUES_RE, value)]
element.join(ANVL_SEPARATOR)
end
elements.join("\n").force_encoding(Encoding::UTF_8)
lines.join("\n").force_encoding(Encoding::UTF_8)
end

def inspect
"#<#{self.class.name} elements=#{elements.inspect}>"
end

def to_s
to_anvl
end

def get(element)
self[element.to_s]
end

def set(element, value)
self[element.to_s] = value
end

protected

def method_missing(method, *args)
return get(method) if args.size == 0
if element = method.to_s[/^([^=]+)=$/, 1]
return set(element, *args)
end
super
end

private

def to_time(value)
Expand Down
Loading

0 comments on commit 3ac81cc

Please sign in to comment.