olibrary 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 560b9646842794293b3becab99d240100e81766cd39f013f1759f1e5dd2a7c7f
4
+ data.tar.gz: 390a0b4d16559d487342cd4811b8993d980104b97bf0db75e983b5c149ac10ab
5
+ SHA512:
6
+ metadata.gz: 39adb4f98f9b3dee1f49dd164bf21ab71915971963bd07b2d8db7b9a6534606117b587f34e1fc3886efe6115951cb970e6ea19a64e6fe1925ae9dcc02df4cd98
7
+ data.tar.gz: f494fa9e4fa25380048bf467c24dd175daceb8c69d4b15bf32adee323349b25a3dd06a5f8a45df4515490bcbe36186dea687f4162c50a1c2a359cb714379a299
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ .idea
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+ .rvmrc
7
+ *~
8
+ *.swp
9
+ .rbenv-version
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ olibrary
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in olibrary.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,238 @@
1
+ == Olibrary
2
+
3
+ > This project is a fork of https://github.com/jayfajardo/openlibrary with a focus on search.
4
+
5
+ The olibrary 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].
6
+
7
+ 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].
8
+
9
+
10
+ == Installation
11
+
12
+ gem install olibrary
13
+
14
+ or in your Gemfile:
15
+
16
+ gem 'olibrary'
17
+
18
+ == Usage
19
+
20
+ You can use the Books client to retrieve a book's Open Library listing information, and the REST client to perform more advanced queries and save changes to Open Library.
21
+
22
+ # just require
23
+ require 'olibrary'
24
+
25
+ == REST Client
26
+
27
+ 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.
28
+
29
+ You can also use the REST client to log in and save changes to Open Library, after you register your profile (or your bot's profile) with the {API Usergroup}[http://openlibrary.org/usergroup/api]. Send a message to the {ol-tech mailing list}[http://mail.archive.org/cgi-bin/mailman/listinfo/ol-tech] to learn how!
30
+
31
+ === Getting Started
32
+
33
+ Before anything else, create a new client:
34
+
35
+ client = Olibrary::Client.new
36
+
37
+ === Books
38
+
39
+ 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. Common properties include `title`, `works`, and `contributors`, but most books will have more.
40
+
41
+ Find a book by its OLID:
42
+
43
+ book = client.book('olid')
44
+
45
+ book.contributors # array of book contributors
46
+ book.covers # array of book cover ids
47
+ book.works # array of works associated with the book
48
+ book.subjects # array of subjects of the book
49
+
50
+ book.title # book title
51
+ book.by_statement # name of primary author(s) of the book
52
+ book.number_of_pages # number of pages in the book
53
+ book.copyright_date # book's copyright date
54
+ book.physical_format # book's physical format
55
+ book.isbn_10[0] # book's ISBN-10 identifier
56
+ book.isbn_13[0] # book's ISBN-13 identifier
57
+ book.goodreads[0] # book's goodreads id
58
+
59
+ Get data on book contributors:
60
+
61
+ book.contributors.each do |c|
62
+ name = c.name # contributor's name
63
+ role = c.role # contributor's role (e.g., cover art)
64
+ end
65
+
66
+ Get the book's subjects:
67
+
68
+ book.subjects.each do |s|
69
+ subject = s
70
+ end
71
+
72
+ Get a book's Open Library object keys by its ISBN, LCCN, or OCLC identifier:
73
+
74
+ keys = client.book_by_isbn('isbn') # isbn must be 10 or 13 characters long
75
+ keys = client.book_by_lccn('lccn')
76
+ keys = client.book_by_oclc('oclc')
77
+
78
+ Iterate through the array of keys:
79
+
80
+ keys.each do |k|
81
+ key = k['key'] # keys are in the format '/books/{OLID}'
82
+ end
83
+
84
+ Although keys are returned in an array, most arrays will only have one element.
85
+
86
+ === Authors
87
+
88
+ Find an author by their OLID:
89
+
90
+ author = client.author('olid')
91
+
92
+ author.name # author name
93
+ author.birth_date # author's birth date
94
+ author.death_date # author's death date
95
+ author.last_modified.value # date and time of last change to page
96
+ author.revision # number of current revision
97
+ author.key! # author key, in the format '/authors/{OLID}
98
+
99
+ === Search
100
+
101
+ Find books through the Open Library free text search:
102
+
103
+ results = client.search("A Tale of Two Cities")
104
+
105
+ Search by book attributes:
106
+
107
+ results = client.search({author: "Doctorow", title: "Little Brother"})
108
+
109
+ You can add multiple requirements to a single parameter by including a comma within the string.
110
+
111
+ results = client.search({subject: "Science, Physics"}) # works as AND
112
+
113
+ Results are arrays of book documents
114
+
115
+ results[0].title # the title of the first result
116
+
117
+ Results include convienence functions for digging deeper
118
+
119
+ results[0].book.call() # a proc that will return a book document as returned by the `book` method for the current documents id.
120
+ results[0].authors.call() # a proc that will return an array of author documents as returned by the `author` method for each of the current documents author ids.
121
+
122
+ === Revision History
123
+
124
+ Get the revision history of any Open Library object:
125
+
126
+ history = client.rev_history('key')
127
+
128
+ The key should be in the format '/type/OLID'. E.g., '/books/OL9220552M', '/authors/OL27349A', or '/works/OL468516W'.
129
+
130
+ === Recent Changes
131
+
132
+ Get an array of recent changes to Open Library:
133
+
134
+ changes = client.recent
135
+
136
+ === Saving Changes
137
+
138
+ Use the login method to get a session cookie:
139
+
140
+ cookie = client.login('username', 'password')
141
+
142
+ Set the other parameters for the object you want to change:
143
+
144
+ key = '/type/OLID' # e.g., '/books/OL9220552M'
145
+ update = full_object_with_changes # must be JSON format
146
+ comment = 'changed X, Y, and Z'
147
+
148
+ Save your changes and receive the updated object as a response:
149
+
150
+ object = client.save(key, cookie, update, comment)
151
+
152
+ NOTICE: Before you can actually save changes to Open Library, you need to register your profile (or bot) with the {API Usergroup}[http://openlibrary.org/usergroup/api]. Send a message to the {ol-tech mailing list}[http://mail.archive.org/cgi-bin/mailman/listinfo/ol-tech] to learn how!
153
+
154
+ == Books Client
155
+
156
+ There are three classes in the openlibrary gem you can use to access the {Books API}[http://openlibrary.org/dev/docs/api/books]. Use Olibrary::View to look up Open Library listing information, Olibrary::Data to get a book's full metadata details, and Olibrary::Details to get book details in addition to what the Olibrary::View class provides.
157
+
158
+ === Olibrary::View
159
+
160
+ Instantiate the class:
161
+
162
+ view = Olibrary::View
163
+
164
+ Look up a book by its ISBN-10 or ISBN-13:
165
+
166
+ book = view.find_by_isbn("0451526538")
167
+
168
+ book.info_url # book's URL on Open Library
169
+ book.preview # book's preview state, either 'noview' or 'full'
170
+ book.thumbnail_url # url of thumbnail cover of the book, if available
171
+
172
+ book.preview_url
173
+ # Links to an archive.org page with a readable version of the book,
174
+ # if one is available. If not, links to the book's Open Library
175
+ # page. `book.preview` should be used first to test if a readable
176
+ # preview of the book exists.
177
+
178
+ Other built-in finder methods:
179
+
180
+ view.find_by_lccn # Library of Congress catalog number
181
+ view.find_by_oclc # Worldcat Control Number
182
+ view.find_by_olid # Open Library ID
183
+
184
+
185
+ === Olibrary::Data
186
+
187
+ Instantiate the class:
188
+
189
+ data = Olibrary::Data
190
+
191
+ Look up a book by its ISBN-10 or ISBN-13:
192
+
193
+ book_data = data.find_by_isbn("0451526538")
194
+
195
+ book_data.title # book's title
196
+ book_data.authors # array of authors
197
+
198
+ Other built-in finder methods:
199
+
200
+ data.find_by_lccn # Library of Congress catalog number
201
+ data.find_by_oclc # Worldcat Control Number
202
+ data.find_by_olid # Open Library ID
203
+
204
+ === Olibrary::Details
205
+
206
+ Instantiate the class:
207
+
208
+ details = Olibrary::Details
209
+
210
+ Look up a book by its ISBN-10 or ISBN-13:
211
+
212
+ book_details = details.find_by_isbn("0451526538")
213
+
214
+ book_details.info_url # book's URL on Open Library
215
+ book_details.details # additional details, such as description
216
+
217
+ Other built-in finder methods:
218
+
219
+ details.find_by_lccn # Library of Congress catalog number
220
+ details.find_by_oclc # Worldcat Control Number
221
+ details.find_by_olid # Open Library ID
222
+
223
+ == CONTRIBUTORS
224
+
225
+ * Jay Fajardo https://github.com/jayfajardo
226
+ * John Shutt https://github.com/pemulis
227
+ * Robert Berry https://github.com/bdigital
228
+ * Eric Larson https://github.com/ewlarson
229
+ * Charles Horn https://github.com/hornc
230
+ * Alex Grant https://github.com/grantovich
231
+ * Bryan L. Fordham https://github.com/bfordham
232
+ * Kyle Corbitt https://github.com/kcorbitt
233
+ * Matt Dressel https://github.com/dresselm
234
+ * Scott Lesser https://github.com/okcscott
235
+
236
+ == LICENSE
237
+
238
+ This code is released under the {CC0 License}[http://creativecommons.org/publicdomain/zero/1.0/], and may be used for any purpose without restrictions.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new('spec')
4
+
@@ -0,0 +1,10 @@
1
+ module Olibrary
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
@@ -0,0 +1,31 @@
1
+ module Olibrary
2
+ module Books
3
+ # Find books in Open Library by OLID, ISBN, LCCN, or OCLC
4
+ #
5
+ def book(olid)
6
+ data = request("/books/#{olid}")
7
+ Hashie::Mash.new(data)
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
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module Olibrary
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 Olibrary
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,10 @@
1
+ module Olibrary
2
+ module Login
3
+ # Log in to Open Library
4
+ #
5
+ def login(username, password)
6
+ response = protected_login("#{username}", "#{password}")
7
+ cookie = Hashie::Mash.new(response).session
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Olibrary
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
@@ -0,0 +1,18 @@
1
+ module Olibrary
2
+ module Save
3
+ # Save changes to Open Library
4
+ #
5
+ # key - Open Library object key
6
+ # cookie - Cookie retrieved by login method
7
+ # update - Complete, updated Open Library JSON object
8
+ # comment - String comment describing the changes
9
+ #
10
+ # Note that 'update' can reference an external JSON file or
11
+ # a properly formatted Ruby object.
12
+ #
13
+ def save(key, cookie, update, comment)
14
+ response = update("#{key}", "#{cookie}", "#{update}", "#{comment}")
15
+ Hashie::Mash.new(response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ module Olibrary
2
+ module Search
3
+ # Robust access to the Olibrary free-text search.
4
+ #
5
+ # A simple search is converted to a cross field query.
6
+ # @example search("A brief history of time")
7
+ #
8
+ # You can add multiple requirements to a single parameter by including a comma within the string.
9
+ # @example: search({subject: "Science, Physics"}) will find all books with both science AND physics as subjects)
10
+ #
11
+ # Likewise you can combine multiple parameters to refine your results
12
+ # @example search({title:"A Brief History of Time", subject: "Science, Physics", author: "Stephen Hawking"})
13
+ #
14
+ # Possible search parameter keys include
15
+ # :q (cross-field query)
16
+ # :author
17
+ # :publisher
18
+ # :isbn
19
+ # :title
20
+ # :person
21
+ # :place
22
+ # :subject
23
+ # @param limit defaults to 10 but can be set to any number or nil for all. OpenLibrary returns results in batches of 100 so a limit greater than that will make subsequent requests until the limit or end of results is reached. Be warned that high limits on broad queries will take considerable time and return large data sets.
24
+ # @param offset is useful if you want to continue a search from a given offset.
25
+ #
26
+ # @return An array of documents matching the query with all attributes accessible via method calls. Additional convenience methods 'book' and 'authors' are procs for retrieving the full document for the book and authors respectively. Usage: results[0].book.call() => client.book(results[0]['cover_edition_key'])
27
+ def search(search_params, limit = 10, offset = 0)
28
+ processed_params = search_params.is_a?(String) ? { q: search_params } : search_params
29
+ _search(processed_params, limit, offset)
30
+ end
31
+
32
+ private
33
+
34
+ def _search(search_params, limit, offset)
35
+ results = []
36
+ loop do
37
+ data = request('/search.json', params: search_params.merge({ limit: limit, offset: offset }))
38
+ data['docs'].each do |result|
39
+ result['book'] = -> { book(result['cover_edition_key']) }
40
+ result['authors'] = -> { result['author_key'].map { |key| author(key) } }
41
+ results << Hashie::Mash.new(result)
42
+ end
43
+ offset = data['offset'] + data['docs'].count
44
+ break if offset >= data['numFound'] || results.count >= limit
45
+ end
46
+ results
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'request'
2
+ require_relative 'client/books'
3
+ require_relative 'client/authors'
4
+ require_relative 'client/history'
5
+ require_relative 'client/recent'
6
+ require_relative 'client/editions'
7
+ require_relative 'client/search'
8
+ require_relative 'client/login'
9
+ require_relative 'client/save'
10
+
11
+ module Olibrary
12
+ class Client
13
+ include Olibrary::Request
14
+ include Olibrary::Books
15
+ include Olibrary::Authors
16
+ include Olibrary::History
17
+ include Olibrary::Recent
18
+ include Olibrary::Editions
19
+ include Olibrary::Search
20
+ include Olibrary::Login
21
+ include Olibrary::Save
22
+
23
+ # Initialize an Olibrary::Client instance
24
+ #
25
+ def initialize(options={})
26
+ unless options.kind_of?(Hash)
27
+ raise ArgumentError, "Options hash required."
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,76 @@
1
+ module Olibrary
2
+
3
+ class Data
4
+ attr_accessor :url
5
+ attr_accessor :title
6
+ attr_accessor :subtitle
7
+ attr_accessor :authors
8
+ attr_accessor :identifiers
9
+ attr_accessor :classifications
10
+ attr_accessor :subjects, :subject_places, :subject_people, :subject_times
11
+ attr_accessor :publishers, :publish_places
12
+ attr_accessor :publish_date
13
+ attr_accessor :excerpts
14
+ attr_accessor :links
15
+ attr_accessor :cover
16
+ attr_accessor :ebooks
17
+ attr_accessor :pages
18
+ attr_accessor :weight
19
+
20
+ def self.find_by_isbn(key)
21
+ find("ISBN",key)
22
+ end
23
+
24
+ def self.find_by_lccn(key)
25
+ find("LCCN",key)
26
+ end
27
+
28
+ def self.find_by_oclc(key)
29
+ find("OCLC",key)
30
+ end
31
+
32
+ def self.find_by_olid(key)
33
+ find("OLID",key)
34
+ end
35
+
36
+ def self.find(type,key)
37
+ type_for_uri = URI.encode_www_form_component(type)
38
+ key_for_uri = URI.encode_www_form_component(key)
39
+
40
+ response = RestClient.get "http://openlibrary.org/api/books" +
41
+ "?bibkeys=#{type_for_uri}:#{key_for_uri}&format=json&jscmd=data"
42
+ response_data = JSON.parse(response)
43
+ book = response_data["#{type}:#{key}"]
44
+
45
+ if book
46
+ book_meta = new
47
+
48
+ book_meta.title = book["title"]
49
+ book_meta.subtitle = book["subtitle"]
50
+ book_meta.authors = book["authors"]
51
+ book_meta.identifiers = book["identifiers"]
52
+ book_meta.classifications = book["classifications"]
53
+ book_meta.subjects = book["subjects"]
54
+ book_meta.subject_places = book["subject_places"]
55
+ book_meta.subject_people = book["subject_people"]
56
+ book_meta.subject_times = book["subject_times"]
57
+ book_meta.publishers = book["publishers"]
58
+ book_meta.publish_places = book["publish_places"]
59
+ book_meta.publish_date = book["publish_date"]
60
+ book_meta.excerpts = book["excerpts"]
61
+ book_meta.links = book["links"]
62
+ book_meta.cover = book["cover"]
63
+ book_meta.ebooks = book["ebooks"]
64
+ book_meta.pages = book["number_of_pages"]
65
+ book_meta.weight = book["weight"]
66
+
67
+ book_meta
68
+ else
69
+ nil
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ end
76
+
@@ -0,0 +1,53 @@
1
+ module Olibrary
2
+
3
+ class Details
4
+ attr_accessor :info_url
5
+ attr_accessor :bib_key
6
+ attr_accessor :preview_url
7
+ attr_accessor :thumbnail_url
8
+ attr_accessor :details
9
+
10
+ def self.find_by_isbn(key)
11
+ find("ISBN",key)
12
+ end
13
+
14
+ def self.find_by_lccn(key)
15
+ find("LCCN",key)
16
+ end
17
+
18
+ def self.find_by_oclc(key)
19
+ find("OCLC",key)
20
+ end
21
+
22
+ def self.find_by_olid(key)
23
+ find("OLID",key)
24
+ end
25
+
26
+ def self.find(type,key)
27
+ type_for_uri = URI.encode_www_form_component(type)
28
+ key_for_uri = URI.encode_www_form_component(key)
29
+
30
+ response = RestClient.get "http://openlibrary.org/api/books" +
31
+ "?bibkeys=#{type_for_uri}:#{key_for_uri}&format=json&jscmd=data"
32
+ response_data = JSON.parse(response)
33
+ book = response_data["#{type}:#{key}"]
34
+
35
+ if book
36
+ book_meta = new
37
+
38
+ book_meta.info_url = book["info_url"]
39
+ book_meta.bib_key = book["bib_key"]
40
+ book_meta.preview_url = book["preview_url"]
41
+ book_meta.thumbnail_url = book["thumbnail_url"]
42
+ book_meta.details = book["details"]
43
+
44
+ book_meta
45
+ else
46
+ nil
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ end
53
+
@@ -0,0 +1,6 @@
1
+ module Olibrary
2
+ class Error < StandardError; end
3
+ class Unauthorized < Error; end
4
+ class NotFound < Error; end
5
+ class Redirect < Error; end
6
+ end