ref2bibtex 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -12
- data/README.md +18 -14
- data/lib/ref2bibtex/version.rb +1 -1
- data/lib/ref2bibtex.rb +82 -36
- data/ref2bibtex.gemspec +2 -2
- data/spec/ref2bibtex_spec.rb +69 -13
- data/spec/support/citations.yml +8 -1
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f7108348cfed966bb638c38ff3b1056bc418ed6
|
4
|
+
data.tar.gz: b6553afe9e23c6a65d5c78a7fdc2d493379fc6ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a14d2e3ee16b6fb7e04cc5c6b7900e0734aceb7548bfd0641f644bcba7e73c364b536c264dedd0df33d221d89ba1dabd36eb345ce1ba7c430c139086a0604811
|
7
|
+
data.tar.gz: d20b75b7ca8d76ffacb1eacb99c037ea99d98d284ceaf86347c530016c263c81dbc887e81020da1ed91c6c8e2d6748bf589a4af7d2f78139c9ac8a6ac7e2d601
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ref2bibtex (0.0
|
4
|
+
ref2bibtex (0.1.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
awesome_print (1.
|
10
|
-
byebug (
|
11
|
-
|
12
|
-
debugger-linecache (~> 1.2)
|
13
|
-
slop (~> 3.6)
|
14
|
-
columnize (0.8.9)
|
15
|
-
debugger-linecache (1.2.0)
|
16
|
-
rake (10.3.2)
|
17
|
-
slop (3.6.0)
|
9
|
+
awesome_print (1.7.0)
|
10
|
+
byebug (9.0.6)
|
11
|
+
rake (12.0.0)
|
18
12
|
|
19
13
|
PLATFORMS
|
20
14
|
ruby
|
@@ -22,6 +16,9 @@ PLATFORMS
|
|
22
16
|
DEPENDENCIES
|
23
17
|
awesome_print
|
24
18
|
bundler (~> 1.6)
|
25
|
-
byebug
|
26
|
-
rake
|
19
|
+
byebug (~> 9.0)
|
20
|
+
rake (~> 12.0)
|
27
21
|
ref2bibtex!
|
22
|
+
|
23
|
+
BUNDLED WITH
|
24
|
+
1.14.6
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
ref2bibtex
|
2
|
-
==========
|
1
|
+
[](https://travis-ci.org/SpeciesFileGroup/ref2bibtex)
|
3
2
|
|
4
|
-
|
3
|
+
# ref2bibtex
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
An (almost) single purpose gem wrapping Crossref's API. Pass it a full reference string, get back bibtex.
|
6
|
+
|
7
|
+
# usage
|
8
8
|
|
9
9
|
Use citation2bibtex (aliased _get_):
|
10
10
|
|
@@ -34,20 +34,24 @@ If you have the doi:
|
|
34
34
|
|
35
35
|
```
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
If you want a score:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
|
41
|
+
Ref2bibtex.get_score('E. Ven. 1337. Fake articles. Journal Get Scores. Hm:mm') # => 23.688715
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
# faq
|
39
46
|
|
40
|
-
What if there are multiple results?
|
41
|
-
-----------------------------------
|
47
|
+
## What if there are multiple results?
|
42
48
|
The code is dumb, it takes the first.
|
43
49
|
|
44
|
-
acknowledgements
|
45
|
-
================
|
50
|
+
# acknowledgements
|
46
51
|
|
47
|
-
The Crossref API
|
52
|
+
The Crossref API. Jon Hill, University of York, for his Python version and bringing up the approach.
|
48
53
|
|
49
|
-
license
|
50
|
-
=======
|
54
|
+
# license
|
51
55
|
|
52
56
|
NCSA, UI flavor. [http://opensource.org/licenses/NCSA]
|
53
57
|
|
data/lib/ref2bibtex/version.rb
CHANGED
data/lib/ref2bibtex.rb
CHANGED
@@ -7,8 +7,25 @@ require 'net/http'
|
|
7
7
|
|
8
8
|
module Ref2bibtex
|
9
9
|
|
10
|
+
# By default sorts by score
|
10
11
|
CROSSREF_URI = URI('http://search.crossref.org/links')
|
11
12
|
|
13
|
+
DEFAULT_CUTOFF = 50
|
14
|
+
|
15
|
+
@@cutoff = DEFAULT_CUTOFF
|
16
|
+
|
17
|
+
def self.cutoff
|
18
|
+
@@cutoff
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.cutoff=(value)
|
22
|
+
@@cutoff = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.reset_cutoff
|
26
|
+
@@cutoff = DEFAULT_CUTOFF
|
27
|
+
end
|
28
|
+
|
12
29
|
# Parse the response into json
|
13
30
|
def self.parse_json(string)
|
14
31
|
begin
|
@@ -26,26 +43,36 @@ module Ref2bibtex
|
|
26
43
|
return false if uri.class == URI::Generic
|
27
44
|
response = Ref2bibtex.request(uri, headers: {'Accept' => 'application/x-bibtex' }, protocol: 'GET', process_response_as: 'text')
|
28
45
|
end
|
29
|
-
|
30
|
-
# Pass a String citation, get a
|
46
|
+
|
47
|
+
# Pass a String citation, get a DOI back
|
31
48
|
def self.get_doi(citation)
|
32
|
-
|
33
|
-
citation = [citation]
|
34
|
-
elsif citation.class != Array
|
35
|
-
raise
|
36
|
-
end
|
37
|
-
|
49
|
+
citation = validate_query(citation)
|
38
50
|
response = Ref2bibtex.request(payload: citation)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
|
52
|
+
return false if !response['results'][0]['match']
|
53
|
+
return false if response['results'][0]['score'] < @@cutoff
|
54
|
+
|
55
|
+
response['results'][0]['doi']
|
56
|
+
end
|
57
|
+
|
58
|
+
# Pass a String citation, get a score back
|
59
|
+
def self.get_score(citation)
|
60
|
+
citation = validate_query(citation)
|
61
|
+
response = Ref2bibtex.request(payload: citation)
|
62
|
+
return false if !response['results'][0]['match']
|
63
|
+
response['results'][0]['score']
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.validate_query(citation)
|
67
|
+
return [citation] if citation.kind_of?(String) && citation.length > 0
|
68
|
+
raise 'citation is not String or Array' if !citation.kind_of?(Array)
|
69
|
+
raise 'citation in array is empty' if citation.empty? || citation.select{|a| a.length == 0}.size > 0
|
70
|
+
citation
|
44
71
|
end
|
45
72
|
|
46
|
-
# Pass a citation, get a String in
|
73
|
+
# Pass a citation, get a String in BibTeX back
|
47
74
|
def self.citation2bibtex(citation)
|
48
|
-
get_bibtex(
|
75
|
+
get_bibtex(get_doi(citation) )
|
49
76
|
end
|
50
77
|
|
51
78
|
class << self
|
@@ -54,47 +81,66 @@ module Ref2bibtex
|
|
54
81
|
|
55
82
|
def self.request(url = CROSSREF_URI, payload: nil, headers: {'content-type' => 'application/json' }, protocol: 'POST', process_response_as: 'json', redirect_limit: 10)
|
56
83
|
raise 'Infinite redirect?' if redirect_limit == 0
|
57
|
-
data = nil
|
58
|
-
if protocol == 'POST'
|
59
|
-
if payload.nil?
|
60
|
-
payload = {}
|
61
|
-
end
|
62
|
-
data = JSON.generate(payload) # Json.new(payload) # utf-8 encoding?
|
63
|
-
else
|
64
|
-
data = nil
|
65
|
-
end
|
66
84
|
|
67
|
-
|
68
|
-
|
69
|
-
elsif protocol == 'GET'
|
70
|
-
request = Net::HTTP::Get.new(url, initheader = headers)
|
71
|
-
end
|
85
|
+
body = request_body(protocol, payload)
|
86
|
+
request = new_request(protocol, url, headers)
|
72
87
|
|
73
|
-
response = Net::HTTP.start(request.uri.hostname, request.uri.port) do |http|
|
74
|
-
request.body =
|
88
|
+
response = Net::HTTP.start(request.uri.hostname, request.uri.port, use_ssl: request.uri.scheme == 'https') do |http|
|
89
|
+
request.body = body
|
75
90
|
http.request(request)
|
76
91
|
end
|
77
92
|
|
78
93
|
case response
|
79
|
-
when Net::HTTPSuccess
|
94
|
+
when Net::HTTPSuccess
|
80
95
|
response = response
|
81
|
-
when Net::HTTPRedirection
|
96
|
+
when Net::HTTPRedirection
|
97
|
+
|
82
98
|
url = URI(response['location'])
|
83
99
|
request = Net::HTTP::Get.new(url, initheader = {'Accept' => 'application/x-bibtex'})
|
84
|
-
|
100
|
+
|
101
|
+
response = Net::HTTP.start(request.uri.hostname, request.uri.port, use_ssl: request.uri.scheme == 'https') do |http|
|
85
102
|
http.request(request)
|
86
103
|
end
|
87
104
|
else
|
88
105
|
response = response.value
|
89
106
|
end
|
90
107
|
|
91
|
-
|
108
|
+
process_response(response, process_response_as)
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
def self.interpret_response(response)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.request_body(protocol, payload)
|
117
|
+
if protocol == 'POST'
|
118
|
+
payload = {} if payload.nil?
|
119
|
+
JSON.generate(payload) # Json.new(payload) # utf-8 encoding?
|
120
|
+
else
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.new_request(protocol, url, headers)
|
126
|
+
case protocol
|
127
|
+
when 'POST'
|
128
|
+
Net::HTTP::Post.new(url, initheader = headers)
|
129
|
+
when 'GET'
|
130
|
+
Net::HTTP::Get.new(url, initheader = headers)
|
131
|
+
else
|
132
|
+
raise 'invalid protocol'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.process_response(response, as)
|
137
|
+
case as
|
92
138
|
when 'text'
|
93
139
|
response.body
|
94
140
|
when 'json'
|
95
141
|
parse_json(response.body)
|
96
142
|
else
|
97
|
-
raise
|
143
|
+
raise 'response process type not provided'
|
98
144
|
end
|
99
145
|
end
|
100
146
|
|
data/ref2bibtex.gemspec
CHANGED
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
-
spec.add_development_dependency "rake"
|
23
|
-
spec.add_development_dependency "byebug"
|
22
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
23
|
+
spec.add_development_dependency "byebug", "~> 9.0"
|
24
24
|
spec.add_development_dependency "awesome_print"
|
25
25
|
|
26
26
|
end
|
data/spec/ref2bibtex_spec.rb
CHANGED
@@ -2,37 +2,37 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Ref2bibtex do
|
4
4
|
|
5
|
-
context '
|
5
|
+
context '.request' do
|
6
6
|
let(:request) { Ref2bibtex.request(payload: [CITATIONS[:first]]) }
|
7
7
|
|
8
|
-
specify '
|
8
|
+
specify 'makes a query_ok request' do
|
9
9
|
expect(request['query_ok']).to eq(true)
|
10
10
|
end
|
11
11
|
|
12
|
-
specify '
|
12
|
+
specify 'returns Hash' do
|
13
13
|
expect(request.class).to eq(Hash)
|
14
14
|
end
|
15
15
|
|
16
|
-
specify '
|
16
|
+
specify 'results is an Array' do
|
17
17
|
expect(request['results'].class).to eq(Array)
|
18
18
|
end
|
19
19
|
|
20
|
-
specify '
|
20
|
+
specify 'results is an Array of Hashes' do
|
21
21
|
expect(request['results'].first.class).to eq(Hash)
|
22
22
|
end
|
23
23
|
|
24
|
-
specify '
|
24
|
+
specify 'results is an Array of Hashes, each one having a doi' do
|
25
25
|
expect(request['results'].first['doi']).to be_truthy
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
context '
|
30
|
-
specify '
|
29
|
+
context '.get_doi' do
|
30
|
+
specify 'takes a full citation and returns a string' do
|
31
31
|
expect(Ref2bibtex.get_doi(CITATIONS[:first])).to eq('http://dx.doi.org/10.3897/zookeys.20.205')
|
32
32
|
end
|
33
33
|
|
34
34
|
specify 'a citation that can not be resolved returns false' do
|
35
|
-
expect(Ref2bibtex.get_doi(CITATIONS[:
|
35
|
+
expect(Ref2bibtex.get_doi(CITATIONS[:eighth])).to eq(false)
|
36
36
|
end
|
37
37
|
|
38
38
|
specify 'a badly formed DOI returns false' do
|
@@ -40,9 +40,9 @@ describe Ref2bibtex do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
context '
|
43
|
+
context '.get_bibtex' do
|
44
44
|
let(:response) { Ref2bibtex.get_bibtex('http://dx.doi.org/10.3897/zookeys.20.205')}
|
45
|
-
specify '
|
45
|
+
specify 'takes a full citation and returns bibtex' do
|
46
46
|
expect(response).to match(/author\s=/)
|
47
47
|
expect(response).to match(/title\s=/)
|
48
48
|
expect(response).to match(/year\s=\s2009/)
|
@@ -53,8 +53,64 @@ describe Ref2bibtex do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
specify "a citation that can not be resolved returns false" do
|
57
|
-
expect(Ref2bibtex.get(CITATIONS[:
|
56
|
+
specify "a citation that can not be resolved returns false from .get" do
|
57
|
+
expect(Ref2bibtex.get(CITATIONS[:eighth])).to eq(false)
|
58
58
|
end
|
59
59
|
|
60
|
+
context 'score' do
|
61
|
+
specify 'can be returned with .get_score' do
|
62
|
+
expect(Ref2bibtex.get_score(CITATIONS[:first])).to be > 0
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'interpretation' do
|
66
|
+
before(:all) {
|
67
|
+
@scores = CITATIONS.keys.inject({}) { |hsh, c|
|
68
|
+
hsh.merge!(
|
69
|
+
c => Ref2bibtex.get_score(CITATIONS[c])
|
70
|
+
)
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
specify 'mangled text is worse than good text' do
|
75
|
+
expect( @scores[:second] > @scores[:seventh] ).to be_truthy
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'default @@cutoff is reasonable and slightly conservative' do
|
79
|
+
let(:good_citations) { [:first, :second, :third, :fourth, :sixth] }
|
80
|
+
let(:bad_citations) { CITATIONS.keys - good_citations }
|
81
|
+
|
82
|
+
specify 'for good citations' do
|
83
|
+
good_citations.each do |c|
|
84
|
+
expect(@scores[c]).to be > Ref2bibtex.cutoff
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
specify 'for bad citations' do
|
89
|
+
bad_citations.each do |c|
|
90
|
+
if @scores[c]
|
91
|
+
expect(@scores[c]).to be < Ref2bibtex.cutoff
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'cutoff' do
|
99
|
+
after(:all) {
|
100
|
+
Ref2bibtex.reset_cutoff
|
101
|
+
}
|
102
|
+
|
103
|
+
specify 'can be used to reject good matches' do
|
104
|
+
Ref2bibtex.cutoff = 1000
|
105
|
+
expect(Ref2bibtex.get_doi(CITATIONS[:first])).to eq(false)
|
106
|
+
end
|
107
|
+
|
108
|
+
specify 'can be used to accept bad matches' do
|
109
|
+
Ref2bibtex.cutoff = 1
|
110
|
+
expect(Ref2bibtex.get_doi(CITATIONS[:fifth])).to be_truthy
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
60
116
|
end
|
data/spec/support/citations.yml
CHANGED
@@ -8,4 +8,11 @@
|
|
8
8
|
:fourth:
|
9
9
|
"Otte, D. 1994. Crickets (Grylloidea). Orthoptera Species File, The Orthopterists' Society and The Academy of Natural Sciences of Philadelphia, Philadelphia 1:87"
|
10
10
|
:fifth:
|
11
|
-
"
|
11
|
+
"Iam, F.K. 1337. Let's go Crossref, give me a DOI for this fake reference in my unit test, I dare you. Journal of Examples for Unit tests. 13:37"
|
12
|
+
:sixth:
|
13
|
+
"Simon, E. (1879b) Les Arachnides de France. Tome 7. Contenant les ordres des Chernetes, Scorpiones et Opiliones. Librairie Encyclopédique de Roret, Paris, pp. 1–332, pl. 17–24. "
|
14
|
+
:seventh:
|
15
|
+
'Jaost & K.P. Shuw. 2007. Phyloguny of Ensifere (Hesapoda: Prthoptera) usine threa rubosomal toci, wuth implocations far teh evolushun off acoustik commmunication. Tolecular Fylogenetics & Evolotion (Mul. Phylagenet. Evil.) 39:509-528'
|
16
|
+
:eighth:
|
17
|
+
'Only two'
|
18
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ref2bibtex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Yoder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,30 +28,30 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '12.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '12.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: byebug
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '9.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '9.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: awesome_print
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
version: '0'
|
107
107
|
requirements: []
|
108
108
|
rubyforge_project:
|
109
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.6.12
|
110
110
|
signing_key:
|
111
111
|
specification_version: 4
|
112
112
|
summary: Pass a full citation, get the bibtex back, that's all.
|