itrigga-net_helper 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +17 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/itrigga/net_helper.rb +217 -0
- data/spec/net_helper_spec.rb +454 -0
- data/spec/spec_helper.rb +19 -0
- data/test/helper.rb +18 -0
- data/test/test_net_helper.rb +7 -0
- metadata +195 -0
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "hpricot"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.4"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
gem 'rspec'
|
14
|
+
gem 'json_pure'
|
15
|
+
gem 'itrigga-core_ext', ">= 0"
|
16
|
+
gem "fastercsv", ">= 1.5.4"
|
17
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
fastercsv (1.5.4)
|
6
|
+
git (1.2.5)
|
7
|
+
hpricot (0.8.4)
|
8
|
+
itrigga-core_ext (0.1.0)
|
9
|
+
jeweler (1.6.4)
|
10
|
+
bundler (~> 1.0)
|
11
|
+
git (>= 1.2.5)
|
12
|
+
rake
|
13
|
+
json_pure (1.5.1)
|
14
|
+
rake (0.8.7)
|
15
|
+
rcov (0.9.9)
|
16
|
+
rspec (2.5.0)
|
17
|
+
rspec-core (~> 2.5.0)
|
18
|
+
rspec-expectations (~> 2.5.0)
|
19
|
+
rspec-mocks (~> 2.5.0)
|
20
|
+
rspec-core (2.5.1)
|
21
|
+
rspec-expectations (2.5.0)
|
22
|
+
diff-lcs (~> 1.1.2)
|
23
|
+
rspec-mocks (2.5.0)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
bundler (~> 1.0.0)
|
30
|
+
fastercsv (>= 1.5.4)
|
31
|
+
hpricot
|
32
|
+
itrigga-core_ext
|
33
|
+
jeweler (~> 1.6.4)
|
34
|
+
json_pure
|
35
|
+
rcov
|
36
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Al Davidson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= net_helper
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to net_helper
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 Al Davidson. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "itrigga-net_helper"
|
18
|
+
gem.homepage = "http://gems.itrigga.com/trigga-net_helper"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Wrapper around Net::HTTP to provide retries, redirects, etc}
|
21
|
+
gem.description = %Q{Provides various more convenient wrappers around Net::HTTP methods}
|
22
|
+
gem.email = "aldavidson@trigga.com"
|
23
|
+
gem.authors = ["Al Davidson"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "net_helper #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'hpricot'
|
3
|
+
require 'json'
|
4
|
+
require 'cgi'
|
5
|
+
require 'timeout'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
module Itrigga
|
9
|
+
module NetHelper
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def do_get(url, time_out=5, retries_on_timeout=5, max_redirects = 3)
|
14
|
+
retrycount = 0
|
15
|
+
resp = nil
|
16
|
+
begin
|
17
|
+
resp = get_with_timeout( url, time_out )
|
18
|
+
|
19
|
+
handle_response( url, resp, retries_on_timeout, max_redirects )
|
20
|
+
|
21
|
+
rescue Timeout::Error
|
22
|
+
if(retrycount.to_i < retries_on_timeout.to_i)
|
23
|
+
retrycount+=1
|
24
|
+
retry
|
25
|
+
else
|
26
|
+
raise IOError.new( "HTTP request timed out #{retrycount} times" )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_with_timeout( url, time_out)
|
33
|
+
resp = timeout(time_out) do
|
34
|
+
Net::HTTP.get_response(URI.parse(url))
|
35
|
+
end
|
36
|
+
resp
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def handle_response( url, resp, retries_on_timeout=5, max_redirects = 3 )
|
41
|
+
if resp.is_a? Net::HTTPSuccess then resp.body
|
42
|
+
elsif resp.is_a? Net::HTTPRedirection
|
43
|
+
if max_redirects > 0
|
44
|
+
do_get( URI.parse(url).merge(resp['location']).to_s, retries_on_timeout, max_redirects - 1 )
|
45
|
+
else
|
46
|
+
raise IOError.new("too many redirects!")
|
47
|
+
end
|
48
|
+
else
|
49
|
+
resp.error!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def get( options = {} )
|
55
|
+
opts = {:timeout=>5, :retries_on_timeout=>5, :max_redirects => 3, :headers=>{} }.merge(options)
|
56
|
+
raise ArgumentError.new(":url is required" ) unless opts[:url]
|
57
|
+
|
58
|
+
if (opts[:username] || opts[:headers]).to_s.empty?
|
59
|
+
do_get(opts[:url], opts[:timeout], opts[:retries_on_timeout], opts[:max_redirects])
|
60
|
+
else
|
61
|
+
|
62
|
+
retrycount = 0
|
63
|
+
resp = begin
|
64
|
+
timeout( opts[:timeout] ) do
|
65
|
+
raw_get(opts)
|
66
|
+
end
|
67
|
+
rescue TimeoutError
|
68
|
+
if(retrycount < opts[:retries_on_timeout])
|
69
|
+
retrycount+=1
|
70
|
+
retry
|
71
|
+
else
|
72
|
+
raise IOError.new( "HTTP request timed out #{retrycount} times" )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
resp
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def raw_get(opts)
|
80
|
+
resp = nil
|
81
|
+
establish_session_if_needed(opts)
|
82
|
+
|
83
|
+
if opts[:username]
|
84
|
+
resp = get_with_auth(opts)
|
85
|
+
retries = 0
|
86
|
+
while resp.is_a? Net::HTTPRedirection do
|
87
|
+
retries += 1
|
88
|
+
raise IOError.new( "HTTP request timed out #{retries} times" ) if retries > (opts[:max_redirects] || 3)
|
89
|
+
|
90
|
+
resp = get_with_auth(opts.merge(:parsed_url=>URI.parse(resp['location'])))
|
91
|
+
end
|
92
|
+
|
93
|
+
resp.body
|
94
|
+
|
95
|
+
else
|
96
|
+
response = opts[:http_session].request_get(opts[:parsed_url].path, opts[:headers])
|
97
|
+
response.body
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_with_auth( opts )
|
102
|
+
establish_session_if_needed(opts)
|
103
|
+
|
104
|
+
req = Net::HTTP::Get.new(opts[:parsed_url].path)
|
105
|
+
req.basic_auth( opts[:username], opts[:password] ) if opts[:username]
|
106
|
+
resp = opts[:http_session].request(req, opts[:headers])
|
107
|
+
end
|
108
|
+
|
109
|
+
def establish_session_if_needed(opts)
|
110
|
+
opts[:parsed_url] ||= URI.parse(opts[:url])
|
111
|
+
opts[:http_session] ||= Net::HTTP.new(opts[:parsed_url].host, opts[:parsed_url].port)
|
112
|
+
opts[:http_session].use_ssl = true if opts[:parsed_url].scheme == 'https'
|
113
|
+
end
|
114
|
+
|
115
|
+
def query_string( h, opts={:encode_values=>false, :skip_empty=>false} )
|
116
|
+
params = []
|
117
|
+
h.each{ |k,v|
|
118
|
+
params << "#{k.to_s}=#{ opts[:encode_values] ? url_encode(v) : v }" unless v.to_s.empty? && opts[:skip_empty]
|
119
|
+
}
|
120
|
+
params.sort.join('&')
|
121
|
+
end
|
122
|
+
|
123
|
+
def url_encode( s )
|
124
|
+
URI.escape( s.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") )
|
125
|
+
end
|
126
|
+
|
127
|
+
def discover_favicon_url(root_url, time_out = 5)
|
128
|
+
favicon_urls = ['favicon.ico'] + discover_icon_hrefs(root_url)
|
129
|
+
favicon_urls.compact.each do |url|
|
130
|
+
abs_url = URI.join(root_url, url).to_s
|
131
|
+
return abs_url if get_with_timeout( abs_url, time_out ).is_a?(Net::HTTPSuccess)
|
132
|
+
end
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def discover_icon_hrefs(url)
|
137
|
+
pd = open(url) { |f| parse_with_hpricot(f) }
|
138
|
+
links = pd.search("//link[@rel='shortcut icon']") + pd.search("//link[@rel='icon']")
|
139
|
+
links.map{ |link| link.attributes['href'] }.compact.to_a
|
140
|
+
end
|
141
|
+
|
142
|
+
# Have difficulty mocking/stubbing the top-level Hpricot call
|
143
|
+
# This wrapper makes it testable
|
144
|
+
def parse_with_hpricot(html)
|
145
|
+
Hpricot.parse(html)
|
146
|
+
end
|
147
|
+
|
148
|
+
def ip_of(server)
|
149
|
+
IPSocket::getaddress(server)
|
150
|
+
end
|
151
|
+
|
152
|
+
# uses the url shortener service defined for this site
|
153
|
+
# by default will use bit.ly
|
154
|
+
def shorten_url(raw_url,attempts = 0)
|
155
|
+
|
156
|
+
return raw_url if attempts > 3
|
157
|
+
|
158
|
+
url = self.format_url_shortener_api_url(raw_url)
|
159
|
+
|
160
|
+
begin
|
161
|
+
response = NetHelper.get :url => url
|
162
|
+
rescue Exception => e
|
163
|
+
sleep 10 unless defined?(RAILS_ENV) && RAILS_ENV == "test"
|
164
|
+
return shorten_url(raw_url,attempts+1)
|
165
|
+
end
|
166
|
+
|
167
|
+
data = JSON.parse(response).recursive_symbolize_keys!
|
168
|
+
|
169
|
+
|
170
|
+
if data[:status_code] == 200
|
171
|
+
return data[:data][:url]
|
172
|
+
else # theres been a problem, try again if we have tries left
|
173
|
+
|
174
|
+
sleep 10 unless defined?(RAILS_ENV) && RAILS_ENV == "test"
|
175
|
+
return shorten_url(raw_url,attempts+1)
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
# parses the :url template for the url shortener service
|
182
|
+
def format_url_shortener_api_url(raw_url, config_hash)
|
183
|
+
escaped_url = CGI::escape(raw_url)
|
184
|
+
config_hash[:url].gsub("{{username}}",config_hash[:username] || "").gsub("{{api_key}}",config_hash[:api_key] || "").gsub("{{raw_url}}",escaped_url)
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Transfer a file using scp between servers
|
189
|
+
#
|
190
|
+
# Options:
|
191
|
+
# :host - the target server name. Hash. Must have keys:
|
192
|
+
# => :port - the port on which to connect
|
193
|
+
# => :ssh_key_path - the absolute path to the ssh key file which it will use to connect
|
194
|
+
# => :user - the user to connect as
|
195
|
+
# => :host - the hostname to connect to
|
196
|
+
# :target_path - the absolute path on the target server to put the file
|
197
|
+
# :file - the file to transfer. Must be an absolute path to the file
|
198
|
+
#
|
199
|
+
def transfer_file_scp(opts = {})
|
200
|
+
|
201
|
+
raise ArgumentError.new("File '#{opts[:file]}' does not exist!") unless opts[:file] && File.exist?(opts[:file])
|
202
|
+
raise ArgumentError.new("host is required") unless opts[:host]
|
203
|
+
raise ArgumentError.new("No target_path defined") unless opts[:target_path]
|
204
|
+
|
205
|
+
#host = TRIGGA_CONFIG.hosts.detect{|host| host[:display_name].to_s == opts[:target].to_s}
|
206
|
+
|
207
|
+
# now that everything checks out make sure the destination dir path exists. If not then create it
|
208
|
+
command = "ssh -p#{opts[:host][:port]} -i #{opts[:host][:ssh_key_path]} #{opts[:host][:user]}@#{opts[:host][:host]} 'mkdir -p #{File.dirname(opts[:target_path])}'"
|
209
|
+
`#{command}`
|
210
|
+
|
211
|
+
# now transfer the file across
|
212
|
+
command = "scp -P#{opts[:host][:port]} -i #{opts[:host][:ssh_key_path]} #{opts[:file]} #{opts[:host][:user]}@#{opts[:host][:host]}:#{opts[:target_path]}"
|
213
|
+
`#{command}`
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,454 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'trigga/core_ext'
|
3
|
+
|
4
|
+
describe "Itrigga::NetHelper" do
|
5
|
+
before(:each) do
|
6
|
+
@mock_response = mock("response")
|
7
|
+
@mock_response.stub!(:body).and_return("body")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "do_get" do
|
11
|
+
it "should get the HTTP response" do
|
12
|
+
Itrigga::NetHelper.stub!(:handle_response).and_return("")
|
13
|
+
Net::HTTP.should_receive( :get_response ).with( URI.parse("http://some.com") ).and_return(@mock_response)
|
14
|
+
Itrigga::NetHelper.do_get( "http://some.com" )
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should call handle_response with the response" do
|
18
|
+
Net::HTTP.stub!( :get_response ).with( URI.parse("http://some.com") ).and_return(@mock_response)
|
19
|
+
Itrigga::NetHelper.should_receive(:handle_response).and_return("")
|
20
|
+
Itrigga::NetHelper.do_get( "http://some.com" )
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
describe "when the GET takes longer than time_out seconds" do
|
25
|
+
before(:each) do
|
26
|
+
Itrigga::NetHelper.stub!(:get_with_timeout).and_raise( TimeoutError.new("expected timeout") )
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "when it has retried < retries_on_timeout times" do
|
30
|
+
it "should retry" do
|
31
|
+
Itrigga::NetHelper.should_receive(:get_with_timeout).exactly(3).times
|
32
|
+
# NOTE: the important expectation is the above one!
|
33
|
+
lambda {
|
34
|
+
Itrigga::NetHelper.do_get( "http://some.com", 1, 2 )
|
35
|
+
}.should raise_error( IOError )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "when it has retried retries_on_timeout times" do
|
40
|
+
it "should raise an IOError" do
|
41
|
+
lambda {
|
42
|
+
Itrigga::NetHelper.do_get( "http://some.com", 0, 2 )
|
43
|
+
}.should raise_error( IOError )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "handle_response" do
|
51
|
+
|
52
|
+
describe "when the response is OK" do
|
53
|
+
before(:each) do
|
54
|
+
@mock_response.stub!(:is_a?).with(Net::HTTPSuccess).and_return true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return the response body" do
|
58
|
+
Itrigga::NetHelper.handle_response("http://some.com", @mock_response).should == "body"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "when the response is a redirect" do
|
63
|
+
before(:each) do
|
64
|
+
@mock_response.stub!(:is_a?).with(Net::HTTPSuccess).and_return false
|
65
|
+
@mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return true
|
66
|
+
@mock_response.stub!(:[]).with('location').and_return("http://some.redirect")
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "when redirects > 0" do
|
70
|
+
it "should recurse" do
|
71
|
+
Itrigga::NetHelper.should_receive(:do_get)
|
72
|
+
Itrigga::NetHelper.handle_response("http://some.com", @mock_response)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should pass the location field from the response as the url, and the same timeout" do
|
76
|
+
Itrigga::NetHelper.should_receive(:do_get).with( "http://some.redirect", 23, anything )
|
77
|
+
Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should pass redirects - 1 as the redirects param" do
|
81
|
+
Itrigga::NetHelper.should_receive(:do_get).with( anything, anything, 15 )
|
82
|
+
Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23, 16)
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "when the response location is relative" do
|
86
|
+
before(:each) do
|
87
|
+
@mock_response.stub!(:[]).with('location').and_return("/some/relative/path?param=567")
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should pass on the absolute url" do
|
91
|
+
Itrigga::NetHelper.should_receive(:do_get).with( "http://some.com/some/relative/path?param=567", anything, anything )
|
92
|
+
Itrigga::NetHelper.handle_response( "http://some.com/some_other/path.xml?id=123", @mock_response, 23, 16)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "when redirects = 0" do
|
98
|
+
it "should raise an IOError" do
|
99
|
+
lambda {
|
100
|
+
Itrigga::NetHelper.handle_response( "http://some.com", @mock_response, 23, 0)
|
101
|
+
}.should raise_error( IOError )
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "query_string" do
|
109
|
+
it "should return a string" do
|
110
|
+
Itrigga::NetHelper.query_string( 'blart' => 'flange' ).should be_a(String)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should map the given hash to query string format" do
|
114
|
+
Itrigga::NetHelper.query_string( 'blart'=>'flange').should == "blart=flange"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should sort the keys" do
|
118
|
+
Itrigga::NetHelper.query_string( :c=>1, :b=>2, :a=>3 ).should == "a=3&b=2&c=1"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should join each key/value pair with an ampersand" do
|
122
|
+
Itrigga::NetHelper.query_string( 'blart'=>'flange', 'donkey' => 'monkey').should == "blart=flange&donkey=monkey"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should transform sym keys to strings" do
|
126
|
+
Itrigga::NetHelper.query_string( :blart=>'flange').should == "blart=flange"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should render nils as empty values" do
|
130
|
+
Itrigga::NetHelper.query_string( 'blart'=>nil).should == "blart="
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "when :encode_values is true" do
|
134
|
+
it "should url encode each value" do
|
135
|
+
Itrigga::NetHelper.query_string( {'blart'=>'flange & more flange'}, :encode_values=>true ).should == "blart=flange%20%26%20more%20flange"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "when :skip_empty is true" do
|
140
|
+
it "should not include empty-valued fields" do
|
141
|
+
Itrigga::NetHelper.query_string( {:c=>1, :b=>nil, :a=>''}, :skip_empty=>true ).should == "c=1"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "discover_favicon_url" do
|
147
|
+
before(:each) do
|
148
|
+
@url = "http://blart.com"
|
149
|
+
Itrigga::NetHelper.stub!(:discover_icon_hrefs).with(@url).and_return([])
|
150
|
+
Itrigga::NetHelper.stub!(:get_with_timeout).and_return("")
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should get the given url joined with favicon.ico" do
|
154
|
+
Itrigga::NetHelper.should_receive(:get_with_timeout).with("http://blart.com/favicon.ico", anything).and_return("")
|
155
|
+
Itrigga::NetHelper.discover_favicon_url("http://blart.com")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should call discover_icon_hrefs" do
|
159
|
+
Itrigga::NetHelper.should_receive(:discover_icon_hrefs).with(@url).and_return([])
|
160
|
+
Itrigga::NetHelper.discover_favicon_url(@url)
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
context "each discovered href" do
|
167
|
+
context "when the get is a success" do
|
168
|
+
before(:each) do
|
169
|
+
Itrigga::NetHelper.stub!(:discover_icon_hrefs).with(@url).and_return(["/some/bad/path.ico", "/some/good/path.ico"])
|
170
|
+
@mock_404 = mock("404"); @mock_200 = mock("200")
|
171
|
+
@mock_404.stub!(:is_a?).with(Net::HTTPSuccess).and_return(false)
|
172
|
+
@mock_200.stub!(:is_a?).with(Net::HTTPSuccess).and_return(true)
|
173
|
+
Itrigga::NetHelper.stub!(:get_with_timeout).and_return( @mock_404, @mock_404, @mock_200 )
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should return the href joined onto the root url" do
|
177
|
+
Itrigga::NetHelper.discover_favicon_url(@url).should == "http://blart.com/some/good/path.ico"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
describe "discover_icon_hrefs" do
|
184
|
+
before(:each) do
|
185
|
+
@html = <<-HTML
|
186
|
+
<html>
|
187
|
+
<head>
|
188
|
+
<link rel="icon" href="http://an.absolute/url" />
|
189
|
+
<link rel="icon" href="relative/url" />
|
190
|
+
</head>
|
191
|
+
</html>
|
192
|
+
HTML
|
193
|
+
@url = "http://blart.com"
|
194
|
+
@mock_doc = mock("hpricot doc")
|
195
|
+
@mock_doc.stub!(:search).and_return([])
|
196
|
+
Itrigga::NetHelper.stub!(:open).with("http://blart.com").and_yield(@html)
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should open the given url" do
|
200
|
+
Itrigga::NetHelper.should_receive(:open).with("http://blart.com").and_yield(@html)
|
201
|
+
Itrigga::NetHelper.discover_icon_hrefs(@url)
|
202
|
+
end
|
203
|
+
it "should parse the given url with hpricot" do
|
204
|
+
Itrigga::NetHelper.should_receive(:parse_with_hpricot).with(@html).and_return(@mock_doc)
|
205
|
+
Itrigga::NetHelper.discover_icon_hrefs(@url)
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should search for links with a rel='shortcut icon'" do
|
209
|
+
Itrigga::NetHelper.stub!(:parse_with_hpricot).with(@html).and_return(@mock_doc)
|
210
|
+
@mock_doc.should_receive(:search).with("//link[@rel='shortcut icon']").and_return([])
|
211
|
+
Itrigga::NetHelper.discover_icon_hrefs(@url)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should search for links with a rel='icon'" do
|
215
|
+
Itrigga::NetHelper.stub!(:parse_with_hpricot).with(@html).and_return(@mock_doc)
|
216
|
+
@mock_doc.should_receive(:search).with("//link[@rel='shortcut icon']").and_return([])
|
217
|
+
Itrigga::NetHelper.discover_icon_hrefs(@url)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should return the collected href attributes" do
|
221
|
+
Itrigga::NetHelper.discover_icon_hrefs(@url).should == ["http://an.absolute/url", "relative/url"]
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "raw_get" do
|
227
|
+
before(:each) do
|
228
|
+
Itrigga::NetHelper.stub!(:get_with_auth).and_return( 'body' )
|
229
|
+
Itrigga::NetHelper.stub!(:establish_session_if_needed)
|
230
|
+
@mock_session = mock("http session")
|
231
|
+
@mock_session.stub!(:request_get).and_return( @mock_response = mock('request_get response') )
|
232
|
+
@mock_response.stub!(:body).and_return('response body')
|
233
|
+
@mock_parsed_url = mock("parsed url")
|
234
|
+
@mock_parsed_url.stub!(:host).and_return("host")
|
235
|
+
@mock_parsed_url.stub!(:path).and_return("path")
|
236
|
+
@mock_parsed_url.stub!(:port).and_return("port")
|
237
|
+
|
238
|
+
@mock_response = mock('response')
|
239
|
+
@mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return(false)
|
240
|
+
@mock_response.stub!(:body).and_return('cheese')
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should call establish_session_if_needed with the given opts" do
|
244
|
+
Itrigga::NetHelper.should_receive(:establish_session_if_needed).with(hash_including(:blart=>'flange'))
|
245
|
+
Itrigga::NetHelper.raw_get(:blart=>'flange', :http_session=>@mock_session, :parsed_url=>@mock_parsed_url)
|
246
|
+
end
|
247
|
+
|
248
|
+
context "when given a :username" do
|
249
|
+
it "should call get_with_auth with the given options" do
|
250
|
+
Itrigga::NetHelper.should_receive(:get_with_auth).with(hash_including(:username=>'dave')).and_return(@mock_response)
|
251
|
+
Itrigga::NetHelper.raw_get(:username=>'dave')
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should return the result of get_with_auth" do
|
255
|
+
Itrigga::NetHelper.stub!(:get_with_auth).with(hash_including(:username=>'dave')).and_return(@mock_response)
|
256
|
+
Itrigga::NetHelper.raw_get(:username=>'dave').should == 'cheese'
|
257
|
+
end
|
258
|
+
|
259
|
+
context "when response is a redirection" do
|
260
|
+
before(:each) do
|
261
|
+
@mock_response.stub!(:is_a?).with(Net::HTTPRedirection).and_return(true, false)
|
262
|
+
@mock_response.stub!(:[]).with('location').and_return("http://cheesefish.com")
|
263
|
+
URI.stub!(:parse).with("http://cheesefish.com").and_return(@mock_parsed_url = mock('parsed url'))
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should follow the redirect" do
|
267
|
+
URI.should_receive(:parse).with("http://cheesefish.com").and_return(@mock_parsed_url = mock('parsed url'))
|
268
|
+
Itrigga::NetHelper.should_receive(:get_with_auth).twice.and_return(@mock_response)
|
269
|
+
Itrigga::NetHelper.raw_get(:username=>'dave')
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
context "when not given a :username" do
|
275
|
+
it "should call request_get on the http session with the :parsed_url's path and :headers" do
|
276
|
+
@mock_session.should_receive(:request_get).with( 'path', {:donkey=>'dipstick'}).and_return(@mock_response)
|
277
|
+
Itrigga::NetHelper.raw_get( :parsed_url=>@mock_parsed_url, :http_session=>@mock_session, :headers=>{:donkey=>'dipstick'} )
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should return the result of calling body on the request_get's response" do
|
281
|
+
Itrigga::NetHelper.raw_get(:parsed_url=>@mock_parsed_url, :http_session=>@mock_session).should == 'response body'
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
describe "get_with_auth" do
|
288
|
+
before(:each) do
|
289
|
+
Itrigga::NetHelper.stub!(:establish_session_if_needed)
|
290
|
+
@mock_get = mock('get')
|
291
|
+
@mock_get.stub!(:basic_auth)
|
292
|
+
Net::HTTP::Get.stub!(:new).and_return(@mock_get)
|
293
|
+
@mock_parsed_url = mock("parsed url")
|
294
|
+
@mock_parsed_url.stub!(:host).and_return("host")
|
295
|
+
@mock_parsed_url.stub!(:path).and_return("path")
|
296
|
+
@mock_parsed_url.stub!(:port).and_return("port")
|
297
|
+
@mock_session = mock("http session")
|
298
|
+
@mock_session.stub!(:request).and_return("request response")
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should call establish_session_if_needed with the given opts" do
|
302
|
+
Itrigga::NetHelper.should_receive(:establish_session_if_needed).with(hash_including(:blart=>'flange'))
|
303
|
+
Itrigga::NetHelper.get_with_auth(:blart=>'flange', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should create a new Net::HTTP::Get with the path of the :parsed_url" do
|
307
|
+
Net::HTTP::Get.should_receive(:new).with('path').and_return(@mock_get)
|
308
|
+
Itrigga::NetHelper.get_with_auth(:blart=>'flange', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should call basic_auth on the get, passing :username and :password from the given params" do
|
312
|
+
@mock_get.should_receive(:basic_auth).with( 'username', 'password' )
|
313
|
+
Itrigga::NetHelper.get_with_auth(:username=>'username', :password=>'password', :parsed_url=>@mock_parsed_url, :http_session=>@mock_session)
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should call request on the http_session with the get, and any given :headers" do
|
317
|
+
@mock_session.should_receive(:request).with(@mock_get, {:header1=>'value1'})
|
318
|
+
Itrigga::NetHelper.get_with_auth(:http_session=>@mock_session, :headers=>{:header1=>'value1'}, :parsed_url=>@mock_parsed_url, :http_session=>@mock_session )
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should return the result of the request" do
|
322
|
+
@mock_session.should_receive(:request).with(@mock_get, {:header1=>'value1'}).and_return("cheese")
|
323
|
+
Itrigga::NetHelper.get_with_auth(:http_session=>@mock_session, :headers=>{:header1=>'value1'}, :parsed_url=>@mock_parsed_url, :http_session=>@mock_session ).should == "cheese"
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
describe "establish_session_if_needed" do
|
328
|
+
before(:each) do
|
329
|
+
@mock_parsed_url = mock("parsed url")
|
330
|
+
@mock_parsed_url.stub!(:host).and_return("host")
|
331
|
+
@mock_parsed_url.stub!(:port).and_return("port")
|
332
|
+
@mock_parsed_url.stub!(:scheme).and_return("scheme")
|
333
|
+
@mock_session = mock('http session')
|
334
|
+
@mock_session.stub!(:use_ssl=)
|
335
|
+
Net::HTTP.stub!(:new).and_return(@mock_session)
|
336
|
+
end
|
337
|
+
|
338
|
+
context "When not given a :parsed_url" do
|
339
|
+
it "should set :parsed_url to URI.parse(:url)" do
|
340
|
+
URI.should_receive(:parse).with("URL").and_return(@mock_parsed_url)
|
341
|
+
Itrigga::NetHelper.establish_session_if_needed(:url=>"URL")
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context "When not given a :http_session" do
|
346
|
+
it "should set :http_session to a new Net::HTTP with the parsed_url's host and port" do
|
347
|
+
Net::HTTP.should_receive(:new).with("host", "port").and_return(@mock_session)
|
348
|
+
Itrigga::NetHelper.establish_session_if_needed(:parsed_url=>@mock_parsed_url)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
context "when the :parsed_url's scheme is https" do
|
353
|
+
before(:each) do
|
354
|
+
@mock_parsed_url.stub!(:scheme).and_return("https")
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should set use_ssl=true on the http session" do
|
358
|
+
@mock_session.should_receive(:use_ssl=).with(true)
|
359
|
+
Itrigga::NetHelper.establish_session_if_needed(:parsed_url=>@mock_parsed_url)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe "shorten_url" do
|
365
|
+
before do
|
366
|
+
@raw_url = "http://very_long_url_goes_here.com"
|
367
|
+
@shortened_url = "http://url_goes_here.com"
|
368
|
+
Itrigga::NetHelper.stub!(:format_url_shortener_api_url).and_return("http://myshorturl.com")
|
369
|
+
Itrigga::NetHelper.stub!(:get).and_return("{\"status_code\":200,\"data\":{\"url\":\"#{@shortened_url}\"}}")
|
370
|
+
end
|
371
|
+
|
372
|
+
describe "with valid input" do
|
373
|
+
it "should call format_url_shortener_api_url" do
|
374
|
+
Itrigga::NetHelper.should_receive(:format_url_shortener_api_url).with(@raw_url)
|
375
|
+
Itrigga::NetHelper.shorten_url(@raw_url)
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should return a short url" do
|
379
|
+
Itrigga::NetHelper.shorten_url(@raw_url).should == @shortened_url
|
380
|
+
end
|
381
|
+
|
382
|
+
it "should return raw_url on web request timesout" do
|
383
|
+
Itrigga::NetHelper.stub!(:get).and_raise(Exception)
|
384
|
+
Itrigga::NetHelper.shorten_url(@raw_url).should == @raw_url
|
385
|
+
end
|
386
|
+
|
387
|
+
it "should return raw url for anything other than a status 200" do
|
388
|
+
Itrigga::NetHelper.stub!(:get).and_return("{\"status_code\":500,\"data\":{\"url\":\"#{@shortened_url}\"}}")
|
389
|
+
Itrigga::NetHelper.shorten_url(@raw_url).should == @raw_url
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
describe "format_url_shortener_api_url" do
|
396
|
+
before do
|
397
|
+
@raw_url = "http://very_long_url_goes_here.com"
|
398
|
+
@config_hash = ( {:url => "{{raw_url}}", :username => "a", :api_key => "123"} )
|
399
|
+
end
|
400
|
+
|
401
|
+
it "should return the api url" do
|
402
|
+
Itrigga::NetHelper.format_url_shortener_api_url(@raw_url, @config_hash).should == "http%3A%2F%2Fvery_long_url_goes_here.com"
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should url encode the raw_url" do
|
406
|
+
CGI.should_receive(:escape).with(@raw_url).and_return("http%3A%2F%2Fvery_long_url_goes_here.com")
|
407
|
+
Itrigga::NetHelper.format_url_shortener_api_url(@raw_url, @config_hash)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
describe "transfer_file_scp" do
|
413
|
+
before(:each) do
|
414
|
+
@host = { :display_name => "display_name", :port => 123, :user => "user", :host => "hostname", :ssh_key_path => "key_file_path" }
|
415
|
+
Itrigga::NetHelper.stub!(:'`').and_return(true)
|
416
|
+
File.stub!(:exist?).and_return(true)
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should raise error if no file in opts" do
|
420
|
+
lambda { Itrigga::NetHelper.transfer_file_scp(:host=>@host) }.should raise_error(ArgumentError)
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should raise error if file in opts does not exist" do
|
424
|
+
File.stub!(:exist?).and_return(false)
|
425
|
+
lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host) }.should raise_error(ArgumentError)
|
426
|
+
end
|
427
|
+
|
428
|
+
it "should raise error if no host in opts" do
|
429
|
+
lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile") }.should raise_error(ArgumentError)
|
430
|
+
end
|
431
|
+
|
432
|
+
it "should raise error if no target_path in opts" do
|
433
|
+
lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host) }.should raise_error(ArgumentError)
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should not raise an error if the host exists" do
|
437
|
+
lambda { Itrigga::NetHelper.transfer_file_scp(:file => "mycrazyfile", :host=>@host, :target_path => "/path/goes/here/to/file.xml")}.should_not raise_error
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should call ssh to create dir path with the correct string" do
|
441
|
+
opts = {:target => "display_name", :file => "a_file_name", :target_path => "/path/goes/here/to/file.xml", :host=>@host}
|
442
|
+
Itrigga::NetHelper.should_receive(:'`').with("ssh -p123 -i key_file_path user@hostname 'mkdir -p /path/goes/here/to'")
|
443
|
+
Itrigga::NetHelper.transfer_file_scp(opts)
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should call scp with the correct string" do
|
447
|
+
opts = {:target => "display_name", :file => "a_file_name", :target_path => "/path/goes/here/to/file.xml", :host=>@host}
|
448
|
+
Itrigga::NetHelper.should_receive(:'`').with("scp -P123 -i key_file_path a_file_name user@hostname:/path/goes/here/to/file.xml")
|
449
|
+
Itrigga::NetHelper.transfer_file_scp(opts)
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'rspec'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'itrigga/net_helper'
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
# some (optional) config here
|
19
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'net_helper'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: itrigga-net_helper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Al Davidson
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-20 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
name: hpricot
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
requirement: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
name: bundler
|
39
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 23
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
version: 1.0.0
|
50
|
+
requirement: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
type: :development
|
53
|
+
prerelease: false
|
54
|
+
name: jeweler
|
55
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 7
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 6
|
64
|
+
- 4
|
65
|
+
version: 1.6.4
|
66
|
+
requirement: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
name: rcov
|
71
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirement: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
name: rspec
|
85
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
requirement: *id005
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
name: json_pure
|
99
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirement: *id006
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
name: itrigga-core_ext
|
113
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
requirement: *id007
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
name: fastercsv
|
127
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 11
|
133
|
+
segments:
|
134
|
+
- 1
|
135
|
+
- 5
|
136
|
+
- 4
|
137
|
+
version: 1.5.4
|
138
|
+
requirement: *id008
|
139
|
+
description: Provides various more convenient wrappers around Net::HTTP methods
|
140
|
+
email: aldavidson@trigga.com
|
141
|
+
executables: []
|
142
|
+
|
143
|
+
extensions: []
|
144
|
+
|
145
|
+
extra_rdoc_files:
|
146
|
+
- LICENSE.txt
|
147
|
+
- README.rdoc
|
148
|
+
files:
|
149
|
+
- Gemfile
|
150
|
+
- Gemfile.lock
|
151
|
+
- LICENSE.txt
|
152
|
+
- README.rdoc
|
153
|
+
- Rakefile
|
154
|
+
- VERSION
|
155
|
+
- lib/itrigga/net_helper.rb
|
156
|
+
- spec/net_helper_spec.rb
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
- test/helper.rb
|
159
|
+
- test/test_net_helper.rb
|
160
|
+
has_rdoc: true
|
161
|
+
homepage: http://gems.itrigga.com/trigga-net_helper
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
hash: 3
|
175
|
+
segments:
|
176
|
+
- 0
|
177
|
+
version: "0"
|
178
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
+
none: false
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
hash: 3
|
184
|
+
segments:
|
185
|
+
- 0
|
186
|
+
version: "0"
|
187
|
+
requirements: []
|
188
|
+
|
189
|
+
rubyforge_project:
|
190
|
+
rubygems_version: 1.3.7
|
191
|
+
signing_key:
|
192
|
+
specification_version: 3
|
193
|
+
summary: Wrapper around Net::HTTP to provide retries, redirects, etc
|
194
|
+
test_files: []
|
195
|
+
|