openlibrary 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,9 +1,8 @@
1
- == Openlibrary
1
+ == Openlibrary 1.0.1
2
2
 
3
+ The openlibrary gem provides Ruby clients for the {Open Library REST API}[http://openlibrary.org/dev/docs/restful_api] and {Books API}[http://openlibrary.org/dev/docs/api/books].
3
4
 
4
- The openlibrary gem is a simple wrapper for the Open Library REST API.
5
-
6
- For more information on the REST calls, you can view the {Open Library API documentation}[http://openlibrary.org/dev/docs/restful_api]. For more info about Open Library development in general, visit the {Open Library Developer Center}[http://openlibrary.org/developers/api] and {Developer Notes}[http://openlibrary.org/dev].
5
+ For more information about Open Library development, visit the {Open Library Developer Center}[http://openlibrary.org/developers/api] and {Developer Notes}[http://openlibrary.org/dev]. If you want to receive the latest updates and learn how to contribute, join us on the {ol-tech mailing list}[http://mail.archive.org/cgi-bin/mailman/listinfo/ol-tech]!
7
6
 
8
7
 
9
8
  == Installation
@@ -19,46 +18,146 @@ or in your Gemfile:
19
18
 
20
19
  == Usage
21
20
 
22
- You can retrieve a book's Open Library listing information.
21
+ You can use the Books client to retrieve a book's Open Library listing information, and the REST client to make broader queries.
23
22
 
24
23
  # just require
25
24
  require 'openlibrary'
26
25
 
27
- Initiate your search
26
+ == REST Client
28
27
 
29
- # create a class proxy
30
- view = Openlibrary::View
31
-
32
- # lookup an item with the ISBN-10 or ISBN-13
33
- book_view = view.find_by_isbn("0451526538")
28
+ You can use the REST client to look up books, authors, the revision history of any Open Library object, and recent changes to Open Library.
34
29
 
35
- or you can use the other built-in finder methods:
30
+ === Getting Started
36
31
 
37
- find_by_lccn # Library of congress catalog number
38
- find_by_oclc # Worldcat Control Number
39
- find_by_olid # Openlibrary ID
32
+ Before anything else, create a new client:
40
33
 
41
- Extract the book information:
42
-
43
- # have a look at the book's info URL on Openlibrary.org
44
- book_view.info_url
34
+ client = Openlibrary::Client.new
35
+
36
+ === Books
37
+
38
+ Since Open Library has varying amounts of information about the books in its database, and returns data in a schemaless format, not every book will have the same properties. Some common properties include `title`, `works`, and `contributors`, but most books will have more.
45
39
 
46
- # or grab the URL of the book's thumbnail as shown on Openlibrary.org
47
- book_view.thumbnail_url
40
+ Find a book by its OLID:
48
41
 
49
- You can also retrieve a book's full metadata details.
42
+ book = client.book('olid')
50
43
 
51
- # create a class proxy
52
- details = Openlibrary::Data
44
+ book.contributors # array of book contributors
45
+ book.covers # array of book cover ids
46
+ book.works # array of works associated with the book
47
+ book.subjects # array of subjects of the book
48
+
49
+ book.title # book title
50
+ book.by_statement # name of primary author(s) of the book
51
+ book.number_of_pages # number of pages in the book
52
+ book.copyright_date # book's copyright date
53
+ book.physical_format # book's physical format
54
+ book.isbn_10[0] # book's ISBN-10 identifier
55
+ book.isbn_13[0] # book's ISBN-13 identifier
56
+ book.goodreads[0] # book's goodreads id
57
+
58
+ Get data on book contributors:
59
+
60
+ book.contributors.each do |c|
61
+ name = c.name # contributor's name
62
+ role = c.role # contributor's role (e.g., cover art)
63
+ end
64
+
65
+ Get the book's subjects:
66
+
67
+ book.subjects.each do |s|
68
+ subject = s
69
+ end
70
+
71
+ Get a book's Open Library object keys by its ISBN, LCCN, or OCLC identifier:
72
+
73
+ keys = client.book_by_isbn('isbn') # isbn must be 10 or 13 characters long
74
+ keys = client.book_by_lccn('lccn')
75
+ keys = client.book_by_oclc('oclc')
76
+
77
+ Iterate through the array of keys:
78
+
79
+ keys.each do |k|
80
+ key = k['key'] # keys are in the format '/books/{OLID}'
81
+ end
82
+
83
+ Although keys are returned in an array, most arrays will only have one element.
84
+
85
+ === Authors
86
+
87
+ Find an author by their OLID:
88
+
89
+ author = client.author('olid')
90
+
91
+ author.name # author name
92
+ author.birth_date # author's birth date
93
+ author.death_date # author's death date
94
+ author.last_modified.value # date and time of last change to page
95
+ author.revision # number of current revision
96
+ author.key! # author key, in the format '/authors/{OLID}
97
+
98
+ === Revision History
99
+
100
+ Get the revision history of any Open Library object:
101
+
102
+ history = client.rev_history('key')
103
+
104
+ The key should be in the format '/books/{OLID}', '/authors/{OLID}', '/works/{OLID}', etc.
105
+
106
+ === Recent Changes
107
+
108
+ Get an array of recent changes to Open Library:
109
+
110
+ changes = client.recent
111
+
112
+ == Books Client
113
+
114
+ There are two classes in the openlibrary gem you can use to access the {Books API}[http://openlibrary.org/dev/docs/api/books]. Use Openlibrary::View to look up Open Library listing information, and Openlibrary::Data to get a book's full metadata details.
115
+
116
+ === Openlibrary::View
117
+
118
+ Instantiate the class:
119
+
120
+ view = Openlibrary::View
121
+
122
+ Look up a book by its ISBN-10 or ISBN-13:
123
+
124
+ book = view.find_by_isbn("0451526538")
125
+
126
+ book.info_url # book's URL on Open Library
127
+ book.preview # book's preview state, either 'noview' or 'full'
128
+ book.thumbnail_url # url of thumbnail cover of the book, if available
53
129
 
54
- # lookup an item with the ISBN-10 or ISBN-13
55
- book_details = details.find_by_isbn("0451526538")
130
+ book.preview_url
131
+ # Links to an archive.org page with a readable version of the book,
132
+ # if one is available. If not, links to the book's Open Library
133
+ # page. `book.preview` should be used first to test if a readable
134
+ # preview of the book exists.
135
+
136
+ Other built-in finder methods:
137
+
138
+ view.find_by_lccn # Library of Congress catalog number
139
+ view.find_by_oclc # Worldcat Control Number
140
+ view.find_by_olid # Open Library ID
141
+
142
+
143
+ === Openlibrary::Data
144
+
145
+ Instantiate the class:
146
+
147
+ data = Openlibrary::Data
148
+
149
+ Look up a book by its ISBN-10 or ISBN-13:
150
+
151
+ book_details = data.find_by_isbn("0451526538")
56
152
 
57
- # have a look at the book's title
58
- book_details.title
153
+ book_details.title # book's title
154
+ book_details.authors # array of authors
155
+
156
+ Other built-in finder methods:
59
157
 
60
- # or an array of authors
61
- book_details.authors
158
+ view.find_by_lccn # Library of Congress catalog number
159
+ view.find_by_oclc # Worldcat Control Number
160
+ view.find_by_olid # Open Library ID
62
161
 
63
162
  == CONTRIBUTORS
64
163
 
@@ -1,27 +1,28 @@
1
1
  require 'openlibrary/request'
2
2
  require 'openlibrary/client/books'
3
+ require 'openlibrary/client/authors'
4
+ require 'openlibrary/client/history'
5
+ require 'openlibrary/client/recent'
6
+ require 'openlibrary/client/editions'
3
7
 
4
8
  module Openlibrary
5
9
  class Client
6
10
  include Openlibrary::Request
7
11
  include Openlibrary::Books
8
-
9
- attr_reader :username, :password
12
+ include Openlibrary::Authors
13
+ include Openlibrary::History
14
+ include Openlibrary::Recent
15
+ include Openlibrary::Editions
10
16
 
11
17
  # Initialize an Openlibrary::Client instance
12
18
  #
13
- # options[:username] - Username
14
- # options[:password] - Password
15
- #
16
19
  def initialize(options={})
17
20
  unless options.kind_of?(Hash)
18
21
  raise ArgumentError, "Options hash required."
19
22
  end
20
23
 
21
- # For future versions that include the ability to log in
22
- #
23
- # @username = options[:username] || Openlibrary.configuration[:username]
24
- # @password = options[:password] || Openlibrary.configuration[:password]
24
+ # For future versions, options may include cookie information
25
+ # and alternative Accept headers (e.g., RDF instead of JSON)
25
26
  end
26
27
  end
27
28
  end
@@ -0,0 +1,10 @@
1
+ module Openlibrary
2
+ module Authors
3
+ # Find authors in Open Library by their key
4
+ #
5
+ def author(key)
6
+ data = request("/authors/#{key}")
7
+ Hashie::Mash.new(data)
8
+ end
9
+ end
10
+ end
@@ -1,10 +1,31 @@
1
1
  module Openlibrary
2
2
  module Books
3
- # Find books in Open Library by ISBN, OLID, LCCN, or OCLC
3
+ # Find books in Open Library by OLID, ISBN, LCCN, or OCLC
4
4
  #
5
5
  def book(olid)
6
6
  data = request("/books/#{olid}")
7
7
  Hashie::Mash.new(data)
8
8
  end
9
+
10
+ def book_by_isbn(isbn)
11
+ type = "/type/edition"
12
+ if isbn.length == 10
13
+ data = query("type=#{type}&isbn_10=#{isbn}")
14
+ elsif isbn.length == 13
15
+ data = query("type=#{type}&isbn_13=#{isbn}")
16
+ else
17
+ raise ArgumentError, "ISBN must be 10 or 13 characters."
18
+ end
19
+ end
20
+
21
+ def book_by_lccn(lccn)
22
+ type = "/type/edition"
23
+ data = query("type=#{type}&lccn=#{lccn}")
24
+ end
25
+
26
+ def book_by_oclc(oclc)
27
+ type = "/type/edition"
28
+ data = query("type=#{type}&oclc_numbers=#{oclc}")
29
+ end
9
30
  end
10
31
  end
@@ -0,0 +1,10 @@
1
+ module Openlibrary
2
+ module Editions
3
+ # Get the editions of a work
4
+ #
5
+ def editions(work, limit=10, offset=0)
6
+ data = request("/works/#{work}/editions.json?limit=#{limit}&offset=#{offset}")
7
+ editions = Hashie::Mash.new(data)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Openlibrary
2
+ module History
3
+ # Get the revision history of an object in Open Library
4
+ #
5
+ def rev_history(object_key)
6
+ data = history("#{object_key}")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Openlibrary
2
+ module Recent
3
+ # Get an array of recent changes to Open Library
4
+ #
5
+ def recent
6
+ data = request("/recentchanges")
7
+ end
8
+ end
9
+ end
@@ -15,11 +15,6 @@ module Openlibrary
15
15
  # path - Request path
16
16
  #
17
17
  def request(path)
18
- # This code is for future versions that allow user login.
19
- #
20
- # username = username || Openlibrary.configuration[:username]
21
- # password = password || Openlibrary.configuration[:password]
22
-
23
18
  url = "#{API_URL}#{path}"
24
19
 
25
20
  resp = RestClient.get(url, { accept: :json }) do |response, request, result, &block|
@@ -35,6 +30,46 @@ module Openlibrary
35
30
  parse(resp)
36
31
  end
37
32
 
33
+ # Get the history of an object in Open Library
34
+ #
35
+ # object - object key, e.g., '/books/OL1M'
36
+ #
37
+ def history(object)
38
+ url = "#{API_URL}#{object}.json?m=history"
39
+
40
+ resp = RestClient.get(url, { accept: :json }) do |response, request, result, &block|
41
+ case response.code
42
+ when 200
43
+ response.return!(request, result, &block)
44
+ when 401
45
+ raise Openlibrary::Unauthorized
46
+ when 404
47
+ raise Openlibrary::NotFound
48
+ end
49
+ end
50
+ parse(resp)
51
+ end
52
+
53
+ # Perform a query using the Query API
54
+ #
55
+ # path - Request path
56
+ #
57
+ def query(query)
58
+ url = "#{API_URL}/query.json?#{query}"
59
+
60
+ resp = RestClient.get(url, { accept: :json }) do |response, request, result, &block|
61
+ case response.code
62
+ when 200
63
+ response.return!(request, result, &block)
64
+ when 401
65
+ raise Openlibrary::Unauthorized
66
+ when 404
67
+ raise Openlibrary::NotFound
68
+ end
69
+ end
70
+ parse(resp)
71
+ end
72
+
38
73
  def parse(resp)
39
74
  object = JSON.parse(resp.body)
40
75
  object
@@ -1,3 +1,3 @@
1
1
  module Openlibrary
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
data/openlibrary.gemspec CHANGED
@@ -1,28 +1,28 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "openlibrary/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "openlibrary"
7
- s.version = Openlibrary::VERSION
8
- s.authors = ["Jay Fajardo"]
9
- s.email = ["jmrfajardo@gmail.com"]
10
- s.homepage = "http://www.proudcloud.net"
11
- s.summary = %q{Ruby Interface for the Openlibrary.org API}
12
- s.description = %q{Openlibrary.org API Interface}
13
-
14
- s.rubyforge_project = "openlibrary"
15
-
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
20
-
21
- s.add_development_dependency 'rspec', '~> 2.13'
22
- s.add_development_dependency 'webmock', '~> 1.6'
23
-
24
- s.add_runtime_dependency 'json', '~> 1.7.7'
25
- s.add_runtime_dependency 'rest-client', '~> 1.6'
26
- s.add_runtime_dependency 'hashie', '~> 1.0'
27
- s.add_runtime_dependency 'activesupport', '~> 3'
28
- end
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "openlibrary/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "openlibrary"
7
+ s.version = Openlibrary::VERSION
8
+ s.authors = ["Jay Fajardo"]
9
+ s.email = ["jmrfajardo@gmail.com"]
10
+ s.homepage = "http://www.proudcloud.net"
11
+ s.summary = %q{Ruby Interface for the Openlibrary.org API}
12
+ s.description = %q{Openlibrary.org API Interface}
13
+
14
+ s.rubyforge_project = "openlibrary"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency 'rspec', '~> 2.13'
22
+ s.add_development_dependency 'webmock', '~> 1.6'
23
+
24
+ s.add_runtime_dependency 'json', '~> 1.7.7'
25
+ s.add_runtime_dependency 'rest-client', '~> 1.6'
26
+ s.add_runtime_dependency 'hashie', '~> 2.0.2'
27
+ s.add_runtime_dependency 'activesupport', '~> 3'
28
+ end
data/spec/client_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Client' do
4
- let(:client) { Openlibrary::Client.new() }
4
+ let(:client) { Openlibrary::Client.new }
5
5
 
6
6
  describe '#new' do
7
7
  it 'requires an argument' do
@@ -26,15 +26,169 @@ describe 'Client' do
26
26
  book = client.book('OL23109860M')
27
27
 
28
28
  book.should be_a Hashie::Mash
29
- book.contributors.should be_a Array
30
- book.covers.should be_a Array
31
-
32
- book.title.should eq 'The Great Gatsby'
33
- book.by_statement.should eq 'F. Scott Fitzgerald.'
34
- book.number_of_pages.should eq 180
35
- book.contributors[0].name.should eq 'Francis Cugat'
36
- book.contributors[0].role.should eq 'Cover Art'
37
- book.copyright_date.should eq '1925'
29
+ book.contributors.should be_a Array
30
+ book.covers.should be_a Array
31
+ book.works.should be_a Array
32
+
33
+ book.title.should eq 'The Great Gatsby'
34
+ book.by_statement.should eq 'F. Scott Fitzgerald.'
35
+ book.number_of_pages.should eq 180
36
+ book.contributors[0].name.should eq 'Francis Cugat'
37
+ book.contributors[0].role.should eq 'Cover Art'
38
+ book.copyright_date.should eq '1925'
39
+ book.isbn_10[0].should eq '0743273567'
40
+ book.identifiers.goodreads[0].should eq '4671'
41
+ book.identifiers.google[0].should eq 'iXn5U2IzVH0C'
42
+ book.physical_format.should eq 'Trade Paperback'
43
+ book.publishers[0].should eq 'Scribner'
44
+ book.subjects[1].should eq 'First loves -- Fiction'
45
+ book.subjects[0].should eq 'Traffic accidents -- Fiction'
46
+
47
+ # Because of a conflict with the internal `key?` method of
48
+ # Hashie::Mash, any key actually named 'key' must be referenced
49
+ # with a bang (!) to get the value.
50
+ book.key!.should eq '/books/OL23109860M'
51
+ book.languages[0].key!.should eq '/languages/eng'
52
+ end
53
+ end
54
+
55
+ describe '#book_by_isbn' do
56
+ before do
57
+ isbn_10 = '046503912X'
58
+ type = '/type/edition'
59
+ stub_get("/query.json?type=#{type}&isbn_10=#{isbn_10}",
60
+ 'book_by_isbn.json')
61
+ end
62
+ it 'returns array of books' do
63
+ expect { client.book_by_isbn('046503912X').not_to raise_error }
64
+ expect { client.book_by_isbn('123').
65
+ to raise_error ArgumentError, "ISBN must be 10 or 13 characters." }
66
+
67
+ books = client.book_by_isbn('046503912X')
68
+
69
+ books.should be_a Array
70
+ books[0].should be_a Hash
71
+
72
+ books[0]['key'].should eq '/books/OL6807502M'
73
+ end
74
+ end
75
+
76
+ describe '#book_by_lccn' do
77
+ before do
78
+ lccn = '00271772'
79
+ type = '/type/edition'
80
+ stub_get("/query.json?type=#{type}&lccn=#{lccn}",
81
+ 'book_by_lccn.json')
82
+ end
83
+ it 'returns array of books' do
84
+ expect { client.book_by_lccn('00271772').not_to raise_error }
85
+
86
+ books = client.book_by_lccn('00271772')
87
+
88
+ books.should be_a Array
89
+ books[0].should be_a Hash
90
+ end
91
+ end
92
+
93
+ describe '#book_by_oclc' do
94
+ before do
95
+ oclc = '42860053'
96
+ type = '/type/edition'
97
+ stub_get("/query.json?type=#{type}&oclc_numbers=#{42860053}",
98
+ 'book_by_oclc.json')
99
+ end
100
+ it 'returns array of books' do
101
+ expect { client.book_by_oclc('42860053').not_to raise_error }
102
+
103
+ books = client.book_by_oclc('42860053')
104
+
105
+ books.should be_a Array
106
+ books[0].should be_a Hash
107
+ end
108
+ end
109
+
110
+ describe '#author' do
111
+ before do
112
+ key = 'OL1A'
113
+ stub_get("/authors/#{key}", 'author.json')
114
+ end
115
+
116
+ it 'returns author details' do
117
+ expect { client.author('OL1A') }.not_to raise_error
118
+
119
+ author = client.author('OL1A')
120
+
121
+ author.should be_a Hashie::Mash
122
+ author.name.should eq 'Sachi Rautroy'
123
+ author.personal_name.should eq 'Sachi Rautroy'
124
+ author.death_date.should eq '2004'
125
+ author.birth_date.should eq '1916'
126
+ author.last_modified.type.should eq '/type/datetime'
127
+ author.last_modified.value.should eq '2008-11-16T07:25:54.131674'
128
+ author.id.should eq 97
129
+ author.revision.should eq 6
130
+
131
+ # Because of a conflict with the internal `key?` method of
132
+ # Hashie::Mash, any key actually named 'key' must be referenced
133
+ # with a bang (!) to get the value.
134
+ author.key!.should eq '/authors/OL1A'
135
+ end
136
+ end
137
+
138
+ describe '#rev_history' do
139
+ before do
140
+ key = '/books/OL1M'
141
+ stub_get("#{key}.json?m=history", 'history.json')
142
+ end
143
+
144
+ it 'returns the revision history of an object' do
145
+ expect { client.rev_history('/books/OL1M') }.not_to raise_error
146
+
147
+ history = client.rev_history('/books/OL1M')
148
+
149
+ history.should be_a Array
150
+ history[0].should be_a Hash
151
+ end
152
+ end
153
+
154
+ describe '#recent' do
155
+ before do
156
+ stub_get("/recentchanges", 'recent.json')
157
+ end
158
+
159
+ it 'returns recent changes to Open Library' do
160
+ expect { client.recent.not_to raise_error }
161
+
162
+ changes = client.recent
163
+
164
+ changes.should be_a Array
165
+ changes[0].should be_a Hash
166
+ end
167
+ end
168
+
169
+ describe '#editions' do
170
+ before do
171
+ work = 'OL27258W'
172
+ stub_get("/works/#{work}/editions.json?limit=10&offset=0", 'editions.json')
173
+ end
174
+
175
+ it 'returns the editions of a work' do
176
+ expect { client.editions('OL27258W') }.not_to raise_error
177
+
178
+ editions = client.editions('OL27258W', 10, 0)
179
+
180
+ editions.should be_a Hashie::Mash
181
+ editions.entries.should be_a Array
182
+
183
+ editions.size!.should eq 19
184
+ editions.links.next.should eq '/works/OL27258W/editions.json?limit=10&offset=10'
185
+ editions.links.self.should eq '/works/OL27258W/editions.json?limit=10&offset=0'
186
+ editions.links.work.should eq '/works/OL27258W'
187
+
188
+ # Failing tests for iteration through entries
189
+ #
190
+ # editions.entries[0].should be_a Hashie::Mash
191
+ # editions.entries[0].number_of_pages.should eq 322
38
192
  end
39
193
  end
40
194
  end