serrano 0.6.0 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7115cc1e655085ff2114f8f5a9a7c093b4b6b53b0292264ba83336d6299f4f21
4
- data.tar.gz: 352701f211ca40a431cc4ccbb01d9431dc12484ce1c2efc2fbe27f145e29cf52
3
+ metadata.gz: 4cfcf7f23380a97af986d90644b8ab541f89c14e5df46485ad84fbcff437a361
4
+ data.tar.gz: ff3571fbbe79b62cb203e54887c09a0f5af81838a7e0e7aec8c2cb3fa1376890
5
5
  SHA512:
6
- metadata.gz: 3b66d48e05bc4233a426154d142004f59a26272f043e56cb384c03045b896dee82ed1b9fc9c3dedf74e64a524676206e86ce8b7694f0e48fe751dc6a235e65af
7
- data.tar.gz: 94a984d7d49ecea0623e546bdf99cdc26ec279ff45f7f88e2c5f0b76e2b9a42b5cb7bfd145fa079c53c8b460b3a0d3b57436d7643fb2f9685c48695ccbe73d51
6
+ metadata.gz: 057e9ff07332d37fcd6711695ddd2648d7fd76f74a87585c795a9412883ee4346cf0868b5819f6025e8fee3ef687ac1da035f8ecbfb07424450f5a161daa88a2
7
+ data.tar.gz: a47b838e2812df16d600df5530175d31682679e2070e78ad0c8c6250f6b65c1e67d71d6a9cc31fefc055caa59de40148f842ec607b68264845eca55ab1a9cfab
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "13:00"
8
+ open-pull-requests-limit: 10
9
+ ignore:
10
+ - dependency-name: codecov
11
+ versions:
12
+ - "> 0.1.17, < 0.2"
13
+ - dependency-name: codecov
14
+ versions:
15
+ - "> 0.2.1, < 0.3"
16
+ - dependency-name: codecov
17
+ versions:
18
+ - 0.4.2
19
+ - 0.4.3
20
+ - dependency-name: simplecov
21
+ versions:
22
+ - 0.20.0
@@ -0,0 +1,30 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ ubuntu-latest, macos-11 ]
15
+ ruby: [ 2.6, 2.7, 3.0, 3.1 ]
16
+ runs-on: ${{ matrix.os }}
17
+ env:
18
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - name: Setup Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ - name: Install dependencies
26
+ run: bundle install
27
+ - name: Run tests
28
+ run: |
29
+ bundle exec rake install
30
+ bundle exec rake test TESTOPTS="-v"
data/.gitignore CHANGED
@@ -26,7 +26,7 @@ build/
26
26
 
27
27
  # for a library or gem, you might want to ignore these files since the code is
28
28
  # intended to run in multiple environments; otherwise, check them in:
29
- #Gemfile.lock
29
+ Gemfile.lock
30
30
  .ruby-version
31
31
  .ruby-gemset
32
32
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.4 (2022-03-26)
2
+
3
+ * Moved to faraday > v2. There's no user facing changes here, but let me know if any issues arise (#172)
4
+ * PR by @LocoDelAssembly fixes `Serrano.content_negotiation(format: "citeproc-json")` by having it return `nil` instead of `Resource not found` when no DOI is found, so that the output is more compatible with flows that use serrano to create JSON (#169)
5
+ * PR by @xuanxu adds `REXML` as a runtime dependency (#159)
6
+
7
+ ## 1.0.0 (2020-10-19)
8
+
9
+ * updated dependency versions
10
+
11
+ ## 0.6.2 (2020-05-29)
12
+
13
+ * put documentation link back in rubygems page (#132)
14
+
1
15
  ## 0.6.0 (2020-02-18)
2
16
 
3
17
  * query.title (`query_title` query filter as used here) has been removed; use `query_bibliographic` instead (#111)
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2020 Scott Chamberlain
1
+ Copyright (C) 2022 Scott Chamberlain
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
data/README.md CHANGED
@@ -2,13 +2,14 @@ serrano
2
2
  =========
3
3
 
4
4
  [![gem version](https://img.shields.io/gem/v/serrano.svg)](https://rubygems.org/gems/serrano)
5
- [![Build Status](https://api.travis-ci.org/sckott/serrano.png)](https://travis-ci.org/sckott/serrano)
6
- [![codecov.io](http://codecov.io/github/sckott/serrano/coverage.svg?branch=master)](http://codecov.io/github/sckott/serrano?branch=master)
5
+ [![Ruby](https://github.com/sckott/serrano/workflows/Ruby/badge.svg)](https://github.com/sckott/serrano/actions)
6
+ [![codecov.io](https://codecov.io/github/sckott/serrano/coverage.svg?branch=main)](https://codecov.io/github/sckott/serrano?branch=main)
7
7
  [![DOI](https://zenodo.org/badge/2600/sckott/serrano.svg)](https://zenodo.org/badge/latestdoi/2600/sckott/serrano)
8
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
8
9
 
9
10
  `serrano` is a low level client for Crossref APIs
10
11
 
11
- Docs: http://www.rubydoc.info/gems/serrano
12
+ Docs: https://www.rubydoc.info/gems/serrano
12
13
 
13
14
  Other Crossref API clients:
14
15
 
@@ -46,7 +47,7 @@ Other methods:
46
47
 
47
48
  Note about searching:
48
49
 
49
- You are using the Crossref search API described at https://github.com/CrossRef/rest-api-doc When you search with query terms, on Crossref servers they are not searching full text, or even abstracts of articles, but only what is available in the data that is returned to you. That is, they search article titles, authors, etc. For some discussion on this, see https://gitlab.com/crossref/issues/issues/101
50
+ You are using the Crossref search API described at https://api.crossref.org When you search with query terms, on Crossref servers they are not searching full text, or even abstracts of articles, but only what is available in the data that is returned to you. That is, they search article titles, authors, etc. For some discussion on this, see https://gitlab.com/crossref/issues/issues/101
50
51
 
51
52
  Rate limits:
52
53
 
@@ -183,6 +184,8 @@ Commands:
183
184
 
184
185
  # Many DOIs
185
186
  ~$ serrano works "10.1007/12080.1874-1746,10.1007/10452.1573-5125"
187
+ ## if above two dois in a file called dois.txt
188
+ ~$ cat dois.txt | xargs -I{} serrano works {}
186
189
 
187
190
  # output JSON, then parse with e.g., jq
188
191
  ~$ serrano works --filter=has_orcid:true --json --limit=2 | jq '.message.items[].author[].ORCID | select(. != null)'
@@ -193,9 +196,8 @@ Commands:
193
196
  * Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
194
197
  * License: MIT
195
198
 
196
- [crapi]: https://github.com/CrossRef/rest-api-doc/blob/master/rest_api.md
197
- [cn]: http://www.crosscite.org/cn/
198
- [tdm]: http://www.crossref.org/tdm/
199
- [ccount]: http://labs.crossref.org/openurl/
199
+ [crapi]: https://api.crossref.org/
200
+ [cn]: https://citation.crosscite.org/docs.html
201
+ [ccount]: https://www.crossref.org/documentation/retrieve-metadata/openurl/
200
202
  [csl]: https://github.com/citation-style-language/styles
201
- [changelog]: https://github.com/sckott/serrano/blob/master/CHANGELOG.md
203
+ [changelog]: https://github.com/sckott/serrano/blob/main/CHANGELOG.md
data/Rakefile CHANGED
@@ -1,49 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
5
- require 'rubocop/rake_task'
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "standard"
6
+ require "standard/rake"
6
7
 
7
8
  Rake::TestTask.new do |t|
8
- t.libs << 'test'
9
- t.test_files = FileList['test/test_*.rb']
9
+ t.libs << "test"
10
+ t.test_files = FileList["test/test_*.rb"]
10
11
  t.verbose = true
11
12
  t.warning = false
12
13
  end
13
14
 
14
- desc 'Run tests'
15
+ desc "Run tests"
15
16
  task default: :test
16
17
 
17
- RuboCop::RakeTask.new(:rubocop) do |t|
18
- t.options = ['--display-cop-names']
19
- end
20
-
21
- desc 'Build serrano docs'
18
+ desc "Build serrano docs"
22
19
  task :docs do
23
- system 'yardoc'
20
+ system "yardoc"
24
21
  end
25
22
 
26
- desc 'bundle install'
23
+ desc "bundle install"
27
24
  task :bundle do
28
- system 'bundle install'
25
+ system "bundle install"
29
26
  end
30
27
 
31
- desc 'clean out builds'
28
+ desc "clean out builds"
32
29
  task :clean do
33
- system 'ls | grep [0-9].gem | xargs rm'
30
+ system "ls | grep [0-9].gem | xargs rm"
34
31
  end
35
32
 
36
- desc 'Build serrano'
33
+ desc "Build serrano"
37
34
  task :build do
38
- system 'gem build serrano.gemspec'
35
+ system "gem build serrano.gemspec"
39
36
  end
40
37
 
41
- desc 'Install serrano'
38
+ desc "Install serrano"
42
39
  task install: %i[bundle build] do
43
40
  system "gem install serrano-#{Serrano::VERSION}.gem"
44
41
  end
45
42
 
46
- desc 'Release to Rubygems'
43
+ desc "Release to Rubygems"
47
44
  task release: :build do
48
45
  system "gem push serrano-#{Serrano::VERSION}.gem"
49
46
  end
47
+
48
+ desc "open an irb session preloaded with this gem"
49
+ task :console do
50
+ sh "irb -r pp -r ./lib/serrano.rb"
51
+ end
data/lib/serrano/cn.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'serrano/version'
4
- require 'serrano/cnrequest'
3
+ require "serrano/version"
4
+ require "serrano/cnrequest"
5
5
 
6
6
  ##
7
7
  # ContentNegotiation - Content Negotiation class
8
8
  #
9
- # @see http://www.crosscite.org/cn/ for details
9
+ # @see https://citation.crosscite.org/docs.html for details
10
10
  module Serrano
11
11
  class ContentNegotiation
12
12
  attr_accessor :ids
@@ -14,7 +14,7 @@ module Serrano
14
14
  attr_accessor :style
15
15
  attr_accessor :locale
16
16
 
17
- def initialize(ids, format = 'bibtex', style = 'apa', locale = 'en-US')
17
+ def initialize(ids, format = "bibtex", style = "apa", locale = "en-US")
18
18
  self.ids = ids
19
19
  self.format = format
20
20
  self.style = style
@@ -1,38 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
4
- require 'faraday_middleware'
5
- require 'multi_json'
6
- require 'serrano/error'
7
- require 'serrano/utils'
8
- require 'serrano/helpers/configuration'
3
+ require "faraday"
4
+ require "faraday/follow_redirects"
5
+ require "multi_json"
6
+ require "serrano/error"
7
+ require "serrano/utils"
8
+ require "serrano/helpers/configuration"
9
9
 
10
- CN_FORMAT_HEADERS = { 'rdf-xml' => 'application/rdf+xml',
11
- 'turtle' => 'text/turtle',
12
- 'citeproc-json' => 'transform/application/vnd.citationstyles.csl+json',
13
- 'text' => 'text/x-bibliography',
14
- 'ris' => 'application/x-research-info-systems',
15
- 'bibtex' => 'application/x-bibtex',
16
- 'crossref-xml' => 'application/vnd.crossref.unixref+xml',
17
- 'datacite-xml' => 'application/vnd.datacite.datacite+xml',
18
- 'bibentry' => 'application/x-bibtex',
19
- 'crossref-tdm' => 'application/vnd.crossref.unixsd+xml' }.freeze
10
+ CN_FORMAT_HEADERS = {"rdf-xml" => "application/rdf+xml",
11
+ "turtle" => "text/turtle",
12
+ "citeproc-json" => "transform/application/vnd.citationstyles.csl+json",
13
+ "text" => "text/x-bibliography",
14
+ "ris" => "application/x-research-info-systems",
15
+ "bibtex" => "application/x-bibtex",
16
+ "crossref-xml" => "application/vnd.crossref.unixref+xml",
17
+ "datacite-xml" => "application/vnd.datacite.datacite+xml",
18
+ "bibentry" => "application/x-bibtex",
19
+ "crossref-tdm" => "application/vnd.crossref.unixsd+xml"}.freeze
20
20
 
21
21
  ##
22
22
  # Serrano::CNRequest
23
23
  #
24
24
  # Class to perform HTTP requests to the Crossref API
25
25
  module Serrano
26
- class CNRequest #:nodoc:
26
+ class CNRequest # :nodoc:
27
27
  attr_accessor :ids
28
28
  attr_accessor :format
29
29
  attr_accessor :style
30
30
  attr_accessor :locale
31
31
 
32
32
  CN_FORMATS = %w[rdf-xml turtle citeproc-json
33
- citeproc-json-ish text ris bibtex
34
- crossref-xml datacite-xml bibentry
35
- crossref-tdm].freeze
33
+ citeproc-json-ish text ris bibtex
34
+ crossref-xml datacite-xml bibentry
35
+ crossref-tdm].freeze
36
36
 
37
37
  def initialize(ids, format, style, locale)
38
38
  self.ids = ids
@@ -43,16 +43,16 @@ module Serrano
43
43
 
44
44
  def perform
45
45
  unless CN_FORMATS.include? format
46
- raise 'format not one of accepted types'
46
+ raise "format not one of accepted types"
47
47
  end
48
48
 
49
- conn = Faraday.new 'https://doi.org/' do |c|
50
- c.use FaradayMiddleware::FollowRedirects
49
+ conn = Faraday.new "https://doi.org/" do |c|
50
+ c.use Faraday::FollowRedirects::Middleware
51
51
  c.adapter :net_http
52
52
  end
53
53
 
54
54
  if ids.length == 1
55
- self.ids = ids[0] if ids.class == Array
55
+ self.ids = ids[0] if ids.instance_of?(Array)
56
56
  make_request(conn, ids, format, style, locale)
57
57
  else
58
58
  coll = []
@@ -68,38 +68,24 @@ end
68
68
  def make_request(conn, ids, format, style, locale)
69
69
  type = CN_FORMAT_HEADERS.select { |x, _| x.include? format }.values[0]
70
70
 
71
- if format == 'citeproc-json'
72
- endpt = 'http://api.crossref.org/works/' + ids + '/' + type
71
+ if format == "citeproc-json"
72
+ endpt = "https://api.crossref.org/works/" + ids + "/" + type
73
73
  cr_works = Faraday.new(url: endpt)
74
74
  cr_works.headers[:user_agent] = make_ua
75
- cr_works.headers['X-USER-AGENT'] = make_ua
75
+ cr_works.headers["X-USER-AGENT"] = make_ua
76
76
  res = cr_works.get
77
77
  else
78
- if format == 'text'
79
- type = type + '; style = ' + style + '; locale = ' + locale
78
+ if format == "text"
79
+ type = type + "; style = " + style + "; locale = " + locale
80
80
  end
81
81
 
82
- res = conn.get do |req|
82
+ res = conn.get { |req|
83
83
  req.url ids
84
- req.headers['Accept'] = type
84
+ req.headers["Accept"] = type
85
85
  req.headers[:user_agent] = make_ua
86
- req.headers['X-USER-AGENT'] = make_ua
87
- end
86
+ req.headers["X-USER-AGENT"] = make_ua
87
+ }
88
88
  end
89
89
 
90
- res.body
90
+ res.body if res.success?
91
91
  end
92
-
93
- # parser <- cn_types[[self.format]]
94
- # if (raw) {
95
- # content(response, "text")
96
- # } else {
97
- # out <- content(response, "parsed", parser, "UTF-8")
98
- # if (format == "text") {
99
- # out <- gsub("\n", "", out)
100
- # }
101
- # if (format == "bibentry") {
102
- # out <- parse_bibtex(out)
103
- # }
104
- # out
105
- # }
@@ -1,72 +1,74 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
4
- require 'multi_json'
3
+ require "faraday"
4
+ require "multi_json"
5
5
 
6
6
  # @private
7
- module FaradayMiddleware
8
- # @private
9
- class RaiseHttpException < Faraday::Middleware
10
- def call(env)
11
- @app.call(env).on_complete do |response|
12
- case response[:status].to_i
13
- when 400
14
- raise Serrano::BadRequest, error_message_400(response)
15
- when 404
16
- raise Serrano::NotFound, error_message_400(response)
17
- when 500
18
- raise Serrano::InternalServerError, error_message_500(response, 'Something is technically wrong.')
19
- when 502
20
- raise Serrano::BadGateway, error_message_500(response, 'The server returned an invalid or incomplete response.')
21
- when 503
22
- raise Serrano::ServiceUnavailable, error_message_500(response, 'Crossref is rate limiting your requests.')
23
- when 504
24
- raise Serrano::GatewayTimeout, error_message_500(response, '504 Gateway Time-out')
7
+ module Faraday
8
+ module SerranoErrors
9
+ # @private
10
+ class Middleware < Faraday::Middleware
11
+ def call(env)
12
+ @app.call(env).on_complete do |response|
13
+ case response[:status].to_i
14
+ when 400
15
+ raise Serrano::BadRequest, error_message_400(response)
16
+ when 404
17
+ raise Serrano::NotFound, error_message_400(response)
18
+ when 500
19
+ raise Serrano::InternalServerError, error_message_500(response, "Something is technically wrong.")
20
+ when 502
21
+ raise Serrano::BadGateway, error_message_500(response, "The server returned an invalid or incomplete response.")
22
+ when 503
23
+ raise Serrano::ServiceUnavailable, error_message_500(response, "Crossref is rate limiting your requests.")
24
+ when 504
25
+ raise Serrano::GatewayTimeout, error_message_500(response, "504 Gateway Time-out")
26
+ end
25
27
  end
26
28
  end
27
- end
28
29
 
29
- def initialize(app)
30
- super app
31
- @parser = nil
32
- end
30
+ def initialize(app)
31
+ super app
32
+ @parser = nil
33
+ end
33
34
 
34
- private
35
+ private
35
36
 
36
- def error_message_400(response)
37
- "\n #{response[:method].to_s.upcase} #{response[:url]}\n Status #{response[:status]}#{error_body(response[:body])}"
38
- end
37
+ def error_message_400(response)
38
+ "\n #{response[:method].to_s.upcase} #{response[:url]}\n Status #{response[:status]}#{error_body(response[:body])}"
39
+ end
39
40
 
40
- def error_body(body)
41
- if !body.nil? && !body.empty? && body.is_a?(String)
42
- if json?(body)
43
- body = ::MultiJson.load(body)
44
- if body['message'].nil?
45
- body = nil
46
- elseif body['message'].length == 1
47
- body = body['message']
48
- else
49
- body = body['message'].collect { |x| x['message'] }.join('; ')
41
+ def error_body(body)
42
+ if !body.nil? && !body.empty? && body.is_a?(String)
43
+ if json?(body)
44
+ body = ::MultiJson.load(body)
45
+ if body["message"].nil?
46
+ body = nil
47
+ elseif body["message"].length == 1
48
+ body = body["message"]
49
+ else
50
+ body = body["message"].collect { |x| x["message"] }.join("; ")
51
+ end
50
52
  end
51
53
  end
52
- end
53
54
 
54
- if body.nil?
55
- nil
56
- else
57
- ": #{body}"
55
+ if body.nil?
56
+ nil
57
+ else
58
+ ": #{body}"
59
+ end
58
60
  end
59
- end
60
61
 
61
- def error_message_500(response, body = nil)
62
- "#{response[:method].to_s.upcase} #{response[:url]}: #{[response[:status].to_s + ':', body].compact.join(' ')}"
63
- end
62
+ def error_message_500(response, body = nil)
63
+ "#{response[:method].to_s.upcase} #{response[:url]}: #{[response[:status].to_s + ":", body].compact.join(" ")}"
64
+ end
64
65
 
65
- def json?(string)
66
- MultiJson.load(string)
67
- true
68
- rescue MultiJson::ParseError
69
- false
66
+ def json?(string)
67
+ MultiJson.load(string)
68
+ true
69
+ rescue MultiJson::ParseError
70
+ false
71
+ end
70
72
  end
71
73
  end
72
74
  end
@@ -4,41 +4,41 @@
4
4
  module Helpers
5
5
  def filter_handler(x = nil)
6
6
  others = %w[license_url license_version license_delay full_text_version full_text_type
7
- award_number award_funder]
7
+ award_number award_funder]
8
8
  if x.nil?
9
9
  nil
10
10
  else
11
11
  x = stringify(x)
12
12
  nn = x.keys.collect(&:to_s)
13
13
  if nn.collect { |w| others.include? w }.any?
14
- nn = nn.collect do |b|
14
+ nn = nn.collect { |b|
15
15
  if others.include? b
16
16
  case b
17
- when 'license_url'
18
- 'license.url'
19
- when 'license_version'
20
- 'license.version'
21
- when 'license_delay'
22
- 'license.delay'
23
- when 'full_text_version'
24
- 'full-text.version'
25
- when 'full_text_type'
26
- 'full-text.type'
27
- when 'award_number'
28
- 'award.number'
29
- when 'award_funder'
30
- 'award.funder'
17
+ when "license_url"
18
+ "license.url"
19
+ when "license_version"
20
+ "license.version"
21
+ when "license_delay"
22
+ "license.delay"
23
+ when "full_text_version"
24
+ "full-text.version"
25
+ when "full_text_type"
26
+ "full-text.type"
27
+ when "award_number"
28
+ "award.number"
29
+ when "award_funder"
30
+ "award.funder"
31
31
  end
32
32
  else
33
33
  b
34
34
  end
35
- end
35
+ }
36
36
  end
37
37
 
38
- newnn = nn.collect { |m| m.tr('_', '-') }
38
+ newnn = nn.collect { |m| m.tr("_", "-") }
39
39
  x = rename_keys(x, newnn)
40
- x = x.collect { |k, v| [k, v].join(':') }.join(',')
41
- x
40
+ x.collect { |k, v| [k, v].join(":") }.join(",")
41
+
42
42
  end
43
43
  end
44
44
 
@@ -52,11 +52,11 @@ module Helpers
52
52
  end
53
53
 
54
54
  module Serrano
55
- class Request #:nodoc:
55
+ class Request # :nodoc:
56
56
  include Helpers
57
57
  end
58
58
 
59
- class RequestCursor #:nodoc:
59
+ class RequestCursor # :nodoc:
60
60
  include Helpers
61
61
  end
62
62
  end