ecwid_api 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f75df6f53fd6f55913cf94526d41c5cf68272ebc
4
- data.tar.gz: e1a2a10f1141300974719d4998c962c617ce44c3
3
+ metadata.gz: 67727922f8d2fc5ab19839abda31f4ae709b67e8
4
+ data.tar.gz: 8e78ebe2a0dc6e83da2a9235e08a57704a04b9c4
5
5
  SHA512:
6
- metadata.gz: 43e85267b0ff0a21482048c8436dc460e3045305acf73d876e0e329f8c7e90b3b62e0f76b341574735fa27e914d04ad7df7950dc44446ecd857955b54b0e6093
7
- data.tar.gz: 044b281f10380c226f1e987b771297d56fa5ee6f213ccd5f4ed771cf628d37646e9c1abae4872096f29cc384b02eb3ab4298e0bd090b4eca4ecbaff122ceb06a
6
+ metadata.gz: f8e57e93e2c5fc0e4109955f3a1aefe311e5cf9edd868a8fb0a5feb1bca59e06eb81d07161b2f53af4c426b9eff96eacc9a4bee59adfb79c7bd4db3b82bbbe9b
7
+ data.tar.gz: 5065b8ba1deff18ee542f71c68ec6b478859e19fc1ca079a419cd46dac3295c6df934c9befc467d80b46fa178b6cbbb327bf82cd7a5f309e8d060a364b521509
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A gem to interface with the Ecwid REST APIs.
4
4
 
5
+ [![Code Climate](https://codeclimate.com/github/davidbiehl/ecwid_api.png)](https://codeclimate.com/github/davidbiehl/ecwid_api)
6
+
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
@@ -32,10 +34,62 @@ to be configured for each new `Client`.
32
34
  config.product_secret_key = 'PRODUCT_SECRET_KEY'
33
35
  end
34
36
 
35
- ### Make some Requests
37
+ ## APIs
38
+
39
+ ### Category API
40
+
41
+ The Category API will allow you to access the categories for an Ecwid store.
42
+ An instance of the Category API is available on the client.
43
+
44
+ api = client.categories
45
+ # => #<EcwidApi::CategoryApi>
46
+
47
+ api.all
48
+ # Returns an Array of all of the `EcwidApi::Category` objects
49
+
50
+ api.root
51
+ # Returns an Array of the top-level `EcwidApi::Category` objects for the
52
+ # store
53
+
54
+ api.find(123)
55
+ # Returns the `EcwidApi::Category` with an ID of 123
56
+
57
+ #### EcwidApi::Category Objects
58
+
59
+ The properties of an `EcwidApi::Category` object can be accessed using the `[]`
60
+ method, or with special snake_cased helper methods.
61
+
62
+ cat = client.categories.find(123)
63
+ # An example response from the API
64
+ # {
65
+ # "id": 123,
66
+ # "parentId": 456,
67
+ # "name": "Special Category"
68
+ # }
69
+
70
+ cat[:id] # Access with a Symbol
71
+ # => 123
72
+
73
+ cat["parentId"] # Access with a String (case sensitive)
74
+ # => 456
75
+
76
+ cat.parent_id # Access with a snake_case method
77
+ # => 456
78
+
79
+ Each `EcwidApi::Category` also has methods to find any sub-categories, and the
80
+ parent category, if there is one.
81
+
82
+ cat.parent
83
+ # Returns the parent `EcwidApi::Category`
84
+
85
+ cat.sub_categories
86
+ # Returns an Array of `EcwidApi::Category`
87
+
88
+ ### Making Ad-Hoc Requests with the Client
36
89
 
37
90
  To make a request, simply call the `#get` method on the client passing in the
38
- API and any parameters it requires. For example, to get some categories:
91
+ relative path and any parameters it requires.
92
+ For example, to get some categories:
39
93
 
40
94
  # GET https://app.ecwid.com/api/v1/[STORE-ID]/categories?parent=1
41
95
 
@@ -44,16 +98,16 @@ API and any parameters it requires. For example, to get some categories:
44
98
  # => #<Faraday::Response>
45
99
 
46
100
  The `Client` is responsible for making raw requests, which is why it returns
47
- a `Faraday::Response`. Eventually there will be a domain model to bury this
48
- detail under an abstraction. In the meantime, please see the
49
- [Faraday documentation](https://github.com/lostisland/faraday)
50
- to learn how to use the `Faraday::Response` object.
101
+ a `Faraday::Response`. The JSON parsing middleware is also active on the Faraday
102
+ connection, so calling `Faraday::Response#body` will return a Hash of the parsed
103
+ JSON.
51
104
 
52
105
  ### Ecwid API Documentation
53
106
 
54
107
  The [Ecwid API documentation](http://kb.ecwid.com/w/page/25232810/API)
55
- should give you a good idea of what is possible to retreive. Please note that
56
- resources requiring the secret keys will be inaccessible until we implement
108
+ should give you a good idea of what is possible to retreive. It also defines
109
+ which properties are available on each of the entities it provies. Please note
110
+ that resources requiring the secret keys will be inaccessible until we implement
57
111
  that feature.
58
112
 
59
113
  ## Contributing
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rspec", "~> 2.14.1"
23
23
 
24
24
  spec.add_dependency "faraday", "~> 0.9.0"
25
+ spec.add_dependency "faraday_middleware", "~> 0.9.1"
25
26
  end
@@ -1,4 +1,5 @@
1
1
  require "ecwid_api/version"
2
+ require "ext/string"
2
3
 
3
4
  # Public: This is the main namespace for the EcwidApi. It can be used to store
4
5
  # the default client.
@@ -6,6 +7,10 @@ require "ecwid_api/version"
6
7
  module EcwidApi
7
8
  autoload :Client, "ecwid_api/client"
8
9
  autoload :Error, "ecwid_api/error"
10
+ autoload :Entity, "ecwid_api/entity"
11
+
12
+ autoload :CategoryApi, "ecwid_api/category_api"
13
+ autoload :Category, "ecwid_api/category"
9
14
 
10
15
  class << self
11
16
  # Public: Gets and configures a default client
@@ -0,0 +1,14 @@
1
+ module EcwidApi
2
+ class Category < Entity
3
+ # Public: Returns an Array of sub categories for the Category
4
+ def sub_categories
5
+ @sub_categories ||= client.categories.all(id)
6
+ end
7
+
8
+ # Public: Returns the parent EcwidApi::Category, or nil if there isn't one
9
+ def parent
10
+ parent_id = data["parentId"]
11
+ client.categories.find(parent_id) if parent_id
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ module EcwidApi
2
+ # Public: This is the Ecwid API for Categories. It abstracts the end-points
3
+ # of the Ecwid API that deal with categories.
4
+ class CategoryApi
5
+ # Private: Gets the Client
6
+ attr_reader :client
7
+ private :client
8
+
9
+ # Public: Initializes a new EcwidApi::CategoryApi
10
+ #
11
+ # client - The EcwidApi::Client to use with the API
12
+ #
13
+ def initialize(client = EcwidApi.default_client)
14
+ @client = client
15
+ raise Error.new("The client cannot be nil") unless client
16
+ end
17
+
18
+ # Public: Returns all of the sub-categories for a given category
19
+ #
20
+ # See: http://kb.ecwid.com/w/page/25285101/Product%20API#RESTAPIMethodcategories
21
+ #
22
+ # parent - The Category ID of the parent category. If the parent is 0 then
23
+ # a list of the root categories will be returned. If the parent is
24
+ # nil, then all of the categories will be returned
25
+ #
26
+ # Returns an array of EcwidApi::Category objects
27
+ def all(parent = nil)
28
+ params = {}
29
+ params[:parent] = parent if parent
30
+
31
+ response = client.get("categories", params)
32
+
33
+ if response.success?
34
+ response.body
35
+ else
36
+ []
37
+ end.map {|category| Category.new(category, client: client) }
38
+ end
39
+
40
+ # Public: Returns an Array of the root level EcwidApi::Category objects
41
+ def root
42
+ all(0)
43
+ end
44
+
45
+ # Public: Returns a single EcwidApi::Category
46
+ #
47
+ # See: http://kb.ecwid.com/w/page/25285101/Product%20API#RESTAPIMethodcategory
48
+ #
49
+ # category_id - A Category ID to get
50
+ #
51
+ # Returns an EcwidApi::Category, or nil if it can't be found
52
+ def find(category_id)
53
+ response = client.get("category", id: category_id)
54
+
55
+ if response.success?
56
+ Category.new(response.body, client: client)
57
+ else
58
+ nil
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,4 +1,5 @@
1
1
  require 'faraday'
2
+ require 'faraday_middleware'
2
3
 
3
4
  module EcwidApi
4
5
  # Public: Client objects manage the connection and interface to a single Ecwid
@@ -69,6 +70,11 @@ module EcwidApi
69
70
  connection.get(path, params)
70
71
  end
71
72
 
73
+ # Public: Returns the Category API
74
+ def categories
75
+ @categories ||= CategoryApi.new(self)
76
+ end
77
+
72
78
  private
73
79
 
74
80
  # Private: Resets the connection.
@@ -80,7 +86,10 @@ module EcwidApi
80
86
 
81
87
  # Private: Returns a Faraday connection to interface with the Ecwid API
82
88
  def connection
83
- @connection ||= Faraday.new(url: store_url)
89
+ @connection ||= Faraday.new store_url do |conn|
90
+ conn.response :json, content_type: /\bjson$/
91
+ conn.adapter Faraday.default_adapter
92
+ end
84
93
  end
85
94
  end
86
95
  end
@@ -0,0 +1,67 @@
1
+ module EcwidApi
2
+ class Entity
3
+ # Private: Gets the Client
4
+ attr_reader :client
5
+ private :client
6
+
7
+ # Private: Gets the Hash of data
8
+ attr_reader :data
9
+ private :data
10
+
11
+ # Public: Initialize a new entity with a reference to the client and data
12
+ #
13
+ # data - A Hash of data that represents the properties of this Entity
14
+ # opts - A Hash of options
15
+ # :client - The EcwidApi::Client creating the Entity
16
+ #
17
+ def initialize(data, opts={})
18
+ @client, @data = opts[:client], data
19
+ end
20
+
21
+ # Public: Returns a property of the data (actual property name)
22
+ #
23
+ # key - A Symbol or String of the property. The key should be the actual
24
+ # key according to the Ecwid API documentation for the given entity.
25
+ # Typically, this is camel cased.
26
+ #
27
+ # Examples
28
+ #
29
+ # entity[:parentId]
30
+ # entity["parentId"]
31
+ #
32
+ # Returns the value of the property, or nil if it doesn't exist
33
+ def [](key)
34
+ data[key.to_s]
35
+ end
36
+
37
+ # Public: Get a property of the data (snake_case)
38
+ #
39
+ # This is used as a helper to allow easy access to the data. It will work
40
+ # with both CamelCased and snake_case keys. For example, if the data
41
+ # contains a "parentId" key, then calling `entity.parent_id` should work.
42
+ #
43
+ # This will NOT return null of the property doesn't exist on the data!
44
+ #
45
+ # Examples
46
+ #
47
+ # entity.parent_id # same as `entity["parentId"]`
48
+ #
49
+ # TODO: #method_missing isn't the ideal solution because Ecwid will only
50
+ # return a property if it doesn't have a null value. An example of this are
51
+ # the top level categories. They don't have a parentId, so that property
52
+ # is ommitted from the API response. Calling `category.parent_id` will
53
+ # result in an "undefined method `parent_id'". However, calling `#parent_id`
54
+ # on any other category will work.
55
+ #
56
+ # Returns the value of the property
57
+ def method_missing(method, *args)
58
+ method_string = method.to_s
59
+
60
+ [ method_string, method_string.camel_case ].each do |key|
61
+ return data[key] if data.has_key?(key)
62
+ end
63
+
64
+ super method, *args
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module EcwidApi
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def camel_case
3
+ split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::CategoryApi, faraday: true do
4
+ let(:client) { EcwidApi::Client.new { |config| config.store_id = '12345' } }
5
+ subject { EcwidApi::CategoryApi.new(client) }
6
+
7
+ before(:each) do
8
+ faraday_client(client)
9
+ end
10
+
11
+ describe "#all" do
12
+ it "gets all of the categories from the client" do
13
+ expect(client).to receive(:get).with("categories", {}).and_call_original
14
+ subject.all
15
+ end
16
+
17
+ it "gets sub categories" do
18
+ expect(client).to receive(:get).with("categories", parent: 5).and_call_original
19
+ subject.all(5)
20
+ end
21
+ end
22
+
23
+ describe "#root" do
24
+ it "gets the root level categories" do
25
+ expect(subject).to receive(:all).with(0).and_call_original
26
+ subject.root
27
+ end
28
+ end
29
+
30
+ describe "#find" do
31
+ it "finds a single category" do
32
+ expect(client).to receive(:get).with("category", id: 5).and_call_original
33
+ subject.find(5)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Category, faraday: true do
4
+ let(:client) { EcwidApi::Client.new { |config| config.store_id = '12345' } }
5
+ subject { EcwidApi::Category.new({"id" => 123, "parentId" => 456}, client: client) }
6
+
7
+ before(:each) do
8
+ faraday_client(client)
9
+ end
10
+
11
+ describe "#sub_categories" do
12
+ it "sends the request to the CategoryApi" do
13
+ expect(client.categories).to receive(:all).with(123)
14
+ subject.sub_categories
15
+ end
16
+
17
+ it "is memoized" do
18
+ subject.sub_categories
19
+ expect(client.categories).to_not receive(:all)
20
+ subject.sub_categories
21
+ end
22
+ end
23
+
24
+ describe "#parent" do
25
+ it "sends the request for the parent to the CategoryApi" do
26
+ expect(client.categories).to receive(:find).with(456)
27
+ subject.parent
28
+ end
29
+
30
+ context "without a parent" do
31
+ subject { EcwidApi::Category.new({"id" => 123}) }
32
+
33
+ it "returns nil" do
34
+ expect(client.categories).to_not receive(:find)
35
+ subject.parent.should be_nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -31,21 +31,9 @@ describe EcwidApi::Client do
31
31
  its(:store_url) { "http://app.ecwid.com/api/v1/12345" }
32
32
  end
33
33
 
34
- describe "#get" do
35
- let(:faraday_stubs) do
36
- Faraday::Adapter::Test::Stubs.new do |stub|
37
- stub.get('categories') { [200, {}, '[]'] }
38
- end
39
- end
40
-
41
- let(:faraday) do
42
- Faraday::new do |builder|
43
- builder.adapter :test, faraday_stubs
44
- end
45
- end
46
-
34
+ describe "#get", faraday: true do
47
35
  before(:each) do
48
- allow(subject).to receive(:connection).and_return(faraday)
36
+ faraday_client(subject)
49
37
  end
50
38
 
51
39
  it "delegates to the Faraday connection" do
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Entity do
4
+ let(:data) { {"id" => 123, "parentId" => 456} }
5
+
6
+ subject { EcwidApi::Entity.new(data) }
7
+
8
+ describe "#[]" do
9
+ it "gets data with a symbol key" do
10
+ subject[:id].should == 123
11
+ end
12
+
13
+ it "gets data with a string key" do
14
+ subject["parentId"].should == 456
15
+ end
16
+ end
17
+
18
+ describe "#method_missing" do
19
+ it "gets data with snake_cased messages" do
20
+ subject.parent_id.should == 456
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "id": 9389012,
4
+ "name": "Bariatric Products",
5
+ "url": "http://www.example.com#!/~/category/id=9389012",
6
+ "productCount": 98
7
+ },
8
+ {
9
+ "id": 9389013,
10
+ "parentId": 9389012,
11
+ "name": "Aids for Daily Living",
12
+ "url": "http://www.example.com#!/~/category/id=9389013",
13
+ "productCount": 72
14
+ },
15
+ {
16
+ "id": 9389106,
17
+ "parentId": 9389012,
18
+ "name": "Mobility",
19
+ "url": "http://www.example.com#!/~/category/id=9389106",
20
+ "productCount": 12
21
+ }
22
+ ]
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": 9389013,
3
+ "parentId": 9389012,
4
+ "name": "Aids for Daily Living",
5
+ "url": "http://www.example.com#!/~/category/id=9389013",
6
+ "productCount": 72
7
+ }
@@ -0,0 +1,30 @@
1
+ require 'faraday'
2
+
3
+ module Helpers
4
+ module Faraday
5
+ def fixtures
6
+ %w(categories category)
7
+ end
8
+
9
+ def faraday_stubs
10
+ ::Faraday::Adapter::Test::Stubs.new do |stub|
11
+ fixtures.each do |fixture|
12
+ stub.get(fixture) { [ 200, {"Content-Type" => "application/json"}, File.read("spec/fixtures/#{fixture}.json") ] }
13
+ end
14
+ end
15
+ end
16
+
17
+ # Public: Returns a test Faraday::Connection
18
+ def faraday
19
+ ::Faraday.new do |builder|
20
+ builder.response :json, content_type: /\bjson$/
21
+ builder.adapter :test, faraday_stubs
22
+ end
23
+ end
24
+
25
+ # Public: Uses the Faraday stub connection with the client
26
+ def faraday_client(client)
27
+ allow(client).to receive(:connection).and_return(faraday)
28
+ end
29
+ end
30
+ end
@@ -6,12 +6,15 @@
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
 
8
8
  require "ecwid_api"
9
+ require "helpers/faraday"
9
10
 
10
11
  RSpec.configure do |config|
11
12
  config.treat_symbols_as_metadata_keys_with_true_values = true
12
13
  config.run_all_when_everything_filtered = true
13
14
  config.filter_run :focus
14
15
 
16
+ config.include Helpers::Faraday, faraday: true
17
+
15
18
  # Run specs in random order to surface order dependencies. If you find an
16
19
  # order dependency and want to debug it, you can fix the order by providing
17
20
  # the seed, which is printed after each run.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecwid_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Biehl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-06 00:00:00.000000000 Z
11
+ date: 2014-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.9.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday_middleware
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.1
69
83
  description:
70
84
  email:
71
85
  - me@davidbiehl.com
@@ -81,11 +95,21 @@ files:
81
95
  - Rakefile
82
96
  - ecwid_api.gemspec
83
97
  - lib/ecwid_api.rb
98
+ - lib/ecwid_api/category.rb
99
+ - lib/ecwid_api/category_api.rb
84
100
  - lib/ecwid_api/client.rb
101
+ - lib/ecwid_api/entity.rb
85
102
  - lib/ecwid_api/error.rb
86
103
  - lib/ecwid_api/version.rb
104
+ - lib/ext/string.rb
105
+ - spec/category_api_spec.rb
106
+ - spec/category_spec.rb
87
107
  - spec/client_spec.rb
88
108
  - spec/ecwid_api_spec.rb
109
+ - spec/entity_spec.rb
110
+ - spec/fixtures/categories.json
111
+ - spec/fixtures/category.json
112
+ - spec/helpers/faraday.rb
89
113
  - spec/spec_helper.rb
90
114
  homepage: ''
91
115
  licenses:
@@ -112,6 +136,12 @@ signing_key:
112
136
  specification_version: 4
113
137
  summary: A client for the Ecwid REST API
114
138
  test_files:
139
+ - spec/category_api_spec.rb
140
+ - spec/category_spec.rb
115
141
  - spec/client_spec.rb
116
142
  - spec/ecwid_api_spec.rb
143
+ - spec/entity_spec.rb
144
+ - spec/fixtures/categories.json
145
+ - spec/fixtures/category.json
146
+ - spec/helpers/faraday.rb
117
147
  - spec/spec_helper.rb