em-net-http 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,7 +3,10 @@ source :rubygems
3
3
  gem 'em-http-request'
4
4
  group :development do
5
5
  gem 'rspec', '>= 1.2.9'
6
+ gem 'diff-lcs'
6
7
  gem 'weary'
7
8
  gem 'right_aws'
8
9
  gem 'tumblr-rb'
10
+ gem 'mimic', '>= 0.3.0'
11
+ gem 'rake'
9
12
  end
data/README.md CHANGED
@@ -21,9 +21,13 @@ fiber:
21
21
 
22
22
  The above will run without blocking your carefully-tuned nonblocking webapp.
23
23
 
24
- I have vaguely tested <tt>em-net-http</tt> with <tt>[right_aws][3]</tt>,
25
- [Weary][4] and the [Tumblr gem][5]. There's no actual unit tests as such; if you're
26
- feeling smarter than I am, please feel free to contribute some! <tt>:-)</tt>
24
+ There are a few tests (taking advantage of Luke Redpath's very useful [Mimic][6] gem)
25
+ that assert that responses are identical to those created by <tt>Net::HTTP</tt>.
26
+ These are by no means exhaustive; if you're using <tt>Net::HTTP</tt> in some other way
27
+ and the <tt>em-net-http</tt>'s behaviour is not what you expect, do send me a failing test
28
+ case.
29
+
30
+ Currently tested with Ruby (MRI) 1.9.1 and 1.9.2.
27
31
 
28
32
  ### Caveat
29
33
 
@@ -35,4 +39,5 @@ therefore vary. Please feed me patches, pull requests and bug reports!
35
39
  [2]: http://rubyeventmachine.com/
36
40
  [3]: http://rightaws.rubyforge.org/
37
41
  [4]: http://github.com/mwunsch/weary
38
- [5]: http://github.com/mwunsch/tumblr
42
+ [5]: http://github.com/mwunsch/tumblr
43
+ [6]: http://github.com/lukeredpath/mimic
data/Rakefile CHANGED
@@ -11,10 +11,10 @@ begin
11
11
  gem.homepage = "http://github.com/jfairbairn/em-net-http"
12
12
  gem.authors = ["James Fairbairn"]
13
13
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
- gem.add_development_dependency "weary"
15
- gem.add_development_dependency "right_aws"
16
-
17
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ gem.add_development_dependency "mimic", ">= 0.3.0"
15
+ gem.add_development_dependency 'weary'
16
+ gem.add_development_dependency 'right_aws'
17
+ gem.add_development_dependency 'tumblr-rb'
18
18
  end
19
19
  Jeweler::GemcutterTasks.new
20
20
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'autospec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('rspec', 'autospec')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'htmldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('diff-lcs', 'htmldiff')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('diff-lcs', 'ldiff')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'oauth' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('oauth', 'oauth')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rackup' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('rack', 'rackup')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('rake', 'rake')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'spec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('rspec', 'spec')
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'tumblr' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'bundler/setup'
13
+
14
+ load Gem.bin_path('tumblr-rb', 'tumblr')
@@ -5,13 +5,14 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{em-net-http}
8
- s.version = "0.1.3"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["James Fairbairn"]
12
- s.date = %q{2010-08-18}
12
+ s.date = %q{2010-08-21}
13
13
  s.description = %q{Monkeypatching Net::HTTP to use em-http-request under the hood.}
14
14
  s.email = %q{james@netlagoon.com}
15
+ s.executables = ["autospec", "htmldiff", "ldiff", "oauth", "rackup", "rake", "spec", "tumblr"]
15
16
  s.extra_rdoc_files = [
16
17
  "LICENSE",
17
18
  "README.md"
@@ -49,17 +50,23 @@ Gem::Specification.new do |s|
49
50
 
50
51
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
52
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
53
+ s.add_development_dependency(%q<mimic>, [">= 0.3.0"])
52
54
  s.add_development_dependency(%q<weary>, [">= 0"])
53
55
  s.add_development_dependency(%q<right_aws>, [">= 0"])
56
+ s.add_development_dependency(%q<tumblr-rb>, [">= 0"])
54
57
  else
55
58
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ s.add_dependency(%q<mimic>, [">= 0.3.0"])
56
60
  s.add_dependency(%q<weary>, [">= 0"])
57
61
  s.add_dependency(%q<right_aws>, [">= 0"])
62
+ s.add_dependency(%q<tumblr-rb>, [">= 0"])
58
63
  end
59
64
  else
60
65
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<mimic>, [">= 0.3.0"])
61
67
  s.add_dependency(%q<weary>, [">= 0"])
62
68
  s.add_dependency(%q<right_aws>, [">= 0"])
69
+ s.add_dependency(%q<tumblr-rb>, [">= 0"])
63
70
  end
64
71
  end
65
72
 
@@ -5,65 +5,85 @@ require 'net/http'
5
5
  require 'fiber'
6
6
 
7
7
  module EventMachine
8
- class NetHTTPResponse
9
- attr_reader :code, :body, :header, :message, :http_version
10
- alias_method :msg, :message
8
+ module NetHTTP
9
+ class Response
10
+ attr_reader :code, :body, :header, :message, :http_version
11
+ alias_method :msg, :message
11
12
 
12
- def initialize(res)
13
- @code = res.response_header.http_status
14
- @message = res.response_header.http_reason
15
- @http_version = res.response_header.http_version
16
- @header = res.response_header
17
- @body = res.response
18
- end
13
+ def initialize(res)
14
+ @code = res.response_header.http_status
15
+ @message = res.response_header.http_reason
16
+ @http_version = res.response_header.http_version
17
+ @header = res.response_header
18
+ @body = res.response
19
+ end
19
20
 
20
- def content_type
21
- self['content-type']
22
- end
21
+ def content_type
22
+ self['content-type']
23
+ end
23
24
 
24
- def [](k)
25
- @header[key(k)]
26
- end
25
+ def [](k)
26
+ @header[key(k)]
27
+ end
27
28
 
28
- def key?(k)
29
- @header.key? key(k)
30
- end
29
+ def key?(k)
30
+ @header.key? key(k)
31
+ end
31
32
 
32
- def read_body(dest=nil,&block)
33
- @body
34
- end
33
+ def read_body(dest=nil,&block)
34
+ @body
35
+ end
35
36
 
36
- def to_hash
37
- h={}
38
- @header.each do |k, v|
39
- h[fromkey(k)] = v
37
+ def to_hash
38
+ h={}
39
+ @header.each do |k, v|
40
+ h[fromkey(k)] = v
41
+ end
42
+ h
40
43
  end
41
- h
42
- end
43
44
 
44
- private
45
- def key(k)
46
- k.upcase.tr('-','_')
47
- end
45
+ private
46
+ def key(k)
47
+ k.upcase.tr('-','_')
48
+ end
48
49
 
49
- def fromkey(k)
50
- k.tr('_', '-').split('-').map{|i|i.capitalize}.join('-')
51
- end
50
+ def fromkey(k)
51
+ k.tr('_', '-').split('-').map{|i|i.capitalize}.join('-')
52
+ end
52
53
 
53
- include Enumerable
54
- def each(&blk)
55
- @header.each(&blk)
56
- end
54
+ include Enumerable
55
+ def each(&blk)
56
+ @header.each(&blk)
57
+ end
57
58
 
59
+ end
58
60
  end
59
61
  end
60
62
 
61
63
 
62
64
  module Net
65
+ class HTTPResponse
66
+ class << self
67
+ public :response_class
68
+ end
69
+
70
+ alias_method :orig_net_http_read_body, :read_body
71
+
72
+ def read_body(dest=nil, &block)
73
+ return orig_net_http_read_body(dest, &block) unless ::EM.reactor_running?
74
+ @body
75
+ end
76
+ end
77
+
63
78
  class HTTP
79
+ alias_method :orig_net_http_request, :request
80
+
64
81
  def request(req, body = nil, &block)
65
- f=Fiber.current
82
+
83
+ return orig_net_http_request(req, body, &block) unless ::EM.reactor_running?
84
+
66
85
  uri = Addressable::URI.parse("#{use_ssl? ? 'https://' : 'http://'}#{addr_port}#{req.path}")
86
+
67
87
  body = body || req.body
68
88
  opts = body.nil? ? {} : {:body => body}
69
89
  if use_ssl?
@@ -72,14 +92,32 @@ module Net
72
92
  sslopts[:private_key_file] = key if key
73
93
  sslopts[:cert_chain_file] = ca_file if ca_file
74
94
  end
95
+
75
96
  headers = opts[:head] = {}
76
97
  req.each do |k, v|
77
98
  headers[k] = v
78
99
  end
100
+
79
101
  headers['content-type'] ||= "application/x-www-form-urlencoded"
102
+
80
103
  httpreq = EM::HttpRequest.new(uri).send(req.class::METHOD.downcase.to_sym, opts)
81
- httpreq.callback {|res|f.resume(EM::NetHTTPResponse.new(res))}
82
- httpreq.errback {|res|f.resume(EM::NetHTTPResponse.new(res))}
104
+
105
+ f=Fiber.current
106
+
107
+ convert_em_http_response = lambda do |res|
108
+ emres = EM::NetHTTP::Response.new(res)
109
+ nhresclass = Net::HTTPResponse.response_class(emres.code)
110
+ nhres = nhresclass.new(emres.http_version, emres.code, emres.message)
111
+ emres.to_hash.each do |k, v|
112
+ nhres.add_field(k, v)
113
+ end
114
+ nhres.body = emres.body if req.response_body_permitted? && nhresclass.body_permitted?
115
+ nhres.instance_variable_set '@read', true
116
+ f.resume nhres
117
+ end
118
+
119
+ httpreq.callback &convert_em_http_response
120
+ httpreq.errback &convert_em_http_response
83
121
  res = Fiber.yield
84
122
  yield res if block_given?
85
123
  res
@@ -1,7 +1,98 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "EmNetHttp" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
3
+ describe "em-net-http" do
4
+ describe 'should be compatible' do
5
+ it 'for Net::HTTP.get()' do
6
+ run_requests {Net::HTTP.get(URI.parse('http://localhost/hello'))}
7
+ @expected_res.should == @actual_res
8
+ end
9
+
10
+ # it 'for Net::HTTP.get_print()' do
11
+ # run_requests {Net::HTTP.get_print(URI.parse('http://localhost/hello'))}
12
+ # @expected_res.should == @actual_res
13
+ # end
14
+
15
+ # We don't test responses like 100 Continue at the moment.
16
+ %w(200 201 202 203 204 205 206 300 301 302 303 307 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 500 501 502 503 504 505).each do |code|
17
+ it "for Net::HTTP.start(host, port, &block) with response code #{code}" do
18
+ assert_identical {
19
+ Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
20
+ http.get("/code/#{code}")
21
+ end
22
+ }
23
+ end
24
+
25
+ it "for Net::HTTP.new(host, port).start(&block) with response code #{code}" do
26
+ assert_identical {
27
+ h = Net::HTTP.new('localhost', Mimic::MIMIC_DEFAULT_PORT)
28
+ h.start do |http|
29
+ http.get("/code/#{code}")
30
+ end
31
+ }
32
+ end
33
+ end
34
+
35
+ it "with response code 304" do
36
+ assert_identical {
37
+ Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
38
+ req = Net::HTTP::Get.new('/code/304')
39
+ req['If-Modified-Since'] = Time.now.rfc2822
40
+ http.request(req)
41
+ end
42
+ }
43
+
44
+ end
45
+
46
+ it 'with post' do
47
+ assert_identical {
48
+ Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
49
+ req = Net::HTTP::Post.new('/testpost')
50
+ req.body = 'hello mimic'
51
+ http.request(req)
52
+ end
53
+ }
54
+
55
+ end
56
+
57
+ end
58
+
59
+ def run_requests(&block)
60
+ @expected_res = yield
61
+ EM.run do
62
+ Fiber.new do
63
+ @actual_res = yield
64
+ end.resume
65
+ EM.add_periodic_timer(0.0) do
66
+ EM.stop_event_loop if @actual_res
67
+ end
68
+ end
69
+ end
70
+
71
+ def assert_identical(&block)
72
+ run_requests(&block)
73
+ @actual_res.should match_response(@expected_res)
74
+ end
75
+
76
+ def match_response(expected)
77
+ ResponseMatcher.new(expected)
78
+ end
79
+
80
+ class ResponseMatcher
81
+ def initialize(expected)
82
+ @expected = expected
83
+ end
84
+
85
+ def matches?(actual)
86
+ # Dates could differ slightly :(
87
+ expected_date = Time.parse(@expected.delete('date').join)
88
+ actual_date = Time.parse(actual.delete('date').join)
89
+ actual_date.should >= expected_date
90
+ actual_date.should <= expected_date + 2
91
+ [:class, :code, :to_hash, :body].each do |i|
92
+ actual.send(i).should == @expected.send(i)
93
+ end
94
+ true
95
+ end
96
+
6
97
  end
7
98
  end
@@ -1,9 +1,28 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'em-net-http'
4
+ require 'time'
4
5
  require 'spec'
5
6
  require 'spec/autorun'
6
7
 
8
+ require 'mimic'
9
+
7
10
  Spec::Runner.configure do |config|
11
+ config.before(:all) do
12
+ Mimic.mimic do
13
+ Net::HTTPResponse::CODE_TO_OBJ.each do |code, klass|
14
+ get("/code/#{code}").returning("#{code} #{klass.name}", code.to_i, {})
15
+ end
16
+
17
+ get('/hello').returning('Hello World!', 200, {'Content-Type'=>'text/plain'})
18
+
19
+ post('/testpost') do
20
+ "You said #{request.body.read}."
21
+ end
22
+ end
23
+ end
8
24
 
25
+ config.after(:all) do
26
+ Mimic.cleanup!
27
+ end
9
28
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - James Fairbairn
@@ -14,12 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-18 00:00:00 +01:00
17
+ date: 2010-08-21 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rspec
22
- prerelease: false
23
22
  requirement: &id001 !ruby/object:Gem::Requirement
24
23
  none: false
25
24
  requirements:
@@ -31,10 +30,10 @@ dependencies:
31
30
  - 9
32
31
  version: 1.2.9
33
32
  type: :development
33
+ prerelease: false
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
- name: weary
37
- prerelease: false
36
+ name: mimic
38
37
  requirement: &id002 !ruby/object:Gem::Requirement
39
38
  none: false
40
39
  requirements:
@@ -42,12 +41,14 @@ dependencies:
42
41
  - !ruby/object:Gem::Version
43
42
  segments:
44
43
  - 0
45
- version: "0"
44
+ - 3
45
+ - 0
46
+ version: 0.3.0
46
47
  type: :development
48
+ prerelease: false
47
49
  version_requirements: *id002
48
50
  - !ruby/object:Gem::Dependency
49
- name: right_aws
50
- prerelease: false
51
+ name: weary
51
52
  requirement: &id003 !ruby/object:Gem::Requirement
52
53
  none: false
53
54
  requirements:
@@ -57,11 +58,45 @@ dependencies:
57
58
  - 0
58
59
  version: "0"
59
60
  type: :development
61
+ prerelease: false
60
62
  version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: right_aws
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: tumblr-rb
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: *id005
61
89
  description: Monkeypatching Net::HTTP to use em-http-request under the hood.
62
90
  email: james@netlagoon.com
63
- executables: []
64
-
91
+ executables:
92
+ - autospec
93
+ - htmldiff
94
+ - ldiff
95
+ - oauth
96
+ - rackup
97
+ - rake
98
+ - spec
99
+ - tumblr
65
100
  extensions: []
66
101
 
67
102
  extra_rdoc_files:
@@ -83,6 +118,14 @@ files:
83
118
  - spec/em-net-http_spec.rb
84
119
  - spec/spec.opts
85
120
  - spec/spec_helper.rb
121
+ - bin/autospec
122
+ - bin/htmldiff
123
+ - bin/ldiff
124
+ - bin/oauth
125
+ - bin/rackup
126
+ - bin/rake
127
+ - bin/spec
128
+ - bin/tumblr
86
129
  has_rdoc: true
87
130
  homepage: http://github.com/jfairbairn/em-net-http
88
131
  licenses: []
@@ -97,6 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
140
  requirements:
98
141
  - - ">="
99
142
  - !ruby/object:Gem::Version
143
+ hash: 969805767585921057
100
144
  segments:
101
145
  - 0
102
146
  version: "0"