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 ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.2-p0@hugs
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "yajl-ruby", "~> 0.7.8"
4
+ gem "net-http-persistent", "~> 1.4.1"
5
+
6
+ group :development do
7
+ gem "rake"
8
+ gem "jeweler", "~> 1.5.1"
9
+ gem "minitest", "~> 2.0.0"
10
+ gem "mocha", "~> 0.9.10"
11
+ end
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
@@ -0,0 +1,4 @@
1
+ "THE BEER-WARE LICENSE" (Revision 42):
2
+ <john@dewey.ws> wrote this file. As long as you retain this notice you
3
+ can do whatever you want with this stuff. If we meet some day, and you think
4
+ this stuff is worth it, you can buy me a beer in return John-B Dewey Jr.
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
@@ -0,0 +1,13 @@
1
+ Bundler.setup :default, :test
2
+
3
+ require "minitest/spec"
4
+ require "mocha"
5
+
6
+ #Dir[File.join "./lib", "**", "*.rb"].each { |f| require f }
7
+
8
+ require "./lib/hugs"
9
+
10
+ class MiniTest::Unit::TestCase
11
+ end
12
+
13
+ MiniTest::Unit.autorun
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