shb 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e59ea891242f1ed837c35ba9be734526226019f1
4
+ data.tar.gz: ff0757e7ed3e2e7a556122804181ab9215cc733c
5
+ SHA512:
6
+ metadata.gz: c0ca8bb25eda6b02228174552d1c23d90199f6c35490899f28ababf6675c7efb161f9c3f84622903dfd1f4f3e73669e8de7c51b998c6948f43c7b645c71580dc
7
+ data.tar.gz: c16c2157ea4be0f51df260c250911e02df0d52d097fcaaae53422fe6c18cc65d0fe0d3741c20a299e5b328108c7c70bf9759d8848504ff8cfb8d82d694cae106
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg
2
+ Gemfile.lock
3
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in slackistrano.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Philip Hallstrom
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,27 @@
1
+ # Shb
2
+
3
+ ## Requirements
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'shb'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ ## Configuration
16
+
17
+ ## Usage
18
+
19
+ ## TODO
20
+
21
+ ## Contributing
22
+
23
+ 1. Fork it
24
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
25
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
26
+ 4. Push to the branch (`git push origin my-new-feature`)
27
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :spec
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
data/circle.yml ADDED
@@ -0,0 +1,3 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.0.0-p451
@@ -0,0 +1,138 @@
1
+ module Shb
2
+ class AbstractClient
3
+
4
+ include ActiveSupport::Configurable
5
+ include HTTParty
6
+
7
+ AGENT_ALIASES = [
8
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.71 (KHTML, like Gecko) Version/6.1 Safari/537.71', # Safari on OSX Lion
9
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9) AppleWebKit/537.71 (KHTML, like Gecko) Version/7.0 Safari/537.71', # Safari on OSX Mavericks
10
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:17.0) Gecko/20100101 Firefox/17.0', # Firefox on Mac
11
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36', # Chrome on Mac
12
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36', # Chrome on Windows 7
13
+ 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)', # IE10 on Windows 7
14
+ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0', # Firefox on Windows 7
15
+ ]
16
+
17
+ config.cache = !!(ENV['SHB_CACHE'] =~ /^[T1Y]/i) # TRUE, 1, YES
18
+ config.cache_class = ::Shb::Cache
19
+ config.cycle_user_agent = false
20
+ config.use_cookies = false
21
+ config.logger = nil
22
+
23
+ parser ::Shb::Parser
24
+ follow_redirects false
25
+ headers 'User-Agent' => AGENT_ALIASES.first
26
+
27
+ def initialize(base_uri: 'http://supremegolf.com')
28
+ self.class.base_uri base_uri
29
+ @root_uri = URI.parse(self.class.base_uri.to_s)
30
+ end
31
+
32
+ def get(path, options = {}, &block)
33
+ make_request!(:get, path, options, &block)
34
+ end
35
+
36
+ def post(path, options = {}, &block)
37
+ make_request!(:post, path, options, &block)
38
+ end
39
+
40
+ def put(path, options = {}, &block)
41
+ make_request!(:put, path, options, &block)
42
+ end
43
+
44
+ ################################################################################
45
+ private
46
+
47
+ #
48
+ def make_request!(method, path, options = {}, &block)
49
+ uri = path_to_uri(path)
50
+ if (response = cache_read(method, uri, options)).nil?
51
+ log_request!(method, uri, options)
52
+ cycle_user_agent!
53
+ set_cookies!
54
+ response = self.class.send(method, uri.to_s, options, &block)
55
+ save_cookies!(response)
56
+ cache_write(response, uri, options)
57
+ end
58
+ response
59
+ rescue SocketError, Net::ReadTimeout => e
60
+ logger.error "ERROR #{e.inspect} : uri=#{uri}"
61
+ sleep 60
62
+ retry
63
+ end
64
+
65
+ #
66
+ def path_to_uri(path)
67
+ @root_uri.merge(path.to_s.gsub(' ', '%20'))
68
+ end
69
+
70
+ #
71
+ def log_request!(method, uri, options)
72
+ logger.info "#{method.to_s.upcase} #{uri.to_s}#{options[:query].nil? ? nil : "?#{HashConversions.to_params(options[:query])}"}"
73
+ end
74
+
75
+ #
76
+ def cycle_user_agent!
77
+ return unless config.cycle_user_agent
78
+ @user_agent_alias_idx ||= 0
79
+ self.class.headers('User-Agent' => AGENT_ALIASES[@user_agent_alias_idx])
80
+ @user_agent_alias_idx += 1
81
+ @user_agent_alias_idx %= AGENT_ALIASES.size
82
+ end
83
+
84
+ #
85
+ def set_cookies!
86
+ return unless config.use_cookies && !@cookies.nil?
87
+ self.class.headers('Cookie' => @cookies)
88
+ end
89
+
90
+ #
91
+ def save_cookies!(response)
92
+ return unless config.use_cookies
93
+ @cookies = response.headers['set-cookie']
94
+ end
95
+
96
+ #
97
+ def logger
98
+ return @logger unless @logger.nil?
99
+
100
+ @logger = if config.logger
101
+ ::Logger.new(config.logger)
102
+ elsif defined?(::Rails)
103
+ ::Logger.new( File.join(::Rails.root, 'log', 'shb.log') )
104
+ else
105
+ ::Logger.new(STDERR)
106
+ end
107
+
108
+ @logger.formatter = proc do |severity, datetime, progname, msg|
109
+ "%-7s [%s] -- %s\n" % [severity, datetime, msg]
110
+ end
111
+
112
+ @logger
113
+ end
114
+
115
+ #
116
+ def cache_write(response, uri, options = {})
117
+ return true unless config.cache
118
+ return true if response.code >= 400 # Don't cache bad responses
119
+ config.cache_class.write(response, uri, options)
120
+ end
121
+
122
+ def cache_read(method, uri, options = {})
123
+ return nil unless config.cache
124
+
125
+ logger.info "#{method.to_s.upcase} CACHE #{uri.to_s}#{method == :get && !options[:query].to_s.empty? ? "?#{HashConversions.to_params(options[:query])}" : nil}"
126
+
127
+ response = config.cache_class.read(method, uri, options)
128
+
129
+ return nil if response.nil?
130
+
131
+ HTTParty::Response.new(OpenStruct.new(options:options), response,
132
+ ->{ self.class.parser.call(response.body, options[:format] || self.class.parser.format_from_mimetype(response.content_type)) },
133
+ body: response.body)
134
+
135
+ end
136
+
137
+ end # of class AbstractClient
138
+ end
data/lib/shb/cache.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'fileutils'
2
+
3
+ module Shb
4
+ class Cache
5
+ class << self
6
+
7
+ def write(response, uri, options = {})
8
+ file = cache_file(uri, options)
9
+ FileUtils.mkdir_p(File.dirname(file))
10
+ File.open(file, 'w') do |f|
11
+ f.puts YAML::dump(response.response)
12
+ end
13
+ end
14
+
15
+ def read(method, uri, options = {})
16
+ file = cache_file(uri, options)
17
+ return nil unless File.exist?(file)
18
+ r = YAML::load_file(file)
19
+ r.content_type = 'text/plain' if r.content_type.nil?
20
+ r
21
+ end
22
+
23
+ def cache_file(uri, options = {})
24
+ bits = []
25
+ bits << Rails.root if defined?(::Rails)
26
+ bits << 'tmp'
27
+ bits << uri.host
28
+ path = uri.path == '/' ? 'ROOT' : uri.path.parameterize
29
+ query = options.empty? ? nil : "?#{HashConversions.to_params(options)}"
30
+ bits << Digest::MD5.hexdigest([path,uri.fragment,uri.query,query].join)
31
+ File.join(bits)
32
+ end
33
+
34
+ end
35
+ end
36
+ end
data/lib/shb/client.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Shb
2
+ class Client
3
+ # http://rubyscale.com/blog/2012/09/24/being-classy-with-httparty/
4
+ class << self
5
+ def new(*args)
6
+ Class.new(AbstractClient).new(*args)
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/shb/parser.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'nokogiri'
2
+ require 'json'
3
+
4
+ module Shb
5
+ class Parser < HTTParty::Parser
6
+ SupportedFormats.merge!(
7
+ 'text/html' => :html,
8
+ 'text/xml' => :xml,
9
+ 'application/jsonnet' => :json,
10
+ 'application/json' => :json
11
+ )
12
+
13
+ def html
14
+ Nokogiri::HTML(body)
15
+ end
16
+
17
+ def xml
18
+ Nokogiri::XML(body)
19
+ end
20
+
21
+ def json
22
+ JSON.parse(body)
23
+ rescue JSON::ParserError
24
+ nil
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Shb
2
+ VERSION = '0.0.2'
3
+ end
data/lib/shb.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'active_support/configurable'
2
+ require 'httparty'
3
+ require 'logger'
4
+ require 'shb/version'
5
+ require 'shb/parser'
6
+ require 'shb/cache'
7
+ require 'shb/abstract_client'
8
+ require 'shb/client'
data/shb.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'shb/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "shb"
8
+ gem.version = Shb::VERSION
9
+ gem.authors = ["Philip Hallstrom"]
10
+ gem.email = ["philip@supremegolf.com"]
11
+ gem.description = %q{}
12
+ gem.summary = %q{}
13
+ gem.homepage = "https://github.com/supremegolf/shb"
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_dependency 'activesupport', '>= 4.0'
22
+ gem.add_dependency 'httparty', '>= 0.13.1'
23
+ gem.add_dependency 'nokogiri', '>= 1.6.3.1'
24
+ gem.add_dependency 'json'
25
+
26
+ gem.add_development_dependency 'rake'
27
+ gem.add_development_dependency 'rspec'
28
+ gem.add_development_dependency 'webmock'
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+ before do
5
+ stub_request(:any, 'supremegolf.com')
6
+ end
7
+
8
+ it "should test more than this" do
9
+ shb = Shb::Client.new
10
+ shb.config.cache = true
11
+ shb.get('/')
12
+ shb.get('/')
13
+ end
14
+
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+
5
+ it "does not cycle the user agent" do
6
+ stub_request(:any, 'supremegolf.com')
7
+ shb = Shb::Client.new
8
+ shb.config.cycle_user_agent = false
9
+
10
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[0]
11
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[0]
12
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[0]
13
+ end
14
+
15
+ it "cycles the user agent" do
16
+ stub_request(:any, 'supremegolf.com')
17
+ shb = Shb::Client.new
18
+ shb.config.cycle_user_agent = true
19
+
20
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[0]
21
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[1]
22
+ expect(shb.get('/').request.options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES[2]
23
+ end
24
+
25
+ end
data/spec/html_spec.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+ before do
5
+ stub_request(:any, 'supremegolf.com').to_return {|r|
6
+ {
7
+ body: '<html><title>Test</title></html>',
8
+ headers: {'Content-Type' => 'text/html'}
9
+ }
10
+ }
11
+ end
12
+ let(:shb) { Shb::Client.new }
13
+
14
+ specify { expect(shb.get('/').parsed_response).to be_a Nokogiri::HTML::Document }
15
+ specify { expect(shb.get('/').parsed_response.at('title').text).to eq 'Test' }
16
+ end
data/spec/json_spec.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+ before do
5
+ stub_request(:any, 'supremegolf.com').to_return {|r|
6
+ {
7
+ body: '{"one":1}',
8
+ headers: {'Content-Type' => 'application/json'}
9
+ }
10
+ }
11
+ stub_request(:any, 'supremegolf.com/bad-json').to_return {|r|
12
+ {
13
+ body: '{missing_first_double_quote":1}',
14
+ headers: {'Content-Type' => 'application/json'}
15
+ }
16
+ }
17
+ end
18
+ let(:shb) { Shb::Client.new }
19
+
20
+ specify { expect(shb.get('/').parsed_response).to be_a Hash }
21
+ specify { expect(shb.get('/').parsed_response['one']).to eq 1 }
22
+ specify { expect(shb.get('/bad-json').parsed_response).to eq nil }
23
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+ before do
5
+ stub_request(:any, 'supremegolf.com')
6
+ end
7
+
8
+ it "logs to STDERR by default" do
9
+ expect(::Logger).to receive(:new).with(STDERR).and_call_original
10
+ shb = Shb::Client.new
11
+ shb.get('/')
12
+ end
13
+
14
+ it "logs to custom location if specified" do
15
+ expect(::Logger).to receive(:new).with(STDOUT).and_call_original
16
+ shb = Shb::Client.new
17
+ shb.config.logger = STDOUT
18
+ shb.get('/')
19
+ end
20
+
21
+ it "logs to Rails.root/tmp/shb.log if using Rails" do
22
+ skip "How to double ::Rails and ::Rails.root?"
23
+ shb = Shb::Client.new
24
+ expect(::Logger).to receive(:new).with('rails-root/log/shb.log').and_call_original
25
+ shb.get('/')
26
+ end
27
+
28
+
29
+ end
data/spec/shb_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+
5
+ context "defaults" do
6
+ specify { expect(Shb::Client.new.config.cache).to be_falsey }
7
+ specify { expect(Shb::Client.new.config.cycle_user_agent).to be_falsey }
8
+ specify { expect(Shb::Client.new.config.use_cookies).to be_falsey }
9
+ specify { expect(Shb::Client.new.class.default_options[:parser]).to eq Shb::Parser }
10
+ specify { expect(Shb::Client.new.class.default_options[:follow_redirects]).to be_falsey }
11
+ specify { expect(Shb::Client.new.class.default_options[:headers]['User-Agent']).to eq Shb::AbstractClient::AGENT_ALIASES.first }
12
+ end
13
+
14
+ context "simple requests" do
15
+ before do
16
+ stub_request(:any, 'supremegolf.com').to_return {|r|
17
+ {
18
+ status:200,
19
+ body: r.method.to_s.downcase
20
+ }
21
+ }
22
+ end
23
+ let(:shb) { Shb::Client.new }
24
+
25
+ specify { expect(shb.get('/').code).to eq 200 }
26
+ specify { expect(shb.get('/').body).to eq "get" }
27
+ specify { expect(shb.post('/').code).to eq 200 }
28
+ specify { expect(shb.post('/').body).to eq "post" }
29
+ specify { expect(shb.put('/').code).to eq 200 }
30
+ specify { expect(shb.put('/').body).to eq "put" }
31
+ end
32
+
33
+ context "requests with data" do
34
+ before do
35
+ stub_request(:any, 'supremegolf.com?q=1').to_return {|r|
36
+ { status:200, body: [r.uri.query, r.body].join('&') }
37
+ }
38
+ end
39
+ let(:shb) { Shb::Client.new }
40
+
41
+ specify { expect(shb.get('/', query: {q: 1}).body).to eq "q=1&" }
42
+ specify { expect(shb.post('/', query: {q: 1}, body: {body: 1}).body).to eq "q=1&body=1" }
43
+ specify { expect(shb.put('/', query: {q: 1}, body: {body: 1}).body).to eq "q=1&body=1" }
44
+ end
45
+
46
+
47
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'shb'
4
+ require 'rspec'
5
+ require 'webmock/rspec'
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir['#{File.dirname(__FILE__)}/support/**/*.rb'].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+ config.order = 'random'
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+
5
+ it "does not use cookies" do
6
+ stub_request(:any, 'supremegolf.com').to_return {|r|
7
+ { headers: {'Set-Cookie' => 'cookie123'} }
8
+ }
9
+ shb = Shb::Client.new
10
+ shb.config.use_cookies = false
11
+
12
+ expect(shb.get('/').request.options[:headers]['Cookie']).to be_nil
13
+ expect(shb.get('/').request.options[:headers]['Cookie']).to be_nil
14
+ end
15
+
16
+ it "uses cookies" do
17
+ stub_request(:any, 'supremegolf.com').to_return {|r|
18
+ { headers: {'Set-Cookie' => 'cookie123'} }
19
+ }
20
+ shb = Shb::Client.new
21
+ shb.config.use_cookies = true
22
+
23
+ expect(shb.get('/').request.options[:headers]['Cookie']).to be_nil
24
+ expect(shb.get('/').request.options[:headers]['Cookie']).to eq 'cookie123'
25
+ end
26
+
27
+ end
data/spec/xml_spec.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shb::Client do
4
+ before do
5
+ stub_request(:any, 'supremegolf.com').to_return {|r|
6
+ {
7
+ body: '<xml><title>Test</title></xml>',
8
+ headers: {'Content-Type' => 'text/xml'}
9
+ }
10
+ }
11
+ end
12
+ let(:shb) { Shb::Client.new }
13
+
14
+ specify { expect(shb.get('/').parsed_response).to be_a Nokogiri::XML::Document }
15
+ specify { expect(shb.get('/').parsed_response.at('title').text).to eq 'Test' }
16
+ end
17
+
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Philip Hallstrom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.13.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.13.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.6.3.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.3.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ''
112
+ email:
113
+ - philip@supremegolf.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - circle.yml
124
+ - lib/shb.rb
125
+ - lib/shb/abstract_client.rb
126
+ - lib/shb/cache.rb
127
+ - lib/shb/client.rb
128
+ - lib/shb/parser.rb
129
+ - lib/shb/version.rb
130
+ - shb.gemspec
131
+ - spec/cache_spec.rb
132
+ - spec/cycle_user_agent_spec.rb
133
+ - spec/html_spec.rb
134
+ - spec/json_spec.rb
135
+ - spec/logger_spec.rb
136
+ - spec/shb_spec.rb
137
+ - spec/spec_helper.rb
138
+ - spec/user_cookies_spec.rb
139
+ - spec/xml_spec.rb
140
+ homepage: https://github.com/supremegolf/shb
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.2.2
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: ''
164
+ test_files:
165
+ - spec/cache_spec.rb
166
+ - spec/cycle_user_agent_spec.rb
167
+ - spec/html_spec.rb
168
+ - spec/json_spec.rb
169
+ - spec/logger_spec.rb
170
+ - spec/shb_spec.rb
171
+ - spec/spec_helper.rb
172
+ - spec/user_cookies_spec.rb
173
+ - spec/xml_spec.rb