goodreads-wrapper 0.0.1

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/.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: []