kookaburra 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -5,7 +5,7 @@ order to keep acceptance tests maintainable.
5
5
 
6
6
  ## Requirements ##
7
7
 
8
- Requires Ruby 1.9. Tested with both MRI and JRUBY (not that you must run
8
+ Requires Ruby 1.9. Tested with both MRI and JRuby (note that you must run
9
9
  JRuby in 1.9 compatability mode.)
10
10
 
11
11
  ## Installation ##
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.1.0
data/kookaburra.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "kookaburra"
8
- s.version = "1.0.0"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Wilger", "Sam Livingston-Gray", "Ravi Gadad"]
12
- s.date = "2012-10-14"
12
+ s.date = "2012-12-14"
13
13
  s.description = "Cucumber + Capybara = Kookaburra? It made sense at the time."
14
14
  s.email = "johnwilger@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
28
28
  "Rakefile",
29
29
  "VERSION",
30
30
  "kookaburra.gemspec",
31
+ "lib/core_ext/object/to_param.rb",
32
+ "lib/core_ext/object/to_query.rb",
31
33
  "lib/kookaburra.rb",
32
34
  "lib/kookaburra/api_driver.rb",
33
35
  "lib/kookaburra/assertion.rb",
@@ -0,0 +1,81 @@
1
+ # If ActiveSupport is available, use the #to_param method it provides,
2
+ # otherwise, use our own. The code is taken from ActiveSupport 3.2.8.
3
+ begin
4
+ require 'active_support/core_ext/object/to_param'
5
+ rescue LoadError
6
+ # Copyright (c) 2005-2012 David Heinemeier Hansson
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to
13
+ # permit persons to whom the Software is furnished to do so, subject to
14
+ # the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be
17
+ # included in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ class Object
27
+ # Alias of <tt>to_s</tt>.
28
+ def to_param
29
+ to_s
30
+ end
31
+ end
32
+
33
+ class NilClass
34
+ def to_param
35
+ self
36
+ end
37
+ end
38
+
39
+ class TrueClass
40
+ def to_param
41
+ self
42
+ end
43
+ end
44
+
45
+ class FalseClass
46
+ def to_param
47
+ self
48
+ end
49
+ end
50
+
51
+ class Array
52
+ # Calls <tt>to_param</tt> on all its elements and joins the result with
53
+ # slashes. This is used by <tt>url_for</tt> in Action Pack.
54
+ def to_param
55
+ collect { |e| e.to_param }.join '/'
56
+ end
57
+ end
58
+
59
+ class Hash
60
+ # Returns a string representation of the receiver suitable for use as a URL
61
+ # query string:
62
+ #
63
+ # {:name => 'David', :nationality => 'Danish'}.to_param
64
+ # # => "name=David&nationality=Danish"
65
+ #
66
+ # An optional namespace can be passed to enclose the param names:
67
+ #
68
+ # {:name => 'David', :nationality => 'Danish'}.to_param('user')
69
+ # # => "user[name]=David&user[nationality]=Danish"
70
+ #
71
+ # The string pairs "key=value" that conform the query string
72
+ # are sorted lexicographically in ascending order.
73
+ #
74
+ # This method is also aliased as +to_query+.
75
+ def to_param(namespace = nil)
76
+ collect do |key, value|
77
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
78
+ end.sort * '&'
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,53 @@
1
+ # If ActiveSupport is available, use the #to_query method it provides,
2
+ # otherwise, use our own. The code is taken from ActiveSupport 3.2.8.
3
+ begin
4
+ require 'active_support/core_ext/object/to_query'
5
+ rescue LoadError
6
+ # Copyright (c) 2005-2012 David Heinemeier Hansson
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to
13
+ # permit persons to whom the Software is furnished to do so, subject to
14
+ # the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be
17
+ # included in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ require 'core_ext/object/to_param'
27
+
28
+ class Object
29
+ # Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
30
+ # param name.
31
+ #
32
+ # Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
33
+ def to_query(key)
34
+ require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
35
+ "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
36
+ end
37
+ end
38
+
39
+ class Array
40
+ # Converts an array into a string suitable for use as a URL query string,
41
+ # using the given +key+ as the param name.
42
+ #
43
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
44
+ def to_query(key)
45
+ prefix = "#{key}[]"
46
+ collect { |value| value.to_query(prefix) }.join '&'
47
+ end
48
+ end
49
+
50
+ class Hash
51
+ alias_method :to_query, :to_param
52
+ end
53
+ end
@@ -1,4 +1,5 @@
1
1
  require 'restclient'
2
+ require 'core_ext/object/to_query'
2
3
  require 'kookaburra/exceptions'
3
4
 
4
5
  class Kookaburra
@@ -99,29 +100,31 @@ class Kookaburra
99
100
  # Convenience method to make a POST request
100
101
  #
101
102
  # @see APIDriver#request
102
- def post(path, data)
103
- request(:post, path, data)
103
+ def post(path, data = nil, headers = {})
104
+ request(:post, path, data, headers)
104
105
  end
105
106
 
106
107
  # Convenience method to make a PUT request
107
108
  #
108
109
  # @see APIDriver#request
109
- def put(path, data)
110
- request(:put, path, data)
110
+ def put(path, data = nil, headers = {})
111
+ request(:put, path, data, headers)
111
112
  end
112
113
 
113
114
  # Convenience method to make a GET request
114
115
  #
115
116
  # @see APIDriver#request
116
- def get(path)
117
- request(:get, path)
117
+ def get(path, data = nil, headers = {})
118
+ path = add_querystring_to_path(path, data)
119
+ request(:get, path, nil, headers)
118
120
  end
119
121
 
120
122
  # Convenience method to make a DELETE request
121
123
  #
122
124
  # @see APIDriver#request
123
- def delete(path)
124
- request(:delete, path)
125
+ def delete(path, data = nil, headers = {})
126
+ path = add_querystring_to_path(path, data)
127
+ request(:delete, path, nil, headers)
125
128
  end
126
129
 
127
130
  # Make an HTTP request
@@ -161,8 +164,9 @@ class Kookaburra
161
164
  #
162
165
  # @raise [Kookaburra::UnexpectedResponse] Raised if the HTTP
163
166
  # response received is not in the 2XX-3XX range.
164
- def request(method, path, data = nil)
167
+ def request(method, path, data, headers)
165
168
  data = encode(data)
169
+ headers = global_headers.merge(headers)
166
170
  response = @http_client.send(method, url_for(path), *[data, headers].compact)
167
171
  decode(response.body)
168
172
  rescue RestClient::Exception => e
@@ -171,7 +175,12 @@ class Kookaburra
171
175
 
172
176
  private
173
177
 
174
- def headers
178
+ def add_querystring_to_path(path, data)
179
+ return path if data.nil? || data == {}
180
+ "#{path}?#{data.to_query}"
181
+ end
182
+
183
+ def global_headers
175
184
  self.class.headers
176
185
  end
177
186
 
@@ -13,90 +13,153 @@ describe Kookaburra::APIDriver do
13
13
 
14
14
  let(:client) { stub('RestClient') }
15
15
 
16
- it 'sends POST requests to the server and returns the response body' do
17
- client.should_receive(:post).with(url_for('/foo'), 'bar', {}) \
18
- .and_return(response)
19
- api.post('/foo', 'bar').should == 'foo'
20
- end
21
-
22
- it 'sends PUT requests to the server and returns the response body' do
23
- client.should_receive(:put).with(url_for('/foo'), 'bar', {}) \
24
- .and_return(response)
25
- api.put('/foo', 'bar').should == 'foo'
26
- end
16
+ shared_examples_for 'any type of HTTP request' do |http_verb|
17
+ context "(#{http_verb})" do
18
+ before(:each) do
19
+ client.stub!(http_verb => response)
20
+ end
27
21
 
28
- it 'sends GET requests to the server and returns the response body' do
29
- client.should_receive(:get).with(url_for('/foo'), {}) \
30
- .and_return(response)
31
- api.get('/foo').should == 'foo'
32
- end
22
+ it 'returns the response body' do
23
+ api.send(http_verb, '/foo').should == 'foo'
24
+ end
33
25
 
34
- it 'sends DELETE requests to the server and returns the response body' do
35
- client.should_receive(:delete).with(url_for('/foo'), {}) \
36
- .and_return(response)
37
- api.delete('/foo').should == 'foo'
38
- end
26
+ it 'raises an UnexpectedResponse if the request is not successful' do
27
+ response.stub!(code: 500)
28
+ client.stub!(http_verb).and_raise(RestClient::Exception.new(response))
29
+ lambda { api.send(http_verb, '/foo') } \
30
+ .should raise_error(Kookaburra::UnexpectedResponse)
31
+ end
39
32
 
40
- describe 'any type of HTTP request' do
41
- before(:each) do
42
- client.stub!(:http_verb => response)
43
- end
33
+ let(:expect_client_to_receive_headers) { ->(expected_headers) {
34
+ # Some HTTP verb methods pass data, some don't, and their arity
35
+ # is different
36
+ client.should_receive(http_verb) do |path, data_or_headers, headers|
37
+ headers ||= data_or_headers
38
+ expect(headers).to eq(expected_headers)
39
+ response
40
+ end
41
+ }}
42
+
43
+ context 'when custom global headers are specified' do
44
+ let(:api) {
45
+ klass = Class.new(Kookaburra::APIDriver) do
46
+ header 'Header-Foo', 'Baz'
47
+ header 'Header-Bar', 'Bam'
48
+ end
49
+ klass.new(configuration, client)
50
+ }
51
+
52
+ it "sets global headers on requests" do
53
+ expect_client_to_receive_headers.call('Header-Foo' => 'Baz', 'Header-Bar' => 'Bam')
54
+ api.send(http_verb, '/foo')
55
+ end
44
56
 
45
- it 'returns the response body' do
46
- api.request(:http_verb, '/foo', 'bar').should == 'foo'
47
- end
57
+ context "and additional headers are specified on a single call" do
58
+ it 'sets both the global and additional headers on the request' do
59
+ expect_client_to_receive_headers.call('Header-Foo' => 'Baz', 'Header-Bar' => 'Bam', 'Yak' => 'Shaved')
60
+ api.send(http_verb, '/foo', nil, 'Yak' => 'Shaved')
61
+ end
48
62
 
49
- it 'raises an UnexpectedResponse if the request is not successful' do
50
- response.stub!(code: 500)
51
- client.stub!(:http_verb).and_raise(RestClient::Exception.new(response))
52
- lambda { api.request(:http_verb, '/foo') } \
53
- .should raise_error(Kookaburra::UnexpectedResponse)
54
- end
63
+ it 'only sets the global headers on subsequent requests' do
64
+ api.send(http_verb, '/foo', nil, 'Yak' => 'Shaved')
55
65
 
56
- context 'when custom headers are specified' do
57
- let(:api) {
58
- klass = Class.new(Kookaburra::APIDriver) do
59
- header 'Header-Foo', 'Baz'
60
- header 'Header-Bar', 'Bam'
66
+ expect_client_to_receive_headers.call('Header-Foo' => 'Baz', 'Header-Bar' => 'Bam')
67
+ api.send(http_verb, '/foo')
68
+ end
61
69
  end
62
- klass.new(configuration, client)
63
- }
64
70
 
65
- it "sets headers on requests" do
66
- client.should_receive(:http_verb).with(url_for('/foo'), {}, 'Header-Foo' => 'Baz', 'Header-Bar' => 'Bam')
67
- api.request(:http_verb, '/foo', {})
71
+ context 'and global header values are overriden by a single call' do
72
+ it 'uses the override value for the the request' do
73
+ expect_client_to_receive_headers.call('Header-Foo' => 'Baz', 'Header-Bar' => 'Yak')
74
+ api.send(http_verb, '/foo', nil, 'Header-Bar' => 'Yak')
75
+ end
76
+
77
+ it 'uses the global value for subsequent requests' do
78
+ api.send(http_verb, '/foo', nil, 'Header-Bar' => 'Yak')
79
+
80
+ expect_client_to_receive_headers.call('Header-Foo' => 'Baz', 'Header-Bar' => 'Bam')
81
+ api.send(http_verb, '/foo')
82
+ end
83
+ end
68
84
  end
69
- end
70
85
 
71
- context 'when a custom encoder is specified' do
72
- let(:api) {
73
- klass = Class.new(Kookaburra::APIDriver) do
74
- encode_with { |data| :some_encoded_data }
86
+ context 'when headers are specified' do
87
+ it 'sets the headers on the request' do
88
+ expected_headers = {'Foo' => 'Bar', 'Baz' => 'Bam'}
89
+ expect_client_to_receive_headers.call(expected_headers)
90
+ api.send(http_verb, '/foo', nil, expected_headers)
75
91
  end
76
- klass.new(configuration, client)
77
- }
78
92
 
79
- it "encodes input to requests" do
80
- client.should_receive(:http_verb) do |_, data, _|
81
- data.should == :some_encoded_data
82
- response
93
+ it 'does not set the headers on subsequent requests' do
94
+ api.send(http_verb, '/foo', nil, :foo => :bar)
95
+
96
+ expect_client_to_receive_headers.call({})
97
+ api.send(http_verb, '/foo')
83
98
  end
99
+ end
84
100
 
85
- api.request(:http_verb, '/foo', :ruby_data)
101
+ context 'when a custom decoder is specified' do
102
+ let(:api) {
103
+ klass = Class.new(Kookaburra::APIDriver) do
104
+ decode_with { |data| :some_decoded_data }
105
+ end
106
+ klass.new(configuration, client)
107
+ }
108
+
109
+ it "decodes response bodies from requests" do
110
+ api.send(http_verb, '/foo').should == :some_decoded_data
111
+ end
86
112
  end
87
113
  end
114
+ end
88
115
 
89
- context 'when a custom decoder is specified' do
90
- let(:api) {
91
- klass = Class.new(Kookaburra::APIDriver) do
92
- decode_with { |data| :some_decoded_data }
116
+ shared_examples_for 'it encodes request data' do |http_verb|
117
+ context "(#{http_verb})" do
118
+ before(:each) do
119
+ client.stub!(http_verb => response)
120
+ end
121
+
122
+ context 'when a custom encoder is specified' do
123
+ let(:api) {
124
+ klass = Class.new(Kookaburra::APIDriver) do
125
+ encode_with { |data|
126
+ data.should == :some_ruby_data
127
+ :some_encoded_data
128
+ }
129
+ end
130
+ klass.new(configuration, client)
131
+ }
132
+
133
+ it "encodes input to requests" do
134
+ client.should_receive(http_verb) do |_, data, _|
135
+ data.should == :some_encoded_data
136
+ response
137
+ end
138
+
139
+ api.send(http_verb, '/foo', :some_ruby_data)
93
140
  end
94
- klass.new(configuration, client)
95
- }
141
+ end
142
+ end
143
+ end
96
144
 
97
- it "decodes response bodies from requests" do
98
- api.request(:http_verb, '/foo').should == :some_decoded_data
145
+ shared_examples_for 'it encodes data as a querystring' do |http_verb|
146
+ context "(#{http_verb})" do
147
+ it 'adds data as querystirng params' do
148
+ client.should_receive(http_verb).with(url_for('/foo?bar=baz&yak=shaved'), {}) \
149
+ .and_return(response)
150
+ api.send(http_verb, '/foo', bar: 'baz', yak: 'shaved')
99
151
  end
100
152
  end
101
153
  end
154
+
155
+ it_behaves_like 'any type of HTTP request', :get
156
+ it_behaves_like 'any type of HTTP request', :post
157
+ it_behaves_like 'any type of HTTP request', :put
158
+ it_behaves_like 'any type of HTTP request', :delete
159
+
160
+ it_behaves_like 'it encodes data as a querystring', :get
161
+ it_behaves_like 'it encodes data as a querystring', :delete
162
+
163
+ it_behaves_like 'it encodes request data', :post
164
+ it_behaves_like 'it encodes request data', :put
102
165
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kookaburra
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-10-14 00:00:00.000000000 Z
14
+ date: 2012-12-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rest-client
@@ -208,6 +208,8 @@ files:
208
208
  - Rakefile
209
209
  - VERSION
210
210
  - kookaburra.gemspec
211
+ - lib/core_ext/object/to_param.rb
212
+ - lib/core_ext/object/to_query.rb
211
213
  - lib/kookaburra.rb
212
214
  - lib/kookaburra/api_driver.rb
213
215
  - lib/kookaburra/assertion.rb
@@ -252,7 +254,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
252
254
  version: '0'
253
255
  segments:
254
256
  - 0
255
- hash: -1361909781639378810
257
+ hash: -3075821559668997121
256
258
  required_rubygems_version: !ruby/object:Gem::Requirement
257
259
  none: false
258
260
  requirements: