hugs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.bundle/config +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +4 -0
- data/README.md +34 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/lib/hugs.rb +93 -0
- data/test/support.rb +13 -0
- data/test/test_hugs.rb +91 -0
- metadata +163 -0
data/.bundle/config
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-1.9.2-p0@hugs
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.5.1)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
minitest (2.0.0)
|
10
|
+
mocha (0.9.10)
|
11
|
+
rake
|
12
|
+
net-http-persistent (1.4.1)
|
13
|
+
rake (0.8.7)
|
14
|
+
yajl-ruby (0.7.8)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
jeweler (~> 1.5.1)
|
21
|
+
minitest (~> 2.0.0)
|
22
|
+
mocha (~> 0.9.10)
|
23
|
+
net-http-persistent (~> 1.4.1)
|
24
|
+
rake
|
25
|
+
yajl-ruby (~> 0.7.8)
|
data/LICENSE
ADDED
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Hugs
|
2
|
+
|
3
|
+
Hugs net-http-persistent with convenient get, delete, post, and put methods.
|
4
|
+
|
5
|
+
Opted to write this gem for two reasons:
|
6
|
+
|
7
|
+
* [Ganeti's API](http://docs.ganeti.org/ganeti/2.2/html/rapi.html), required
|
8
|
+
the sending of a message body with the HTTP Get request, which
|
9
|
+
[rest-client](https://github.com/archiloque/rest-client) does not do.
|
10
|
+
* Wanted a [fast](http://blog.segment7.net/articles/2010/05/07/net-http-is-not-slow),
|
11
|
+
thread-safe, and persistent client.
|
12
|
+
|
13
|
+
## Assumptions
|
14
|
+
|
15
|
+
* The webservice returns JSON.
|
16
|
+
* You want to objectify the returned JSON.
|
17
|
+
* The message body is JSON.
|
18
|
+
* The webservice requires basic auth (will remove this requirement shortly).
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
### Bundler
|
23
|
+
|
24
|
+
gem "hugs"
|
25
|
+
|
26
|
+
### Examples
|
27
|
+
|
28
|
+
See the 'Examples' section in the [wiki](http://github.com/retr0h/rubineti/wiki/).
|
29
|
+
|
30
|
+
### TODO
|
31
|
+
|
32
|
+
* Remove HTTP Auth requirement, as mentioned in the 'Assumptions' section.
|
33
|
+
* Move @request instance method in #response_for to local. It was set to an instance
|
34
|
+
for ease of testing but it bothers me.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "jeweler"
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "hugs"
|
8
|
+
gem.summary = %Q{Hugs net-http-persistent with convenient get, delete, post, and put methods.}
|
9
|
+
gem.email = "john@dewey.ws"
|
10
|
+
gem.homepage = "http://github.com/retr0h/hugs"
|
11
|
+
gem.authors = ["retr0h"]
|
12
|
+
end
|
13
|
+
Jeweler::GemcutterTasks.new
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
16
|
+
end
|
17
|
+
|
18
|
+
require "rake/testtask"
|
19
|
+
Rake::TestTask.new(:test) do |test|
|
20
|
+
test.libs << "lib" << "test"
|
21
|
+
test.pattern = "test/**/test_*.rb"
|
22
|
+
test.verbose = true
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/hugs.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require "net/http/persistent"
|
2
|
+
require "yajl"
|
3
|
+
|
4
|
+
class Hugs
|
5
|
+
Headers = {
|
6
|
+
:json => "application/json"
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
##
|
10
|
+
# Required options:
|
11
|
+
# +user+: A String containing the username for use in HTTP Basic auth.
|
12
|
+
# +password+: A String containing the password for use in HTTP Basic auth.
|
13
|
+
# +host+: A String with the host to connect.
|
14
|
+
# Optional:
|
15
|
+
# +port+: An Integer containing the port to connect.
|
16
|
+
# +scheme+: A String containing the HTTP scheme.
|
17
|
+
|
18
|
+
def initialize options
|
19
|
+
@user = options[:user]
|
20
|
+
@password = options[:password]
|
21
|
+
@host = options[:host]
|
22
|
+
@port = options[:port] || 80
|
23
|
+
@scheme = options[:scheme] || "https"
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Perform an HTTP get, delete, post, or put.
|
28
|
+
# +path+: A String with the path to the HTTP resource.
|
29
|
+
# +params+: A Hash with the following keys:
|
30
|
+
# - +:query+: Query String in the format "foo=bar"
|
31
|
+
# - +:body+: A sub Hash to be JSON encoded, and posted in
|
32
|
+
# the message body.
|
33
|
+
|
34
|
+
%w(get delete post put).each do |verb|
|
35
|
+
define_method verb do |*args|
|
36
|
+
path = args[0]
|
37
|
+
params = args[1] || {}
|
38
|
+
clazz = eval "Net::HTTP::#{verb.capitalize}"
|
39
|
+
|
40
|
+
parse response_for(clazz, path, params)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# :method: get
|
46
|
+
|
47
|
+
##
|
48
|
+
# :method: delete
|
49
|
+
|
50
|
+
##
|
51
|
+
# :method: post
|
52
|
+
|
53
|
+
##
|
54
|
+
# :method: put
|
55
|
+
|
56
|
+
private
|
57
|
+
##
|
58
|
+
# Worker method to be called by #get, #delete, #post, #put.
|
59
|
+
# Method arguments have been documented in the callers.
|
60
|
+
|
61
|
+
def response_for request, path, params
|
62
|
+
query = params[:query] && params.delete(:query)
|
63
|
+
body = params[:body] && params.delete(:body)
|
64
|
+
|
65
|
+
@http ||= Net::HTTP::Persistent.new
|
66
|
+
@url ||= URI.parse "#{@scheme}://#{@host}:#{@port}"
|
67
|
+
|
68
|
+
@request = request.new [path, query].compact.join "?"
|
69
|
+
@request.body = encode(body) if body
|
70
|
+
common_headers @request
|
71
|
+
|
72
|
+
@http.request(@url, @request).body
|
73
|
+
end
|
74
|
+
|
75
|
+
def common_headers request
|
76
|
+
request.basic_auth @user, @password
|
77
|
+
case request.class.to_s
|
78
|
+
when Net::HTTP::Get.to_s, Net::HTTP::Delete.to_s
|
79
|
+
request.add_field "accept", Headers[:json]
|
80
|
+
when Net::HTTP::Post.to_s, Net::HTTP::Put.to_s
|
81
|
+
request.add_field "accept", Headers[:json]
|
82
|
+
request.add_field "content-type", Headers[:json]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse data
|
87
|
+
::Yajl::Parser.parse data
|
88
|
+
end
|
89
|
+
|
90
|
+
def encode hash
|
91
|
+
::Yajl::Encoder.encode hash
|
92
|
+
end
|
93
|
+
end
|
data/test/support.rb
ADDED
data/test/test_hugs.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require "support"
|
2
|
+
require "base64"
|
3
|
+
require "hugs"
|
4
|
+
|
5
|
+
describe Hugs do
|
6
|
+
before do
|
7
|
+
@user = "user",
|
8
|
+
@password = "credentials"
|
9
|
+
@valid_options = {
|
10
|
+
:user => @user,
|
11
|
+
:password => @password,
|
12
|
+
:host => "example.com",
|
13
|
+
:port => 80,
|
14
|
+
:scheme => "https",
|
15
|
+
}
|
16
|
+
|
17
|
+
@instance = Hugs.new @valid_options
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#response_for" do
|
21
|
+
before do
|
22
|
+
@http = mock(:request => mock(:body => :body))
|
23
|
+
@request = Net::HTTP::Get
|
24
|
+
|
25
|
+
Net::HTTP::Persistent.stubs :new => @http
|
26
|
+
end
|
27
|
+
|
28
|
+
it "generates a path" do
|
29
|
+
@instance.send :response_for, @request, "/", {}
|
30
|
+
|
31
|
+
@instance.instance_variable_get(:@request).path.must_equal "/"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "generates a path when a valid :query exists" do
|
35
|
+
@instance.send :response_for, @request, "/", :query => "foo=bar"
|
36
|
+
|
37
|
+
@instance.instance_variable_get(:@request).path.must_equal "/?foo=bar"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "generates a path when a nil :query exists" do
|
41
|
+
@instance.send :response_for, @request, "/", :query => nil
|
42
|
+
|
43
|
+
@instance.instance_variable_get(:@request).path.must_equal "/"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "sets the body as JSON when a valid :body exists" do
|
47
|
+
@instance.send :response_for, @request, "/", :body => {:foo => :bar}
|
48
|
+
|
49
|
+
@instance.instance_variable_get(:@request).body.must_equal '{"foo":"bar"}'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "doesn't set the body when an invalid :body exists" do
|
53
|
+
@instance.send :response_for, @request, "/", :body => nil
|
54
|
+
|
55
|
+
@instance.instance_variable_get(:@request).body.must_be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "headers" do
|
59
|
+
Json_Headers_Matcher = %r{#{"application/json"}}
|
60
|
+
|
61
|
+
it "has authentication" do
|
62
|
+
@instance.send :response_for, @request, "/", {}
|
63
|
+
|
64
|
+
@instance.instance_variable_get(:@request).get_fields("authorization").join.
|
65
|
+
must_match %r{Basic #{Base64.encode64("#{@user}:#{@password}").delete("\r\n")}}
|
66
|
+
end
|
67
|
+
|
68
|
+
[Net::HTTP::Post, Net::HTTP::Put].each do |clazz|
|
69
|
+
it "has content-type and accept for '#{clazz}'" do
|
70
|
+
@instance.send :response_for, clazz, "/", {}
|
71
|
+
|
72
|
+
@instance.instance_variable_get(:@request).get_fields("content-type").join.
|
73
|
+
must_match Json_Headers_Matcher
|
74
|
+
@instance.instance_variable_get(:@request).get_fields("accept").join.
|
75
|
+
must_match Json_Headers_Matcher
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
[Net::HTTP::Get, Net::HTTP::Delete].each do |clazz|
|
80
|
+
it "has accept for '#{clazz}'" do
|
81
|
+
@instance.send :response_for, clazz, "/", {}
|
82
|
+
|
83
|
+
@instance.instance_variable_get(:@request).get_fields("accept").join.
|
84
|
+
must_match Json_Headers_Matcher
|
85
|
+
@instance.instance_variable_get(:@request).get_fields("content-type").
|
86
|
+
must_be_nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hugs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- retr0h
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-11 00:00:00 -08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: yajl-ruby
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 7
|
30
|
+
- 8
|
31
|
+
version: 0.7.8
|
32
|
+
type: :runtime
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: net-http-persistent
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 4
|
45
|
+
- 1
|
46
|
+
version: 1.4.1
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: jeweler
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 1
|
72
|
+
- 5
|
73
|
+
- 1
|
74
|
+
version: 1.5.1
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: minitest
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 2
|
87
|
+
- 0
|
88
|
+
- 0
|
89
|
+
version: 2.0.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: mocha
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ~>
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
- 9
|
103
|
+
- 10
|
104
|
+
version: 0.9.10
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: *id006
|
108
|
+
description:
|
109
|
+
email: john@dewey.ws
|
110
|
+
executables: []
|
111
|
+
|
112
|
+
extensions: []
|
113
|
+
|
114
|
+
extra_rdoc_files:
|
115
|
+
- LICENSE
|
116
|
+
- README.md
|
117
|
+
files:
|
118
|
+
- .bundle/config
|
119
|
+
- .rvmrc
|
120
|
+
- Gemfile
|
121
|
+
- Gemfile.lock
|
122
|
+
- LICENSE
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- VERSION
|
126
|
+
- lib/hugs.rb
|
127
|
+
- test/support.rb
|
128
|
+
- test/test_hugs.rb
|
129
|
+
has_rdoc: true
|
130
|
+
homepage: http://github.com/retr0h/hugs
|
131
|
+
licenses: []
|
132
|
+
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
version: "0"
|
154
|
+
requirements: []
|
155
|
+
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 1.3.7
|
158
|
+
signing_key:
|
159
|
+
specification_version: 3
|
160
|
+
summary: Hugs net-http-persistent with convenient get, delete, post, and put methods.
|
161
|
+
test_files:
|
162
|
+
- test/support.rb
|
163
|
+
- test/test_hugs.rb
|