From 71b93988be3f82e003c80493bd8a1b0dda126f7b Mon Sep 17 00:00:00 2001 From: carolyncole <1599081+carolyncole@users.noreply.github.com> Date: Tue, 23 Aug 2022 11:21:26 -0400 Subject: [PATCH] Breaking out PDCMetadata classes into thier own files (#325) Also removing rubocop violations Co-authored-by: Hector Correa --- app/models/pdc_metadata/affiliation.rb | 17 +++ app/models/pdc_metadata/creator.rb | 65 +++++++++ app/models/pdc_metadata/name_identifier.rb | 42 ++++++ app/models/pdc_metadata/resource.rb | 159 ++++----------------- app/models/pdc_metadata/title.rb | 17 +++ spec/models/pdc_metadata/resource_spec.rb | 5 + 6 files changed, 170 insertions(+), 135 deletions(-) create mode 100644 app/models/pdc_metadata/affiliation.rb create mode 100644 app/models/pdc_metadata/creator.rb create mode 100644 app/models/pdc_metadata/name_identifier.rb create mode 100644 app/models/pdc_metadata/title.rb diff --git a/app/models/pdc_metadata/affiliation.rb b/app/models/pdc_metadata/affiliation.rb new file mode 100644 index 000000000..2ac3f16ae --- /dev/null +++ b/app/models/pdc_metadata/affiliation.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Class for storing an affiliation in our local representation +module PDCMetadata + # value: "datacite" + # identifier: "https://ror.org/04aj4c181" + # scheme: "ROR" + # scheme_uri: "https://ror.org/" + class Affiliation + attr_accessor :value, :identifier, :scheme, :scheme_uri + def initialize(value: nil, identifier: nil, scheme: nil, scheme_uri: nil) + @value = value + @identifier = identifier + @scheme = scheme + @scheme_uri = scheme_uri + end + end +end diff --git a/app/models/pdc_metadata/creator.rb b/app/models/pdc_metadata/creator.rb new file mode 100644 index 000000000..1ce889c3e --- /dev/null +++ b/app/models/pdc_metadata/creator.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +# Class for storing a creator in our local representation +module PDCMetadata + # value: "Miller, Elizabeth" + # name_type: "Personal" + # given_name: "Elizabeth" + # family_name: "Miller" + class Creator + attr_accessor :value, :name_type, :given_name, :family_name, :identifier, :affiliations, :sequence + + class << self + def from_hash(creator) + given_name = creator["given_name"] + family_name = creator["family_name"] + orcid = creator.dig("identifier", "scheme") == "ORCID" ? creator.dig("identifier", "value") : nil + sequence = (creator["sequence"] || "").to_i + PDCMetadata::Creator.new_person(given_name, family_name, orcid, sequence) + end + end + + # rubocop:disable Metrics/ParameterLists + def initialize(value: nil, name_type: nil, given_name: nil, family_name: nil, identifier: nil, sequence: 0) + @value = value + @name_type = name_type + @given_name = given_name + @family_name = family_name + @identifier = identifier + @affiliations = [] + @sequence = sequence + end + # rubocop:enable Metrics/ParameterLists + + def orcid_url + identifier&.orcid_url + end + + def orcid + identifier&.orcid + end + + def self.new_person(given_name, family_name, orcid_id = nil, sequence = 0) + full_name = "#{family_name}, #{given_name}" + creator = Creator.new(value: full_name, name_type: "Personal", given_name: given_name, family_name: family_name, sequence: sequence) + if orcid_id.present? + creator.identifier = NameIdentifier.new_orcid(orcid_id.strip) + end + creator + end + + def to_xml(builder) + if name_type == "Personal" + builder.creator("nameType" => "Personal") do + builder.creatorName value + builder.givenName given_name + builder.familyName family_name + identifier&.to_xml(builder) + end + else + builder.creator("nameType" => "Organization") do + builder.creatorName value + end + end + end + end +end diff --git a/app/models/pdc_metadata/name_identifier.rb b/app/models/pdc_metadata/name_identifier.rb new file mode 100644 index 000000000..192e54008 --- /dev/null +++ b/app/models/pdc_metadata/name_identifier.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# Class for storing a named identifier for the creator in our local representation. This identifier can be a person or organization. +# **Please Note:** +# The class name NameIdentifier is being utilized becuase it matches with the DataCite Schema: https://support.datacite.org/docs/datacite-metadata-schema-v44-mandatory-properties#24-nameidentifier +# It also matches with the DaCite xml mapping gem that we are utilizing: https://github.com/CDLUC3/datacite-mapping/blob/master/lib/datacite/mapping/name_identifier.rb +module PDCMetadata + # value: "0000-0001-5000-0007" + # scheme: "ORCID" + # scheme_uri: "https://orcid.org/"" + class NameIdentifier + attr_accessor :value, :scheme, :scheme_uri + def initialize(value: nil, scheme: nil, scheme_uri: nil) + @value = value + @scheme = scheme + @scheme_uri = scheme_uri + end + + def orcid_url + return nil unless scheme == "ORCID" + "#{scheme_uri}/#{value}" + end + + def orcid + return nil unless scheme == "ORCID" + value + end + + # Convenience method since this is the most common (only?) identifier that we are currently supporting + def self.new_orcid(value) + NameIdentifier.new(value: value, scheme: "ORCID", scheme_uri: "https://orcid.org") + end + + def to_xml(builder) + builder.nameIdentifier( + "schemeURI" => scheme_uri, + "nameIdentifierScheme" => scheme + ) do + builder.text value + end + end + end +end diff --git a/app/models/pdc_metadata/resource.rb b/app/models/pdc_metadata/resource.rb index 2f2db61fd..85bf50d9e 100644 --- a/app/models/pdc_metadata/resource.rb +++ b/app/models/pdc_metadata/resource.rb @@ -3,7 +3,6 @@ module PDCMetadata # Represents a PUL Datacite resource # https://support.datacite.org/docs/datacite-metadata-schema-v44-properties-overview # - # rubocop:disable Metrics/ClassLength class Resource attr_accessor :creators, :titles, :publisher, :publication_year, :resource_type, :description, :doi, :ark @@ -68,25 +67,7 @@ def to_xml end xml.creators do @creators.each do |creator| - if creator.name_type == "Personal" - xml.creator("nameType" => "Personal") do - xml.creatorName creator.value - xml.givenName creator.given_name - xml.familyName creator.family_name - unless creator.name_identifier.nil? - xml.nameIdentifier( - "schemeURI" => creator.name_identifier.scheme_uri, - "nameIdentifierScheme" => creator.name_identifier.scheme - ) do - xml.text creator.name_identifier.value - end - end - end - else - xml.creator("nameType" => "Organization") do - xml.creatorName creator.value - end - end + creator.to_xml(xml) end end xml.publisher do @@ -103,129 +84,37 @@ def to_xml # rubocop:enable Metrics/BlockLength # rubocop:enable Metrics/AbcSize - # Creates a PDCMetadata::Resource from a JSON string - # rubocop:disable Metrics/MethodLength - # rubocop:disable Metrics/AbcSize - def self.new_from_json(json_string) - resource = PDCMetadata::Resource.new - hash = json_string.blank? ? {} : JSON.parse(json_string) - - resource.doi = hash["doi"] - resource.ark = hash["ark"] - resource.description = hash["description"] + class << self + # Creates a PDCMetadata::Resource from a JSON string + def new_from_json(json_string) + resource = PDCMetadata::Resource.new + hash = json_string.blank? ? {} : JSON.parse(json_string) - hash["titles"]&.each do |title| - resource.titles << PDCMetadata::Title.new(title: title["title"], title_type: title["title_type"]) - end - - hash["creators"]&.each do |creator| - given_name = creator["given_name"] - family_name = creator["family_name"] - orcid = creator.dig("name_identifier", "scheme") == "ORCID" ? creator.dig("name_identifier", "value") : nil - sequence = (creator["sequence"] || "").to_i - resource.creators << PDCMetadata::Creator.new_person(given_name, family_name, orcid, sequence) - end - resource.creators.sort_by!(&:sequence) - - resource.publisher = hash["publisher"] - resource.publication_year = hash["publication_year"] - - resource - end - # rubocop:enable Metrics/AbcSize - # rubocop:enable Metrics/MethodLength - end - # rubocop:enable Metrics/ClassLength - - # value: "Miller, Elizabeth" - # name_type: "Personal" - # given_name: "Elizabeth" - # family_name: "Miller" - class Creator - attr_accessor :value, :name_type, :given_name, :family_name, :name_identifier, :affiliations, :sequence - - # rubocop:disable Metrics/ParameterLists - def initialize(value: nil, name_type: nil, given_name: nil, family_name: nil, name_identifier: nil, sequence: 0) - @value = value - @name_type = name_type - @given_name = given_name - @family_name = family_name - @name_identifier = name_identifier - @affiliations = [] - @sequence = sequence - end - # rubocop:enable Metrics/ParameterLists + resource.doi = hash["doi"] + resource.ark = hash["ark"] + resource.description = hash["description"] - def orcid_url - name_identifier&.orcid_url - end + hash["titles"]&.each do |title| + resource.titles << PDCMetadata::Title.new(title: title["title"], title_type: title["title_type"]) + end - def orcid - name_identifier&.orcid - end + creators_from_json(resource, hash["creators"]) + resource.publisher = hash["publisher"] + resource.publication_year = hash["publication_year"] - def self.new_person(given_name, family_name, orcid_id = nil, sequence = 0) - full_name = "#{family_name}, #{given_name}" - creator = Creator.new(value: full_name, name_type: "Personal", given_name: given_name, family_name: family_name, sequence: sequence) - if orcid_id.present? - creator.name_identifier = NameIdentifier.new_orcid(orcid_id.strip) + resource end - creator - end - end - # value: "0000-0001-5000-0007" - # scheme: "ORCID" - # scheme_uri: "https://orcid.org/"" - class NameIdentifier - attr_accessor :value, :scheme, :scheme_uri - def initialize(value: nil, scheme: nil, scheme_uri: nil) - @value = value - @scheme = scheme - @scheme_uri = scheme_uri - end + private - def orcid_url - return nil unless scheme == "ORCID" - "#{scheme_uri}/#{value}" - end + def creators_from_json(resource, creators) + return if creators.blank? - def orcid - return nil unless scheme == "ORCID" - value - end - - # Convenience method since this is the most common (only?) identifier that we are currently supporting - def self.new_orcid(value) - NameIdentifier.new(value: value, scheme: "ORCID", scheme_uri: "https://orcid.org") - end - end - - # value: "datacite" - # identifier: "https://ror.org/04aj4c181" - # scheme: "ROR" - # scheme_uri: "https://ror.org/" - class Affiliation - attr_accessor :value, :identifier, :scheme, :scheme_uri - def initialize(value: nil, identifier: nil, scheme: nil, scheme_uri: nil) - @value = value - @identifier = identifier - @scheme = scheme - @scheme_uri = scheme_uri - end - end - - # value: "100 años de soledad" - # title_type: "TranslatedTitle" - class Title - attr_accessor :title, :title_type - def initialize(title:, title_type: nil) - @title = title - @title_type = title_type - end - - def main? - @title_type.blank? + creators.each do |creator| + resource.creators << Creator.from_hash(creator) + end + resource.creators.sort_by!(&:sequence) + end end end end diff --git a/app/models/pdc_metadata/title.rb b/app/models/pdc_metadata/title.rb new file mode 100644 index 000000000..e0319349c --- /dev/null +++ b/app/models/pdc_metadata/title.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Class for storing a title in our local representation +module PDCMetadata + # value: "100 años de soledad" + # title_type: "TranslatedTitle" + class Title + attr_accessor :title, :title_type + def initialize(title:, title_type: nil) + @title = title + @title_type = title_type + end + + def main? + @title_type.blank? + end + end +end diff --git a/spec/models/pdc_metadata/resource_spec.rb b/spec/models/pdc_metadata/resource_spec.rb index 98599e0c7..38995561a 100644 --- a/spec/models/pdc_metadata/resource_spec.rb +++ b/spec/models/pdc_metadata/resource_spec.rb @@ -46,4 +46,9 @@ no_orcid = PDCMetadata::Creator.new_person("Elizabeth", "Miller") expect(no_orcid.orcid).to be nil end + + it "creates the expected json" do + work = FactoryBot.create(:shakespeare_and_company_work) + expect(work.metadata).to eq(work.resource.to_json) + end end