goodreads-wrapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ goodreads
2
+ =========
3
+
4
+ home :: http://github.com/tiagoluchini/goodreads
5
+ bugs :: http://github.com/tiagoluchini/goodreads/issues
6
+
7
+ ## Description
8
+
9
+ This gem allows you to easily access publicly available data from Goodreads.
10
+
11
+ ## Features
12
+
13
+ `goodreads` currently features the following:
14
+
15
+ * Querying details of a specified book
16
+
17
+ ## In a nutshell
18
+
19
+ b = Goodreads::Book.new('9780375403170')
20
+
21
+ b.title
22
+ #=> "Les Misérables"
23
+ b.characters
24
+ #=> ["Jean Valjean", "Javert", "Cosette", "Fantine", "Bishop Myriel"]
25
+ b.cover
26
+ #=> "http://d.gr-assets.com/books/1320406739l/24284.jpg"
27
+
28
+ ## Installation
29
+
30
+ $ gem install goodreads-wrapper
31
+
32
+ ## Future features
33
+
34
+ The following features are considered next steps:
35
+
36
+ * Search by title or author
37
+ * Expose more details about genres, characters, authors
38
+ * Expose editions
39
+ * Expose 'similar items'
40
+
41
+ ## License
42
+
43
+ (The MIT License)
44
+
45
+ Copyright (c) 2013 Tiago Luchini
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of this software and associated documentation files (the
49
+ 'Software'), to deal in the Software without restriction, including
50
+ without limitation the rights to use, copy, modify, merge, publish,
51
+ distribute, sublicense, and/or sell copies of the Software, and to
52
+ permit persons to whom the Software is furnished to do so, subject to
53
+ the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be
56
+ included in all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
59
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
60
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
61
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
62
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
63
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
64
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/goodreads.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "goodreads/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "goodreads-wrapper"
7
+ s.version = Goodreads::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Tiago Luchini"]
10
+ s.email = ["info@tiagoluchini.eu"]
11
+ s.homepage = "http://github.com/tiagoluchini/goodreads"
12
+ s.summary = %q{Easily access the publicly available information on Goodreads.}
13
+ s.description = %q{Easily use Ruby to find information on Goodreads.com.}
14
+
15
+ s.rubyforge_project = "goodreads-wrapper"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'hpricot', '~> 0.8.4'
23
+
24
+ s.add_development_dependency 'rake', '~> 0.9.2'
25
+ s.add_development_dependency 'rspec', '~> 1.3.2'
26
+ s.add_development_dependency 'gokdok'
27
+ s.add_development_dependency 'rdoc', '~> 3.11'
28
+ s.add_development_dependency 'fakeweb'
29
+ end
data/lib/goodreads.rb ADDED
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'open-uri'
5
+ require 'rubygems'
6
+ require 'hpricot'
7
+
8
+ require 'goodreads/book'
9
+ require 'goodreads/string_extensions'
10
+ require 'goodreads/version'
@@ -0,0 +1,85 @@
1
+ module Goodreads
2
+
3
+ # Represents a Book on goodreads.com
4
+ class Book
5
+ attr_accessor :isbn, :url, :query_url
6
+
7
+ # Initialize a new Goodreads book object with its ISBN (as a String)
8
+ #
9
+ # book = Goodreads::Book.new("9780375403170")
10
+ #
11
+ # Goodreads::Book objects are lazy loading, meaning that no HTTP request
12
+ # will be performed when a new object is created. Only when you use an
13
+ # accessor that needs the remote data, a HTTP request is made (once).
14
+ #
15
+ def initialize(isbn)
16
+ @isbn = isbn
17
+ @query_url = Goodreads::Book.make_query_url(isbn)
18
+ end
19
+
20
+ # Returns the id used by Goodreads (does not trigger lazy loading)
21
+ def goodreads_id
22
+ @url.match(/\/(\d+)\./)[1] rescue nil
23
+ end
24
+
25
+ # Returns a string containing the title
26
+ def title
27
+ document.search(".bookTitle").innerHTML.strip rescue nil
28
+ end
29
+
30
+ # Returns a string containing the URL for the cover file
31
+ def cover
32
+ document.at("img[@id='coverImage']")['src'] rescue nil
33
+ end
34
+
35
+ # Returns an array with the authors of the book
36
+ def authors
37
+ document.search("[@id='bookAuthors']/[@itemprop='author']/a/span").map { |elem| elem.innerHTML.strip } rescue []
38
+ end
39
+
40
+ # Returns a string with the current Goodreads rating
41
+ def rating
42
+ document.at("[@id='bookMeta']/*/[@itemprop='ratingValue']").innerHTML.strip rescue nil
43
+ end
44
+
45
+ # Retursn a string with the book's description
46
+ def description
47
+ document.at("[@id='description']/span[1]").innerHTML.goodreads_strip_tags.goodreads_strip_bad_description_content rescue nil
48
+ end
49
+
50
+ # Returns an array with the main characters of the book
51
+ def characters
52
+ document.search("[@id='bookDataBox']/*/[@class='infoBoxRowItem']/a").select {|elem| elem['href'] =~ /character/}.map {|elem| elem.innerHTML.strip} rescue []
53
+ end
54
+
55
+ # Returns an integer with the number of pages
56
+ def number_of_pages
57
+ document.at("[@itemprop='numberOfPages']").innerHTML.scan(/\d+/).first.to_i rescue nil
58
+ end
59
+
60
+ # Returns an array with the genres of the book
61
+ def genres
62
+ document.search("[@class='actionLinkLite']").select { |elem| elem['href'] =~ /genres/ }.map { |elem| elem.innerHTML.strip } rescue []
63
+ end
64
+
65
+
66
+ private
67
+
68
+ # Returns a new Hpricot document for parsing.
69
+ def document
70
+ @document ||= Hpricot(open_goodreads)
71
+ end
72
+
73
+ def open_goodreads
74
+ f = open(@query_url)
75
+ @url = f.base_uri.to_s
76
+ f.read
77
+ end
78
+
79
+ def self.make_query_url(isbn)
80
+ "http://www.goodreads.com/search?utf8=%E2%9C%93&query=#{isbn}"
81
+ end
82
+
83
+ end # Book
84
+
85
+ end # Goodreads
@@ -0,0 +1,32 @@
1
+ require 'cgi'
2
+
3
+ module Goodreads #:nordoc:
4
+ module StringExtensions
5
+
6
+ # Unescape HTML
7
+ def goodreads_unescape_html
8
+ if String.method_defined?(:encode)
9
+ CGI::unescapeHTML(self.encode("UTF-8", 'ISO-8859-1'))
10
+ else
11
+ require 'iconv'
12
+ Iconv.conv("UTF-8", 'ISO-8859-1', CGI::unescapeHTML(self))
13
+ end
14
+ end
15
+
16
+ # Strip tags
17
+ def goodreads_strip_tags
18
+ gsub(/<\/?[^>]*>/, "")
19
+ end
20
+
21
+ def goodreads_strip_bad_description_content
22
+ gsub(/^\([^\)]+\)/, '').gsub(/more$/, '')
23
+ end
24
+
25
+ # Strips out whitespace then tests if the string is empty.
26
+ def blank?
27
+ strip.empty?
28
+ end unless method_defined?(:blank?)
29
+ end
30
+ end
31
+
32
+ String.send :include, Goodreads::StringExtensions
@@ -0,0 +1,3 @@
1
+ module Goodreads
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: goodreads-wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tiago Luchini
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hpricot
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.2
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.3.2
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.2
62
+ - !ruby/object:Gem::Dependency
63
+ name: gokdok
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rdoc
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '3.11'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '3.11'
94
+ - !ruby/object:Gem::Dependency
95
+ name: fakeweb
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Easily use Ruby to find information on Goodreads.com.
111
+ email:
112
+ - info@tiagoluchini.eu
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - Gemfile
119
+ - README.md
120
+ - goodreads.gemspec
121
+ - lib/goodreads.rb
122
+ - lib/goodreads/book.rb
123
+ - lib/goodreads/string_extensions.rb
124
+ - lib/goodreads/version.rb
125
+ homepage: http://github.com/tiagoluchini/goodreads
126
+ licenses: []
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project: goodreads-wrapper
145
+ rubygems_version: 1.8.24
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: Easily access the publicly available information on Goodreads.
149
+ test_files: []