openlibrary 1.0.1 → 1.0.2

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.
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