libdoi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 43fa380332a5eb90e5256f97fa57eaf92dcb96fd
4
+ data.tar.gz: 3e2298e22fb298f9e7ebc787fb2e064ed8e9b570
5
+ SHA512:
6
+ metadata.gz: e504fdb335e4856b1b0cdd9eda88ac46e31e8fcf1d41f281a8aca18148586fa0061b95aa098feae3bd6aeb97fdef6929770c3615ddb441dd1a266dc983944762
7
+ data.tar.gz: b20963646458837690fd9e39cba33a17a44d0e0c881152c35c5fbf03e6fff752c1284e4759b5f434b397799a8e10f68bdc5830483c92c717846614e364250ced
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+ require 'uri'
5
+
6
+ class DOI
7
+
8
+ VERSION = '1.0.0'
9
+
10
+ def initialize dir, reg, dss #:nodoc:
11
+ @dir = dir
12
+ @reg = reg
13
+ @dss = dss
14
+ end
15
+ attr_reader :dir, :reg, :dss
16
+
17
+ ##
18
+ # Concatenation--Returns a new DOI containing +other+ concatenated to this DOI's suffix string.
19
+ #
20
+ def + other
21
+ self.class.new @dir, @reg, @dss + other.to_s
22
+ end
23
+
24
+ ##
25
+ # Append--Concatenates the given object to this DOI's suffix string.
26
+ #
27
+ def << other
28
+ @dss << other.to_s
29
+ self
30
+ end
31
+
32
+ ##
33
+ # Returns a String that represents this DOI.
34
+ #
35
+ # * prefix: Prepends 'doi:' to the returned string.
36
+ #
37
+ def to_s prefix: true
38
+ (prefix ? 'doi:' : '') + "#{@dir}.#{@reg}/#{@dss}"
39
+ end
40
+
41
+ ##
42
+ # Returns a URI.
43
+ #
44
+ # For example: "https://doi.org/10.1000/foo%23bar"
45
+ #
46
+ # * info: Returns an 'info:' URI instead of 'https:'
47
+ #
48
+ def to_uri info: false
49
+ if info
50
+ URI(_info_uri)
51
+ else
52
+ URI(_http_url)
53
+ end
54
+ end
55
+
56
+ class <<self
57
+ ##
58
+ # Parses the given string as a DOI.
59
+ #
60
+ # Raises an ArgumentError if parsing fails.
61
+ #
62
+ def parse str
63
+ str = "#{str}"
64
+ if str =~ %r[^https?://(?:(?:dx\.)?doi\.org|doi\.acm\.org|doi\.ieeecomputersociety\.org)/+(?:doi:)?(.*)]i
65
+ # It looks like a HTTP proxy URL.
66
+ doi = CGI.unescape $1
67
+ elsif str =~ %r[^info:doi/(.*)]i
68
+ # It looks like an info URI.
69
+ doi = CGI.unescape $1
70
+ else
71
+ # It's probably a DOI string.
72
+ doi = str.sub %r[^doi:\s*]i, ''
73
+ end
74
+
75
+ # ANSI/NISO Z39.84-2005
76
+ # <http://www.niso.org/apps/group_public/download.php/6587/Syntax%20for%20the%20Digital%20Object%20Identifier.pdf>
77
+ if doi =~ %r[^(10)\.([^/]+)/(\p{Graph}(?:[^/]\p{Graph}*)?)$]
78
+ # FIXME: $2 and $3 may contain characters outside of /\p{Graph}/
79
+ new $1, $2, $3
80
+ else
81
+ raise ArgumentError, "'#{str}' is not a valid DOI string";
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ InfoURI = 'info:doi/'.freeze
89
+ HTTPURI = 'https://doi.org/'.freeze
90
+
91
+ # Returns a percent-encoded "dir.reg/dss" string.
92
+ def _uri_path
93
+ "#{@dir}.#{CGI.escape @reg}/#{CGI.escape @dss}"
94
+ end
95
+
96
+ # Returns an "info:doi/..." URI string.
97
+ def _info_uri
98
+ InfoURI + _uri_path
99
+ end
100
+
101
+ # Returns a "https://doi.org/..." URI string.
102
+ def _http_url
103
+ HTTPURI + _uri_path
104
+ end
105
+
106
+ end
107
+
108
+
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../libdoi'
4
+
5
+ require 'net/http'
6
+ require 'json'
7
+
8
+ class DOI
9
+
10
+ ##
11
+ # Looks for a DOI at doi.org.
12
+ #
13
+ # Returns a URI if it finds a match, otherwise returns nil.
14
+ #
15
+ def find
16
+ _http_get(self.to_uri) do |response|
17
+ # FIXME: this is both presumptuous and intolerant
18
+ loc = response['Location']
19
+ return URI(loc) if loc
20
+ end
21
+ nil
22
+ end
23
+
24
+ ##
25
+ # Gets data about this DOI from CrossRef.
26
+ #
27
+ def data
28
+ uri = URI(_data_url)
29
+ _http_get(uri, 'Accept'=>JSON_Type) do |response|
30
+ return JSON.parse(response.body) if response.code.to_i == 200
31
+ end
32
+ nil
33
+ end
34
+
35
+ class <<self
36
+ ##
37
+ # Looks for a DOI at doi.org.
38
+ #
39
+ # Returns a URI if it finds a match, otherwise returns nil.
40
+ #
41
+ def find doi
42
+ doi = parse(doi) unless doi.is_a? DOI
43
+ doi.find
44
+ end
45
+
46
+ ##
47
+ # Gets data about a DOI from CrossRef.
48
+ #
49
+ def data doi
50
+ doi = parse(doi) unless doi.is_a? DOI
51
+ doi.data
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ JSON_Type = 'application/vnd.citationstyles.csl+json'.freeze
58
+ UAString = "ruby/#{::RUBY_VERSION} libdoi/#{DOI::VERSION}".freeze
59
+ CrossRefURL = 'https://data.crossref.org/'.freeze
60
+
61
+ def _http_get uri, opts={}, &block
62
+ Net::HTTP.start(uri.host, uri.port,
63
+ :use_ssl=>uri.is_a?(URI::HTTPS),
64
+ ) do |http|
65
+ query = Net::HTTP::Get.new uri, 'Accept-Encoding'=>''
66
+ query['Connection'] = 'close'
67
+ query['User-Agent'] = UAString
68
+ opts.each_pair {|k,v| query[k] = v }
69
+ http.request query, &block
70
+ end
71
+ end
72
+
73
+ # Returns a data.crossref.org URI string.
74
+ def _data_url
75
+ CrossRefURL + _uri_path
76
+ end
77
+
78
+ end
79
+
80
+
@@ -0,0 +1,36 @@
1
+ require 'test/unit'
2
+ require 'uri'
3
+ $VERBOSE = true
4
+
5
+ require_relative '../lib/libdoi/network'
6
+ class Test_libdoi_network < Test::Unit::TestCase
7
+ STRING = '10.17487/RFC8089'.freeze
8
+
9
+ URL = URI('https://www.rfc-editor.org/info/rfc8089')
10
+
11
+ FAMILY = 'Kerwin'.freeze
12
+ TITLE = 'The "file" URI Scheme'.freeze
13
+
14
+ def test_find
15
+ doi = DOI.parse STRING
16
+ url = doi.find
17
+ assert_equal( url, URL )
18
+ end
19
+ def test_find2
20
+ url = DOI.find STRING
21
+ assert_equal( url, URL )
22
+ end
23
+ def test_data
24
+ doi = DOI.parse STRING
25
+ data = doi.data
26
+ assert_equal( data['author'][0]['family'], FAMILY )
27
+ assert_equal( data['title'], TITLE )
28
+ end
29
+ def test_data2
30
+ data = DOI.data STRING
31
+ assert_equal( data['author'][0]['family'], FAMILY )
32
+ assert_equal( data['title'], TITLE )
33
+ end
34
+ end
35
+
36
+
@@ -0,0 +1,81 @@
1
+ require 'test/unit'
2
+ require 'uri'
3
+ $VERBOSE = true
4
+
5
+ require_relative '../lib/libdoi'
6
+ class Test_libdoi < Test::Unit::TestCase
7
+ DIR = '10'.freeze
8
+ REQ = '17487'.freeze
9
+ DSS = 'RFC8089'.freeze
10
+
11
+ STRING1 = 'doi:10.17487/RFC8089'.freeze
12
+ STRING2 = '10.17487/RFC8089'.freeze
13
+
14
+ HTTP_URL = URI('https://doi.org/10.17487/RFC8089')
15
+ INFO_URL = URI('info:doi/10.17487/RFC8089')
16
+
17
+ def test_construct
18
+ doi = DOI.new DIR.dup, REQ.dup, DSS.dup
19
+ assert_kind_of( DOI, doi )
20
+ assert_equal( DIR, doi.dir )
21
+ assert_equal( REQ, doi.reg )
22
+ assert_equal( DSS, doi.dss )
23
+ end
24
+ def test_concat
25
+ doi1 = DOI.new DIR.dup, REQ.dup, 'RFC'
26
+ doi2 = doi1 + '8089'
27
+ assert_equal( [DIR,REQ,'RFC'], [doi1.dir, doi1.reg, doi1.dss] )
28
+ assert_equal( [DIR,REQ,'RFC8089'], [doi2.dir, doi2.reg, doi2.dss] )
29
+ end
30
+ def test_append
31
+ doi1 = DOI.new DIR.dup, REQ.dup, 'RFC'
32
+ doi2 = doi1 << '8089'
33
+ assert_equal( [DIR.dup,REQ.dup,'RFC8089'], [doi1.dir, doi1.reg, doi1.dss] )
34
+ assert_same( doi1, doi2 )
35
+ end
36
+ def test_to_s
37
+ doi = DOI.new DIR.dup, REQ.dup, DSS.dup
38
+ assert_equal( STRING1, doi.to_s )
39
+ assert_equal( STRING1, doi.to_s(prefix: true) )
40
+ assert_equal( STRING2, doi.to_s(prefix: false) )
41
+ end
42
+ def test_to_uri
43
+ doi = DOI.new DIR.dup, REQ.dup, DSS.dup
44
+ uri1 = doi.to_uri
45
+ assert_kind_of( URI, uri1 )
46
+ assert_equal( HTTP_URL, uri1 )
47
+
48
+ uri2 = doi.to_uri(info: false)
49
+ assert_kind_of( URI, uri2 )
50
+ assert_equal( HTTP_URL, uri2 )
51
+
52
+ uri3 = doi.to_uri(info: true)
53
+ assert_kind_of(URI, uri3)
54
+ assert_equal( INFO_URL, uri3 )
55
+ end
56
+ def test_parse
57
+ [
58
+ 'http://dx.doi.org/10.17487/RFC8089',
59
+ 'https://doi.org/10.17487/RFC8089',
60
+ 'http://doi.acm.org/10.17487/RFC8089',
61
+ 'http://doi.ieeecomputersociety.org/10.17487/RFC8089',
62
+ 'info:doi/10.17487/RFC8089',
63
+ 'doi:10.17487/RFC8089',
64
+ 'DOI: 10.17487/RFC8089',
65
+ '10.17487/RFC8089',
66
+ ].each do |good|
67
+ doi = DOI.parse(good)
68
+ assert_kind_of( DOI, doi )
69
+ assert_equal( STRING1, doi.to_s )
70
+ end
71
+
72
+ [
73
+ '10.0001/x/abc', # DSS matching "^./" is forbidden by the spec
74
+ 'https://doi.org/not-a-doi',
75
+ 'garbage',
76
+ ].each do |bad|
77
+ assert_raise(ArgumentError) { DOI.parse bad }
78
+ end
79
+ end
80
+ end
81
+
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libdoi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Kerwin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ == DOI Library
15
+
16
+ Parse, display, and dereference DOIs.
17
+
18
+ See the documentation at http://phluid61.github.io/libdoi/
19
+ email:
20
+ - matthew@kerwin.net.au
21
+ executables: []
22
+ extensions: []
23
+ extra_rdoc_files: []
24
+ files:
25
+ - lib/libdoi.rb
26
+ - lib/libdoi/network.rb
27
+ - test/test-libdoi-network.rb
28
+ - test/test-libdoi.rb
29
+ homepage: http://phluid61.github.com/libdoi
30
+ licenses:
31
+ - ISC
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.6.8
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: DOI Library
53
+ test_files:
54
+ - test/test-libdoi-network.rb
55
+ - test/test-libdoi.rb