hugs 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.md +4 -0
- data/VERSION +1 -1
- data/hugs.gemspec +5 -2
- data/lib/hugs.rb +35 -18
- data/test/test_hugs.rb +91 -35
- metadata +26 -11
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -9,6 +9,7 @@ GEM
|
|
9
9
|
git (>= 1.2.5)
|
10
10
|
rake
|
11
11
|
minitest (2.0.0)
|
12
|
+
multipart-post (1.0.1)
|
12
13
|
net-http-persistent (1.4.1)
|
13
14
|
nokogiri (1.4.4)
|
14
15
|
rake (0.8.7)
|
@@ -23,6 +24,7 @@ PLATFORMS
|
|
23
24
|
DEPENDENCIES
|
24
25
|
jeweler (~> 1.5.1)
|
25
26
|
minitest (~> 2.0.0)
|
27
|
+
multipart-post (~> 1.0.1)
|
26
28
|
net-http-persistent (~> 1.4.1)
|
27
29
|
nokogiri (~> 1.4.4)
|
28
30
|
rake
|
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.1.0
|
data/hugs.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{hugs}
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.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 = ["retr0h"]
|
12
|
-
s.date = %q{2010-12-
|
12
|
+
s.date = %q{2010-12-23}
|
13
13
|
s.email = %q{john@dewey.ws}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
@@ -45,6 +45,7 @@ Gem::Specification.new do |s|
|
|
45
45
|
s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
46
46
|
s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.4"])
|
47
47
|
s.add_runtime_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
48
|
+
s.add_runtime_dependency(%q<multipart-post>, ["~> 1.0.1"])
|
48
49
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
49
50
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
50
51
|
s.add_development_dependency(%q<minitest>, ["~> 2.0.0"])
|
@@ -53,6 +54,7 @@ Gem::Specification.new do |s|
|
|
53
54
|
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
54
55
|
s.add_dependency(%q<nokogiri>, ["~> 1.4.4"])
|
55
56
|
s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
57
|
+
s.add_dependency(%q<multipart-post>, ["~> 1.0.1"])
|
56
58
|
s.add_dependency(%q<rake>, [">= 0"])
|
57
59
|
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
58
60
|
s.add_dependency(%q<minitest>, ["~> 2.0.0"])
|
@@ -62,6 +64,7 @@ Gem::Specification.new do |s|
|
|
62
64
|
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
63
65
|
s.add_dependency(%q<nokogiri>, ["~> 1.4.4"])
|
64
66
|
s.add_dependency(%q<net-http-persistent>, ["~> 1.4.1"])
|
67
|
+
s.add_dependency(%q<multipart-post>, ["~> 1.0.1"])
|
65
68
|
s.add_dependency(%q<rake>, [">= 0"])
|
66
69
|
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
67
70
|
s.add_dependency(%q<minitest>, ["~> 2.0.0"])
|
data/lib/hugs.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
require "yajl"
|
3
|
-
require "nokogiri"
|
1
|
+
%w(net/http/persistent net/http/post/multipart yajl nokogiri).each { |r| require r }
|
4
2
|
|
5
3
|
class Hugs
|
6
4
|
Headers = {
|
@@ -8,7 +6,12 @@ class Hugs
|
|
8
6
|
:xml => "application/xml",
|
9
7
|
}.freeze
|
10
8
|
|
11
|
-
|
9
|
+
Classes = [
|
10
|
+
Net::HTTP::Get,
|
11
|
+
Net::HTTP::Delete,
|
12
|
+
Net::HTTP::Post,
|
13
|
+
Net::HTTP::Put,
|
14
|
+
].freeze
|
12
15
|
|
13
16
|
##
|
14
17
|
# Required options:
|
@@ -36,11 +39,12 @@ class Hugs
|
|
36
39
|
# - +:body+: A sub Hash to be JSON encoded, and posted in
|
37
40
|
# the message body.
|
38
41
|
|
39
|
-
|
42
|
+
Classes.each do |clazz|
|
43
|
+
verb = clazz.to_s.split("::")[-1].tr 'A-Z', 'a-z'
|
44
|
+
|
40
45
|
define_method verb do |*args|
|
41
46
|
path = args[0]
|
42
47
|
params = args[1] || {}
|
43
|
-
clazz = eval "Net::HTTP::#{verb.capitalize}"
|
44
48
|
|
45
49
|
response = response_for(clazz, path, params)
|
46
50
|
response.body = parse response.body
|
@@ -66,27 +70,40 @@ private
|
|
66
70
|
# Method arguments have been documented in the callers.
|
67
71
|
|
68
72
|
def response_for request, path, params
|
69
|
-
query
|
70
|
-
body
|
73
|
+
query = params[:query] && params.delete(:query)
|
74
|
+
body = params[:body] && params.delete(:body)
|
75
|
+
upload = params[:upload] && params.delete(:upload)
|
71
76
|
|
72
77
|
@http ||= Net::HTTP::Persistent.new
|
73
78
|
@url ||= URI.parse "#{@scheme}://#{@host}:#{@port}"
|
74
79
|
|
75
|
-
|
76
|
-
|
77
|
-
|
80
|
+
if upload && request.class === Net::HTTP::Post
|
81
|
+
parts = upload[:parts] || {}
|
82
|
+
parts[:file] = UploadIO.new(parts[:file], upload[:content_type]) if parts[:file]
|
83
|
+
|
84
|
+
request = Net::HTTP::Post::Multipart.new path_with_query(path, query), parts
|
85
|
+
else
|
86
|
+
request = request.new path_with_query path, query
|
87
|
+
request.body = encode(body) if body
|
88
|
+
|
89
|
+
common_headers request
|
90
|
+
end
|
78
91
|
|
92
|
+
request.basic_auth(@user, @password) if requires_authentication?
|
79
93
|
@http.request(@url, request)
|
80
94
|
end
|
81
95
|
|
96
|
+
def path_with_query path, query
|
97
|
+
[path, query].compact.join "?"
|
98
|
+
end
|
99
|
+
|
82
100
|
def common_headers request
|
83
|
-
request
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
request.add_field "
|
89
|
-
request.add_field "content-type", Headers[@type]
|
101
|
+
case request
|
102
|
+
when Net::HTTP::Get, Net::HTTP::Delete
|
103
|
+
request.add_field "Accept", Headers[@type]
|
104
|
+
when Net::HTTP::Post, Net::HTTP::Put
|
105
|
+
request.add_field "Accept", Headers[@type]
|
106
|
+
request.add_field "Content-Type", Headers[@type]
|
90
107
|
end
|
91
108
|
end
|
92
109
|
|
data/test/test_hugs.rb
CHANGED
@@ -2,10 +2,14 @@
|
|
2
2
|
|
3
3
|
describe Hugs do
|
4
4
|
before do
|
5
|
+
@scheme = "https"
|
6
|
+
@host = "example.com"
|
7
|
+
@port = 80
|
8
|
+
@base = "#{@host}:#{@port}"
|
5
9
|
@valid_options = {
|
6
|
-
:host =>
|
7
|
-
:port =>
|
8
|
-
:scheme =>
|
10
|
+
:host => @host,
|
11
|
+
:port => @port,
|
12
|
+
:scheme => @scheme,
|
9
13
|
}
|
10
14
|
|
11
15
|
WebMock.reset!
|
@@ -17,39 +21,91 @@ describe Hugs do
|
|
17
21
|
@request = Net::HTTP::Get
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
describe "path" do
|
25
|
+
it "is valid" do
|
26
|
+
stub_request :get, "#{@scheme}://#{@base}/"
|
22
27
|
|
23
|
-
|
28
|
+
@instance.send :response_for, @request, "/", {}
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
assert_requested :get, "#{@scheme}://#{@base}/"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is valid when an invalid :query is supplied" do
|
34
|
+
stub_request :get, "#{@scheme}://#{@base}/"
|
35
|
+
|
36
|
+
@instance.send :response_for, @request, "/", :query => nil
|
37
|
+
|
38
|
+
assert_requested :get, "#{@scheme}://#{@base}/"
|
39
|
+
end
|
27
40
|
|
28
|
-
|
29
|
-
|
41
|
+
it "also has a query string" do
|
42
|
+
stub_request(:get, "#{@scheme}://#{@base}/").with:query => {"foo" => "bar"}
|
30
43
|
|
31
|
-
|
44
|
+
@instance.send :response_for, @request, "/", :query => "foo=bar"
|
32
45
|
|
33
|
-
|
46
|
+
assert_requested :get, "#{@scheme}://#{@base}/", :query => {"foo" => "bar"}
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
|
-
|
37
|
-
|
50
|
+
describe "multi-part" do
|
51
|
+
Content_Type_Matcher = %r{multipart/form-data}
|
52
|
+
|
53
|
+
before do
|
54
|
+
@request = Net::HTTP::Post
|
55
|
+
end
|
56
|
+
|
57
|
+
it "uploads a file" do
|
58
|
+
stub_request :post, "#{@scheme}://#{@base}/"
|
38
59
|
|
39
|
-
|
60
|
+
upload = {
|
61
|
+
:upload => {
|
62
|
+
:parts => { :file => "/dev/null" },
|
63
|
+
:content_type => "type/subtype"
|
64
|
+
}
|
65
|
+
}
|
40
66
|
|
41
|
-
|
67
|
+
@instance.send :response_for, @request, "/", upload
|
68
|
+
|
69
|
+
assert_requested :post, "#{@scheme}://#{@base}/", :body => %r{Content-Type: type/subtype}, :headers => {
|
70
|
+
"Content-Type" => Content_Type_Matcher
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
it "has parts" do
|
75
|
+
stub_request :post, "#{@scheme}://#{@base}/"
|
76
|
+
|
77
|
+
upload = {
|
78
|
+
:upload => {
|
79
|
+
:parts => { :foo => :bar, :baz => :xyzzy },
|
80
|
+
:content_type => "foo/bar"
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
@instance.send :response_for, @request, "/", upload
|
85
|
+
|
86
|
+
### wtf can't use mx together.
|
87
|
+
content_disposition_matcher = %r{^Content-Disposition: form-data; name="foo".*^bar.*^Content-Disposition: form-data; name="baz".*^xyzzy.*}m
|
88
|
+
assert_requested :post, "#{@scheme}://#{@base}/", :body => content_disposition_matcher, :headers => {
|
89
|
+
"Content-Type" => Content_Type_Matcher
|
90
|
+
}
|
91
|
+
end
|
42
92
|
end
|
43
93
|
|
44
94
|
describe "body" do
|
45
95
|
before do
|
46
|
-
stub_request :get, "
|
96
|
+
stub_request :get, "#{@scheme}://#{@base}/"
|
47
97
|
end
|
48
98
|
|
49
|
-
it "
|
99
|
+
it "is not set when :body invalid" do
|
50
100
|
@instance.send :response_for, @request, "/", :body => nil
|
51
101
|
|
52
|
-
assert_requested :get, "
|
102
|
+
assert_requested :get, "#{@scheme}://#{@base}/", :body => nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "is not set when :body is missing" do
|
106
|
+
@instance.send :response_for, @request, "/", {}
|
107
|
+
|
108
|
+
assert_requested :get, "#{@scheme}://#{@base}/", {}
|
53
109
|
end
|
54
110
|
|
55
111
|
describe "json" do
|
@@ -57,10 +113,10 @@ describe Hugs do
|
|
57
113
|
@instance = Hugs.new @valid_options.merge(:type => :json)
|
58
114
|
end
|
59
115
|
|
60
|
-
it "
|
116
|
+
it "is valid" do
|
61
117
|
@instance.send :response_for, @request, "/", :body => {:foo => :bar}
|
62
118
|
|
63
|
-
assert_requested :get, "
|
119
|
+
assert_requested :get, "#{@scheme}://#{@base}/", :body => '{"foo":"bar"}'
|
64
120
|
end
|
65
121
|
end
|
66
122
|
|
@@ -69,35 +125,35 @@ describe Hugs do
|
|
69
125
|
@instance = Hugs.new @valid_options.merge(:type => :xml)
|
70
126
|
end
|
71
127
|
|
72
|
-
it "
|
128
|
+
it "is valid" do
|
73
129
|
@instance.send :response_for, @request, "/", :body => "foo bar"
|
74
130
|
|
75
|
-
assert_requested :get, "
|
131
|
+
assert_requested :get, "#{@scheme}://#{@base}/", :body => "foo bar"
|
76
132
|
end
|
77
133
|
end
|
78
134
|
end
|
79
135
|
|
80
136
|
describe "headers" do
|
81
137
|
it "authenticates" do
|
82
|
-
stub_request :get, "
|
138
|
+
stub_request :get, "#{@scheme}://user:credentials@#{@base}/"
|
83
139
|
|
84
140
|
@instance = Hugs.new @valid_options.merge(:user => "user", :password => "credentials")
|
85
141
|
|
86
142
|
@instance.send :response_for, @request, "/", {}
|
87
143
|
|
88
|
-
assert_requested :get, "
|
144
|
+
assert_requested :get, "#{@scheme}://user:credentials@#{@base}/"
|
89
145
|
end
|
90
146
|
|
91
147
|
[:user, :password].each do |option|
|
92
148
|
it "doesn't authenticate when '#{option}' missing" do
|
93
|
-
stub_request :get, "
|
149
|
+
stub_request :get, "#{@scheme}://#{@base}/"
|
94
150
|
|
95
151
|
invalid_options = @valid_options.reject { |k,v| k == option }
|
96
152
|
@instance = Hugs.new invalid_options
|
97
153
|
|
98
154
|
@instance.send :response_for, @request, "/", {}
|
99
155
|
|
100
|
-
assert_requested :get, "
|
156
|
+
assert_requested :get, "#{@scheme}://#{@base}/"
|
101
157
|
end
|
102
158
|
end
|
103
159
|
|
@@ -110,13 +166,13 @@ describe Hugs do
|
|
110
166
|
clazz = eval "Net::HTTP::#{verb.capitalize}"
|
111
167
|
|
112
168
|
it "has '#{subtype}' Content-Type and Accept for '#{clazz}'" do
|
113
|
-
stub_request verb, "
|
169
|
+
stub_request verb, "#{@scheme}://#{@base}/"
|
114
170
|
|
115
171
|
@instance = Hugs.new @valid_options.merge(:type => type)
|
116
172
|
|
117
173
|
@instance.send :response_for, clazz, "/", {}
|
118
174
|
|
119
|
-
assert_requested verb, "
|
175
|
+
assert_requested verb, "#{@scheme}://#{@base}/", :headers => {
|
120
176
|
"Accept" => ["*/*", subtype], "Content-Type" => subtype }
|
121
177
|
end
|
122
178
|
end
|
@@ -125,13 +181,13 @@ describe Hugs do
|
|
125
181
|
clazz = eval "Net::HTTP::#{verb.capitalize}"
|
126
182
|
|
127
183
|
it "has '#{subtype}' Accept for '#{clazz}'" do
|
128
|
-
stub_request verb, "
|
184
|
+
stub_request verb, "#{@scheme}://#{@base}/"
|
129
185
|
|
130
186
|
@instance = Hugs.new @valid_options.merge(:type => type)
|
131
187
|
|
132
188
|
@instance.send :response_for, clazz, "/", {}
|
133
189
|
|
134
|
-
assert_requested verb, "
|
190
|
+
assert_requested verb, "#{@scheme}://#{@base}/", :headers => {
|
135
191
|
"Accept" => ["*/*", subtype] }
|
136
192
|
end
|
137
193
|
end
|
@@ -146,8 +202,8 @@ describe Hugs do
|
|
146
202
|
@instance = Hugs.new @valid_options.merge(:type => :json)
|
147
203
|
end
|
148
204
|
|
149
|
-
it "objectifies
|
150
|
-
stub_request(:get, "
|
205
|
+
it "objectifies and returns a hash" do
|
206
|
+
stub_request(:get, "#{@scheme}://#{@base}/").to_return :body => '{"foo":"bar"}'
|
151
207
|
|
152
208
|
response = @instance.get "/", :body => { :foo => :bar }
|
153
209
|
|
@@ -160,8 +216,8 @@ describe Hugs do
|
|
160
216
|
@instance = Hugs.new @valid_options.merge(:type => :xml)
|
161
217
|
end
|
162
218
|
|
163
|
-
it "parses
|
164
|
-
stub_request(:get, "
|
219
|
+
it "parses and returns a Nokogiri object" do
|
220
|
+
stub_request(:get, "#{@scheme}://#{@base}/").to_return :body => "<STORAGE></STORAGE>"
|
165
221
|
|
166
222
|
response = @instance.get "/", :body => { :foo => :bar }
|
167
223
|
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 2
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 2.0.0
|
9
|
+
version: 2.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- retr0h
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-12-
|
17
|
+
date: 2010-12-23 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -63,8 +63,23 @@ dependencies:
|
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: *id003
|
65
65
|
- !ruby/object:Gem::Dependency
|
66
|
-
name:
|
66
|
+
name: multipart-post
|
67
67
|
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 0
|
75
|
+
- 1
|
76
|
+
version: 1.0.1
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rake
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
68
83
|
none: false
|
69
84
|
requirements:
|
70
85
|
- - ">="
|
@@ -74,10 +89,10 @@ dependencies:
|
|
74
89
|
version: "0"
|
75
90
|
type: :development
|
76
91
|
prerelease: false
|
77
|
-
version_requirements: *
|
92
|
+
version_requirements: *id005
|
78
93
|
- !ruby/object:Gem::Dependency
|
79
94
|
name: jeweler
|
80
|
-
requirement: &
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
81
96
|
none: false
|
82
97
|
requirements:
|
83
98
|
- - ~>
|
@@ -89,10 +104,10 @@ dependencies:
|
|
89
104
|
version: 1.5.1
|
90
105
|
type: :development
|
91
106
|
prerelease: false
|
92
|
-
version_requirements: *
|
107
|
+
version_requirements: *id006
|
93
108
|
- !ruby/object:Gem::Dependency
|
94
109
|
name: minitest
|
95
|
-
requirement: &
|
110
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
96
111
|
none: false
|
97
112
|
requirements:
|
98
113
|
- - ~>
|
@@ -104,10 +119,10 @@ dependencies:
|
|
104
119
|
version: 2.0.0
|
105
120
|
type: :development
|
106
121
|
prerelease: false
|
107
|
-
version_requirements: *
|
122
|
+
version_requirements: *id007
|
108
123
|
- !ruby/object:Gem::Dependency
|
109
124
|
name: webmock
|
110
|
-
requirement: &
|
125
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
111
126
|
none: false
|
112
127
|
requirements:
|
113
128
|
- - "="
|
@@ -119,7 +134,7 @@ dependencies:
|
|
119
134
|
version: 1.6.1
|
120
135
|
type: :development
|
121
136
|
prerelease: false
|
122
|
-
version_requirements: *
|
137
|
+
version_requirements: *id008
|
123
138
|
description:
|
124
139
|
email: john@dewey.ws
|
125
140
|
executables: []
|