agent_cooper 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +1 -1
  2. data/README.md +13 -4
  3. data/Rakefile +0 -3
  4. data/agent_cooper.gemspec +12 -13
  5. data/features/finder.feature +4 -6
  6. data/features/merchandiser.feature +1 -2
  7. data/features/shopper.feature +2 -2
  8. data/features/support/env.rb +5 -5
  9. data/features/support/vcr.rb +10 -0
  10. data/lib/agent_cooper.rb +17 -4
  11. data/lib/agent_cooper/config.rb +3 -9
  12. data/lib/agent_cooper/nokogiri_decorator.rb +47 -0
  13. data/lib/agent_cooper/request.rb +36 -13
  14. data/lib/agent_cooper/requests/finder.rb +25 -0
  15. data/lib/agent_cooper/requests/merchandiser.rb +25 -0
  16. data/lib/agent_cooper/requests/shopper.rb +23 -0
  17. data/lib/agent_cooper/response.rb +3 -4
  18. data/lib/agent_cooper/synchrony.rb +34 -0
  19. data/lib/agent_cooper/version.rb +1 -1
  20. data/spec/agent_cooper/request_spec.rb +91 -6
  21. data/spec/agent_cooper/requests/finder_spec.rb +13 -0
  22. data/spec/agent_cooper/requests/merchandiser_spec.rb +13 -0
  23. data/spec/agent_cooper/requests/shopper_spec.rb +13 -0
  24. data/spec/agent_cooper/response_spec.rb +51 -1
  25. data/spec/agent_cooper_spec.rb +12 -0
  26. data/spec/fixtures/cassettes/finder/find_items_advanced/d49218a9522a4a055e31fc6b88c3a2b5.yml +528 -0
  27. data/spec/fixtures/cassettes/finder/find_items_by_category/85e07de9993e68d09e895f1b01234c5a.yml +463 -0
  28. data/spec/fixtures/cassettes/finder/find_items_by_keywords/91d7d9b4b62b82877604465a20f9ffa9.yml +668 -0
  29. data/spec/fixtures/cassettes/finder/find_items_by_product/59ee1391b6dfc2a93e30c8911942fc71.yml +744 -0
  30. data/spec/fixtures/cassettes/finder/find_items_in_ebay_stores/c7d658804b6353fda03809c21b183af2.yml +472 -0
  31. data/spec/fixtures/cassettes/finder/get_histograms/80bd04d96cd529af4148866a2d28f079.yml +46 -0
  32. data/spec/fixtures/cassettes/finder/get_search_keywords_recommendation/ec96bf3af091373de08550ff46f86c87.yml +41 -0
  33. data/spec/fixtures/cassettes/merchandiser/get_most_watched_items/3c0cb6fb7bb94b384cae15be175e9640.yml +51 -0
  34. data/spec/fixtures/cassettes/merchandiser/get_related_category_items/c949e90fb2bd975020df657a4348328d.yml +41 -0
  35. data/spec/fixtures/cassettes/merchandiser/get_similar_items/56c2c41a60135db83d359053778a065f.yml +41 -0
  36. data/spec/fixtures/cassettes/merchandiser/get_top_selling_products/a82dcb1f094754e54f2a5de191818c3f.yml +53 -0
  37. data/spec/fixtures/cassettes/shopper/find_half_products/77ad8a2ade8e4efadef07346677e43a9.yml +55 -0
  38. data/spec/fixtures/cassettes/shopper/find_popular_items/532fcb32fee187bdc6cc5fb7e4336992.yml +258 -0
  39. data/spec/fixtures/cassettes/shopper/find_popular_searches/6db9b375ea610e870e7a4ca4e20974ec.yml +45 -0
  40. data/spec/fixtures/cassettes/shopper/find_products/3fd6d6000037cd409ab1ef18a6075257.yml +52 -0
  41. data/spec/fixtures/cassettes/shopper/find_reviews_and_guides/8586a984e122cb84136d3cc0bb8bec77.yml +174 -0
  42. data/spec/fixtures/cassettes/shopper/get_item_status/f34cf10c602f9fec7a388297888b4299.yml +45 -0
  43. data/spec/fixtures/cassettes/shopper/get_multiple_items/c1183c23add6cad9afbb73f986c2692e.yml +46 -0
  44. data/spec/fixtures/cassettes/shopper/get_shipping_costs/e7de18031f266637414155639797c097.yml +45 -0
  45. data/spec/fixtures/cassettes/shopper/get_single_item/d4a895de6b214907c47a0b32ab630b9a.yml +44 -0
  46. data/spec/fixtures/cassettes/shopper/get_user_profile/dccabbf426bfeba4d898ca546e17dd4b.yml +47 -0
  47. data/spec/{support → fixtures}/ebay.yml.sample +0 -0
  48. data/spec/spec_helper.rb +4 -0
  49. metadata +141 -177
  50. data/lib/agent_cooper/finder.rb +0 -21
  51. data/lib/agent_cooper/merchandiser.rb +0 -24
  52. data/lib/agent_cooper/shopper.rb +0 -22
  53. data/spec/agent_cooper/config_spec.rb +0 -21
  54. data/spec/agent_cooper/finder_spec.rb +0 -19
  55. data/spec/agent_cooper/merchandiser_spec.rb +0 -18
  56. data/spec/agent_cooper/shopper_spec.rb +0 -18
data/.gitignore CHANGED
@@ -2,4 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
- *.yml
5
+ ebay.yml
data/README.md CHANGED
@@ -12,42 +12,51 @@ Usage
12
12
  -----
13
13
  Set up.
14
14
 
15
- AgentCooper::Config.set do |config|
15
+ ```ruby
16
+ AgentCooper.configure do |config|
16
17
  config.app_id = "SOME_OBSCURE_APP_ID"
17
18
  end
19
+ ```
18
20
 
19
21
  Initialize a request
20
22
 
23
+ ```ruby
21
24
  request = AgentCooper::Finder.new
22
25
  request = AgentCooper::Shopper.new
23
26
  request = AgentCooper::Merchandiser.new
24
-
27
+ ```
25
28
  Build request params.
26
29
 
30
+ ```ruby
27
31
  request << {
28
32
  'OPERATION-NAME' => 'getSearchKeywordsRecommendation',
29
33
  'KEYWORDS' => 'arry potter'
30
34
  }
35
+ ```
31
36
 
32
37
  Get a response.
33
38
 
39
+ ```ruby
34
40
  response = request.get
41
+ ```
35
42
 
36
43
  Return a hash:
37
44
 
45
+ ```ruby
38
46
  response.to_hash
39
47
 
40
48
  returns: {'getSearchKeywordsRecommendationResponse' => {'xmnls' => 'http://www.ebay.com/marketplace/search/v1/services', 'ack' => 'Success', 'version' => '1.9.0', 'keywords' => 'harry potter'}}
41
-
49
+ ```
42
50
 
43
51
  Or parse a response with Nokogiri:
44
52
 
53
+ ```ruby
45
54
  response.xml.css("Item > Title").each do |title|
46
55
  some business value
47
56
  end
48
57
 
49
58
  response.xml.xpath("//Item")
50
-
59
+ ```
51
60
  ----
52
61
 
53
62
  Based on papercavalier's [sucker](http://github.com/papercavalier/sucker).
data/Rakefile CHANGED
@@ -13,6 +13,3 @@ 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, :features]
18
-
data/agent_cooper.gemspec CHANGED
@@ -15,22 +15,21 @@ Gem::Specification.new do |s|
15
15
  s.rubyforge_project = "agent_cooper"
16
16
 
17
17
  {
18
- 'httparty' => '~> 0.7.7',
19
- 'nokogiri' => '~> 1.4.4'
18
+ 'httpclient' => '~> 2.2',
19
+ 'nokogiri' => '~> 1.4'
20
20
  }.each {|lib, version| s.add_runtime_dependency lib, version }
21
-
22
-
21
+
22
+
23
23
  {
24
- 'bundler' => '~> 1.0.0',
25
- 'addressable' => '2.2.4',
26
- 'cucumber' => '~> 0.10.0',
27
- 'rake' => '~> 0.8.7',
28
- 'relish' => '~> 0.3.0.pre',
29
- 'rspec' => '~> 2.5.0',
30
- 'vcr' => '~> 1.9.0',
31
- 'webmock' => '~> 1.6.0'
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'
32
31
  }.each {|lib, version| s.add_development_dependency lib, version }
33
-
32
+
34
33
  s.files = `git ls-files`.split("\n")
35
34
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
36
35
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -1,9 +1,9 @@
1
1
  Feature: Ebay Finder
2
2
  As an API consumer
3
3
 
4
- Background:
4
+ Background:
5
5
  Given a new finder request
6
-
6
+
7
7
  Scenario: getSearchKeywordsRecommendation
8
8
  Given the following parameters:
9
9
  | OPERATION-NAME | keywords |
@@ -11,7 +11,7 @@ Feature: Ebay Finder
11
11
  When I tape the "finder" request as: "get_search_keywords_recommendation"
12
12
  Then the response code should be "200"
13
13
  And the response should have 1 "keywords" nodes
14
-
14
+
15
15
  Scenario: findItemsByKeywords
16
16
  Given the following parameters:
17
17
  | OPERATION-NAME | keywords |
@@ -27,7 +27,7 @@ Feature: Ebay Finder
27
27
  When I tape the "finder" request as: "find_items_by_category"
28
28
  Then the response code should be "200"
29
29
  And the response should have 100 "item" nodes
30
-
30
+
31
31
  Scenario: findItemsAdvanced
32
32
  Given the following parameters:
33
33
  | OPERATION-NAME | keywords |
@@ -60,5 +60,3 @@ Feature: Ebay Finder
60
60
  When I tape the "finder" request as: "get_histograms"
61
61
  Then the response code should be "200"
62
62
  And the response should have 6 "childCategoryHistogram" nodes
63
-
64
-
@@ -1,7 +1,7 @@
1
1
  Feature: Ebay Merchandiser
2
2
  As an API consumer
3
3
 
4
- Background:
4
+ Background:
5
5
  Given a new merchandiser request
6
6
 
7
7
  Scenario: getMostWatchedItems
@@ -31,4 +31,3 @@ Feature: Ebay Merchandiser
31
31
  | getTopSellingProducts | 3 |
32
32
  When I tape the "merchandiser" request as: "get_top_selling_products"
33
33
  Then the response code should be "200"
34
-
@@ -1,9 +1,9 @@
1
1
  Feature: Ebay Shopper
2
2
  As an API consumer
3
3
 
4
- Background:
4
+ Background:
5
5
  Given a new shopper request
6
-
6
+
7
7
  Scenario: FindProducts
8
8
  Given the following parameters:
9
9
  | CALLNAME | QueryKeywords |
@@ -4,9 +4,9 @@ require 'digest/md5'
4
4
  require 'agent_cooper'
5
5
 
6
6
 
7
- module AgentCooperMethods
7
+ module AgentCooperMethods
8
8
  def ebay
9
- @ebay ||= YAML::load_file(File.dirname(__FILE__) + "/../../spec/support/ebay.yml")
9
+ @ebay ||= YAML::load_file(File.dirname(__FILE__) + "/../../spec/fixtures/ebay.yml")
10
10
  end
11
11
 
12
12
  def ebay_app_id
@@ -14,14 +14,14 @@ module AgentCooperMethods
14
14
  end
15
15
 
16
16
  def cassette_name
17
- Digest::MD5.hexdigest(@request.options.to_json)
17
+ Digest::MD5.hexdigest(@request.parameters.to_json)
18
18
  end
19
19
  end
20
20
 
21
21
  World(AgentCooperMethods)
22
22
 
23
23
  Before do
24
- AgentCooper::Config.set do |config|
25
- config.app_id = 'SOME_OBSCURE_APP_ID'
24
+ AgentCooper.configure do |config|
25
+ config.app_id = ebay_app_id
26
26
  end
27
27
  end
@@ -1,9 +1,19 @@
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
+ def ebay_app_id
8
+ ebay['app_id']
9
+ end
10
+
11
+
3
12
  VCR.config do |c|
4
13
  c.cassette_library_dir = File.dirname(__FILE__) + '/../../spec/fixtures/cassettes'
5
14
  c.default_cassette_options = {
6
15
  :record => :none,
7
16
  :match_requests_on => [:host] }
8
17
  c.stub_with :webmock
18
+ c.filter_sensitive_data('YOUR-APP-ID') { ebay_app_id }
9
19
  end
data/lib/agent_cooper.rb CHANGED
@@ -1,9 +1,22 @@
1
+ # Utilities
1
2
  require 'agent_cooper/config'
2
- require 'agent_cooper/request'
3
3
  require 'agent_cooper/response'
4
- require 'agent_cooper/finder'
5
- require 'agent_cooper/shopper'
6
- require 'agent_cooper/merchandiser'
4
+ require 'agent_cooper/request'
5
+
6
+ require 'agent_cooper/nokogiri_decorator'
7
+
8
+ # Requests
9
+ require 'agent_cooper/requests/finder'
10
+ require 'agent_cooper/requests/shopper'
11
+ require 'agent_cooper/requests/merchandiser'
12
+
13
+ #Version
14
+ require "agent_cooper/version"
7
15
 
8
16
  module AgentCooper
17
+ class << self
18
+ def configure(&block)
19
+ Config.configure(&block)
20
+ end
21
+ end
9
22
  end
@@ -1,16 +1,10 @@
1
1
  module AgentCooper
2
2
  class Config
3
3
  class << self
4
- def set(&block)
5
- yield self
6
- end
4
+ attr_accessor :app_id
7
5
 
8
- def app_id=(app_id)
9
- @@app_id = app_id
10
- end
11
-
12
- def app_id
13
- @@app_id ||= nil
6
+ def configure(&block)
7
+ yield self
14
8
  end
15
9
  end
16
10
  end
@@ -0,0 +1,47 @@
1
+ module AgentCooper
2
+
3
+ # Based on https://gist.github.com/335286
4
+
5
+ class Nokogiri::XML::Document
6
+ def to_hash
7
+ root.to_hash
8
+ end
9
+ end
10
+
11
+ class Nokogiri::XML::Element
12
+ def to_hash
13
+ ({}).tap do |hash|
14
+
15
+ attributes.each_pair do |key, attribute|
16
+ hash[key] = attribute.value
17
+ end
18
+
19
+ children.each do |child|
20
+ result = child.to_hash
21
+
22
+ if child.name == 'text'
23
+ if hash.empty?
24
+ return result
25
+ else
26
+ hash['__content__'] = result
27
+ end
28
+ elsif hash[child.name]
29
+ if hash[child.name].is_a?(Array)
30
+ hash[child.name] << result
31
+ else
32
+ hash[child.name] = [hash[child.name]] << result
33
+ end
34
+ else
35
+ hash[child.name] = result
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ class Nokogiri::XML::Text
43
+ def to_hash
44
+ content.to_s
45
+ end
46
+ end
47
+ end
@@ -1,30 +1,53 @@
1
- require 'httparty'
1
+ require 'forwardable'
2
+ require 'httpclient'
3
+ require 'cgi'
2
4
 
3
5
  module AgentCooper
4
6
  class Request
5
7
 
8
+ extend Forwardable
9
+
10
+ def_delegators :@config, :app_id
11
+
6
12
  ENCODING = 'XML'
7
13
 
8
- include HTTParty
9
- format :xml
14
+ def initialize
15
+ @config = Config
16
+ end
10
17
 
11
- attr_accessor :locale
18
+ def adapter
19
+ @adapter ||= HTTPClient.new
20
+ end
12
21
 
13
- def options
14
- @options ||= {}
22
+ def get
23
+ response = adapter.get(url)
24
+ Response.new(response)
15
25
  end
16
26
 
17
- def <<(hash)
18
- options.merge!(hash)
27
+ def url
28
+ URI::HTTP.build(
29
+ :host => host,
30
+ :path => path,
31
+ :query => query
32
+ )
19
33
  end
20
34
 
21
- def reset!
22
- @options = {}
35
+ def query
36
+ query = default_parameters.merge(parameters)
37
+
38
+ query.collect {|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"} * '&'
23
39
  end
24
40
 
25
- def get
26
- r = self.class.get(path, :query => options.merge(credentials))
27
- Response.new(r)
41
+ def parameters
42
+ @parameters ||= {}
43
+ end
44
+
45
+ def <<(hash)
46
+ parameters.merge!(hash)
47
+ end
48
+
49
+ def reset!
50
+ @parameters = {}
28
51
  end
29
52
  end
30
53
  end
@@ -0,0 +1,25 @@
1
+ module AgentCooper
2
+ class Finder < Request
3
+
4
+ VERSION = '1.9.0'
5
+
6
+ def host
7
+ 'svcs.ebay.com'
8
+ end
9
+
10
+
11
+ def path
12
+ '/services/search/FindingService/v1'
13
+ end
14
+
15
+ def default_parameters
16
+ {
17
+ 'SECURITY-APPNAME' => app_id,
18
+ 'SECURITY-VERSION' => VERSION,
19
+ 'RESPONSE-DATA-FORMAT' => ENCODING,
20
+ 'REST-PAYLOAD' => ''
21
+ }
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module AgentCooper
2
+ class Merchandiser < Request
3
+
4
+ SERVICE_NAME = 'MerchandisingService'
5
+ VERSION = '1.4.0'
6
+
7
+ def host
8
+ 'svcs.ebay.com'
9
+ end
10
+
11
+ def path
12
+ '/MerchandisingService'
13
+ end
14
+
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' => ''
22
+ }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ module AgentCooper
2
+ class Shopper < Request
3
+
4
+ VERSION = '717'
5
+
6
+ def host
7
+ 'open.api.ebay.com'
8
+ end
9
+
10
+ def path
11
+ '/shopping'
12
+ end
13
+
14
+ def default_parameters
15
+ {
16
+ 'APPID' => app_id,
17
+ 'RESPONSEENCODING' => ENCODING,
18
+ 'VERSION' => VERSION,
19
+ 'SITEID' => 0
20
+ }
21
+ end
22
+ end
23
+ end