ecwid_api 0.0.1 → 0.0.2

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.
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