Class: Relaton::Doi::Parser
- Inherits:
-
Object
- Object
- Relaton::Doi::Parser
- Defined in:
- lib/relaton/doi/parser.rb
Constant Summary collapse
- COUNTRIES =
%w[USA].freeze
- TYPES =
{ "book-chapter" => "inbook", "book-part" => "inbook", "book-section" => "inbook", "book-series" => "book", "book-set" => "book", "book-track" => "inbook", "component" => "misc", "database" => "dataset", "dissertation" => "thesis", "edited-book" => "book", "grant" => "misc", "journal-article" => "article", "journal-issue" => "article", "journal-volume" => "journal", "monograph" => "book", "other" => "misc", "peer-review" => "article", "posted-content" => "dataset", "proceedings-article" => "inproceedings", "proceedings-series" => "proceedings", "reference-book" => "book", "reference-entry" => "inbook", "report-component" => "techreport", "report-series" => "techreport", "report" => "techreport", }.freeze
- REALATION_TYPES =
{ "is-cited-by" => "isCitedIn", "belongs-to" => "related", "is-child-of" => "includedIn", "is-expression-of" => "expressionOf", "has-expression" => "hasExpression", "is-manifestation-of" => "manifestationOf", "is-manuscript-of" => "draftOf", "has-manuscript" => "hasDraft", "is-preprint-of" => "draftOf", "has-preprint" => "hasDraft", "is-replaced-by" => "obsoletedBy", "replaces" => "obsoletes", "is-translation-of" => "translatedFrom", "has-translation" => "hasTranslation", "is-version-of" => "editionOf", "has-version" => "hasEdition", "is-based-on" => "updates", "is-basis-for" => "updatedBy", "is-comment-on" => "commentaryOf", "has-comment" => "hasCommentary", "is-continued-by" => "hasSuccessor", "continues" => "successorOf", "is-derived-from" => "derives", "has-derivation" => "derivedFrom", "is-documented-by" => "describedBy", "documents" => "describes", "is-part-of" => "partOf", "has-part" => "hasPart", "is-review-of" => "reviewOf", "has-review" => "hasReview", "references" => "cites", "is-referenced-by" => "isCitedIn", "requires" => "hasComplement", "is-required-by" => "complementOf", "is-supplement-to" => "complementOf", "is-supplemented-by" => "hasComplement", }.freeze
- ATTRS =
i[type fetched title docidentifier date source abstract contributor place ext relation extent series medium].freeze
- CROSSREF_API_URL =
"https://api.crossref.org/works?query=%{query}&filter=%{filter}".freeze
- MAX_RETRIES =
3
Class Method Summary collapse
-
.parse(src) ⇒ Bib::ItemData
Initialize instance and parse the source hash.
Instance Method Summary collapse
-
#author_investigators ⇒ Array<Bib::Contributor>
Create authors investigators from the source hash.
-
#authors_editors_translators ⇒ Array<Bib::Contributor>
Create authors editors translators from the source hash.
-
#completename(person) ⇒ Bib::LocalizedString
Create a complete name from a person hash.
-
#contribs_from_parent(contribs) ⇒ Array<Bib::Contributor>
Fetch authors and editors from parent if they are not present in the book part.
-
#contributor(entity, type, descriprion = nil) ⇒ Bib::Contributor
Create contributor from an entity and a role type.
-
#create_affiliation(person) ⇒ Array<Bib::Affiliation>
Create person affiliations from a person hash.
-
#create_authors_editors(has, type) ⇒ Array<Bib::Contributor>
Create authors and editors from parent item.
-
#create_bibitem(doi, bibitem) ⇒ Bib::ItemData
Create a bibitem from the bibitem hash.
-
#create_enabler(name) ⇒ Bib::Contributor
Create enabler contributor with type "enabler".
-
#create_investigators(project, type) ⇒ Array<Bib::Contributor>
Create investigators from the project.
-
#create_org(name, abbreviation = nil) ⇒ Bib::Organization
Create an organization with properly typed name and abbreviation.
-
#create_person(person) ⇒ Bib::Person
Create a person from a person hash.
-
#create_person_name(person) ⇒ Bib::FullName
Create a person full name from a person hash.
-
#create_title(title, type = "main") ⇒ Bib::Title
Create a title from the title and type.
-
#date_type(type) ⇒ String
Join date parts into a string.
-
#fetch_crossref(query:, filter:) ⇒ Array<Hash>?
Fetch data from Crossref API with retry logic.
-
#fetch_location ⇒ String?
Fetch location from container.
-
#fetch_year ⇒ String
Fetch year from the source hash.
-
#forename(person) ⇒ Array<Bib::FullNameType::Forename>
Create a forename from a person hash.
-
#included_in_relation ⇒ Array<Bib::Relation>
Create included in relation.
-
#initialize(src) ⇒ Parser
constructor
Initialize instance.
-
#issn_type(type, id) ⇒ String
Create an ISSN type if it's an ISSN ID.
-
#main_sub_titles ⇒ Array<Bib::Title>
Parse main and subtitle from the source hash.
-
#nameaddition(person) ⇒ Array<Bib::LocalizedString>
Create an addition from a person hash.
-
#nameprefix(person) ⇒ Array<Bib::LocalizedString>
Create a person name prefix from a person hash.
-
#normalize_markup(str) ⇒ String
Decode the HTML entities of raw Crossref content.
-
#org_aurhorizer ⇒ Array<Bib::Contributor>
Parse authorizer contributor from the source hash.
-
#org_enabler ⇒ Array<Bib::Contributor>
Parse enabler contributor from the source hash.
-
#org_publisher ⇒ Bib::Organization
Cerate an organization publisher from the source hash.
-
#parent_item ⇒ Hash?
Fetch parent item from Crossref.
-
#parse ⇒ Bib::ItemData
Parse the source hash.
-
#parse_abstract ⇒ Array<Bib::LocalizedMarkedUpString>
Parse abstract from the source hash.
-
#parse_contributor ⇒ Array<Bib::Contributor>
Parse contributors from the source hash.
-
#parse_date ⇒ Array<Bib::Date>
Parce dates from the source hash.
-
#parse_docidentifier ⇒ Array<Bib::Docidentifier>
Parse a docidentifier from the source hash.
-
#parse_ext ⇒ Bib::Ext
Parse the ext element with doctype.
-
#parse_extent ⇒ Array<Bib::Extent>
Parse an extent from the source hash.
-
#parse_fetched ⇒ String
Parse the fetched date.
-
#parse_medium ⇒ Bib::Medium?
Parse a medium from the source hash.
-
#parse_place ⇒ Array<Bib::Place>
Parse a place from the source hash.
-
#parse_relation ⇒ Array<Bib::Relation>
Parse relations from the source hash.
-
#parse_series ⇒ Array<Bib::Series>
Parse a series from the source hash.
-
#parse_source ⇒ Array<Bib::Uri>
Parse source URIs from the source hash.
-
#parse_title ⇒ Array<Bib::Title>
Parse titles from the source hash.
-
#parse_type ⇒ String
Parse the type.
-
#person_id(person) ⇒ Array<Bib::Person::Identifier>
Create a person identifier from a person hash.
-
#project_titles ⇒ Array<Bib::Title>
Fetch titles from the projects.
-
#relation_type(crtype) ⇒ Array<String>
Transform crossref relation type to relaton relation type.
-
#str_cleanup(str) ⇒ String
Clean up trailing punctuation and whitespace from a string.
-
#titlecase(str) ⇒ <Type>
Capitalize the first letter of each word in a string except for words that are 2 letters or less.
Constructor Details
#initialize(src) ⇒ Parser
Initialize instance.
84 85 86 87 |
# File 'lib/relaton/doi/parser.rb', line 84 def initialize(src) @src = src @item = {} end |
Class Method Details
.parse(src) ⇒ Bib::ItemData
Initialize instance and parse the source hash.
96 97 98 |
# File 'lib/relaton/doi/parser.rb', line 96 def self.parse(src) new(src).parse end |
Instance Method Details
#author_investigators ⇒ Array<Bib::Contributor>
Create authors investigators from the source hash.
352 353 354 355 356 357 |
# File 'lib/relaton/doi/parser.rb', line 352 def Array(@src["project"]).reduce([]) do |memo, proj| memo + create_investigators(proj, "lead-investigator") + create_investigators(proj, "investigator") end end |
#authors_editors_translators ⇒ Array<Bib::Contributor>
Create authors editors translators from the source hash.
379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/relaton/doi/parser.rb', line 379 def %w[author editor translator].each_with_object([]) do |type, a| @src[type]&.each do |c| contrib = if c["family"] create_person(c) else create_org(str_cleanup(c["name"])) end a << contributor(contrib, type) end end end |
#completename(person) ⇒ Bib::LocalizedString
Create a complete name from a person hash.
614 615 616 617 618 |
# File 'lib/relaton/doi/parser.rb', line 614 def completename(person) return unless person["name"] Bib::LocalizedString.new(content: person["name"], language: "en", script: "Latn") end |
#contribs_from_parent(contribs) ⇒ Array<Bib::Contributor>
Fetch authors and editors from parent if they are not present in the book part.
399 400 401 402 403 404 405 406 407 |
# File 'lib/relaton/doi/parser.rb', line 399 def contribs_from_parent(contribs) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity return [] unless %w[inbook inproceedings dataset].include?(parse_type) && @src["container-title"] = contribs.any? { |c| c.role&.any? { |r| r.type == "author" } } has_editors = contribs.any? { |c| c.role&.any? { |r| r.type == "editor" } } return [] if && has_editors (, "author") end |
#contributor(entity, type, descriprion = nil) ⇒ Bib::Contributor
Create contributor from an entity and a role type.
522 523 524 525 526 527 528 529 530 |
# File 'lib/relaton/doi/parser.rb', line 522 def contributor(entity, type, descriprion = nil) desc = descriprion ? [Bib::LocalizedMarkedUpString.new(content: descriprion)] : nil role = [Bib::Contributor::Role.new(type: type, description: desc)] if entity.is_a?(Bib::Person) Bib::Contributor.new(role: role, person: entity) else Bib::Contributor.new(role: role, organization: entity) end end |
#create_affiliation(person) ⇒ Array<Bib::Affiliation>
Create person affiliations from a person hash.
554 555 556 557 558 |
# File 'lib/relaton/doi/parser.rb', line 554 def create_affiliation(person) (person["affiliation"] || []).map do |a| Bib::Affiliation.new organization: create_org(a["name"]) end end |
#create_authors_editors(has, type) ⇒ Array<Bib::Contributor>
Create authors and editors from parent item.
431 432 433 434 435 |
# File 'lib/relaton/doi/parser.rb', line 431 def (has, type) return [] if has || !parent_item Array(parent_item[type]).map { |a| contributor(create_person(a), type) } end |
#create_bibitem(doi, bibitem) ⇒ Bib::ItemData
Create a bibitem from the bibitem hash.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/relaton/doi/parser.rb', line 118 def create_bibitem(doi, bibitem) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength doctype_content = @src["type"] case doi when /\/nist/ bibitem[:ext] = Nist::Ext.new(doctype: Nist::Doctype.new(content: doctype_content)) Nist::ItemData.new(**bibitem) when /\/rfc\d+/ bibitem[:ext] = Ietf::Ext.new(doctype: Ietf::Doctype.new(content: doctype_content)) Ietf::ItemData.new(**bibitem) when /\/0026-1394\// bibitem[:ext] = Bipm::Ext.new(doctype: Bipm::Doctype.new(content: doctype_content)) Bipm::ItemData.new(**bibitem) when /\/ieee/ bibitem[:ext] = Ieee::Ext.new(doctype: Ieee::Doctype.new(content: doctype_content)) Ieee::ItemData.new(**bibitem) else Bib::ItemData.new(**bibitem) end end |
#create_enabler(name) ⇒ Bib::Contributor
Create enabler contributor with type "enabler".
510 511 512 |
# File 'lib/relaton/doi/parser.rb', line 510 def create_enabler(name) contributor(create_org(name), "enabler") end |
#create_investigators(project, type) ⇒ Array<Bib::Contributor>
Create investigators from the project.
367 368 369 370 371 372 |
# File 'lib/relaton/doi/parser.rb', line 367 def create_investigators(project, type) description = type.gsub("-", " ") Array(project[type]).map do |inv| contributor(create_person(inv), "author", description) end end |
#create_org(name, abbreviation = nil) ⇒ Bib::Organization
Create an organization with properly typed name and abbreviation.
470 471 472 473 474 475 476 |
# File 'lib/relaton/doi/parser.rb', line 470 def create_org(name, abbreviation = nil) n = [Bib::TypedLocalizedString.new(content: CGI.unescapeHTML(name))] a = if abbreviation Bib::LocalizedString.new(content: CGI.unescapeHTML(abbreviation)) end Bib::Organization.new name: n, abbreviation: a end |
#create_person(person) ⇒ Bib::Person
Create a person from a person hash.
539 540 541 542 543 544 545 |
# File 'lib/relaton/doi/parser.rb', line 539 def create_person(person) Bib::Person.new( name: create_person_name(person), affiliation: create_affiliation(person), identifier: person_id(person), ) end |
#create_person_name(person) ⇒ Bib::FullName
Create a person full name from a person hash.
567 568 569 570 571 572 573 574 |
# File 'lib/relaton/doi/parser.rb', line 567 def create_person_name(person) surname = titlecase(person["family"]) sn = Bib::LocalizedString.new(content: surname, language: "en", script: "Latn") Bib::FullName.new( surname: sn, forename: forename(person), addition: nameaddition(person), completename: completename(person), prefix: nameprefix(person) ) end |
#create_title(title, type = "main") ⇒ Bib::Title
Create a title from the title and type.
211 212 213 214 |
# File 'lib/relaton/doi/parser.rb', line 211 def create_title(title, type = "main") cnt = str_cleanup normalize_markup(title) Bib::Title.new type: type, content: cnt, script: "Latn" end |
#date_type(type) ⇒ String
Join date parts into a string.
289 290 291 |
# File 'lib/relaton/doi/parser.rb', line 289 def date_type(type) @src[type]["date-parts"][0].map { |d| d.to_s.rjust(2, "0") }.join "-" end |
#fetch_crossref(query:, filter:) ⇒ Array<Hash>?
Fetch data from Crossref API with retry logic.
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 |
# File 'lib/relaton/doi/parser.rb', line 826 def fetch_crossref(query:, filter:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength url = format(CROSSREF_API_URL, query: query, filter: filter) retries = 0 begin resp = Crossref.agent.get url JSON.parse(resp.body).dig("message", "items") rescue Mechanize::ResponseCodeError => e return nil if e.response_code.start_with?("4") raise Relaton::RequestError, "Crossref request failed: #{e.response_code} #{e.page.body}" rescue Net::HTTP::Persistent::Error, Net::HTTPError, Errno::ECONNREFUSED => e retries += 1 retry if retries <= MAX_RETRIES raise Relaton::RequestError, "Crossref network error after #{MAX_RETRIES} retries: #{e.message}" rescue JSON::ParserError => e raise Relaton::RequestError, "Crossref JSON parsing error: #{e.message}" end end |
#fetch_location ⇒ String?
Fetch location from container.
690 691 692 693 694 695 696 697 698 699 |
# File 'lib/relaton/doi/parser.rb', line 690 def fetch_location title = @item[:title].first&.content qparts = [title, fetch_year, @src["publisher"]] query = CGI.escape qparts.compact.join("+").gsub(" ", "+") filter = "type:#{%w[book-chapter book-part book-section book-track].join(',type:')}" items = fetch_crossref(query: query, filter: filter) items&.detect do |i| i["publisher-location"] && i["container-title"].include?(title) end&.dig("publisher-location") end |
#fetch_year ⇒ String
Fetch year from the source hash.
760 761 762 763 |
# File 'lib/relaton/doi/parser.rb', line 760 def fetch_year d = @src["published"] || @src["approved"] || @src["created"] d["date-parts"][0][0] end |
#forename(person) ⇒ Array<Bib::FullNameType::Forename>
Create a forename from a person hash.
627 628 629 630 631 632 |
# File 'lib/relaton/doi/parser.rb', line 627 def forename(person) return [] unless person["given"] fname = titlecase(person["given"]) [Bib::FullNameType::Forename.new(content: fname, language: "en", script: "Latn")] end |
#included_in_relation ⇒ Array<Bib::Relation>
Create included in relation.
740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
# File 'lib/relaton/doi/parser.rb', line 740 def included_in_relation types = %w[ book book-chapter book-part book-section book-track dataset journal-issue journal-value proceedings-article reference-entry report-component ] return [] unless @src["container-title"] && types.include?(@src["type"]) @src["container-title"].map do |ct| contrib = false, "editor" title = Bib::Title.new content: normalize_markup(ct) bib = Bib::ItemBase.new(title: [title], contributor: contrib) Bib::Relation.new(type: "includedIn", bibitem: bib) end end |
#issn_type(type, id) ⇒ String
Create an ISSN type if it's an ISSN ID.
258 259 260 261 262 263 |
# File 'lib/relaton/doi/parser.rb', line 258 def issn_type(type, id) return type unless type == "ISSN" t = @src["issn-type"]&.find { |it| it["value"] == id }&.dig("type") t ? "issn.#{t}" : type.downcase end |
#main_sub_titles ⇒ Array<Bib::Title>
Parse main and subtitle from the source hash.
185 186 187 188 189 190 |
# File 'lib/relaton/doi/parser.rb', line 185 def main_sub_titles title = @src["title"].map { |t| create_title t } Array(@src["subtitle"]).each { |t| title << create_title(t, "subtitle") } Array(@src["short-title"]).each { |t| title << create_title(t, "short") } title end |
#nameaddition(person) ⇒ Array<Bib::LocalizedString>
Create an addition from a person hash.
641 642 643 644 645 |
# File 'lib/relaton/doi/parser.rb', line 641 def nameaddition(person) return [] unless person["suffix"] [Bib::LocalizedString.new(content: person["suffix"], language: "en", script: "Latn")] end |
#nameprefix(person) ⇒ Array<Bib::LocalizedString>
Create a person name prefix from a person hash.
601 602 603 604 605 |
# File 'lib/relaton/doi/parser.rb', line 601 def nameprefix(person) return [] unless person["prefix"] [Bib::LocalizedString.new(content: person["prefix"], language: "en", script: "Latn")] end |
#normalize_markup(str) ⇒ String
Decode the HTML entities of raw Crossref content.
Crossref sometimes returns the JATS markup as HTML entities. The
relaton-bib sanitizer detects a tag by a real <, so it treats the
encoded form as plain text and leaves it alone. Decode the entities
here, and the sanitizer maps the markup to the basicdoc set.
The sanitizer removes the jats: and xlink: namespace prefixes
itself since relaton-bib 2.1.9, so this method no longer does.
231 232 233 |
# File 'lib/relaton/doi/parser.rb', line 231 def normalize_markup(str) CGI.unescapeHTML(str) end |
#org_aurhorizer ⇒ Array<Bib::Contributor>
Parse authorizer contributor from the source hash.
483 484 485 486 487 488 |
# File 'lib/relaton/doi/parser.rb', line 483 def org_aurhorizer return [] unless @src["standards-body"] name, acronym = @src["standards-body"].values_at("name", "acronym") [contributor(create_org(name, acronym), "authorizer")] end |
#org_enabler ⇒ Array<Bib::Contributor>
Parse enabler contributor from the source hash.
495 496 497 498 499 500 501 |
# File 'lib/relaton/doi/parser.rb', line 495 def org_enabler Array(@src["project"]).each_with_object([]) do |proj, memo| proj["funding"].each do |f| memo << create_enabler(f.dig("funder", "name")) end end + Array(@src["funder"]).map { |f| create_enabler f["name"] } end |
#org_publisher ⇒ Bib::Organization
Cerate an organization publisher from the source hash.
442 443 444 445 446 447 448 449 |
# File 'lib/relaton/doi/parser.rb', line 442 def org_publisher pbr = @src["institution"]&.detect do |i| @src["publisher"].include?(i["name"]) || i["name"].include?(@src["publisher"]) end a = pbr["acronym"]&.first if pbr create_org(str_cleanup(@src["publisher"]), a) end |
#parent_item ⇒ Hash?
Fetch parent item from Crossref.
414 415 416 417 418 419 420 421 |
# File 'lib/relaton/doi/parser.rb', line 414 def parent_item @parent_item ||= begin query = CGI.escape [@src["container-title"][0], fetch_year].compact.join("+") filter = "type:#{%w[book book-set edited-book monograph reference-book].join ',type:'}" items = fetch_crossref(query: query, filter: filter) items&.detect { |i| i["title"].include? @src["container-title"][0] } end end |
#parse ⇒ Bib::ItemData
Parse the source hash.
105 106 107 108 |
# File 'lib/relaton/doi/parser.rb', line 105 def parse ATTRS.each { |m| @item[m] = send "parse_#{m}" } create_bibitem @src["DOI"], @item end |
#parse_abstract ⇒ Array<Bib::LocalizedMarkedUpString>
Parse abstract from the source hash.
322 323 324 325 326 327 328 329 330 331 |
# File 'lib/relaton/doi/parser.rb', line 322 def parse_abstract return [] unless @src["abstract"] abstract = Bib::Abstract.new( content: normalize_markup(@src["abstract"]), language: "en", script: "Latn", ) [abstract] end |
#parse_contributor ⇒ Array<Bib::Contributor>
Parse contributors from the source hash.
338 339 340 341 342 343 344 345 |
# File 'lib/relaton/doi/parser.rb', line 338 def parse_contributor contribs = contribs += contribs += contribs_from_parent(contribs) contribs << contributor(org_publisher, "publisher") contribs += org_aurhorizer contribs + org_enabler end |
#parse_date ⇒ Array<Bib::Date>
Parce dates from the source hash.
270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/relaton/doi/parser.rb', line 270 def parse_date # rubocop:disable Metrics/CyclomaticComplexity dates = %w[issued published approved].each_with_object([]) do |type, obj| next unless @src.dig(type, "date-parts")&.first&.compact&.any? obj << Bib::Date.new(type: type, at: date_type(type)) end if dates.none? dates << Bib::Date.new(type: "created", at: date_type("created")) end dates end |
#parse_docidentifier ⇒ Array<Bib::Docidentifier>
Parse a docidentifier from the source hash.
240 241 242 243 244 245 246 247 248 |
# File 'lib/relaton/doi/parser.rb', line 240 def parse_docidentifier %w[DOI ISBN ISSN].each_with_object([]) do |type, obj| prm = type == "DOI" Array(@src[type]).each do |id| t = issn_type(type, id) obj << Bib::Docidentifier.new(type: t, content: id, primary: prm) end end end |
#parse_ext ⇒ Bib::Ext
Parse the ext element with doctype.
151 152 153 |
# File 'lib/relaton/doi/parser.rb', line 151 def parse_ext Bib::Ext.new doctype: Bib::Doctype.new(content: @src["type"]) end |
#parse_extent ⇒ Array<Bib::Extent>
Parse an extent from the source hash.
770 771 772 773 774 775 776 777 778 779 |
# File 'lib/relaton/doi/parser.rb', line 770 def parse_extent # rubocop:disable Metrics/AbcSize extent = [] extent << Bib::Locality.new(type: "volume", reference_from: @src["volume"]) if @src["volume"] extent << Bib::Locality.new(type: "issue", reference_from: @src["issue"]) if @src["issue"] if @src["page"] from, to = @src["page"].split("-") extent << Bib::Locality.new(type: "page", reference_from: from, reference_to: to) end extent.any? ? [Bib::Extent.new(locality: extent)] : [] end |
#parse_fetched ⇒ String
Parse the fetched date.
160 161 162 |
# File 'lib/relaton/doi/parser.rb', line 160 def parse_fetched Date.today.to_s end |
#parse_medium ⇒ Bib::Medium?
Parse a medium from the source hash.
809 810 811 812 813 814 |
# File 'lib/relaton/doi/parser.rb', line 809 def parse_medium genre = @src["degree"]&.first return unless genre Bib::Medium.new genre: genre end |
#parse_place ⇒ Array<Bib::Place>
Parse a place from the source hash.
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
# File 'lib/relaton/doi/parser.rb', line 665 def parse_place # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize pub_location = @src["publisher-location"] || fetch_location return [] unless pub_location pls1, pls2 = pub_location.split(", ") pls1 = str_cleanup pls1 pls2 &&= str_cleanup pls2 if COUNTRIES.include? pls2 country = Bib::Place::RegionType.new(content: pls2) [Bib::Place.new(city: pls1, country: [country])] elsif pls2 && pls2 == pls2&.upcase region = Bib::Place::RegionType.new(content: pls2) [Bib::Place.new(city: pls1, region: [region])] elsif pls1 == pls2 || pls2.nil? || pls2.empty? [Bib::Place.new(city: pls1)] else [Bib::Place.new(city: pls1), Bib::Place.new(city: pls2)] end end |
#parse_relation ⇒ Array<Bib::Relation>
Parse relations from the source hash.
706 707 708 709 710 711 712 713 714 715 716 717 718 |
# File 'lib/relaton/doi/parser.rb', line 706 def parse_relation # rubocop:disable Metrics/AbcSize, Metrics/MethodLength rels = included_in_relation @src["relation"].each_with_object(rels) do |(k, v), a| type, desc = relation_type k Array(v).each do |r| rel_item = Crossref.get_by_id r["id"] title = rel_item["title"].map { |t| create_title t } docid = Bib::Docidentifier.new(content: r["id"], type: "DOI") bib = create_bibitem r["id"], title: title, docidentifier: [docid] a << Bib::Relation.new(type: type, description: desc, bibitem: bib) end end end |
#parse_series ⇒ Array<Bib::Series>
Parse a series from the source hash.
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 |
# File 'lib/relaton/doi/parser.rb', line 786 def parse_series # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity types = %w[inbook incollection inproceedings] return [] if !@src["container-title"] || types.include?(@item[:type]) || @src["type"] == "report-component" con_ttl = if main_sub_titles.any? || project_titles.any? @src["container-title"] elsif @src["container-title"].size > 1 sct = @src["short-container-title"]&.last abbrev = Bib::LocalizedString.new(content: sct) if sct @src["container-title"][-1..-1] else [] end con_ttl.map do |ct| title = Bib::Title.new content: normalize_markup(ct) Bib::Series.new title: [title], abbreviation: abbrev end end |
#parse_source ⇒ Array<Bib::Uri>
Parse source URIs from the source hash.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/relaton/doi/parser.rb', line 298 def parse_source # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity disprefered_links = %w[similarity-checking text-mining] links = [] if @src["URL"] links << Bib::Uri.new(type: "DOI", content: @src["URL"]) end [@src["link"], @src.dig("resource", "primary")].flatten.compact.each do |l| next if disprefered_links.include? l["intended-application"] type = case l["URL"] when /\.pdf$/ then "pdf" # when /\/rfc\d+$|iopscience\.iop\.org|ieeexplore\.ieee\.org/ else "src" end links << Bib::Uri.new(type: type, content: l["URL"]) # if type end links end |
#parse_title ⇒ Array<Bib::Title>
Parse titles from the source hash.
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/relaton/doi/parser.rb', line 169 def parse_title # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity if @src["title"].is_a?(Array) && @src["title"].any? main_sub_titles elsif @src["project"].is_a?(Array) && @src["project"].any? project_titles elsif @src["container-title"].is_a?(Array) && @src["container-title"].size > 1 @src["container-title"][0..-2].map { |t| create_title t } else [] end end |
#parse_type ⇒ String
Parse the type.
142 143 144 |
# File 'lib/relaton/doi/parser.rb', line 142 def parse_type TYPES[@src["type"]] || @src["type"] end |
#person_id(person) ⇒ Array<Bib::Person::Identifier>
Create a person identifier from a person hash.
654 655 656 657 658 |
# File 'lib/relaton/doi/parser.rb', line 654 def person_id(person) return [] unless person["ORCID"] [Bib::Person::Identifier.new(type: "orcid", content: person["ORCID"])] end |
#project_titles ⇒ Array<Bib::Title>
Fetch titles from the projects.
197 198 199 200 201 |
# File 'lib/relaton/doi/parser.rb', line 197 def project_titles Array(@src["project"]).reduce([]) do |memo, proj| memo + Array(proj["project-title"]).map { |t| create_title t["title"] } end end |
#relation_type(crtype) ⇒ Array<String>
Transform crossref relation type to relaton relation type.
727 728 729 730 731 732 733 |
# File 'lib/relaton/doi/parser.rb', line 727 def relation_type(crtype) type = REALATION_TYPES[crtype] || begin desc = Bib::LocalizedMarkedUpString.new(content: crtype) "related" end [type, desc] end |
#str_cleanup(str) ⇒ String
Clean up trailing punctuation and whitespace from a string.
458 459 460 |
# File 'lib/relaton/doi/parser.rb', line 458 def str_cleanup(str) str.strip.sub(/[,\/\s]+$/, "").sub(/\s:$/, "") end |
#titlecase(str) ⇒ <Type>
Capitalize the first letter of each word in a string except for words that are 2 letters or less.
584 585 586 587 588 589 590 591 592 |
# File 'lib/relaton/doi/parser.rb', line 584 def titlecase(str) str.split.map do |s| if s.size > 2 && s.upcase == s && !/\.&/.match?(s) s.capitalize else s end end.join " " end |