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 +4 -4
- data/.github/dependabot.yml +22 -0
- data/.github/workflows/ruby.yml +30 -0
- data/.gitignore +1 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +11 -9
- data/Rakefile +22 -20
- data/lib/serrano/cn.rb +4 -4
- data/lib/serrano/cnrequest.rb +34 -48
- data/lib/serrano/faraday.rb +55 -53
- data/lib/serrano/filterhandler.rb +22 -22
- data/lib/serrano/filters.rb +67 -67
- data/lib/serrano/request.rb +29 -32
- data/lib/serrano/request_cursor.rb +48 -52
- data/lib/serrano/styles.rb +17 -17
- data/lib/serrano/utils.rb +8 -9
- data/lib/serrano/version.rb +1 -1
- data/lib/serrano.rb +69 -73
- data/serrano.gemspec +34 -33
- metadata +76 -75
- data/.rubocop.yml +0 -30
- data/.rubocop_todo.yml +0 -105
- data/.travis.yml +0 -11
- data/Gemfile.lock +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cfcf7f23380a97af986d90644b8ab541f89c14e5df46485ad84fbcff437a361
|
4
|
+
data.tar.gz: ff3571fbbe79b62cb203e54887c09a0f5af81838a7e0e7aec8c2cb3fa1376890
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
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
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (C)
|
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
|
-
[![
|
6
|
-
[![codecov.io](
|
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:
|
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://
|
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://
|
197
|
-
[cn]:
|
198
|
-
[
|
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/
|
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
|
4
|
-
require
|
5
|
-
require
|
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 <<
|
9
|
-
t.test_files = FileList[
|
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
|
15
|
+
desc "Run tests"
|
15
16
|
task default: :test
|
16
17
|
|
17
|
-
|
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
|
20
|
+
system "yardoc"
|
24
21
|
end
|
25
22
|
|
26
|
-
desc
|
23
|
+
desc "bundle install"
|
27
24
|
task :bundle do
|
28
|
-
system
|
25
|
+
system "bundle install"
|
29
26
|
end
|
30
27
|
|
31
|
-
desc
|
28
|
+
desc "clean out builds"
|
32
29
|
task :clean do
|
33
|
-
system
|
30
|
+
system "ls | grep [0-9].gem | xargs rm"
|
34
31
|
end
|
35
32
|
|
36
|
-
desc
|
33
|
+
desc "Build serrano"
|
37
34
|
task :build do
|
38
|
-
system
|
35
|
+
system "gem build serrano.gemspec"
|
39
36
|
end
|
40
37
|
|
41
|
-
desc
|
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
|
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
|
4
|
-
require
|
3
|
+
require "serrano/version"
|
4
|
+
require "serrano/cnrequest"
|
5
5
|
|
6
6
|
##
|
7
7
|
# ContentNegotiation - Content Negotiation class
|
8
8
|
#
|
9
|
-
# @see
|
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 =
|
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
|
data/lib/serrano/cnrequest.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
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 = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
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
|
-
|
34
|
-
|
35
|
-
|
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
|
46
|
+
raise "format not one of accepted types"
|
47
47
|
end
|
48
48
|
|
49
|
-
conn = Faraday.new
|
50
|
-
c.use
|
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.
|
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 ==
|
72
|
-
endpt =
|
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[
|
75
|
+
cr_works.headers["X-USER-AGENT"] = make_ua
|
76
76
|
res = cr_works.get
|
77
77
|
else
|
78
|
-
if format ==
|
79
|
-
type = type +
|
78
|
+
if format == "text"
|
79
|
+
type = type + "; style = " + style + "; locale = " + locale
|
80
80
|
end
|
81
81
|
|
82
|
-
res = conn.get
|
82
|
+
res = conn.get { |req|
|
83
83
|
req.url ids
|
84
|
-
req.headers[
|
84
|
+
req.headers["Accept"] = type
|
85
85
|
req.headers[:user_agent] = make_ua
|
86
|
-
req.headers[
|
87
|
-
|
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
|
-
# }
|
data/lib/serrano/faraday.rb
CHANGED
@@ -1,72 +1,74 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "faraday"
|
4
|
+
require "multi_json"
|
5
5
|
|
6
6
|
# @private
|
7
|
-
module
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
def initialize(app)
|
31
|
+
super app
|
32
|
+
@parser = nil
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
+
private
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
if body.nil?
|
56
|
+
nil
|
57
|
+
else
|
58
|
+
": #{body}"
|
59
|
+
end
|
58
60
|
end
|
59
|
-
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
14
|
+
nn = nn.collect { |b|
|
15
15
|
if others.include? b
|
16
16
|
case b
|
17
|
-
when
|
18
|
-
|
19
|
-
when
|
20
|
-
|
21
|
-
when
|
22
|
-
|
23
|
-
when
|
24
|
-
|
25
|
-
when
|
26
|
-
|
27
|
-
when
|
28
|
-
|
29
|
-
when
|
30
|
-
|
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
|
-
|
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
|
41
|
-
|
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
|
55
|
+
class Request # :nodoc:
|
56
56
|
include Helpers
|
57
57
|
end
|
58
58
|
|
59
|
-
class RequestCursor
|
59
|
+
class RequestCursor # :nodoc:
|
60
60
|
include Helpers
|
61
61
|
end
|
62
62
|
end
|