persistent_httparty 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/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0 - 2012-09-09
2
+
3
+ * initial release
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Matt Campbell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ [![Build Status](https://secure.travis-ci.org/soupmatt/persistent_httparty.png?branch=master)](http://travis-ci.org/soupmatt/persistent_httparty)
2
+
3
+ # persistent_httparty
4
+
5
+ Persistent HTTP connections for HTTParty!
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'persistent_httparty'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install persistent_httparty
20
+
21
+ ## Requirements
22
+
23
+ * [httparty](/jnunemaker/httparty) and [persistent_http](/bpardee/persistent_http)
24
+ * You like to `Keep-Alive` the party!
25
+
26
+ ## Usage
27
+
28
+ Just call `persistent_connection_adapter` and then use HTTParty as
29
+ normal.
30
+
31
+ ```ruby
32
+ class Twitter
33
+ include HTTParty
34
+ persistent_connection_adapter
35
+ end
36
+ ```
37
+
38
+ You can also pass in parameters to the `persistent_http` gem. The
39
+ regular HTTParty config will be passed through as applicable.
40
+
41
+ ```ruby
42
+ class MyCoolRestClient
43
+ include HTTParty
44
+ persistent_connection_adapter { :name => 'my_cool_rest_client',
45
+ :pool_size => 2,
46
+ :idle_timeout => 10,
47
+ :keep-alive => 30 }
48
+ end
49
+ ```
50
+
51
+ ## License
52
+
53
+ Distributed under the [MIT License](/soupmatt/persistent_httparty/blob/master/LICENSE)
54
+
55
+ ## Special Thanks
56
+
57
+ * To @jnunemaker for maintaining a tight ship on the extremely useful
58
+ [httparty](/jnunemaker/httparty)
59
+ * To @bpardee for writing the best persistent http connection library
60
+ for ruby I've found in [persistent_http](/bpardee/persistent_http)
61
+ * To @vibes for letting me open source as much of the work I do there
62
+ as possible.
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ Feature: Persistent HTTP Connections
2
+
3
+ Scenario:
4
+ Given I have an http end point "http://www.example.com/api/thing.json"
5
+ And I perform a "get" against that end point
6
+ And The end point returns "application/json"
7
+ """
8
+ {"name":"foo", "type":"thing"}
9
+ """
10
+ When I visit that end point with HTTParty
11
+ Then the parsed_response contains
12
+ | name | foo |
13
+ | type | thing |
@@ -0,0 +1,22 @@
1
+ Given /^I have an http end point "(.*?)"$/ do |uri|
2
+ @web_request = WebRequest.new
3
+ @web_request.uri = uri
4
+ end
5
+
6
+ Given /^I perform a "(.*?)" against that end point$/ do |verb|
7
+ @web_request.verb = verb
8
+ end
9
+
10
+ Given /^The end point returns "(.*?)"$/ do |content_type, body|
11
+ @web_request.content_type = content_type
12
+ @web_request.response_body = body
13
+ end
14
+
15
+ When /^I visit that end point with HTTParty$/ do
16
+ @web_request.mock
17
+ @response = @web_request.perform
18
+ end
19
+
20
+ Then /^the parsed_response contains$/ do |table|
21
+ @response.parsed_response.should == table.rows_hash
22
+ end
@@ -0,0 +1 @@
1
+ require 'persistent_httparty'
@@ -0,0 +1,40 @@
1
+ class TestHTTPartyClient
2
+ include HTTParty
3
+ persistent_connection_adapter
4
+ end
5
+
6
+ class WebRequest
7
+ include WebMock::API
8
+
9
+ attr_accessor :uri, :verb, :content_type, :request_body, :response_body
10
+
11
+ def initialize
12
+ @uri = 'http://www.example.com/'
13
+ @verb = :get
14
+ @content_type = 'text/plain'
15
+ @response_body = 'Hello!'
16
+ end
17
+
18
+ def verb=(arg)
19
+ unless arg.is_a? Symbol
20
+ @verb = arg.to_s.downcase.to_sym
21
+ else
22
+ @verb = arg
23
+ end
24
+ end
25
+
26
+ VALID_VERBS = %w(get head post put delete patch options).collect { |v| v.to_sym }
27
+
28
+ def mock
29
+ stub_request(verb, uri).to_return(:body => response_body, :headers => {:content_type => content_type})
30
+ end
31
+
32
+ def perform
33
+ case verb
34
+ when :get
35
+ TestHTTPartyClient.get(uri)
36
+ else
37
+ raise "#{verb} is not a supported HTTP verb"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ require 'webmock/cucumber'
@@ -0,0 +1,15 @@
1
+ require 'httparty'
2
+
3
+ module HTTParty::Persistent
4
+ module ClassMethods
5
+ def persistent_connection_adapter(opts={})
6
+ connection_adapter(HTTParty::Persistent::ConnectionAdapter.new, opts)
7
+ end
8
+ end
9
+ end
10
+
11
+ HTTParty::ClassMethods.module_exec do
12
+ include HTTParty::Persistent::ClassMethods
13
+ end
14
+
15
+ require 'httparty/persistent/connection_adapter'
@@ -0,0 +1,34 @@
1
+ require 'persistent_http'
2
+
3
+ module HTTParty::Persistent
4
+ class ConnectionAdapter
5
+
6
+ attr_accessor :persistent_http
7
+
8
+ def call(uri, options)
9
+ if @persistent_http.nil?
10
+ @persistent_http = build_persistent_http(uri, options)
11
+ end
12
+ @persistent_http
13
+ end
14
+
15
+ def build_persistent_http(uri, options)
16
+ opts = {:url => uri}
17
+ opts.merge!(options[:connection_adapter_options]) if options[:connection_adapter_options]
18
+ if options[:timeout] && (options[:timeout].is_a?(Integer) || options[:timeout].is_a?(Float))
19
+ opts.merge!(:read_timeout => options[:timeout], :open_timeout => options[:timeout])
20
+ end
21
+ opts.merge!(:debug_output => options[:debug_output]) if options[:debug_output]
22
+
23
+ if options[:http_proxyaddr]
24
+ proxy_opts = {:host => options[:http_proxyaddr]}
25
+ proxy_opts[:port] = options[:http_proxyport] if options[:http_proxyport]
26
+ opts[:proxy] = URI::HTTP.build(proxy_opts)
27
+ opts[:proxy].user = options[:http_proxyuser] if options[:http_proxyuser]
28
+ opts[:proxy].password = options[:http_proxypass] if options[:http_proxypass]
29
+ end
30
+
31
+ PersistentHTTP.new(opts)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,2 @@
1
+ require "persistent_httparty/version"
2
+ require "httparty/persistent"
@@ -0,0 +1,3 @@
1
+ module PersistentHttparty
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,159 @@
1
+ require 'spec_helper'
2
+
3
+ describe HTTParty::Persistent::ConnectionAdapter do
4
+ let(:uri) { URI 'http://foo.com:8085' }
5
+ let(:connection_adapter_options) { {} }
6
+ let(:options) { {:connection_adapter_options => connection_adapter_options} }
7
+ let!(:adapter) { HTTParty::Persistent::ConnectionAdapter.new }
8
+ subject { adapter }
9
+
10
+ describe "#call" do
11
+ subject { adapter.call(uri, options) }
12
+
13
+ it "returns a PersistentHTTP" do
14
+ subject.should be_a PersistentHTTP
15
+ end
16
+
17
+ it "returns the same PersistentHTTP across calls" do
18
+ adapter.call(uri, options).should be subject
19
+ end
20
+
21
+ describe "the resulting PersistentHTTP" do
22
+ subject { adapter.call(uri, options) }
23
+
24
+ it { should_not be_nil }
25
+ it { should be_instance_of PersistentHTTP }
26
+ its(:host) { should == uri.host }
27
+ its(:port) { should == uri.port }
28
+
29
+ it "is the same across multiple calls" do
30
+ adapter.call(uri, options).should be subject
31
+ adapter.call(uri, options).should be subject
32
+ end
33
+
34
+ context "when dealing with ssl" do
35
+ Spec::Matchers.define :use_ssl do
36
+ match do |connection|
37
+ connection.use_ssl
38
+ end
39
+ end
40
+
41
+ context "using port 443 for ssl" do
42
+ let(:uri) { URI 'https://api.foo.com/v1:443' }
43
+ it { should use_ssl }
44
+ end
45
+
46
+ context "using port 80" do
47
+ let(:uri) { URI 'http://foobar.com' }
48
+ it { should_not use_ssl }
49
+ end
50
+
51
+ context "https scheme with default port" do
52
+ let(:uri) { URI 'https://foobar.com' }
53
+ it { should use_ssl }
54
+ end
55
+
56
+ context "https scheme with non-standard port" do
57
+ let(:uri) { URI 'https://foobar.com:123456' }
58
+ it { should use_ssl }
59
+ end
60
+ end
61
+
62
+ context "when setting timeout" do
63
+ context "to 5 seconds" do
64
+ let(:options) { {:timeout => 5} }
65
+
66
+ its(:open_timeout) { should == 5 }
67
+ its(:read_timeout) { should == 5 }
68
+ end
69
+
70
+ context "and timeout is a string" do
71
+ let(:options) { {:timeout => "five seconds"} }
72
+
73
+ it "doesn't set the timeout" do
74
+ subject.open_timeout.should be_nil
75
+ subject.read_timeout.should be_nil
76
+ end
77
+ end
78
+ end
79
+
80
+ context "when debug_output" do
81
+ context "is set to $stderr" do
82
+ let(:options) { {:debug_output => $stderr} }
83
+ it "has debug output set" do
84
+ subject.debug_output.should == $stderr
85
+ end
86
+ end
87
+
88
+ context "is not provided" do
89
+ let(:options) { {} }
90
+ it "does not set_debug_output" do
91
+ subject.debug_output.should be_nil
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when providing proxy address and port' do
97
+ let(:options) { {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080} }
98
+
99
+ its(:proxy_uri) { should == URI.parse('http://1.2.3.4:8080') }
100
+
101
+ context 'as well as proxy user and password' do
102
+ let(:options) do
103
+ {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080,
104
+ :http_proxyuser => 'user', :http_proxypass => 'pass'}
105
+ end
106
+ its(:proxy_uri) do
107
+ uri = URI.parse('http://1.2.3.4:8080')
108
+ uri.user = 'user'
109
+ uri.password = 'pass'
110
+ should == uri
111
+ end
112
+ end
113
+ end
114
+
115
+ context "when providing PEM certificates", :pending => true do
116
+ let(:pem) { :pem_contents }
117
+ let(:options) { {:pem => pem, :pem_password => "password"} }
118
+
119
+ context "when scheme is https" do
120
+ let(:uri) { URI 'https://google.com' }
121
+ let(:cert) { mock("OpenSSL::X509::Certificate") }
122
+ let(:key) { mock("OpenSSL::PKey::RSA") }
123
+
124
+ before do
125
+ OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(cert)
126
+ OpenSSL::PKey::RSA.should_receive(:new).with(pem, "password").and_return(key)
127
+ end
128
+
129
+ it "uses the provided PEM certificate " do
130
+ subject.cert.should == cert
131
+ subject.key.should == key
132
+ end
133
+
134
+ it "will verify the certificate" do
135
+ subject.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
136
+ end
137
+ end
138
+
139
+ context "when scheme is not https" do
140
+ let(:uri) { URI 'http://google.com' }
141
+ let(:http) { Net::HTTP.new(uri) }
142
+
143
+ before do
144
+ Net::HTTP.stub(:new => http)
145
+ OpenSSL::X509::Certificate.should_not_receive(:new).with(pem)
146
+ OpenSSL::PKey::RSA.should_not_receive(:new).with(pem, "password")
147
+ http.should_not_receive(:cert=)
148
+ http.should_not_receive(:key=)
149
+ end
150
+
151
+ it "has no PEM certificate " do
152
+ subject.cert.should be_nil
153
+ subject.key.should be_nil
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe HTTParty::Persistent do
4
+ let!(:klass) { Class.new }
5
+ before(:each) do
6
+ klass.instance_eval { include HTTParty }
7
+ end
8
+
9
+ describe HTTParty do
10
+ it "includes HTTParty::Persistent" do
11
+ HTTParty::ClassMethods.should include_module(HTTParty::Persistent::ClassMethods)
12
+ end
13
+
14
+ context "across multiple requests" do
15
+ let(:base_uri) { URI 'http://example.com' }
16
+
17
+ it "reuses the same http connection" do
18
+ http = Net::HTTP.new(base_uri.host, base_uri.port)
19
+ Net::HTTP.should_receive(:new).once().and_return(http)
20
+
21
+ stub_request(:get, "#{base_uri.to_s}/status").
22
+ to_return(:status => 200, :body => "", :headers => {})
23
+
24
+ stub_request(:get, "#{base_uri.to_s}/info").
25
+ to_return(:status => 200, :body => "", :headers => {})
26
+
27
+ klass.base_uri base_uri.to_s
28
+ klass.persistent_connection_adapter
29
+
30
+ klass.get('/status')
31
+ klass.get('/info')
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#persistent_connection_adapter" do
37
+ before(:each) { klass.persistent_connection_adapter }
38
+
39
+ it "sets the connection_adapter to HTTParty::Persistent::ConnectionAdapter" do
40
+ klass.connection_adapter.should be_a HTTParty::Persistent::ConnectionAdapter
41
+ end
42
+
43
+ context "with connection_adapter_options" do
44
+ let(:connection_adapter_options) { {:foo => :bar} }
45
+ before(:each) { klass.persistent_connection_adapter(connection_adapter_options) }
46
+
47
+ it "sets the connection_adapter_options that are passed to it" do
48
+ klass.default_options[:connection_adapter_options].should == connection_adapter_options
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,25 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'persistent_httparty'
9
+ require 'webmock/rspec'
10
+
11
+ app_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
12
+
13
+ Dir[File.join(app_root, "spec/support/**/*.rb")].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+
20
+ # Run specs in random order to surface order dependencies. If you find an
21
+ # order dependency and want to debug it, you can fix the order by providing
22
+ # the seed, which is printed after each run.
23
+ # --seed 1234
24
+ config.order = 'random'
25
+ end
@@ -0,0 +1,11 @@
1
+ RSpec::Matchers.define :include_module do |module_to_include|
2
+ match do |subject|
3
+ subject.include? module_to_include
4
+ end
5
+ end
6
+
7
+ RSpec::Matchers.define :define_instance_variable do |instance_variable|
8
+ match do |subject|
9
+ subject.instance_variable_defined? instance_variable
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: persistent_httparty
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Campbell
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: persistent_http
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.11.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.11.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: cucumber
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: webmock
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Persistent HTTP connections for HTTParty using the persistent_http gem.
111
+ Keep the party alive!
112
+ email:
113
+ - persistent_httparty@soupmatt.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - lib/httparty/persistent.rb
119
+ - lib/httparty/persistent/connection_adapter.rb
120
+ - lib/persistent_httparty.rb
121
+ - lib/persistent_httparty/version.rb
122
+ - README.md
123
+ - LICENSE
124
+ - CHANGELOG.md
125
+ - features/persistent_http_connections.feature
126
+ - features/step_definitions/persistent_http_connections_steps.rb
127
+ - features/step_definitions/support/env.rb
128
+ - features/step_definitions/support/web_request.rb
129
+ - features/support/env.rb
130
+ - spec/lib/httparty/persistent/connection_adapter_spec.rb
131
+ - spec/lib/httparty/persistent_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/support/matchers.rb
134
+ homepage: https://github.com/soupmatt/persistent_httparty
135
+ licenses: []
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ segments:
147
+ - 0
148
+ hash: -710231127126955515
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ segments:
156
+ - 0
157
+ hash: -710231127126955515
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.23
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Persistent HTTP connections for HTTParty
164
+ test_files:
165
+ - features/persistent_http_connections.feature
166
+ - features/step_definitions/persistent_http_connections_steps.rb
167
+ - features/step_definitions/support/env.rb
168
+ - features/step_definitions/support/web_request.rb
169
+ - features/support/env.rb
170
+ - spec/lib/httparty/persistent/connection_adapter_spec.rb
171
+ - spec/lib/httparty/persistent_spec.rb
172
+ - spec/spec_helper.rb
173
+ - spec/support/matchers.rb