silly_putty 0.1.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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/lib/silly_putty.rb +3 -0
- data/lib/silly_putty/base.rb +50 -0
- data/lib/silly_putty/clients/auto_detect.rb +4 -0
- data/lib/silly_putty/clients/kirk.rb +28 -0
- data/lib/silly_putty/clients/net_http.rb +27 -0
- data/lib/silly_putty/clients/patron.rb +32 -0
- data/lib/silly_putty/version.rb +3 -0
- data/silly_putty.gemspec +21 -0
- data/spec/kirk_spec.rb +10 -0
- data/spec/net_http_spec.rb +10 -0
- data/spec/patron_spec.rb +10 -0
- data/spec/spec_helper.rb +119 -0
- data/test/test_silly.rb +19 -0
- metadata +76 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/silly_putty.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
module SillyPutty
|
3
|
+
class Base
|
4
|
+
attr_reader :host, :port, :base_url
|
5
|
+
attr_accessor :request_handler, :response_handler
|
6
|
+
|
7
|
+
def initialize(host, port)
|
8
|
+
@host = host
|
9
|
+
@port = port
|
10
|
+
@base_url = "http://" + host + ":" + port.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def request(method, uri, body, headers)
|
14
|
+
if (method == :GET || method == :DELETE || method == :HEAD) && body
|
15
|
+
raise ArgumentError, "#{method} must not contain a body!"
|
16
|
+
end
|
17
|
+
|
18
|
+
original = {:method => method, :base_url => @base_url, :path => uri, :body => body, :headers => headers}
|
19
|
+
fixedup = fixup_request(original)
|
20
|
+
|
21
|
+
@request_handler.call(fixedup) if @request_handler
|
22
|
+
|
23
|
+
response = perform_request(fixedup[:method], fixedup[:path], fixedup[:body], fixedup[:headers])
|
24
|
+
|
25
|
+
@response_handler.call({:status => response.status, :body => response.body, :headers => response.headers}) if @response_handler
|
26
|
+
|
27
|
+
response
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def fixup_request(original)
|
33
|
+
original
|
34
|
+
end
|
35
|
+
|
36
|
+
def perform_request(method, uri, body, headers)
|
37
|
+
raise 'not implemented!'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Response
|
42
|
+
attr_reader :status, :body, :headers
|
43
|
+
|
44
|
+
def initialize(status, body, headers)
|
45
|
+
@status = status
|
46
|
+
@body = body
|
47
|
+
@headers = headers
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'kirk/client'
|
2
|
+
|
3
|
+
module SillyPutty
|
4
|
+
class KirkClient < Base
|
5
|
+
private
|
6
|
+
def fixup_request(original)
|
7
|
+
headers = original[:headers]
|
8
|
+
headers = headers.merge({"Accept" => "*/*"})
|
9
|
+
|
10
|
+
if original[:body] && headers["Content-Type"].nil?
|
11
|
+
headers = headers.merge({"Content-Type" => "application/x-www-form-urlencoded"})
|
12
|
+
end
|
13
|
+
|
14
|
+
original.merge({:headers => headers})
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform_request(method, uri, body, headers)
|
18
|
+
response = Kirk::Client.request(method, @base_url + uri, nil, body, headers)
|
19
|
+
|
20
|
+
Response.new(response.status, response.body, response.headers)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless defined?(DefaultClient)
|
25
|
+
class DefaultClient < SillyPutty::KirkClient
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module SillyPutty
|
4
|
+
class NetHttpClient < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def fixup_request(original)
|
8
|
+
original.merge({:method => original[:method].to_s})
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform_request(method, uri, body, headers)
|
12
|
+
Net::HTTP.start(@host, @port) do |http|
|
13
|
+
response = http.send_request(method, uri, body, headers)
|
14
|
+
|
15
|
+
the_headers = {}
|
16
|
+
response.each_capitalized {|k,v| the_headers[k] = v}
|
17
|
+
|
18
|
+
Response.new(response.code.to_i, response.body, the_headers)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
unless defined?(DefaultClient)
|
24
|
+
class DefaultClient < SillyPutty::NetHttpClient
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'patron'
|
2
|
+
|
3
|
+
module SillyPutty
|
4
|
+
class PatronClient < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def fixup_request(original)
|
8
|
+
headers = original[:headers]
|
9
|
+
|
10
|
+
if !original[:body].nil? && headers["Content-Type"].nil?
|
11
|
+
headers = headers.merge({"Content-Type" => "application/x-www-form-urlencoded"})
|
12
|
+
end
|
13
|
+
|
14
|
+
original.merge({:headers => headers})
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform_request(method, uri, body, headers)
|
18
|
+
options = {}
|
19
|
+
options[:data] = body unless body.nil?
|
20
|
+
headers = headers ? headers : {}
|
21
|
+
|
22
|
+
response = Patron::Session.new.request(method.to_s.downcase.to_sym, @base_url + uri, headers, options)
|
23
|
+
|
24
|
+
Response.new(response.status, response.body, response.headers)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
unless defined?(DefaultClient)
|
29
|
+
class DefaultClient < SillyPutty::PatronClient
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/silly_putty.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "silly_putty/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "silly_putty"
|
7
|
+
s.version = SillyPutty::VERSION
|
8
|
+
s.authors = ["Sunny Gleason"]
|
9
|
+
s.email = ["sunny.gleason@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = "makes switching between http clients easy as pie"
|
12
|
+
s.description = "makes switching between http clients easy as pie"
|
13
|
+
|
14
|
+
s.rubyforge_project = "silly_putty"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
21
|
+
|
data/spec/kirk_spec.rb
ADDED
data/spec/patron_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
|
2
|
+
require 'silly_putty'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'webrick'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
# yes, this seemed clean at the time
|
8
|
+
class String
|
9
|
+
def to_class
|
10
|
+
chain = self.split "::"
|
11
|
+
i=0
|
12
|
+
res = chain.inject(Module) do |ans,obj|
|
13
|
+
break if ans.nil?
|
14
|
+
i+=1
|
15
|
+
klass = ans.const_get(obj)
|
16
|
+
# Make sure the current obj is a valid class
|
17
|
+
# Or it's a module but not the last element,
|
18
|
+
# as the last element should be a class
|
19
|
+
klass.is_a?(Class) || (klass.is_a?(Module) and i != chain.length) ? klass : nil
|
20
|
+
end
|
21
|
+
rescue NameError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class EchoServlet < WEBrick::HTTPServlet::AbstractServlet
|
27
|
+
def do_HEAD(request, response)
|
28
|
+
handle(:HEAD, request, response)
|
29
|
+
end
|
30
|
+
|
31
|
+
def do_GET(request, response)
|
32
|
+
handle(:GET, request, response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_POST(request, response)
|
36
|
+
handle(:POST, request, response)
|
37
|
+
end
|
38
|
+
|
39
|
+
def do_PUT(request, response)
|
40
|
+
handle(:PUT, request, response)
|
41
|
+
end
|
42
|
+
|
43
|
+
def do_DELETE(request, response)
|
44
|
+
handle(:DELETE, request, response)
|
45
|
+
end
|
46
|
+
|
47
|
+
def handle(method, request, response)
|
48
|
+
if request['expect'] == "100-continue" && request.http_version.to_s >= "1.1"
|
49
|
+
request.instance_variable_get(:@socket).write "HTTP/#{response.http_version} 100 continue\r\n\r\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
headers = {}
|
53
|
+
request.raw_header.each do |h|
|
54
|
+
h.chomp!
|
55
|
+
p = h.index(': ')
|
56
|
+
headers[h[0..p-1]] = h[p+2..-1]
|
57
|
+
end
|
58
|
+
|
59
|
+
response.status = request['x-desired-status'] || 200
|
60
|
+
response['Content-Type'] = request['x-desired-content-type'] || "application/json"
|
61
|
+
response.body = request['x-desired-body'] || JSON({
|
62
|
+
:method => method,
|
63
|
+
:headers => headers,
|
64
|
+
:uri => request.unparsed_uri,
|
65
|
+
:body => request.body
|
66
|
+
})
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
shared_examples "silly_putty" do
|
71
|
+
before(:each) do
|
72
|
+
@port = 5000 + rand(1000)
|
73
|
+
@client = client.to_class.new("localhost", @port)
|
74
|
+
@server = WEBrick::HTTPServer.new(:Port=>@port, :ServerName=>"localhost", :Logger => WEBrick::Log.new("/dev/null"), :AccessLog => [nil, nil])
|
75
|
+
@server.mount("/", EchoServlet)
|
76
|
+
Thread.new(@server) {|server| server.start}
|
77
|
+
end
|
78
|
+
|
79
|
+
after(:each) do
|
80
|
+
@server.stop
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should be instantiable" do
|
84
|
+
@client.nil?.should == false
|
85
|
+
end
|
86
|
+
|
87
|
+
it "methods work with nil body" do
|
88
|
+
[:GET, :DELETE].each do |m|
|
89
|
+
JSON(@client.request(m, "/foo", nil, {'Foo' => 'bar'}).body).should == {
|
90
|
+
"method"=> m.to_s,
|
91
|
+
"headers"=>{"Foo"=>"bar", "Host"=>"localhost:" + @port.to_s, "Accept"=>"*/*"},
|
92
|
+
"uri"=>"/foo", "body"=>nil}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "methods work with zero-length body" do
|
97
|
+
[:POST].each do |m|
|
98
|
+
JSON(@client.request(m, "/foo", "", {'Foo' => 'bar'}).body).should == {
|
99
|
+
"method"=> m.to_s,
|
100
|
+
"headers"=>{"Foo"=>"bar", "Host"=>"localhost:" + @port.to_s, "Accept"=>"*/*", "Content-Length"=>"0", "Content-Type"=>"application/x-www-form-urlencoded"},
|
101
|
+
"uri"=>"/foo", "body"=>nil}
|
102
|
+
end
|
103
|
+
[:PUT].each do |m|
|
104
|
+
JSON(@client.request(m, "/foo", "", {'Foo' => 'bar'}).body).should == {
|
105
|
+
"method"=> m.to_s,
|
106
|
+
"headers"=>{"Foo"=>"bar", "Host"=>"localhost:" + @port.to_s, "Accept"=>"*/*", "Content-Length"=>"0", "Content-Type"=>"application/x-www-form-urlencoded"},
|
107
|
+
"uri"=>"/foo", "body"=>nil}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "works with non-empty body" do
|
112
|
+
[:POST, :PUT].each do |m|
|
113
|
+
JSON(@client.request(m, "/foo", 'whee', {'Foo' => 'bar'}).body).should == {
|
114
|
+
"method"=> m.to_s,
|
115
|
+
"headers"=>{"Host"=>"localhost:" + @port.to_s, "Accept"=>"*/*","Foo"=>"bar", "Content-Length"=>"4", "Content-Type"=>"application/x-www-form-urlencoded"},
|
116
|
+
"uri"=>"/foo", "body"=>'whee'}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/test/test_silly.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'silly_putty'
|
3
|
+
require 'silly_putty/clients/auto_detect'
|
4
|
+
require 'silly_putty/clients/kirk'
|
5
|
+
require 'silly_putty/clients/net_http'
|
6
|
+
require 'silly_putty/clients/patron'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
clients = [
|
10
|
+
SillyPutty::NetHttpClient.new("localhost", 8080),
|
11
|
+
SillyPutty::KirkClient.new("localhost", 8080),
|
12
|
+
SillyPutty::PatronClient.new("localhost", 8080),
|
13
|
+
SillyPutty::DefaultClient.new("localhost", 8080)
|
14
|
+
]
|
15
|
+
|
16
|
+
clients.each do |c|
|
17
|
+
resp = c.request(:GET, "/bench", nil, nil)
|
18
|
+
pp resp
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: silly_putty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sunny Gleason
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-11-23 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: makes switching between http clients easy as pie
|
18
|
+
email:
|
19
|
+
- sunny.gleason@gmail.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files: []
|
25
|
+
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- Gemfile
|
29
|
+
- Rakefile
|
30
|
+
- lib/silly_putty.rb
|
31
|
+
- lib/silly_putty/base.rb
|
32
|
+
- lib/silly_putty/clients/auto_detect.rb
|
33
|
+
- lib/silly_putty/clients/kirk.rb
|
34
|
+
- lib/silly_putty/clients/net_http.rb
|
35
|
+
- lib/silly_putty/clients/patron.rb
|
36
|
+
- lib/silly_putty/version.rb
|
37
|
+
- silly_putty.gemspec
|
38
|
+
- spec/kirk_spec.rb
|
39
|
+
- spec/net_http_spec.rb
|
40
|
+
- spec/patron_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- test/test_silly.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: ""
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: silly_putty
|
67
|
+
rubygems_version: 1.5.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: makes switching between http clients easy as pie
|
71
|
+
test_files:
|
72
|
+
- spec/kirk_spec.rb
|
73
|
+
- spec/net_http_spec.rb
|
74
|
+
- spec/patron_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- test/test_silly.rb
|