bolognese 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +56 -0
- data/.travis.yml +23 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +118 -0
- data/LICENSE +21 -0
- data/README.md +3 -0
- data/Rakefile +12 -0
- data/bin/bolognese +5 -0
- data/bolognese.gemspec +40 -0
- data/lib/bolognese.rb +12 -0
- data/lib/bolognese/author_utils.rb +61 -0
- data/lib/bolognese/cli.rb +38 -0
- data/lib/bolognese/crossref.rb +202 -0
- data/lib/bolognese/datacite.rb +157 -0
- data/lib/bolognese/date_utils.rb +48 -0
- data/lib/bolognese/doi_utils.rb +48 -0
- data/lib/bolognese/github.rb +106 -0
- data/lib/bolognese/metadata.rb +30 -0
- data/lib/bolognese/orcid.rb +24 -0
- data/lib/bolognese/pid_utils.rb +23 -0
- data/lib/bolognese/pubmed.rb +34 -0
- data/lib/bolognese/string.rb +5 -0
- data/lib/bolognese/utils.rb +27 -0
- data/lib/bolognese/version.rb +3 -0
- data/spec/cli_spec.rb +37 -0
- data/spec/crossref_spec.rb +113 -0
- data/spec/datacite_spec.rb +49 -0
- data/spec/doi_spec.rb +89 -0
- data/spec/fixtures/crossref.xml +742 -0
- data/spec/fixtures/datacite.xml +40 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_CLI/read/crossref/as_crossref.yml +760 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_CLI/read/crossref/as_schema_org.yml +1476 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_CLI/read/datacite/as_datacite.yml +214 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_CLI/read/datacite/as_schema_org.yml +384 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/doi_registration_agency/crossref.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/doi_registration_agency/datacite.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/doi_registration_agency/medra.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/doi_registration_agency/not_found.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/DOI_test.yml +843 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/DOI_with_SICI_DOI.yml +277 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/DOI_with_data_citation.yml +15755 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/date_in_future.yml +2691 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/journal_article.yml +1857 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/not_found_error.yml +93 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Crossref/get_metadata/posted_content.yml +5715 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Datacite/get_metadata/BlogPosting.yml +307 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Datacite/get_metadata/Dataset.yml +343 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/find_PID_provider/crossref.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/find_PID_provider/crossref_doi_not_url.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/find_PID_provider/datacite.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/find_PID_provider/datacite_doi_http.yml +44 -0
- data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/find_PID_provider/orcid.yml +44 -0
- data/spec/metadata_spec.rb +35 -0
- data/spec/orcid_spec.rb +23 -0
- data/spec/spec_helper.rb +88 -0
- metadata +419 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3a6b175047cc9fe1cae1eba94b41164dd0c9e406
|
4
|
+
data.tar.gz: f78c9e066599d1a2b6db5c66cc1a19e8024dd73b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fede61f6811145761b605513ae01345508e8f60a7e2d807d22ac17fd80096326d7ab4af1a8b3ca117c1856adb2f31012a23ed3392023d8f9213b424d32c2e459
|
7
|
+
data.tar.gz: 4ddc0ca66cda0fbb1ea3d10021d97b1f532f733dd221c39509d1994a4c51da09f27da515fdb0536d086d425d3d0075a00fb6f498e9813802e19b0bcde70cbb87
|
data/.gitignore
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
51
|
+
|
52
|
+
coverage/
|
53
|
+
.env
|
54
|
+
.env.*
|
55
|
+
!.env.example
|
56
|
+
!.env.travis
|
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.3.3
|
4
|
+
|
5
|
+
before_install:
|
6
|
+
- export TZ=Europe/Berlin
|
7
|
+
|
8
|
+
install:
|
9
|
+
- travis_retry bundle install
|
10
|
+
|
11
|
+
script: bundle exec rspec
|
12
|
+
|
13
|
+
notifications:
|
14
|
+
email: false
|
15
|
+
|
16
|
+
deploy:
|
17
|
+
provider: rubygems
|
18
|
+
api_key:
|
19
|
+
secure: jNV7zS0e1cSV+oVCqRyolo16QHJFgba7vnFnbG1Nb4Xk3p/hQnE/WTvV0up7jXE9HVKDmMTPPVUfdtvyE/xsTlWNpjIaQ5NdAz+wf4fTkwN8in8AHvxL0V1Zj202cgn6Ikoy2Zwkg4eZTxo1PJ6niyyfMHd/XpaW7zRd7BBN3901DeR0qCsYTJaFF8cO5d/CeKBn0aCHv7vzqRvm+NsEgVmfNCgjQAvMfDZChrlYzUZlOpcmh01u2z0vZyRmsidmAehLRF6GcZpoL8CVBbyzHr6EVjOrI2XVikwj17j4hPLcEzB/gGyK6OUX4JuiSxdRYxAPApZY96SUbFFrfIDusHv1csgwznAlEF4VgerpHq8C5B+CylXHjreT17b5U2QBsr79z401a6m6aC+RM/RDu2lW1p93f/fAK/znBO3DyodlvmVYGN16PuA7g7pa8LYKwtZGSQmTlbAycwcbKHgvbdKmxYAFTOE6CWeginLM7bvOmF6IHcNGzBHK1I8xES0y1XQHFKYl4nT3cMEsA6aRRRQCIQwbr6FE8gyPZrs5P/W9vPM9p6cryXFaSJWbGbounr6lqQgtCmfDdqXPxAszTbcBu/yBukxeM3KvRVrsbtuIanuHn1ppvA31M4bUGTP9CfwKojE9bdo6m7nfHTpjNy7eqOPuUH33cQhIPMCvpZ4=
|
20
|
+
gem: bolognese
|
21
|
+
on:
|
22
|
+
tags: true
|
23
|
+
repo: datacite/bolognese
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
Bolognese (0.2)
|
5
|
+
activesupport (~> 4.2, >= 4.2.5)
|
6
|
+
builder (~> 3.2, >= 3.2.2)
|
7
|
+
dotenv (~> 2.1, >= 2.1.1)
|
8
|
+
maremma (~> 3.5)
|
9
|
+
namae (~> 0.10.2)
|
10
|
+
nokogiri (~> 1.6, >= 1.6.8)
|
11
|
+
postrank-uri (~> 1.0, >= 1.0.18)
|
12
|
+
thor (~> 0.19)
|
13
|
+
|
14
|
+
GEM
|
15
|
+
remote: https://rubygems.org/
|
16
|
+
specs:
|
17
|
+
activesupport (4.2.7.1)
|
18
|
+
i18n (~> 0.7)
|
19
|
+
json (~> 1.7, >= 1.7.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
22
|
+
tzinfo (~> 1.1)
|
23
|
+
addressable (2.3.8)
|
24
|
+
builder (3.2.3)
|
25
|
+
codeclimate-test-reporter (1.0.5)
|
26
|
+
simplecov
|
27
|
+
crack (0.4.3)
|
28
|
+
safe_yaml (~> 1.0.0)
|
29
|
+
diff-lcs (1.3)
|
30
|
+
docile (1.1.5)
|
31
|
+
dotenv (2.2.0)
|
32
|
+
excon (0.45.4)
|
33
|
+
faraday (0.9.2)
|
34
|
+
multipart-post (>= 1.2, < 3)
|
35
|
+
faraday-encoding (0.0.4)
|
36
|
+
faraday
|
37
|
+
faraday_middleware (0.10.1)
|
38
|
+
faraday (>= 0.7.4, < 1.0)
|
39
|
+
hashdiff (0.3.2)
|
40
|
+
i18n (0.8.0)
|
41
|
+
json (1.8.6)
|
42
|
+
maremma (3.5)
|
43
|
+
activesupport (~> 4.2, >= 4.2.5)
|
44
|
+
addressable (>= 2.3.6)
|
45
|
+
builder (~> 3.2, >= 3.2.2)
|
46
|
+
excon (~> 0.45.0)
|
47
|
+
faraday (~> 0.9.2)
|
48
|
+
faraday-encoding (~> 0.0.1)
|
49
|
+
faraday_middleware (~> 0.10.0)
|
50
|
+
multi_json (~> 1.11.2)
|
51
|
+
nokogiri (~> 1.6.7)
|
52
|
+
oj (~> 2.18, >= 2.18.1)
|
53
|
+
mini_portile2 (2.1.0)
|
54
|
+
minitest (5.10.1)
|
55
|
+
multi_json (1.11.3)
|
56
|
+
multipart-post (2.0.0)
|
57
|
+
namae (0.10.2)
|
58
|
+
nokogiri (1.6.8.1)
|
59
|
+
mini_portile2 (~> 2.1.0)
|
60
|
+
oj (2.18.1)
|
61
|
+
postrank-uri (1.0.18)
|
62
|
+
addressable (~> 2.3.0)
|
63
|
+
nokogiri (~> 1.6.1)
|
64
|
+
public_suffix (~> 1.1.3)
|
65
|
+
public_suffix (1.1.3)
|
66
|
+
rack (2.0.1)
|
67
|
+
rack-test (0.6.3)
|
68
|
+
rack (>= 1.0)
|
69
|
+
rake (12.0.0)
|
70
|
+
rspec (3.5.0)
|
71
|
+
rspec-core (~> 3.5.0)
|
72
|
+
rspec-expectations (~> 3.5.0)
|
73
|
+
rspec-mocks (~> 3.5.0)
|
74
|
+
rspec-core (3.5.4)
|
75
|
+
rspec-support (~> 3.5.0)
|
76
|
+
rspec-expectations (3.5.0)
|
77
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
78
|
+
rspec-support (~> 3.5.0)
|
79
|
+
rspec-mocks (3.5.0)
|
80
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
81
|
+
rspec-support (~> 3.5.0)
|
82
|
+
rspec-support (3.5.0)
|
83
|
+
rspec-xsd (0.1.0)
|
84
|
+
nokogiri (~> 1.6)
|
85
|
+
rspec (~> 3)
|
86
|
+
safe_yaml (1.0.4)
|
87
|
+
simplecov (0.12.0)
|
88
|
+
docile (~> 1.1.0)
|
89
|
+
json (>= 1.8, < 3)
|
90
|
+
simplecov-html (~> 0.10.0)
|
91
|
+
simplecov-html (0.10.0)
|
92
|
+
thor (0.19.4)
|
93
|
+
thread_safe (0.3.5)
|
94
|
+
tzinfo (1.2.2)
|
95
|
+
thread_safe (~> 0.1)
|
96
|
+
vcr (3.0.3)
|
97
|
+
webmock (1.24.6)
|
98
|
+
addressable (>= 2.3.6)
|
99
|
+
crack (>= 0.3.2)
|
100
|
+
hashdiff
|
101
|
+
|
102
|
+
PLATFORMS
|
103
|
+
ruby
|
104
|
+
|
105
|
+
DEPENDENCIES
|
106
|
+
Bolognese!
|
107
|
+
bundler (~> 1.0)
|
108
|
+
codeclimate-test-reporter (~> 1.0, >= 1.0.0)
|
109
|
+
rack-test (~> 0)
|
110
|
+
rake (~> 12.0)
|
111
|
+
rspec (~> 3.4)
|
112
|
+
rspec-xsd (~> 0.1.0)
|
113
|
+
simplecov (~> 0.12.0)
|
114
|
+
vcr (~> 3.0, >= 3.0.3)
|
115
|
+
webmock (~> 1.22, >= 1.22.3)
|
116
|
+
|
117
|
+
BUNDLED WITH
|
118
|
+
1.12.5
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 DataCite
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/bolognese
ADDED
data/bolognese.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "date"
|
2
|
+
require File.expand_path("../lib/bolognese/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.authors = "Martin Fenner"
|
6
|
+
s.email = "mfenner@datacite.org"
|
7
|
+
s.name = "bolognese"
|
8
|
+
s.homepage = "https://github.com/datacite/bolognese"
|
9
|
+
s.summary = "Ruby client library for conversion of DOI Metadata"
|
10
|
+
s.date = Date.today
|
11
|
+
s.description = "Convert DOI metadata to and from Crossref and DataCite XML, as well as schema.org/JSON-LD"
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.version = Bolognese::VERSION
|
14
|
+
s.extra_rdoc_files = ["README.md"]
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
# Declary dependencies here, rather than in the Gemfile
|
18
|
+
s.add_dependency 'maremma', '~> 3.5'
|
19
|
+
s.add_dependency 'nokogiri', '~> 1.6', '>= 1.6.8'
|
20
|
+
s.add_dependency 'builder', '~> 3.2', '>= 3.2.2'
|
21
|
+
s.add_dependency 'activesupport', '~> 4.2', '>= 4.2.5'
|
22
|
+
s.add_dependency 'dotenv', '~> 2.1', '>= 2.1.1'
|
23
|
+
s.add_dependency 'thor', '~> 0.19'
|
24
|
+
s.add_dependency 'namae', '~> 0.10.2'
|
25
|
+
s.add_dependency 'postrank-uri', '~> 1.0', '>= 1.0.18'
|
26
|
+
s.add_development_dependency 'bundler', '~> 1.0'
|
27
|
+
s.add_development_dependency 'rspec', '~> 3.4'
|
28
|
+
s.add_development_dependency 'rspec-xsd', '~> 0.1.0'
|
29
|
+
s.add_development_dependency 'rake', '~> 12.0'
|
30
|
+
s.add_development_dependency 'rack-test', '~> 0'
|
31
|
+
s.add_development_dependency 'vcr', '~> 3.0', '>= 3.0.3'
|
32
|
+
s.add_development_dependency 'webmock', '~> 1.22', '>= 1.22.3'
|
33
|
+
s.add_development_dependency 'codeclimate-test-reporter', '~> 1.0', '>= 1.0.0'
|
34
|
+
s.add_development_dependency 'simplecov', '~> 0.12.0'
|
35
|
+
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.files = `git ls-files`.split($/)
|
38
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
39
|
+
s.executables = ["bolognese"]
|
40
|
+
end
|
data/lib/bolognese.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'maremma'
|
4
|
+
require 'postrank-uri'
|
5
|
+
|
6
|
+
require "bolognese/version"
|
7
|
+
require "bolognese/metadata"
|
8
|
+
require "bolognese/crossref"
|
9
|
+
require "bolognese/datacite"
|
10
|
+
require "bolognese/orcid"
|
11
|
+
require "bolognese/cli"
|
12
|
+
require "bolognese/string"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'namae'
|
2
|
+
|
3
|
+
module Bolognese
|
4
|
+
module AuthorUtils
|
5
|
+
# only assume personal name when using sort-order: "Turing, Alan"
|
6
|
+
def get_one_author(author, options = {})
|
7
|
+
orcid = get_name_identifier(author)
|
8
|
+
author = author.fetch("creatorName", nil)
|
9
|
+
|
10
|
+
return { "Name" => "" } if author.strip.blank?
|
11
|
+
|
12
|
+
author = cleanup_author(author)
|
13
|
+
names = Namae.parse(author)
|
14
|
+
|
15
|
+
if names.blank? || is_personal_name?(author).blank?
|
16
|
+
{ "@type" => "Agent",
|
17
|
+
"@id" => orcid,
|
18
|
+
"Name" => author }.compact
|
19
|
+
else
|
20
|
+
name = names.first
|
21
|
+
|
22
|
+
{ "@type" => "Person",
|
23
|
+
"@id" => orcid,
|
24
|
+
"givenName" => name.given,
|
25
|
+
"familyName" => name.family }.compact
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def cleanup_author(author)
|
30
|
+
# detect pattern "Smith J.", but not "Smith, John K."
|
31
|
+
author = author.gsub(/[[:space:]]([A-Z]\.)?(-?[A-Z]\.)$/, ', \1\2') unless author.include?(",")
|
32
|
+
|
33
|
+
# titleize strings
|
34
|
+
# remove non-standard space characters
|
35
|
+
author.my_titleize
|
36
|
+
.gsub(/[[:space:]]/, ' ')
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_personal_name?(author)
|
40
|
+
return true if author.include?(",")
|
41
|
+
|
42
|
+
# lookup given name
|
43
|
+
#::NameDetector.name_exists?(author.split.first)
|
44
|
+
end
|
45
|
+
|
46
|
+
# parse array of author strings into CSL format
|
47
|
+
def get_authors(authors, options={})
|
48
|
+
Array(authors).map { |author| get_one_author(author, options) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_name_identifier(author)
|
52
|
+
name_identifier = author.dig("nameIdentifier", "text")
|
53
|
+
name_identifier_scheme = author.dig("nameIdentifier", "nameIdentifierScheme") || "ORCID"
|
54
|
+
if name_identifier_scheme.downcase == "orcid" && name_identifier = validate_orcid(name_identifier)
|
55
|
+
"http://orcid.org/#{name_identifier}"
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
module Bolognese
|
6
|
+
class CLI < Thor
|
7
|
+
def self.exit_on_failure?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
# from http://stackoverflow.com/questions/22809972/adding-a-version-option-to-a-ruby-thor-cli
|
12
|
+
map %w[--version -v] => :__print_version
|
13
|
+
|
14
|
+
desc "--version, -v", "print the version"
|
15
|
+
def __print_version
|
16
|
+
puts Bolognese::VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "read pid", "read metadata for PID"
|
20
|
+
method_option :as, :default => "schema_org"
|
21
|
+
def read(pid)
|
22
|
+
provider = Metadata.new(pid).provider
|
23
|
+
|
24
|
+
case
|
25
|
+
when provider == "crossref" && options[:as] == "crossref"
|
26
|
+
puts Crossref.new(pid).raw
|
27
|
+
when provider == "crossref"
|
28
|
+
puts Crossref.new(pid).as_schema_org
|
29
|
+
when provider == "datacite" && options[:as] == "datacite"
|
30
|
+
puts Datacite.new(pid).raw
|
31
|
+
when "datacite"
|
32
|
+
puts Datacite.new(pid).as_schema_org
|
33
|
+
else
|
34
|
+
puts "not implemented"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require_relative 'doi_utils'
|
2
|
+
require_relative 'utils'
|
3
|
+
|
4
|
+
module Bolognese
|
5
|
+
class Crossref < Metadata
|
6
|
+
include Bolognese::DoiUtils
|
7
|
+
include Bolognese::Utils
|
8
|
+
|
9
|
+
# CrossRef types from https://api.crossref.org/types
|
10
|
+
CROSSREF_TYPE_TRANSLATIONS = {
|
11
|
+
"Proceedings" => nil,
|
12
|
+
"ReferenceBook" => nil,
|
13
|
+
"JournalIssue" => nil,
|
14
|
+
"ProceedingsArticle" => nil,
|
15
|
+
"Other" => nil,
|
16
|
+
"Dissertation" => "Thesis",
|
17
|
+
"Dataset" => "Dataset",
|
18
|
+
"EditedBook" => "Book",
|
19
|
+
"JournalArticle" => "ScholarlyArticle",
|
20
|
+
"Journal" => nil,
|
21
|
+
"Report" => nil,
|
22
|
+
"BookSeries" => nil,
|
23
|
+
"ReportSeries" => nil,
|
24
|
+
"BookTrack" => nil,
|
25
|
+
"Standard" => nil,
|
26
|
+
"BookSection" => nil,
|
27
|
+
"BookPart" => nil,
|
28
|
+
"Book" => "Book",
|
29
|
+
"BookChapter" => "Chapter",
|
30
|
+
"StandardSeries" => nil,
|
31
|
+
"Monograph" => "Book",
|
32
|
+
"Component" => nil,
|
33
|
+
"ReferenceEntry" => nil,
|
34
|
+
"JournalVolume" => nil,
|
35
|
+
"BookSet" => nil,
|
36
|
+
"PostedContent" => nil
|
37
|
+
}
|
38
|
+
|
39
|
+
attr_reader = :id, :metadata, :schema_org
|
40
|
+
|
41
|
+
def initialize(doi)
|
42
|
+
@id = normalize_doi(doi)
|
43
|
+
end
|
44
|
+
|
45
|
+
def raw
|
46
|
+
response = Maremma.get(@id, accept: "application/vnd.crossref.unixref+xml", host: true, raw: true)
|
47
|
+
@raw ||= response.body.fetch("data", nil)
|
48
|
+
end
|
49
|
+
|
50
|
+
def metadata
|
51
|
+
@metadata ||= raw.present? ? Maremma.from_xml(raw).fetch("doi_records", {}).fetch("doi_record", {}) : {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def exists?
|
55
|
+
metadata.present?
|
56
|
+
end
|
57
|
+
|
58
|
+
def journal_metadata
|
59
|
+
metadata.dig("crossref", "journal", "journal_metadata").presence || {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def bibliographic_metadata
|
63
|
+
if metadata.dig("crossref", "journal", "journal_article").present?
|
64
|
+
metadata.dig("crossref", "journal", "journal_article")
|
65
|
+
else
|
66
|
+
k = metadata.dig("crossref").keys.last
|
67
|
+
metadata.dig("crossref", k).presence || {}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def program_metadata
|
72
|
+
bibliographic_metadata.dig("program") ||
|
73
|
+
bibliographic_metadata.dig("crossmark", "custom_metadata", "program") || {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def additional_type
|
77
|
+
if metadata.dig("crossref", "journal").present?
|
78
|
+
metadata.dig("crossref", "journal").keys.last.camelize
|
79
|
+
else
|
80
|
+
metadata.dig("crossref").keys.last.camelize
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def type
|
85
|
+
CROSSREF_TYPE_TRANSLATIONS[additional_type] || "CreativeWork"
|
86
|
+
end
|
87
|
+
|
88
|
+
def name
|
89
|
+
parse_attribute(bibliographic_metadata.dig("titles", "title"))
|
90
|
+
end
|
91
|
+
|
92
|
+
def alternate_name
|
93
|
+
if bibliographic_metadata.fetch("publisher_item", nil).present?
|
94
|
+
parse_attribute(bibliographic_metadata.dig("publisher_item", "item_number"))
|
95
|
+
else
|
96
|
+
parse_attribute(bibliographic_metadata.fetch("item_number", nil))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def description
|
101
|
+
bibliographic_metadata.fetch("abstract", {}).values.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def license
|
105
|
+
access_indicator = Array.wrap(program_metadata).find { |m| m["name"] == "AccessIndicators" }
|
106
|
+
if access_indicator.present?
|
107
|
+
parse_attribute(access_indicator["license_ref"])
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def author
|
114
|
+
person = bibliographic_metadata.dig("contributors", "person_name")
|
115
|
+
Array(person).select { |a| a["contributor_role"] == "author" }.map do |a|
|
116
|
+
{ "@type" => "Person",
|
117
|
+
"@id" => a["ORCID"],
|
118
|
+
"givenName" => a["given_name"],
|
119
|
+
"familyName" => a["surname"] }.compact
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def editor
|
124
|
+
person = bibliographic_metadata.dig("contributors", "person_name")
|
125
|
+
Array(person).select { |a| a["contributor_role"] == "editor" }.map do |a|
|
126
|
+
{ "@type" => "Person",
|
127
|
+
"@id" => a["ORCID"],
|
128
|
+
"givenName" => a["given_name"],
|
129
|
+
"familyName" => a["surname"] }.compact
|
130
|
+
end.presence
|
131
|
+
end
|
132
|
+
|
133
|
+
def date_published
|
134
|
+
pub_date = bibliographic_metadata.fetch("publication_date", nil) ||
|
135
|
+
bibliographic_metadata.fetch("acceptance_date", nil)
|
136
|
+
if pub_date.present?
|
137
|
+
get_date_from_parts(pub_date["year"], pub_date["month"], pub_date["day"])
|
138
|
+
else
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def date_modified
|
144
|
+
Time.parse(metadata.fetch("timestamp", "")).utc.iso8601
|
145
|
+
end
|
146
|
+
|
147
|
+
def page_start
|
148
|
+
bibliographic_metadata.dig("pages", "first_page")
|
149
|
+
end
|
150
|
+
|
151
|
+
def page_end
|
152
|
+
bibliographic_metadata.dig("pages", "last_page")
|
153
|
+
end
|
154
|
+
|
155
|
+
def is_part_of
|
156
|
+
if journal_metadata.present?
|
157
|
+
{ "@type" => "Periodical",
|
158
|
+
"name" => journal_metadata["full_title"],
|
159
|
+
"issn" => parse_attribute(journal_metadata.fetch("issn", nil)) }.compact
|
160
|
+
else
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def citation
|
166
|
+
citations = bibliographic_metadata.dig("citation_list", "citation")
|
167
|
+
Array(citations).map do |c|
|
168
|
+
{ "@type" => "CreativeWork",
|
169
|
+
"@id" => normalize_doi(c["doi"]),
|
170
|
+
"position" => c["key"],
|
171
|
+
"name" => c["article_title"],
|
172
|
+
"datePublished" => c["cYear"] }.compact
|
173
|
+
end.presence
|
174
|
+
end
|
175
|
+
|
176
|
+
def provider
|
177
|
+
{ "@type" => "Organization",
|
178
|
+
"name" => "Crossref" }
|
179
|
+
end
|
180
|
+
|
181
|
+
def as_schema_org
|
182
|
+
{ "@context" => "http://schema.org",
|
183
|
+
"@type" => type,
|
184
|
+
"@id" => id,
|
185
|
+
"additionalType" => additional_type,
|
186
|
+
"name" => name,
|
187
|
+
"alternateName" => alternate_name,
|
188
|
+
"author" => author,
|
189
|
+
"editor" => editor,
|
190
|
+
"description" => description,
|
191
|
+
"license" => license,
|
192
|
+
"datePublished" => date_published,
|
193
|
+
"dateModified" => date_modified,
|
194
|
+
"pageStart" => page_start,
|
195
|
+
"pageEnd" => page_end,
|
196
|
+
"isPartOf" => is_part_of,
|
197
|
+
"citation" => citation,
|
198
|
+
"provider" => provider
|
199
|
+
}.compact
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|