agent_cooper 0.0.6 → 0.0.7.pre

Sign up to get free protection for your applications and to get access to all the features.
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