agent_cooper 0.0.6 → 0.0.7.pre

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.
Files changed (60) hide show
  1. data/.gitignore +0 -1
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +2 -0
  4. data/README.md +6 -4
  5. data/Rakefile +2 -0
  6. data/agent_cooper.gemspec +16 -14
  7. data/features/finder.feature +1 -1
  8. data/features/support/env.rb +1 -5
  9. data/features/support/vcr.rb +2 -6
  10. data/lib/agent_cooper.rb +13 -15
  11. data/lib/agent_cooper/builder.rb +46 -0
  12. data/lib/agent_cooper/config.rb +6 -1
  13. data/lib/agent_cooper/request.rb +54 -30
  14. data/lib/agent_cooper/requests/finder.rb +12 -15
  15. data/lib/agent_cooper/requests/merchandiser.rb +15 -16
  16. data/lib/agent_cooper/requests/shopper.rb +14 -14
  17. data/lib/agent_cooper/response.rb +9 -10
  18. data/lib/agent_cooper/synchrony.rb +22 -9
  19. data/lib/agent_cooper/version.rb +1 -1
  20. data/spec/agent_cooper/config_spec.rb +36 -0
  21. data/spec/agent_cooper/request_spec.rb +17 -106
  22. data/spec/agent_cooper/requests/finder_spec.rb +11 -8
  23. data/spec/agent_cooper/requests/merchandiser_spec.rb +13 -7
  24. data/spec/agent_cooper/requests/shopper_spec.rb +12 -7
  25. data/spec/agent_cooper/response_spec.rb +21 -53
  26. data/spec/agent_cooper_spec.rb +5 -2
  27. data/spec/fixtures/cassettes/finder/find_items_advanced/0612b88aa6d3bcece0d88b587267b6de.yml +590 -0
  28. data/spec/fixtures/cassettes/finder/find_items_by_category/e782300f74c9c6669d5c0d9719d03853.yml +420 -0
  29. data/spec/fixtures/cassettes/finder/find_items_by_keywords/a6e74b4aff9c701b73db82def8b31bc8.yml +632 -0
  30. data/spec/fixtures/cassettes/finder/find_items_by_product/9dd9b3128cbf3cda22e027207825c4c0.yml +684 -0
  31. data/spec/fixtures/cassettes/finder/find_items_in_ebay_stores/6514aa6b1db3f9fbddcfbb32b58fb67e.yml +464 -0
  32. data/spec/fixtures/cassettes/finder/get_histograms/{80bd04d96cd529af4148866a2d28f079.yml → 1cc52302ce2de278051c3b6be90ccd36.yml} +11 -11
  33. data/spec/fixtures/cassettes/finder/get_search_keywords_recommendation/{ec96bf3af091373de08550ff46f86c87.yml → 85a972f0b32d1e011b2c8b74fff19261.yml} +6 -6
  34. data/spec/fixtures/cassettes/merchandiser/get_most_watched_items/66600b7c4cb52b32e517f3e5563463e1.yml +51 -0
  35. data/spec/fixtures/cassettes/merchandiser/get_related_category_items/{c949e90fb2bd975020df657a4348328d.yml → c74a3e3dff9ffb3e5a84c057d1a88bf3.yml} +6 -6
  36. data/spec/fixtures/cassettes/merchandiser/get_similar_items/{56c2c41a60135db83d359053778a065f.yml → 943af1f951bf437e72a0d6325bc167af.yml} +6 -6
  37. data/spec/fixtures/cassettes/merchandiser/get_top_selling_products/323d900971616df3712c8bc7737a70f1.yml +51 -0
  38. data/spec/fixtures/cassettes/shopper/find_half_products/{77ad8a2ade8e4efadef07346677e43a9.yml → 7bf13f5c5fad44a19d46d68168dc05a3.yml} +15 -15
  39. data/spec/fixtures/cassettes/shopper/find_popular_items/67c26e00c0be5bfa5994b1ae408517f7.yml +258 -0
  40. data/spec/fixtures/cassettes/shopper/find_popular_searches/{6db9b375ea610e870e7a4ca4e20974ec.yml → bcf07f2cb90cae7cb40f2252dde126a6.yml} +8 -8
  41. data/spec/fixtures/cassettes/shopper/find_products/{3fd6d6000037cd409ab1ef18a6075257.yml → b1001bc7a19381f533b36d7b40daedd7.yml} +16 -16
  42. data/spec/fixtures/cassettes/shopper/find_reviews_and_guides/{8586a984e122cb84136d3cc0bb8bec77.yml → ceb14bd40e2371d3e58e9c4645e857f2.yml} +16 -16
  43. data/spec/fixtures/cassettes/shopper/get_item_status/{f34cf10c602f9fec7a388297888b4299.yml → 83876f24642637642979b09a6475b475.yml} +8 -8
  44. data/spec/fixtures/cassettes/shopper/get_multiple_items/{c1183c23add6cad9afbb73f986c2692e.yml → 1f42d0c0fe105f8c0ad79d08f1900738.yml} +8 -8
  45. data/spec/fixtures/cassettes/shopper/get_shipping_costs/{e7de18031f266637414155639797c097.yml → 9ca24c61a943a3f6647e45b0ae30261f.yml} +8 -8
  46. data/spec/fixtures/cassettes/shopper/get_single_item/{d4a895de6b214907c47a0b32ab630b9a.yml → d50997fefbf6099325c3c01ef2a4cb51.yml} +8 -8
  47. data/spec/fixtures/cassettes/shopper/get_user_profile/{dccabbf426bfeba4d898ca546e17dd4b.yml → a5a8fd7e8aeaea9a16dc09c6cb8f3092.yml} +8 -8
  48. data/spec/spec_helper.rb +2 -1
  49. data/spec/support/shared/request.rb +67 -0
  50. metadata +83 -92
  51. data/lib/agent_cooper/nokogiri_decorator.rb +0 -47
  52. data/spec/fixtures/cassettes/finder/find_items_advanced/d49218a9522a4a055e31fc6b88c3a2b5.yml +0 -528
  53. data/spec/fixtures/cassettes/finder/find_items_by_category/85e07de9993e68d09e895f1b01234c5a.yml +0 -463
  54. data/spec/fixtures/cassettes/finder/find_items_by_keywords/91d7d9b4b62b82877604465a20f9ffa9.yml +0 -668
  55. data/spec/fixtures/cassettes/finder/find_items_by_product/59ee1391b6dfc2a93e30c8911942fc71.yml +0 -744
  56. data/spec/fixtures/cassettes/finder/find_items_in_ebay_stores/c7d658804b6353fda03809c21b183af2.yml +0 -472
  57. data/spec/fixtures/cassettes/merchandiser/get_most_watched_items/3c0cb6fb7bb94b384cae15be175e9640.yml +0 -51
  58. data/spec/fixtures/cassettes/merchandiser/get_top_selling_products/a82dcb1f094754e54f2a5de191818c3f.yml +0 -53
  59. data/spec/fixtures/cassettes/shopper/find_popular_items/532fcb32fee187bdc6cc5fb7e4336992.yml +0 -258
  60. data/spec/fixtures/ebay.yml.sample +0 -1
data/.gitignore CHANGED
@@ -2,4 +2,3 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
- ebay.yml
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create 1.9.2@agent_cooper
data/.travis.yml ADDED
@@ -0,0 +1,2 @@
1
+ rvm:
2
+ - 1.9.2
data/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  Agent Cooper
2
2
  ======
3
3
 
4
- Agent Cooper is a minimalistic, Nokogiri-based Ruby wrapper to the [eBay Web Services API](http://developer.ebay.com/).
4
+ [![travis](https://secure.travis-ci.org/rclosner/agent_cooper.png)](http://travis-ci.org/rclosner/agent_cooper)
5
5
 
6
- Currently the following eBay APIs are supported:
6
+ Agent Cooper is a minimalist, Nokogiri-based Ruby wrapper to the [eBay Web Services API](http://developer.ebay.com/).
7
+
8
+ It supports the following eBay APIs are supported:
7
9
  - [Finding API](http://developer.ebay.com/products/finding/)
8
10
  - [Shopping API](http://developer.ebay.com/products/shopping/)
9
11
  - [Merchandising API](http://developer.ebay.com/products/merchandising/)
@@ -14,7 +16,7 @@ Set up.
14
16
 
15
17
  ```ruby
16
18
  AgentCooper.configure do |config|
17
- config.app_id = "SOME_OBSCURE_APP_ID"
19
+ config.app_id = "YOUR_EBAY_APP_ID"
18
20
  end
19
21
  ```
20
22
 
@@ -59,4 +61,4 @@ Or parse a response with Nokogiri:
59
61
  ```
60
62
  ----
61
63
 
62
- Based on papercavalier's [sucker](http://github.com/papercavalier/sucker).
64
+ Based on hakanensari's [amazon_product](http://github.com/hakanensari/amazon_product).
data/Rakefile CHANGED
@@ -13,3 +13,5 @@ end
13
13
  Cucumber::Rake::Task.new(:features) do |t|
14
14
  t.cucumber_opts = "features --format pretty"
15
15
  end
16
+
17
+ task :default => [:spec]
data/agent_cooper.gemspec CHANGED
@@ -7,28 +7,30 @@ Gem::Specification.new do |s|
7
7
  s.version = AgentCooper::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Ryan Closner"]
10
- s.email = ["ryan.closner@gmail.com"]
10
+ s.email = ["ryan@ryanclosner.com"]
11
11
  s.homepage = "https://rubygems.org/gems/agent_cooper"
12
12
  s.summary = %q{A Ruby wrapper to the eBay Web Services API}
13
13
  s.description = %q{A Ruby wrapper to the eBay Web Services API}
14
14
 
15
15
  s.rubyforge_project = "agent_cooper"
16
16
 
17
- {
18
- 'httpclient' => '~> 2.2',
19
- 'nokogiri' => '~> 1.4'
20
- }.each {|lib, version| s.add_runtime_dependency lib, version }
17
+ runtime_dependencies = {
18
+ "httpclient" => "~> 2.2.3",
19
+ "nokogiri" => "~> 1.5.0",
20
+ "virtus" => "~> 0.0.9"
21
+ }
21
22
 
23
+ runtime_dependencies.each {|lib, version| s.add_runtime_dependency(lib, version) }
22
24
 
23
- {
24
- 'cucumber' => '~> 1.0',
25
- 'em-http-request' => '~> 1.0.0.beta.4',
26
- 'em-synchrony' => '~> 0.3.0.beta.1',
27
- 'rake' => '~> 0.9',
28
- 'rspec' => '~> 2.6',
29
- 'vcr' => '~> 1.10',
30
- 'webmock' => '~> 1.6'
31
- }.each {|lib, version| s.add_development_dependency lib, version }
25
+ development_dependencies = {
26
+ "cucumber" => "~> 1.1.2",
27
+ "rake" => "~> 0.9.2",
28
+ "rspec" => "~> 2.7.0",
29
+ "vcr" => "~> 1.11.3",
30
+ "webmock" => "~> 1.7.7"
31
+ }
32
+
33
+ development_dependencies.each {|lib, version| s.add_development_dependency(lib, version) }
32
34
 
33
35
  s.files = `git ls-files`.split("\n")
34
36
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -18,7 +18,7 @@ Feature: Ebay Finder
18
18
  | findItemsByKeywords | harry potter phoenix |
19
19
  When I tape the "finder" request as: "find_items_by_keywords"
20
20
  Then the response code should be "200"
21
- And the response should have 100 "item" nodes
21
+ And the response should have 99 "item" nodes
22
22
 
23
23
  Scenario: findItemsByCategory
24
24
  Given the following parameters:
@@ -5,12 +5,8 @@ require 'agent_cooper'
5
5
 
6
6
 
7
7
  module AgentCooperMethods
8
- def ebay
9
- @ebay ||= YAML::load_file(File.dirname(__FILE__) + "/../../spec/fixtures/ebay.yml")
10
- end
11
-
12
8
  def ebay_app_id
13
- ebay['app_id']
9
+ ENV['EBAY_APP_ID'] || "APP_ID"
14
10
  end
15
11
 
16
12
  def cassette_name
@@ -1,11 +1,7 @@
1
1
  require 'vcr'
2
2
 
3
- def ebay
4
- @ebay ||= YAML::load_file(File.dirname(__FILE__) + "/../../spec/fixtures/ebay.yml")
5
- end
6
-
7
3
  def ebay_app_id
8
- ebay['app_id']
4
+ ENV['EBAY_APP_ID'] || "APP_ID"
9
5
  end
10
6
 
11
7
 
@@ -15,5 +11,5 @@ VCR.config do |c|
15
11
  :record => :none,
16
12
  :match_requests_on => [:host] }
17
13
  c.stub_with :webmock
18
- c.filter_sensitive_data('YOUR-APP-ID') { ebay_app_id }
14
+ c.filter_sensitive_data('APP_ID') { ebay_app_id }
19
15
  end
data/lib/agent_cooper.rb CHANGED
@@ -1,22 +1,20 @@
1
- # Utilities
1
+ require 'nokogiri'
2
+ require 'httpclient'
3
+ require 'virtus'
4
+ require 'cgi'
5
+
6
+ module AgentCooper
7
+ def self.configure(&block)
8
+ Config.configure(&block)
9
+ end
10
+ end
11
+
2
12
  require 'agent_cooper/config'
3
13
  require 'agent_cooper/response'
4
- require 'agent_cooper/request'
5
-
6
- require 'agent_cooper/nokogiri_decorator'
14
+ require 'agent_cooper/builder'
7
15
 
8
- # Requests
16
+ require 'agent_cooper/request'
9
17
  require 'agent_cooper/requests/finder'
10
18
  require 'agent_cooper/requests/shopper'
11
19
  require 'agent_cooper/requests/merchandiser'
12
-
13
- #Version
14
20
  require "agent_cooper/version"
15
-
16
- module AgentCooper
17
- class << self
18
- def configure(&block)
19
- Config.configure(&block)
20
- end
21
- end
22
- end
@@ -0,0 +1,46 @@
1
+ module AgentCooper
2
+ class Builder
3
+
4
+ # Based on https://gist.github.com/335286
5
+
6
+ # @api public
7
+ def self.from_xml(xml)
8
+ case xml
9
+ when Nokogiri::XML::Document
10
+ from_xml(xml.root)
11
+ when Nokogiri::XML::Element
12
+ hsh = {}
13
+
14
+ xml.attributes.each_pair do |key, attr|
15
+ hsh[key] = attr.value
16
+ end
17
+
18
+ xml.children.each do |child|
19
+ result = from_xml(child)
20
+
21
+ if child.name == 'text'
22
+ if hsh.empty?
23
+ return result
24
+ else
25
+ hsh['__content__'] = result
26
+ end
27
+ elsif hsh[child.name]
28
+ case hsh[child.name]
29
+ when Array
30
+ hsh[child.name] << result
31
+ else
32
+ hsh[child.name] = [hsh[child.name]] << result
33
+ end
34
+ else
35
+ hsh[child.name] = result
36
+ end
37
+ end
38
+
39
+ hsh
40
+ else
41
+ xml.content.to_s
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -3,8 +3,13 @@ module AgentCooper
3
3
  class << self
4
4
  attr_accessor :app_id
5
5
 
6
+ # @api public
6
7
  def configure(&block)
7
- yield self
8
+ unless block_given?
9
+ raise ArgumentError, "No block given"
10
+ end
11
+
12
+ yield self if block_given?
8
13
  end
9
14
  end
10
15
  end
@@ -1,53 +1,77 @@
1
- require 'forwardable'
2
- require 'httpclient'
3
- require 'cgi'
4
-
5
1
  module AgentCooper
6
2
  class Request
7
3
 
8
- extend Forwardable
4
+ include Virtus
9
5
 
10
- def_delegators :@config, :app_id
6
+ # config attributes
7
+ attribute :app_id, String,
8
+ :default => Proc.new { AgentCooper::Config.app_id },
9
+ :writer => :protected
11
10
 
12
- ENCODING = 'XML'
11
+ # request attributes
12
+ attribute :request_adapter, Object,
13
+ :default => Proc.new { HTTPClient.new },
14
+ :accessor => :protected
13
15
 
14
- def initialize
15
- @config = Config
16
- end
16
+ attribute :query_parameters, Hash,
17
+ :default => Proc.new { {} },
18
+ :accessor => :protected
17
19
 
18
- def adapter
19
- @adapter ||= HTTPClient.new
20
- end
20
+ attribute :default_parameters, Hash,
21
+ :accessor => :protected
21
22
 
23
+ attribute :host, String,
24
+ :accessor => :protected
25
+
26
+ attribute :path, String,
27
+ :accessor => :protected
28
+
29
+ # @api public
22
30
  def get
23
- response = adapter.get(url)
24
- Response.new(response)
31
+ Response.new(:response => request_adapter.get(url))
25
32
  end
26
33
 
27
- def url
28
- URI::HTTP.build(
29
- :host => host,
30
- :path => path,
31
- :query => query
32
- )
33
- end
34
+ # @api public
35
+ def <<(parameters)
36
+ unless parameters.is_a?(Hash)
37
+ raise ArgumentError, "+parameters+ must be an instance of Hash"
38
+ end
34
39
 
35
- def query
36
- query = default_parameters.merge(parameters)
40
+ query_parameters.merge!(parameters)
41
+ end
37
42
 
38
- query.collect {|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"} * '&'
43
+ # @api public
44
+ def reset!
45
+ self.query_parameters = {}
39
46
  end
40
47
 
48
+ # @api public
41
49
  def parameters
42
- @parameters ||= {}
50
+ default_parameters.merge(query_parameters)
51
+ end
52
+
53
+ protected
54
+
55
+ # @api private
56
+ def query
57
+ parameters.collect { |k,v| "#{escape(k)}=#{escape(v)}" }.sort * '&'
43
58
  end
44
59
 
45
- def <<(hash)
46
- parameters.merge!(hash)
60
+ # @api private
61
+ def escape(value)
62
+ CGI.escape("#{value}")
47
63
  end
48
64
 
49
- def reset!
50
- @parameters = {}
65
+ # @api private
66
+ def url
67
+ options = {
68
+ :host => host,
69
+ :path => path,
70
+ :query => query
71
+ }
72
+
73
+ URI::HTTP.build(options)
51
74
  end
75
+
52
76
  end
53
77
  end
@@ -1,23 +1,20 @@
1
1
  module AgentCooper
2
2
  class Finder < Request
3
3
 
4
- VERSION = '1.9.0'
4
+ VERSION = "1.11.0".freeze
5
+ HOST = "svcs.ebay.com".freeze
6
+ PATH = "/services/search/FindingService/v1".freeze
7
+ ENCODING = "XML".freeze
5
8
 
6
- def host
7
- 'svcs.ebay.com'
8
- end
9
-
10
-
11
- def path
12
- '/services/search/FindingService/v1'
13
- end
9
+ def initialize
10
+ self.host = HOST
11
+ self.path = PATH
14
12
 
15
- def default_parameters
16
- {
17
- 'SECURITY-APPNAME' => app_id,
18
- 'SECURITY-VERSION' => VERSION,
19
- 'RESPONSE-DATA-FORMAT' => ENCODING,
20
- 'REST-PAYLOAD' => ''
13
+ self.default_parameters = {
14
+ "SECURITY-APPNAME" => app_id,
15
+ "SECURITY-VERSION" => VERSION,
16
+ "RESPONSE-DATA-FORMAT" => ENCODING,
17
+ "REST-PAYLOAD" => ""
21
18
  }
22
19
  end
23
20
 
@@ -1,25 +1,24 @@
1
1
  module AgentCooper
2
2
  class Merchandiser < Request
3
3
 
4
- SERVICE_NAME = 'MerchandisingService'
5
- VERSION = '1.4.0'
4
+ VERSION = "1.5.0".freeze
5
+ HOST = "svcs.ebay.com".freeze
6
+ SERVICE_NAME = "MerchandisingService".freeze
7
+ PATH = "/MerchandisingService".freeze
8
+ ENCODING = "XML".freeze
6
9
 
7
- def host
8
- 'svcs.ebay.com'
9
- end
10
-
11
- def path
12
- '/MerchandisingService'
13
- end
10
+ def initialize
11
+ self.host = HOST
12
+ self.path = PATH
14
13
 
15
- def default_parameters
16
- {
17
- 'CONSUMER-ID' => app_id,
18
- 'SERVICE-NAME' => SERVICE_NAME,
19
- 'SERVICE-VERSION' => VERSION,
20
- 'RESPONSE-DATA-FORMAT' => ENCODING,
21
- 'REST-PAYLOAD' => ''
14
+ self.default_parameters = {
15
+ "CONSUMER-ID" => app_id,
16
+ "SERVICE-NAME" => SERVICE_NAME,
17
+ "SERVICE-VERSION" => VERSION,
18
+ "RESPONSE-DATA-FORMAT" => ENCODING,
19
+ "REST-PAYLOAD" => ""
22
20
  }
23
21
  end
22
+
24
23
  end
25
24
  end
@@ -1,23 +1,23 @@
1
1
  module AgentCooper
2
2
  class Shopper < Request
3
3
 
4
- VERSION = '717'
4
+ VERSION = "745".freeze
5
+ HOST = "open.api.ebay.com".freeze
6
+ PATH = "/shopping".freeze
7
+ SITE_ID = 0.freeze
8
+ ENCODING = "XML".freeze
5
9
 
6
- def host
7
- 'open.api.ebay.com'
8
- end
10
+ def initialize
11
+ self.host = HOST
12
+ self.path = PATH
9
13
 
10
- def path
11
- '/shopping'
14
+ self.default_parameters = {
15
+ "APPID" => app_id,
16
+ "RESPONSEENCODING" => ENCODING,
17
+ "VERSION" => VERSION,
18
+ "SITEID" => SITE_ID
19
+ }
12
20
  end
13
21
 
14
- def default_parameters
15
- {
16
- 'APPID' => app_id,
17
- 'RESPONSEENCODING' => ENCODING,
18
- 'VERSION' => VERSION,
19
- 'SITEID' => 0
20
- }
21
- end
22
22
  end
23
23
  end