sucker 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG.md +9 -18
  2. data/README.md +9 -5
  3. data/lib/sucker.rb +0 -3
  4. data/lib/sucker/request.rb +96 -18
  5. data/lib/sucker/response.rb +20 -14
  6. data/lib/sucker/version.rb +1 -1
  7. data/spec/integration/multiple_locales_spec.rb +28 -3
  8. data/spec/support/vcr.rb +3 -2
  9. data/spec/unit/sucker/request_spec.rb +109 -29
  10. data/spec/unit/sucker/response_spec.rb +26 -23
  11. metadata +23 -137
  12. data/lib/sucker.rbc +0 -341
  13. data/lib/sucker/request.rbc +0 -2481
  14. data/lib/sucker/response.rbc +0 -1554
  15. data/lib/sucker/version.rbc +0 -130
  16. data/spec/fixtures/cassette_library/integration/alternate_versions.yml +0 -27
  17. data/spec/fixtures/cassette_library/integration/errors.yml +0 -27
  18. data/spec/fixtures/cassette_library/integration/france.yml +0 -27
  19. data/spec/fixtures/cassette_library/integration/images.yml +0 -27
  20. data/spec/fixtures/cassette_library/integration/item_lookup/multiple.yml +0 -27
  21. data/spec/fixtures/cassette_library/integration/item_lookup/single.yml +0 -27
  22. data/spec/fixtures/cassette_library/integration/item_search.yml +0 -27
  23. data/spec/fixtures/cassette_library/integration/japan.yml +0 -27
  24. data/spec/fixtures/cassette_library/integration/keyword_search.yml +0 -27
  25. data/spec/fixtures/cassette_library/integration/kindle.yml +0 -27
  26. data/spec/fixtures/cassette_library/integration/kindle_2.yml +0 -27
  27. data/spec/fixtures/cassette_library/integration/multiple_locales.yml +0 -157
  28. data/spec/fixtures/cassette_library/integration/power_search.yml +0 -27
  29. data/spec/fixtures/cassette_library/integration/related_items/child.yml +0 -27
  30. data/spec/fixtures/cassette_library/integration/related_items/parent.yml +0 -27
  31. data/spec/fixtures/cassette_library/integration/seller_listings_search.yml +0 -27
  32. data/spec/fixtures/cassette_library/integration/twenty_items.yml +0 -27
  33. data/spec/fixtures/cassette_library/unit/sucker/request.yml +0 -29
  34. data/spec/fixtures/cassette_library/unit/sucker/response.yml +0 -27
  35. data/spec/integration/alternate_versions_spec.rbc +0 -843
  36. data/spec/integration/errors_spec.rbc +0 -964
  37. data/spec/integration/france_spec.rbc +0 -1012
  38. data/spec/integration/images_spec.rbc +0 -1047
  39. data/spec/integration/item_lookup_spec.rbc +0 -1723
  40. data/spec/integration/item_search_spec.rbc +0 -926
  41. data/spec/integration/japan_spec.rbc +0 -849
  42. data/spec/integration/keyword_search_spec.rbc +0 -838
  43. data/spec/integration/kindle_spec.rbc +0 -1425
  44. data/spec/integration/multiple_locales_spec.rbc +0 -1090
  45. data/spec/integration/power_search_spec.rbc +0 -838
  46. data/spec/integration/related_items_spec.rbc +0 -1228
  47. data/spec/integration/seller_listing_search_spec.rbc +0 -852
  48. data/spec/integration/twenty_items_spec.rbc +0 -1166
  49. data/spec/spec_helper.rbc +0 -231
  50. data/spec/support/amazon.yml +0 -3
  51. data/spec/support/amazon_credentials.rbc +0 -154
  52. data/spec/support/asins.rbc +0 -335
  53. data/spec/support/vcr.rbc +0 -360
  54. data/spec/unit/sucker/request_spec.rbc +0 -4031
  55. data/spec/unit/sucker/response_spec.rbc +0 -3787
  56. data/spec/unit/sucker_spec.rbc +0 -299
data/CHANGELOG.md CHANGED
@@ -1,34 +1,25 @@
1
- Version 1.0.0
1
+ Version 1.1.0
2
2
  =============
3
3
 
4
- Release date: 2010-11-04
4
+ * Removed Request#get!. Bloat.
5
+ * Added Request#get_all to fetch responses from all venues
6
+ simultaneously.
7
+ * Added Request#associate_tags= to set associate tags for all locales.
8
+ * Added Request#keys= to set distinct keys for locales.
9
+ * Request#get validates presence of key and locale.
5
10
 
6
- Added
7
- -----
11
+ Version 1.0.0
12
+ =============
8
13
 
9
14
  * Added #each and #map to Response. #find no longer yields.
10
15
 
11
16
  Version 1.0.0.beta4
12
17
  ===================
13
18
 
14
- Release date: 2010-10-28
15
-
16
- Added
17
- -----
18
-
19
19
  * Sucker::Request#get! raises an error if response is not valid.
20
20
 
21
21
  Version 1.0.0.beta3
22
22
  ===================
23
23
 
24
- Release date: 2010-10-25
25
-
26
- Added
27
- -----
28
-
29
24
  * Sucker::Response#find yields to a block if given one.
30
-
31
- Deprecated
32
- ----------
33
-
34
25
  * Renamed #node to #find
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  Sucker
2
2
  ======
3
3
 
4
- Sucker is a Ruby wrapper to the [Amazon Product Advertising API](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html). It runs on [curb](http://github.com/taf2/curb) and [the Nokogiri implementation of the XML Mini module](http://github.com/rails/rails/blob/master/activesupport/lib/active_support/xml_mini/nokogiri.rb) in Active Support. It's fast and supports __the entire API__.
4
+ Sucker is a minimal Ruby wrapper to the [Amazon Product Advertising API](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html). It runs on [curb](http://github.com/taf2/curb) and [the Nokogiri implementation of the XML Mini module](http://github.com/rails/rails/blob/master/activesupport/lib/active_support/xml_mini/nokogiri.rb) in Active Support. It's fast and supports __the entire API__.
5
5
 
6
- ![Sucker](http://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg/480px-FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg)
6
+ ![Electrolux](http://github.com/papercavalier/sucker/raw/master/electrolux.jpg)
7
7
 
8
8
  Examples
9
9
  --------
@@ -43,10 +43,14 @@ Iterate over items in your item lookup.
43
43
 
44
44
  response.each("Item") { |item| ... }
45
45
 
46
- Iterate over errors.
46
+ Map errors to a block.
47
47
 
48
48
  errors = response.map("Error") { |error| ... }
49
49
 
50
+ Or simply get a hash of matching items.
51
+
52
+ items = response.find("Item")
53
+
50
54
  Repeat ad infinitum.
51
55
 
52
56
  Check my [integration specs](http://github.com/papercavalier/sucker/tree/master/spec/integration/) for more examples. See [twenty items](http://github.com/papercavalier/sucker/tree/master/spec/integration/twenty_items_spec.rb) and [multiple locales](http://github.com/papercavalier/sucker/tree/master/spec/integration/multiple_locales_spec.rb) for relatively advanced usage.
@@ -58,12 +62,12 @@ Stubbing
58
62
 
59
63
  Use [VCR](http://github.com/myronmarston/vcr) to stub your requests.
60
64
 
61
- Caveat: Match URIs on host only and create a new cassette for each query. [This is how I do it](http://github.com/papercavalier/sucker/blob/master/spec/support/vcr.rb).
65
+ Caveat: Match URIs on host only and create a new cassette for each query. [This is how my VCR helper looks like.](http://github.com/papercavalier/sucker/blob/master/spec/support/vcr.rb).
62
66
 
63
67
  Compatibility
64
68
  -------------
65
69
 
66
- Specs pass against Ruby 1.8.7, Ruby 1.9.2, and Rubinius 1.1.
70
+ Specs pass against Ruby 1.8.7 and Ruby 1.9.2.
67
71
 
68
72
  Sucker works seamlessly with or without Rails.
69
73
 
data/lib/sucker.rb CHANGED
@@ -1,8 +1,5 @@
1
- require "active_support/xml_mini/nokogiri"
2
- require "curb"
3
1
  require "sucker/request"
4
2
  require "sucker/response"
5
- require "uri"
6
3
 
7
4
  # = Sucker
8
5
  #
@@ -1,3 +1,7 @@
1
+ require "curb"
2
+ require "ostruct"
3
+ require "uri"
4
+
1
5
  module Sucker #:nodoc:
2
6
 
3
7
  # A wrapper around the API request
@@ -49,56 +53,125 @@ module Sucker #:nodoc:
49
53
  self.parameters.merge!(hash)
50
54
  end
51
55
 
52
- # Sets the associate tag
56
+ # Returns the associate tag for the current locale
57
+ def associate_tag
58
+ @associate_tags[locale.to_sym] rescue nil
59
+ end
60
+
61
+ # Sets the associate tag for the current locale
53
62
  #
54
63
  # worker = Sucker.new
55
64
  # worker.associate_tag = 'foo-bar'
56
65
  #
57
66
  def associate_tag=(token)
58
- parameters["AssociateTag"] = token
67
+ @associate_tags = HOSTS.keys.inject({}) do |tags, loc|
68
+ tags[loc] = token
69
+ tags
70
+ end
71
+ end
72
+
73
+ # Sets associate tags for all locales
74
+ #
75
+ # tags = {
76
+ # :us => 'foo-bar-10',
77
+ # :uk => 'foo-bar-20',
78
+ # :de => 'foo-bar-30',
79
+ # ... }
80
+ #
81
+ # worker = Sucker.new
82
+ # worker.associate_tags = tags
83
+ #
84
+ def associate_tags=(tokens)
85
+ @associate_tags = tokens
59
86
  end
60
87
 
61
- # A configurable curl object
88
+ # Returns options for curl and yields them if given a block
62
89
  #
63
90
  # worker = Sucker.new
64
91
  # worker.curl { |c| c.interface = "eth1" }
65
92
  #
66
- def curl
67
- @curl ||= Curl::Easy.new
68
- yield @curl if block_given?
69
- @curl
93
+ def curl_opts
94
+ @curl_opts ||= CurlOptions.new
95
+ yield @curl_opts if block_given?
96
+
97
+ @curl_opts.marshal_dump
70
98
  end
71
99
 
72
- # Performs the request and returns a response object
100
+ # Performs a request and returns a response
73
101
  #
74
102
  # worker = Sucker.new
75
103
  # response = worker.get
76
104
  #
77
105
  def get
78
- curl.url = uri.to_s
79
- curl.perform
106
+ raise ArgumentError.new "Locale missing" unless locale
107
+ raise ArgumentError.new "AWS access key missing" unless key
108
+
109
+ curl = Curl::Easy.perform(uri.to_s) do |easy|
110
+ curl_opts.each { |k, v| easy.send(k, v) }
111
+ end
80
112
 
81
113
  Response.new(curl)
82
114
  end
83
115
 
84
- Similar to get but raises an error if response is not valid
85
- def get!
86
- response = get
116
+ Performs a request for all locales, returns an array of responses, and
117
+ # yields them if given a block
118
+ #
119
+ # worker = Sucker.new
120
+ #
121
+ # # This blocks until all requests are complete
122
+ # responses = worker.get_all
123
+ #
124
+ # # This does not block
125
+ # worker.get_all do |response|
126
+ # process_response
127
+ # end
128
+ #
129
+ def get_all
130
+ uris = HOSTS.keys.map do |locale|
131
+ self.locale = locale
132
+ uri.to_s
133
+ end
134
+ responses = []
87
135
 
88
- unless response.valid?
89
- raise ResponseError, response.inspect
136
+ Curl::Multi.get(uris, curl_opts) do |curl|
137
+ response = Response.new(curl)
138
+ yield response if block_given?
139
+ responses << response
90
140
  end
91
141
 
92
- response
142
+ responses
93
143
  end
94
144
 
95
- # Sets the AWS Access Key ID
145
+ # Returns the AWS access key for the current locale
146
+ def key
147
+ @keys[locale.to_sym]
148
+ end
149
+
150
+ # Sets a global AWS access key ID
96
151
  #
97
152
  # worker = Sucker.new
98
153
  # worker.key = 'foo'
99
154
  #
100
155
  def key=(token)
101
- parameters["AWSAccessKeyId"] = token
156
+ @keys = HOSTS.keys.inject({}) do |keys, locale|
157
+ keys[locale] = token
158
+ keys
159
+ end
160
+ end
161
+
162
+ # Sets distinct AWS access keys for the locales
163
+ #
164
+ # keys = {
165
+ # :us => 'foo',
166
+ # :uk => 'bar',
167
+ # :de => 'baz',
168
+ # ... }
169
+ #
170
+ # worker = Sucker.new
171
+ # worker.keys = keys
172
+ #
173
+ def keys=(tokens)
174
+ @keys = tokens
102
175
  end
103
176
 
104
177
  # Sets the Amazon API version
@@ -116,6 +189,8 @@ module Sucker #:nodoc:
116
189
  def build_query
117
190
  parameters.
118
191
  merge(timestamp).
192
+ merge({ "AWSAccessKeyId" => key }).
193
+ merge({ "AssociateTag" => associate_tag }).
119
194
  sort.
120
195
  collect do |k, v|
121
196
  "#{k}=" + escape(v.is_a?(Array) ? v.join(",") : v.to_s)
@@ -156,4 +231,7 @@ module Sucker #:nodoc:
156
231
  { "Timestamp" => Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ') }
157
232
  end
158
233
  end
234
+
235
+ # Curl options
236
+ class CurlOptions < OpenStruct; end
159
237
  end
@@ -1,3 +1,5 @@
1
+ require "active_support/xml_mini/nokogiri"
2
+
1
3
  module Sucker #:nodoc:
2
4
 
3
5
  # A Nokogiri-driven wrapper around the cURL response
@@ -12,19 +14,23 @@ module Sucker #:nodoc:
12
14
  # Transaction time in seconds for request
13
15
  attr_accessor :time
14
16
 
17
+ # The request URI
18
+ attr_accessor :uri
19
+
15
20
  def initialize(curl)
16
21
  self.body = curl.body_str
17
22
  self.code = curl.response_code
18
23
  self.time = curl.total_time
24
+ self.uri = curl.url
19
25
  end
20
26
 
21
- # A shorthand that yields each match to a block
22
- #
23
- # worker.get.each("Item") { |item| process(item) }
24
- #
25
- def each(path)
26
- find(path).each { |node| yield node }
27
- end
27
+ # A shorthand that yields each match to a block
28
+ #
29
+ # worker.get.each("Item") { |item| process(item) }
30
+ #
31
+ def each(path)
32
+ find(path).each { |e| yield e }
33
+ end
28
34
 
29
35
  # Queries an xpath and returns an array of matching nodes
30
36
  #
@@ -32,15 +38,15 @@ module Sucker #:nodoc:
32
38
  # response.find("Item").each { |item| ... }
33
39
  #
34
40
  def find(path)
35
- xml.xpath("//xmlns:#{path}").map { |node| strip_content(node.to_hash[path]) }
41
+ xml.xpath("//xmlns:#{path}").map { |e| strip_content(e.to_hash[path]) }
36
42
  end
37
43
 
38
- # A shorthand that yields matches to a block and collects returned values
39
- #
40
- # descriptions = worker.get.map("Item") { |item| build_description(item) }
41
- #
42
- def map(path)
43
- find(path).map { |e| yield e }
44
+ # A shorthand that yields matches to a block and collects returned values
45
+ #
46
+ # descriptions = worker.get.map("Item") { |item| build_description(item) }
47
+ #
48
+ def map(path)
49
+ find(path).map { |e| yield e }
44
50
  end
45
51
 
46
52
  def node(path) # :nodoc:
@@ -1,3 +1,3 @@
1
1
  module Sucker #:nodoc:
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -5,11 +5,36 @@ module Sucker
5
5
 
6
6
  describe "Item lookup" do
7
7
 
8
- context "when using threads to search multiple locales" do
8
+ use_vcr_cassette "integration/multiple_locales", :record => :new_episodes
9
9
 
10
- use_vcr_cassette "integration/multiple_locales", :record => :new_episodes
10
+ context "when using Curl::Multi to search all locales simultaneously" do
11
11
 
12
- it "returns matches across all locales" do
12
+ it "returns matches for all locales" do
13
+ worker = Sucker.new(
14
+ :key => amazon["key"],
15
+ :secret => amazon["secret"])
16
+ worker << {
17
+ "Operation" => "ItemLookup",
18
+ "IdType" => "ASIN",
19
+ "ResponseGroup" => "ItemAttributes",
20
+ "ItemId" => "0816614024" }
21
+
22
+ bindings = worker.get_all.map do |response|
23
+ item = response.find("Item").first
24
+ item["ItemAttributes"]["Binding"]
25
+ end
26
+
27
+ bindings.uniq.should =~ %w{ Paperback Taschenbuch Broché ペーパーバック }
28
+
29
+ end
30
+
31
+ end
32
+
33
+ context "when using threads to search all locales simultaneously" do
34
+
35
+ # Leaving this spec here for reference purposes. Use approach in above spec.
36
+
37
+ it "returns matches for all locales" do
13
38
  locales = %w{us uk de ca fr jp}
14
39
 
15
40
  params = {
data/spec/support/vcr.rb CHANGED
@@ -2,10 +2,11 @@ require 'vcr'
2
2
 
3
3
  VCR.config do |c|
4
4
  c.cassette_library_dir = File.dirname(__FILE__) + '/../fixtures/cassette_library'
5
- c.http_stubbing_library = :webmock
6
5
  c.default_cassette_options = {
7
- :record => :new_episodes,
6
+ :record => :none,
8
7
  :match_requests_on => [:host] }
8
+
9
+ c.stub_with :webmock
9
10
  end
10
11
 
11
12
  RSpec.configure do |config|
@@ -42,60 +42,134 @@ module Sucker
42
42
 
43
43
  end
44
44
 
45
- describe "#associate_tag=" do
45
+ describe "#associate_tag" do
46
46
 
47
- it "sets the associate tag in the parameters" do
48
- worker.associate_tag = "foo"
49
- worker.parameters["AssociateTag"].should eql "foo"
47
+ it "returns the associate tag for the current locale" do
48
+ worker.instance_variable_set(:@associate_tags, { :us => 'foo-bar'})
49
+
50
+ worker.associate_tag.should eql 'foo-bar'
51
+ end
52
+
53
+ it "returns nil if an associate tag is not set for the current locale" do
54
+ worker.associate_tag.should eql nil
50
55
  end
51
56
 
52
57
  end
53
58
 
54
- describe "#curl" do
59
+ describe "#associate_tags=" do
55
60
 
56
- it "returns curl" do
57
- worker.curl.should be_an_instance_of Curl::Easy
61
+ it "sets associate tags for the locales" do
62
+ tags = {
63
+ :us => 'foo',
64
+ :uk => 'bar',
65
+ :de => 'baz',
66
+ :ca => 'foo',
67
+ :fr => 'bar',
68
+ :jp => 'baz' }
69
+ worker.associate_tags = tags
70
+
71
+ worker.instance_variable_get(:@associate_tags).should eql tags
58
72
  end
59
73
 
60
- context "when given a block" do
74
+ end
61
75
 
62
- it "yields curl" do
63
- worker.curl.interface.should be_nil
76
+ describe "#curl_opts" do
64
77
 
65
- worker.curl { |curl| curl.interface = "eth1" }
78
+ it "returns options for curl" do
79
+ worker.curl_opts.should be_an_instance_of Hash
80
+ end
81
+
82
+ context "when given a block" do
66
83
 
67
- worker.curl.interface.should eql "eth1"
84
+ it "yields options for curl" do
85
+ worker.curl_opts { |c| c.interface = "eth1" }
86
+
87
+ worker.curl_opts[:interface].should eql "eth1"
68
88
  end
69
89
 
70
90
  end
71
91
 
72
92
  end
73
93
 
74
- describe "#get!" do
94
+ describe "#get" do
95
+
96
+ it "returns a response" do
97
+ worker.get.class.ancestors.should include Response
98
+ end
75
99
 
76
- it "raises if response is not valid" do
77
- worker << {
78
- "Operation" => "ItemLookup",
79
- "IdType" => "ASIN",
80
- "ItemId" => "0816614024" }
81
- lambda { worker.get! }.should raise_error ResponseError
100
+ it "raises an argument error if no key is provided" do
101
+ worker.key = nil
102
+ expect do
103
+ worker.get
104
+ end.to raise_error(/AWS access key missing/)
82
105
  end
83
106
 
107
+ it "raises an argument error if no locale is provided" do
108
+ worker.locale = nil
109
+ expect do
110
+ worker.get
111
+ end.to raise_error(/Locale missing/)
112
+ end
84
113
  end
85
114
 
86
- describe "#get" do
115
+ describe "#get_all" do
87
116
 
88
- it "returns a response" do
89
- worker.get.class.ancestors.should include Response
117
+ it "returns an array of responses" do
118
+ responses = worker.get_all
119
+
120
+ responses.should be_an_instance_of Array
121
+ responses.each { |resp| resp.should be_an_instance_of Response }
122
+ end
123
+
124
+ context "when given a block" do
125
+
126
+ it "yields responses" do
127
+ count = 0
128
+ worker.get_all do |resp|
129
+ resp.should be_an_instance_of Response
130
+ count += 1
131
+ end
132
+
133
+ count.should eql Request::HOSTS.size
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#key" do
139
+
140
+ it "returns the Amazon AWS access key for the current locale" do
141
+ worker.instance_variable_set(:@keys, { :us => 'foo' })
142
+
143
+ worker.key.should eql 'foo'
90
144
  end
91
145
 
92
146
  end
93
147
 
94
148
  describe "#key=" do
95
149
 
96
- it "sets the Amazon AWS access key in the parameters" do
150
+ it "sets a global Amazon AWS access key" do
97
151
  worker.key = "foo"
98
- worker.parameters["AWSAccessKeyId"].should eql "foo"
152
+ keys = worker.instance_variable_get(:@keys)
153
+
154
+ keys.size.should eql Request::HOSTS.size
155
+ keys.values.uniq.should eql ["foo"]
156
+ end
157
+
158
+ end
159
+
160
+ describe "#keys=" do
161
+
162
+ it "sets distinct Amazon AWS access keys for the locales" do
163
+ keys = {
164
+ :us => 'foo',
165
+ :uk => 'bar',
166
+ :de => 'baz',
167
+ :ca => 'foo',
168
+ :fr => 'bar',
169
+ :jp => 'baz' }
170
+ worker.keys = keys
171
+
172
+ worker.instance_variable_get(:@keys).should eql keys
99
173
  end
100
174
 
101
175
  end
@@ -104,32 +178,38 @@ module Sucker
104
178
 
105
179
  describe "#build_query" do
106
180
 
181
+ let(:query) { worker.send(:build_query) }
182
+
107
183
  it "canonicalizes parameters" do
108
- query = worker.send(:build_query)
109
184
  query.should match /Service=([^&]+)&Timestamp=([^&]+)&Version=([^&]+)/
110
185
  end
111
186
 
187
+ it "includes the key for the current locale" do
188
+ worker.instance_variable_set(:@keys, { :us => 'foo' })
189
+ query.should include 'AWSAccessKeyId=foo'
190
+ end
191
+
192
+ it "includes a timestamp" do
193
+ query.should include 'Timestamp='
194
+ end
195
+
112
196
  it "sorts parameters" do
113
197
  worker.parameters["AAA"] = "foo"
114
- query = worker.send(:build_query)
115
198
  query.should match /^AAA=foo/
116
199
  end
117
200
 
118
201
  it "converts a parameter whose value is an array to a string" do
119
202
  worker.parameters["Foo"] = ["bar", "baz"]
120
- query = worker.send(:build_query)
121
203
  query.should match /Foo=bar%2Cbaz/
122
204
  end
123
205
 
124
206
  it "handles integer parameter values" do
125
207
  worker.parameters["Foo"] = 1
126
- query = worker.send(:build_query)
127
208
  query.should match /Foo=1/
128
209
  end
129
210
 
130
211
  it "handles floating-point parameter values" do
131
212
  worker.parameters["Foo"] = 1.0
132
- query = worker.send(:build_query)
133
213
  query.should match /Foo=1/
134
214
  end
135
215