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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in silly_putty.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+
2
+ require "silly_putty/version"
3
+ require "silly_putty/base"
@@ -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,4 @@
1
+
2
+ module SillyPutty
3
+ require 'silly_putty/clients/net_http'
4
+ 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
@@ -0,0 +1,3 @@
1
+ module SillyPutty
2
+ VERSION = "0.1.0"
3
+ end
@@ -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
+
@@ -0,0 +1,10 @@
1
+ def client
2
+ 'SillyPutty::KirkClient'
3
+ end
4
+
5
+ require 'spec/spec_helper'
6
+ require 'silly_putty/clients/kirk'
7
+
8
+ describe SillyPutty::KirkClient do
9
+ it_behaves_like "silly_putty"
10
+ end
@@ -0,0 +1,10 @@
1
+ def client
2
+ 'SillyPutty::NetHttpClient'
3
+ end
4
+
5
+ require 'spec/spec_helper'
6
+ require 'silly_putty/clients/net_http'
7
+
8
+ describe SillyPutty::NetHttpClient do
9
+ it_behaves_like "silly_putty"
10
+ end
@@ -0,0 +1,10 @@
1
+ def client
2
+ 'SillyPutty::PatronClient'
3
+ end
4
+
5
+ require 'spec/spec_helper'
6
+ require 'silly_putty/clients/patron'
7
+
8
+ describe SillyPutty::PatronClient do
9
+ it_behaves_like "silly_putty"
10
+ end
@@ -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
@@ -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