serrano 0.3.6 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +28 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +50 -0
- data/.rubocop_todo.yml +105 -0
- data/CHANGELOG.md +33 -0
- data/{CONDUCT.md → CODE_OF_CONDUCT.md} +2 -2
- data/Gemfile +2 -0
- data/Gemfile.lock +56 -38
- data/LICENSE +1 -1
- data/README.md +35 -7
- data/Rakefile +26 -18
- data/bin/serrano +96 -98
- data/lib/serrano.rb +194 -77
- data/lib/serrano/cn.rb +7 -9
- data/lib/serrano/cnrequest.rb +42 -28
- data/lib/serrano/error.rb +2 -0
- data/lib/serrano/faraday.rb +15 -14
- data/lib/serrano/filterhandler.rb +13 -15
- data/lib/serrano/filters.rb +91 -78
- data/lib/serrano/helpers/configuration.rb +2 -2
- data/lib/serrano/request.rb +46 -39
- data/lib/serrano/request_cursor.rb +66 -59
- data/lib/serrano/styles.rb +14 -9
- data/lib/serrano/utils.rb +21 -14
- data/lib/serrano/version.rb +3 -1
- data/serrano.gemspec +33 -20
- metadata +87 -69
- data/.travis.yml +0 -8
- data/lib/serrano/constants.rb +0 -36
- data/lib/serrano/cursor_testing.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 53cd7acc47b07971aa23568ba4abb703eb1f7ac4d73483c9b74efc97e9245234
|
4
|
+
data.tar.gz: 6307728ec83729a96377ac3a3b7a1c3642f19b746e7eb1d69e6805e9cfbe3d47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b322cef9465854069679385525b296b9cdfcdba1b8b2b3b1a831bbeabc4e4b77f3686845619898d8809e02bf0079cebe23c9eb1c95908eeaa7df4b4de80d1a03
|
7
|
+
data.tar.gz: f511e386ab6c92b1e3f7984de2ca6e044fac87e7d824b7f8360c3165b7e9d7591b5d93b5af283f3c0e128c1a301146a7e8aedf5777ed9ceac5e34f4cd1e898ee
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
strategy:
|
12
|
+
fail-fast: false
|
13
|
+
matrix:
|
14
|
+
os: [ ubuntu-latest, macos-latest ]
|
15
|
+
ruby: [ 2.5, 2.6, 2.7 ]
|
16
|
+
runs-on: ${{ matrix.os }}
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- name: Setup Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby }}
|
23
|
+
- name: Install dependencies
|
24
|
+
run: bundle install
|
25
|
+
- name: Run tests
|
26
|
+
run: bundle exec rake test TESTOPTS="-v"
|
27
|
+
- name: Run rubocop
|
28
|
+
run: bundle exec rubocop
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
Naming/FileName:
|
4
|
+
Exclude:
|
5
|
+
- 'test/test-helper.rb'
|
6
|
+
|
7
|
+
Metrics/ParameterLists:
|
8
|
+
Max: 18
|
9
|
+
|
10
|
+
Metrics/ModuleLength:
|
11
|
+
Max: 800
|
12
|
+
|
13
|
+
# Offense count: 22
|
14
|
+
# Configuration parameters: AllowedVariables.
|
15
|
+
Lint/UselessAssignment:
|
16
|
+
Exclude:
|
17
|
+
- 'lib/serrano/filters.rb'
|
18
|
+
|
19
|
+
Lint/RaiseException:
|
20
|
+
Enabled: true
|
21
|
+
|
22
|
+
Lint/StructNewOverride:
|
23
|
+
Enabled: true
|
24
|
+
|
25
|
+
Style/HashEachMethods:
|
26
|
+
Enabled: true
|
27
|
+
|
28
|
+
Style/HashTransformKeys:
|
29
|
+
Enabled: true
|
30
|
+
|
31
|
+
Style/HashTransformValues:
|
32
|
+
Enabled: true
|
33
|
+
|
34
|
+
Layout/LineLength:
|
35
|
+
Max: 525
|
36
|
+
|
37
|
+
Layout/SpaceAroundMethodCallOperator:
|
38
|
+
Enabled: true
|
39
|
+
|
40
|
+
Style/ExponentialNotation:
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
44
|
+
Enabled: true
|
45
|
+
|
46
|
+
Style/SlicingWithRange:
|
47
|
+
Enabled: true
|
48
|
+
|
49
|
+
Lint/DeprecatedOpenSSLConstant:
|
50
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2020-02-18 08:24:37 -0800 using RuboCop version 0.80.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: Include.
|
11
|
+
# Include: **/*.gemspec
|
12
|
+
Gemspec/RequiredRubyVersion:
|
13
|
+
Exclude:
|
14
|
+
- 'serrano.gemspec'
|
15
|
+
|
16
|
+
# Offense count: 32
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Max: 91
|
19
|
+
|
20
|
+
# Offense count: 1
|
21
|
+
# Configuration parameters: CountBlocks.
|
22
|
+
Metrics/BlockNesting:
|
23
|
+
Max: 4
|
24
|
+
|
25
|
+
# Offense count: 2
|
26
|
+
# Configuration parameters: CountComments.
|
27
|
+
Metrics/ClassLength:
|
28
|
+
Max: 367
|
29
|
+
|
30
|
+
# Offense count: 5
|
31
|
+
Metrics/CyclomaticComplexity:
|
32
|
+
Max: 11
|
33
|
+
|
34
|
+
# Offense count: 21
|
35
|
+
# Configuration parameters: CountComments, ExcludedMethods.
|
36
|
+
Metrics/MethodLength:
|
37
|
+
Max: 54
|
38
|
+
|
39
|
+
# Offense count: 8
|
40
|
+
Metrics/PerceivedComplexity:
|
41
|
+
Max: 15
|
42
|
+
|
43
|
+
# Offense count: 7
|
44
|
+
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
45
|
+
# AllowedNames: io, id, to, by, on, in, at, ip, db, os, pp
|
46
|
+
Naming/MethodParameterName:
|
47
|
+
Exclude:
|
48
|
+
- 'lib/serrano/filterhandler.rb'
|
49
|
+
- 'lib/serrano/request_cursor.rb'
|
50
|
+
- 'lib/serrano/utils.rb'
|
51
|
+
|
52
|
+
# Offense count: 3
|
53
|
+
# Cop supports --auto-correct.
|
54
|
+
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
55
|
+
# SupportedStyles: assign_to_condition, assign_inside_condition
|
56
|
+
Style/ConditionalAssignment:
|
57
|
+
Exclude:
|
58
|
+
- 'bin/serrano'
|
59
|
+
|
60
|
+
# Offense count: 6
|
61
|
+
Style/Documentation:
|
62
|
+
Exclude:
|
63
|
+
- 'spec/**/*'
|
64
|
+
- 'test/**/*'
|
65
|
+
- 'bin/serrano'
|
66
|
+
- 'lib/serrano.rb'
|
67
|
+
- 'lib/serrano/cn.rb'
|
68
|
+
- 'lib/serrano/filters.rb'
|
69
|
+
- 'lib/serrano/utils.rb'
|
70
|
+
|
71
|
+
# Offense count: 1
|
72
|
+
# Cop supports --auto-correct.
|
73
|
+
# Configuration parameters: EnforcedStyle.
|
74
|
+
# SupportedStyles: format, sprintf, percent
|
75
|
+
Style/FormatString:
|
76
|
+
Exclude:
|
77
|
+
- 'lib/serrano/utils.rb'
|
78
|
+
|
79
|
+
# Offense count: 1
|
80
|
+
# Configuration parameters: EnforcedStyle.
|
81
|
+
# SupportedStyles: annotated, template, unannotated
|
82
|
+
Style/FormatStringToken:
|
83
|
+
Exclude:
|
84
|
+
- 'lib/serrano/utils.rb'
|
85
|
+
|
86
|
+
# Offense count: 3
|
87
|
+
# Cop supports --auto-correct.
|
88
|
+
Style/IfUnlessModifier:
|
89
|
+
Exclude:
|
90
|
+
- 'lib/serrano/cnrequest.rb'
|
91
|
+
- 'lib/serrano/utils.rb'
|
92
|
+
|
93
|
+
# Offense count: 1
|
94
|
+
# Cop supports --auto-correct.
|
95
|
+
Style/SelfAssignment:
|
96
|
+
Exclude:
|
97
|
+
- 'lib/serrano/utils.rb'
|
98
|
+
|
99
|
+
# Offense count: 1
|
100
|
+
# Cop supports --auto-correct.
|
101
|
+
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
|
102
|
+
# SupportedStyles: single_quotes, double_quotes
|
103
|
+
Style/StringLiterals:
|
104
|
+
Exclude:
|
105
|
+
- 'lib/serrano/utils.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
## 0.6.2 (2020-05-29)
|
2
|
+
|
3
|
+
* put documentation link back in rubygems page (#132)
|
4
|
+
|
5
|
+
## 0.6.0 (2020-02-18)
|
6
|
+
|
7
|
+
* query.title (`query_title` query filter as used here) has been removed; use `query_bibliographic` instead (#111)
|
8
|
+
* bump `faraday` to version 0.17.1 from 0.17.0 (via dependabot) (#107)
|
9
|
+
* bump `json` to version 2.3 from 2.2 (via dependabot) (#109)
|
10
|
+
* bump `thor` minimum version (via dependabot) (#110)
|
11
|
+
* better checking of filters; always check filters for proper formatting and acceptable types; improve filter tests; link to information on filters (#105) via PR from @beechnut
|
12
|
+
|
13
|
+
## 0.5.4 (2019-11-27)
|
14
|
+
|
15
|
+
* `Serrano.registration_agency` fixed: a change in an internal function caused this function to fail; tests added to prevent this in the future (#106)
|
16
|
+
* bundle update, changes in gemfile.lock
|
17
|
+
|
18
|
+
## 0.5.2 (2019-08-07)
|
19
|
+
|
20
|
+
* fix url encoding (#51)
|
21
|
+
* started using Rubocop; many styling changes (#52)
|
22
|
+
|
23
|
+
## 0.5.0 (2018-04-08)
|
24
|
+
|
25
|
+
* Updated dependency versions
|
26
|
+
* Change url used in content negotation from `http://dx.doi.org/` to `https://doi.org/` (#49)
|
27
|
+
* Fix `cursor_max` parameter type check to avoid Fixnum warning (#50)
|
28
|
+
* Add support for `mailto` email polite pool, and docs updated with info (#46) (#47)
|
29
|
+
* Add select parameter throughout methods (#43)
|
30
|
+
* Added additional filter options (#45) (#40)
|
31
|
+
* Added to docs info about additional `sort` parameter options (#41)
|
32
|
+
* Added to docs info about additional field query options (#42)
|
33
|
+
|
1
34
|
## 0.3.6 (2017-04-04)
|
2
35
|
|
3
36
|
* Updated dependency versions
|
@@ -21,5 +21,5 @@ Instances of abusive, harassing, or otherwise unacceptable behavior may be repor
|
|
21
21
|
opening an issue or contacting one or more of the project maintainers.
|
22
22
|
|
23
23
|
This Code of Conduct is adapted from the Contributor Covenant
|
24
|
-
(
|
25
|
-
|
24
|
+
(https://contributor-covenant.org), version 1.0.0, available at
|
25
|
+
https://contributor-covenant.org/version/1/0/0/
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,64 +1,82 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
serrano (0.
|
5
|
-
faraday (~> 0.
|
6
|
-
faraday_middleware (~>
|
7
|
-
multi_json (~> 1.
|
8
|
-
thor (
|
4
|
+
serrano (0.6.2)
|
5
|
+
faraday (~> 1.0, >= 1.0.1)
|
6
|
+
faraday_middleware (~> 1.0)
|
7
|
+
multi_json (~> 1.13, >= 1.13.1)
|
8
|
+
thor (>= 0.20, < 1.1)
|
9
9
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
addressable (2.
|
14
|
-
public_suffix (
|
15
|
-
|
13
|
+
addressable (2.7.0)
|
14
|
+
public_suffix (>= 2.0.2, < 5.0)
|
15
|
+
ast (2.4.0)
|
16
|
+
codecov (0.1.16)
|
16
17
|
json
|
17
18
|
simplecov
|
18
19
|
url
|
19
20
|
crack (0.4.3)
|
20
21
|
safe_yaml (~> 1.0.0)
|
21
|
-
docile (1.
|
22
|
-
faraday (
|
22
|
+
docile (1.3.2)
|
23
|
+
faraday (1.0.1)
|
23
24
|
multipart-post (>= 1.2, < 3)
|
24
|
-
faraday_middleware (0.
|
25
|
-
faraday (
|
26
|
-
hashdiff (0.
|
27
|
-
json (2.0
|
28
|
-
multi_json (1.
|
29
|
-
multipart-post (2.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
25
|
+
faraday_middleware (1.0.0)
|
26
|
+
faraday (~> 1.0)
|
27
|
+
hashdiff (1.0.1)
|
28
|
+
json (2.3.0)
|
29
|
+
multi_json (1.14.1)
|
30
|
+
multipart-post (2.1.1)
|
31
|
+
parallel (1.19.1)
|
32
|
+
parser (2.7.1.2)
|
33
|
+
ast (~> 2.4.0)
|
34
|
+
power_assert (1.1.7)
|
35
|
+
public_suffix (4.0.4)
|
36
|
+
rainbow (3.0.0)
|
37
|
+
rake (13.0.1)
|
38
|
+
rexml (3.2.4)
|
39
|
+
rubocop (0.84.0)
|
40
|
+
parallel (~> 1.10)
|
41
|
+
parser (>= 2.7.0.1)
|
42
|
+
rainbow (>= 2.2.2, < 4.0)
|
43
|
+
rexml
|
44
|
+
rubocop-ast (>= 0.0.3)
|
45
|
+
ruby-progressbar (~> 1.7)
|
46
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
47
|
+
rubocop-ast (0.0.3)
|
48
|
+
parser (>= 2.7.0.1)
|
49
|
+
ruby-progressbar (1.10.1)
|
50
|
+
safe_yaml (1.0.5)
|
51
|
+
simplecov (0.18.5)
|
52
|
+
docile (~> 1.1)
|
53
|
+
simplecov-html (~> 0.11)
|
54
|
+
simplecov-html (0.12.2)
|
55
|
+
test-unit (3.3.5)
|
40
56
|
power_assert
|
41
|
-
thor (0.
|
57
|
+
thor (1.0.1)
|
58
|
+
unicode-display_width (1.7.0)
|
42
59
|
url (0.3.2)
|
43
|
-
vcr (
|
44
|
-
webmock (
|
60
|
+
vcr (6.0.0)
|
61
|
+
webmock (3.8.3)
|
45
62
|
addressable (>= 2.3.6)
|
46
63
|
crack (>= 0.3.2)
|
47
|
-
hashdiff
|
64
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
48
65
|
|
49
66
|
PLATFORMS
|
50
67
|
ruby
|
51
68
|
|
52
69
|
DEPENDENCIES
|
53
|
-
bundler (~>
|
70
|
+
bundler (~> 2.0, >= 2.0.2)
|
54
71
|
codecov (~> 0.1.10)
|
55
|
-
json (~> 2.
|
56
|
-
rake (~>
|
72
|
+
json (~> 2.1)
|
73
|
+
rake (~> 13.0, >= 12.3.1)
|
74
|
+
rubocop (~> 0.84.0)
|
57
75
|
serrano!
|
58
|
-
simplecov (~> 0.
|
59
|
-
test-unit (~> 3.2, >= 3.2.
|
60
|
-
vcr (~>
|
61
|
-
webmock (~>
|
76
|
+
simplecov (~> 0.18.5)
|
77
|
+
test-unit (~> 3.2, >= 3.2.7)
|
78
|
+
vcr (~> 6.0)
|
79
|
+
webmock (~> 3.4, >= 3.4.1)
|
62
80
|
|
63
81
|
BUNDLED WITH
|
64
|
-
1.
|
82
|
+
2.1.4
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (C)
|
1
|
+
Copyright (C) 2020 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,8 +2,8 @@ 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=master)](https://codecov.io/github/sckott/serrano?branch=master)
|
7
7
|
[![DOI](https://zenodo.org/badge/2600/sckott/serrano.svg)](https://zenodo.org/badge/latestdoi/2600/sckott/serrano)
|
8
8
|
|
9
9
|
`serrano` is a low level client for Crossref APIs
|
@@ -15,6 +15,8 @@ Other Crossref API clients:
|
|
15
15
|
- Python: [habanero](https://github.com/sckott/habanero)
|
16
16
|
- R: [rcrossref](https://github.com/ropensci/rcrossref)
|
17
17
|
|
18
|
+
Crossref's API issue tracker: https://gitlab.com/crossref/issues
|
19
|
+
|
18
20
|
## Changes
|
19
21
|
|
20
22
|
For changes see the [Changelog][changelog]
|
@@ -44,7 +46,7 @@ Other methods:
|
|
44
46
|
|
45
47
|
Note about searching:
|
46
48
|
|
47
|
-
You are using the Crossref search API described at https://github.com/CrossRef/rest-api-doc
|
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
|
48
50
|
|
49
51
|
Rate limits:
|
50
52
|
|
@@ -54,6 +56,16 @@ limit is 50 requests per second. Look for the headers `X-Rate-Limit-Limit`
|
|
54
56
|
and `X-Rate-Limit-Interval` in requests to see what the current rate
|
55
57
|
limits are.
|
56
58
|
|
59
|
+
The Polite Pool:
|
60
|
+
|
61
|
+
To get in the polite pool it's a good idea now to include a `mailto` email
|
62
|
+
address. See docs for more information. TLDR: set your email in an env var `CROSSREF_EMAIL`.
|
63
|
+
|
64
|
+
|
65
|
+
URL Encoding:
|
66
|
+
|
67
|
+
We do URL encoding of DOIs for you for all methods except `Serrano.citation_count` which doesn't work if you encode DOIs beforehand. We use `ERB::Util.url_encode` to encode.
|
68
|
+
|
57
69
|
|
58
70
|
## Install
|
59
71
|
|
@@ -79,10 +91,20 @@ This will also be the way to set up other user options, as needed down the road.
|
|
79
91
|
|
80
92
|
```ruby
|
81
93
|
Serrano.configuration do |config|
|
82
|
-
config.base_url = "
|
94
|
+
config.base_url = "https://api.crossref.org"
|
83
95
|
end
|
84
96
|
```
|
85
97
|
|
98
|
+
We recommend you set your `mailto` email here so you can get in the "polite pool" which gives you faster rate limits:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Serrano.configuration do |config|
|
102
|
+
config.mailto = "jane@doe.org"
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Or use an env var with name `CROSSREF_EMAIL`
|
107
|
+
|
86
108
|
## Examples
|
87
109
|
|
88
110
|
### Use in a Ruby repl
|
@@ -100,6 +122,12 @@ Search works by query string
|
|
100
122
|
Serrano.works(query: "ecology")
|
101
123
|
```
|
102
124
|
|
125
|
+
Search works using metadata filters. See [CrossRef filter docs](https://github.com/CrossRef/rest-api-doc#filter-names).
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Serrano.works(query: "ecology", filter: { has_abstract: true })
|
129
|
+
```
|
130
|
+
|
103
131
|
Search journals by publisher name
|
104
132
|
|
105
133
|
```ruby
|
@@ -166,8 +194,8 @@ Commands:
|
|
166
194
|
* License: MIT
|
167
195
|
|
168
196
|
[crapi]: https://github.com/CrossRef/rest-api-doc/blob/master/rest_api.md
|
169
|
-
[cn]:
|
170
|
-
[tdm]:
|
171
|
-
[ccount]:
|
197
|
+
[cn]: https://citation.crosscite.org/docs.html
|
198
|
+
[tdm]: https://www.crossref.org/education/retrieve-metadata/rest-api/text-and-data-mining/
|
199
|
+
[ccount]: https://labs.crossref.org/openurl/
|
172
200
|
[csl]: https://github.com/citation-style-language/styles
|
173
201
|
[changelog]: https://github.com/sckott/serrano/blob/master/CHANGELOG.md
|