shopify_api 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,10 @@
1
+ == Version 2.2.0
2
+
3
+ * Fix issues with resources that have both direct and namespaced routes
4
+ * Added detailed logger to help with debugging ActiveResource
5
+ requests/responses
6
+ * Add fulfillment#cancel
7
+
1
8
  == Version 2.1.0
2
9
 
3
10
  * Fix JSON errors handling
@@ -2,15 +2,30 @@ require 'active_support/core_ext/module/aliasing'
2
2
 
3
3
  module ActiveResource
4
4
  class Connection
5
-
5
+
6
6
  attr_reader :response
7
-
7
+
8
8
  def handle_response_with_response_capture(response)
9
9
  @response = handle_response_without_response_capture(response)
10
10
  end
11
-
11
+
12
+ def request_with_detailed_log_subscriber(method, path, *arguments)
13
+ result = request_without_detailed_log_subscriber(method, path, *arguments)
14
+ detailed_log_subscriber(result, arguments)
15
+ result
16
+ rescue => e
17
+ detailed_log_subscriber(e.response, arguments) if e.respond_to?(:response)
18
+ raise
19
+ end
20
+
21
+ def detailed_log_subscriber(response, arguments)
22
+ ActiveSupport::Notifications.instrument("request.active_resource_detailed") do |payload|
23
+ payload[:response] = response
24
+ payload[:data] = arguments
25
+ end
26
+ end
27
+
12
28
  alias_method_chain :handle_response, :response_capture
13
- # alias_method :handle_response_without_instance, :handle_response
14
- # alias_method :handle_response, :handle_response_with_instance
29
+ alias_method_chain :request, :detailed_log_subscriber
15
30
  end
16
- end
31
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveResource
2
+ class DetailedLogSubscriber < ActiveSupport::LogSubscriber
3
+ def request(event)
4
+ data = event.payload[:data]
5
+ headers = data.extract_options!
6
+ request_body = data.first
7
+
8
+ info "Request:\n#{request_body}" if request_body
9
+ info "Headers: #{headers.inspect}"
10
+ info "Response:\n#{event.payload[:response].body}"
11
+ end
12
+
13
+ def logger
14
+ ActiveResource::Base.logger
15
+ end
16
+ end
17
+ end
18
+
19
+ ActiveResource::DetailedLogSubscriber.attach_to :active_resource_detailed
@@ -0,0 +1,8 @@
1
+ module DisablePrefixCheck
2
+ extend ActiveSupport::Concern
3
+
4
+ module ClassMethods
5
+ def check_prefix_options(options)
6
+ end
7
+ end
8
+ end
data/lib/shopify_api.rb CHANGED
@@ -5,9 +5,11 @@ require 'active_support/core_ext/class/attribute_accessors'
5
5
  require 'digest/md5'
6
6
  require 'base64'
7
7
  require 'active_resource/connection_ext'
8
+ require 'active_resource/detailed_log_subscriber'
8
9
  require 'shopify_api/limits'
9
10
  require 'shopify_api/json_format'
10
11
  require 'active_resource/json_errors'
12
+ require 'active_resource/disable_prefix_check'
11
13
 
12
14
  module ShopifyAPI
13
15
  include Limits
@@ -32,6 +32,8 @@ module ShopifyAPI
32
32
  # the value will be copied:
33
33
  # asset.source_key = "assets/another_image.png"
34
34
  class Asset < Base
35
+ include DisablePrefixCheck
36
+
35
37
  self.primary_key = 'key'
36
38
  self.prefix = "/admin/themes/:theme_id/"
37
39
 
@@ -2,5 +2,10 @@ module ShopifyAPI
2
2
  class Base < ActiveResource::Base
3
3
  extend Countable
4
4
  self.include_root_in_json = false
5
+
6
+ private
7
+ def only_id
8
+ encode(:only => :id, :include => [], :methods => [])
9
+ end
5
10
  end
6
11
  end
@@ -5,9 +5,5 @@ module ShopifyAPI
5
5
  def approve; load_attributes_from_response(post(:approve, {}, only_id)); end
6
6
  def restore; load_attributes_from_response(post(:restore, {}, only_id)); end
7
7
  def not_spam; load_attributes_from_response(post(:not_spam, {}, only_id)); end
8
-
9
- def only_id
10
- encode(:only => :id)
11
- end
12
8
  end
13
9
  end
@@ -1,5 +1,7 @@
1
1
  module ShopifyAPI
2
2
  class Event < Base
3
+ include DisablePrefixCheck
4
+
3
5
  self.prefix = "/admin/:resource/:resource_id/"
4
6
 
5
7
  # Hack to allow both Shop and other Events in through the same AR class
@@ -1,5 +1,7 @@
1
1
  module ShopifyAPI
2
2
  class Fulfillment < Base
3
3
  self.prefix = "/admin/orders/:order_id/"
4
+
5
+ def cancel; load_attributes_from_response(post(:cancel, {}, only_id)); end
4
6
  end
5
7
  end
@@ -1,5 +1,7 @@
1
1
  module ShopifyAPI
2
2
  class Metafield < Base
3
+ include DisablePrefixCheck
4
+
3
5
  self.prefix = "/admin/:resource/:resource_id/"
4
6
 
5
7
  # Hack to allow both Shop and other Metafields in through the same AR class
@@ -17,9 +17,5 @@ module ShopifyAPI
17
17
  def capture(amount = "")
18
18
  Transaction.create(:amount => amount, :kind => "capture", :order_id => id)
19
19
  end
20
-
21
- def only_id
22
- encode(:only => :id, :include => [], :methods => [], :fields => [])
23
- end
24
20
  end
25
21
  end
@@ -1,6 +1,7 @@
1
1
  module ShopifyAPI
2
2
  class Variant < Base
3
3
  include Metafields
4
+ include DisablePrefixCheck
4
5
 
5
6
  self.prefix = "/admin/products/:product_id/"
6
7
 
data/shopify_api.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{shopify_api}
5
- s.version = "2.1.0"
5
+ s.version = "2.2.0"
6
6
  s.author = "Shopify"
7
7
 
8
8
  s.summary = %q{The Shopify API gem is a lightweight gem for accessing the Shopify admin REST web services}
@@ -27,7 +27,9 @@ Gem::Specification.new do |s|
27
27
 
28
28
  if s.respond_to?(:add_development_dependency)
29
29
  s.add_development_dependency("mocha", ">= 0.9.8")
30
+ s.add_development_dependency("fakeweb")
30
31
  else
31
32
  s.add_dependency("mocha", ">= 0.9.8")
33
+ s.add_dependency("fakeweb")
32
34
  end
33
35
  end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+ require 'uri'
3
+
4
+ class AssetTest < Test::Unit::TestCase
5
+ def test_get_assetss
6
+ fake "themes/1/assets", :method => :get, :body => load_fixture('assets')
7
+ v = ShopifyAPI::Asset.find(:all, :params => {:theme_id => 1})
8
+ end
9
+
10
+ def test_get_asset_namespaced
11
+ fake "themes/1/assets.json?asset%5Bkey%5D=templates%2Findex.liquid&theme_id=1", :extension=> false, :method => :get, :body => load_fixture('asset')
12
+ v = ShopifyAPI::Asset.find('templates/index.liquid', :params => {:theme_id => 1})
13
+ end
14
+
15
+ def test_get_asset
16
+ fake "assets.json?asset%5Bkey%5D=templates%2Findex.liquid", :extension=> false, :method => :get, :body => load_fixture('asset')
17
+ v = ShopifyAPI::Asset.find('templates/index.liquid')
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require "active_support/log_subscriber/test_helper"
3
+
4
+ class LogSubscriberTest < Test::Unit::TestCase
5
+ include ActiveSupport::LogSubscriber::TestHelper
6
+
7
+ def setup
8
+ super
9
+ @page = { :page => { :id => 1, :title => 'Shopify API' } }.to_json
10
+
11
+ ShopifyAPI::Base.site = "http://localhost/admin"
12
+
13
+ ActiveResource::LogSubscriber.attach_to :active_resource
14
+ ActiveResource::DetailedLogSubscriber.attach_to :active_resource_detailed
15
+ end
16
+
17
+ def set_logger(logger)
18
+ ActiveResource::Base.logger = logger
19
+ end
20
+
21
+ test "logging on #find" do
22
+ fake "pages/1", :method => :get, :body => @page
23
+
24
+ ShopifyAPI::Page.find(1)
25
+
26
+ assert_equal 4, @logger.logged(:info).size
27
+ assert_equal "GET http://localhost:80/admin/pages/1.json", @logger.logged(:info)[0]
28
+ assert_match /\-\-\> 200/, @logger.logged(:info)[1]
29
+ assert_equal "Headers: {\"Accept\"=>\"application/json\"}", @logger.logged(:info)[2]
30
+ assert_equal "Response:\n{\"page\":{\"title\":\"Shopify API\",\"id\":1}}", @logger.logged(:info)[3]
31
+ end
32
+
33
+ test "logging on #find with an error" do
34
+ fake "pages/2", :method => :get, :body => nil, :status => 404
35
+
36
+ assert_raise ActiveResource::ResourceNotFound do
37
+ ShopifyAPI::Page.find(2)
38
+ end
39
+
40
+ assert_equal 4, @logger.logged(:info).size
41
+ assert_equal "GET http://localhost:80/admin/pages/2.json", @logger.logged(:info)[0]
42
+ assert_match /\-\-\> 404/, @logger.logged(:info)[1]
43
+ assert_equal "Headers: {\"Accept\"=>\"application/json\"}", @logger.logged(:info)[2]
44
+ assert_equal "Response:", @logger.logged(:info)[3]
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "asset": {
3
+ "created_at": "2010-07-12T15:31:50-04:00",
4
+ "updated_at": "2010-07-12T15:31:50-04:00",
5
+ "public_url": null,
6
+ "value": "<!-- LIST 3 PER ROW -->\n<h2>Featured Products</h2>\n<table id=\"products\" cellspacing=\"0\" cellpadding=\"0\">\n{% tablerow product in collections.frontpage.products cols:3 %}\n <a href=\"{{product.url}}\">{{ product.featured_image | product_img_url: 'small' | img_tag }}</a>\n <h3><a href=\"{{product.url}}\">{{product.title}}</a></h3>\n <ul class=\"attributes\">\n <li><span class=\"money\">{{product.price_min | money}}</span></li>\n </ul>\n{% endtablerow %}\n</table>\n<!-- /LIST 3 PER ROW -->\n\n <div id=\"articles\">\n \t{% assign article = pages.frontpage %}\n\n <div class=\"article\">\n {% if article.content != \"\" %}\n\t\t <h3>{{ article.title }}</h3>\n <div class=\"article-body textile\">\n \t\t {{ article.content }}\n \t\t</div>\n \t{% else %}\n <div class=\"article-body textile\">\n \t In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br />\n \t {{ \"Learn more about handles\" | link_to \"http://wiki.shopify.com/Handle\" }}\n </div>\n \t{% endif %}\n </div>\n\n </div>\n\n",
7
+ "key": "templates/index.liquid"
8
+ }
9
+ }
@@ -0,0 +1,136 @@
1
+ {
2
+ "assets": [
3
+ {
4
+ "created_at": "2010-07-12T15:31:50-04:00",
5
+ "updated_at": "2010-07-12T15:31:50-04:00",
6
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-body-green.gif?1",
7
+ "key": "assets/bg-body-green.gif"
8
+ },
9
+ {
10
+ "created_at": "2010-07-12T15:31:50-04:00",
11
+ "updated_at": "2010-07-12T15:31:50-04:00",
12
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-body-orange.gif?1",
13
+ "key": "assets/bg-body-orange.gif"
14
+ },
15
+ {
16
+ "created_at": "2010-07-12T15:31:50-04:00",
17
+ "updated_at": "2010-07-12T15:31:50-04:00",
18
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-body-pink.gif?1",
19
+ "key": "assets/bg-body-pink.gif"
20
+ },
21
+ {
22
+ "created_at": "2010-07-12T15:31:50-04:00",
23
+ "updated_at": "2010-07-12T15:31:50-04:00",
24
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-body.gif?1",
25
+ "key": "assets/bg-body.gif"
26
+ },
27
+ {
28
+ "created_at": "2010-07-12T15:31:50-04:00",
29
+ "updated_at": "2010-07-12T15:31:50-04:00",
30
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-content.gif?1",
31
+ "key": "assets/bg-content.gif"
32
+ },
33
+ {
34
+ "created_at": "2010-07-12T15:31:50-04:00",
35
+ "updated_at": "2010-07-12T15:31:50-04:00",
36
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-footer.gif?1",
37
+ "key": "assets/bg-footer.gif"
38
+ },
39
+ {
40
+ "created_at": "2010-07-12T15:31:50-04:00",
41
+ "updated_at": "2010-07-12T15:31:50-04:00",
42
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-main.gif?1",
43
+ "key": "assets/bg-main.gif"
44
+ },
45
+ {
46
+ "created_at": "2010-07-12T15:31:50-04:00",
47
+ "updated_at": "2010-07-12T15:31:50-04:00",
48
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/bg-sidebar.gif?1",
49
+ "key": "assets/bg-sidebar.gif"
50
+ },
51
+ {
52
+ "created_at": "2010-07-12T15:31:50-04:00",
53
+ "updated_at": "2010-07-12T15:31:50-04:00",
54
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/shop.css?1",
55
+ "key": "assets/shop.css"
56
+ },
57
+ {
58
+ "created_at": "2010-07-12T15:31:50-04:00",
59
+ "updated_at": "2010-07-12T15:31:50-04:00",
60
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/shop.css.liquid?1",
61
+ "key": "assets/shop.css.liquid"
62
+ },
63
+ {
64
+ "created_at": "2010-07-12T15:31:50-04:00",
65
+ "updated_at": "2010-07-12T15:31:50-04:00",
66
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/shop.js?1",
67
+ "key": "assets/shop.js"
68
+ },
69
+ {
70
+ "created_at": "2010-07-12T15:31:50-04:00",
71
+ "updated_at": "2010-07-12T15:31:50-04:00",
72
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/sidebar-devider.gif?1",
73
+ "key": "assets/sidebar-devider.gif"
74
+ },
75
+ {
76
+ "created_at": "2010-07-12T15:31:50-04:00",
77
+ "updated_at": "2010-07-12T15:31:50-04:00",
78
+ "public_url": "http://static.shopify.com/s/files/1/6909/3384/t/1/assets/sidebar-menu.jpg?1",
79
+ "key": "assets/sidebar-menu.jpg"
80
+ },
81
+ {
82
+ "created_at": "2010-07-12T15:31:50-04:00",
83
+ "updated_at": "2010-07-12T15:31:50-04:00",
84
+ "public_url": null,
85
+ "key": "config/settings.html"
86
+ },
87
+ {
88
+ "created_at": "2010-07-12T15:31:50-04:00",
89
+ "updated_at": "2010-07-12T15:31:50-04:00",
90
+ "public_url": null,
91
+ "key": "layout/theme.liquid"
92
+ },
93
+ {
94
+ "created_at": "2010-07-12T15:31:50-04:00",
95
+ "updated_at": "2010-07-12T15:31:50-04:00",
96
+ "public_url": null,
97
+ "key": "templates/article.liquid"
98
+ },
99
+ {
100
+ "created_at": "2010-07-12T15:31:50-04:00",
101
+ "updated_at": "2010-07-12T15:31:50-04:00",
102
+ "public_url": null,
103
+ "key": "templates/blog.liquid"
104
+ },
105
+ {
106
+ "created_at": "2010-07-12T15:31:50-04:00",
107
+ "updated_at": "2010-07-12T15:31:50-04:00",
108
+ "public_url": null,
109
+ "key": "templates/cart.liquid"
110
+ },
111
+ {
112
+ "created_at": "2010-07-12T15:31:50-04:00",
113
+ "updated_at": "2010-07-12T15:31:50-04:00",
114
+ "public_url": null,
115
+ "key": "templates/collection.liquid"
116
+ },
117
+ {
118
+ "created_at": "2010-07-12T15:31:50-04:00",
119
+ "updated_at": "2010-07-12T15:31:50-04:00",
120
+ "public_url": null,
121
+ "key": "templates/index.liquid"
122
+ },
123
+ {
124
+ "created_at": "2010-07-12T15:31:50-04:00",
125
+ "updated_at": "2010-07-12T15:31:50-04:00",
126
+ "public_url": null,
127
+ "key": "templates/page.liquid"
128
+ },
129
+ {
130
+ "created_at": "2010-07-12T15:31:50-04:00",
131
+ "updated_at": "2010-07-12T15:31:50-04:00",
132
+ "public_url": null,
133
+ "key": "templates/product.liquid"
134
+ }
135
+ ]
136
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "events": [
3
+ {
4
+ "verb": "placed",
5
+ "created_at": "2008-01-10T11:00:00-05:00",
6
+ "body": null,
7
+ "subject_id": 450789469,
8
+ "id": 852065041,
9
+ "subject_type": "Order",
10
+ "message": "Order was placed"
11
+ },
12
+ {
13
+ "verb": "confirmed",
14
+ "created_at": "2008-01-10T11:00:00-05:00",
15
+ "body": null,
16
+ "subject_id": 450789469,
17
+ "id": 164748010,
18
+ "subject_type": "Order",
19
+ "message": "Received new order <a href=\"/admin/orders/show/450789469\">#1001</a> by Bob Norman"
20
+ },
21
+ {
22
+ "verb": "authorization_success",
23
+ "created_at": "2008-01-10T11:00:00-05:00",
24
+ "body": null,
25
+ "subject_id": 450789469,
26
+ "id": 103105390,
27
+ "subject_type": "Order",
28
+ "message": "<a href=\"/admin/orders/450789469/transactions/389404469\">The customer successfully authorized us to capture 210.94 USD</a>"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "metafields": {
3
+ "created_at": "2011-10-20T14:05:13-04:00",
4
+ "updated_at": "2011-10-20T14:05:13-04:00",
5
+ "namespace": "contact",
6
+ "id": 721389482,
7
+ "value": "123@example.com",
8
+ "description": null,
9
+ "key": "email",
10
+ "value_type": "string"
11
+ }
12
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "metafields": [
3
+ {
4
+ "created_at": "2011-10-20T14:05:13-04:00",
5
+ "updated_at": "2011-10-20T14:05:13-04:00",
6
+ "namespace": "affiliates",
7
+ "id": 721389482,
8
+ "value": "app_key",
9
+ "description": null,
10
+ "key": "app_key",
11
+ "value_type": "string"
12
+ },
13
+ {
14
+ "created_at": "2011-10-20T14:05:13-04:00",
15
+ "updated_at": "2011-10-20T14:05:13-04:00",
16
+ "namespace": "contact",
17
+ "id": 721389480,
18
+ "value": "1231231231",
19
+ "description": null,
20
+ "key": "phone",
21
+ "value_type": "string"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,112 @@
1
+ {
2
+ "product": {
3
+ "product_type": "Cult Products",
4
+ "handle": "ipod-nano",
5
+ "created_at": "2011-10-20T14:05:13-04:00",
6
+ "body_html": "<p>It's the small iPod with one very big idea: Video. Now the world's most popular music player, available in 4GB and 8GB models, lets you enjoy TV shows, movies, video podcasts, and more. The larger, brighter display means amazing picture quality. In six eye-catching colors, iPod nano is stunning all around. And with models starting at just $149, little speaks volumes.</p>",
7
+ "title": "IPod Nano - 8GB",
8
+ "template_suffix": null,
9
+ "updated_at": "2011-10-20T14:05:13-04:00",
10
+ "id": 632910392,
11
+ "tags": "Emotive, Flash Memory, MP3, Music",
12
+ "images": [
13
+ {
14
+ "position": 1,
15
+ "created_at": "2011-10-20T14:05:13-04:00",
16
+ "product_id": 632910392,
17
+ "updated_at": "2011-10-20T14:05:13-04:00",
18
+ "src": "http://static.shopify.com/s/files/1/6909/3384/products/ipod-nano.png?0",
19
+ "id": 850703190
20
+ }
21
+ ],
22
+ "variants": [
23
+ {
24
+ "position": 1,
25
+ "price": "199.00",
26
+ "created_at": "2011-10-20T14:05:13-04:00",
27
+ "requires_shipping": true,
28
+ "title": "Pink",
29
+ "inventory_quantity": 10,
30
+ "compare_at_price": null,
31
+ "inventory_policy": "continue",
32
+ "updated_at": "2011-10-20T14:05:13-04:00",
33
+ "inventory_management": "shopify",
34
+ "id": 808950810,
35
+ "taxable": true,
36
+ "grams": 200,
37
+ "sku": "IPOD2008PINK",
38
+ "option1": "Pink",
39
+ "fulfillment_service": "manual",
40
+ "option2": null,
41
+ "option3": null
42
+ },
43
+ {
44
+ "position": 2,
45
+ "price": "199.00",
46
+ "created_at": "2011-10-20T14:05:13-04:00",
47
+ "requires_shipping": true,
48
+ "title": "Red",
49
+ "inventory_quantity": 20,
50
+ "compare_at_price": null,
51
+ "inventory_policy": "continue",
52
+ "updated_at": "2011-10-20T14:05:13-04:00",
53
+ "inventory_management": "shopify",
54
+ "id": 49148385,
55
+ "taxable": true,
56
+ "grams": 200,
57
+ "sku": "IPOD2008RED",
58
+ "option1": "Red",
59
+ "fulfillment_service": "manual",
60
+ "option2": null,
61
+ "option3": null
62
+ },
63
+ {
64
+ "position": 3,
65
+ "price": "199.00",
66
+ "created_at": "2011-10-20T14:05:13-04:00",
67
+ "requires_shipping": true,
68
+ "title": "Green",
69
+ "inventory_quantity": 30,
70
+ "compare_at_price": null,
71
+ "inventory_policy": "continue",
72
+ "updated_at": "2011-10-20T14:05:13-04:00",
73
+ "inventory_management": "shopify",
74
+ "id": 39072856,
75
+ "taxable": true,
76
+ "grams": 200,
77
+ "sku": "IPOD2008GREEN",
78
+ "option1": "Green",
79
+ "fulfillment_service": "manual",
80
+ "option2": null,
81
+ "option3": null
82
+ },
83
+ {
84
+ "position": 4,
85
+ "price": "199.00",
86
+ "created_at": "2011-10-20T14:05:13-04:00",
87
+ "requires_shipping": true,
88
+ "title": "Black",
89
+ "inventory_quantity": 40,
90
+ "compare_at_price": null,
91
+ "inventory_policy": "continue",
92
+ "updated_at": "2011-10-20T14:05:13-04:00",
93
+ "inventory_management": "shopify",
94
+ "id": 457924702,
95
+ "taxable": true,
96
+ "grams": 200,
97
+ "sku": "IPOD2008BLACK",
98
+ "option1": "Black",
99
+ "fulfillment_service": "manual",
100
+ "option2": null,
101
+ "option3": null
102
+ }
103
+ ],
104
+ "vendor": "Apple",
105
+ "published_at": "2007-12-31T19:00:00-05:00",
106
+ "options": [
107
+ {
108
+ "name": "Title"
109
+ }
110
+ ]
111
+ }
112
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "shop": {
3
+ "name": "Apple Computers",
4
+ "city": "Cupertino",
5
+ "address1": "1 Infinite Loop",
6
+ "zip": "95014",
7
+ "created_at": "2007-12-31T19:00:00-05:00",
8
+ "shop_owner": "Steve Jobs",
9
+ "plan_name": "enterprise",
10
+ "public": false,
11
+ "country": "US",
12
+ "money_with_currency_format": "$ {{amount}} USD",
13
+ "money_format": "$ {{amount}}",
14
+ "domain": "shop.apple.com",
15
+ "taxes_included": null,
16
+ "id": 690933842,
17
+ "timezone": "(GMT-05:00) Eastern Time (US & Canada)",
18
+ "tax_shipping": null,
19
+ "phone": null,
20
+ "currency": "USD",
21
+ "myshopify_domain": "apple.myshopify.com",
22
+ "source": null,
23
+ "province": "CA",
24
+ "email": "steve@apple.com"
25
+ }
26
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "variant": {
3
+ "price": "199.00",
4
+ "position": 1,
5
+ "created_at": "2011-10-20T14:05:13-04:00",
6
+ "title": "Pink",
7
+ "requires_shipping": true,
8
+ "updated_at": "2011-10-20T14:05:13-04:00",
9
+ "inventory_policy": "continue",
10
+ "compare_at_price": null,
11
+ "inventory_quantity": 10,
12
+ "inventory_management": "shopify",
13
+ "taxable": true,
14
+ "id": 808950810,
15
+ "grams": 200,
16
+ "sku": "IPOD2008PINK",
17
+ "option1": "Pink",
18
+ "option2": null,
19
+ "fulfillment_service": "manual",
20
+ "option3": null
21
+ }
22
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "variants": [
3
+ {
4
+ "price": "199.00",
5
+ "position": 1,
6
+ "created_at": "2011-10-20T14:05:13-04:00",
7
+ "title": "Pink",
8
+ "requires_shipping": true,
9
+ "updated_at": "2011-10-20T14:05:13-04:00",
10
+ "inventory_policy": "continue",
11
+ "compare_at_price": null,
12
+ "inventory_quantity": 10,
13
+ "inventory_management": "shopify",
14
+ "taxable": true,
15
+ "id": 808950810,
16
+ "grams": 200,
17
+ "sku": "IPOD2008PINK",
18
+ "option1": "Pink",
19
+ "option2": null,
20
+ "fulfillment_service": "manual",
21
+ "option3": null
22
+ },
23
+ {
24
+ "price": "199.00",
25
+ "position": 2,
26
+ "created_at": "2011-10-20T14:05:13-04:00",
27
+ "title": "Red",
28
+ "requires_shipping": true,
29
+ "updated_at": "2011-10-20T14:05:13-04:00",
30
+ "inventory_policy": "continue",
31
+ "compare_at_price": null,
32
+ "inventory_quantity": 20,
33
+ "inventory_management": "shopify",
34
+ "taxable": true,
35
+ "id": 49148385,
36
+ "grams": 200,
37
+ "sku": "IPOD2008RED",
38
+ "option1": "Red",
39
+ "option2": null,
40
+ "fulfillment_service": "manual",
41
+ "option3": null
42
+ },
43
+ {
44
+ "price": "199.00",
45
+ "position": 3,
46
+ "created_at": "2011-10-20T14:05:13-04:00",
47
+ "title": "Green",
48
+ "requires_shipping": true,
49
+ "updated_at": "2011-10-20T14:05:13-04:00",
50
+ "inventory_policy": "continue",
51
+ "compare_at_price": null,
52
+ "inventory_quantity": 30,
53
+ "inventory_management": "shopify",
54
+ "taxable": true,
55
+ "id": 39072856,
56
+ "grams": 200,
57
+ "sku": "IPOD2008GREEN",
58
+ "option1": "Green",
59
+ "option2": null,
60
+ "fulfillment_service": "manual",
61
+ "option3": null
62
+ },
63
+ {
64
+ "price": "199.00",
65
+ "position": 4,
66
+ "created_at": "2011-10-20T14:05:13-04:00",
67
+ "title": "Black",
68
+ "requires_shipping": true,
69
+ "updated_at": "2011-10-20T14:05:13-04:00",
70
+ "inventory_policy": "continue",
71
+ "compare_at_price": null,
72
+ "inventory_quantity": 40,
73
+ "inventory_management": "shopify",
74
+ "taxable": true,
75
+ "id": 457924702,
76
+ "grams": 200,
77
+ "sku": "IPOD2008BLACK",
78
+ "option1": "Black",
79
+ "option2": null,
80
+ "fulfillment_service": "manual",
81
+ "option3": null
82
+ }
83
+ ]
84
+ }
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class ProductTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+
7
+ fake "products/632910392", :body => load_fixture('product')
8
+ @product = ShopifyAPI::Product.find(632910392)
9
+ end
10
+
11
+ def test_add_metafields_to_product
12
+ fake "products/632910392/metafields", :method => :post, :status => 201, :body => load_fixture('metafield')
13
+
14
+ field = @product.add_metafield(ShopifyAPI::Metafield.new(:namespace => "contact", :key => "email", :value => "123@example.com", :value_type => "string"))
15
+
16
+ assert !field.new_record?
17
+ assert_equal "contact", field.namespace
18
+ assert_equal "email", field.key
19
+ assert_equal "123@example.com", field.value
20
+ end
21
+
22
+ def test_get_metafields_for_product
23
+ fake "products/632910392/metafields", :body => load_fixture('metafields')
24
+
25
+ metafields = @product.metafields
26
+
27
+ assert_equal 2, metafields.length
28
+ assert metafields.all?{|m| m.is_a?(ShopifyAPI::Metafield)}
29
+ end
30
+ end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ShopifyApiTest < Test::Unit::TestCase
3
+ class SessionTest < Test::Unit::TestCase
4
4
 
5
5
  context "Session" do
6
6
  should "not be valid without a url" do
@@ -51,5 +51,15 @@ class ShopifyApiTest < Test::Unit::TestCase
51
51
  assert_equal 'https://key:e56d5793b869753d87cf03ceb6bb5dfc@testshop.myshopify.com/admin', assigned_site.to_s
52
52
  assert_equal 'http://www.original.com', ShopifyAPI::Base.site.to_s
53
53
  end
54
+
55
+ should "return permissions url" do
56
+ session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token")
57
+ assert_equal "http://testshop.myshopify.com/admin/api/auth?api_key=key", session.create_permission_url
58
+ end
59
+
60
+ should "return site for session" do
61
+ session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token")
62
+ assert_equal "https://key:e56d5793b869753d87cf03ceb6bb5dfc@testshop.myshopify.com/admin", session.site
63
+ end
54
64
  end
55
65
  end
data/test/shop_test.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ class ShopTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+ fake "shop"
7
+ @shop = ShopifyAPI::Shop.current
8
+ end
9
+
10
+ def test_current_should_return_current_shop
11
+ assert @shop.is_a?(ShopifyAPI::Shop)
12
+ assert_equal "Apple Computers", @shop.name
13
+ assert_equal "apple.myshopify.com", @shop.myshopify_domain
14
+ assert_equal 690933842, @shop.id
15
+ assert_equal "2007-12-31T19:00:00-05:00", @shop.created_at
16
+ assert_nil @shop.tax_shipping
17
+ end
18
+
19
+ def test_get_metafields_for_shop
20
+ fake "metafields"
21
+
22
+ metafields = @shop.metafields
23
+
24
+ assert_equal 2, metafields.length
25
+ assert metafields.all?{|m| m.is_a?(ShopifyAPI::Metafield)}
26
+ end
27
+
28
+ def test_add_metafield
29
+ fake "metafields", :method => :post, :status => 201, :body =>load_fixture('metafield')
30
+
31
+ field = @shop.add_metafield(ShopifyAPI::Metafield.new(:namespace => "contact", :key => "email", :value => "123@example.com", :value_type => "string"))
32
+
33
+ assert !field.new_record?
34
+ assert_equal "contact", field.namespace
35
+ assert_equal "email", field.key
36
+ assert_equal "123@example.com", field.value
37
+ end
38
+
39
+ def test_events
40
+ fake "events"
41
+
42
+ events = @shop.events
43
+
44
+ assert_equal 3, events.length
45
+ assert events.all?{|m| m.is_a?(ShopifyAPI::Event)}
46
+ end
47
+ end
data/test/test_helper.rb CHANGED
@@ -1,13 +1,15 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
+ require 'fakeweb'
3
4
  require 'mocha'
4
5
 
5
6
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
7
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
8
  require 'shopify_api'
8
9
 
10
+ FakeWeb.allow_net_connect = false
11
+
9
12
  # setup ShopifyAPI with fake api_key and secret
10
- ShopifyAPI::Session.setup(:api_key => "API Test key", :secret => "API Test secret")
11
13
 
12
14
  class Test::Unit::TestCase
13
15
  def self.test(string, &block)
@@ -21,9 +23,42 @@ class Test::Unit::TestCase
21
23
  def self.context(string)
22
24
  yield
23
25
  end
26
+
27
+ def setup
28
+ ActiveResource::Base.format = :json
29
+ ShopifyAPI.constants.each do |const|
30
+ begin
31
+ const = "ShopifyAPI::#{const}".constantize
32
+ const.format = :json if const.respond_to?(:format=)
33
+ rescue NameError
34
+ end
35
+ end
36
+
37
+ ShopifyAPI::Base.site = "http://localhost/admin"
38
+ ShopifyAPI::Base.password = nil
39
+ ShopifyAPI::Base.user = nil
40
+ end
41
+
42
+ def teardown
43
+ FakeWeb.clean_registry
44
+ end
24
45
 
25
46
  # Custom Assertions
26
47
  def assert_not(expression)
27
48
  assert_block("Expected <#{expression}> to be false!") { not expression }
28
- end
49
+ end
50
+
51
+ def load_fixture(name, format=:json)
52
+ File.read(File.dirname(__FILE__) + "/fixtures/#{name}.#{format}")
53
+ end
54
+
55
+ def fake(endpoint, options={})
56
+ body = options.has_key?(:body) ? options.delete(:body) : load_fixture(endpoint)
57
+ format = options.delete(:format) || :json
58
+ method = options.delete(:method) || :get
59
+ extension = ".#{options.delete(:extension)||'json'}" unless options[:extension]==false
60
+
61
+ url = "http://localhost/admin/#{endpoint}#{extension}"
62
+ FakeWeb.register_uri(method, url, {:body => body, :status => 200, :content_type => "text/#{format}", :content_length => 1}.merge(options))
63
+ end
29
64
  end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ class VariantTest < Test::Unit::TestCase
4
+
5
+ def test_get_variants
6
+ fake "products/632910392/variants", :method => :get, :body => load_fixture('variants')
7
+
8
+ v = ShopifyAPI::Variant.find(:all, :params => {:product_id => 632910392})
9
+ end
10
+
11
+ def test_get_variant_namespaced
12
+ fake "products/632910392/variants/808950810", :method => :get, :body => load_fixture('variant')
13
+
14
+ v = ShopifyAPI::Variant.find(808950810, :params => {:product_id => 632910392})
15
+ end
16
+
17
+ def test_get_variant
18
+ fake "variants/808950810", :method => :get, :body => load_fixture('variant')
19
+
20
+ v = ShopifyAPI::Variant.find(808950810)
21
+ end
22
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify_api
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 2.1.0
10
+ version: 2.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Shopify
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-17 00:00:00 -04:00
18
+ date: 2011-11-25 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -66,6 +66,20 @@ dependencies:
66
66
  version: 0.9.8
67
67
  type: :development
68
68
  version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeweb
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id004
69
83
  description: The Shopify API gem allows Ruby developers to programmatically access the admin section of Shopify stores. The API is implemented as JSON or XML over HTTP using all four verbs (GET/POST/PUT/DELETE). Each resource, like Order, Product, or Collection, has its own URL and is manipulated in isolation.
70
84
  email: developers@jadedpixel.com
71
85
  executables:
@@ -86,6 +100,8 @@ files:
86
100
  - Rakefile
87
101
  - bin/shopify
88
102
  - lib/active_resource/connection_ext.rb
103
+ - lib/active_resource/detailed_log_subscriber.rb
104
+ - lib/active_resource/disable_prefix_check.rb
89
105
  - lib/active_resource/json_errors.rb
90
106
  - lib/shopify_api.rb
91
107
  - lib/shopify_api/cli.rb
@@ -137,11 +153,25 @@ files:
137
153
  - lib/shopify_api/resources/webhook.rb
138
154
  - lib/shopify_api/session.rb
139
155
  - shopify_api.gemspec
156
+ - test/asset_test.rb
140
157
  - test/cli_test.rb
158
+ - test/detailed_log_subscriber_test.rb
159
+ - test/fixtures/asset.json
160
+ - test/fixtures/assets.json
161
+ - test/fixtures/events.json
162
+ - test/fixtures/metafield.json
163
+ - test/fixtures/metafields.json
164
+ - test/fixtures/product.json
165
+ - test/fixtures/shop.json
166
+ - test/fixtures/variant.json
167
+ - test/fixtures/variants.json
141
168
  - test/limits_test.rb
142
169
  - test/order_test.rb
143
- - test/shopify_api_test.rb
170
+ - test/product_test.rb
171
+ - test/session_test.rb
172
+ - test/shop_test.rb
144
173
  - test/test_helper.rb
174
+ - test/variant_test.rb
145
175
  has_rdoc: true
146
176
  homepage: http://www.shopify.com/partners/apps
147
177
  licenses: