fletcher 0.1.0 → 0.2.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.
- data/README.md +49 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/fletcher.gemspec +15 -6
- data/lib/fletcher.rb +27 -7
- data/lib/fletcher/data.rb +7 -2
- data/lib/fletcher/item/amazon.rb +17 -4
- data/lib/fletcher/item/base.rb +14 -7
- data/lib/fletcher/item/ebay.rb +29 -0
- data/lib/fletcher/item/etsy.rb +29 -0
- data/lib/fletcher/item/image.rb +8 -0
- data/lib/fletcher/item/thinkgeek.rb +29 -0
- data/lib/fletcher/nokogiri.rb +53 -0
- data/lib/fletcher/string.rb +11 -0
- data/spec/factories/item.rb +14 -0
- data/spec/lib/fletcher/item/amazon_spec.rb +4 -5
- data/spec/lib/fletcher/item/base_spec.rb +1 -4
- data/spec/lib/fletcher/item/ebay_spec.rb +14 -0
- data/spec/lib/fletcher/item/etsy_spec.rb +15 -0
- data/spec/lib/fletcher/item/thinkgeek_spec.rb +14 -0
- data/spec/lib/fletcher/nokogiri_spec.rb +27 -0
- data/spec/lib/fletcher_spec.rb +35 -4
- metadata +33 -24
- data/README.textile +0 -40
- data/index.html +0 -1
data/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Fletcher
|
|
2
|
+
|
|
3
|
+
Fletcher is a cross-website product/item information fetcher. Give fletcher a product url and you'll get back a nice, simple object that's easy to work with.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
* Uses nokogiri for data parsing
|
|
8
|
+
* No third-party API Access Required (Good for websites that don't even have API access)
|
|
9
|
+
|
|
10
|
+
## Supported Websites
|
|
11
|
+
|
|
12
|
+
* [Amazon](http://www.amazon.com) (name, description, images)
|
|
13
|
+
* [eBay](http://www.ebay.com) (name, images)
|
|
14
|
+
* [ThinkGeek](http://www.thinkgeek.com) (name, description, images)
|
|
15
|
+
* [Etsy](http://www.etsy.com) (name, description, images)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
gem install fletcher
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
item = Fletcher.fetch "http://www.amazon.com/Avenir-Deluxe-Unicycle-20-Inch-Wheel/dp/B00165Q9F8"
|
|
27
|
+
|
|
28
|
+
item.name # => "Avenir Deluxe Unicycle (20-Inch Wheel)"
|
|
29
|
+
|
|
30
|
+
item.description # => "A wonderful unicycle"
|
|
31
|
+
|
|
32
|
+
item.image # => {:url => "http://ecx.images-amazon.com/images/I/41b3TNb3uCL._SL500_AA300_.jpg", :alt => "Picture of Unicycle"}
|
|
33
|
+
|
|
34
|
+
item.image.url # => "http://ecx.images-amazon.com/images/I/41b3TNb3uCL._SL500_AA300_.jpg"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Get Raw Nokogiri Document
|
|
38
|
+
item.doc.class.name # => Nokogiri::HTML::Document
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Attributes
|
|
42
|
+
|
|
43
|
+
The following attributes are available from items:
|
|
44
|
+
|
|
45
|
+
* title - (String) The name of the item/product
|
|
46
|
+
* description - (String) The item/product description
|
|
47
|
+
* image - (Hash) The main image of the item
|
|
48
|
+
* images - (Array) Any available images of the item
|
|
49
|
+
|
data/Rakefile
CHANGED
|
@@ -18,7 +18,7 @@ Jeweler::Tasks.new do |gem|
|
|
|
18
18
|
gem.homepage = "http://github.com/hulihanapplications/fletcher"
|
|
19
19
|
gem.license = "MIT"
|
|
20
20
|
gem.summary = %Q{A cross-website product/item information fetcher.}
|
|
21
|
-
gem.description = %Q{
|
|
21
|
+
gem.description = %Q{Easily fetch product/item information from third party websites such as Amazon, eBay, etc.}
|
|
22
22
|
gem.email = "dave@hulihanapplications.com"
|
|
23
23
|
gem.authors = ["Dave Hulihan", "Hulihan Applications"]
|
|
24
24
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
data/fletcher.gemspec
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{fletcher}
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "0.2.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Dave Hulihan", "Hulihan Applications"]
|
|
12
|
-
s.date = %q{2011-12-
|
|
13
|
-
s.description = %q{
|
|
12
|
+
s.date = %q{2011-12-15}
|
|
13
|
+
s.description = %q{Easily fetch product/item information from third party websites such as Amazon, eBay, etc.}
|
|
14
14
|
s.email = %q{dave@hulihanapplications.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
|
16
16
|
"LICENSE.txt",
|
|
17
|
-
"README.
|
|
17
|
+
"README.md"
|
|
18
18
|
]
|
|
19
19
|
s.files = [
|
|
20
20
|
".document",
|
|
@@ -22,19 +22,28 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
"Gemfile",
|
|
23
23
|
"Gemfile.lock",
|
|
24
24
|
"LICENSE.txt",
|
|
25
|
-
"README.
|
|
25
|
+
"README.md",
|
|
26
26
|
"Rakefile",
|
|
27
27
|
"VERSION",
|
|
28
28
|
"fletcher.gemspec",
|
|
29
|
-
"index.html",
|
|
30
29
|
"lib/fletcher.rb",
|
|
31
30
|
"lib/fletcher/data.rb",
|
|
32
31
|
"lib/fletcher/item/amazon.rb",
|
|
33
32
|
"lib/fletcher/item/base.rb",
|
|
33
|
+
"lib/fletcher/item/ebay.rb",
|
|
34
|
+
"lib/fletcher/item/etsy.rb",
|
|
35
|
+
"lib/fletcher/item/image.rb",
|
|
36
|
+
"lib/fletcher/item/thinkgeek.rb",
|
|
37
|
+
"lib/fletcher/nokogiri.rb",
|
|
38
|
+
"lib/fletcher/string.rb",
|
|
34
39
|
"spec/factories/item.rb",
|
|
35
40
|
"spec/lib/fletcher/data_spec.rb",
|
|
36
41
|
"spec/lib/fletcher/item/amazon_spec.rb",
|
|
37
42
|
"spec/lib/fletcher/item/base_spec.rb",
|
|
43
|
+
"spec/lib/fletcher/item/ebay_spec.rb",
|
|
44
|
+
"spec/lib/fletcher/item/etsy_spec.rb",
|
|
45
|
+
"spec/lib/fletcher/item/thinkgeek_spec.rb",
|
|
46
|
+
"spec/lib/fletcher/nokogiri_spec.rb",
|
|
38
47
|
"spec/lib/fletcher_spec.rb",
|
|
39
48
|
"spec/spec_helper.rb",
|
|
40
49
|
"spec/support/benchmark.rb",
|
data/lib/fletcher.rb
CHANGED
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
# = Fletcher
|
|
2
2
|
# Author:: Dave Hulihan - 2011
|
|
3
3
|
require "uri"
|
|
4
|
+
require "fletcher/data"
|
|
5
|
+
require "fletcher/string"
|
|
6
|
+
require "fletcher/nokogiri"
|
|
4
7
|
|
|
5
8
|
module Fletcher
|
|
6
|
-
autoload :Data, 'fletcher/data'
|
|
9
|
+
#autoload :Data, 'fletcher/data'
|
|
10
|
+
#autoload :Nokogiri, 'fletcher/nokogiri'
|
|
7
11
|
|
|
8
|
-
module Item
|
|
12
|
+
module Item
|
|
13
|
+
dir = 'fletcher/item'
|
|
14
|
+
Dir[File.join(dir, "*.rb")].each do |f|
|
|
15
|
+
#autoload f
|
|
16
|
+
end
|
|
9
17
|
autoload :Base, 'fletcher/item/base'
|
|
10
18
|
autoload :Amazon, 'fletcher/item/amazon'
|
|
19
|
+
autoload :Ebay, 'fletcher/item/ebay'
|
|
20
|
+
autoload :Thinkgeek, 'fletcher/item/thinkgeek'
|
|
21
|
+
autoload :Etsy, 'fletcher/item/etsy'
|
|
11
22
|
end
|
|
12
23
|
|
|
13
24
|
# Detect service by url
|
|
14
|
-
# Fletcher.
|
|
15
|
-
def self.
|
|
25
|
+
# Fletcher.identify_service("http://www.amazon.com/whatever") => :amazon
|
|
26
|
+
def self.identify_service(url)
|
|
16
27
|
if url =~ ::URI::regexp
|
|
17
28
|
uri = ::URI::parse(url)
|
|
18
29
|
host = uri.host
|
|
19
30
|
if host =~ Fletcher::Item::Amazon.regexp
|
|
20
31
|
service = :amazon
|
|
32
|
+
elsif host =~ Fletcher::Item::Ebay.regexp
|
|
33
|
+
service = :ebay
|
|
34
|
+
elsif host =~ Fletcher::Item::Thinkgeek.regexp
|
|
35
|
+
service = :thinkgeek
|
|
36
|
+
elsif host =~ Fletcher::Item::Etsy.regexp
|
|
37
|
+
service = :etsy
|
|
21
38
|
else
|
|
22
39
|
service = :unknown
|
|
23
40
|
raise ArgumentError, "Fletcher doesn't support #{host} yet."
|
|
@@ -29,10 +46,13 @@ module Fletcher
|
|
|
29
46
|
|
|
30
47
|
# Fetch information based on url
|
|
31
48
|
def self.fetch(url)
|
|
32
|
-
|
|
49
|
+
service = identify_service(url)
|
|
33
50
|
data = Fletcher::Data.read(url)
|
|
34
|
-
item = Fletcher::Item::Base.generate(
|
|
51
|
+
item = Fletcher::Item::Base.generate(service, data)
|
|
52
|
+
# Store url
|
|
53
|
+
item.url = url
|
|
54
|
+
|
|
35
55
|
item.parse(data)
|
|
36
56
|
return item
|
|
37
|
-
end
|
|
57
|
+
end
|
|
38
58
|
end
|
data/lib/fletcher/data.rb
CHANGED
|
@@ -6,7 +6,12 @@ module Fletcher
|
|
|
6
6
|
class Data
|
|
7
7
|
# Get read url and get data object
|
|
8
8
|
def self.read(url)
|
|
9
|
-
|
|
9
|
+
remote_file = open(url).read
|
|
10
|
+
doc = ::Nokogiri::HTML(remote_file)
|
|
11
|
+
|
|
12
|
+
# Save contents of URL/Remote File
|
|
13
|
+
#last_url_file = File.expand_path(File.join("..", "..", "remote_file"), File.dirname(__FILE__))
|
|
14
|
+
#File.new(last_url_file, "w+").write(remote_file.read)
|
|
10
15
|
end
|
|
11
16
|
end
|
|
12
|
-
end
|
|
17
|
+
end
|
data/lib/fletcher/item/amazon.rb
CHANGED
|
@@ -8,10 +8,23 @@ module Fletcher
|
|
|
8
8
|
|
|
9
9
|
# Parse data and look for object attributes to give to object
|
|
10
10
|
def parse(data)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
# Store raw document object
|
|
12
|
+
self.doc = data
|
|
13
|
+
|
|
14
|
+
case doc
|
|
15
|
+
when Nokogiri::HTML::Document
|
|
16
|
+
# Get Name
|
|
17
|
+
self.name = doc.css("h1.parseasinTitle").first_string
|
|
18
|
+
|
|
19
|
+
# Get Description
|
|
20
|
+
self.description = doc.css("div#productDescriptionWrapper").first_string
|
|
21
|
+
|
|
22
|
+
# Get description from meta title if not found
|
|
23
|
+
self.description = doc.xpath("//meta[@name='description']/@content").first_string if description.nil?
|
|
24
|
+
|
|
25
|
+
# Get Images
|
|
26
|
+
self.images = doc.xpath("//table[@class='productImageGrid']//img").attribute_array
|
|
27
|
+
self.image = images.first
|
|
15
28
|
end
|
|
16
29
|
end
|
|
17
30
|
end
|
data/lib/fletcher/item/base.rb
CHANGED
|
@@ -2,22 +2,29 @@ require "hashie"
|
|
|
2
2
|
|
|
3
3
|
module Fletcher
|
|
4
4
|
module Item
|
|
5
|
-
class Base < ::Hashie::Mash
|
|
6
|
-
|
|
5
|
+
class Base < ::Hashie::Mash
|
|
7
6
|
# Create a product object based on service
|
|
8
7
|
# Fletcher::Item::Base.generate(:amazon, "<html>...") # => #<Fletcher::Item::Amazon:0x...>
|
|
9
8
|
def self.generate(service = nil, data = nil)
|
|
10
|
-
case service
|
|
9
|
+
case service
|
|
11
10
|
when :amazon
|
|
12
|
-
|
|
11
|
+
item = Fletcher::Item::Amazon.new
|
|
13
12
|
when :ebay
|
|
14
|
-
|
|
13
|
+
item = Fletcher::Item::Ebay.new
|
|
14
|
+
when :thinkgeek
|
|
15
|
+
item = Fletcher::Item::Thinkgeek.new
|
|
16
|
+
when :etsy
|
|
17
|
+
item = Fletcher::Item::Etsy.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
item.parse(data)
|
|
21
|
+
return item
|
|
15
22
|
end
|
|
16
23
|
|
|
17
24
|
# Parse data and set object attributes
|
|
18
25
|
def parse(data)
|
|
19
|
-
|
|
26
|
+
self.doc = data # save data for if user wants to access it later
|
|
20
27
|
end
|
|
21
28
|
end # Base
|
|
22
|
-
end #
|
|
29
|
+
end # Item
|
|
23
30
|
end # Fletcher
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Fletcher
|
|
2
|
+
module Item
|
|
3
|
+
class Ebay < Fletcher::Item::Base
|
|
4
|
+
# A regular expression for determining if a url comes from a specific service/website
|
|
5
|
+
def self.regexp
|
|
6
|
+
/ebay\.com/
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Parse data and look for object attributes to give to object
|
|
10
|
+
def parse(data)
|
|
11
|
+
# Store raw document object
|
|
12
|
+
self.doc = data
|
|
13
|
+
|
|
14
|
+
case doc
|
|
15
|
+
when Nokogiri::HTML::Document
|
|
16
|
+
# Get Name
|
|
17
|
+
self.name = doc.xpath("//h1[@itemprop='name']").first_string
|
|
18
|
+
|
|
19
|
+
# Get Description
|
|
20
|
+
# OMITTED: This is tough to get because ebay item descriptions are custom html/content created by sellers
|
|
21
|
+
|
|
22
|
+
# Get Image
|
|
23
|
+
self.images = [{:url => doc.xpath("//span[@itemprop='image']/img").first_string}]
|
|
24
|
+
self.image = images.first
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Fletcher
|
|
2
|
+
module Item
|
|
3
|
+
class Etsy < Fletcher::Item::Base
|
|
4
|
+
# A regular expression for determining if a url comes from a specific service/website
|
|
5
|
+
def self.regexp
|
|
6
|
+
/etsy\.com/
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Parse data and look for object attributes to give to object
|
|
10
|
+
def parse(data)
|
|
11
|
+
# Store raw document object
|
|
12
|
+
self.doc = data
|
|
13
|
+
|
|
14
|
+
case doc
|
|
15
|
+
when Nokogiri::HTML::Document
|
|
16
|
+
# Get Name
|
|
17
|
+
self.name = doc.xpath("//div[@id='item-title']/h1").first_string
|
|
18
|
+
|
|
19
|
+
# Get Description
|
|
20
|
+
self.description = doc.xpath("//div[@id='item-description']/div[@class='section-content']").first_string
|
|
21
|
+
|
|
22
|
+
# Get Images
|
|
23
|
+
self.images = doc.xpath("//div[@id='item-main']//div[@id='fullimage_link1']//img").attribute_array
|
|
24
|
+
self.image = images.first
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Fletcher
|
|
2
|
+
module Item
|
|
3
|
+
class Thinkgeek < Fletcher::Item::Base
|
|
4
|
+
# A regular expression for determining if a url comes from a specific service/website
|
|
5
|
+
def self.regexp
|
|
6
|
+
/thinkgeek\.com/
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Parse data and look for object attributes to give to object
|
|
10
|
+
def parse(data)
|
|
11
|
+
# Store raw document object
|
|
12
|
+
self.doc = data
|
|
13
|
+
|
|
14
|
+
case doc
|
|
15
|
+
when Nokogiri::HTML::Document
|
|
16
|
+
# Get Name
|
|
17
|
+
self.name = doc.xpath("//meta[@property='og:title']/@content").first_string
|
|
18
|
+
|
|
19
|
+
# Get Description
|
|
20
|
+
self.description = doc.xpath("//meta[@property='og:description']/@content").first_string
|
|
21
|
+
|
|
22
|
+
# Get Images
|
|
23
|
+
self.images = [{:url => doc.xpath("//meta[@property='og:image']/@content").first_string}]
|
|
24
|
+
self.image = images.first
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "cgi"
|
|
2
|
+
|
|
3
|
+
module Fletcher
|
|
4
|
+
# This contains helper methods for Nokogiri interactions
|
|
5
|
+
module Nokogiri
|
|
6
|
+
module HTML
|
|
7
|
+
module Document
|
|
8
|
+
|
|
9
|
+
end # Document
|
|
10
|
+
end # HTML
|
|
11
|
+
|
|
12
|
+
module XML
|
|
13
|
+
module NodeSet
|
|
14
|
+
# get string from first nodeset item
|
|
15
|
+
def first_string
|
|
16
|
+
node = first
|
|
17
|
+
case node
|
|
18
|
+
# xml/html element?
|
|
19
|
+
when ::Nokogiri::XML::Element
|
|
20
|
+
return node.content.sanitize
|
|
21
|
+
# xml/html attribute?
|
|
22
|
+
when ::Nokogiri::XML::Attr
|
|
23
|
+
return node.value.sanitize
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# convert nodeset items to an array of hashes
|
|
28
|
+
# @doc.xpath("//img")).attribute_array # => [{:element => "img", :src => ".../someimage.png"}]
|
|
29
|
+
def attribute_array
|
|
30
|
+
a = Array.new
|
|
31
|
+
each do |node|
|
|
32
|
+
temp_hash = Hash.new
|
|
33
|
+
case node
|
|
34
|
+
when ::Nokogiri::XML::Element
|
|
35
|
+
temp_hash[:element] = node.name
|
|
36
|
+
node.attributes.each do |key, value|
|
|
37
|
+
case value
|
|
38
|
+
when ::Nokogiri::XML::Attr
|
|
39
|
+
temp_hash[key.to_sym] = value.value.sanitize
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
a << temp_hash
|
|
44
|
+
end
|
|
45
|
+
return a
|
|
46
|
+
end
|
|
47
|
+
end # Nodeset
|
|
48
|
+
end # XML
|
|
49
|
+
end # Nokogiri
|
|
50
|
+
end # Fletcher
|
|
51
|
+
|
|
52
|
+
::Nokogiri::HTML::Document.send(:include, ::Fletcher::Nokogiri::HTML::Document)
|
|
53
|
+
::Nokogiri::XML::NodeSet.send(:include, ::Fletcher::Nokogiri::XML::NodeSet)
|
data/spec/factories/item.rb
CHANGED
|
@@ -9,8 +9,22 @@ end
|
|
|
9
9
|
|
|
10
10
|
Factory.define :valid_item, :parent => :item do |o|
|
|
11
11
|
o.url "http://www.amazon.com/Kindle-Fire-Amazon-Tablet/dp/B0051VVOB2"
|
|
12
|
+
o.title_xpath "//h1[@class='parseasinTitle']"
|
|
13
|
+
o.images_xpath "//table[@class='productImageGrid']//img"
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
Factory.define :amazon_item, :parent => :item do |o|
|
|
15
17
|
o.url "http://www.amazon.com/Kindle-Fire-Amazon-Tablet/dp/B0051VVOB2"
|
|
16
18
|
end
|
|
19
|
+
|
|
20
|
+
Factory.define :ebay_item, :parent => :item do |o|
|
|
21
|
+
o.url "http://www.ebay.com/itm/24-Wheel-Leakproof-Butyl-Tire-Adjustable-Unicycle-Free-Stand-Cycling-Bike-Green-/370564417915"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Factory.define :thinkgeek_item, :parent => :item do |o|
|
|
25
|
+
o.url "http://www.thinkgeek.com/geektoys/plush/e7f8/"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Factory.define :etsy_item, :parent => :item do |o|
|
|
29
|
+
o.url "http://www.etsy.com/listing/78608690/farm-fresh-125-x-19-in-pick-your-color"
|
|
30
|
+
end
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Fletcher::Item::Amazon do
|
|
4
|
-
describe "parse" do
|
|
5
|
-
|
|
4
|
+
describe "parse" do
|
|
6
5
|
context "with valid data" do
|
|
7
|
-
it "should
|
|
6
|
+
it "should return correct item info" do
|
|
8
7
|
item = described_class.new
|
|
9
8
|
item.parse Fletcher::Data.read(Factory(:amazon_item).url)
|
|
10
|
-
item.x = "1"
|
|
11
|
-
puts item.inspect
|
|
12
9
|
item.name.should_not be_nil
|
|
10
|
+
item.description.should_not be_nil
|
|
11
|
+
item.image.should_not be_nil
|
|
13
12
|
end
|
|
14
13
|
end
|
|
15
14
|
end
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Fletcher::Item::Base do
|
|
4
|
-
describe "generate" do
|
|
5
|
-
|
|
4
|
+
describe "generate" do
|
|
6
5
|
end
|
|
7
6
|
|
|
8
7
|
describe "new" do
|
|
9
8
|
it "should create properly" do
|
|
10
|
-
item = described_class.new(Factory(:item).url)
|
|
11
|
-
puts item.inspect
|
|
12
9
|
end
|
|
13
10
|
end
|
|
14
11
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Fletcher::Item::Ebay do
|
|
4
|
+
describe "parse" do
|
|
5
|
+
context "with valid data" do
|
|
6
|
+
it "should return correct item info" do
|
|
7
|
+
item = described_class.new
|
|
8
|
+
item.parse Fletcher::Data.read(Factory(:ebay_item).url)
|
|
9
|
+
item.name.should_not be_nil
|
|
10
|
+
item.image.should_not be_nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Fletcher::Item::Etsy do
|
|
4
|
+
describe "parse" do
|
|
5
|
+
context "with valid data" do
|
|
6
|
+
it "should return correct item info" do
|
|
7
|
+
item = described_class.new
|
|
8
|
+
item.parse Fletcher::Data.read(Factory(:etsy_item).url)
|
|
9
|
+
item.name.should_not be_nil
|
|
10
|
+
item.description.should_not be_nil
|
|
11
|
+
item.image.should_not be_nil
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Fletcher::Item::Thinkgeek do
|
|
4
|
+
describe "parse" do
|
|
5
|
+
context "with valid data" do
|
|
6
|
+
it "should return correct item info" do
|
|
7
|
+
item = described_class.new
|
|
8
|
+
item.parse Fletcher::Data.read(Factory(:thinkgeek_item).url)
|
|
9
|
+
item.name.should_not be_nil
|
|
10
|
+
item.image.should_not be_nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Fletcher::Nokogiri::HTML::Document do
|
|
4
|
+
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
describe Fletcher::Nokogiri::XML::NodeSet do
|
|
8
|
+
before :each do
|
|
9
|
+
@doc = Fletcher::Data.read(Factory(:valid_item).url)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "first_string" do
|
|
13
|
+
it "should return a valid string" do
|
|
14
|
+
nodeset = @doc.xpath(Factory(:valid_item).title_xpath)
|
|
15
|
+
string = nodeset.first_string
|
|
16
|
+
string.should_not be_nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "attribute_array" do
|
|
21
|
+
it "should return an array of attribute hashes" do
|
|
22
|
+
nodeset = @doc.xpath(Factory(:valid_item).images_xpath)
|
|
23
|
+
attribute_array = nodeset.attribute_array
|
|
24
|
+
attribute_array.class.should == Array
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/spec/lib/fletcher_spec.rb
CHANGED
|
@@ -3,19 +3,50 @@ require 'spec_helper'
|
|
|
3
3
|
describe Fletcher do
|
|
4
4
|
describe :service do
|
|
5
5
|
it "should raise an error when using an unsupported domain" do
|
|
6
|
-
lambda{described_class.
|
|
6
|
+
lambda{described_class.identify_service(Factory(:item).url)}.should raise_error
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it "should return :amazon when using an amazon domain" do
|
|
10
|
-
described_class.
|
|
10
|
+
described_class.identify_service(Factory(:amazon_item).url).should == :amazon
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
it "should return :ebay when using an ebay domain" do
|
|
14
|
+
described_class.identify_service(Factory(:ebay_item).url).should == :ebay
|
|
15
|
+
end
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
describe :fetch do
|
|
15
19
|
context :amazon do
|
|
16
|
-
it "should
|
|
17
|
-
described_class.fetch(Factory(:amazon_item).url)
|
|
20
|
+
it "should fetch amazon item info successfully" do
|
|
21
|
+
item = described_class.fetch(Factory(:amazon_item).url)
|
|
22
|
+
item.should_not be_nil
|
|
23
|
+
item.name.should_not be_nil
|
|
24
|
+
item.description.should_not be_nil
|
|
18
25
|
end
|
|
19
26
|
end
|
|
27
|
+
|
|
28
|
+
context :ebay do
|
|
29
|
+
it "should fetch item info successfully" do
|
|
30
|
+
item = described_class.fetch(Factory(:ebay_item).url)
|
|
31
|
+
item.should_not be_nil
|
|
32
|
+
item.name.should_not be_nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context :thinkgeek do
|
|
37
|
+
it "should fetch item info successfully" do
|
|
38
|
+
item = described_class.fetch(Factory(:thinkgeek_item).url)
|
|
39
|
+
item.should_not be_nil
|
|
40
|
+
item.name.should_not be_nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context :etsy do
|
|
45
|
+
it "should fetch item info successfully" do
|
|
46
|
+
item = described_class.fetch(Factory(:etsy_item).url)
|
|
47
|
+
item.should_not be_nil
|
|
48
|
+
item.name.should_not be_nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
20
51
|
end
|
|
21
52
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fletcher
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -10,11 +10,11 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2011-12-
|
|
13
|
+
date: 2011-12-15 00:00:00.000000000Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: hashie
|
|
17
|
-
requirement: &
|
|
17
|
+
requirement: &72722980 !ruby/object:Gem::Requirement
|
|
18
18
|
none: false
|
|
19
19
|
requirements:
|
|
20
20
|
- - ! '>='
|
|
@@ -22,10 +22,10 @@ dependencies:
|
|
|
22
22
|
version: '0'
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
|
-
version_requirements: *
|
|
25
|
+
version_requirements: *72722980
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: nokogiri
|
|
28
|
-
requirement: &
|
|
28
|
+
requirement: &72722640 !ruby/object:Gem::Requirement
|
|
29
29
|
none: false
|
|
30
30
|
requirements:
|
|
31
31
|
- - ! '>='
|
|
@@ -33,10 +33,10 @@ dependencies:
|
|
|
33
33
|
version: '0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
|
-
version_requirements: *
|
|
36
|
+
version_requirements: *72722640
|
|
37
37
|
- !ruby/object:Gem::Dependency
|
|
38
38
|
name: shoulda
|
|
39
|
-
requirement: &
|
|
39
|
+
requirement: &72722400 !ruby/object:Gem::Requirement
|
|
40
40
|
none: false
|
|
41
41
|
requirements:
|
|
42
42
|
- - ! '>='
|
|
@@ -44,10 +44,10 @@ dependencies:
|
|
|
44
44
|
version: '0'
|
|
45
45
|
type: :development
|
|
46
46
|
prerelease: false
|
|
47
|
-
version_requirements: *
|
|
47
|
+
version_requirements: *72722400
|
|
48
48
|
- !ruby/object:Gem::Dependency
|
|
49
49
|
name: bundler
|
|
50
|
-
requirement: &
|
|
50
|
+
requirement: &72722160 !ruby/object:Gem::Requirement
|
|
51
51
|
none: false
|
|
52
52
|
requirements:
|
|
53
53
|
- - ~>
|
|
@@ -55,10 +55,10 @@ dependencies:
|
|
|
55
55
|
version: 1.0.0
|
|
56
56
|
type: :development
|
|
57
57
|
prerelease: false
|
|
58
|
-
version_requirements: *
|
|
58
|
+
version_requirements: *72722160
|
|
59
59
|
- !ruby/object:Gem::Dependency
|
|
60
60
|
name: jeweler
|
|
61
|
-
requirement: &
|
|
61
|
+
requirement: &72721910 !ruby/object:Gem::Requirement
|
|
62
62
|
none: false
|
|
63
63
|
requirements:
|
|
64
64
|
- - ~>
|
|
@@ -66,10 +66,10 @@ dependencies:
|
|
|
66
66
|
version: 1.6.4
|
|
67
67
|
type: :development
|
|
68
68
|
prerelease: false
|
|
69
|
-
version_requirements: *
|
|
69
|
+
version_requirements: *72721910
|
|
70
70
|
- !ruby/object:Gem::Dependency
|
|
71
71
|
name: rcov
|
|
72
|
-
requirement: &
|
|
72
|
+
requirement: &72721670 !ruby/object:Gem::Requirement
|
|
73
73
|
none: false
|
|
74
74
|
requirements:
|
|
75
75
|
- - ! '>='
|
|
@@ -77,10 +77,10 @@ dependencies:
|
|
|
77
77
|
version: '0'
|
|
78
78
|
type: :development
|
|
79
79
|
prerelease: false
|
|
80
|
-
version_requirements: *
|
|
80
|
+
version_requirements: *72721670
|
|
81
81
|
- !ruby/object:Gem::Dependency
|
|
82
82
|
name: rspec
|
|
83
|
-
requirement: &
|
|
83
|
+
requirement: &72721430 !ruby/object:Gem::Requirement
|
|
84
84
|
none: false
|
|
85
85
|
requirements:
|
|
86
86
|
- - ! '>='
|
|
@@ -88,10 +88,10 @@ dependencies:
|
|
|
88
88
|
version: '0'
|
|
89
89
|
type: :development
|
|
90
90
|
prerelease: false
|
|
91
|
-
version_requirements: *
|
|
91
|
+
version_requirements: *72721430
|
|
92
92
|
- !ruby/object:Gem::Dependency
|
|
93
93
|
name: factory_girl
|
|
94
|
-
requirement: &
|
|
94
|
+
requirement: &72721190 !ruby/object:Gem::Requirement
|
|
95
95
|
none: false
|
|
96
96
|
requirements:
|
|
97
97
|
- - ! '>='
|
|
@@ -99,34 +99,43 @@ dependencies:
|
|
|
99
99
|
version: '0'
|
|
100
100
|
type: :development
|
|
101
101
|
prerelease: false
|
|
102
|
-
version_requirements: *
|
|
103
|
-
description:
|
|
104
|
-
as Amazon, eBay, etc
|
|
102
|
+
version_requirements: *72721190
|
|
103
|
+
description: Easily fetch product/item information from third party websites such
|
|
104
|
+
as Amazon, eBay, etc.
|
|
105
105
|
email: dave@hulihanapplications.com
|
|
106
106
|
executables: []
|
|
107
107
|
extensions: []
|
|
108
108
|
extra_rdoc_files:
|
|
109
109
|
- LICENSE.txt
|
|
110
|
-
- README.
|
|
110
|
+
- README.md
|
|
111
111
|
files:
|
|
112
112
|
- .document
|
|
113
113
|
- .travis.yml
|
|
114
114
|
- Gemfile
|
|
115
115
|
- Gemfile.lock
|
|
116
116
|
- LICENSE.txt
|
|
117
|
-
- README.
|
|
117
|
+
- README.md
|
|
118
118
|
- Rakefile
|
|
119
119
|
- VERSION
|
|
120
120
|
- fletcher.gemspec
|
|
121
|
-
- index.html
|
|
122
121
|
- lib/fletcher.rb
|
|
123
122
|
- lib/fletcher/data.rb
|
|
124
123
|
- lib/fletcher/item/amazon.rb
|
|
125
124
|
- lib/fletcher/item/base.rb
|
|
125
|
+
- lib/fletcher/item/ebay.rb
|
|
126
|
+
- lib/fletcher/item/etsy.rb
|
|
127
|
+
- lib/fletcher/item/image.rb
|
|
128
|
+
- lib/fletcher/item/thinkgeek.rb
|
|
129
|
+
- lib/fletcher/nokogiri.rb
|
|
130
|
+
- lib/fletcher/string.rb
|
|
126
131
|
- spec/factories/item.rb
|
|
127
132
|
- spec/lib/fletcher/data_spec.rb
|
|
128
133
|
- spec/lib/fletcher/item/amazon_spec.rb
|
|
129
134
|
- spec/lib/fletcher/item/base_spec.rb
|
|
135
|
+
- spec/lib/fletcher/item/ebay_spec.rb
|
|
136
|
+
- spec/lib/fletcher/item/etsy_spec.rb
|
|
137
|
+
- spec/lib/fletcher/item/thinkgeek_spec.rb
|
|
138
|
+
- spec/lib/fletcher/nokogiri_spec.rb
|
|
130
139
|
- spec/lib/fletcher_spec.rb
|
|
131
140
|
- spec/spec_helper.rb
|
|
132
141
|
- spec/support/benchmark.rb
|
|
@@ -147,7 +156,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
147
156
|
version: '0'
|
|
148
157
|
segments:
|
|
149
158
|
- 0
|
|
150
|
-
hash:
|
|
159
|
+
hash: 1392307
|
|
151
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
161
|
none: false
|
|
153
162
|
requirements:
|
data/README.textile
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
h1. Fletcher
|
|
2
|
-
|
|
3
|
-
Fletcher is a cross-website product/item information fetcher. Give fletcher producturl and you'll get back a nice, standardized object that's easy to work with.
|
|
4
|
-
|
|
5
|
-
h2. Features
|
|
6
|
-
|
|
7
|
-
* Uses nokogiri for data parsing
|
|
8
|
-
* No third-party API Access Required (Good for websites that don't even have API access)
|
|
9
|
-
|
|
10
|
-
h2. Supported Websites
|
|
11
|
-
|
|
12
|
-
* "Amazon":http://www.amazon.com
|
|
13
|
-
* "eBay":http://www.ebay.com (Coming Soon)
|
|
14
|
-
|
|
15
|
-
h2. Installation
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
gem install fletcher
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
h2. Examples
|
|
22
|
-
|
|
23
|
-
```ruby
|
|
24
|
-
product = Fletcher.fetch("http://www.amazon.com/Avenir-Deluxe-Unicycle-20-Inch-Wheel/dp/B00165Q9F8")
|
|
25
|
-
|
|
26
|
-
product.name # => "Avenir Deluxe Unicycle (20-Inch Wheel)"
|
|
27
|
-
|
|
28
|
-
product.description # => "A wonderful unicycle"
|
|
29
|
-
|
|
30
|
-
product.images # => [{:url => "http://ecx.images-amazon.com/images/I/41b3TNb3uCL._SL500_AA300_.jpg", :alt => "Avenir Deluxe Unicycle (20-Inch Wheel)"}]
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
h2. Attributes
|
|
34
|
-
|
|
35
|
-
The following attributes are available from items:
|
|
36
|
-
|
|
37
|
-
* title - (String) The name of the item/product
|
|
38
|
-
* description - (String) The item/product description
|
|
39
|
-
* images - (Array) Any available images of the item
|
|
40
|
-
|
data/index.html
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<html><head><meta http-equiv="refresh" content="0;url=http://webhelper.centurylink.com/index.php?origURL=http://time/"/></head><body><script>window.location="http://webhelper.centurylink.com/index.php?origURL="+escape(window.location)+"&r="+escape(document.referrer);</script></body></html>
|