http_vanilli 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,105 @@
1
+ require 'addressable/uri'
2
+ require 'rack'
3
+ require 'pp'
4
+
5
+ class Object
6
+ def tapp(tag=nil)
7
+ print "#{tag}=" if tag
8
+ pp self
9
+ self
10
+ end
11
+ end
12
+
13
+ class AngryWeb
14
+ class ValueMatcher
15
+ attr_reader :mismatch_reason
16
+ def initialize(value)
17
+ @mismatch_reason = "<no reason>"
18
+ @value = value
19
+ end
20
+ end
21
+
22
+ class HashSubsetMatcher < ValueMatcher
23
+ def match?(params)
24
+ @value.keys.all? do |k|
25
+ match = @value[k]
26
+ param = params[k.to_s]
27
+
28
+ case match
29
+ when Regexp
30
+ !! param[match]
31
+ else
32
+ match == param
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ class REMatcher < ValueMatcher
39
+ def match?(other)
40
+ other.to_s.match(@value)
41
+ end
42
+ end
43
+
44
+ class EqlMatcher < ValueMatcher
45
+ def match?(other)
46
+ @value == other
47
+ end
48
+ end
49
+
50
+ class Matcher
51
+ attr_reader :mismatches
52
+
53
+ def initialize(&blk)
54
+ @parts = {}
55
+ yield self
56
+ end
57
+
58
+ def match?(uri)
59
+ uri = Addressable::URI.heuristic_parse(uri)
60
+ uri_hash = uri.to_hash
61
+
62
+ @mismatches = []
63
+
64
+ @parts.each {|k,v|
65
+ unless v.match?(__transform_value_from_uri(uri_hash,k))
66
+ @mismatches << v.mismatch_reason
67
+ end
68
+ }
69
+
70
+ @mismatches.empty?
71
+ end
72
+
73
+ def hash_subset(spec)
74
+ HashSubsetMatcher.new(spec)
75
+ end
76
+
77
+ def method_missing(meth,*args,&block)
78
+ if args.size == 1
79
+ @parts[meth] = __convert_value(args.first)
80
+ else
81
+ super
82
+ end
83
+ end
84
+
85
+ def __convert_value(value)
86
+ case value
87
+ when ValueMatcher
88
+ value
89
+ when Regexp
90
+ REMatcher.new(value)
91
+ else
92
+ EqlMatcher.new(value)
93
+ end
94
+ end
95
+
96
+ def __transform_value_from_uri(uri,key)
97
+ case key
98
+ when :params
99
+ Rack::Utils.parse_query(uri[:query])
100
+ else
101
+ uri[key]
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,13 @@
1
+ module HttpVanilli
2
+ module AbstractResponder
3
+ include HttpVanilli::NetHttp::YieldResponse
4
+
5
+ def response_for_request(request)
6
+ code,headers,body = rack_response(request)
7
+
8
+ response = HttpVanilli::NetHttp::Response.new(code,headers,body)
9
+
10
+ nh_yield_response(response,request)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,60 @@
1
+ require 'addressable/uri'
2
+
3
+ module HttpVanilli
4
+ class BasicMapper
5
+ attr_accessor :responder
6
+
7
+ def initialize(extra_responders = {})
8
+ responder_classes.update(extra_responders)
9
+ end
10
+
11
+ def responder_classes
12
+ @responder_classes ||= {
13
+ :block => HttpVanilli::Responders::Block,
14
+ :rack => HttpVanilli::Responders::Rack
15
+ }
16
+ end
17
+
18
+ def responders; @responders ||= [] end
19
+
20
+ def add_block_responder(*args,&block)
21
+ responders << responder_classes[:block].new(*args,&block)
22
+ end
23
+
24
+ def add_rack_responder(*args,&block)
25
+ responders << responder_classes[:rack].new(*args,&block)
26
+ end
27
+
28
+ def add_responder(kind,*args,&block)
29
+ responders << responder_classes[kind].new(*args,&block)
30
+ end
31
+
32
+ ## Mapping API
33
+
34
+ # Take the info from the innards of Net::HTTP and build a request.
35
+ def build_request(kind,http,request,&block)
36
+ HttpVanilli::Request.build(kind,http,request,&block)
37
+ end
38
+
39
+ # Should we map the request?
40
+ def map_request?(request)
41
+ !! find_responder(request)
42
+ end
43
+
44
+ # Map the request
45
+ def map_request(request)
46
+ find_responder(request).response_for_request(request)
47
+ end
48
+
49
+ # The request wasn't matched and normal net connection was disallowed.
50
+ def unmapped_request(request)
51
+ raise "unmatched_request #{request}"
52
+ end
53
+
54
+ protected
55
+
56
+ def find_responder(request)
57
+ responders.find {|responder| responder.match?(request)}
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,22 @@
1
+ require 'addressable/uri'
2
+
3
+ module Unused
4
+ class BasicMapping
5
+ include HttpVanilli::NetHttp::YieldResponse
6
+
7
+ def initialize(method,url,&block)
8
+ @method = method
9
+ @url = Addressable::URI.heuristic_parse(url)
10
+ @block = block
11
+ end
12
+
13
+ def match?(request)
14
+ (request.host == @url.host)
15
+ end
16
+
17
+ def rack_response
18
+ @block[request]
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,88 @@
1
+ require 'http_vanilli/net_http/stubs'
2
+ require 'http_vanilli/net_http/util'
3
+ require 'http_vanilli/net_http/request'
4
+ require 'http_vanilli/net_http/response'
5
+ require 'net/http'
6
+ require 'net/https'
7
+ require 'stringio'
8
+
9
+ module HttpVanilli
10
+ module NetHttp
11
+ def self.override!
12
+ record_loaded_net_http_replacement_libs
13
+ puts_warning_for_net_http_around_advice_libs_if_needed
14
+ end
15
+ end
16
+ end
17
+
18
+ module Net #:nodoc: all
19
+ class BufferedIO
20
+ def initialize_with_http_vanilli(io, debug_output = nil)
21
+ @read_timeout = 60
22
+ @rbuf = ''
23
+ @debug_output = debug_output
24
+
25
+ @io = case io
26
+ when Socket, OpenSSL::SSL::SSLSocket, IO
27
+ io
28
+ when String
29
+ if !io.include?("\0") && File.exists?(io) && !File.directory?(io)
30
+ File.open(io, "r")
31
+ else
32
+ StringIO.new(io)
33
+ end
34
+ end
35
+ raise "Unable to create local socket" unless @io
36
+ end
37
+ alias_method :initialize_without_http_vanilli, :initialize
38
+ alias_method :initialize, :initialize_with_http_vanilli
39
+ end
40
+
41
+ class HTTP
42
+ class << self
43
+ def socket_type_with_http_vanilli
44
+ HttpVanilli::NetHttp::StubSocket
45
+ end
46
+ alias_method :socket_type_without_http_vanilli, :socket_type
47
+ alias_method :socket_type, :socket_type_with_http_vanilli
48
+ end
49
+
50
+ def request_with_http_vanilli(request, body = nil, &block)
51
+ mapper = HttpVanilli.request_mapper
52
+
53
+ request.set_body_internal body
54
+
55
+ # Wrap Net::HTTPRequest & associated info in a HttpVanilli::Request
56
+ vanilli_request = mapper.build_request(:net_http, self, request, &block)
57
+
58
+ # The mapper can map the request. Do it.
59
+ if mapper.map_request?(vanilli_request)
60
+ @socket = Net::HTTP.socket_type.new
61
+ mapper.map_request(vanilli_request)
62
+
63
+ # otherwise, either allow the request to happen as normal,
64
+ elsif HttpVanilli.allow_net_connect?
65
+ connect_without_http_vanilli
66
+ request_without_http_vanilli(request, body, &block)
67
+
68
+ # or note the request as unmapped.
69
+ else
70
+ mapper.unmapped_request(vanilli_request)
71
+ end
72
+ end
73
+ alias_method :request_without_http_vanilli, :request
74
+ alias_method :request, :request_with_http_vanilli
75
+
76
+
77
+ def connect_with_http_vanilli
78
+ unless @@alredy_checked_for_net_http_replacement_libs ||= false
79
+ HttpVanilli::NetHttp.puts_warning_for_net_http_replacement_libs_if_needed
80
+ @@alredy_checked_for_net_http_replacement_libs = true
81
+ end
82
+ nil
83
+ end
84
+ alias_method :connect_without_http_vanilli, :connect
85
+ alias_method :connect, :connect_with_http_vanilli
86
+ end
87
+
88
+ end
@@ -0,0 +1,33 @@
1
+ require 'http_vanilli/request'
2
+
3
+ module HttpVanilli
4
+ module NetHttp
5
+ class Request < HttpVanilli::Request
6
+ attr_reader :block, :uri, :method, :original_request
7
+
8
+ def initialize(http,request,&block)
9
+ @http = http
10
+ @original_request = request
11
+ @block = block
12
+
13
+ protocol = http.use_ssl? ? "https" : "http"
14
+
15
+ path = request.path
16
+ path = Addressable::URI.parse(request.path).request_uri if request.path =~ /^https?:/
17
+
18
+ @uri = Addressable::URI.parse( "#{protocol}://#{http.address}:#{http.port}#{path}" )
19
+ @method = request.method.downcase.to_sym
20
+ end
21
+
22
+ def host; @uri.host end
23
+
24
+ def to_s
25
+ "#{@method} #{@uri.to_s}"
26
+ end
27
+
28
+ def body
29
+ @original_request.body
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ module HttpVanilli
2
+ module NetHttp
3
+ module YieldResponse
4
+ def nh_yield_response(response,request)
5
+ nh_rsp = response.to_net_http
6
+ request.block[nh_rsp] if request.block
7
+ nh_rsp
8
+ end
9
+ end
10
+
11
+ class Response < HttpVanilli::Response
12
+ attr_accessor :headers, :body
13
+ attr_reader :code, :message
14
+
15
+ def initialize(code,headers,body,message=StatusMessage[code.to_i])
16
+ @code,@body,@message = code.to_i,body,message
17
+ @headers = headers || {}
18
+ end
19
+
20
+ def body
21
+ @body.join("")
22
+ end
23
+
24
+ def to_net_http
25
+ response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, message)
26
+
27
+ response.instance_variable_set(:@body, body) if body
28
+ headers.each { |name, value| response[name] = value }
29
+
30
+ response.instance_variable_set(:@read, true)
31
+ response.extend HttpVanilli::NetHttp::ResponseMixin
32
+
33
+ response
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ module HttpVanilli
2
+ module NetHttp
3
+ class StubSocket #:nodoc:
4
+
5
+ def initialize(*args)
6
+ end
7
+
8
+ def closed?
9
+ @closed ||= true
10
+ end
11
+
12
+ def readuntil(*args)
13
+ end
14
+
15
+ end
16
+
17
+ module ResponseMixin #:nodoc:
18
+ def read_body(*args, &block)
19
+ yield @body if block_given?
20
+ @body
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ module HttpVanilli
2
+ module NetHttp
3
+ def self.puts_warning_for_net_http_around_advice_libs_if_needed
4
+ libs = {"Samuel" => defined?(Samuel)}
5
+ warnings = libs.select { |_, loaded| loaded }.map do |name, _|
6
+ <<-TEXT.gsub(/ {10}/, '')
7
+ \e[1mWarning: HttpVanilli was loaded after #{name}\e[0m
8
+ * #{name}'s code is being ignored when a request is handled by HttpVanilli::NetHttp,
9
+ because both libraries work by patching Net::HTTP.
10
+ * To fix this, just reorder your requires so that HttpVanilli is before #{name}.
11
+ TEXT
12
+ end
13
+ $stderr.puts "\n" + warnings.join("\n") + "\n" if warnings.any?
14
+ end
15
+
16
+ def self.record_loaded_net_http_replacement_libs
17
+ libs = {"RightHttpConnection" => defined?(RightHttpConnection)}
18
+ @loaded_net_http_replacement_libs = libs.map { |name, loaded| name if loaded }.compact
19
+ end
20
+
21
+ def self.puts_warning_for_net_http_replacement_libs_if_needed
22
+ libs = {"RightHttpConnection" => defined?(RightHttpConnection)}
23
+ warnings = libs.select { |_, loaded| loaded }.
24
+ reject { |name, _| @loaded_net_http_replacement_libs.include?(name) }.
25
+ map do |name, _|
26
+ <<-TEXT.gsub(/ {10}/, '')
27
+ \e[1mWarning: #{name} was loaded after HttpVanilli::NetHttp\e[0m
28
+ * HttpVanilli's code is being ignored, because #{name} replaces parts of
29
+ Net::HTTP without deferring to other libraries. This will break Net::HTTP requests.
30
+ * To fix this, just reorder your requires so that #{name} is before HttpVanilli.
31
+ TEXT
32
+ end
33
+ $stderr.puts "\n" + warnings.join("\n") + "\n" if warnings.any?
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,54 @@
1
+ require 'ostruct'
2
+ require 'pp'
3
+
4
+ module HttpVanilli
5
+ class OtherMapper
6
+ def customise_request(&block)
7
+ @customise_request = block
8
+ end
9
+
10
+ # Take the info from the innards of Net::HTTP and build a request.
11
+ def build_request(kind,http,request,body,&block)
12
+ req = OpenStruct.new
13
+ req.block = block
14
+
15
+ pp http
16
+ pp request.to_hash
17
+
18
+ protocol = http.use_ssl? ? "https" : "http"
19
+
20
+ path = request.path
21
+ path = Addressable::URI.parse(request.path).request_uri if request.path =~ /^http/
22
+
23
+ req.uri = Addressable::URI.parse( "#{protocol}://#{http.address}:#{http.port}#{path}" )
24
+ req.method = request.method.downcase.to_sym
25
+
26
+ if @customise_request
27
+ @customise_request[req]
28
+ end
29
+
30
+ req
31
+ end
32
+
33
+ # Should we map the request?
34
+ def map_request?(request)
35
+ true
36
+ end
37
+
38
+ # Map the request
39
+ def map_request(request)
40
+ response = HttpVanilli::NetHttp::Response.new(200,'cool')
41
+ response.body = "boddy"
42
+
43
+ nhrsp = response.to_net_http
44
+ request.block[nhrsp] if request.block
45
+
46
+ nhrsp
47
+ end
48
+
49
+ # The request wasn't matched and normal net connection was disallowed.
50
+ def unmapped_request(request)
51
+ raise "unmatched_request :("
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ module HttpVanilli
2
+ class Request
3
+ def self.build(kind,*args,&block)
4
+ case kind
5
+ when :net_http
6
+ HttpVanilli::NetHttp::Request.new(*args,&block)
7
+ else
8
+ raise "Unknown request kind #{kind}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ module HttpVanilli
2
+ module Responders
3
+ class Block
4
+ include HttpVanilli::AbstractResponder
5
+
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ def match?(request)
11
+ !! @block[request]
12
+ end
13
+
14
+ def rack_response(request)
15
+ @block[request]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ module HttpVanilli
2
+ module Responders
3
+ class Rack
4
+ include HttpVanilli::AbstractResponder
5
+
6
+ def initialize(app_class,*args,&block)
7
+ @app_class = app_class
8
+ @args = args
9
+ @block = block
10
+ end
11
+
12
+ BadStatus = 999
13
+ def match?(request)
14
+ rsp = rack_response(request)
15
+ Array === rsp && rsp.first != BadStatus
16
+ end
17
+
18
+ def rack_response(request)
19
+ uri = request.uri
20
+
21
+ env = {
22
+ 'REQUEST_METHOD' => request.original_request.method,
23
+
24
+ # this'll to for now
25
+ 'SCRIPT_NAME' => "",
26
+ 'PATH_INFO' => uri.path,
27
+
28
+ 'QUERY_STRING' => uri.query,
29
+ 'SERVER_NAME' => uri.host,
30
+ 'SERVER_PORT' => uri.port
31
+ }
32
+
33
+ request.original_request.each_header {|k,v|
34
+ env["HTTP_#{k.upcase}"] = v
35
+ }
36
+
37
+ rack_input = StringIO.new((request.body || '').to_s)
38
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
39
+
40
+ env.update({"rack.version" => [1,1],
41
+ "rack.input" => rack_input,
42
+ "rack.errors" => $stderr,
43
+
44
+ "rack.multithread" => true,
45
+ "rack.multiprocess" => false,
46
+ "rack.run_once" => false,
47
+
48
+ "rack.url_scheme" => request.uri.scheme
49
+ })
50
+
51
+ app.call(env)
52
+ end
53
+
54
+ def app
55
+ inner_app = lambda {|l| [BadStatus,{'Content-Type' => 'text/plain'},['']]}
56
+ @app_class.new(inner_app,*@args,&@block)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,6 @@
1
+ module HttpVanilli
2
+ module Responders
3
+ autoload :Block, 'http_vanilli/responders/block'
4
+ autoload :Rack , 'http_vanilli/responders/rack'
5
+ end
6
+ end
@@ -0,0 +1,46 @@
1
+ module HttpVanilli
2
+ class Response
3
+ StatusMessage = {
4
+ 100, 'Continue',
5
+ 101, 'Switching Protocols',
6
+ 200, 'OK',
7
+ 201, 'Created',
8
+ 202, 'Accepted',
9
+ 203, 'Non-Authoritative Information',
10
+ 204, 'No Content',
11
+ 205, 'Reset Content',
12
+ 206, 'Partial Content',
13
+ 300, 'Multiple Choices',
14
+ 301, 'Moved Permanently',
15
+ 302, 'Found',
16
+ 303, 'See Other',
17
+ 304, 'Not Modified',
18
+ 305, 'Use Proxy',
19
+ 307, 'Temporary Redirect',
20
+ 400, 'Bad Request',
21
+ 401, 'Unauthorized',
22
+ 402, 'Payment Required',
23
+ 403, 'Forbidden',
24
+ 404, 'Not Found',
25
+ 405, 'Method Not Allowed',
26
+ 406, 'Not Acceptable',
27
+ 407, 'Proxy Authentication Required',
28
+ 408, 'Request Timeout',
29
+ 409, 'Conflict',
30
+ 410, 'Gone',
31
+ 411, 'Length Required',
32
+ 412, 'Precondition Failed',
33
+ 413, 'Request Entity Too Large',
34
+ 414, 'Request-URI Too Large',
35
+ 415, 'Unsupported Media Type',
36
+ 416, 'Request Range Not Satisfiable',
37
+ 417, 'Expectation Failed',
38
+ 500, 'Internal Server Error',
39
+ 501, 'Not Implemented',
40
+ 502, 'Bad Gateway',
41
+ 503, 'Service Unavailable',
42
+ 504, 'Gateway Timeout',
43
+ 505, 'HTTP Version Not Supported'
44
+ }
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ require 'http_vanilli'
2
+
3
+ module HttpVanilli
4
+ module RSpec
5
+ def stub_web(method, url, &block)
6
+ HttpVanilli.mapper.add_mapping(method,url,&block)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ require 'uri'
2
+
3
+ module HttpVanilli
4
+ class Util
5
+ def self.decode_userinfo_from_header(header)
6
+ header.sub(/^Basic /, "").unpack("m").first
7
+ end
8
+
9
+ def self.encode_unsafe_chars_in_userinfo(userinfo)
10
+ unsafe_in_userinfo = /[^#{URI::REGEXP::PATTERN::UNRESERVED};&=+$,]|^(#{URI::REGEXP::PATTERN::ESCAPED})/
11
+ userinfo.split(":").map { |part| uri_escape(part, unsafe_in_userinfo) }.join(":")
12
+ end
13
+
14
+ def self.strip_default_port_from_uri(uri)
15
+ case uri
16
+ when %r{^http://} then uri.sub(%r{:80(/|$)}, '\1')
17
+ when %r{^https://} then uri.sub(%r{:443(/|$)}, '\1')
18
+ else uri
19
+ end
20
+ end
21
+
22
+ # Wrapper for URI escaping that switches between URI::Parser#escape and
23
+ # URI.escape for 1.9-compatibility
24
+ def self.uri_escape(*args)
25
+ if URI.const_defined?(:Parser)
26
+ URI::Parser.new.escape(*args)
27
+ else
28
+ URI.escape(*args)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module HttpVanilli
2
+ Version = '0.0.2'
3
+ end
@@ -0,0 +1,62 @@
1
+ require 'pathname'
2
+ require 'pp'
3
+
4
+ class Object
5
+ def tapp(tag=nil)
6
+ print "#{tag}=" if tag
7
+ pp self
8
+ self
9
+ end
10
+ end
11
+
12
+ module HttpVanilli
13
+ autoload :Util , 'http_vanilli/util'
14
+
15
+ autoload :BasicMapper , 'http_vanilli/basic_mapper'
16
+
17
+ autoload :AbstractResponder, 'http_vanilli/abstract_responder'
18
+ autoload :Responders , 'http_vanilli/responders'
19
+
20
+ autoload :Request , 'http_vanilli/request'
21
+ autoload :Response, 'http_vanilli/response'
22
+
23
+ class << self
24
+ def here
25
+ @here ||= Pathname(__FILE__).dirname
26
+ end
27
+
28
+ def override_net_http!
29
+ require here+'http_vanilli/net_http/override'
30
+ HttpVanilli::NetHttp.override!
31
+ end
32
+
33
+ def allow_net_connect!
34
+ @allow_net_connect = true
35
+ end
36
+
37
+ def disallow_net_connect!
38
+ @allow_net_connect = false
39
+ end
40
+
41
+ def allow_net_connect?
42
+ !(FalseClass === @allow_net_connect)
43
+ end
44
+
45
+ def use_basic_mapper!(extra_responder_classes={})
46
+ self.request_mapper = BasicMapper.new(extra_responder_classes)
47
+ end
48
+
49
+ def request_mapper=(request_mapper)
50
+ @request_mapper = request_mapper
51
+ end
52
+
53
+ def request_mapper
54
+ unless @request_mapper
55
+ raise "HttpVanilli requires a request mapper.\n" +
56
+ "Use the basic mapper with HttpVanilli.basic_mapper! ,\n" +
57
+ "or plug one in with HttpVanilli.request_mapper=Yourmapper.new"
58
+ end
59
+ @request_mapper
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_vanilli
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Lachie Cox
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-01 00:00:00 +10:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: exemplor
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: HttpVanilli gives you lip-synced http connections with pluggable band members for testing.
33
+ email:
34
+ - lachiec@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - lib/angry_web/matcher.rb
43
+ - lib/http_vanilli/abstract_responder.rb
44
+ - lib/http_vanilli/basic_mapper.rb
45
+ - lib/http_vanilli/basic_mapping.rb
46
+ - lib/http_vanilli/net_http/override.rb
47
+ - lib/http_vanilli/net_http/request.rb
48
+ - lib/http_vanilli/net_http/response.rb
49
+ - lib/http_vanilli/net_http/stubs.rb
50
+ - lib/http_vanilli/net_http/util.rb
51
+ - lib/http_vanilli/other_mapper.rb
52
+ - lib/http_vanilli/request.rb
53
+ - lib/http_vanilli/responders/block.rb
54
+ - lib/http_vanilli/responders/rack.rb
55
+ - lib/http_vanilli/responders.rb
56
+ - lib/http_vanilli/response.rb
57
+ - lib/http_vanilli/test_adapters/rspec.rb
58
+ - lib/http_vanilli/util.rb
59
+ - lib/http_vanilli/version.rb
60
+ - lib/http_vanilli.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/lachie/http_vanilli
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 1
83
+ - 3
84
+ - 6
85
+ version: 1.3.6
86
+ requirements: []
87
+
88
+ rubyforge_project: http_vanilli
89
+ rubygems_version: 1.3.6
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Flexible web connection mocking lib.
93
+ test_files: []
94
+