etsy 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.
- data/README.rdoc +125 -0
- data/Rakefile +40 -0
- data/lib/etsy.rb +65 -0
- data/lib/etsy/image.rb +27 -0
- data/lib/etsy/listing.rb +76 -0
- data/lib/etsy/model.rb +64 -0
- data/lib/etsy/request.rb +48 -0
- data/lib/etsy/response.rb +30 -0
- data/lib/etsy/shop.rb +50 -0
- data/lib/etsy/user.rb +54 -0
- data/lib/etsy/version.rb +13 -0
- data/test/fixtures/getShopDetails.json +70 -0
- data/test/fixtures/getShopListings.json +135 -0
- data/test/fixtures/getUserDetails.json +34 -0
- data/test/test_helper.rb +54 -0
- data/test/unit/etsy/image_test.rb +22 -0
- data/test/unit/etsy/listing_test.rb +92 -0
- data/test/unit/etsy/request_test.rb +74 -0
- data/test/unit/etsy/response_test.rb +49 -0
- data/test/unit/etsy/shop_test.rb +63 -0
- data/test/unit/etsy/user_test.rb +75 -0
- data/test/unit/etsy_test.rb +21 -0
- metadata +88 -0
data/README.rdoc
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
= Etsy
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
The Etsy gem provides a friendly Ruby interface to the Etsy API
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
Installing the latest stable version is simple:
|
10
|
+
|
11
|
+
sudo gem install etsy
|
12
|
+
|
13
|
+
If you want to be on the bleeding edge, install from GitHub:
|
14
|
+
|
15
|
+
sudo gem install reagent-etsy --source=http://gems.github.com
|
16
|
+
|
17
|
+
== Usage
|
18
|
+
|
19
|
+
The Etsy API is read-only - all you need to gain access is an API Key (available
|
20
|
+
from http://developer.etsy.com). Once you have your API key, set it in your script:
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'etsy'
|
24
|
+
Etsy.api_key = 'foobar'
|
25
|
+
|
26
|
+
From there, you can make any calls to the API that you need.
|
27
|
+
|
28
|
+
=== Users
|
29
|
+
|
30
|
+
If you're starting with a user, the easiest way is to use the Etsy.user method:
|
31
|
+
|
32
|
+
>> user = Etsy.user('littletjane')
|
33
|
+
=> #<Etsy::User:0x107f82c @result=[{"city"=>"Washington, DC", ... >
|
34
|
+
>> user.username
|
35
|
+
=> "littletjane"
|
36
|
+
>> user.id
|
37
|
+
=> 5327518
|
38
|
+
>> user.url
|
39
|
+
=> "http://www.etsy.com/shop.php?user_id=5327518"
|
40
|
+
|
41
|
+
For more information about what is available for a user, check out the documentation
|
42
|
+
for Etsy::User.
|
43
|
+
|
44
|
+
== Shops
|
45
|
+
|
46
|
+
Each user may optionally have a shop. If a user is a seller, he / she also has an
|
47
|
+
associated shop object:
|
48
|
+
|
49
|
+
>> user.seller?
|
50
|
+
=> true
|
51
|
+
>> shop = user.shop
|
52
|
+
=> #<Etsy::Shop:0x102578c @result={"is_vacation"=>"", "announcement"=> ... >
|
53
|
+
>> shop.name
|
54
|
+
=> "littletjane"
|
55
|
+
>> shop.title
|
56
|
+
=> "a cute and crafty mix of handmade goods."
|
57
|
+
|
58
|
+
More information about shops can be found in the documentation for Etsy::Shop.
|
59
|
+
|
60
|
+
== Listings
|
61
|
+
|
62
|
+
Shops contain multiple listings:
|
63
|
+
|
64
|
+
>> shop.listings
|
65
|
+
=> [#<Etsy::Listing:0x119acac @result={} ...>, ... ]
|
66
|
+
>> listing = shop.listings.first
|
67
|
+
=> #<Etsy::Listing:0x19a981c @result={} ... >
|
68
|
+
>> listing.title
|
69
|
+
=> "hanging with the bad boys matchbox"
|
70
|
+
>> listing.description
|
71
|
+
=> "standard size matchbox, approx. 1.5 x 2 inches ..."
|
72
|
+
>> listing.url
|
73
|
+
=> "http://www.etsy.com/view_listing.php?listing_id=24165902"
|
74
|
+
>> listing.view_count
|
75
|
+
=> 19
|
76
|
+
>> listing.created_at
|
77
|
+
=> Sat Apr 25 11:31:34 -0400 2009
|
78
|
+
|
79
|
+
See the documentation for Etsy::Listing for more information.
|
80
|
+
|
81
|
+
== Images
|
82
|
+
|
83
|
+
Each listing has one or more images available:
|
84
|
+
|
85
|
+
>> listing.images
|
86
|
+
=> [#<Etsy::Image:0x18f85e4 @result={} ... >,
|
87
|
+
#<Etsy::Image:0x18f85d0 @result={} ... >]
|
88
|
+
>> listing.images.first.small_square
|
89
|
+
=> "http://ny-image2.etsy.com/il_25x25.67765346.jpg"
|
90
|
+
>> listing.images.first.large
|
91
|
+
=> "http://ny-image2.etsy.com/il_430xN.67765346.jpg"
|
92
|
+
|
93
|
+
Listings also have a primary image:
|
94
|
+
|
95
|
+
>> listing.image
|
96
|
+
=> #<Etsy::Image:0x18c3060 @result={} ... >
|
97
|
+
>> listing.image.large
|
98
|
+
=> "http://ny-image2.etsy.com/il_430xN.67765346.jpg"
|
99
|
+
|
100
|
+
More information is available in the documentation for Etsy::Image.
|
101
|
+
|
102
|
+
== License
|
103
|
+
|
104
|
+
Copyright (c) 2009 Patrick Reagan (reaganpr@gmail.com)
|
105
|
+
|
106
|
+
Permission is hereby granted, free of charge, to any person
|
107
|
+
obtaining a copy of this software and associated documentation
|
108
|
+
files (the "Software"), to deal in the Software without
|
109
|
+
restriction, including without limitation the rights to use,
|
110
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
111
|
+
copies of the Software, and to permit persons to whom the
|
112
|
+
Software is furnished to do so, subject to the following
|
113
|
+
conditions:
|
114
|
+
|
115
|
+
The above copyright notice and this permission notice shall be
|
116
|
+
included in all copies or substantial portions of the Software.
|
117
|
+
|
118
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
119
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
120
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
121
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
122
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
123
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
124
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
125
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'lib/etsy/version'
|
6
|
+
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'etsy'
|
11
|
+
s.version = Etsy::Version.to_s
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
14
|
+
s.rdoc_options = %w(--main README.rdoc)
|
15
|
+
s.summary = "Provides a friendly ruby-like interface to the Etsy API"
|
16
|
+
s.author = 'Patrick Reagan'
|
17
|
+
s.email = 'reaganpr@gmail.com'
|
18
|
+
s.homepage = 'http://sneaq.net'
|
19
|
+
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
|
20
|
+
# s.executables = ['etsy']
|
21
|
+
|
22
|
+
s.add_dependency('json', '~> 1.1.0')
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
26
|
+
pkg.gem_spec = spec
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::TestTask.new do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
32
|
+
t.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Generate the gemspec to serve this Gem from Github'
|
36
|
+
task :github do
|
37
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
38
|
+
File.open(file, 'w') {|f| f << spec.to_ruby }
|
39
|
+
puts "Created gemspec: #{file}"
|
40
|
+
end
|
data/lib/etsy.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'etsy/request'
|
7
|
+
require 'etsy/response'
|
8
|
+
|
9
|
+
require 'etsy/model'
|
10
|
+
require 'etsy/user'
|
11
|
+
require 'etsy/shop'
|
12
|
+
require 'etsy/listing'
|
13
|
+
require 'etsy/image'
|
14
|
+
|
15
|
+
# = Etsy: A friendly Ruby interface to the Etsy API
|
16
|
+
#
|
17
|
+
# == Quick Start
|
18
|
+
#
|
19
|
+
# Getting started is easy. First, you will need a valid API key from the Etsy
|
20
|
+
# developer site (http://developer.etsy.com/). Since the API is read-only at
|
21
|
+
# the moment, that's all you need to do.
|
22
|
+
#
|
23
|
+
# To start using the API, require the etsy gem and set it up to use your API key:
|
24
|
+
#
|
25
|
+
# require 'rubygems'
|
26
|
+
# require 'etsy'
|
27
|
+
#
|
28
|
+
# Etsy.api_key = 'itsasecret'
|
29
|
+
#
|
30
|
+
# Now you can make API calls that originate from an Etsy user:
|
31
|
+
#
|
32
|
+
# # Find a user by username
|
33
|
+
# user = Etsy.user('littletjane')
|
34
|
+
#
|
35
|
+
# # Grab that user's shop information
|
36
|
+
# user.seller?
|
37
|
+
# user.shop
|
38
|
+
# user.shop.title
|
39
|
+
#
|
40
|
+
# # ... and the listings in the shop
|
41
|
+
# listing = user.shop.listings.first
|
42
|
+
# listing.title
|
43
|
+
# listing.description
|
44
|
+
#
|
45
|
+
# To see what else is available for a user, check out the full documentation for
|
46
|
+
# the Etsy::User class.
|
47
|
+
#
|
48
|
+
module Etsy
|
49
|
+
|
50
|
+
# Set the API key for all requests
|
51
|
+
def self.api_key=(api_key)
|
52
|
+
@api_key = api_key
|
53
|
+
end
|
54
|
+
|
55
|
+
# Retrieve the API key
|
56
|
+
def self.api_key
|
57
|
+
@api_key
|
58
|
+
end
|
59
|
+
|
60
|
+
# Find a user by username. See Etsy::User for more information.
|
61
|
+
def self.user(username)
|
62
|
+
User.find_by_username(username)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/etsy/image.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = Image
|
4
|
+
#
|
5
|
+
# Represents an image resource of an Etsy listing and contains multiple sizes.
|
6
|
+
# Sizes available are:
|
7
|
+
#
|
8
|
+
# [small_square] The smallest square image (25x25 pixels)
|
9
|
+
# [medium_square] The medium square image (50x50 pixels)
|
10
|
+
# [large_square] The largest square image (75x75 pixels)
|
11
|
+
# [small] The small image for this listing (155x125 pixels)
|
12
|
+
# [medium] The medium image for this listing (200x200 pixels)
|
13
|
+
# [large] The largest image available for this listing (430x? pixels)
|
14
|
+
#
|
15
|
+
class Image
|
16
|
+
|
17
|
+
include Etsy::Model
|
18
|
+
|
19
|
+
attribute :small_square, :from => :image_url_25x25
|
20
|
+
attribute :medium_square, :from => :image_url_50x50
|
21
|
+
attribute :large_square, :from => :image_url_75x75
|
22
|
+
attribute :small, :from => :image_url_155x125
|
23
|
+
attribute :medium, :from => :image_url_200x200
|
24
|
+
attribute :large, :from => :image_url_430xN
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/etsy/listing.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = Listing
|
4
|
+
#
|
5
|
+
# Represents a single Etsy listing. Has the following attributes:
|
6
|
+
#
|
7
|
+
# [id] The unique identifier for this listing
|
8
|
+
# [title] The title of this listing
|
9
|
+
# [description] This listing's full description
|
10
|
+
# [view_count] The number of times this listing has been viewed
|
11
|
+
# [url] The full URL to this listing's detail page
|
12
|
+
# [price] The price of this listing item
|
13
|
+
# [currency] The currency that the seller is using for this listing item
|
14
|
+
# [quantity] The number of items available for sale
|
15
|
+
# [tags] An array of tags that the seller has used for this listing
|
16
|
+
# [materials] Any array of materials that was used in the production of this item
|
17
|
+
#
|
18
|
+
# Additionally, the following queries on this item are available:
|
19
|
+
#
|
20
|
+
# [active?] Is this listing active?
|
21
|
+
# [removed?] Has this listing been removed?
|
22
|
+
# [sold_out?] Is this listing sold out?
|
23
|
+
# [expired?] Has this listing expired?
|
24
|
+
# [alchemy?] Is this listing an Alchemy item? (i.e. requested by an Etsy user)
|
25
|
+
#
|
26
|
+
class Listing
|
27
|
+
|
28
|
+
include Etsy::Model
|
29
|
+
|
30
|
+
STATES = %w(active removed sold_out expired alchemy)
|
31
|
+
|
32
|
+
finder :all, '/shops/:user_id/listings'
|
33
|
+
|
34
|
+
attribute :id, :from => :listing_id
|
35
|
+
attribute :view_count, :from => :views
|
36
|
+
attribute :created, :from => :creation_epoch
|
37
|
+
attribute :currency, :from => :currency_code
|
38
|
+
attribute :ending, :from => :ending_epoch
|
39
|
+
|
40
|
+
attributes :title, :description, :state, :url, :price, :quantity,
|
41
|
+
:tags, :materials
|
42
|
+
|
43
|
+
STATES.each do |state|
|
44
|
+
define_method "#{state}?" do
|
45
|
+
self.state == state.sub('_', '')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Time that this listing was created
|
50
|
+
#
|
51
|
+
def created_at
|
52
|
+
Time.at(created)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Time that this listing is ending (will be removed from store)
|
56
|
+
#
|
57
|
+
def ending_at
|
58
|
+
Time.at(ending)
|
59
|
+
end
|
60
|
+
|
61
|
+
# The list of images associated with this listing. See Etsy::Image
|
62
|
+
# for more information
|
63
|
+
#
|
64
|
+
def images
|
65
|
+
@result['all_images'].map {|image_data| Image.new(image_data) }
|
66
|
+
end
|
67
|
+
|
68
|
+
# The primary image for this listing. See Etsy::Image for more
|
69
|
+
# information
|
70
|
+
#
|
71
|
+
def image
|
72
|
+
images.first
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/etsy/model.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Etsy
|
2
|
+
module Model # :nodoc:all
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
def attribute(name, options = {})
|
7
|
+
from = options.fetch(:from, name)
|
8
|
+
|
9
|
+
class_eval <<-CODE
|
10
|
+
def #{name}
|
11
|
+
@result['#{from}']
|
12
|
+
end
|
13
|
+
CODE
|
14
|
+
end
|
15
|
+
|
16
|
+
def attributes(*names)
|
17
|
+
names.each {|name| attribute(name) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def finder(type, endpoint)
|
21
|
+
parameter = endpoint.scan(/:\w+/).first
|
22
|
+
parameter.sub!(/^:/, '')
|
23
|
+
|
24
|
+
endpoint.sub!(":#{parameter}", '#{' + parameter + '}')
|
25
|
+
|
26
|
+
send("find_#{type}", parameter, endpoint)
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_all(parameter, endpoint)
|
30
|
+
class_eval <<-CODE
|
31
|
+
def self.find_all_by_#{parameter}(#{parameter})
|
32
|
+
response = Request.get("#{endpoint}")
|
33
|
+
response.result.map {|listing| new(listing) }
|
34
|
+
end
|
35
|
+
CODE
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_one(parameter, endpoint)
|
39
|
+
class_eval <<-CODE
|
40
|
+
def self.find_by_#{parameter}(#{parameter})
|
41
|
+
response = Request.get("#{endpoint}")
|
42
|
+
new response.result
|
43
|
+
end
|
44
|
+
CODE
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
module InstanceMethods
|
50
|
+
|
51
|
+
def initialize(result = nil)
|
52
|
+
@result = result
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.included(other)
|
58
|
+
other.send(:extend, Etsy::Model::ClassMethods)
|
59
|
+
other.send(:include, Etsy::Model::InstanceMethods)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/etsy/request.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Etsy
|
2
|
+
|
3
|
+
# = Request
|
4
|
+
#
|
5
|
+
# A basic wrapper around GET requests to the Etsy JSON API
|
6
|
+
#
|
7
|
+
class Request
|
8
|
+
|
9
|
+
# The base URL for API requests
|
10
|
+
def self.base_url
|
11
|
+
"http://beta-api.etsy.com/v1"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Perform a GET request for the resource with optional parameters - returns
|
15
|
+
# A Response object with the payload data
|
16
|
+
def self.get(resource_path, parameters = {})
|
17
|
+
request = Request.new(resource_path, parameters)
|
18
|
+
Response.new(request.get)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create a new request for the resource with optional parameters
|
22
|
+
def initialize(resource_path, parameters = {})
|
23
|
+
@resource_path = resource_path
|
24
|
+
@parameters = parameters
|
25
|
+
end
|
26
|
+
|
27
|
+
# Perform a GET request against the API endpoint and return the raw
|
28
|
+
# response data
|
29
|
+
def get
|
30
|
+
Net::HTTP.get(endpoint_uri)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parameters # :nodoc:
|
34
|
+
@parameters.merge(:api_key => Etsy.api_key, :detail_level => 'high')
|
35
|
+
end
|
36
|
+
|
37
|
+
def query # :nodoc:
|
38
|
+
parameters.map {|k,v| "#{k}=#{v}"}.join('&')
|
39
|
+
end
|
40
|
+
|
41
|
+
def endpoint_uri # :nodoc:
|
42
|
+
uri = URI.parse("#{self.class.base_url}#{@resource_path}")
|
43
|
+
uri.query = query
|
44
|
+
uri
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|