Vendor gems to make installing the plugins work properly.
The `gems:vendor` Rake task will properly pull everything needed into vendor/ruby
This commit is contained in:
parent
98fcdd5a07
commit
1c36a292c2
18
Gemfile
18
Gemfile
|
@ -1,10 +1,16 @@
|
|||
source :gemcutter
|
||||
source :rubygems
|
||||
|
||||
gem 'rake'
|
||||
gem 'heroku'
|
||||
gem 'sauce'
|
||||
gem 'launchy'
|
||||
gem 'httparty', :path => 'vendor/httparty'
|
||||
# This group is for vendoring changes for a "release"
|
||||
group :vendor do
|
||||
gem 'httparty'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'rake'
|
||||
gem 'heroku'
|
||||
gem 'sauce'
|
||||
gem 'launchy'
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'rspec'
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
source :rubygems
|
||||
|
||||
# This group is for vendoring changes for a "release"
|
||||
group :vendor do
|
||||
gem 'httparty'
|
||||
end
|
||||
|
||||
# vim: ft=ruby
|
|
@ -0,0 +1,14 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
httparty (0.9.0)
|
||||
multi_json (~> 1.0)
|
||||
multi_xml
|
||||
multi_json (1.4.0)
|
||||
multi_xml (0.5.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
httparty
|
22
Rakefile
22
Rakefile
|
@ -7,3 +7,25 @@ RSpec::Core::RakeTask.new('spec') do |t|
|
|||
end
|
||||
|
||||
Cucumber::Rake::Task.new('cucumber')
|
||||
|
||||
|
||||
BUNDLER_VARS = %w(BUNDLE_GEMFILE RUBYOPT GEM_HOME)
|
||||
def with_clean_env
|
||||
begin
|
||||
bundled_env = ENV.to_hash
|
||||
BUNDLER_VARS.each{ |var| ENV.delete(var) }
|
||||
yield
|
||||
ensure
|
||||
ENV.replace(bundled_env.to_hash)
|
||||
end
|
||||
end
|
||||
|
||||
namespace :gems do
|
||||
desc 'Vendor the gems in Gemfile.deploy'
|
||||
task :vendor do
|
||||
with_clean_env do
|
||||
sh 'bundle install --deployment --standalone=vendor --gemfile=Gemfile.deploy --path=vendor'
|
||||
sh 'bundle install --no-deployment'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
1
init.rb
1
init.rb
|
@ -1 +1,2 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/vendor/bundler/setup.rb')
|
||||
require 'sauce/heroku/cli'
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
require 'heroku'
|
||||
require 'heroku/command/base'
|
||||
require 'httparty'
|
||||
require 'sauce'
|
||||
require 'json'
|
||||
#require 'sauce'
|
||||
require 'yaml'
|
||||
|
||||
module Heroku
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
path = File.expand_path('..', __FILE__)
|
||||
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/multi_json-1.4.0/lib")
|
||||
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/multi_xml-0.5.1/lib")
|
||||
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/httparty-0.9.0/lib")
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# This file was generated by RubyGems.
|
||||
#
|
||||
# The application 'httparty' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require 'rubygems'
|
||||
|
||||
version = ">= 0"
|
||||
|
||||
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
|
||||
version = $1
|
||||
ARGV.shift
|
||||
end
|
||||
|
||||
gem 'httparty', version
|
||||
load Gem.bin_path('httparty', 'httparty', version)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,10 @@
|
|||
Gemfile.lock
|
||||
.DS_Store
|
||||
.yardoc/
|
||||
doc/
|
||||
tmp/
|
||||
log/
|
||||
pkg/
|
||||
*.swp
|
||||
/.bundle
|
||||
.rvmrc
|
|
@ -0,0 +1,8 @@
|
|||
language: ruby
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- ree
|
||||
- 1.9.3
|
||||
notifications:
|
||||
email: false
|
||||
bundler_args: --without development
|
|
@ -0,0 +1,15 @@
|
|||
source :rubygems
|
||||
gemspec
|
||||
|
||||
gem 'rake'
|
||||
gem 'cucumber', '~> 0.7'
|
||||
gem 'fakeweb', '~> 1.2'
|
||||
gem 'rspec', '~> 1.3'
|
||||
gem 'mongrel', '1.2.0.pre2'
|
||||
gem 'multi_json', '~> 1.3'
|
||||
|
||||
group :development do
|
||||
gem 'guard'
|
||||
gem 'guard-rspec'
|
||||
gem 'guard-bundler'
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
rspec_options = {
|
||||
:version => 1,
|
||||
:all_after_pass => false,
|
||||
:all_on_start => false,
|
||||
}
|
||||
|
||||
guard 'rspec', rspec_options do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
end
|
||||
|
||||
guard 'bundler' do
|
||||
watch('Gemfile')
|
||||
watch(/^.+\.gemspec/)
|
||||
end
|
|
@ -0,0 +1,293 @@
|
|||
== 0.9.0 2012-09-07
|
||||
* new
|
||||
* [support for connection adapters](https://github.com/jnunemaker/httparty/pull/157)
|
||||
* [allow ssl_version on ruby 1.9](https://github.com/jnunemaker/httparty/pull/159)
|
||||
|
||||
* bug fixes
|
||||
* [don't treat port 4430 as ssl](https://github.com/jnunemaker/httparty/commit/a296b1c97f83d7dcc6ef85720a43664c265685ac)
|
||||
* [deep clone default options](https://github.com/jnunemaker/httparty/commit/f74227d30f9389b4b23a888c9af49fb9b8248e1f)
|
||||
* a few net digest auth fixes
|
||||
|
||||
== 0.8.3 2012-04-21
|
||||
* new
|
||||
* [lazy parsing of responses](https://github.com/jnunemaker/httparty/commit/9fd5259c8dab00e426082b66af44ede2c9068f45)
|
||||
* [add support for PATCH requests](https://github.com/jnunemaker/httparty/commit/7ab6641e37a9e31517e46f6124f38c615395d38a)
|
||||
* bug fixes
|
||||
* [subclasses no longer override superclass options](https://github.com/jnunemaker/httparty/commit/682af8fbf672e7b3009e650da776c85cdfe78d39)
|
||||
|
||||
== 0.8.2 2012-04-12
|
||||
* new
|
||||
* add -r to make CLI return failure code if status >= 400
|
||||
* allow blank username from CLI
|
||||
* bug fixes
|
||||
* return nil for null body
|
||||
* automatically deflate responses with a Content-Encoding: x-gzip header
|
||||
* Do not HEAD on POST request with digest authentication
|
||||
* add support for proxy authentication
|
||||
* fix posting data with CLI
|
||||
* require rexml/document if xml format from CLI
|
||||
* support for fragmented responses
|
||||
|
||||
== 0.8.1 2011-10-05
|
||||
* bug fixes
|
||||
* content-encoding header should be removed when automatically inflating the body
|
||||
|
||||
== 0.8.0 2011-09-13
|
||||
* new
|
||||
* switch to multi json/xml for parsing by default
|
||||
* bug fixes
|
||||
* fix redirects to relative uri's
|
||||
|
||||
== 0.7.8 2011-06-06
|
||||
* bug fix
|
||||
* Make response honor respond to
|
||||
* net http timeout can also be a float
|
||||
|
||||
== 0.7.7 2011-04-16
|
||||
* bug fix
|
||||
* Fix NoMethodError when using the NON_RAILS_QUERY_STRING_NORMALIZER with a hash whose key is a symbol and value is nil
|
||||
|
||||
== 0.7.5 2011-04-16
|
||||
* bug fix
|
||||
* caused issue with latest rubygems
|
||||
|
||||
== 0.7.4 2011-02-13
|
||||
* bug fixes
|
||||
* Set VERIFY_NONE when using https. Ruby 1.9.2 no longer sets this for us. gh-67
|
||||
|
||||
== 0.7.3 2011-01-20
|
||||
* bug fixes
|
||||
* Fix digest auth for unspecified quality of protection (bjoernalbers, mtrudel, dwo)
|
||||
|
||||
== 0.7.2 2011-01-20
|
||||
* bug fixes
|
||||
* Fix gem dependencies
|
||||
|
||||
== 0.7.1 2011-01-19
|
||||
* bug fixes
|
||||
* Fix uninitialized constant HTTParty::Response::Net in 1.9.2 (cap10morgan)
|
||||
* Other fixes for 1.9.2, full suite still fails (cap10morgan)
|
||||
|
||||
== 0.7.0 2011-01-18
|
||||
* minor enhancements
|
||||
* Added query methods for HTTP status codes, i.e. response.success?
|
||||
response.created? (thanks citizenparker)
|
||||
* Added support for ssl_ca_file and ssl_ca_path (dlitz)
|
||||
* Allow custom query string normalization. gh-8
|
||||
* Unlock private keys with password (freerange)
|
||||
* Added high level request documentation (phildarnowsky)
|
||||
* Added basic post example (pbuckley)
|
||||
* Response object has access to its corresponding request object
|
||||
* Added example of siginin into tripit.com
|
||||
* Added option to follow redirects (rkj). gh-56
|
||||
* bug fixes
|
||||
* Fixed superclass mismatch exception while running tests
|
||||
(thanks dlitz http://github.com/dlitz/httparty/commit/48224f0615b32133afcff4718ad426df7a4b401b)
|
||||
|
||||
== 0.6.1 2010-07-07
|
||||
* minor enhancements
|
||||
* updated to crack 0.1.8
|
||||
* bug fixes
|
||||
* subclasses always merge into the parent's default_options and
|
||||
default_cookies (l4rk).
|
||||
* subclasses play nicely with grand parents. gh-49
|
||||
|
||||
== 0.6.0 2010-06-13
|
||||
* major enhancements
|
||||
* Digest Auth (bartiaco, sbecker, gilles, and aaronrussell)
|
||||
* Maintain HTTP method across redirects (bartiaco and sbecker)
|
||||
* HTTParty::Response#response returns the Net::HTTPResponse object
|
||||
* HTTParty::Response#headers returns a HTTParty::Response::Headers object
|
||||
which quacks like a Hash + Net::HTTPHeader. The #headers method continues
|
||||
to be backwards-compatible with the old Hash return value but may become
|
||||
deprecated in the future.
|
||||
|
||||
* minor enhancements
|
||||
* Update crack requirement to version 0.1.7
|
||||
You may still get a warning because Crack's version constant is out of date
|
||||
* Timeout option can be set for all requests using HTTParty.default_timeout (taazza)
|
||||
* Closed #38 "headers hash should downcase keys so canonical header name can be used"
|
||||
* Closed #40 "Gzip response" wherein gziped and deflated responses are
|
||||
automatically inflated. (carsonmcdonald)
|
||||
|
||||
== 0.5.2 2010-01-31
|
||||
* minor enhancements
|
||||
* Update crack requirement to version 0.1.6
|
||||
|
||||
== 0.5.1 2010-01-30
|
||||
* bug fixes
|
||||
* Handle 304 response correctly by returning the HTTParty::Response object instead of redirecting (seth and hellvinz)
|
||||
* Only redirect 300 responses if the header contains a Location
|
||||
* Don't append empty query strings to the uri. Closes #31
|
||||
* When no_follow is enabled, only raise the RedirectionTooDeep exception when a response tries redirecting. Closes #28
|
||||
|
||||
* major enhancements
|
||||
* Removed rubygems dependency. I suggest adding rubygems to RUBYOPT if this causes problems for you.
|
||||
$ export RUBYOPT='rubygems'
|
||||
* HTTParty#debug_output prints debugging information for the current request (iwarshak)
|
||||
* HTTParty#no_follow now available as a class-level option. Sets whether or not to follow redirects.
|
||||
|
||||
* minor enhancements
|
||||
* HTTParty::VERSION now available
|
||||
* Update crack requirement to version 0.1.5
|
||||
|
||||
== 0.5.0 2009-12-07
|
||||
* bug fixes
|
||||
* inheritable attributes no longer mutable by subclasses (yyyc514)
|
||||
* namespace BasicObject within HTTParty to avoid class name collisions (eric)
|
||||
|
||||
* major enhancements
|
||||
* Custom Parsers via class or proc
|
||||
* Deprecation warning on HTTParty::AllowedFormats
|
||||
moved to HTTParty::Parser::SupportedFormats
|
||||
|
||||
* minor enhancements
|
||||
* Curl inspired output when using the binary in verbose mode (alexvollmer)
|
||||
* raise UnsupportedURIScheme when scheme is not HTTP or HTTPS (djspinmonkey)
|
||||
* Allow SSL for ports other than 443 when scheme is HTTPS (stefankroes)
|
||||
* Accept PEM certificates via HTTParty#pem (chrislo)
|
||||
* Support HEAD and OPTION verbs (grempe)
|
||||
* Verify SSL certificates when providing a PEM file (collectiveidea/danielmorrison)
|
||||
|
||||
== 0.4.5 2009-09-12
|
||||
* bug fixes
|
||||
* Fixed class-level headers overwritten by cookie management code. Closes #19
|
||||
* Fixed "superclass mismatch for class BlankSlate" error. Closes #20
|
||||
* Fixed reading files as post data from the command line (vesan)
|
||||
|
||||
* minor enhancements
|
||||
* Timeout option added; will raise a Timeout::Error after the timeout has elapsed (attack). Closes #17
|
||||
HTTParty.get "http://github.com", :timeout => 1
|
||||
* Building gem with Jeweler
|
||||
|
||||
== 0.4.4 2009-07-19
|
||||
* 2 minor update
|
||||
* :query no longer sets form data. Use body and set content type to application/x-www-form-urlencoded if you need it. :query was wrong for that.
|
||||
* Fixed a bug in the cookies class method that caused cookies to be forgotten after the first request.
|
||||
* Also, some general cleanup of tests and such.
|
||||
|
||||
== 0.4.3 2009-04-23
|
||||
* 1 minor update
|
||||
* added message to the response object
|
||||
|
||||
== 0.4.2 2009-03-30
|
||||
* 2 minor changes
|
||||
* response code now returns an integer instead of a string (jqr)
|
||||
* rubyforge project setup for crack so i'm now depending on that instead of jnunemaker-crack
|
||||
|
||||
== 0.4.1 2009-03-29
|
||||
* 1 minor fix
|
||||
* gem 'jnunemaker-crack' instead of gem 'crack'
|
||||
|
||||
== 0.4.0 2009-03-29
|
||||
* 1 minor change
|
||||
* Switched xml and json parsing to crack (same code as before just moved to gem for easier reuse in other projects)
|
||||
|
||||
== 0.3.1 2009-02-10
|
||||
* 1 minor fix, 1 minor enhancement
|
||||
* Fixed unescaping umlauts (siebertm)
|
||||
* Added yaml response parsing (Miha Filej)
|
||||
|
||||
== 0.3.0 2009-01-31
|
||||
* 1 major enhancement, 1 bug fix
|
||||
* JSON gem no longer a requirement. It was conflicting with rails json stuff so I just stole ActiveSupport's json decoding and bundled it with HTTParty.
|
||||
* Fixed bug where query strings were being duplicated on redirects
|
||||
* Added a bunch of specs and moved some code around.
|
||||
|
||||
== 0.2.10 2009-01-29
|
||||
* 1 minor enhancement
|
||||
* Made encoding on query parameters treat everything except URI::PATTERN::UNRESERVED as UNSAFE to force encoding of '+' character (Julian Russell)
|
||||
|
||||
== 0.2.9 2009-01-29
|
||||
* 3 minor enhancements
|
||||
* Added a 'headers' accessor to the response with a hash of any HTTP headers. (Don Peterson)
|
||||
* Add support for a ":cookies" option to be used at the class level, or as an option on any individual call. It should be passed a hash, which will be converted to the proper format and added to the request headers when the call is made. (Don Peterson)
|
||||
* Refactored several specs and added a full suite of cucumber features (Don Peterson)
|
||||
|
||||
== 0.2.8 2009-01-28
|
||||
* 1 major fix
|
||||
* fixed major bug with response where it wouldn't iterate or really work at all with parsed responses
|
||||
|
||||
== 0.2.7 2009-01-28
|
||||
* 2 minor fixes, 2 minor enhancements, 2 major enhancements
|
||||
* fixed undefined method add_node for nil class error that occasionally happened (juliocesar)
|
||||
* Handle nil or unexpected values better when typecasting. (Brian Landau)
|
||||
* More robust handling of mime types (Alex Vollmer)
|
||||
* Fixed support for specifying headers and added support for basic auth to CLI. (Alex Vollmer)
|
||||
* Added first class response object that includes original body and status code (Alex Vollmer)
|
||||
* Now parsing all response types as some non-200 responses provide important information, this means no more exception raising (Alex Vollmer)
|
||||
|
||||
== 0.2.6 2009-01-05
|
||||
* 1 minor bug fix
|
||||
* added explicit require of time as Time#parse failed outside of rails (willcodeforfoo)
|
||||
|
||||
== 0.2.5 2009-01-05
|
||||
* 1 major enhancement
|
||||
* Add command line interface to HTTParty (Alex Vollmer)
|
||||
|
||||
== 0.2.4 2008-12-23
|
||||
* 1 bug fix
|
||||
* Fixed that mimetype detection was failing if no mimetype was returned from service (skippy)
|
||||
== 0.2.3 2008-12-23
|
||||
* 1 bug fix
|
||||
* Fixed typecasting class variable naming issue
|
||||
|
||||
== 0.2.2 2008-12-08
|
||||
* 1 bug fix
|
||||
* Added the missing core extension hash method to_xml_attributes
|
||||
|
||||
== 0.2.1 2008-12-08
|
||||
* 1 bug fix
|
||||
* Fixed that HTTParty was borking ActiveSupport and as such Rails (thanks to Rob Sanheim)
|
||||
|
||||
== 0.2.0 2008-12-07
|
||||
* 1 major enhancement
|
||||
* Removed ActiveSupport as a dependency. Now requires json gem for json deserialization and uses an included class to do the xml parsing.
|
||||
|
||||
== 0.1.8 2008-11-30
|
||||
* 3 major enhancements
|
||||
* Moved base_uri normalization into request class and out of httparty module, fixing
|
||||
the problem where base_uri was not always being normalized.
|
||||
* Stupid simple support for HTTParty.get/post/put/delete. (jqr)
|
||||
* Switched gem management to Echoe from newgem.
|
||||
|
||||
== 0.1.7 2008-11-30
|
||||
* 1 major enhancement
|
||||
* fixed multiple class definitions overriding each others options
|
||||
|
||||
== 0.1.6 2008-11-26
|
||||
* 1 major enhancement
|
||||
* now passing :query to set_form_data if post request to avoid content length errors
|
||||
|
||||
== 0.1.5 2008-11-14
|
||||
* 2 major enhancements
|
||||
* Refactored send request method out into its own object.
|
||||
* Added :html format if you just want to do that.
|
||||
|
||||
== 0.1.4 2008-11-08
|
||||
* 3 major enhancements:
|
||||
* Removed some cruft
|
||||
* Added ability to follow redirects automatically and turn that off (Alex Vollmer)
|
||||
|
||||
== 0.1.3 2008-08-22
|
||||
|
||||
* 3 major enhancements:
|
||||
* Added http_proxy key for setting proxy server and port (francxk@gmail.com)
|
||||
* Now raises exception when http error occurs (francxk@gmail.com)
|
||||
* Changed auto format detection from file extension to response content type (Jay Pignata)
|
||||
|
||||
== 0.1.2 2008-08-09
|
||||
|
||||
* 1 major enhancement:
|
||||
* default_params were not being appended to query string if option[:query] was blank
|
||||
|
||||
== 0.1.1 2008-07-30
|
||||
|
||||
* 2 major enhancement:
|
||||
* Added :basic_auth key for options when making a request
|
||||
* :query and :body both now work with query string or hash
|
||||
|
||||
== 0.1.0 2008-07-27
|
||||
|
||||
* 1 major enhancement:
|
||||
* Initial release
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2008 John Nunemaker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,79 @@
|
|||
# httparty
|
||||
|
||||
Makes http fun again!
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
gem install httparty
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
* multi_json and multi_xml
|
||||
* You like to party!
|
||||
|
||||
## Examples
|
||||
|
||||
```ruby
|
||||
# Use the class methods to get down to business quickly
|
||||
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
|
||||
puts response.body, response.code, response.message, response.headers.inspect
|
||||
|
||||
response.each do |item|
|
||||
puts item['user']['screen_name']
|
||||
end
|
||||
|
||||
# Or wrap things up in your own class
|
||||
class Twitter
|
||||
include HTTParty
|
||||
base_uri 'twitter.com'
|
||||
|
||||
def initialize(u, p)
|
||||
@auth = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
# which can be :friends, :user or :public
|
||||
# options[:query] can be things like since, since_id, count, etc.
|
||||
def timeline(which=:friends, options={})
|
||||
options.merge!({:basic_auth => @auth})
|
||||
self.class.get("/statuses/#{which}_timeline.json", options)
|
||||
end
|
||||
|
||||
def post(text)
|
||||
options = { :body => {:status => text}, :basic_auth => @auth }
|
||||
self.class.post('/statuses/update.json', options)
|
||||
end
|
||||
end
|
||||
|
||||
twitter = Twitter.new(config['email'], config['password'])
|
||||
pp twitter.timeline
|
||||
```
|
||||
|
||||
See the [examples directory](http://github.com/jnunemaker/httparty/tree/master/examples) for even more goodies.
|
||||
|
||||
## Command Line Interface
|
||||
|
||||
httparty also includes the executable `httparty` which can be
|
||||
used to query web services and examine the resulting output. By default
|
||||
it will output the response as a pretty-printed Ruby object (useful for
|
||||
grokking the structure of output). This can also be overridden to output
|
||||
formatted XML or JSON. Execute `httparty --help` for all the
|
||||
options. Below is an example of how easy it is.
|
||||
|
||||
```
|
||||
httparty "http://twitter.com/statuses/public_timeline.json"
|
||||
```
|
||||
|
||||
## Help and Docs
|
||||
|
||||
* https://groups.google.com/forum/#!forum/httparty-gem
|
||||
* http://rdoc.info/projects/jnunemaker/httparty
|
||||
|
||||
## Contributing
|
||||
|
||||
* Fork the project.
|
||||
* Make your feature addition or bug fix.
|
||||
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
||||
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
|
||||
* Send me a pull request. Bonus points for topic branches.
|
|
@ -0,0 +1,15 @@
|
|||
require 'bundler'
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'spec/rake/spectask'
|
||||
Spec::Rake::SpecTask.new(:spec) do |spec|
|
||||
spec.ruby_opts << '-rubygems'
|
||||
spec.libs << 'lib' << 'spec'
|
||||
spec.spec_files = FileList['spec/**/*_spec.rb']
|
||||
spec.spec_opts = ['--options', 'spec/spec.opts']
|
||||
end
|
||||
|
||||
require 'cucumber/rake/task'
|
||||
Cucumber::Rake::Task.new(:features)
|
||||
|
||||
task :default => [:spec, :features]
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require "optparse"
|
||||
require "pp"
|
||||
|
||||
$:.unshift(File.join(File.dirname(__FILE__), "/../lib"))
|
||||
require "httparty"
|
||||
|
||||
opts = {
|
||||
:action => :get,
|
||||
:headers => {},
|
||||
:verbose => false
|
||||
}
|
||||
|
||||
OptionParser.new do |o|
|
||||
o.banner = "USAGE: #{$0} [options] [url]"
|
||||
|
||||
o.on("-f",
|
||||
"--format [FORMAT]",
|
||||
"Output format to use instead of pretty-print ruby: " +
|
||||
"plain, json or xml") do |f|
|
||||
opts[:output_format] = f.downcase.to_sym
|
||||
end
|
||||
|
||||
o.on("-a",
|
||||
"--action [ACTION]",
|
||||
"HTTP action: get (default), post, put, delete, head, or options") do |a|
|
||||
opts[:action] = a.downcase.to_sym
|
||||
end
|
||||
|
||||
o.on("-d",
|
||||
"--data [BODY]",
|
||||
"Data to put in request body (prefix with '@' for file)") do |d|
|
||||
if d =~ /^@/
|
||||
opts[:body] = open(d[1..-1]).read
|
||||
else
|
||||
opts[:body] = d
|
||||
end
|
||||
end
|
||||
|
||||
o.on("-H", "--header [NAME:VALUE]", "Additional HTTP headers in NAME:VALUE form") do |h|
|
||||
abort "Invalid header specification, should be Name:Value" unless h =~ /.+:.+/
|
||||
name, value = h.split(':')
|
||||
opts[:headers][name.strip] = value.strip
|
||||
end
|
||||
|
||||
o.on("-v", "--verbose", "If set, print verbose output") do |v|
|
||||
opts[:verbose] = true
|
||||
end
|
||||
|
||||
o.on("-u", "--user [CREDS]", "Use basic authentication. Value should be user:password") do |u|
|
||||
abort "Invalid credentials format. Must be user:password" unless u =~ /.*:.+/
|
||||
user, password = u.split(':')
|
||||
opts[:basic_auth] = { :username => user, :password => password }
|
||||
end
|
||||
|
||||
o.on("-r", "--response-code", "Command fails if response code >= 400") do
|
||||
opts[:response_code] = true
|
||||
end
|
||||
|
||||
o.on("-h", "--help", "Show help documentation") do |h|
|
||||
puts o
|
||||
exit
|
||||
end
|
||||
end.parse!
|
||||
|
||||
|
||||
if ARGV.empty?
|
||||
STDERR.puts "You need to provide a URL"
|
||||
STDERR.puts "USAGE: #{$0} [options] [url]"
|
||||
end
|
||||
|
||||
def dump_headers(response)
|
||||
resp_type = Net::HTTPResponse::CODE_TO_OBJ[response.code.to_s]
|
||||
puts "#{response.code} #{resp_type.to_s.sub(/^Net::HTTP/, '')}"
|
||||
response.headers.each do |n,v|
|
||||
puts "#{n}: #{v}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
if opts[:verbose]
|
||||
puts "#{opts[:action].to_s.upcase} #{ARGV.first}"
|
||||
opts[:headers].each do |n,v|
|
||||
puts "#{n}: #{v}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
response = HTTParty.send(opts[:action], ARGV.first, opts)
|
||||
if opts[:output_format].nil?
|
||||
dump_headers(response) if opts[:verbose]
|
||||
pp response
|
||||
else
|
||||
print_format = opts[:output_format]
|
||||
dump_headers(response) if opts[:verbose]
|
||||
|
||||
case opts[:output_format]
|
||||
when :json
|
||||
begin
|
||||
require 'json'
|
||||
puts JSON.pretty_generate(response.delegate)
|
||||
rescue LoadError
|
||||
puts YAML.dump(response.delegate)
|
||||
end
|
||||
when :xml
|
||||
require 'rexml/document'
|
||||
REXML::Document.new(response.body).write(STDOUT, 2)
|
||||
puts
|
||||
else
|
||||
puts response
|
||||
end
|
||||
end
|
||||
exit false if opts[:response_code] && response.code >= 400
|
|
@ -0,0 +1 @@
|
|||
default: features --format progress
|
|
@ -0,0 +1,32 @@
|
|||
require 'rubygems'
|
||||
require 'active_support'
|
||||
|
||||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
config = YAML::load(File.read(File.join(ENV['HOME'], '.aaws')))
|
||||
|
||||
module AAWS
|
||||
class Book
|
||||
include HTTParty
|
||||
base_uri 'http://ecs.amazonaws.com'
|
||||
default_params :Service => 'AWSECommerceService', :Operation => 'ItemSearch', :SearchIndex => 'Books'
|
||||
|
||||
def initialize(key)
|
||||
self.class.default_params :AWSAccessKeyId => key
|
||||
end
|
||||
|
||||
def search(options={})
|
||||
raise ArgumentError, 'You must search for something' if options[:query].blank?
|
||||
|
||||
# amazon uses nasty camelized query params
|
||||
options[:query] = options[:query].inject({}) { |h, q| h[q[0].to_s.camelize] = q[1]; h }
|
||||
|
||||
# make a request and return the items (NOTE: this doesn't handle errors at this point)
|
||||
self.class.get('/onca/xml', options)['ItemSearchResponse']['Items']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
aaws = AAWS::Book.new(config[:access_key])
|
||||
pp aaws.search(:query => {:title => 'Ruby On Rails'})
|
|
@ -0,0 +1,32 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
# You can also use post, put, delete, head, options in the same fashion
|
||||
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
|
||||
puts response.body, response.code, response.message, response.headers.inspect
|
||||
|
||||
response.each do |item|
|
||||
puts item['user']['screen_name']
|
||||
end
|
||||
|
||||
# An example post to a minimal rails app in the development environment
|
||||
# Note that "skip_before_filter :verify_authenticity_token" must be set in the
|
||||
# "pears" controller for this example
|
||||
|
||||
class Partay
|
||||
include HTTParty
|
||||
base_uri 'http://localhost:3000'
|
||||
end
|
||||
|
||||
options = {
|
||||
:body => {
|
||||
:pear => { # your resource
|
||||
:foo => '123', # your columns/data
|
||||
:bar => 'second',
|
||||
:baz => 'last thing'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pp Partay.post('/pears.xml', options)
|
|
@ -0,0 +1,19 @@
|
|||
require 'rubygems'
|
||||
require 'crack'
|
||||
|
||||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
class Rep
|
||||
include HTTParty
|
||||
|
||||
parser(
|
||||
Proc.new do |body, format|
|
||||
Crack::XML.parse(body)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php?zip=46544')
|
||||
pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php', :query => {:zip => 46544})
|
|
@ -0,0 +1,67 @@
|
|||
class ParseAtom
|
||||
include HTTParty
|
||||
|
||||
# Support Atom along with the default parsers: xml, json, yaml, etc.
|
||||
class Parser::Atom < HTTParty::Parser
|
||||
SupportedFormats.merge!({"application/atom+xml" => :atom})
|
||||
|
||||
protected
|
||||
|
||||
# perform atom parsing on body
|
||||
def atom
|
||||
body.to_atom
|
||||
end
|
||||
end
|
||||
|
||||
parser Parser::Atom
|
||||
end
|
||||
|
||||
|
||||
class OnlyParseAtom
|
||||
include HTTParty
|
||||
|
||||
# Only support Atom
|
||||
class Parser::OnlyAtom < HTTParty::Parser
|
||||
SupportedFormats = {"application/atom+xml" => :atom}
|
||||
|
||||
protected
|
||||
|
||||
# perform atom parsing on body
|
||||
def atom
|
||||
body.to_atom
|
||||
end
|
||||
end
|
||||
|
||||
parser Parser::OnlyAtom
|
||||
end
|
||||
|
||||
|
||||
class SkipParsing
|
||||
include HTTParty
|
||||
|
||||
# Parse the response body however you like
|
||||
class Parser::Simple < HTTParty::Parser
|
||||
def parse
|
||||
body
|
||||
end
|
||||
end
|
||||
|
||||
parser Parser::Simple
|
||||
end
|
||||
|
||||
|
||||
class AdHocParsing
|
||||
include HTTParty
|
||||
parser(
|
||||
Proc.new do |body, format|
|
||||
case format
|
||||
when :json
|
||||
body.to_json
|
||||
when :xml
|
||||
body.to_xml
|
||||
else
|
||||
body
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
config = YAML::load(File.read(File.join(ENV['HOME'], '.delicious')))
|
||||
|
||||
class Delicious
|
||||
include HTTParty
|
||||
base_uri 'https://api.del.icio.us/v1'
|
||||
|
||||
def initialize(u, p)
|
||||
@auth = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
# query params that filter the posts are:
|
||||
# tag (optional). Filter by this tag.
|
||||
# dt (optional). Filter by this date (CCYY-MM-DDThh:mm:ssZ).
|
||||
# url (optional). Filter by this url.
|
||||
# ie: posts(:query => {:tag => 'ruby'})
|
||||
def posts(options={})
|
||||
options.merge!({:basic_auth => @auth})
|
||||
self.class.get('/posts/get', options)
|
||||
end
|
||||
|
||||
# query params that filter the posts are:
|
||||
# tag (optional). Filter by this tag.
|
||||
# count (optional). Number of items to retrieve (Default:15, Maximum:100).
|
||||
def recent(options={})
|
||||
options.merge!({:basic_auth => @auth})
|
||||
self.class.get('/posts/recent', options)
|
||||
end
|
||||
end
|
||||
|
||||
delicious = Delicious.new(config['username'], config['password'])
|
||||
pp delicious.posts(:query => {:tag => 'ruby'})
|
||||
pp delicious.recent
|
||||
|
||||
delicious.recent['posts']['post'].each { |post| puts post['href'] }
|
|
@ -0,0 +1,16 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
class Google
|
||||
include HTTParty
|
||||
format :html
|
||||
end
|
||||
|
||||
# google.com redirects to www.google.com so this is live test for redirection
|
||||
pp Google.get('http://google.com')
|
||||
|
||||
puts '', '*'*70, ''
|
||||
|
||||
# check that ssl is requesting right
|
||||
pp Google.get('https://www.google.com')
|
|
@ -0,0 +1,6 @@
|
|||
# To send custom user agents to identify your application to a web service (or mask as a specific browser for testing), send "User-Agent" as a hash to headers as shown below.
|
||||
|
||||
require 'httparty'
|
||||
|
||||
APPLICATION_NAME = "Httparty"
|
||||
response = HTTParty.get('http://example.com', :headers => {"User-Agent" => APPLICATION_NAME})
|
|
@ -0,0 +1,22 @@
|
|||
require 'rubygems'
|
||||
require 'nokogiri'
|
||||
|
||||
|
||||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
class HtmlParserIncluded < HTTParty::Parser
|
||||
SupportedFormats.merge!('text/html' => :html)
|
||||
|
||||
def html
|
||||
Nokogiri::HTML(body)
|
||||
end
|
||||
end
|
||||
|
||||
class Page
|
||||
include HTTParty
|
||||
parser HtmlParserIncluded
|
||||
end
|
||||
|
||||
pp Page.get('http://www.google.com')
|
|
@ -0,0 +1,14 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
class Rubyurl
|
||||
include HTTParty
|
||||
base_uri 'rubyurl.com'
|
||||
|
||||
def self.shorten( website_url )
|
||||
post( '/api/links.json', :query => { :link => { :website_url => website_url } } )
|
||||
end
|
||||
end
|
||||
|
||||
pp Rubyurl.shorten( 'http://istwitterdown.com/')
|
|
@ -0,0 +1,33 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
|
||||
class TripIt
|
||||
include HTTParty
|
||||
base_uri 'http://www.tripit.com'
|
||||
debug_output
|
||||
|
||||
def initialize(email, password)
|
||||
@email = email
|
||||
response = self.class.get('/account/login')
|
||||
response = self.class.post(
|
||||
'/account/login',
|
||||
:body => {
|
||||
:login_email_address => email,
|
||||
:login_password => password
|
||||
},
|
||||
:headers => {'Cookie' => response.headers['Set-Cookie']}
|
||||
)
|
||||
@cookie = response.request.options[:headers]['Cookie']
|
||||
end
|
||||
|
||||
def account_settings
|
||||
self.class.get('/account/edit', :headers => {'Cookie' => @cookie})
|
||||
end
|
||||
|
||||
def logged_in?
|
||||
account_settings.include? "You're logged in as #{@email}"
|
||||
end
|
||||
end
|
||||
|
||||
tripit = TripIt.new('email', 'password')
|
||||
puts "Logged in: #{tripit.logged_in?}"
|
|
@ -0,0 +1,31 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
config = YAML::load(File.read(File.join(ENV['HOME'], '.twitter')))
|
||||
|
||||
class Twitter
|
||||
include HTTParty
|
||||
base_uri 'twitter.com'
|
||||
|
||||
def initialize(u, p)
|
||||
@auth = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
# which can be :friends, :user or :public
|
||||
# options[:query] can be things like since, since_id, count, etc.
|
||||
def timeline(which=:friends, options={})
|
||||
options.merge!({:basic_auth => @auth})
|
||||
self.class.get("/statuses/#{which}_timeline.json", options)
|
||||
end
|
||||
|
||||
def post(text)
|
||||
options = { :query => {:status => text}, :basic_auth => @auth }
|
||||
self.class.post('/statuses/update.json', options)
|
||||
end
|
||||
end
|
||||
|
||||
twitter = Twitter.new(config['email'], config['password'])
|
||||
pp twitter.timeline
|
||||
# pp twitter.timeline(:friends, :query => {:since_id => 868482746})
|
||||
# pp twitter.timeline(:friends, :query => 'since_id=868482746')
|
||||
# pp twitter.post('this is a test of 0.2.0')
|
|
@ -0,0 +1,10 @@
|
|||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
require File.join(dir, 'httparty')
|
||||
require 'pp'
|
||||
|
||||
class Rep
|
||||
include HTTParty
|
||||
end
|
||||
|
||||
pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php?zip=46544')
|
||||
pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php', :query => {:zip => 46544})
|
|
@ -0,0 +1,20 @@
|
|||
Feature: Basic Authentication
|
||||
|
||||
As a developer
|
||||
I want to be able to use a service that requires Basic Authentication
|
||||
Because that is not an uncommon requirement
|
||||
|
||||
Scenario: Passing no credentials to a page requiring Basic Authentication
|
||||
Given a restricted page at '/basic_auth.html'
|
||||
When I call HTTParty#get with '/basic_auth.html'
|
||||
Then it should return a response with a 401 response code
|
||||
|
||||
Scenario: Passing proper credentials to a page requiring Basic Authentication
|
||||
Given a remote service that returns 'Authenticated Page'
|
||||
And that service is accessed at the path '/basic_auth.html'
|
||||
And that service is protected by Basic Authentication
|
||||
And that service requires the username 'jcash' with the password 'maninblack'
|
||||
When I call HTTParty#get with '/basic_auth.html' and a basic_auth hash:
|
||||
| username | password |
|
||||
| jcash | maninblack |
|
||||
Then the return value should match 'Authenticated Page'
|
|
@ -0,0 +1,7 @@
|
|||
Feature: Command Line
|
||||
|
||||
As a developer
|
||||
I want to be able to harness the power of HTTParty from the command line
|
||||
Because that would make quick testing and debugging easy
|
||||
And 'easy' is my middle name
|
||||
And I'm kidding it's actually 'Danger'!
|
26
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/deals_with_http_error_codes.feature
vendored
Normal file
26
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/deals_with_http_error_codes.feature
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
Feature: Deals with HTTP error codes
|
||||
|
||||
As a developer
|
||||
I want to be informed of non-successful responses
|
||||
Because sometimes thing explode
|
||||
And I should probably know what happened
|
||||
|
||||
Scenario: A response of '404 - Not Found'
|
||||
Given a remote service that returns a 404 status code
|
||||
And that service is accessed at the path '/404_service.html'
|
||||
When I call HTTParty#get with '/404_service.html'
|
||||
Then it should return a response with a 404 response code
|
||||
|
||||
Scenario: A response of '500 - Internal Server Error'
|
||||
Given a remote service that returns a 500 status code
|
||||
And that service is accessed at the path '/500_service.html'
|
||||
When I call HTTParty#get with '/500_service.html'
|
||||
Then it should return a response with a 500 response code
|
||||
|
||||
Scenario: A non-successful response where I need the body
|
||||
Given a remote service that returns a 400 status code
|
||||
And the response from the service has a body of 'Bad response'
|
||||
And that service is accessed at the path '/400_service.html'
|
||||
When I call HTTParty#get with '/400_service.html'
|
||||
Then it should return a response with a 400 response code
|
||||
And the return value should match 'Bad response'
|
20
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/digest_authentication.feature
vendored
Normal file
20
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/digest_authentication.feature
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
Feature: Digest Authentication
|
||||
|
||||
As a developer
|
||||
I want to be able to use a service that requires Digest Authentication
|
||||
Because that is not an uncommon requirement
|
||||
|
||||
Scenario: Passing no credentials to a page requiring Digest Authentication
|
||||
Given a restricted page at '/digest_auth.html'
|
||||
When I call HTTParty#get with '/digest_auth.html'
|
||||
Then it should return a response with a 401 response code
|
||||
|
||||
Scenario: Passing proper credentials to a page requiring Digest Authentication
|
||||
Given a remote service that returns 'Digest Authenticated Page'
|
||||
And that service is accessed at the path '/digest_auth.html'
|
||||
And that service is protected by Digest Authentication
|
||||
And that service requires the username 'jcash' with the password 'maninblack'
|
||||
When I call HTTParty#get with '/digest_auth.html' and a digest_auth hash:
|
||||
| username | password |
|
||||
| jcash | maninblack |
|
||||
Then the return value should match 'Digest Authenticated Page'
|
19
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/handles_compressed_responses.feature
vendored
Normal file
19
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/handles_compressed_responses.feature
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Feature: Handles Compressed Responses
|
||||
|
||||
In order to save bandwidth
|
||||
As a developer
|
||||
I want to uncompress compressed responses
|
||||
|
||||
Scenario: Supports deflate encoding
|
||||
Given a remote deflate service
|
||||
And the response from the service has a body of '<h1>Some HTML</h1>'
|
||||
And that service is accessed at the path '/deflate_service.html'
|
||||
When I call HTTParty#get with '/deflate_service.html'
|
||||
Then the return value should match '<h1>Some HTML</h1>'
|
||||
|
||||
Scenario: Supports gzip encoding
|
||||
Given a remote gzip service
|
||||
And the response from the service has a body of '<h1>Some HTML</h1>'
|
||||
And that service is accessed at the path '/gzip_service.html'
|
||||
When I call HTTParty#get with '/gzip_service.html'
|
||||
Then the return value should match '<h1>Some HTML</h1>'
|
34
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/handles_multiple_formats.feature
vendored
Normal file
34
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/handles_multiple_formats.feature
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
Feature: Handles Multiple Formats
|
||||
|
||||
As a developer
|
||||
I want to be able to consume remote services of many different formats
|
||||
And I want those formats to be automatically detected and handled
|
||||
Because web services take many forms
|
||||
And I don't want to have to do any extra work
|
||||
|
||||
Scenario: An HTML service
|
||||
Given a remote service that returns '<h1>Some HTML</h1>'
|
||||
And that service is accessed at the path '/html_service.html'
|
||||
And the response from the service has a Content-Type of 'text/html'
|
||||
When I call HTTParty#get with '/html_service.html'
|
||||
Then it should return a String
|
||||
And the return value should match '<h1>Some HTML</h1>'
|
||||
|
||||
Scenario: A JSON service
|
||||
Given a remote service that returns '{ "jennings": "waylon", "cash": "johnny" }'
|
||||
And that service is accessed at the path '/service.json'
|
||||
And the response from the service has a Content-Type of 'application/json'
|
||||
When I call HTTParty#get with '/service.json'
|
||||
Then it should return a Hash equaling:
|
||||
| key | value |
|
||||
| jennings | waylon |
|
||||
| cash | johnny |
|
||||
|
||||
Scenario: An XML Service
|
||||
Given a remote service that returns '<singer>waylon jennings</singer>'
|
||||
And that service is accessed at the path '/service.xml'
|
||||
And the response from the service has a Content-Type of 'text/xml'
|
||||
When I call HTTParty#get with '/service.xml'
|
||||
Then it should return a Hash equaling:
|
||||
| key | value |
|
||||
| singer | waylon jennings |
|
|
@ -0,0 +1,22 @@
|
|||
require 'mongrel'
|
||||
require './lib/httparty'
|
||||
require 'spec/expectations'
|
||||
|
||||
Before do
|
||||
def new_port
|
||||
server = TCPServer.new('0.0.0.0', nil)
|
||||
port = server.addr[1]
|
||||
ensure
|
||||
server.close
|
||||
end
|
||||
|
||||
port = ENV["HTTPARTY_PORT"] || new_port
|
||||
@host_and_port = "0.0.0.0:#{port}"
|
||||
@server = Mongrel::HttpServer.new("0.0.0.0", port)
|
||||
@server.run
|
||||
@request_options = {}
|
||||
end
|
||||
|
||||
After do
|
||||
@server.stop
|
||||
end
|
26
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/steps/httparty_response_steps.rb
vendored
Normal file
26
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/steps/httparty_response_steps.rb
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
Then /it should return an? (\w+)$/ do |class_string|
|
||||
@response_from_httparty.should be_an_instance_of(class_string.class)
|
||||
end
|
||||
|
||||
Then /the return value should match '(.*)'/ do |expected_text|
|
||||
@response_from_httparty.should eql(expected_text)
|
||||
end
|
||||
|
||||
Then /it should return a Hash equaling:/ do |hash_table|
|
||||
@response_from_httparty.should be_an_instance_of(Hash)
|
||||
@response_from_httparty.keys.length.should eql(hash_table.rows.length)
|
||||
hash_table.hashes.each do |pair|
|
||||
key, value = pair["key"], pair["value"]
|
||||
@response_from_httparty.keys.should include(key)
|
||||
@response_from_httparty[key].should eql(value)
|
||||
end
|
||||
end
|
||||
|
||||
Then /it should return a response with a (\d+) response code/ do |code|
|
||||
@response_from_httparty.code.should eql(code.to_i)
|
||||
end
|
||||
|
||||
Then /it should raise (?:an|a) ([\w:]+) exception/ do |exception|
|
||||
@exception_from_httparty.should_not be_nil
|
||||
@exception_from_httparty.class.name.should eql(exception)
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
When /^I set my HTTParty timeout option to (\d+)$/ do |timeout|
|
||||
@request_options[:timeout] = timeout.to_i
|
||||
end
|
||||
|
||||
When /I call HTTParty#get with '(.*)'$/ do |url|
|
||||
begin
|
||||
@response_from_httparty = HTTParty.get("http://#{@host_and_port}#{url}", @request_options)
|
||||
rescue HTTParty::RedirectionTooDeep, Timeout::Error => e
|
||||
@exception_from_httparty = e
|
||||
end
|
||||
end
|
||||
|
||||
When /I call HTTParty#get with '(.*)' and a basic_auth hash:/ do |url, auth_table|
|
||||
h = auth_table.hashes.first
|
||||
@response_from_httparty = HTTParty.get(
|
||||
"http://#{@host_and_port}#{url}",
|
||||
:basic_auth => { :username => h["username"], :password => h["password"] }
|
||||
)
|
||||
end
|
||||
|
||||
When /I call HTTParty#get with '(.*)' and a digest_auth hash:/ do |url, auth_table|
|
||||
h = auth_table.hashes.first
|
||||
@response_from_httparty = HTTParty.get(
|
||||
"http://#{@host_and_port}#{url}",
|
||||
:digest_auth => { :username => h["username"], :password => h["password"] }
|
||||
)
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
require 'base64'
|
||||
class BasicMongrelHandler < Mongrel::HttpHandler
|
||||
attr_accessor :content_type, :custom_headers, :response_body, :response_code, :preprocessor, :username, :password
|
||||
|
||||
def initialize
|
||||
@content_type = "text/html"
|
||||
@response_body = ""
|
||||
@response_code = 200
|
||||
@custom_headers = {}
|
||||
end
|
||||
|
||||
def process(request, response)
|
||||
instance_eval &preprocessor if preprocessor
|
||||
reply_with(response, response_code, response_body)
|
||||
end
|
||||
|
||||
def reply_with(response, code, response_body)
|
||||
response.start(code) do |head, body|
|
||||
head["Content-Type"] = content_type
|
||||
custom_headers.each { |k,v| head[k] = v }
|
||||
body.write(response_body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DeflateHandler < BasicMongrelHandler
|
||||
def process(request, response)
|
||||
response.start do |head, body|
|
||||
head['Content-Encoding'] = 'deflate'
|
||||
body.write Zlib::Deflate.deflate(response_body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class GzipHandler < BasicMongrelHandler
|
||||
def process(request, response)
|
||||
response.start do |head, body|
|
||||
head['Content-Encoding'] = 'gzip'
|
||||
body.write gzip(response_body)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def gzip(string)
|
||||
sio = StringIO.new('', 'r+')
|
||||
gz = Zlib::GzipWriter.new sio
|
||||
gz.write string
|
||||
gz.finish
|
||||
sio.rewind
|
||||
sio.read
|
||||
end
|
||||
end
|
||||
|
||||
module BasicAuthentication
|
||||
def self.extended(base)
|
||||
base.custom_headers["WWW-Authenticate"] = 'Basic Realm="Super Secret Page"'
|
||||
end
|
||||
|
||||
def process(request, response)
|
||||
if authorized?(request)
|
||||
super
|
||||
else
|
||||
reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
|
||||
end
|
||||
end
|
||||
|
||||
def authorized?(request)
|
||||
request.params["HTTP_AUTHORIZATION"] == "Basic " + Base64.encode64("#{@username}:#{@password}").strip
|
||||
end
|
||||
end
|
||||
|
||||
module DigestAuthentication
|
||||
def self.extended(base)
|
||||
base.custom_headers["WWW-Authenticate"] = 'Digest realm="testrealm@host.com",qop="auth,auth-int",nonce="nonce",opaque="opaque"'
|
||||
end
|
||||
|
||||
def process(request, response)
|
||||
if authorized?(request)
|
||||
super
|
||||
else
|
||||
reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
|
||||
end
|
||||
end
|
||||
|
||||
def authorized?(request)
|
||||
request.params["HTTP_AUTHORIZATION"] =~ /Digest.*uri=/
|
||||
end
|
||||
end
|
||||
|
||||
def new_mongrel_redirector(target_url, relative_path = false)
|
||||
target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
|
||||
Mongrel::RedirectHandler.new(target_url)
|
||||
end
|
69
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/steps/remote_service_steps.rb
vendored
Normal file
69
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/steps/remote_service_steps.rb
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
Given /a remote service that returns '(.*)'/ do |response_body|
|
||||
@handler = BasicMongrelHandler.new
|
||||
Given "the response from the service has a body of '#{response_body}'"
|
||||
end
|
||||
|
||||
Given /a remote service that returns a (\d+) status code/ do |code|
|
||||
@handler = BasicMongrelHandler.new
|
||||
@handler.response_code = code
|
||||
end
|
||||
|
||||
Given /that service is accessed at the path '(.*)'/ do |path|
|
||||
@server.register(path, @handler)
|
||||
end
|
||||
|
||||
Given /^that service takes (\d+) seconds to generate a response$/ do |time|
|
||||
@server_response_time = time.to_i
|
||||
@handler.preprocessor = Proc.new { sleep time.to_i }
|
||||
end
|
||||
|
||||
Given /^a remote deflate service$/ do
|
||||
@handler = DeflateHandler.new
|
||||
end
|
||||
|
||||
Given /^a remote gzip service$/ do
|
||||
@handler = GzipHandler.new
|
||||
end
|
||||
|
||||
Given /the response from the service has a Content-Type of '(.*)'/ do |content_type|
|
||||
@handler.content_type = content_type
|
||||
end
|
||||
|
||||
Given /the response from the service has a body of '(.*)'/ do |response_body|
|
||||
@handler.response_body = response_body
|
||||
end
|
||||
|
||||
Given /the url '(.*)' redirects to '(.*)'/ do |redirection_url, target_url|
|
||||
@server.register redirection_url, new_mongrel_redirector(target_url)
|
||||
end
|
||||
|
||||
Given /that service is protected by Basic Authentication/ do
|
||||
@handler.extend BasicAuthentication
|
||||
end
|
||||
|
||||
Given /that service is protected by Digest Authentication/ do
|
||||
@handler.extend DigestAuthentication
|
||||
end
|
||||
|
||||
Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
|
||||
@handler.username = username
|
||||
@handler.password = password
|
||||
end
|
||||
|
||||
Given /a restricted page at '(.*)'/ do |url|
|
||||
Given "a remote service that returns 'A response I will never see'"
|
||||
And "that service is accessed at the path '#{url}'"
|
||||
And "that service is protected by Basic Authentication"
|
||||
And "that service requires the username 'something' with the password 'secret'"
|
||||
end
|
||||
|
||||
# This joins the server thread, and halts cucumber, so you can actually hit the
|
||||
# server with a browser. Runs until you kill it with Ctrl-c
|
||||
Given /I want to hit this in a browser/ do
|
||||
@server.acceptor.join
|
||||
end
|
||||
|
||||
Then /I wait for the server to recover/ do
|
||||
timeout = @request_options[:timeout] || 0
|
||||
sleep @server_response_time - timeout
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
Feature: Supports Redirection
|
||||
|
||||
As a developer
|
||||
I want to work with services that may redirect me
|
||||
And I want it to follow a reasonable number of redirects
|
||||
Because sometimes web services do that
|
||||
|
||||
Scenario: A service that redirects once
|
||||
Given a remote service that returns 'Service Response'
|
||||
And that service is accessed at the path '/landing_service.html'
|
||||
And the url '/redirector.html' redirects to '/landing_service.html'
|
||||
When I call HTTParty#get with '/redirector.html'
|
||||
Then the return value should match 'Service Response'
|
||||
|
||||
# TODO: Look in to why this actually fails...
|
||||
Scenario: A service that redirects to a relative URL
|
||||
|
||||
Scenario: A service that redirects infinitely
|
||||
Given the url '/first.html' redirects to '/second.html'
|
||||
And the url '/second.html' redirects to '/first.html'
|
||||
When I call HTTParty#get with '/first.html'
|
||||
Then it should raise an HTTParty::RedirectionTooDeep exception
|
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/supports_timeout_option.feature
vendored
Normal file
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/features/supports_timeout_option.feature
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
Feature: Supports the timeout option
|
||||
In order to handle inappropriately slow response times
|
||||
As a developer
|
||||
I want my request to raise an exception after my specified timeout as elapsed
|
||||
|
||||
Scenario: A long running response
|
||||
Given a remote service that returns '<h1>Some HTML</h1>'
|
||||
And that service is accessed at the path '/long_running_service.html'
|
||||
And that service takes 2 seconds to generate a response
|
||||
When I set my HTTParty timeout option to 1
|
||||
And I call HTTParty#get with '/long_running_service.html'
|
||||
Then it should raise a Timeout::Error exception
|
||||
And I wait for the server to recover
|
|
@ -0,0 +1,24 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "httparty/version"
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "httparty"
|
||||
s.version = HTTParty::VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["John Nunemaker", "Sandro Turriate"]
|
||||
s.email = ["nunemaker@gmail.com"]
|
||||
s.homepage = "http://jnunemaker.github.com/httparty"
|
||||
s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
||||
s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
||||
|
||||
s.add_dependency 'multi_json', "~> 1.0"
|
||||
s.add_dependency 'multi_xml'
|
||||
|
||||
s.post_install_message = "When you HTTParty, you must party hard!"
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
s.require_paths = ["lib"]
|
||||
end
|
|
@ -0,0 +1,503 @@
|
|||
require 'pathname'
|
||||
require 'net/http'
|
||||
require 'net/https'
|
||||
require 'uri'
|
||||
require 'zlib'
|
||||
require 'multi_xml'
|
||||
require 'multi_json'
|
||||
|
||||
require 'httparty/module_inheritable_attributes'
|
||||
require 'httparty/cookie_hash'
|
||||
require 'httparty/net_digest_auth'
|
||||
require 'httparty/version'
|
||||
require 'httparty/connection_adapter'
|
||||
|
||||
# @see HTTParty::ClassMethods
|
||||
module HTTParty
|
||||
module AllowedFormatsDeprecation
|
||||
def const_missing(const)
|
||||
if const.to_s =~ /AllowedFormats$/
|
||||
Kernel.warn("Deprecated: Use HTTParty::Parser::SupportedFormats")
|
||||
HTTParty::Parser::SupportedFormats
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
extend AllowedFormatsDeprecation
|
||||
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
base.send :include, HTTParty::ModuleInheritableAttributes
|
||||
base.send(:mattr_inheritable, :default_options)
|
||||
base.send(:mattr_inheritable, :default_cookies)
|
||||
base.instance_variable_set("@default_options", {})
|
||||
base.instance_variable_set("@default_cookies", CookieHash.new)
|
||||
end
|
||||
|
||||
# == Common Request Options
|
||||
# Request methods (get, post, patch, put, delete, head, options) all take a common set of options. These are:
|
||||
#
|
||||
# [:+body+:] Body of the request. If passed a Hash, will try to normalize it first, by default passing it to ActiveSupport::to_params. Any other kind of object will get used as-is.
|
||||
# [:+http_proxyaddr+:] Address of proxy server to use.
|
||||
# [:+http_proxyport+:] Port of proxy server to use.
|
||||
# [:+http_proxyuser+:] User for proxy server authentication.
|
||||
# [:+http_proxypass+:] Password for proxy server authentication.
|
||||
# [:+limit+:] Maximum number of redirects to follow. Takes precedences over :+no_follow+.
|
||||
# [:+query+:] Query string, or a Hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use a Hash. See also HTTParty::ClassMethods.default_params.
|
||||
# [:+timeout+:] Timeout for opening connection and reading data.
|
||||
#
|
||||
# There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are:
|
||||
# * :+base_uri+: see HTTParty::ClassMethods.base_uri.
|
||||
# * :+basic_auth+: see HTTParty::ClassMethods.basic_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError.
|
||||
# * :+debug_output+: see HTTParty::ClassMethods.debug_output.
|
||||
# * :+digest_auth+: see HTTParty::ClassMethods.digest_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError.
|
||||
# * :+format+: see HTTParty::ClassMethods.format.
|
||||
# * :+headers+: see HTTParty::ClassMethods.headers. Must be a Hash.
|
||||
# * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects.
|
||||
# * :+no_follow+: see HTTParty::ClassMethods.no_follow.
|
||||
# * :+parser+: see HTTParty::ClassMethods.parser.
|
||||
# * :+connection_adapter+: see HTTParty::ClassMethods.connection_adapter.
|
||||
# * :+pem+: see HTTParty::ClassMethods.pem.
|
||||
# * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer
|
||||
# * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file.
|
||||
# * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path.
|
||||
|
||||
module ClassMethods
|
||||
|
||||
extend AllowedFormatsDeprecation
|
||||
|
||||
# Allows setting http proxy information to be used
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# http_proxy 'http://foo.com', 80, 'user', 'pass'
|
||||
# end
|
||||
def http_proxy(addr=nil, port=nil, user=nil, pass=nil)
|
||||
default_options[:http_proxyaddr] = addr
|
||||
default_options[:http_proxyport] = port
|
||||
default_options[:http_proxyuser] = user
|
||||
default_options[:http_proxypass] = pass
|
||||
end
|
||||
|
||||
# Allows setting a base uri to be used for each request.
|
||||
# Will normalize uri to include http, etc.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# base_uri 'twitter.com'
|
||||
# end
|
||||
def base_uri(uri=nil)
|
||||
return default_options[:base_uri] unless uri
|
||||
default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
|
||||
end
|
||||
|
||||
# Allows setting basic authentication username and password.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# basic_auth 'username', 'password'
|
||||
# end
|
||||
def basic_auth(u, p)
|
||||
default_options[:basic_auth] = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
# Allows setting digest authentication username and password.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# digest_auth 'username', 'password'
|
||||
# end
|
||||
def digest_auth(u, p)
|
||||
default_options[:digest_auth] = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
# Do not send rails style query strings.
|
||||
# Specically, don't use bracket notation when sending an array
|
||||
#
|
||||
# For a query:
|
||||
# get '/', :query => {:selected_ids => [1,2,3]}
|
||||
#
|
||||
# The default query string looks like this:
|
||||
# /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
|
||||
#
|
||||
# Call `disable_rails_query_string_format` to transform the query string
|
||||
# into:
|
||||
# /?selected_ids=1&selected_ids=2&selected_ids=3
|
||||
#
|
||||
# @example
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# disable_rails_query_string_format
|
||||
# end
|
||||
def disable_rails_query_string_format
|
||||
query_string_normalizer Request::NON_RAILS_QUERY_STRING_NORMALIZER
|
||||
end
|
||||
|
||||
# Allows setting default parameters to be appended to each request.
|
||||
# Great for api keys and such.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# default_params :api_key => 'secret', :another => 'foo'
|
||||
# end
|
||||
def default_params(h={})
|
||||
raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
|
||||
default_options[:default_params] ||= {}
|
||||
default_options[:default_params].merge!(h)
|
||||
end
|
||||
|
||||
# Allows setting a default timeout for all HTTP calls
|
||||
# Timeout is specified in seconds.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# default_timeout 10
|
||||
# end
|
||||
def default_timeout(t)
|
||||
raise ArgumentError, 'Timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
|
||||
default_options[:timeout] = t
|
||||
end
|
||||
|
||||
# Set an output stream for debugging, defaults to $stderr.
|
||||
# The output stream is passed on to Net::HTTP#set_debug_output.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# debug_output $stderr
|
||||
# end
|
||||
def debug_output(stream = $stderr)
|
||||
default_options[:debug_output] = stream
|
||||
end
|
||||
|
||||
# Allows setting HTTP headers to be used for each request.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# headers 'Accept' => 'text/html'
|
||||
# end
|
||||
def headers(h={})
|
||||
raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
|
||||
default_options[:headers] ||= {}
|
||||
default_options[:headers].merge!(h)
|
||||
end
|
||||
|
||||
def cookies(h={})
|
||||
raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash)
|
||||
default_cookies.add_cookies(h)
|
||||
end
|
||||
|
||||
# Proceed to the location header when an HTTP response dictates a redirect.
|
||||
# Redirects are always followed by default.
|
||||
#
|
||||
# @example
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# base_uri 'http://google.com'
|
||||
# follow_redirects true
|
||||
# end
|
||||
def follow_redirects(value = true)
|
||||
default_options[:follow_redirects] = value
|
||||
end
|
||||
|
||||
# Allows setting the format with which to parse.
|
||||
# Must be one of the allowed formats ie: json, xml
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# format :json
|
||||
# end
|
||||
def format(f = nil)
|
||||
if f.nil?
|
||||
default_options[:format]
|
||||
else
|
||||
parser(Parser) if parser.nil?
|
||||
default_options[:format] = f
|
||||
validate_format
|
||||
end
|
||||
end
|
||||
|
||||
# Declare whether or not to follow redirects. When true, an
|
||||
# {HTTParty::RedirectionTooDeep} error will raise upon encountering a
|
||||
# redirect. You can then gain access to the response object via
|
||||
# HTTParty::RedirectionTooDeep#response.
|
||||
#
|
||||
# @see HTTParty::ResponseError#response
|
||||
#
|
||||
# @example
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# base_uri 'http://google.com'
|
||||
# no_follow true
|
||||
# end
|
||||
#
|
||||
# begin
|
||||
# Foo.get('/')
|
||||
# rescue HTTParty::RedirectionTooDeep => e
|
||||
# puts e.response.body
|
||||
# end
|
||||
def no_follow(value = false)
|
||||
default_options[:no_follow] = value
|
||||
end
|
||||
|
||||
# Declare that you wish to maintain the chosen HTTP method across redirects.
|
||||
# The default behavior is to follow redirects via the GET method.
|
||||
# If you wish to maintain the original method, you can set this option to true.
|
||||
#
|
||||
# @example
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# base_uri 'http://google.com'
|
||||
# maintain_method_across_redirects true
|
||||
# end
|
||||
|
||||
def maintain_method_across_redirects(value = true)
|
||||
default_options[:maintain_method_across_redirects] = value
|
||||
end
|
||||
|
||||
# Allows setting a PEM file to be used
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# pem File.read('/home/user/my.pem'), "optional password"
|
||||
# end
|
||||
def pem(pem_contents, password=nil)
|
||||
default_options[:pem] = pem_contents
|
||||
default_options[:pem_password] = password
|
||||
end
|
||||
|
||||
# Override the way query strings are normalized.
|
||||
# Helpful for overriding the default rails normalization of Array queries.
|
||||
#
|
||||
# For a query:
|
||||
# get '/', :query => {:selected_ids => [1,2,3]}
|
||||
#
|
||||
# The default query string normalizer returns:
|
||||
# /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
|
||||
#
|
||||
# Let's change it to this:
|
||||
# /?selected_ids=1&selected_ids=2&selected_ids=3
|
||||
#
|
||||
# Pass a Proc to the query normalizer which accepts the yielded query.
|
||||
#
|
||||
# @example Modifying Array query strings
|
||||
# class ServiceWrapper
|
||||
# include HTTParty
|
||||
#
|
||||
# query_string_normalizer proc { |query|
|
||||
# query.map do |key, value|
|
||||
# value.map {|v| "#{key}=#{v}"}
|
||||
# end.join('&')
|
||||
# }
|
||||
# end
|
||||
#
|
||||
# @param [Proc] normalizer custom query string normalizer.
|
||||
# @yield [Hash, String] query string
|
||||
# @yieldreturn [Array] an array that will later be joined with '&'
|
||||
def query_string_normalizer(normalizer)
|
||||
default_options[:query_string_normalizer] = normalizer
|
||||
end
|
||||
|
||||
# Allows setting of SSL version to use. This only works in Ruby 1.9.
|
||||
# You can get a list of valid versions from OpenSSL::SSL::SSLContext::METHODS.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# ssl_version :SSLv3
|
||||
# end
|
||||
def ssl_version(version)
|
||||
default_options[:ssl_version] = version
|
||||
end
|
||||
|
||||
# Allows setting an OpenSSL certificate authority file
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# ssl_ca_file '/etc/ssl/certs/ca-certificates.crt'
|
||||
# end
|
||||
def ssl_ca_file(path)
|
||||
default_options[:ssl_ca_file] = path
|
||||
end
|
||||
|
||||
# Allows setting an OpenSSL certificate authority path (directory)
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# ssl_ca_path '/etc/ssl/certs/'
|
||||
# end
|
||||
def ssl_ca_path(path)
|
||||
default_options[:ssl_ca_path] = path
|
||||
end
|
||||
|
||||
# Allows setting a custom parser for the response.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# parser Proc.new {|data| ...}
|
||||
# end
|
||||
def parser(custom_parser = nil)
|
||||
if custom_parser.nil?
|
||||
default_options[:parser]
|
||||
else
|
||||
default_options[:parser] = custom_parser
|
||||
validate_format
|
||||
end
|
||||
end
|
||||
|
||||
# Allows setting a custom connection_adapter for the http connections
|
||||
#
|
||||
# @example
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# connection_adapter Proc.new {|uri, options| ... }
|
||||
# end
|
||||
#
|
||||
# @example provide optional configuration for your connection_adapter
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# connection_adapter Proc.new {|uri, options| ... }, {:foo => :bar}
|
||||
# end
|
||||
#
|
||||
# @see HTTParty::ConnectionAdapter
|
||||
def connection_adapter(custom_adapter = nil, options = nil)
|
||||
if custom_adapter.nil?
|
||||
default_options[:connection_adapter]
|
||||
else
|
||||
default_options[:connection_adapter] = custom_adapter
|
||||
default_options[:connection_adapter_options] = options
|
||||
end
|
||||
end
|
||||
|
||||
# Allows making a get request to a url.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# end
|
||||
#
|
||||
# # Simple get with full url
|
||||
# Foo.get('http://foo.com/resource.json')
|
||||
#
|
||||
# # Simple get with full url and query parameters
|
||||
# # ie: http://foo.com/resource.json?limit=10
|
||||
# Foo.get('http://foo.com/resource.json', :query => {:limit => 10})
|
||||
def get(path, options={}, &block)
|
||||
perform_request Net::HTTP::Get, path, options, &block
|
||||
end
|
||||
|
||||
# Allows making a post request to a url.
|
||||
#
|
||||
# class Foo
|
||||
# include HTTParty
|
||||
# end
|
||||
#
|
||||
# # Simple post with full url and setting the body
|
||||
# Foo.post('http://foo.com/resources', :body => {:bar => 'baz'})
|
||||
#
|
||||
# # Simple post with full url using :query option,
|
||||
# # which gets set as form data on the request.
|
||||
# Foo.post('http://foo.com/resources', :query => {:bar => 'baz'})
|
||||
def post(path, options={}, &block)
|
||||
perform_request Net::HTTP::Post, path, options, &block
|
||||
end
|
||||
|
||||
# Perform a PATCH request to a path
|
||||
def patch(path, options={}, &block)
|
||||
perform_request Net::HTTP::Patch, path, options, &block
|
||||
end
|
||||
|
||||
# Perform a PUT request to a path
|
||||
def put(path, options={}, &block)
|
||||
perform_request Net::HTTP::Put, path, options, &block
|
||||
end
|
||||
|
||||
# Perform a DELETE request to a path
|
||||
def delete(path, options={}, &block)
|
||||
perform_request Net::HTTP::Delete, path, options, &block
|
||||
end
|
||||
|
||||
# Perform a HEAD request to a path
|
||||
def head(path, options={}, &block)
|
||||
perform_request Net::HTTP::Head, path, options, &block
|
||||
end
|
||||
|
||||
# Perform an OPTIONS request to a path
|
||||
def options(path, options={}, &block)
|
||||
perform_request Net::HTTP::Options, path, options, &block
|
||||
end
|
||||
|
||||
def default_options #:nodoc:
|
||||
@default_options
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def perform_request(http_method, path, options, &block) #:nodoc:
|
||||
options = default_options.dup.merge(options)
|
||||
process_cookies(options)
|
||||
Request.new(http_method, path, options).perform(&block)
|
||||
end
|
||||
|
||||
def process_cookies(options) #:nodoc:
|
||||
return unless options[:cookies] || default_cookies.any?
|
||||
options[:headers] ||= headers.dup
|
||||
options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
|
||||
end
|
||||
|
||||
def validate_format
|
||||
if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
|
||||
raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map{|f| f.to_s}.sort.join(', ')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.normalize_base_uri(url) #:nodoc:
|
||||
normalized_url = url.dup
|
||||
use_ssl = (normalized_url =~ /^https/) || (normalized_url =~ /:443\b/)
|
||||
ends_with_slash = normalized_url =~ /\/$/
|
||||
|
||||
normalized_url.chop! if ends_with_slash
|
||||
normalized_url.gsub!(/^https?:\/\//i, '')
|
||||
|
||||
"http#{'s' if use_ssl}://#{normalized_url}"
|
||||
end
|
||||
|
||||
class Basement #:nodoc:
|
||||
include HTTParty
|
||||
end
|
||||
|
||||
def self.get(*args, &block)
|
||||
Basement.get(*args, &block)
|
||||
end
|
||||
|
||||
def self.post(*args, &block)
|
||||
Basement.post(*args, &block)
|
||||
end
|
||||
|
||||
def self.patch(*args, &block)
|
||||
Basement.patch(*args, &block)
|
||||
end
|
||||
|
||||
def self.put(*args, &block)
|
||||
Basement.put(*args, &block)
|
||||
end
|
||||
|
||||
def self.delete(*args, &block)
|
||||
Basement.delete(*args, &block)
|
||||
end
|
||||
|
||||
def self.head(*args, &block)
|
||||
Basement.head(*args, &block)
|
||||
end
|
||||
|
||||
def self.options(*args, &block)
|
||||
Basement.options(*args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
require 'httparty/core_extensions'
|
||||
require 'httparty/hash_conversions'
|
||||
require 'httparty/exceptions'
|
||||
require 'httparty/parser'
|
||||
require 'httparty/request'
|
||||
require 'httparty/response'
|
|
@ -0,0 +1,116 @@
|
|||
module HTTParty
|
||||
# Default connection adapter that returns a new Net::HTTP each time
|
||||
#
|
||||
# == Custom Connection Factories
|
||||
#
|
||||
# If you like to implement your own connection adapter, subclassing
|
||||
# HTTPParty::ConnectionAdapter will make it easier. Just override
|
||||
# the #connection method. The uri and options attributes will have
|
||||
# all the info you need to construct your http connection. Whatever
|
||||
# you return from your connection method needs to adhere to the
|
||||
# Net::HTTP interface as this is what HTTParty expects.
|
||||
#
|
||||
# @example log the uri and options
|
||||
# class LoggingConnectionAdapter < HTTParty::ConnectionAdapter
|
||||
# def connection
|
||||
# puts uri
|
||||
# puts options
|
||||
# Net::HTTP.new(uri)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example count number of http calls
|
||||
# class CountingConnectionAdapter < HTTParty::ConnectionAdapter
|
||||
# @@count = 0
|
||||
#
|
||||
# self.count
|
||||
# @@count
|
||||
# end
|
||||
#
|
||||
# def connection
|
||||
# self.count += 1
|
||||
# super
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# === Configuration
|
||||
# There is lots of configuration data available for your connection adapter
|
||||
# in the #options attribute. It is up to you to interpret them within your
|
||||
# connection adapter. Take a look at the implementation of
|
||||
# HTTParty::ConnectionAdapter#connection for examples of how they are used.
|
||||
# Something are probably interesting are as follows:
|
||||
# * :+timeout+: timeout in seconds
|
||||
# * :+debug_output+: see HTTParty::ClassMethods.debug_output.
|
||||
# * :+pem+: contains pem data. see HTTParty::ClassMethods.pem.
|
||||
# * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file.
|
||||
# * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path.
|
||||
# * :+connection_adapter_options+: contains the hash your passed to HTTParty.connection_adapter when you configured your connection adapter
|
||||
class ConnectionAdapter
|
||||
|
||||
def self.call(uri, options)
|
||||
new(uri, options).connection
|
||||
end
|
||||
|
||||
attr_reader :uri, :options
|
||||
|
||||
def initialize(uri, options={})
|
||||
raise ArgumentError, "uri must be a URI, not a #{uri.class}" unless uri.kind_of? URI
|
||||
|
||||
@uri = uri
|
||||
@options = options
|
||||
end
|
||||
|
||||
def connection
|
||||
http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport], options[:http_proxyuser], options[:http_proxypass])
|
||||
|
||||
http.use_ssl = ssl_implied?(uri)
|
||||
|
||||
attach_ssl_certificates(http, options)
|
||||
|
||||
if options[:timeout] && (options[:timeout].is_a?(Integer) || options[:timeout].is_a?(Float))
|
||||
http.open_timeout = options[:timeout]
|
||||
http.read_timeout = options[:timeout]
|
||||
end
|
||||
|
||||
if options[:debug_output]
|
||||
http.set_debug_output(options[:debug_output])
|
||||
end
|
||||
|
||||
return http
|
||||
end
|
||||
|
||||
private
|
||||
def ssl_implied?(uri)
|
||||
uri.port == 443 || uri.instance_of?(URI::HTTPS)
|
||||
end
|
||||
|
||||
def attach_ssl_certificates(http, options)
|
||||
if http.use_ssl?
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
|
||||
# Client certificate authentication
|
||||
if options[:pem]
|
||||
http.cert = OpenSSL::X509::Certificate.new(options[:pem])
|
||||
http.key = OpenSSL::PKey::RSA.new(options[:pem], options[:pem_password])
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
|
||||
# SSL certificate authority file and/or directory
|
||||
if options[:ssl_ca_file]
|
||||
http.ca_file = options[:ssl_ca_file]
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
|
||||
if options[:ssl_ca_path]
|
||||
http.ca_path = options[:ssl_ca_path]
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
|
||||
# This is only Ruby 1.9+
|
||||
if options[:ssl_version] && http.respond_to?(:ssl_version=)
|
||||
http.ssl_version = options[:ssl_version]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
class HTTParty::CookieHash < Hash #:nodoc:
|
||||
|
||||
CLIENT_COOKIES = %w{path expires domain path secure HTTPOnly}
|
||||
|
||||
def add_cookies(value)
|
||||
case value
|
||||
when Hash
|
||||
merge!(value)
|
||||
when String
|
||||
value.split('; ').each do |cookie|
|
||||
array = cookie.split('=')
|
||||
self[array[0].to_sym] = array[1]
|
||||
end
|
||||
else
|
||||
raise "add_cookies only takes a Hash or a String"
|
||||
end
|
||||
end
|
||||
|
||||
def to_cookie_string
|
||||
delete_if { |k, v| CLIENT_COOKIES.include?(k.to_s) }.collect { |k, v| "#{k}=#{v}" }.join("; ")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
module HTTParty
|
||||
if defined?(::BasicObject)
|
||||
BasicObject = ::BasicObject #:nodoc:
|
||||
else
|
||||
class BasicObject #:nodoc:
|
||||
instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ }
|
||||
end
|
||||
end
|
||||
|
||||
unless defined?(Net::HTTP::Patch)
|
||||
class Net::HTTP
|
||||
def patch(path, data, initheader = nil, dest = nil, &block) #:nodoc:
|
||||
res = nil
|
||||
request(Patch.new(path, initheader), data) {|r|
|
||||
r.read_body dest, &block
|
||||
res = r
|
||||
}
|
||||
unless @newimpl
|
||||
res.value
|
||||
return res, res.body
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
class Patch < Net::HTTPRequest
|
||||
METHOD = 'PATCH'
|
||||
REQUEST_HAS_BODY = true
|
||||
RESPONSE_HAS_BODY = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
module HTTParty
|
||||
# Exception raised when you attempt to set a non-existant format
|
||||
class UnsupportedFormat < StandardError; end
|
||||
|
||||
# Exception raised when using a URI scheme other than HTTP or HTTPS
|
||||
class UnsupportedURIScheme < StandardError; end
|
||||
|
||||
# @abstract Exceptions which inherit from ResponseError contain the Net::HTTP
|
||||
# response object accessible via the {#response} method.
|
||||
class ResponseError < StandardError
|
||||
# Returns the response of the last request
|
||||
# @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g.
|
||||
# Net::HTTPOK
|
||||
attr_reader :response
|
||||
|
||||
# Instantiate an instance of ResponseError with a Net::HTTPResponse object
|
||||
# @param [Net::HTTPResponse]
|
||||
def initialize(response)
|
||||
@response = response
|
||||
end
|
||||
end
|
||||
|
||||
# Exception that is raised when request has redirected too many times.
|
||||
# Calling {#response} returns the Net:HTTP response object.
|
||||
class RedirectionTooDeep < ResponseError; end
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
module HTTParty
|
||||
module HashConversions
|
||||
# @return <String> This hash as a query string
|
||||
#
|
||||
# @example
|
||||
# { :name => "Bob",
|
||||
# :address => {
|
||||
# :street => '111 Ruby Ave.',
|
||||
# :city => 'Ruby Central',
|
||||
# :phones => ['111-111-1111', '222-222-2222']
|
||||
# }
|
||||
# }.to_params
|
||||
# #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
|
||||
def self.to_params(hash)
|
||||
params = hash.map { |k,v| normalize_param(k,v) }.join
|
||||
params.chop! # trailing &
|
||||
params
|
||||
end
|
||||
|
||||
# @param key<Object> The key for the param.
|
||||
# @param value<Object> The value for the param.
|
||||
#
|
||||
# @return <String> This key value pair as a param
|
||||
#
|
||||
# @example normalize_param(:name, "Bob Jones") #=> "name=Bob%20Jones&"
|
||||
def self.normalize_param(key, value)
|
||||
param = ''
|
||||
stack = []
|
||||
|
||||
if value.is_a?(Array)
|
||||
param << value.map { |element| normalize_param("#{key}[]", element) }.join
|
||||
elsif value.is_a?(Hash)
|
||||
stack << [key,value]
|
||||
else
|
||||
param << "#{key}=#{URI.encode(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&"
|
||||
end
|
||||
|
||||
stack.each do |parent, hash|
|
||||
hash.each do |key, value|
|
||||
if value.is_a?(Hash)
|
||||
stack << ["#{parent}[#{key}]", value]
|
||||
else
|
||||
param << normalize_param("#{parent}[#{key}]", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
param
|
||||
end
|
||||
end
|
||||
end
|
44
vendor/ruby/1.9.1/gems/httparty-0.9.0/lib/httparty/module_inheritable_attributes.rb
vendored
Normal file
44
vendor/ruby/1.9.1/gems/httparty-0.9.0/lib/httparty/module_inheritable_attributes.rb
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
module HTTParty
|
||||
module ModuleInheritableAttributes #:nodoc:
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# borrowed from Rails 3.2 ActiveSupport
|
||||
def self.hash_deep_dup(h)
|
||||
duplicate = h.dup
|
||||
duplicate.each_pair do |k,v|
|
||||
tv = duplicate[k]
|
||||
duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? hash_deep_dup(tv) : v
|
||||
end
|
||||
duplicate
|
||||
end
|
||||
|
||||
module ClassMethods #:nodoc:
|
||||
def mattr_inheritable(*args)
|
||||
@mattr_inheritable_attrs ||= [:mattr_inheritable_attrs]
|
||||
@mattr_inheritable_attrs += args
|
||||
args.each do |arg|
|
||||
module_eval %(class << self; attr_accessor :#{arg} end)
|
||||
end
|
||||
@mattr_inheritable_attrs
|
||||
end
|
||||
|
||||
def inherited(subclass)
|
||||
super
|
||||
@mattr_inheritable_attrs.each do |inheritable_attribute|
|
||||
ivar = "@#{inheritable_attribute}"
|
||||
subclass.instance_variable_set(ivar, instance_variable_get(ivar).clone)
|
||||
if instance_variable_get(ivar).respond_to?(:merge)
|
||||
method = <<-EOM
|
||||
def self.#{inheritable_attribute}
|
||||
#{ivar} = superclass.#{inheritable_attribute}.merge ModuleInheritableAttributes.hash_deep_dup(#{ivar})
|
||||
end
|
||||
EOM
|
||||
subclass.class_eval method
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
require 'digest/md5'
|
||||
require 'net/http'
|
||||
|
||||
module Net
|
||||
module HTTPHeader
|
||||
def digest_auth(username, password, response)
|
||||
@header['Authorization'] = DigestAuthenticator.new(username, password,
|
||||
@method, @path, response).authorization_header
|
||||
end
|
||||
|
||||
|
||||
class DigestAuthenticator
|
||||
def initialize(username, password, method, path, response_header)
|
||||
@username = username
|
||||
@password = password
|
||||
@method = method
|
||||
@path = path
|
||||
@response = parse(response_header)
|
||||
end
|
||||
|
||||
def authorization_header
|
||||
@cnonce = md5(random)
|
||||
header = [
|
||||
%Q(Digest username="#{@username}"),
|
||||
%Q(realm="#{@response['realm']}"),
|
||||
%Q(nonce="#{@response['nonce']}"),
|
||||
%Q(uri="#{@path}"),
|
||||
%Q(response="#{request_digest}"),
|
||||
]
|
||||
|
||||
if qop_present?
|
||||
fields = [
|
||||
%Q(cnonce="#{@cnonce}"),
|
||||
%Q(qop="#{@response['qop']}"),
|
||||
%Q(nc="00000001")
|
||||
]
|
||||
fields.each { |field| header << field }
|
||||
end
|
||||
|
||||
header << %Q(opaque="#{@response['opaque']}") if opaque_present?
|
||||
header
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse(response_header)
|
||||
response_header['www-authenticate'] =~ /^(\w+) (.*)/
|
||||
params = {}
|
||||
$2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
||||
params
|
||||
end
|
||||
|
||||
def opaque_present?
|
||||
@response.has_key?('opaque') and not @response['opaque'].empty?
|
||||
end
|
||||
|
||||
def qop_present?
|
||||
@response.has_key?('qop') and not @response['qop'].empty?
|
||||
end
|
||||
|
||||
def random
|
||||
"%x" % (Time.now.to_i + rand(65535))
|
||||
end
|
||||
|
||||
def request_digest
|
||||
a = [md5(a1), @response['nonce'], md5(a2)]
|
||||
a.insert(2, "00000001", @cnonce, @response['qop']) if qop_present?
|
||||
md5(a.join(":"))
|
||||
end
|
||||
|
||||
def md5(str)
|
||||
Digest::MD5.hexdigest(str)
|
||||
end
|
||||
|
||||
def a1
|
||||
[@username, @response['realm'], @password].join(":")
|
||||
end
|
||||
|
||||
def a2
|
||||
[@method, @path].join(":")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,145 @@
|
|||
module HTTParty
|
||||
# The default parser used by HTTParty, supports xml, json, html, yaml, and
|
||||
# plain text.
|
||||
#
|
||||
# == Custom Parsers
|
||||
#
|
||||
# If you'd like to do your own custom parsing, subclassing HTTParty::Parser
|
||||
# will make that process much easier. There are a few different ways you can
|
||||
# utilize HTTParty::Parser as a superclass.
|
||||
#
|
||||
# @example Intercept the parsing for all formats
|
||||
# class SimpleParser < HTTParty::Parser
|
||||
# def parse
|
||||
# perform_parsing
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example Add the atom format and parsing method to the default parser
|
||||
# class AtomParsingIncluded < HTTParty::Parser
|
||||
# SupportedFormats.merge!(
|
||||
# {"application/atom+xml" => :atom}
|
||||
# )
|
||||
#
|
||||
# def atom
|
||||
# perform_atom_parsing
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example Only support the atom format
|
||||
# class ParseOnlyAtom < HTTParty::Parser
|
||||
# SupportedFormats = {"application/atom+xml" => :atom}
|
||||
#
|
||||
# def atom
|
||||
# perform_atom_parsing
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @abstract Read the Custom Parsers section for more information.
|
||||
class Parser
|
||||
SupportedFormats = {
|
||||
'text/xml' => :xml,
|
||||
'application/xml' => :xml,
|
||||
'application/json' => :json,
|
||||
'text/json' => :json,
|
||||
'application/javascript' => :json,
|
||||
'text/javascript' => :json,
|
||||
'text/html' => :html,
|
||||
'application/x-yaml' => :yaml,
|
||||
'text/yaml' => :yaml,
|
||||
'text/plain' => :plain
|
||||
}
|
||||
|
||||
# The response body of the request
|
||||
# @return [String]
|
||||
attr_reader :body
|
||||
|
||||
# The intended parsing format for the request
|
||||
# @return [Symbol] e.g. :json
|
||||
attr_reader :format
|
||||
|
||||
# Instantiate the parser and call {#parse}.
|
||||
# @param [String] body the response body
|
||||
# @param [Symbol] format the response format
|
||||
# @return parsed response
|
||||
def self.call(body, format)
|
||||
new(body, format).parse
|
||||
end
|
||||
|
||||
# @return [Hash] the SupportedFormats hash
|
||||
def self.formats
|
||||
const_get(:SupportedFormats)
|
||||
end
|
||||
|
||||
# @param [String] mimetype response MIME type
|
||||
# @return [Symbol]
|
||||
# @return [nil] mime type not supported
|
||||
def self.format_from_mimetype(mimetype)
|
||||
formats[formats.keys.detect {|k| mimetype.include?(k)}]
|
||||
end
|
||||
|
||||
# @return [Array<Symbol>] list of supported formats
|
||||
def self.supported_formats
|
||||
formats.values.uniq
|
||||
end
|
||||
|
||||
# @param [Symbol] format e.g. :json, :xml
|
||||
# @return [Boolean]
|
||||
def self.supports_format?(format)
|
||||
supported_formats.include?(format)
|
||||
end
|
||||
|
||||
def initialize(body, format)
|
||||
@body = body
|
||||
@format = format
|
||||
end
|
||||
|
||||
# @return [Object] the parsed body
|
||||
# @return [nil] when the response body is nil, an empty string, spaces only or "null"
|
||||
def parse
|
||||
return nil if body.nil? || body.strip.empty? || body == "null"
|
||||
if supports_format?
|
||||
parse_supported_format
|
||||
else
|
||||
body
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def xml
|
||||
MultiXml.parse(body)
|
||||
end
|
||||
|
||||
def json
|
||||
# https://github.com/sferik/rails/commit/5e62670131dfa1718eaf21ff8dd3371395a5f1cc
|
||||
if MultiJson.respond_to?(:adapter)
|
||||
MultiJson.load(body)
|
||||
else
|
||||
MultiJson.decode(body)
|
||||
end
|
||||
end
|
||||
|
||||
def yaml
|
||||
YAML.load(body)
|
||||
end
|
||||
|
||||
def html
|
||||
body
|
||||
end
|
||||
|
||||
def plain
|
||||
body
|
||||
end
|
||||
|
||||
def supports_format?
|
||||
self.class.supports_format?(format)
|
||||
end
|
||||
|
||||
def parse_supported_format
|
||||
send(format)
|
||||
rescue NoMethodError => e
|
||||
raise NotImplementedError, "#{self.class.name} has not implemented a parsing method for the #{format.inspect} format.", e.backtrace
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,239 @@
|
|||
module HTTParty
|
||||
class Request #:nodoc:
|
||||
SupportedHTTPMethods = [
|
||||
Net::HTTP::Get,
|
||||
Net::HTTP::Post,
|
||||
Net::HTTP::Patch,
|
||||
Net::HTTP::Put,
|
||||
Net::HTTP::Delete,
|
||||
Net::HTTP::Head,
|
||||
Net::HTTP::Options
|
||||
]
|
||||
|
||||
SupportedURISchemes = [URI::HTTP, URI::HTTPS]
|
||||
|
||||
NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new do |query|
|
||||
Array(query).map do |key, value|
|
||||
if value.nil?
|
||||
key.to_s
|
||||
elsif value.is_a?(Array)
|
||||
value.map {|v| "#{key}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
|
||||
else
|
||||
HashConversions.to_params(key => value)
|
||||
end
|
||||
end.flatten.sort.join('&')
|
||||
end
|
||||
|
||||
attr_accessor :http_method, :path, :options, :last_response, :redirect, :last_uri
|
||||
|
||||
def initialize(http_method, path, o={})
|
||||
self.http_method = http_method
|
||||
self.path = path
|
||||
self.options = {
|
||||
:limit => o.delete(:no_follow) ? 1 : 5,
|
||||
:default_params => {},
|
||||
:follow_redirects => true,
|
||||
:parser => Parser,
|
||||
:connection_adapter => ConnectionAdapter
|
||||
}.merge(o)
|
||||
end
|
||||
|
||||
def path=(uri)
|
||||
@path = URI.parse(uri)
|
||||
end
|
||||
|
||||
def uri
|
||||
new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path
|
||||
|
||||
# avoid double query string on redirects [#12]
|
||||
unless redirect
|
||||
new_uri.query = query_string(new_uri)
|
||||
end
|
||||
|
||||
unless SupportedURISchemes.include? new_uri.class
|
||||
raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP or HTTPS"
|
||||
end
|
||||
|
||||
@last_uri = new_uri
|
||||
end
|
||||
|
||||
def base_uri
|
||||
redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
|
||||
end
|
||||
|
||||
def format
|
||||
options[:format] || (format_from_mimetype(last_response['content-type']) if last_response)
|
||||
end
|
||||
|
||||
def parser
|
||||
options[:parser]
|
||||
end
|
||||
|
||||
def connection_adapter
|
||||
options[:connection_adapter]
|
||||
end
|
||||
|
||||
def perform(&block)
|
||||
validate
|
||||
setup_raw_request
|
||||
chunked_body = nil
|
||||
|
||||
self.last_response = http.request(@raw_request) do |http_response|
|
||||
if block
|
||||
chunks = []
|
||||
|
||||
http_response.read_body do |fragment|
|
||||
chunks << fragment
|
||||
block.call(fragment)
|
||||
end
|
||||
|
||||
chunked_body = chunks.join
|
||||
end
|
||||
end
|
||||
|
||||
handle_deflation
|
||||
handle_response(chunked_body)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def http
|
||||
connection_adapter.call(uri, options)
|
||||
end
|
||||
|
||||
def body
|
||||
options[:body].is_a?(Hash) ? normalize_query(options[:body]) : options[:body]
|
||||
end
|
||||
|
||||
def credentials
|
||||
options[:basic_auth] || options[:digest_auth]
|
||||
end
|
||||
|
||||
def username
|
||||
credentials[:username]
|
||||
end
|
||||
|
||||
def password
|
||||
credentials[:password]
|
||||
end
|
||||
|
||||
def normalize_query(query)
|
||||
if query_string_normalizer
|
||||
query_string_normalizer.call(query)
|
||||
else
|
||||
HashConversions.to_params(query)
|
||||
end
|
||||
end
|
||||
|
||||
def query_string_normalizer
|
||||
options[:query_string_normalizer]
|
||||
end
|
||||
|
||||
def setup_raw_request
|
||||
@raw_request = http_method.new(uri.request_uri)
|
||||
@raw_request.body = body if body
|
||||
@raw_request.initialize_http_header(options[:headers])
|
||||
@raw_request.basic_auth(username, password) if options[:basic_auth]
|
||||
setup_digest_auth if options[:digest_auth]
|
||||
end
|
||||
|
||||
def setup_digest_auth
|
||||
auth_request = http_method.new(uri.request_uri)
|
||||
auth_request.initialize_http_header(options[:headers])
|
||||
res = http.request(auth_request)
|
||||
|
||||
if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
|
||||
@raw_request.digest_auth(username, password, res)
|
||||
end
|
||||
end
|
||||
|
||||
def query_string(uri)
|
||||
query_string_parts = []
|
||||
query_string_parts << uri.query unless uri.query.nil?
|
||||
|
||||
if options[:query].is_a?(Hash)
|
||||
query_string_parts << normalize_query(options[:default_params].merge(options[:query]))
|
||||
else
|
||||
query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
|
||||
query_string_parts << options[:query] unless options[:query].nil?
|
||||
end
|
||||
|
||||
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
||||
end
|
||||
|
||||
def handle_response(body)
|
||||
if response_redirects?
|
||||
options[:limit] -= 1
|
||||
self.path = last_response['location']
|
||||
self.redirect = true
|
||||
self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
|
||||
capture_cookies(last_response)
|
||||
perform
|
||||
else
|
||||
body = body || last_response.body
|
||||
Response.new(self, last_response, lambda { parse_response(body) }, :body => body)
|
||||
end
|
||||
end
|
||||
|
||||
# Inspired by Ruby 1.9
|
||||
def handle_deflation
|
||||
case last_response["content-encoding"]
|
||||
when "gzip", "x-gzip"
|
||||
body_io = StringIO.new(last_response.body)
|
||||
last_response.body.replace Zlib::GzipReader.new(body_io).read
|
||||
last_response.delete('content-encoding')
|
||||
when "deflate"
|
||||
last_response.body.replace Zlib::Inflate.inflate(last_response.body)
|
||||
last_response.delete('content-encoding')
|
||||
end
|
||||
end
|
||||
|
||||
def response_redirects?
|
||||
case last_response
|
||||
when Net::HTTPMultipleChoice, # 300
|
||||
Net::HTTPMovedPermanently, # 301
|
||||
Net::HTTPFound, # 302
|
||||
Net::HTTPSeeOther, # 303
|
||||
Net::HTTPUseProxy, # 305
|
||||
Net::HTTPTemporaryRedirect
|
||||
options[:follow_redirects] && last_response.key?('location')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_response(body)
|
||||
parser.call(body, format)
|
||||
end
|
||||
|
||||
def capture_cookies(response)
|
||||
return unless response['Set-Cookie']
|
||||
cookies_hash = HTTParty::CookieHash.new()
|
||||
cookies_hash.add_cookies(options[:headers]['Cookie']) if options[:headers] && options[:headers]['Cookie']
|
||||
cookies_hash.add_cookies(response['Set-Cookie'])
|
||||
options[:headers] ||= {}
|
||||
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
|
||||
end
|
||||
|
||||
# Uses the HTTP Content-Type header to determine the format of the
|
||||
# response It compares the MIME type returned to the types stored in the
|
||||
# SupportedFormats hash
|
||||
def format_from_mimetype(mimetype)
|
||||
if mimetype && parser.respond_to?(:format_from_mimetype)
|
||||
parser.format_from_mimetype(mimetype)
|
||||
end
|
||||
end
|
||||
|
||||
def validate
|
||||
raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
|
||||
raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
|
||||
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
|
||||
raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
|
||||
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
||||
raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
|
||||
raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
|
||||
end
|
||||
|
||||
def post?
|
||||
Net::HTTP::Post == http_method
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
module HTTParty
|
||||
class Response < HTTParty::BasicObject #:nodoc:
|
||||
def self.underscore(string)
|
||||
string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
|
||||
end
|
||||
|
||||
attr_reader :request, :response, :body, :headers
|
||||
|
||||
def initialize(request, response, parsed_block, options={})
|
||||
@request = request
|
||||
@response = response
|
||||
@body = response.body || options[:body]
|
||||
@parsed_block = parsed_block
|
||||
@headers = Headers.new(response.to_hash)
|
||||
end
|
||||
|
||||
def parsed_response
|
||||
@parsed_response ||= @parsed_block.call
|
||||
end
|
||||
|
||||
def class
|
||||
Response
|
||||
end
|
||||
|
||||
def code
|
||||
response.code.to_i
|
||||
end
|
||||
|
||||
def inspect
|
||||
inspect_id = "%x" % (object_id * 2)
|
||||
%(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
|
||||
end
|
||||
|
||||
CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
|
||||
|
||||
CODES_TO_OBJ.each do |response_code, klass|
|
||||
name = klass.name.sub("Net::HTTP", '')
|
||||
define_method("#{underscore(name)}?") do
|
||||
klass === response
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to?(name)
|
||||
return true if [:request, :response, :parsed_response, :body, :headers].include?(name)
|
||||
parsed_response.respond_to?(name) || response.respond_to?(name)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
if parsed_response.respond_to?(name)
|
||||
parsed_response.send(name, *args, &block)
|
||||
elsif response.respond_to?(name)
|
||||
response.send(name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'httparty/response/headers'
|
|
@ -0,0 +1,31 @@
|
|||
module HTTParty
|
||||
class Response #:nodoc:
|
||||
class Headers
|
||||
include ::Net::HTTPHeader
|
||||
|
||||
def initialize(header = {})
|
||||
@header = header
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@header == other
|
||||
end
|
||||
|
||||
def inspect
|
||||
@header.inspect
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
if @header.respond_to?(name)
|
||||
@header.send(name, *args, &block)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to?(method)
|
||||
super || @header.respond_to?(method)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module HTTParty
|
||||
VERSION = "0.9.0"
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
<posts user="jnunemaker" tag="ruby">
|
||||
<post href="http://roxml.rubyforge.org/" hash="19bba2ab667be03a19f67fb67dc56917" description="ROXML - Ruby Object to XML Mapping Library" tag="ruby xml gems mapping" time="2008-08-09T05:24:20Z" others="56" extended="ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes."/>
|
||||
<post href="http://code.google.com/p/sparrow/" hash="1df8a7cb9e8960992556518c0ea0d146" description="sparrow - Google Code" tag="ruby sparrow memcache queue" time="2008-08-06T15:07:24Z" others="115" extended="Sparrow is a really fast lightweight queue written in Ruby that speaks memcache. That means you can use Sparrow with any memcached client library (Ruby or otherwise)."/>
|
||||
<post href="http://code.google.com/p/query-reviewer/" hash="963187e8bf350ae42e21eee13a2bef07" description="query-reviewer - Google Code" tag="rails ruby railstips plugins database optimization" time="2008-08-04T21:50:14Z" others="180" extended="This rails plugin not only runs "EXPLAIN" before each of your select queries in development, but provides a small DIV in the rendered output of each page with the summary of query warnings that it analyzed."/>
|
||||
<post href="http://dev.zeraweb.com/introducing-functor" hash="2cdd545934bd37ae6f4829c51b3041c5" description="dev.zeraweb.com: Introducing Functor" tag="ruby methods gems railstips" time="2008-08-04T21:46:47Z" others="61" extended="Really cool ruby lib for overloading method definitions. I can think of a few places this would be handy."/>
|
||||
<post href="http://prawn.majesticseacreature.com/" hash="92764e019de7553b4cd38017e42e4aaa" description="prawn.majesticseacreature.com" tag="pdf ruby railstips" time="2008-08-04T21:26:20Z" others="237" extended="pure ruby pdf generation library."/>
|
||||
<post href="http://meme-rocket.com/2006/09/28/ruby-moduleinclude-at-odds-with-duck-typing/" hash="4ce96c7c237161819e9625737c22b462" description="Bill Burcham’s memeRocket :: Ruby Module#include at Odds with Duck Typing." tag="ruby railstips enumerable comparable" time="2008-08-03T16:09:24Z" others="3" extended="How to build your own enumerable and comparable objects in ruby. This article is old but just came across it and found it handy."/>
|
||||
<post href="http://bl.ogtastic.com/archives/2008/7" hash="6bebd138c037d7d7c88a7046ca03f671" description="The right way to do something you should never do" tag="juggernaut observers rails flash ruby" time="2008-08-03T03:50:58Z" others="0" extended="Example of how to use juggernaut with an observer."/>
|
||||
<post href="http://ncavig.com/blog/?page_id=8" hash="55450d103d6e2dd609b203ad133d751f" description="Nic’s Notions » Juggernaut Tutorials" tag="juggernaut rails ruby flash plugins server chat" time="2008-08-03T02:26:39Z" others="30" extended="Several juggernaut tutorials."/>
|
||||
<post href="http://blog.labnotes.org/2008/05/05/distributed-twitter-client-in-20-lines-of-code/" hash="7c2a36292db109b144036a02eb3f46b7" description="Labnotes » Distributed Twitter Client in 20 lines of code" tag="xmpp ruby jabber xmpp4r" time="2008-08-01T18:16:23Z" others="18" extended="Cool little snippet of xmpp goodness to check your buddies status messages."/>
|
||||
<post href="http://labs.reevoo.com/plugins/beanstalk-messaging" hash="d100c10208acbf5e954320a5577838d9" description="reevoolabs - Beanstalk Messaging" tag="railstips messaging queue rails ruby" time="2008-07-28T02:57:00Z" others="33" extended="Good write up on beanstalk"/>
|
||||
<post href="http://www.slideshare.net/guest807bb2/rubyfringe?src=embed" hash="c3dc3b940dbe25e39737240b4e1ab071" description="Rockstar Memcached" tag="memcached performance caching ruby rails railstips" time="2008-07-28T02:30:50Z" others="11" extended="Killer presentation on memcached by Tobi of Shopify."/>
|
||||
<post href="http://www.igvita.com/2008/07/22/unix-signals-for-live-debugging/" hash="288054a38d870b15bdf060ed5c6b2a2e" description="Unix Signals for Live Debugging - igvita.com" tag="ruby signals unix debugging signal railstips" time="2008-07-27T04:53:00Z" others="86" extended="I've known how to kill processes and such but never quite understood kill. Ilya Grigorik explains not only how to send those signals but how to use them in your scripts to change the way they behave on the fly. Very cool."/>
|
||||
<post href="http://www.rubyinside.com/redcloth-4-released-962.html" hash="b3db9b84940ce550e26a560b83eb2f66" description="RedCloth 4.0 Released: 40x Faster Textile Rendering" tag="textile ruby gems railstips" time="2008-07-27T04:42:29Z" others="20" extended="Redcloth gets some serious love. It's now much faster. Sweet!"/>
|
||||
<post href="http://code.google.com/p/rubycas-server/" hash="b532ea5933e4eba76c44823e17fecd31" description="rubycas-server - Google Code" tag="sso authentication cas ruby" time="2008-07-22T17:04:09Z" others="132" extended="RubyCAS-Server provides a single sign-on solution for web applications, implementing the server-end of JA-SIG's CAS protocol."/>
|
||||
<post href="http://reinh.com/blog/2008/07/14/a-thinking-mans-sphinx.html" hash="033d72ac54d8c722618383e0e2aa18ff" description="ReinH — A Thinking Man's Sphinx" tag="rails railstips sphinx search ruby" time="2008-07-17T19:34:59Z" others="142" extended="A guide to the two sphynx plugins: ultrasphynx and thinksphynx and why you should choose one or the other."/>
|
||||
<post href="http://www.rubyinside.com/ruby-xml-crisis-over-libxml-0-8-0-released-955.html" hash="70490d9786f09db5ba5f7904f88d304c" description="libxml-ruby 0.8.0 Released: Ruby Gets Fast, Reliable XML Processing At Last" tag="libxml xml ruby gems" time="2008-07-17T18:22:23Z" others="55" extended="lib xml gets an update and now it's really fast."/>
|
||||
<post href="http://github.com/RISCfuture/autumn/tree/master" hash="9b47db4bf59da2009642f4084e3113a2" description="autumn at master — GitHub" tag="irc ruby gems" time="2008-07-17T18:20:19Z" others="18" extended="Easy, fresh, feature-rich IRC bots in Ruby"/>
|
||||
<post href="http://groups.google.com/group/datamapper/browse_thread/thread/d33fbb20e41fad04" hash="4403898c92b37788f002ad6d79a66b68" description="New Finder Syntax (before 1.0) -" tag="railstips ruby datamapper" time="2008-07-05T20:42:27Z" others="1" extended="really cool idea for conditions in datamapper. even if you don't use datamapper, read this as it's sweet."/>
|
||||
<post href="http://codeclimber.blogspot.com/2008/06/using-ruby-for-imap-with-gmail.html" hash="33bbf2492beac5fbf1fc167014060067" description="CodeClimber: using Ruby for IMAP with Gmail" tag="email gems gmail google imap rails railstips ruby" time="2008-07-05T20:06:47Z" others="118" extended="how to check gmail using ruby's IMAP libraries. the key is to use the login method instead of the authenticate one."/>
|
||||
<post href="http://xullicious.blogspot.com/2008/07/updated-curb-multi-interface-patch.html" hash="f95dcc012bdc13bc26bace3ceed10656" description="Xul for thought: Updated curb multi interface patch" tag="curl ruby http" time="2008-07-03T21:52:45Z" others="1" extended="Really cool multi curl stuff to rapidly hit urls."/>
|
||||
</posts>
|
||||
<!-- fe04.api.del.ac4.yahoo.net uncompressed/chunked Sat Aug 9 00:20:11 PDT 2008 -->
|
|
@ -0,0 +1,3 @@
|
|||
<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><style>body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}#gbar{height:22px;padding-left:2px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#gbi,#gbs{background:#fff;left:0;position:absolute;top:24px;visibility:hidden;z-index:1000}#gbi{border:1px solid;border-color:#c9d7f1 #36c #36c #a2bae7;z-index:1001}#guser{padding-bottom:7px !important}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.73em;vertical-align:top}#gbar{float:left}}.gb2{display:block;padding:.2em .5em}a.gb1,a.gb2,a.gb3{color:#00c !important}.gb2,.gb3{text-decoration:none}a.gb2:hover{background:#36c;color:#fff !important}</style><script>window.google={kEI:"Zuk6ScOkLKHCMrrttckF",kEXPI:"17259,19124,19314",kHL:"en"};
|
||||
google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};function sf(){document.f.q.focus()}
|
||||
window.gbar={};(function(){var b=window.gbar,f,h;b.qs=function(a){var c=window.encodeURIComponent&&(document.forms[0].q||"").value;if(c)a.href=a.href.replace(/([?&])q=[^&]*|$/,function(i,g){return(g||"&")+"q="+encodeURIComponent(c)})};function j(a,c){a.visibility=h?"hidden":"visible";a.left=c+"px"}b.tg=function(a){a=a||window.event;var c=0,i,g=window.navExtra,d=document.getElementById("gbi"),e=a.target||a.srcElement;a.cancelBubble=true;if(!f){f=document.createElement(Array.every||window.createPopup?"iframe":"div");f.frameBorder="0";f.src="#";d.parentNode.appendChild(f).id="gbs";if(g)for(i in g)d.insertBefore(g[i],d.firstChild).className="gb2";document.onclick=b.close}if(e.className!="gb3")e=e.parentNode;do c+=e.offsetLeft;while(e=e.offsetParent);j(d.style,c);f.style.width=d.offsetWidth+"px";f.style.height=d.offsetHeight+"px";j(f.style,c);h=!h};b.close=function(a){h&&b.tg(a)}})();</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="sf();if(document.images)new Image().src='/images/nav_logo3.png'" topmargin=3 marginheight=3><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.com/imghp?hl=en&tab=wi" onclick=gbar.qs(this) class=gb1>Images</a> <a href="http://maps.google.com/maps?hl=en&tab=wl" onclick=gbar.qs(this) class=gb1>Maps</a> <a href="http://news.google.com/nwshp?hl=en&tab=wn" onclick=gbar.qs(this) class=gb1>News</a> <a href="http://www.google.com/prdhp?hl=en&tab=wf" onclick=gbar.qs(this) class=gb1>Shopping</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.com/intl/en/options/" onclick="this.blur();gbar.tg(event);return !1" class=gb3><u>more</u> <small>▼</small></a><div id=gbi> <a href="http://video.google.com/?hl=en&tab=wv" onclick=gbar.qs(this) class=gb2>Video</a> <a href="http://groups.google.com/grphp?hl=en&tab=wg" onclick=gbar.qs(this) class=gb2>Groups</a> <a href="http://books.google.com/bkshp?hl=en&tab=wp" onclick=gbar.qs(this) class=gb2>Books</a> <a href="http://scholar.google.com/schhp?hl=en&tab=ws" onclick=gbar.qs(this) class=gb2>Scholar</a> <a href="http://finance.google.com/finance?hl=en&tab=we" onclick=gbar.qs(this) class=gb2>Finance</a> <a href="http://blogsearch.google.com/?hl=en&tab=wb" onclick=gbar.qs(this) class=gb2>Blogs</a> <div class=gb2><div class=gbd></div></div> <a href="http://www.youtube.com/?hl=en&tab=w1" onclick=gbar.qs(this) class=gb2>YouTube</a> <a href="http://www.google.com/calendar/render?hl=en&tab=wc" class=gb2>Calendar</a> <a href="http://picasaweb.google.com/home?hl=en&tab=wq" onclick=gbar.qs(this) class=gb2>Photos</a> <a href="http://docs.google.com/?hl=en&tab=wo" class=gb2>Documents</a> <a href="http://www.google.com/reader/view/?hl=en&tab=wy" class=gb2>Reader</a> <a href="http://sites.google.com/?hl=en&tab=w3" class=gb2>Sites</a> <div class=gb2><div class=gbd></div></div> <a href="http://www.google.com/intl/en/options/" class=gb2>even more »</a></div> </nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><div align=right id=guser style="font-size:84%;padding:0 0 4px" width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a> | <a href="https://www.google.com/accounts/Login?continue=http://www.google.com/&hl=en">Sign in</a></nobr></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ALL/images/logo.gif" width=276><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%> </td><td align=center nowrap><input name=hl type=hidden value=en><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 title="Google Search" value=""><br><input name=btnG type=submit value="Google Search"><input name=btnI type=submit value="I'm Feeling Lucky"></td><td nowrap width=25%><font size=-2> <a href=/advanced_search?hl=en>Advanced Search</a><br> <a href=/preferences?hl=en>Preferences</a><br> <a href=/language_tools?hl=en>Language Tools</a></font></td></tr></table></form><br><br><font size=-1><a href="/intl/en/ads/">Advertising Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a></font><p><font size=-2>©2008 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center></body><script>if(google.y)google.y.first=[];window.setTimeout(function(){var xjs=document.createElement('script');xjs.src='/extern_js/f/CgJlbhICdXMgACswCjgMLCswDjgCLCswGDgDLA/8MIofMT_4o8.js';document.getElementsByTagName('head')[0].appendChild(xjs)},0);google.y.first.push(function(){google.ac.i(document.f,document.f.q,'','')})</script></html>
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ -d "generated" ] ; then
|
||||
echo >&2 "error: 'generated' directory already exists. Delete it first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir generated
|
||||
|
||||
# Generate the CA private key and certificate
|
||||
openssl req -batch -subj '/CN=INSECURE Test Certificate Authority' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/ca.key -nodes -out generated/ca.crt
|
||||
|
||||
# Create symlinks for ssl_ca_path
|
||||
c_rehash generated
|
||||
|
||||
# Generate the server private key and self-signed certificate
|
||||
openssl req -batch -subj '/CN=localhost' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/server.key -nodes -out generated/selfsigned.crt
|
||||
|
||||
# Generate certificate signing request with bogus hostname
|
||||
openssl req -batch -subj '/CN=bogo' -new -days 999999 -key generated/server.key -nodes -out generated/bogushost.csr
|
||||
|
||||
# Sign the certificate requests
|
||||
openssl x509 -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/selfsigned.crt -out generated/server.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999
|
||||
openssl x509 -req -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/bogushost.csr -out generated/bogushost.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999
|
||||
|
||||
# Remove certificate signing requests
|
||||
rm -f generated/*.csr
|
||||
|
16
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/1fe462c2.0
vendored
Normal file
16
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/1fe462c2.0
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV
|
||||
BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy
|
||||
MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU
|
||||
ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
|
||||
gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr
|
||||
9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H
|
||||
Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB
|
||||
jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz
|
||||
6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg
|
||||
Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN
|
||||
BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E
|
||||
gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR
|
||||
cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp
|
||||
pw==
|
||||
-----END CERTIFICATE-----
|
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/bogushost.crt
vendored
Normal file
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/bogushost.crt
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICBTCCAW6gAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF
|
||||
Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa
|
||||
GA80NzQ4MDkxNTEzNDYyM1owDzENMAsGA1UEAxMEYm9nbzCBnzANBgkqhkiG9w0B
|
||||
AQEFAAOBjQAwgYkCgYEAr6b0ZBrRrVvPmPbQv36Jnj5jv00ZkhimXrmbv9Z1AdIZ
|
||||
WSsBpMd8TP7exE5OR5/DaxKmiZqVskgRyRkLm52/Dkt7Ncrzr5I3unHnMqsAv/28
|
||||
5fGlYoRxnkCGMse/6NOFgCemRFw/bglxPNAGrFYKStameBRbCm0dCgtlvcwzdf8C
|
||||
AwEAAaNQME4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUddLPFtGmb0aFWbTl2kAo
|
||||
xD+fd6kwHwYDVR0jBBgwFoAUy0Lz6RgmtpywlBOXdPABQArp358wDQYJKoZIhvcN
|
||||
AQEFBQADgYEAosqpPVsFu6cOIhGFT85Y1wwRUaihO0vWO7ghBU5ScuRU3tuvyJDZ
|
||||
Z/HoAMXV6XZjVZzRosjtPjFbyWkZYjUqJJRMyEaRiGArWe6urKLzwnD6R9O3eNa5
|
||||
7bgFhzZ5WBldJmtq4A3oNqBuvgZkYM6NVKvS4UoakkTliHB21/mDOSY=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV
|
||||
BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy
|
||||
MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU
|
||||
ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
|
||||
gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr
|
||||
9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H
|
||||
Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB
|
||||
jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz
|
||||
6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg
|
||||
Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN
|
||||
BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E
|
||||
gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR
|
||||
cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp
|
||||
pw==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXgIBAAKBgQDeWQFx3fnaqIgjOqfK+8mPn1zHV2fMzKOe5orZxEfjbSsF+6Qs
|
||||
TYxs5Wv2dir/sJ2OpekTy4UAX5RNIgroxZn9uJ2SvbF39638J7alUhXEf6u3eknP
|
||||
fBmELcdjP4dTgIPaIj3ADOxvqYxXuZ3V+OVh+KvhIEYY9ORypQlSnb+1AwIDAQAB
|
||||
AoGBAL147VFCDlM1gGU865V+wIFCFQbNxedwjxGuda4io/v6oEoF6R3Tq5F0Y27v
|
||||
va6Lq4fOe/LhYGI0EKU2GEPJd3F2wA21r+81InPKAkqYI5CDQtKDDNLviur8ZVKF
|
||||
i3UzutjeYoCqmWeHaKPD6w5DtqeBieem7LTWRyXlFtHZV/nBAkEA8nsMOSd1+JTm
|
||||
ZT4HDsEFQrN8mIFUUioFSHPut2CwzvTEW+hTkLQiog3bua4n7uQOFImR63X9qMsh
|
||||
IjZRJQNmowJBAOq+mQdnRWYKl0SYb++Eb3uW6L4h1zsW375+caKo9omtpeqDW/y0
|
||||
BWyY0q4DPkm3yU26Yr+b2JijISrml9/8PiECQQDHuXyG8y7jktn3GFE94NURbL+6
|
||||
6gPnLX9ufzdoSjc4MDowrbtvHEDOlHWgioeP6L6EQhA0DtrhlnbzNCRARX3bAkEA
|
||||
jQOsF+dwqAjKr/lGnMKY2cxgyf64NZXbGKsKhmUrnK9E0SjR9G8MJx1yyffGzi/q
|
||||
bJf/xAzRw3eTcBsPtwznIQJAHq5MOK7oaUuO+6cbsZYpOYOOkKIvDLiOtdSr7LTI
|
||||
DziH/fpzB0VhCmFhhEQwHhlB4t3m66A9TelHmhrCDsIaLA==
|
||||
-----END RSA PRIVATE KEY-----
|
14
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/selfsigned.crt
vendored
Normal file
14
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/selfsigned.crt
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICHTCCAYagAwIBAgIJALT/G+ylQljIMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
|
||||
BAMTCWxvY2FsaG9zdDAgFw0xMDEwMjAxMzQ2MjNaGA80NzQ4MDkxNTEzNDYyM1ow
|
||||
FDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||
gQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGkx3xM/t7ETk5H
|
||||
n8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVihHGeQIYyx7/o
|
||||
04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQABo3UwczAdBgNV
|
||||
HQ4EFgQUddLPFtGmb0aFWbTl2kAoxD+fd6kwRAYDVR0jBD0wO4AUddLPFtGmb0aF
|
||||
WbTl2kAoxD+fd6mhGKQWMBQxEjAQBgNVBAMTCWxvY2FsaG9zdIIJALT/G+ylQljI
|
||||
MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAlOCBO54S88mD3VYviER6
|
||||
V+lkd7iWmdas2wUUDeMKA9CxnirWi7ne2U7wQH/5FJ1j3ImSfjb4h/98xiVJE84e
|
||||
Ld7mb61g/M4g4b62kt0HK8/cGUxfuz5zwIfi28qJq3ow6AFEq1fywbJvUAnnamwU
|
||||
cZF/qoVfJhus2mXjYc4hFWg=
|
||||
-----END CERTIFICATE-----
|
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/server.crt
vendored
Normal file
13
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/server.crt
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICCjCCAXOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF
|
||||
Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa
|
||||
GA80NzQ4MDkxNTEzNDYyM1owFDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqG
|
||||
SIb3DQEBAQUAA4GNADCBiQKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/
|
||||
1nUB0hlZKwGkx3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecy
|
||||
qwC//bzl8aVihHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9
|
||||
zDN1/wIDAQABo1AwTjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBR10s8W0aZvRoVZ
|
||||
tOXaQCjEP593qTAfBgNVHSMEGDAWgBTLQvPpGCa2nLCUE5d08AFACunfnzANBgkq
|
||||
hkiG9w0BAQUFAAOBgQCR4Oor0YAvK0tNFrOLtqmC6D0F5IYCyu7komk7JGn9L4nn
|
||||
7VyVxd4MXdc1r1v+WP5JtnA9ZjMmEmH9gl4gwR/Cu+TMkArsq0Z8mREOLNL8pwpx
|
||||
Zxgk0CwacYR9RQcpuJ9nSDzVoO5ecYkb5C9q7gwgqbmCzr7oz/rwTqRwiUZCVQ==
|
||||
-----END CERTIFICATE-----
|
15
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/server.key
vendored
Normal file
15
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/ssl/generated/server.key
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGk
|
||||
x3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVi
|
||||
hHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQAB
|
||||
AoGALIdgkTgTS6VovVhklwcXEBy04LxE7Tp+gqj/COTvCKUgc/BpHELOCh7ajl1j
|
||||
jti7i5tQyLV9mZKXn6lPvgWBd0w+p6VhM4NFA97CoodEJm2ckFC9zUABCh9dOpbm
|
||||
8KzF7hdpYWgJJchwwZ60tbcP7K1DkiNX6Kk9qKQEWvitMBECQQDpOSzzLldcEU9l
|
||||
ze/nG2+rf6ecaPnKeafY8R2qVils8I7ZJAW3+0bNT5gQs7rT7aWo8vMvrXq++lWb
|
||||
JkNV6hK9AkEAwM5wsmg7REmAaDwgUBq5mNt963/uG2ihAODFS70lYT23UYl5Y3rD
|
||||
s3qU4ntG4DvWIQgPdwdstzDh9fMBVXa1awJBAID1WoOE5k1ETRDP1I2HwDGmPnng
|
||||
Ge75YfQ1LuAXEITqZzJuFrNqv/Waw0zI9M9moqlO3WVJmYusRFWrzKPe8EkCQEwC
|
||||
FlN+275z63csHOD3aCtmfCGW8VtEyBP8iErvagkHt3khZQVepD/hF0ihqLNFY4jq
|
||||
EI6wEp+1WZ8ICYKTpbkCQQDhl5QLdy5Xo3k3agCnB9nktSzs2iqFvsGvfOAW4628
|
||||
iThKTNua6bBvbdiG0Vh2Sv0XBYVJoHB3WnTVgFyPJaaF
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,9 @@
|
|||
[ca]
|
||||
basicConstraints=critical,CA:true
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
|
||||
[cert]
|
||||
basicConstraints=critical,CA:false
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,403 @@
|
|||
<statuses type="array">
|
||||
<status>
|
||||
<created_at>Sun Dec 07 00:36:16 +0000 2008</created_at>
|
||||
<id>1042729116</id>
|
||||
<text>@sebbo Outlook not so good</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id>1042716367</in_reply_to_status_id>
|
||||
<in_reply_to_user_id>2989541</in_reply_to_user_id>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17656026</id>
|
||||
<name>Magic 8 Bot</name>
|
||||
<screen_name>magic8bot</screen_name>
|
||||
<description>ask me a question</description>
|
||||
<location></location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>90</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729115</id>
|
||||
<text>Azdel Slade :friends from midian city http://bloghud.com/id/27312</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>801094</id>
|
||||
<name>BlogHUD</name>
|
||||
<screen_name>bloghud</screen_name>
|
||||
<description />
|
||||
<location />
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/25235272/bloghud_twitter_normal.jpg</profile_image_url>
|
||||
<url />
|
||||
<protected>false</protected>
|
||||
<followers_count>313</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729114</id>
|
||||
<text>Reading: "The Reckoning - Debt Watchdogs - Tamed or Caught Napping? - Series - NYTimes.com" ( http://tinyurl.com/5754s6 )</text>
|
||||
<source>twitthat</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>3512101</id>
|
||||
<name>bill</name>
|
||||
<screen_name>niubi</screen_name>
|
||||
<description>in beijing learning socialism 2 prepare 4 return 2 us</description>
|
||||
<location>beijing</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53292616/realtwitterers_normal.jpg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>710</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729113</id>
|
||||
<text>Fianlly done and headed home!</text>
|
||||
<source>sms</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>13186842</id>
|
||||
<name>Okthirddayfan</name>
|
||||
<screen_name>Okthirddayfan</screen_name>
|
||||
<description></description>
|
||||
<location>Oklahoma!</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/61414367/mecropped_normal.jpg</profile_image_url>
|
||||
<url>http://thirddaypix.blogspot.com/</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>68</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:16 +0000 2008</created_at>
|
||||
<id>1042729112</id>
|
||||
<text>Adobe Flashplayer 10 and Debug versions: http://www.adobe.com/support/flashplayer/downloads.html</text>
|
||||
<source>toro</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>15243380</id>
|
||||
<name>cbrueggenolte</name>
|
||||
<screen_name>cbrueggenolte</screen_name>
|
||||
<description>27, Male, Mac Geek, Developer Java &amp; Flex &amp; Air</description>
|
||||
<location>Aachen</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/55929263/214508011845f026bfd407c_normal.jpg</profile_image_url>
|
||||
<url>http://my.opera.com/carstenbrueggenolte</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>16</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729111</id>
|
||||
<text>Done and done.</text>
|
||||
<source>twitterrific</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>10978752</id>
|
||||
<name>Sergey Safonov</name>
|
||||
<screen_name>iron_Lung</screen_name>
|
||||
<description>I have my fingers in many pies.</description>
|
||||
<location>Moscow</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/57841057/eat38_normal.gif</profile_image_url>
|
||||
<url>http://www.flickr.com/photos/iron_Lung</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>11</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729110</id>
|
||||
<text>Veja a tabela de preços do Acquaplay da Tecnisa aqui:http://tinyurl.com/acquaplaypreco</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>13735402</id>
|
||||
<name>Tecnisa S.A</name>
|
||||
<screen_name>Tecnisa</screen_name>
|
||||
<description>Mais construtora por m2</description>
|
||||
<location>Faria Lima, 3144 - SP</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/56572222/logo_normal.jpg</profile_image_url>
|
||||
<url>http://www.tecnisa.com.br</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>77</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:16 +0000 2008</created_at>
|
||||
<id>1042729108</id>
|
||||
<text>devin harris has the flu. always have the memory of jordan scoring 50 on the knicks at the garden with the flu</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17930773</id>
|
||||
<name>24 Seconds to Shoot</name>
|
||||
<screen_name>NBA24sts</screen_name>
|
||||
<description>NBA handicapping insight and analysis.</description>
|
||||
<location>las vegas</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/66593862/fresno_normal.jpg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>1</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:16 +0000 2008</created_at>
|
||||
<id>1042729105</id>
|
||||
<text>At Brandon and Shannon's holiday party..</text>
|
||||
<source>twitterberry</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>5388602</id>
|
||||
<name>Mike J. (Telligent)</name>
|
||||
<screen_name>mjamrst</screen_name>
|
||||
<description>Video Game Account Manager</description>
|
||||
<location>Palo Alto, CA</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/66375174/Thanksgiving_11272008-048_normal.jpg</profile_image_url>
|
||||
<url>http://www.telligent.com</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>225</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729104</id>
|
||||
<text>Xinhua: Forty percent of Australian PM office' staff quit : CANBERRA, Dec. 7 (Xinhua) -- Only.. http://tinyurl.com/5gwotd</text>
|
||||
<source>twitterfeed</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>11566502</id>
|
||||
<name>Headline News</name>
|
||||
<screen_name>headlinenews</screen_name>
|
||||
<description></description>
|
||||
<location></location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/41784602/1890_wires_normal.jpg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>575</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729101</id>
|
||||
<text>@hilarycassman soo funnny</text>
|
||||
<source>sms</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id>1042725825</in_reply_to_status_id>
|
||||
<in_reply_to_user_id>17644455</in_reply_to_user_id>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17887548</id>
|
||||
<name>katieballss</name>
|
||||
<screen_name>katieballss</screen_name>
|
||||
<description></description>
|
||||
<location></location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/66523737/th_Photo87_normal.jpg</profile_image_url>
|
||||
<url>http://www.myspace.com/xxpeachxx101</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>23</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729100</id>
|
||||
<text>d'ora in poi, oltre al ferragosto, odiera' anche il natale e tutto il mese che ci gira intorno.. =.=''</text>
|
||||
<source>mobile</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>9719482</id>
|
||||
<name>trotto</name>
|
||||
<screen_name>trotto</screen_name>
|
||||
<description>sociologo di formazione... uno dei tanti attivisti! :)</description>
|
||||
<location>Fano - Italy</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/55603933/mybob-calimetux-1526_normal.png</profile_image_url>
|
||||
<url>http://trotto1308.netsons.org/wordpress/</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>98</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729099</id>
|
||||
<text>Came across an ad on another site with a redneck looking santa... said "Bust Santa's zit and win a free ipod." Umm... disturbing much?</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>9937182</id>
|
||||
<name>froggybluesock</name>
|
||||
<screen_name>froggybluesock</screen_name>
|
||||
<description></description>
|
||||
<location>Indiana</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/35393032/about_me_normal.jpg</profile_image_url>
|
||||
<url>http://www.footprintsonthemoon.com</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>82</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:17 +0000 2008</created_at>
|
||||
<id>1042729098</id>
|
||||
<text>nothing</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17932339</id>
|
||||
<name>treblehook</name>
|
||||
<screen_name>treblehook</screen_name>
|
||||
<description />
|
||||
<location />
|
||||
<profile_image_url>http://static.twitter.com/images/default_profile_normal.png</profile_image_url>
|
||||
<url />
|
||||
<protected>false</protected>
|
||||
<followers_count>0</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729095</id>
|
||||
<text>Setting up my new Windows Live profile</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17906075</id>
|
||||
<name>Mark_Layton</name>
|
||||
<screen_name>Mark_Layton</screen_name>
|
||||
<description />
|
||||
<location />
|
||||
<profile_image_url>http://static.twitter.com/images/default_profile_normal.png</profile_image_url>
|
||||
<url />
|
||||
<protected>false</protected>
|
||||
<followers_count>2</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729092</id>
|
||||
<text>me voy a sobar, a ver si mañana estoy mejor, wenas noches a tod@s</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>14062655</id>
|
||||
<name>tmaniak</name>
|
||||
<screen_name>tmaniak</screen_name>
|
||||
<description></description>
|
||||
<location></location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/51680481/BF-109_normal.jpg</profile_image_url>
|
||||
<url>http://dhost.info/tmaniak</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>10</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729090</id>
|
||||
<text>バイト延長戦入りましたー 店長が遅刻ってどうなんだ。しかも何回も</text>
|
||||
<source>natsuliphone</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>15618846</id>
|
||||
<name>kabayaki</name>
|
||||
<screen_name>kabayaki</screen_name>
|
||||
<description>FPS(L4D、TF2、CS:S、BF)、TPS、RCG、マンガ、アニメ、デジモノが好きなとある学生</description>
|
||||
<location>tokyo</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/57305902/184_normal.jpg</profile_image_url>
|
||||
<url>http://kabayakiya.blog43.fc2.com/</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>20</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:13 +0000 2008</created_at>
|
||||
<id>1042729089</id>
|
||||
<text>just drove to southern california and joy of children hugging grandparents made it all worthwhile. heading to imedia in la quinta tomorrow.</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>1630261</id>
|
||||
<name>mark silva</name>
|
||||
<screen_name>marksilva</screen_name>
|
||||
<description>digital media http://realbranding.com Principal, Managing Director</description>
|
||||
<location>often san francisco</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/29807902/silvasimpson3th_normal.jpg</profile_image_url>
|
||||
<url>http://marksilva.com</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>497</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:14 +0000 2008</created_at>
|
||||
<id>1042729088</id>
|
||||
<text>@wholefoods would love to have a juicebar in one of your cambridge or boston locations</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id>1041125103</in_reply_to_status_id>
|
||||
<in_reply_to_user_id>15131310</in_reply_to_user_id>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>15856582</id>
|
||||
<name>Maura McGovern</name>
|
||||
<screen_name>mmcgovern</screen_name>
|
||||
<description>photographer with a day job in venture capital; obsessed with design blogs, long walks, yoga, social networking, people watching. tea and music are essential!</description>
|
||||
<location>Boston</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/66110383/DSCN1740_normal.JPG</profile_image_url>
|
||||
<url>http://lefteyephotography.blogspot.com</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>244</followers_count>
|
||||
</user>
|
||||
</status><status>
|
||||
<created_at>Sun Dec 07 00:36:15 +0000 2008</created_at>
|
||||
<id>1042729087</id>
|
||||
<text>Going over the Advent lists.</text>
|
||||
<source>web</source>
|
||||
<truncated>false</truncated>
|
||||
<in_reply_to_status_id />
|
||||
<in_reply_to_user_id />
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>17122107</id>
|
||||
<name>gsusan</name>
|
||||
<screen_name>gsusan</screen_name>
|
||||
<description>US American writer/sister/daughter/aunt/woman from New England living in SoCal.</description>
|
||||
<location>San Diego, CA USA</location>
|
||||
<profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/63951854/susan_ocracoke_normal.jpg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>6</followers_count>
|
||||
</user>
|
||||
</status>
|
||||
</statuses>
|
2
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/undefined_method_add_node_for_nil.xml
vendored
Normal file
2
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/fixtures/undefined_method_add_node_for_nil.xml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entities total="0" results="0" page="1" page-size="25" href="https://s3-sandbox.parature.com/api/v1/5578/5633/Account" />
|
206
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/httparty/connection_adapter_spec.rb
vendored
Normal file
206
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/httparty/connection_adapter_spec.rb
vendored
Normal file
|
@ -0,0 +1,206 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe HTTParty::ConnectionAdapter do
|
||||
|
||||
describe "initialization" do
|
||||
let(:uri) { URI 'http://www.google.com' }
|
||||
it "takes a URI as input" do
|
||||
HTTParty::ConnectionAdapter.new(uri)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError if the uri is nil" do
|
||||
expect { HTTParty::ConnectionAdapter.new(nil) }.to raise_error ArgumentError
|
||||
end
|
||||
|
||||
it "raises an ArgumentError if the uri is a String" do
|
||||
expect { HTTParty::ConnectionAdapter.new('http://www.google.com') }.to raise_error ArgumentError
|
||||
end
|
||||
|
||||
it "sets the uri" do
|
||||
adapter = HTTParty::ConnectionAdapter.new(uri)
|
||||
adapter.uri.should be uri
|
||||
end
|
||||
|
||||
it "also accepts an optional options hash" do
|
||||
HTTParty::ConnectionAdapter.new(uri, {})
|
||||
end
|
||||
|
||||
it "sets the options" do
|
||||
options = {:foo => :bar}
|
||||
adapter = HTTParty::ConnectionAdapter.new(uri, options)
|
||||
adapter.options.should be options
|
||||
end
|
||||
end
|
||||
|
||||
describe ".call" do
|
||||
it "generates an HTTParty::ConnectionAdapter instance with the given uri and options" do
|
||||
HTTParty::ConnectionAdapter.should_receive(:new).with(@uri, @options).and_return(stub(:connection => nil))
|
||||
HTTParty::ConnectionAdapter.call(@uri, @options)
|
||||
end
|
||||
|
||||
it "calls #connection on the connection adapter" do
|
||||
adapter = mock('Adapter')
|
||||
connection = mock('Connection')
|
||||
adapter.should_receive(:connection).and_return(connection)
|
||||
HTTParty::ConnectionAdapter.stub(:new => adapter)
|
||||
HTTParty::ConnectionAdapter.call(@uri, @options).should be connection
|
||||
end
|
||||
end
|
||||
|
||||
describe '#connection' do
|
||||
let(:uri) { URI 'http://www.google.com' }
|
||||
let(:options) { Hash.new }
|
||||
let(:adapter) { HTTParty::ConnectionAdapter.new(uri, options) }
|
||||
|
||||
describe "the resulting connection" do
|
||||
subject { adapter.connection }
|
||||
it { should be_an_instance_of Net::HTTP }
|
||||
|
||||
context "using port 80" do
|
||||
let(:uri) { URI 'http://foobar.com' }
|
||||
it { should_not use_ssl }
|
||||
end
|
||||
|
||||
context "when dealing with ssl" do
|
||||
let(:uri) { URI 'https://foobar.com' }
|
||||
|
||||
context "using port 443 for ssl" do
|
||||
let(:uri) { URI 'https://api.foo.com/v1:443' }
|
||||
it { should use_ssl }
|
||||
end
|
||||
|
||||
context "https scheme with default port" do
|
||||
it { should use_ssl }
|
||||
end
|
||||
|
||||
context "https scheme with non-standard port" do
|
||||
let(:uri) { URI 'https://foobar.com:123456' }
|
||||
it { should use_ssl }
|
||||
end
|
||||
|
||||
context "when ssl version is set" do
|
||||
let(:options) { {:ssl_version => :TLSv1} }
|
||||
|
||||
it "sets ssl version" do
|
||||
subject.ssl_version.should == :TLSv1
|
||||
end
|
||||
end if RUBY_VERSION > '1.9'
|
||||
end
|
||||
|
||||
context "when timeout is not set" do
|
||||
it "doesn't set the timeout" do
|
||||
http = mock("http", :null_object => true)
|
||||
http.should_not_receive(:open_timeout=)
|
||||
http.should_not_receive(:read_timeout=)
|
||||
Net::HTTP.stub(:new => http)
|
||||
|
||||
adapter.connection
|
||||
end
|
||||
end
|
||||
|
||||
context "when setting timeout" do
|
||||
context "to 5 seconds" do
|
||||
let(:options) { {:timeout => 5} }
|
||||
|
||||
its(:open_timeout) { should == 5 }
|
||||
its(:read_timeout) { should == 5 }
|
||||
end
|
||||
|
||||
context "and timeout is a string" do
|
||||
let(:options) { {:timeout => "five seconds"} }
|
||||
|
||||
it "doesn't set the timeout" do
|
||||
http = mock("http", :null_object => true)
|
||||
http.should_not_receive(:open_timeout=)
|
||||
http.should_not_receive(:read_timeout=)
|
||||
Net::HTTP.stub(:new => http)
|
||||
|
||||
adapter.connection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when debug_output" do
|
||||
let(:http) { Net::HTTP.new(uri) }
|
||||
before do
|
||||
Net::HTTP.stub(:new => http)
|
||||
end
|
||||
|
||||
context "is set to $stderr" do
|
||||
let(:options) { {:debug_output => $stderr} }
|
||||
it "has debug output set" do
|
||||
http.should_receive(:set_debug_output).with($stderr)
|
||||
adapter.connection
|
||||
end
|
||||
end
|
||||
|
||||
context "is not provided" do
|
||||
it "does not set_debug_output" do
|
||||
http.should_not_receive(:set_debug_output)
|
||||
adapter.connection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when providing proxy address and port' do
|
||||
let(:options) { {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080} }
|
||||
|
||||
it { should be_a_proxy }
|
||||
its(:proxy_address) { should == '1.2.3.4' }
|
||||
its(:proxy_port) { should == 8080 }
|
||||
|
||||
context 'as well as proxy user and password' do
|
||||
let(:options) do
|
||||
{:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080,
|
||||
:http_proxyuser => 'user', :http_proxypass => 'pass'}
|
||||
end
|
||||
its(:proxy_user) { should == 'user' }
|
||||
its(:proxy_pass) { should == 'pass' }
|
||||
end
|
||||
end
|
||||
|
||||
context "when providing PEM certificates" do
|
||||
let(:pem) { :pem_contents }
|
||||
let(:options) { {:pem => pem, :pem_password => "password"} }
|
||||
|
||||
context "when scheme is https" do
|
||||
let(:uri) { URI 'https://google.com' }
|
||||
let(:cert) { mock("OpenSSL::X509::Certificate") }
|
||||
let(:key) { mock("OpenSSL::PKey::RSA") }
|
||||
|
||||
before do
|
||||
OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(cert)
|
||||
OpenSSL::PKey::RSA.should_receive(:new).with(pem, "password").and_return(key)
|
||||
end
|
||||
|
||||
it "uses the provided PEM certificate " do
|
||||
subject.cert.should == cert
|
||||
subject.key.should == key
|
||||
end
|
||||
|
||||
it "will verify the certificate" do
|
||||
subject.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
|
||||
end
|
||||
end
|
||||
|
||||
context "when scheme is not https" do
|
||||
let(:uri) { URI 'http://google.com' }
|
||||
let(:http) { Net::HTTP.new(uri) }
|
||||
|
||||
before do
|
||||
Net::HTTP.stub(:new => http)
|
||||
OpenSSL::X509::Certificate.should_not_receive(:new).with(pem)
|
||||
OpenSSL::PKey::RSA.should_not_receive(:new).with(pem, "password")
|
||||
http.should_not_receive(:cert=)
|
||||
http.should_not_receive(:key=)
|
||||
end
|
||||
|
||||
it "has no PEM certificate " do
|
||||
subject.cert.should be_nil
|
||||
subject.key.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,70 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
||||
|
||||
describe HTTParty::CookieHash do
|
||||
before(:each) do
|
||||
@cookie_hash = HTTParty::CookieHash.new
|
||||
end
|
||||
|
||||
describe "#add_cookies" do
|
||||
describe "with a hash" do
|
||||
it "should add new key/value pairs to the hash" do
|
||||
@cookie_hash.add_cookies(:foo => "bar")
|
||||
@cookie_hash.add_cookies(:rofl => "copter")
|
||||
@cookie_hash.length.should eql(2)
|
||||
end
|
||||
|
||||
it "should overwrite any existing key" do
|
||||
@cookie_hash.add_cookies(:foo => "bar")
|
||||
@cookie_hash.add_cookies(:foo => "copter")
|
||||
@cookie_hash.length.should eql(1)
|
||||
@cookie_hash[:foo].should eql("copter")
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a string" do
|
||||
it "should add new key/value pairs to the hash" do
|
||||
@cookie_hash.add_cookies("first=one; second=two; third")
|
||||
@cookie_hash[:first].should == 'one'
|
||||
@cookie_hash[:second].should == 'two'
|
||||
@cookie_hash[:third].should == nil
|
||||
end
|
||||
|
||||
it "should overwrite any existing key" do
|
||||
@cookie_hash[:foo] = 'bar'
|
||||
@cookie_hash.add_cookies("foo=tar")
|
||||
@cookie_hash.length.should eql(1)
|
||||
@cookie_hash[:foo].should eql("tar")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with other class' do
|
||||
it "should error" do
|
||||
lambda {
|
||||
@cookie_hash.add_cookies(Array.new)
|
||||
}.should raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The regexen are required because Hashes aren't ordered, so a test against
|
||||
# a hardcoded string was randomly failing.
|
||||
describe "#to_cookie_string" do
|
||||
before(:each) do
|
||||
@cookie_hash.add_cookies(:foo => "bar")
|
||||
@cookie_hash.add_cookies(:rofl => "copter")
|
||||
@s = @cookie_hash.to_cookie_string
|
||||
end
|
||||
|
||||
it "should format the key/value pairs, delimited by semi-colons" do
|
||||
@s.should match(/foo=bar/)
|
||||
@s.should match(/rofl=copter/)
|
||||
@s.should match(/^\w+=\w+; \w+=\w+$/)
|
||||
end
|
||||
|
||||
it "should not include client side only cookies" do
|
||||
@cookie_hash.add_cookies(:path => "/")
|
||||
@s = @cookie_hash.to_cookie_string
|
||||
@s.should_not match(/path=\//)
|
||||
end
|
||||
end
|
||||
end
|
115
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/httparty/net_digest_auth_spec.rb
vendored
Normal file
115
vendor/ruby/1.9.1/gems/httparty-0.9.0/spec/httparty/net_digest_auth_spec.rb
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe Net::HTTPHeader::DigestAuthenticator do
|
||||
def setup_digest(response)
|
||||
digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa",
|
||||
"Circle Of Life", "GET", "/dir/index.html", response)
|
||||
digest.stub(:random).and_return("deadbeef")
|
||||
Digest::MD5.stub(:hexdigest) { |str| "md5(#{str})" }
|
||||
digest
|
||||
end
|
||||
|
||||
def authorization_header
|
||||
@digest.authorization_header.join(", ")
|
||||
end
|
||||
|
||||
|
||||
context "with an opaque value in the response header" do
|
||||
before do
|
||||
@digest = setup_digest({
|
||||
'www-authenticate' => 'Digest realm="myhost@testrealm.com", opaque="solid"'
|
||||
})
|
||||
end
|
||||
|
||||
it "should set opaque" do
|
||||
authorization_header.should include(%Q(opaque="solid"))
|
||||
end
|
||||
end
|
||||
|
||||
context "without an opaque valid in the response header" do
|
||||
before do
|
||||
@digest = setup_digest({
|
||||
'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
|
||||
})
|
||||
end
|
||||
|
||||
it "should not set opaque" do
|
||||
authorization_header.should_not include(%Q(opaque=))
|
||||
end
|
||||
end
|
||||
|
||||
context "with specified quality of protection (qop)" do
|
||||
before do
|
||||
@digest = setup_digest({
|
||||
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
|
||||
})
|
||||
end
|
||||
|
||||
it "should set prefix" do
|
||||
authorization_header.should =~ /^Digest /
|
||||
end
|
||||
|
||||
it "should set username" do
|
||||
authorization_header.should include(%Q(username="Mufasa"))
|
||||
end
|
||||
|
||||
it "should set digest-uri" do
|
||||
authorization_header.should include(%Q(uri="/dir/index.html"))
|
||||
end
|
||||
|
||||
it "should set qop" do
|
||||
authorization_header.should include(%Q(qop="auth"))
|
||||
end
|
||||
|
||||
it "should set cnonce" do
|
||||
authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
|
||||
end
|
||||
|
||||
it "should set nonce-count" do
|
||||
authorization_header.should include(%Q(nc="00000001"))
|
||||
end
|
||||
|
||||
it "should set response" do
|
||||
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
|
||||
authorization_header.should include(%Q(response="#{request_digest}"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "with unspecified quality of protection (qop)" do
|
||||
before do
|
||||
@digest = setup_digest({
|
||||
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"',
|
||||
})
|
||||
end
|
||||
|
||||
it "should set prefix" do
|
||||
authorization_header.should =~ /^Digest /
|
||||
end
|
||||
|
||||
it "should set username" do
|
||||
authorization_header.should include(%Q(username="Mufasa"))
|
||||
end
|
||||
|
||||
it "should set digest-uri" do
|
||||
authorization_header.should include(%Q(uri="/dir/index.html"))
|
||||
end
|
||||
|
||||
it "should not set qop" do
|
||||
authorization_header.should_not include(%Q(qop=))
|
||||
end
|
||||
|
||||
it "should not set cnonce" do
|
||||
authorization_header.should_not include(%Q(cnonce=))
|
||||
end
|
||||
|
||||
it "should not set nonce-count" do
|
||||
authorization_header.should_not include(%Q(nc=))
|
||||
end
|
||||
|
||||
it "should set response" do
|
||||
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))"
|
||||
authorization_header.should include(%Q(response="#{request_digest}"))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,171 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe HTTParty::Parser do
|
||||
describe ".SupportedFormats" do
|
||||
it "returns a hash" do
|
||||
HTTParty::Parser::SupportedFormats.should be_instance_of(Hash)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".call" do
|
||||
it "generates an HTTParty::Parser instance with the given body and format" do
|
||||
HTTParty::Parser.should_receive(:new).with('body', :plain).and_return(stub(:parse => nil))
|
||||
HTTParty::Parser.call('body', :plain)
|
||||
end
|
||||
|
||||
it "calls #parse on the parser" do
|
||||
parser = mock('Parser')
|
||||
parser.should_receive(:parse)
|
||||
HTTParty::Parser.stub(:new => parser)
|
||||
parser = HTTParty::Parser.call('body', :plain)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".formats" do
|
||||
it "returns the SupportedFormats constant" do
|
||||
HTTParty::Parser.formats.should == HTTParty::Parser::SupportedFormats
|
||||
end
|
||||
|
||||
it "returns the SupportedFormats constant for subclasses" do
|
||||
class MyParser < HTTParty::Parser
|
||||
SupportedFormats = {"application/atom+xml" => :atom}
|
||||
end
|
||||
MyParser.formats.should == {"application/atom+xml" => :atom}
|
||||
end
|
||||
end
|
||||
|
||||
describe ".format_from_mimetype" do
|
||||
it "returns a symbol representing the format mimetype" do
|
||||
HTTParty::Parser.format_from_mimetype("text/plain").should == :plain
|
||||
end
|
||||
|
||||
it "returns nil when the mimetype is not supported" do
|
||||
HTTParty::Parser.format_from_mimetype("application/atom+xml").should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe ".supported_formats" do
|
||||
it "returns a unique set of supported formats represented by symbols" do
|
||||
HTTParty::Parser.supported_formats.should == HTTParty::Parser::SupportedFormats.values.uniq
|
||||
end
|
||||
end
|
||||
|
||||
describe ".supports_format?" do
|
||||
it "returns true for a supported format" do
|
||||
HTTParty::Parser.stub(:supported_formats => [:json])
|
||||
HTTParty::Parser.supports_format?(:json).should be_true
|
||||
end
|
||||
|
||||
it "returns false for an unsupported format" do
|
||||
HTTParty::Parser.stub(:supported_formats => [])
|
||||
HTTParty::Parser.supports_format?(:json).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#parse" do
|
||||
before do
|
||||
@parser = HTTParty::Parser.new('body', :json)
|
||||
end
|
||||
|
||||
it "attempts to parse supported formats" do
|
||||
@parser.stub(:supports_format? => true)
|
||||
@parser.should_receive(:parse_supported_format)
|
||||
@parser.parse
|
||||
end
|
||||
|
||||
it "returns the unparsed body when the format is unsupported" do
|
||||
@parser.stub(:supports_format? => false)
|
||||
@parser.parse.should == @parser.body
|
||||
end
|
||||
|
||||
it "returns nil for an empty body" do
|
||||
@parser.stub(:body => '')
|
||||
@parser.parse.should be_nil
|
||||
end
|
||||
|
||||
it "returns nil for a nil body" do
|
||||
@parser.stub(:body => nil)
|
||||
@parser.parse.should be_nil
|
||||
end
|
||||
|
||||
it "returns nil for a 'null' body" do
|
||||
@parser.stub(:body => "null")
|
||||
@parser.parse.should be_nil
|
||||
end
|
||||
|
||||
it "returns nil for a body with spaces only" do
|
||||
@parser.stub(:body => " ")
|
||||
@parser.parse.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#supports_format?" do
|
||||
it "utilizes the class method to determine if the format is supported" do
|
||||
HTTParty::Parser.should_receive(:supports_format?).with(:json)
|
||||
parser = HTTParty::Parser.new('body', :json)
|
||||
parser.send(:supports_format?)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#parse_supported_format" do
|
||||
it "calls the parser for the given format" do
|
||||
parser = HTTParty::Parser.new('body', :json)
|
||||
parser.should_receive(:json)
|
||||
parser.send(:parse_supported_format)
|
||||
end
|
||||
|
||||
context "when a parsing method does not exist for the given format" do
|
||||
it "raises an exception" do
|
||||
parser = HTTParty::Parser.new('body', :atom)
|
||||
expect do
|
||||
parser.send(:parse_supported_format)
|
||||
end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.")
|
||||
end
|
||||
|
||||
it "raises a useful exception message for subclasses" do
|
||||
atom_parser = Class.new(HTTParty::Parser) do
|
||||
def self.name; 'AtomParser'; end
|
||||
end
|
||||
parser = atom_parser.new 'body', :atom
|
||||
expect do
|
||||
parser.send(:parse_supported_format)
|
||||
end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "parsers" do
|
||||
subject do
|
||||
HTTParty::Parser.new('body', nil)
|
||||
end
|
||||
|
||||
it "parses xml with MultiXml" do
|
||||
MultiXml.should_receive(:parse).with('body')
|
||||
subject.send(:xml)
|
||||
end
|
||||
|
||||
it "parses json with MultiJson" do
|
||||
MultiJson.should_receive(:load).with('body')
|
||||
subject.send(:json)
|
||||
end
|
||||
|
||||
it "uses MultiJson.decode if MultiJson does not respond to adapter" do
|
||||
MultiJson.should_receive(:respond_to?).with(:adapter).and_return(false)
|
||||
MultiJson.should_receive(:decode).with('body')
|
||||
subject.send(:json)
|
||||
end
|
||||
|
||||
it "parses yaml" do
|
||||
YAML.should_receive(:load).with('body')
|
||||
subject.send(:yaml)
|
||||
end
|
||||
|
||||
it "parses html by simply returning the body" do
|
||||
subject.send(:html).should == 'body'
|
||||
end
|
||||
|
||||
it "parses plain text by simply returning the body" do
|
||||
subject.send(:plain).should == 'body'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,495 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe HTTParty::Request do
|
||||
before do
|
||||
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
|
||||
end
|
||||
|
||||
describe "::NON_RAILS_QUERY_STRING_NORMALIZER" do
|
||||
let(:normalizer) { HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER }
|
||||
|
||||
it "doesn't modify strings" do
|
||||
query_string = normalizer["foo=bar&foo=baz"]
|
||||
URI.unescape(query_string).should == "foo=bar&foo=baz"
|
||||
end
|
||||
|
||||
context "when the query is an array" do
|
||||
|
||||
it "doesn't include brackets" do
|
||||
query_string = normalizer[{:page => 1, :foo => %w(bar baz)}]
|
||||
URI.unescape(query_string).should == "foo=bar&foo=baz&page=1"
|
||||
end
|
||||
|
||||
it "URI encodes array values" do
|
||||
query_string = normalizer[{:people => ["Bob Marley", "Tim & Jon"]}]
|
||||
query_string.should == "people=Bob%20Marley&people=Tim%20%26%20Jon"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the query is a hash" do
|
||||
it "correctly handles nil values" do
|
||||
query_string = normalizer[{:page => 1, :per_page => nil}]
|
||||
query_string.should == "page=1&per_page"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "initialization" do
|
||||
it "sets parser to HTTParty::Parser" do
|
||||
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
|
||||
request.parser.should == HTTParty::Parser
|
||||
end
|
||||
|
||||
it "sets parser to the optional parser" do
|
||||
my_parser = lambda {}
|
||||
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :parser => my_parser)
|
||||
request.parser.should == my_parser
|
||||
end
|
||||
|
||||
it "sets connection_adapter to HTTPParty::ConnectionAdapter" do
|
||||
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
|
||||
request.connection_adapter.should == HTTParty::ConnectionAdapter
|
||||
end
|
||||
|
||||
it "sets connection_adapter to the optional connection_adapter" do
|
||||
my_adapter = lambda {}
|
||||
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :connection_adapter => my_adapter)
|
||||
request.connection_adapter.should == my_adapter
|
||||
end
|
||||
end
|
||||
|
||||
describe "#format" do
|
||||
context "request yet to be made" do
|
||||
it "returns format option" do
|
||||
request = HTTParty::Request.new 'get', '/', :format => :xml
|
||||
request.format.should == :xml
|
||||
end
|
||||
|
||||
it "returns nil format" do
|
||||
request = HTTParty::Request.new 'get', '/'
|
||||
request.format.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "request has been made" do
|
||||
it "returns format option" do
|
||||
request = HTTParty::Request.new 'get', '/', :format => :xml
|
||||
request.last_response = stub
|
||||
request.format.should == :xml
|
||||
end
|
||||
|
||||
it "returns the content-type from the last response when the option is not set" do
|
||||
request = HTTParty::Request.new 'get', '/'
|
||||
response = stub
|
||||
response.should_receive(:[]).with('content-type').and_return('text/json')
|
||||
request.last_response = response
|
||||
request.format.should == :json
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "options" do
|
||||
it "should use basic auth when configured" do
|
||||
@request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'}
|
||||
@request.send(:setup_raw_request)
|
||||
@request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
|
||||
end
|
||||
|
||||
it "should use digest auth when configured" do
|
||||
FakeWeb.register_uri(:get, "http://api.foo.com/v1",
|
||||
:www_authenticate => 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false')
|
||||
|
||||
@request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
|
||||
@request.send(:setup_raw_request)
|
||||
|
||||
raw_request = @request.instance_variable_get(:@raw_request)
|
||||
raw_request.instance_variable_get(:@header)['Authorization'].should_not be_nil
|
||||
end
|
||||
|
||||
it "should use the right http method for digest authentication" do
|
||||
@post_request = HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml)
|
||||
FakeWeb.register_uri(:post, "http://api.foo.com/v1", {})
|
||||
|
||||
http = @post_request.send(:http)
|
||||
@post_request.should_receive(:http).and_return(http)
|
||||
http.should_not_receive(:head).and_return({'www-authenticate' => nil})
|
||||
@post_request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
|
||||
@post_request.send(:setup_raw_request)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#uri" do
|
||||
context "query strings" do
|
||||
it "does not add an empty query string when default_params are blank" do
|
||||
@request.options[:default_params] = {}
|
||||
@request.uri.query.should be_nil
|
||||
end
|
||||
|
||||
it "respects the query string normalization proc" do
|
||||
empty_proc = lambda {|qs| ""}
|
||||
@request.options[:query_string_normalizer] = empty_proc
|
||||
@request.options[:query] = {:foo => :bar}
|
||||
URI.unescape(@request.uri.query).should == ""
|
||||
end
|
||||
|
||||
context "when representing an array" do
|
||||
it "returns a Rails style query string" do
|
||||
@request.options[:query] = {:foo => %w(bar baz)}
|
||||
URI.unescape(@request.uri.query).should == "foo[]=bar&foo[]=baz"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "#setup_raw_request" do
|
||||
context "when query_string_normalizer is set" do
|
||||
it "sets the body to the return value of the proc" do
|
||||
@request.options[:query_string_normalizer] = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER
|
||||
@request.options[:body] = {:page => 1, :foo => %w(bar baz)}
|
||||
@request.send(:setup_raw_request)
|
||||
body = @request.instance_variable_get(:@raw_request).body
|
||||
URI.unescape(body).should == "foo=bar&foo=baz&page=1"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'http' do
|
||||
it "should get a connection from the connection_adapter" do
|
||||
http = Net::HTTP.new('google.com')
|
||||
adapter = mock('adapter')
|
||||
request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', :connection_adapter => adapter)
|
||||
adapter.should_receive(:call).with(request.uri, request.options).and_return(http)
|
||||
request.send(:http).should be http
|
||||
end
|
||||
end
|
||||
|
||||
describe '#format_from_mimetype' do
|
||||
it 'should handle text/xml' do
|
||||
["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :xml
|
||||
end
|
||||
end
|
||||
|
||||
it 'should handle application/xml' do
|
||||
["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :xml
|
||||
end
|
||||
end
|
||||
|
||||
it 'should handle text/json' do
|
||||
["text/json", "text/json; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :json
|
||||
end
|
||||
end
|
||||
|
||||
it 'should handle application/json' do
|
||||
["application/json", "application/json; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :json
|
||||
end
|
||||
end
|
||||
|
||||
it 'should handle text/javascript' do
|
||||
["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :json
|
||||
end
|
||||
end
|
||||
|
||||
it 'should handle application/javascript' do
|
||||
["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
|
||||
@request.send(:format_from_mimetype, ct).should == :json
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil for an unrecognized mimetype" do
|
||||
@request.send(:format_from_mimetype, "application/atom+xml").should be_nil
|
||||
end
|
||||
|
||||
it "returns nil when using a default parser" do
|
||||
@request.options[:parser] = lambda {}
|
||||
@request.send(:format_from_mimetype, "text/json").should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'parsing responses' do
|
||||
it 'should handle xml automatically' do
|
||||
xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
|
||||
@request.options[:format] = :xml
|
||||
@request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
||||
end
|
||||
|
||||
it 'should handle json automatically' do
|
||||
json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
|
||||
@request.options[:format] = :json
|
||||
@request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
||||
end
|
||||
|
||||
it 'should handle yaml automatically' do
|
||||
yaml = "books: \n book: \n name: Foo Bar!\n id: \"1234\"\n"
|
||||
@request.options[:format] = :yaml
|
||||
@request.send(:parse_response, yaml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
||||
end
|
||||
|
||||
it "should include any HTTP headers in the returned response" do
|
||||
@request.options[:format] = :html
|
||||
response = stub_response "Content"
|
||||
response.initialize_http_header("key" => "value")
|
||||
|
||||
@request.perform.headers.should == { "key" => ["value"] }
|
||||
end
|
||||
|
||||
describe 'with non-200 responses' do
|
||||
context "3xx responses" do
|
||||
it 'returns a valid object for 304 not modified' do
|
||||
stub_response '', 304
|
||||
resp = @request.perform
|
||||
resp.code.should == 304
|
||||
resp.body.should == ''
|
||||
resp.should be_nil
|
||||
end
|
||||
|
||||
it "redirects if a 300 contains a location header" do
|
||||
redirect = stub_response '', 300
|
||||
redirect['location'] = 'http://foo.com/foo'
|
||||
ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
||||
@http.stub!(:request).and_return(redirect, ok)
|
||||
response = @request.perform
|
||||
response.request.base_uri.to_s.should == "http://foo.com"
|
||||
response.request.path.to_s.should == "http://foo.com/foo"
|
||||
response.request.uri.request_uri.should == "/foo"
|
||||
response.request.uri.to_s.should == "http://foo.com/foo"
|
||||
response.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "redirects if a 300 contains a relative location header" do
|
||||
redirect = stub_response '', 300
|
||||
redirect['location'] = '/foo/bar'
|
||||
ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
||||
@http.stub!(:request).and_return(redirect, ok)
|
||||
response = @request.perform
|
||||
response.request.base_uri.to_s.should == "http://api.foo.com"
|
||||
response.request.path.to_s.should == "/foo/bar"
|
||||
response.request.uri.request_uri.should == "/foo/bar"
|
||||
response.request.uri.to_s.should == "http://api.foo.com/foo/bar"
|
||||
response.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "handles multiple redirects and relative location headers on different hosts" do
|
||||
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', :format => :xml)
|
||||
FakeWeb.register_uri(:get, "http://test.com/redirect", :status => [300, "REDIRECT"], :location => "http://api.foo.com/v2")
|
||||
FakeWeb.register_uri(:get, "http://api.foo.com/v2", :status => [300, "REDIRECT"], :location => "/v3")
|
||||
FakeWeb.register_uri(:get, "http://api.foo.com/v3", :body => "<hash><foo>bar</foo></hash>")
|
||||
response = @request.perform
|
||||
response.request.base_uri.to_s.should == "http://api.foo.com"
|
||||
response.request.path.to_s.should == "/v3"
|
||||
response.request.uri.request_uri.should == "/v3"
|
||||
response.request.uri.to_s.should == "http://api.foo.com/v3"
|
||||
response.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "returns the HTTParty::Response when the 300 does not contain a location header" do
|
||||
net_response = stub_response '', 300
|
||||
HTTParty::Response.should === @request.perform
|
||||
end
|
||||
end
|
||||
|
||||
it 'should return a valid object for 4xx response' do
|
||||
stub_response '<foo><bar>yes</bar></foo>', 401
|
||||
resp = @request.perform
|
||||
resp.code.should == 401
|
||||
resp.body.should == "<foo><bar>yes</bar></foo>"
|
||||
resp['foo']['bar'].should == "yes"
|
||||
end
|
||||
|
||||
it 'should return a valid object for 5xx response' do
|
||||
stub_response '<foo><bar>error</bar></foo>', 500
|
||||
resp = @request.perform
|
||||
resp.code.should == 500
|
||||
resp.body.should == "<foo><bar>error</bar></foo>"
|
||||
resp['foo']['bar'].should == "error"
|
||||
end
|
||||
|
||||
it "parses response lazily so codes can be checked prior" do
|
||||
stub_response 'not xml', 500
|
||||
@request.options[:format] = :xml
|
||||
lambda {
|
||||
response = @request.perform
|
||||
response.code.should == 500
|
||||
response.body.should == 'not xml'
|
||||
}.should_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "should not attempt to parse empty responses" do
|
||||
[204, 304].each do |code|
|
||||
stub_response "", code
|
||||
|
||||
@request.options[:format] = :xml
|
||||
@request.perform.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it "should not fail for missing mime type" do
|
||||
stub_response "Content for you"
|
||||
@request.options[:format] = :html
|
||||
@request.perform.should == 'Content for you'
|
||||
end
|
||||
|
||||
describe "a request that redirects" do
|
||||
before(:each) do
|
||||
@redirect = stub_response("", 302)
|
||||
@redirect['location'] = '/foo'
|
||||
|
||||
@ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
||||
end
|
||||
|
||||
describe "once" do
|
||||
before(:each) do
|
||||
@http.stub!(:request).and_return(@redirect, @ok)
|
||||
end
|
||||
|
||||
it "should be handled by GET transparently" do
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by POST transparently" do
|
||||
@request.http_method = Net::HTTP::Post
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by DELETE transparently" do
|
||||
@request.http_method = Net::HTTP::Delete
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by PATCH transparently" do
|
||||
@request.http_method = Net::HTTP::Patch
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by PUT transparently" do
|
||||
@request.http_method = Net::HTTP::Put
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by HEAD transparently" do
|
||||
@request.http_method = Net::HTTP::Head
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should be handled by OPTIONS transparently" do
|
||||
@request.http_method = Net::HTTP::Options
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
end
|
||||
|
||||
it "should keep track of cookies between redirects" do
|
||||
@redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
|
||||
@request.perform
|
||||
@request.options[:headers]['Cookie'].should match(/foo=bar/)
|
||||
@request.options[:headers]['Cookie'].should match(/name=value/)
|
||||
end
|
||||
|
||||
it 'should update cookies with rediects' do
|
||||
@request.options[:headers] = {'Cookie'=> 'foo=bar;'}
|
||||
@redirect['Set-Cookie'] = 'foo=tar;'
|
||||
@request.perform
|
||||
@request.options[:headers]['Cookie'].should match(/foo=tar/)
|
||||
end
|
||||
|
||||
it 'should keep cookies between rediects' do
|
||||
@request.options[:headers] = {'Cookie'=> 'keep=me'}
|
||||
@redirect['Set-Cookie'] = 'foo=tar;'
|
||||
@request.perform
|
||||
@request.options[:headers]['Cookie'].should match(/keep=me/)
|
||||
end
|
||||
|
||||
it 'should make resulting request a get request if it not already' do
|
||||
@request.http_method = Net::HTTP::Delete
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
@request.http_method.should == Net::HTTP::Get
|
||||
end
|
||||
|
||||
it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
|
||||
@request.options[:maintain_method_across_redirects] = true
|
||||
@request.http_method = Net::HTTP::Delete
|
||||
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
||||
@request.http_method.should == Net::HTTP::Delete
|
||||
end
|
||||
end
|
||||
|
||||
describe "infinitely" do
|
||||
before(:each) do
|
||||
@http.stub!(:request).and_return(@redirect)
|
||||
end
|
||||
|
||||
it "should raise an exception" do
|
||||
lambda { @request.perform }.should raise_error(HTTParty::RedirectionTooDeep)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#handle_deflation" do
|
||||
context "context-encoding" do
|
||||
before do
|
||||
@request.options[:format] = :html
|
||||
@last_response = mock()
|
||||
@last_response.stub!(:body).and_return('')
|
||||
end
|
||||
|
||||
it "should inflate the gzipped body with content-encoding: gzip" do
|
||||
@last_response.stub!(:[]).with("content-encoding").and_return("gzip")
|
||||
@request.stub!(:last_response).and_return(@last_response)
|
||||
Zlib::GzipReader.should_receive(:new).and_return(StringIO.new(''))
|
||||
@request.last_response.should_receive(:delete).with('content-encoding')
|
||||
@request.send(:handle_deflation)
|
||||
end
|
||||
|
||||
it "should inflate the gzipped body with content-encoding: x-gzip" do
|
||||
@last_response.stub!(:[]).with("content-encoding").and_return("x-gzip")
|
||||
@request.stub!(:last_response).and_return(@last_response)
|
||||
Zlib::GzipReader.should_receive(:new).and_return(StringIO.new(''))
|
||||
@request.last_response.should_receive(:delete).with('content-encoding')
|
||||
@request.send(:handle_deflation)
|
||||
end
|
||||
|
||||
it "should inflate the deflated body" do
|
||||
@last_response.stub!(:[]).with("content-encoding").and_return("deflate")
|
||||
@request.stub!(:last_response).and_return(@last_response)
|
||||
Zlib::Inflate.should_receive(:inflate).and_return('')
|
||||
@request.last_response.should_receive(:delete).with('content-encoding')
|
||||
@request.send(:handle_deflation)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with POST http method" do
|
||||
it "should raise argument error if query is not a hash" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml, :query => 'astring').perform
|
||||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "argument validation" do
|
||||
it "should raise argument error if basic_auth and digest_auth are both present" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => {}, :digest_auth => {}).perform
|
||||
}.should raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
|
||||
end
|
||||
|
||||
it "should raise argument error if basic_auth is not a hash" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => ["foo", "bar"]).perform
|
||||
}.should raise_error(ArgumentError, ":basic_auth must be a hash")
|
||||
end
|
||||
|
||||
it "should raise argument error if digest_auth is not a hash" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :digest_auth => ["foo", "bar"]).perform
|
||||
}.should raise_error(ArgumentError, ":digest_auth must be a hash")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe HTTParty::Response do
|
||||
before do
|
||||
@last_modified = Date.new(2010, 1, 15).to_s
|
||||
@content_length = '1024'
|
||||
@request_object = HTTParty::Request.new Net::HTTP::Get, '/'
|
||||
@response_object = Net::HTTPOK.new('1.1', 200, 'OK')
|
||||
@response_object.stub(:body => "{foo:'bar'}")
|
||||
@response_object['last-modified'] = @last_modified
|
||||
@response_object['content-length'] = @content_length
|
||||
@parsed_response = lambda { {"foo" => "bar"} }
|
||||
@response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
end
|
||||
|
||||
describe ".underscore" do
|
||||
it "works with one capitalized word" do
|
||||
HTTParty::Response.underscore("Accepted").should == "accepted"
|
||||
end
|
||||
|
||||
it "works with titlecase" do
|
||||
HTTParty::Response.underscore("BadGateway").should == "bad_gateway"
|
||||
end
|
||||
|
||||
it "works with all caps" do
|
||||
HTTParty::Response.underscore("OK").should == "ok"
|
||||
end
|
||||
end
|
||||
|
||||
describe "initialization" do
|
||||
it "should set the Net::HTTP Response" do
|
||||
@response.response.should == @response_object
|
||||
end
|
||||
|
||||
it "should set body" do
|
||||
@response.body.should == @response_object.body
|
||||
end
|
||||
|
||||
it "should set code" do
|
||||
@response.code.should.to_s == @response_object.code
|
||||
end
|
||||
|
||||
it "should set code as a Fixnum" do
|
||||
@response.code.should be_an_instance_of(Fixnum)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns response headers" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.headers.should == {'last-modified' => [@last_modified], 'content-length' => [@content_length]}
|
||||
end
|
||||
|
||||
it "should send missing methods to delegate" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response['foo'].should == 'bar'
|
||||
end
|
||||
|
||||
it "response to request" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:request).should be_true
|
||||
end
|
||||
|
||||
it "responds to response" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:response).should be_true
|
||||
end
|
||||
|
||||
it "responds to body" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:body).should be_true
|
||||
end
|
||||
|
||||
it "responds to headers" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:headers).should be_true
|
||||
end
|
||||
|
||||
it "responds to parsed_response" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:parsed_response).should be_true
|
||||
end
|
||||
|
||||
it "responds to anything parsed_response responds to" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.respond_to?(:[]).should be_true
|
||||
end
|
||||
|
||||
it "should be able to iterate if it is array" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, lambda { [{'foo' => 'bar'}, {'foo' => 'baz'}] })
|
||||
response.size.should == 2
|
||||
expect {
|
||||
response.each { |item| }
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it "allows headers to be accessed by mixed-case names in hash notation" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.headers['Content-LENGTH'].should == @content_length
|
||||
end
|
||||
|
||||
it "returns a comma-delimited value when multiple values exist" do
|
||||
@response_object.add_field 'set-cookie', 'csrf_id=12345; path=/'
|
||||
@response_object.add_field 'set-cookie', '_github_ses=A123CdE; path=/'
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
response.headers['set-cookie'].should == "csrf_id=12345; path=/, _github_ses=A123CdE; path=/"
|
||||
end
|
||||
|
||||
# Backwards-compatibility - previously, #headers returned a Hash
|
||||
it "responds to hash methods" do
|
||||
response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
||||
hash_methods = {}.methods - response.headers.methods
|
||||
hash_methods.each do |method_name|
|
||||
response.headers.respond_to?(method_name).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "semantic methods for response codes" do
|
||||
def response_mock(klass)
|
||||
response = klass.new('', '', '')
|
||||
response.stub(:body)
|
||||
response
|
||||
end
|
||||
|
||||
context "major codes" do
|
||||
it "is information" do
|
||||
net_response = response_mock(Net::HTTPInformation)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.information?.should be_true
|
||||
end
|
||||
|
||||
it "is success" do
|
||||
net_response = response_mock(Net::HTTPSuccess)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.success?.should be_true
|
||||
end
|
||||
|
||||
it "is redirection" do
|
||||
net_response = response_mock(Net::HTTPRedirection)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.redirection?.should be_true
|
||||
end
|
||||
|
||||
it "is client error" do
|
||||
net_response = response_mock(Net::HTTPClientError)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.client_error?.should be_true
|
||||
end
|
||||
|
||||
it "is server error" do
|
||||
net_response = response_mock(Net::HTTPServerError)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.server_error?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "for specific codes" do
|
||||
SPECIFIC_CODES = {
|
||||
:accepted? => Net::HTTPAccepted,
|
||||
:bad_gateway? => Net::HTTPBadGateway,
|
||||
:bad_request? => Net::HTTPBadRequest,
|
||||
:conflict? => Net::HTTPConflict,
|
||||
:continue? => Net::HTTPContinue,
|
||||
:created? => Net::HTTPCreated,
|
||||
:expectation_failed? => Net::HTTPExpectationFailed,
|
||||
:forbidden? => Net::HTTPForbidden,
|
||||
:found? => Net::HTTPFound,
|
||||
:gateway_time_out? => Net::HTTPGatewayTimeOut,
|
||||
:gone? => Net::HTTPGone,
|
||||
:internal_server_error? => Net::HTTPInternalServerError,
|
||||
:length_required? => Net::HTTPLengthRequired,
|
||||
:method_not_allowed? => Net::HTTPMethodNotAllowed,
|
||||
:moved_permanently? => Net::HTTPMovedPermanently,
|
||||
:multiple_choice? => Net::HTTPMultipleChoice,
|
||||
:no_content? => Net::HTTPNoContent,
|
||||
:non_authoritative_information? => Net::HTTPNonAuthoritativeInformation,
|
||||
:not_acceptable? => Net::HTTPNotAcceptable,
|
||||
:not_found? => Net::HTTPNotFound,
|
||||
:not_implemented? => Net::HTTPNotImplemented,
|
||||
:not_modified? => Net::HTTPNotModified,
|
||||
:ok? => Net::HTTPOK,
|
||||
:partial_content? => Net::HTTPPartialContent,
|
||||
:payment_required? => Net::HTTPPaymentRequired,
|
||||
:precondition_failed? => Net::HTTPPreconditionFailed,
|
||||
:proxy_authentication_required? => Net::HTTPProxyAuthenticationRequired,
|
||||
:request_entity_too_large? => Net::HTTPRequestEntityTooLarge,
|
||||
:request_time_out? => Net::HTTPRequestTimeOut,
|
||||
:request_uri_too_long? => Net::HTTPRequestURITooLong,
|
||||
:requested_range_not_satisfiable? => Net::HTTPRequestedRangeNotSatisfiable,
|
||||
:reset_content? => Net::HTTPResetContent,
|
||||
:see_other? => Net::HTTPSeeOther,
|
||||
:service_unavailable? => Net::HTTPServiceUnavailable,
|
||||
:switch_protocol? => Net::HTTPSwitchProtocol,
|
||||
:temporary_redirect? => Net::HTTPTemporaryRedirect,
|
||||
:unauthorized? => Net::HTTPUnauthorized,
|
||||
:unsupported_media_type? => Net::HTTPUnsupportedMediaType,
|
||||
:use_proxy? => Net::HTTPUseProxy,
|
||||
:version_not_supported? => Net::HTTPVersionNotSupported
|
||||
}.each do |method, klass|
|
||||
it "responds to #{method}" do
|
||||
net_response = response_mock(klass)
|
||||
response = HTTParty::Response.new(@request_object, net_response, '')
|
||||
response.__send__(method).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "headers" do
|
||||
it "can initialize without headers" do
|
||||
headers = HTTParty::Response::Headers.new
|
||||
headers.should == {}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
||||
|
||||
describe HTTParty::Request do
|
||||
context "SSL certificate verification" do
|
||||
before do
|
||||
FakeWeb.allow_net_connect = true
|
||||
end
|
||||
|
||||
after do
|
||||
FakeWeb.allow_net_connect = false
|
||||
end
|
||||
|
||||
it "should work when no trusted CA list is specified" do
|
||||
ssl_verify_test(nil, nil, "selfsigned.crt").should == {'success' => true}
|
||||
end
|
||||
|
||||
it "should work when no trusted CA list is specified, even with a bogus hostname" do
|
||||
ssl_verify_test(nil, nil, "bogushost.crt").should == {'success' => true}
|
||||
end
|
||||
|
||||
it "should work when using ssl_ca_file with a self-signed CA" do
|
||||
ssl_verify_test(:ssl_ca_file, "selfsigned.crt", "selfsigned.crt").should == {'success' => true}
|
||||
end
|
||||
|
||||
it "should work when using ssl_ca_file with a certificate authority" do
|
||||
ssl_verify_test(:ssl_ca_file, "ca.crt", "server.crt").should == {'success' => true}
|
||||
end
|
||||
|
||||
it "should work when using ssl_ca_path with a certificate authority" do
|
||||
http = Net::HTTP.new('www.google.com', 443, nil, nil, nil, nil)
|
||||
response = stub(Net::HTTPResponse, :[] => '', :body => '', :to_hash => {})
|
||||
http.stub(:request).and_return(response)
|
||||
Net::HTTP.should_receive(:new).with('www.google.com', 443, nil, nil, nil, nil).and_return(http)
|
||||
http.should_receive(:ca_path=).with('/foo/bar')
|
||||
HTTParty.get('https://www.google.com', :ssl_ca_path => '/foo/bar')
|
||||
end
|
||||
|
||||
it "should fail when using ssl_ca_file and the server uses an unrecognized certificate authority" do
|
||||
lambda do
|
||||
ssl_verify_test(:ssl_ca_file, "ca.crt", "selfsigned.crt")
|
||||
end.should raise_error(OpenSSL::SSL::SSLError)
|
||||
end
|
||||
|
||||
it "should fail when using ssl_ca_path and the server uses an unrecognized certificate authority" do
|
||||
lambda do
|
||||
ssl_verify_test(:ssl_ca_path, ".", "selfsigned.crt")
|
||||
end.should raise_error(OpenSSL::SSL::SSLError)
|
||||
end
|
||||
|
||||
it "should fail when using ssl_ca_file and the server uses a bogus hostname" do
|
||||
lambda do
|
||||
ssl_verify_test(:ssl_ca_file, "ca.crt", "bogushost.crt")
|
||||
end.should raise_error(OpenSSL::SSL::SSLError)
|
||||
end
|
||||
|
||||
it "should fail when using ssl_ca_path and the server uses a bogus hostname" do
|
||||
lambda do
|
||||
ssl_verify_test(:ssl_ca_path, ".", "bogushost.crt")
|
||||
end.should raise_error(OpenSSL::SSL::SSLError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,703 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
||||
|
||||
describe HTTParty do
|
||||
before(:each) do
|
||||
@klass = Class.new
|
||||
@klass.instance_eval { include HTTParty }
|
||||
end
|
||||
|
||||
describe "AllowedFormats deprecated" do
|
||||
before do
|
||||
Kernel.stub(:warn)
|
||||
end
|
||||
|
||||
it "warns with a deprecation message" do
|
||||
Kernel.should_receive(:warn).with("Deprecated: Use HTTParty::Parser::SupportedFormats")
|
||||
HTTParty::AllowedFormats
|
||||
end
|
||||
|
||||
it "returns HTTPart::Parser::SupportedFormats" do
|
||||
HTTParty::AllowedFormats.should == HTTParty::Parser::SupportedFormats
|
||||
end
|
||||
end
|
||||
|
||||
describe "pem" do
|
||||
it 'should set the pem content' do
|
||||
@klass.pem 'PEM-CONTENT'
|
||||
@klass.default_options[:pem].should == 'PEM-CONTENT'
|
||||
end
|
||||
|
||||
it "should set the password to nil if it's not provided" do
|
||||
@klass.pem 'PEM-CONTENT'
|
||||
@klass.default_options[:pem_password].should be_nil
|
||||
end
|
||||
|
||||
it 'should set the password' do
|
||||
@klass.pem 'PEM-CONTENT', 'PASSWORD'
|
||||
@klass.default_options[:pem_password].should == 'PASSWORD'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ssl_version' do
|
||||
it 'should set the ssl_version content' do
|
||||
@klass.ssl_version :SSLv3
|
||||
@klass.default_options[:ssl_version].should == :SSLv3
|
||||
end
|
||||
end
|
||||
|
||||
describe 'http_proxy' do
|
||||
it 'should set the address' do
|
||||
@klass.http_proxy 'proxy.foo.com', 80
|
||||
options = @klass.default_options
|
||||
options[:http_proxyaddr].should == 'proxy.foo.com'
|
||||
options[:http_proxyport].should == 80
|
||||
end
|
||||
|
||||
it 'should set the proxy user and pass when they are provided' do
|
||||
@klass.http_proxy 'proxy.foo.com', 80, 'user', 'pass'
|
||||
options = @klass.default_options
|
||||
options[:http_proxyuser].should == 'user'
|
||||
options[:http_proxypass].should == 'pass'
|
||||
end
|
||||
end
|
||||
|
||||
describe "base uri" do
|
||||
before(:each) do
|
||||
@klass.base_uri('api.foo.com/v1')
|
||||
end
|
||||
|
||||
it "should have reader" do
|
||||
@klass.base_uri.should == 'http://api.foo.com/v1'
|
||||
end
|
||||
|
||||
it 'should have writer' do
|
||||
@klass.base_uri('http://api.foobar.com')
|
||||
@klass.base_uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
|
||||
it 'should not modify the parameter during assignment' do
|
||||
uri = 'http://api.foobar.com'
|
||||
@klass.base_uri(uri)
|
||||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
end
|
||||
|
||||
describe ".disable_rails_query_string_format" do
|
||||
it "sets the query string normalizer to HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER" do
|
||||
@klass.disable_rails_query_string_format
|
||||
@klass.default_options[:query_string_normalizer].should == HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER
|
||||
end
|
||||
end
|
||||
|
||||
describe ".normalize_base_uri" do
|
||||
it "should add http if not present for non ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('api.foobar.com')
|
||||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
|
||||
it "should add https if not present for ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('api.foo.com/v1:443')
|
||||
uri.should == 'https://api.foo.com/v1:443'
|
||||
end
|
||||
|
||||
it "should not remove https for ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443')
|
||||
uri.should == 'https://api.foo.com/v1:443'
|
||||
end
|
||||
|
||||
it 'should not modify the parameter' do
|
||||
uri = 'http://api.foobar.com'
|
||||
HTTParty.normalize_base_uri(uri)
|
||||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
|
||||
it "should not treat uri's with a port of 4430 as ssl" do
|
||||
uri = HTTParty.normalize_base_uri('http://api.foo.com:4430/v1')
|
||||
uri.should == 'http://api.foo.com:4430/v1'
|
||||
end
|
||||
end
|
||||
|
||||
describe "headers" do
|
||||
def expect_headers(header={})
|
||||
HTTParty::Request.should_receive(:new) \
|
||||
.with(anything, anything, hash_including({ :headers => header })) \
|
||||
.and_return(mock("mock response", :perform => nil))
|
||||
end
|
||||
|
||||
it "should default to empty hash" do
|
||||
@klass.headers.should == {}
|
||||
end
|
||||
|
||||
it "should be able to be updated" do
|
||||
init_headers = {:foo => 'bar', :baz => 'spax'}
|
||||
@klass.headers init_headers
|
||||
@klass.headers.should == init_headers
|
||||
end
|
||||
|
||||
it "uses the class headers when sending a request" do
|
||||
expect_headers(:foo => 'bar')
|
||||
@klass.headers(:foo => 'bar')
|
||||
@klass.get('')
|
||||
end
|
||||
|
||||
it "overwrites class headers when passing in headers" do
|
||||
expect_headers(:baz => 'spax')
|
||||
@klass.headers(:foo => 'bar')
|
||||
@klass.get('', :headers => {:baz => 'spax'})
|
||||
end
|
||||
|
||||
context "with cookies" do
|
||||
it 'utilizes the class-level cookies' do
|
||||
expect_headers(:foo => 'bar', 'cookie' => 'type=snickerdoodle')
|
||||
@klass.headers(:foo => 'bar')
|
||||
@klass.cookies(:type => 'snickerdoodle')
|
||||
@klass.get('')
|
||||
end
|
||||
|
||||
it 'adds cookies to the headers' do
|
||||
expect_headers(:foo => 'bar', 'cookie' => 'type=snickerdoodle')
|
||||
@klass.headers(:foo => 'bar')
|
||||
@klass.get('', :cookies => {:type => 'snickerdoodle'})
|
||||
end
|
||||
|
||||
it 'adds optional cookies to the optional headers' do
|
||||
expect_headers(:baz => 'spax', 'cookie' => 'type=snickerdoodle')
|
||||
@klass.get('', :cookies => {:type => 'snickerdoodle'}, :headers => {:baz => 'spax'})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "cookies" do
|
||||
def expect_cookie_header(s)
|
||||
HTTParty::Request.should_receive(:new) \
|
||||
.with(anything, anything, hash_including({ :headers => { "cookie" => s } })) \
|
||||
.and_return(mock("mock response", :perform => nil))
|
||||
end
|
||||
|
||||
it "should not be in the headers by default" do
|
||||
HTTParty::Request.stub!(:new).and_return(stub(nil, :perform => nil))
|
||||
@klass.get("")
|
||||
@klass.headers.keys.should_not include("cookie")
|
||||
end
|
||||
|
||||
it "should raise an ArgumentError if passed a non-Hash" do
|
||||
lambda do
|
||||
@klass.cookies("nonsense")
|
||||
end.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should allow a cookie to be specified with a one-off request" do
|
||||
expect_cookie_header "type=snickerdoodle"
|
||||
@klass.get("", :cookies => { :type => "snickerdoodle" })
|
||||
end
|
||||
|
||||
describe "when a cookie is set at the class level" do
|
||||
before(:each) do
|
||||
@klass.cookies({ :type => "snickerdoodle" })
|
||||
end
|
||||
|
||||
it "should include that cookie in the request" do
|
||||
expect_cookie_header "type=snickerdoodle"
|
||||
@klass.get("")
|
||||
end
|
||||
|
||||
it "should pass the proper cookies when requested multiple times" do
|
||||
2.times do
|
||||
expect_cookie_header "type=snickerdoodle"
|
||||
@klass.get("")
|
||||
end
|
||||
end
|
||||
|
||||
it "should allow the class defaults to be overridden" do
|
||||
expect_cookie_header "type=chocolate_chip"
|
||||
|
||||
@klass.get("", :cookies => { :type => "chocolate_chip" })
|
||||
end
|
||||
end
|
||||
|
||||
describe "in a class with multiple methods that use different cookies" do
|
||||
before(:each) do
|
||||
@klass.instance_eval do
|
||||
def first_method
|
||||
get("first_method", :cookies => { :first_method_cookie => "foo" })
|
||||
end
|
||||
|
||||
def second_method
|
||||
get("second_method", :cookies => { :second_method_cookie => "foo" })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "should not allow cookies used in one method to carry over into other methods" do
|
||||
expect_cookie_header "first_method_cookie=foo"
|
||||
@klass.first_method
|
||||
|
||||
expect_cookie_header "second_method_cookie=foo"
|
||||
@klass.second_method
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "default params" do
|
||||
it "should default to empty hash" do
|
||||
@klass.default_params.should == {}
|
||||
end
|
||||
|
||||
it "should be able to be updated" do
|
||||
new_defaults = {:foo => 'bar', :baz => 'spax'}
|
||||
@klass.default_params new_defaults
|
||||
@klass.default_params.should == new_defaults
|
||||
end
|
||||
end
|
||||
|
||||
describe "default timeout" do
|
||||
it "should default to nil" do
|
||||
@klass.default_options[:timeout].should == nil
|
||||
end
|
||||
|
||||
it "should support updating" do
|
||||
@klass.default_timeout 10
|
||||
@klass.default_options[:timeout].should == 10
|
||||
end
|
||||
|
||||
it "should support floats" do
|
||||
@klass.default_timeout 0.5
|
||||
@klass.default_options[:timeout].should == 0.5
|
||||
end
|
||||
end
|
||||
|
||||
describe "debug_output" do
|
||||
it "stores the given stream as a default_option" do
|
||||
@klass.debug_output $stdout
|
||||
@klass.default_options[:debug_output].should == $stdout
|
||||
end
|
||||
|
||||
it "stores the $stderr stream by default" do
|
||||
@klass.debug_output
|
||||
@klass.default_options[:debug_output].should == $stderr
|
||||
end
|
||||
end
|
||||
|
||||
describe "basic http authentication" do
|
||||
it "should work" do
|
||||
@klass.basic_auth 'foobar', 'secret'
|
||||
@klass.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
|
||||
end
|
||||
end
|
||||
|
||||
describe "digest http authentication" do
|
||||
it "should work" do
|
||||
@klass.digest_auth 'foobar', 'secret'
|
||||
@klass.default_options[:digest_auth].should == {:username => 'foobar', :password => 'secret'}
|
||||
end
|
||||
end
|
||||
|
||||
describe "parser" do
|
||||
class CustomParser
|
||||
def self.parse(body)
|
||||
return {:sexy => true}
|
||||
end
|
||||
end
|
||||
|
||||
let(:parser) do
|
||||
Proc.new{ |data, format| CustomParser.parse(data) }
|
||||
end
|
||||
|
||||
it "should set parser options" do
|
||||
@klass.parser parser
|
||||
@klass.default_options[:parser].should == parser
|
||||
end
|
||||
|
||||
it "should be able parse response with custom parser" do
|
||||
@klass.parser parser
|
||||
FakeWeb.register_uri(:get, 'http://twitter.com/statuses/public_timeline.xml', :body => 'tweets')
|
||||
custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml')
|
||||
custom_parsed_response[:sexy].should == true
|
||||
end
|
||||
|
||||
it "raises UnsupportedFormat when the parser cannot handle the format" do
|
||||
@klass.format :json
|
||||
class MyParser < HTTParty::Parser
|
||||
SupportedFormats = {}
|
||||
end unless defined?(MyParser)
|
||||
expect do
|
||||
@klass.parser MyParser
|
||||
end.to raise_error(HTTParty::UnsupportedFormat)
|
||||
end
|
||||
|
||||
it 'does not validate format whe custom parser is a proc' do
|
||||
expect do
|
||||
@klass.format :json
|
||||
@klass.parser lambda {|body, format|}
|
||||
end.to_not raise_error(HTTParty::UnsupportedFormat)
|
||||
end
|
||||
end
|
||||
|
||||
describe "connection_adapter" do
|
||||
let(:uri) { 'http://google.com/api.json' }
|
||||
let(:connection_adapter) { mock('CustomConnectionAdapter') }
|
||||
|
||||
it "should set the connection_adapter" do
|
||||
@klass.connection_adapter connection_adapter
|
||||
@klass.default_options[:connection_adapter].should be connection_adapter
|
||||
end
|
||||
|
||||
it "should set the connection_adapter_options when provided" do
|
||||
options = {:foo => :bar}
|
||||
@klass.connection_adapter connection_adapter, options
|
||||
@klass.default_options[:connection_adapter_options].should be options
|
||||
end
|
||||
|
||||
it "should not set the connection_adapter_options when not provided" do
|
||||
@klass.connection_adapter connection_adapter
|
||||
@klass.default_options[:connection_adapter_options].should be_nil
|
||||
end
|
||||
|
||||
it "should process a request with a connection from the adapter" do
|
||||
connection_adapter_options = {:foo => :bar}
|
||||
connection_adapter.should_receive(:call) do |u,o|
|
||||
o[:connection_adapter_options].should == connection_adapter_options
|
||||
HTTParty::ConnectionAdapter.call(u,o)
|
||||
end.with(URI.parse(uri), kind_of(Hash))
|
||||
FakeWeb.register_uri(:get, uri, :body => 'stuff')
|
||||
@klass.connection_adapter connection_adapter, connection_adapter_options
|
||||
@klass.get(uri).should == 'stuff'
|
||||
end
|
||||
end
|
||||
|
||||
describe "format" do
|
||||
it "should allow xml" do
|
||||
@klass.format :xml
|
||||
@klass.default_options[:format].should == :xml
|
||||
end
|
||||
|
||||
it "should allow json" do
|
||||
@klass.format :json
|
||||
@klass.default_options[:format].should == :json
|
||||
end
|
||||
|
||||
it "should allow yaml" do
|
||||
@klass.format :yaml
|
||||
@klass.default_options[:format].should == :yaml
|
||||
end
|
||||
|
||||
it "should allow plain" do
|
||||
@klass.format :plain
|
||||
@klass.default_options[:format].should == :plain
|
||||
end
|
||||
|
||||
it 'should not allow funky format' do
|
||||
lambda do
|
||||
@klass.format :foobar
|
||||
end.should raise_error(HTTParty::UnsupportedFormat)
|
||||
end
|
||||
|
||||
it 'should only print each format once with an exception' do
|
||||
lambda do
|
||||
@klass.format :foobar
|
||||
end.should raise_error(HTTParty::UnsupportedFormat, "':foobar' Must be one of: html, json, plain, xml, yaml")
|
||||
end
|
||||
|
||||
it 'sets the default parser' do
|
||||
@klass.default_options[:parser].should be_nil
|
||||
@klass.format :json
|
||||
@klass.default_options[:parser].should == HTTParty::Parser
|
||||
end
|
||||
|
||||
it 'does not reset parser to the default parser' do
|
||||
my_parser = lambda {}
|
||||
@klass.parser my_parser
|
||||
@klass.format :json
|
||||
@klass.parser.should == my_parser
|
||||
end
|
||||
end
|
||||
|
||||
describe "#no_follow" do
|
||||
it "sets no_follow to false by default" do
|
||||
@klass.no_follow
|
||||
@klass.default_options[:no_follow].should be_false
|
||||
end
|
||||
|
||||
it "sets the no_follow option to true" do
|
||||
@klass.no_follow true
|
||||
@klass.default_options[:no_follow].should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#maintain_method_across_redirects" do
|
||||
it "sets maintain_method_across_redirects to true by default" do
|
||||
@klass.maintain_method_across_redirects
|
||||
@klass.default_options[:maintain_method_across_redirects].should be_true
|
||||
end
|
||||
|
||||
it "sets the maintain_method_across_redirects option to false" do
|
||||
@klass.maintain_method_across_redirects false
|
||||
@klass.default_options[:maintain_method_across_redirects].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe ".follow_redirects" do
|
||||
it "sets follow redirects to true by default" do
|
||||
@klass.follow_redirects
|
||||
@klass.default_options[:follow_redirects].should be_true
|
||||
end
|
||||
|
||||
it "sets the follow_redirects option to false" do
|
||||
@klass.follow_redirects false
|
||||
@klass.default_options[:follow_redirects].should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe ".query_string_normalizer" do
|
||||
it "sets the query_string_normalizer option" do
|
||||
normalizer = proc {}
|
||||
@klass.query_string_normalizer normalizer
|
||||
@klass.default_options[:query_string_normalizer].should == normalizer
|
||||
end
|
||||
end
|
||||
|
||||
describe "with explicit override of automatic redirect handling" do
|
||||
before do
|
||||
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml, :no_follow => true)
|
||||
@redirect = stub_response 'first redirect', 302
|
||||
@redirect['location'] = 'http://foo.com/bar'
|
||||
HTTParty::Request.stub(:new => @request)
|
||||
end
|
||||
|
||||
it "should fail with redirected GET" do
|
||||
lambda do
|
||||
@error = @klass.get('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected POST" do
|
||||
lambda do
|
||||
@klass.post('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected PATCH" do
|
||||
lambda do
|
||||
@klass.patch('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected DELETE" do
|
||||
lambda do
|
||||
@klass.delete('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected PUT" do
|
||||
lambda do
|
||||
@klass.put('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected HEAD" do
|
||||
lambda do
|
||||
@klass.head('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
|
||||
it "should fail with redirected OPTIONS" do
|
||||
lambda do
|
||||
@klass.options('/foo', :no_follow => true)
|
||||
end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'}
|
||||
end
|
||||
end
|
||||
|
||||
describe "with multiple class definitions" do
|
||||
before(:each) do
|
||||
@klass.instance_eval do
|
||||
base_uri "http://first.com"
|
||||
default_params :one => 1
|
||||
end
|
||||
|
||||
@additional_klass = Class.new
|
||||
@additional_klass.instance_eval do
|
||||
include HTTParty
|
||||
base_uri "http://second.com"
|
||||
default_params :two => 2
|
||||
end
|
||||
end
|
||||
|
||||
it "should not run over each others options" do
|
||||
@klass.default_options.should == { :base_uri => 'http://first.com', :default_params => { :one => 1 } }
|
||||
@additional_klass.default_options.should == { :base_uri => 'http://second.com', :default_params => { :two => 2 } }
|
||||
end
|
||||
end
|
||||
|
||||
describe "two child classes inheriting from one parent" do
|
||||
before(:each) do
|
||||
@parent = Class.new do
|
||||
include HTTParty
|
||||
def self.name
|
||||
"Parent"
|
||||
end
|
||||
end
|
||||
|
||||
@child1 = Class.new(@parent)
|
||||
@child2 = Class.new(@parent)
|
||||
end
|
||||
|
||||
it "does not modify each others inherited attributes" do
|
||||
@child1.default_params :joe => "alive"
|
||||
@child2.default_params :joe => "dead"
|
||||
|
||||
@child1.default_options.should == { :default_params => {:joe => "alive"} }
|
||||
@child2.default_options.should == { :default_params => {:joe => "dead"} }
|
||||
|
||||
@parent.default_options.should == { }
|
||||
end
|
||||
|
||||
it "inherits default_options from the superclass" do
|
||||
@parent.basic_auth 'user', 'password'
|
||||
@child1.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}}
|
||||
@child1.basic_auth 'u', 'p' # modifying child1 has no effect on child2
|
||||
@child2.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}}
|
||||
end
|
||||
|
||||
it "doesn't modify the parent's default options" do
|
||||
@parent.basic_auth 'user', 'password'
|
||||
|
||||
@child1.basic_auth 'u', 'p'
|
||||
@child1.default_options.should == {:basic_auth => {:username => 'u', :password => 'p'}}
|
||||
|
||||
@child1.basic_auth 'email', 'token'
|
||||
@child1.default_options.should == {:basic_auth => {:username => 'email', :password => 'token'}}
|
||||
|
||||
@parent.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}}
|
||||
end
|
||||
|
||||
it "doesn't modify hashes in the parent's default options" do
|
||||
@parent.headers 'Accept' => 'application/json'
|
||||
@child1.headers 'Accept' => 'application/xml'
|
||||
|
||||
@parent.default_options[:headers].should == {'Accept' => 'application/json'}
|
||||
@child1.default_options[:headers].should == {'Accept' => 'application/xml'}
|
||||
end
|
||||
|
||||
it "inherits default_cookies from the parent class" do
|
||||
@parent.cookies 'type' => 'chocolate_chip'
|
||||
@child1.default_cookies.should == {"type" => "chocolate_chip"}
|
||||
@child1.cookies 'type' => 'snickerdoodle'
|
||||
@child1.default_cookies.should == {"type" => "snickerdoodle"}
|
||||
@child2.default_cookies.should == {"type" => "chocolate_chip"}
|
||||
end
|
||||
|
||||
it "doesn't modify the parent's default cookies" do
|
||||
@parent.cookies 'type' => 'chocolate_chip'
|
||||
|
||||
@child1.cookies 'type' => 'snickerdoodle'
|
||||
@child1.default_cookies.should == {"type" => "snickerdoodle"}
|
||||
|
||||
@parent.default_cookies.should == {"type" => "chocolate_chip"}
|
||||
end
|
||||
end
|
||||
|
||||
describe "grand parent with inherited callback" do
|
||||
before do
|
||||
@grand_parent = Class.new do
|
||||
def self.inherited(subclass)
|
||||
subclass.instance_variable_set(:@grand_parent, true)
|
||||
end
|
||||
end
|
||||
@parent = Class.new(@grand_parent) do
|
||||
include HTTParty
|
||||
end
|
||||
end
|
||||
it "continues running the #inherited on the parent" do
|
||||
child = Class.new(@parent)
|
||||
child.instance_variable_get(:@grand_parent).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#get" do
|
||||
it "should be able to get html" do
|
||||
stub_http_response_with('google.html')
|
||||
HTTParty.get('http://www.google.com').should == file_fixture('google.html')
|
||||
end
|
||||
|
||||
it "should be able to get chunked html" do
|
||||
chunks = ["Chunk1", "Chunk2", "Chunk3", "Chunk4"]
|
||||
stub_chunked_http_response_with(chunks)
|
||||
|
||||
HTTParty.get('http://www.google.com') do |fragment|
|
||||
chunks.should include(fragment)
|
||||
end.should == chunks.join
|
||||
end
|
||||
|
||||
it "should be able parse response type json automatically" do
|
||||
stub_http_response_with('twitter.json')
|
||||
tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
|
||||
tweets.size.should == 20
|
||||
tweets.first['user'].should == {
|
||||
"name" => "Pyk",
|
||||
"url" => nil,
|
||||
"id" => "7694602",
|
||||
"description" => nil,
|
||||
"protected" => false,
|
||||
"screen_name" => "Pyk",
|
||||
"followers_count" => 1,
|
||||
"location" => "Opera Plaza, California",
|
||||
"profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
|
||||
}
|
||||
end
|
||||
|
||||
it "should be able parse response type xml automatically" do
|
||||
stub_http_response_with('twitter.xml')
|
||||
tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
|
||||
tweets['statuses'].size.should == 20
|
||||
tweets['statuses'].first['user'].should == {
|
||||
"name" => "Magic 8 Bot",
|
||||
"url" => nil,
|
||||
"id" => "17656026",
|
||||
"description" => "ask me a question",
|
||||
"protected" => "false",
|
||||
"screen_name" => "magic8bot",
|
||||
"followers_count" => "90",
|
||||
"profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
|
||||
"location" => nil
|
||||
}
|
||||
end
|
||||
|
||||
it "should not get undefined method add_node for nil class for the following xml" do
|
||||
stub_http_response_with('undefined_method_add_node_for_nil.xml')
|
||||
result = HTTParty.get('http://foobar.com')
|
||||
result.should == {"Entities"=>{"href"=>"https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results"=>"0", "total"=>"0", "page_size"=>"25", "page"=>"1"}}
|
||||
end
|
||||
|
||||
it "should parse empty response fine" do
|
||||
stub_http_response_with('empty.xml')
|
||||
result = HTTParty.get('http://foobar.com')
|
||||
result.should be_nil
|
||||
end
|
||||
|
||||
it "should accept http URIs" do
|
||||
stub_http_response_with('google.html')
|
||||
lambda do
|
||||
HTTParty.get('http://google.com')
|
||||
end.should_not raise_error(HTTParty::UnsupportedURIScheme)
|
||||
end
|
||||
|
||||
it "should accept https URIs" do
|
||||
stub_http_response_with('google.html')
|
||||
lambda do
|
||||
HTTParty.get('https://google.com')
|
||||
end.should_not raise_error(HTTParty::UnsupportedURIScheme)
|
||||
end
|
||||
|
||||
it "should raise an ArgumentError on URIs that are not http or https" do
|
||||
lambda do
|
||||
HTTParty.get("file:///there_is_no_party_on/my/filesystem")
|
||||
end.should raise_error(HTTParty::UnsupportedURIScheme)
|
||||
end
|
||||
|
||||
it "should raise an InvalidURIError on URIs that can't be parsed at all" do
|
||||
lambda do
|
||||
HTTParty.get("It's the one that says 'Bad URI'")
|
||||
end.should raise_error(URI::InvalidURIError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
--colour
|
||||
--backtrace
|
|
@ -0,0 +1,30 @@
|
|||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "httparty"
|
||||
|
||||
require 'spec/autorun'
|
||||
require 'fakeweb'
|
||||
|
||||
def file_fixture(filename)
|
||||
open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read
|
||||
end
|
||||
|
||||
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.include HTTParty::StubResponse
|
||||
config.include HTTParty::SSLTestHelper
|
||||
|
||||
config.before(:suite) do
|
||||
FakeWeb.allow_net_connect = false
|
||||
end
|
||||
|
||||
config.after(:suite) do
|
||||
FakeWeb.allow_net_connect = true
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :use_ssl do
|
||||
match do |connection|
|
||||
connection.use_ssl?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
require 'pathname'
|
||||
|
||||
module HTTParty
|
||||
module SSLTestHelper
|
||||
def ssl_verify_test(mode, ca_basename, server_cert_filename)
|
||||
options = {
|
||||
:format => :json,
|
||||
:timeout => 30,
|
||||
}
|
||||
|
||||
if mode
|
||||
ca_path = File.expand_path("../../fixtures/ssl/generated/#{ca_basename}", __FILE__)
|
||||
raise ArgumentError.new("#{ca_path} does not exist") unless File.exist?(ca_path)
|
||||
options[mode] = ca_path
|
||||
end
|
||||
|
||||
begin
|
||||
test_server = SSLTestServer.new(
|
||||
:rsa_key => File.read(File.expand_path("../../fixtures/ssl/generated/server.key", __FILE__)),
|
||||
:cert => File.read(File.expand_path("../../fixtures/ssl/generated/#{server_cert_filename}", __FILE__)))
|
||||
|
||||
test_server.start
|
||||
|
||||
if mode
|
||||
ca_path = File.expand_path("../../fixtures/ssl/generated/#{ca_basename}", __FILE__)
|
||||
raise ArgumentError.new("#{ca_path} does not exist") unless File.exist?(ca_path)
|
||||
return HTTParty.get("https://localhost:#{test_server.port}/", :format => :json, :timeout => 30, mode => ca_path)
|
||||
else
|
||||
return HTTParty.get("https://localhost:#{test_server.port}/", :format => :json, :timeout => 30)
|
||||
end
|
||||
ensure
|
||||
test_server.stop if test_server
|
||||
end
|
||||
|
||||
test_server = SSLTestServer.new({
|
||||
:rsa_key => path.join('server.key').read,
|
||||
:cert => path.join(server_cert_filename).read,
|
||||
})
|
||||
|
||||
test_server.start
|
||||
|
||||
HTTParty.get("https://localhost:#{test_server.port}/", options)
|
||||
ensure
|
||||
test_server.stop if test_server
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,80 @@
|
|||
require 'openssl'
|
||||
require 'socket'
|
||||
require 'thread'
|
||||
|
||||
# NOTE: This code is garbage. It probably has deadlocks, it might leak
|
||||
# threads, and otherwise cause problems in a real system. It's really only
|
||||
# intended for testing HTTParty.
|
||||
class SSLTestServer
|
||||
attr_accessor :ctx # SSLContext object
|
||||
attr_reader :port
|
||||
|
||||
def initialize(options={})
|
||||
@ctx = OpenSSL::SSL::SSLContext.new
|
||||
@ctx.cert = OpenSSL::X509::Certificate.new(options[:cert])
|
||||
@ctx.key = OpenSSL::PKey::RSA.new(options[:rsa_key])
|
||||
@ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Don't verify client certificate
|
||||
@port = options[:port] || 0
|
||||
@thread = nil
|
||||
@stopping_mutex = Mutex.new
|
||||
@stopping = false
|
||||
end
|
||||
|
||||
def start
|
||||
@raw_server = TCPServer.new(@port)
|
||||
|
||||
if @port == 0
|
||||
@port = Socket::getnameinfo(@raw_server.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)[1].to_i
|
||||
end
|
||||
|
||||
@ssl_server = OpenSSL::SSL::SSLServer.new(@raw_server, @ctx)
|
||||
|
||||
@stopping_mutex.synchronize{
|
||||
return if @stopping
|
||||
@thread = Thread.new{ thread_main }
|
||||
}
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def stop
|
||||
@stopping_mutex.synchronize{
|
||||
return if @stopping
|
||||
@stopping = true
|
||||
}
|
||||
@thread.join
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def thread_main
|
||||
until @stopping_mutex.synchronize{ @stopping }
|
||||
(rr,ww,ee) = select([@ssl_server.to_io], nil, nil, 0.1)
|
||||
|
||||
next unless rr && rr.include?(@ssl_server.to_io)
|
||||
|
||||
socket = @ssl_server.accept
|
||||
|
||||
Thread.new{
|
||||
header = []
|
||||
|
||||
until (line = socket.readline).rstrip.empty?
|
||||
header << line
|
||||
end
|
||||
|
||||
response =<<EOF
|
||||
HTTP/1.1 200 OK
|
||||
Connection: close
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
|
||||
{"success":true}
|
||||
EOF
|
||||
|
||||
socket.write(response.gsub(/\r\n/n, "\n").gsub(/\n/n, "\r\n"))
|
||||
socket.close
|
||||
}
|
||||
end
|
||||
|
||||
@ssl_server.close
|
||||
end
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
module HTTParty
|
||||
module StubResponse
|
||||
def stub_http_response_with(filename)
|
||||
format = filename.split('.').last.intern
|
||||
data = file_fixture(filename)
|
||||
|
||||
response = Net::HTTPOK.new("1.1", 200, "Content for you")
|
||||
response.stub!(:body).and_return(data)
|
||||
|
||||
http_request = HTTParty::Request.new(Net::HTTP::Get, 'http://localhost', :format => format)
|
||||
http_request.stub_chain(:http, :request).and_return(response)
|
||||
|
||||
HTTParty::Request.should_receive(:new).and_return(http_request)
|
||||
end
|
||||
|
||||
def stub_chunked_http_response_with(chunks)
|
||||
response = Net::HTTPResponse.new("1.1", 200, nil)
|
||||
response.stub(:chunked_data).and_return(chunks)
|
||||
def response.read_body(&block)
|
||||
@body || chunked_data.each(&block)
|
||||
end
|
||||
|
||||
http_request = HTTParty::Request.new(Net::HTTP::Get, 'http://localhost', :format => "html")
|
||||
http_request.stub_chain(:http, :request).and_yield(response).and_return(response)
|
||||
|
||||
HTTParty::Request.should_receive(:new).and_return(http_request)
|
||||
end
|
||||
|
||||
def stub_response(body, code = 200)
|
||||
@request.options[:base_uri] ||= 'http://localhost'
|
||||
unless defined?(@http) && @http
|
||||
@http = Net::HTTP.new('localhost', 80)
|
||||
@request.stub!(:http).and_return(@http)
|
||||
end
|
||||
|
||||
response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new("1.1", code, body)
|
||||
response.stub!(:body).and_return(body)
|
||||
|
||||
@http.stub!(:request).and_return(response)
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
@media screen, projection {
|
||||
/*
|
||||
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://developer.yahoo.net/yui/license.txt
|
||||
version: 2.2.0
|
||||
*/
|
||||
body {font:13px arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}pre, code {font:115% monospace;*font-size:100%;}body * {line-height:1.22em;}
|
||||
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}/*ol,ul {list-style:none;}*/caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;}
|
||||
/* end of yahoo reset and fonts */
|
||||
|
||||
body {color:#333; background:#4b1a1a; line-height:1.3;}
|
||||
p {margin:0 0 20px;}
|
||||
a {color:#4b1a1a;}
|
||||
a:hover {text-decoration:none;}
|
||||
strong {font-weight:bold;}
|
||||
em {font-style:italics;}
|
||||
h1,h2,h3,h4,h5,h6 {font-weight:bold;}
|
||||
h1 {font-size:197%; margin:30px 0; color:#4b1a1a;}
|
||||
h2 {font-size:174%; margin:20px 0; color:#b8111a;}
|
||||
h3 {font-size:152%; margin:10px 0;}
|
||||
h4 {font-size:129%; margin:10px 0;}
|
||||
pre {background:#eee; margin:0 0 20px; padding:20px; border:1px solid #ccc; font-size:100%; overflow:auto;}
|
||||
code {font-size:100%; margin:0; padding:0;}
|
||||
ul, ol {margin:10px 0 10px 25px;}
|
||||
ol li {margin:0 0 10px;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
div#wrapper {background:#fff; width:560px; margin:0 auto; padding:20px; border:10px solid #bc8c46; border-width:0 10px;}
|
||||
div#header {position:relative; border-bottom:1px dotted; margin:0 0 10px; padding:0 0 10px;}
|
||||
div#header p {margin:0; padding:0;}
|
||||
div#header h1 {margin:0; padding:0;}
|
||||
ul#nav {position:absolute; top:0; right:0; list-style:none; margin:0; padding:0;}
|
||||
ul#nav li {display:inline; padding:0 0 0 5px;}
|
||||
ul#nav li a {}
|
||||
div#content {}
|
||||
div#footer {margin:40px 0 0; border-top:1px dotted; padding:10px 0 0;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>HTTParty by John Nunemaker</title>
|
||||
<link rel="stylesheet" href="css/common.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="wrapper">
|
||||
<div id="header">
|
||||
<h1>HTTParty</h1>
|
||||
<p>Tonight we're gonna HTTParty like it's 1999!</p>
|
||||
|
||||
<ul id="nav">
|
||||
<li><a href="rdoc/">Docs</a></li>
|
||||
<li><a href="http://github.com/jnunemaker/httparty">Github</a></li>
|
||||
<li><a href="http://rubyforge.org/projects/httparty/">Rubyforge</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h2>Install</h2>
|
||||
<pre><code>$ sudo gem install httparty</code></pre>
|
||||
|
||||
<h2>Some Quick Examples</h2>
|
||||
|
||||
<p>The following is a simple example of wrapping Twitter's API for posting updates.</p>
|
||||
|
||||
<pre><code>class Twitter
|
||||
include HTTParty
|
||||
base_uri 'twitter.com'
|
||||
basic_auth 'username', 'password'
|
||||
end
|
||||
|
||||
Twitter.post('/statuses/update.json', :query => {:status => "It's an HTTParty and everyone is invited!"})</code></pre>
|
||||
|
||||
<p>That is really it! The object returned is a ruby hash that is decoded from Twitter's json response. JSON parsing is used because of the .json extension in the path of the request. You can also explicitly set a format (see the examples). </p>
|
||||
|
||||
<p>That works and all but what if you don't want to embed your username and password in the class? Below is an example to fix that:</p>
|
||||
|
||||
<pre><code>class Twitter
|
||||
include HTTParty
|
||||
base_uri 'twitter.com'
|
||||
|
||||
def initialize(u, p)
|
||||
@auth = {:username => u, :password => p}
|
||||
end
|
||||
|
||||
def post(text)
|
||||
options = { :query => {:status => text}, :basic_auth => @auth }
|
||||
self.class.post('/statuses/update.json', options)
|
||||
end
|
||||
end
|
||||
|
||||
Twitter.new('username', 'password').post("It's an HTTParty and everyone is invited!")</code></pre>
|
||||
|
||||
<p><strong>More Examples:</strong> There are <a href="http://github.com/jnunemaker/httparty/tree/master/examples/">several examples in the gem itself</a>.</p>
|
||||
|
||||
<h2>Support</h2>
|
||||
<p>Conversations welcome in the <a href="http://groups.google.com/group/httparty-gem">google group</a> and bugs/features over at <a href="http://github.com/jnunemaker/httparty">Github</a>.</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p>Created by <a href="http://addictedtonew.com/about/">John Nunemaker</a> |
|
||||
<a href="http://orderedlist.com/">Hire Me at Ordered List</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,5 @@
|
|||
LICENSE.md
|
||||
README.md
|
||||
bin/*
|
||||
features/**/*.feature
|
||||
lib/**/*.rb
|
|
@ -0,0 +1,3 @@
|
|||
--color
|
||||
--fail-fast
|
||||
--order random
|
|
@ -0,0 +1,10 @@
|
|||
language: ruby
|
||||
rvm:
|
||||
- rbx-18mode
|
||||
- rbx-19mode
|
||||
- jruby-18mode
|
||||
- jruby-19mode
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- 1.9.3
|
||||
- ruby-head
|
|
@ -0,0 +1,7 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'json', '~> 1.4', :require => nil
|
||||
gem 'oj', '~> 1.0', :require => nil, :platforms => [:ruby, :mswin, :mingw]
|
||||
gem 'yajl-ruby', '~> 1.0', :require => nil, :platforms => [:ruby, :mswin, :mingw]
|
||||
|
||||
gemspec
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2010 Michael Bleigh, Josh Kalderimis, Erik Michaels-Ober, and Intridea, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,72 @@
|
|||
# MultiJSON [![Build Status](https://secure.travis-ci.org/intridea/multi_json.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/intridea/multi_json.png?travis)][gemnasium]
|
||||
|
||||
[travis]: http://travis-ci.org/intridea/multi_json
|
||||
[gemnasium]: https://gemnasium.com/intridea/multi_json
|
||||
|
||||
Lots of Ruby libraries parse JSON and everyone has their favorite JSON coder.
|
||||
Instead of choosing a single JSON coder and forcing users of your library to be
|
||||
stuck with it, you can use MultiJSON instead, which will simply choose the
|
||||
fastest available JSON coder. Here's how to use it:
|
||||
|
||||
require 'multi_json'
|
||||
|
||||
MultiJson.load('{"abc":"def"}') #=> {"abc" => "def"}
|
||||
MultiJson.load('{"abc":"def"}', :symbolize_keys => true) #=> {:abc => "def"}
|
||||
MultiJson.dump({:abc => 'def'}) # convert Ruby back to JSON
|
||||
MultiJson.dump({:abc => 'def'}, :pretty => true) # encoded in a pretty form (if supported by the coder)
|
||||
|
||||
The `use` method, which sets the MultiJson adapter, takes either a symbol or a
|
||||
class (to allow for custom JSON parsers) that responds to both `.load` and `.dump`
|
||||
at the class level.
|
||||
|
||||
MultiJSON tries to have intelligent defaulting. That is, if you have any of the
|
||||
supported engines already loaded, it will utilize them before attempting to
|
||||
load any. When loading, libraries are ordered by speed. First Oj, then Yajl,
|
||||
then the JSON gem, then JSON pure. If no other JSON library is available,
|
||||
MultiJSON falls back to [OkJson][], a simple, vendorable JSON parser.
|
||||
|
||||
[okjson]: https://github.com/kr/okjson
|
||||
|
||||
## Supported JSON Engines
|
||||
|
||||
* [Oj](https://github.com/ohler55/oj) Optimized JSON by Peter Ohler
|
||||
* [Yajl](https://github.com/brianmario/yajl-ruby) Yet Another JSON Library by Brian Lopez
|
||||
* [JSON](https://github.com/flori/json) The default JSON gem with C-extensions (ships with Ruby 1.9)
|
||||
* [JSON Pure](https://github.com/flori/json) A Ruby variant of the JSON gem
|
||||
* [NSJSONSerialization](https://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html) Wrapper for Apple's NSJSONSerialization in the Cocoa Framework (MacRuby only)
|
||||
* [OkJson][okjson] A simple, vendorable JSON parser
|
||||
|
||||
## Supported Ruby Versions
|
||||
This library aims to support and is [tested against][travis] the following Ruby
|
||||
implementations:
|
||||
|
||||
* Ruby 1.8.7
|
||||
* Ruby 1.9.2
|
||||
* Ruby 1.9.3
|
||||
* [JRuby][]
|
||||
* [Rubinius][]
|
||||
* [MacRuby][] (not tested on Travis CI)
|
||||
|
||||
[jruby]: http://www.jruby.org/
|
||||
[rubinius]: http://rubini.us/
|
||||
[macruby]: http://www.macruby.org/
|
||||
|
||||
If something doesn't work on one of these interpreters, it should be considered
|
||||
a bug.
|
||||
|
||||
This library may inadvertently work (or seem to work) on other Ruby
|
||||
implementations, however support will only be provided for the versions listed
|
||||
above.
|
||||
|
||||
If you would like this library to support another Ruby version, you may
|
||||
volunteer to be a maintainer. Being a maintainer entails making sure all tests
|
||||
run and pass on that implementation. When something breaks on your
|
||||
implementation, you will be personally responsible for providing patches in a
|
||||
timely fashion. If critical issues for a particular implementation exist at the
|
||||
time of a major release, support for that Ruby version may be dropped.
|
||||
|
||||
## Copyright
|
||||
Copyright (c) 2010 Michael Bleigh, Josh Kalderimis, Erik Michaels-Ober, and Intridea, Inc.
|
||||
See [LICENSE][] for details.
|
||||
|
||||
[license]: https://github.com/intridea/multi_json/blob/master/LICENSE.md
|
|
@ -0,0 +1,20 @@
|
|||
require 'bundler'
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
desc "Run all examples"
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
task :default => :spec
|
||||
task :test => :spec
|
||||
|
||||
namespace :doc do
|
||||
require 'rdoc/task'
|
||||
require File.expand_path('../lib/multi_json/version', __FILE__)
|
||||
RDoc::Task.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = "multi_json #{MultiJson::VERSION}"
|
||||
rdoc.main = 'README.md'
|
||||
rdoc.rdoc_files.include('README.md', 'LICENSE.md', 'lib/**/*.rb')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,122 @@
|
|||
module MultiJson
|
||||
class DecodeError < StandardError
|
||||
attr_reader :data
|
||||
def initialize(message="", backtrace=[], data="")
|
||||
super(message)
|
||||
self.set_backtrace(backtrace)
|
||||
@data = data
|
||||
end
|
||||
end
|
||||
|
||||
@adapter = nil
|
||||
|
||||
REQUIREMENT_MAP = [
|
||||
["oj", :oj],
|
||||
["yajl", :yajl],
|
||||
["json", :json_gem],
|
||||
["json/pure", :json_pure]
|
||||
]
|
||||
|
||||
class << self
|
||||
|
||||
# The default adapter based on what you currently
|
||||
# have loaded and installed. First checks to see
|
||||
# if any adapters are already loaded, then checks
|
||||
# to see which are installed if none are loaded.
|
||||
def default_adapter
|
||||
return :oj if defined?(::Oj)
|
||||
return :yajl if defined?(::Yajl)
|
||||
return :json_gem if defined?(::JSON)
|
||||
|
||||
REQUIREMENT_MAP.each do |(library, adapter)|
|
||||
begin
|
||||
require library
|
||||
return adapter
|
||||
rescue LoadError
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
Kernel.warn "[WARNING] MultiJson is using the default adapter (ok_json). We recommend loading a different JSON library to improve performance."
|
||||
:ok_json
|
||||
end
|
||||
# :nodoc:
|
||||
alias :default_engine :default_adapter
|
||||
|
||||
# Get the current adapter class.
|
||||
def adapter
|
||||
return @adapter if @adapter
|
||||
self.use self.default_adapter
|
||||
@adapter
|
||||
end
|
||||
# :nodoc:
|
||||
alias :engine :adapter
|
||||
|
||||
# Set the JSON parser utilizing a symbol, string, or class.
|
||||
# Supported by default are:
|
||||
#
|
||||
# * <tt>:oj</tt>
|
||||
# * <tt>:json_gem</tt>
|
||||
# * <tt>:json_pure</tt>
|
||||
# * <tt>:ok_json</tt>
|
||||
# * <tt>:yajl</tt>
|
||||
# * <tt>:nsjsonserialization</tt> (MacRuby only)
|
||||
def use(new_adapter)
|
||||
@adapter = load_adapter(new_adapter)
|
||||
end
|
||||
alias :adapter= :use
|
||||
# :nodoc:
|
||||
alias :engine= :use
|
||||
|
||||
def load_adapter(new_adapter)
|
||||
case new_adapter
|
||||
when String, Symbol
|
||||
require "multi_json/adapters/#{new_adapter}"
|
||||
MultiJson::Adapters.const_get(:"#{new_adapter.to_s.split('_').map{|s| s.capitalize}.join('')}")
|
||||
when NilClass, FalseClass
|
||||
default_adapter = self.default_adapter
|
||||
require "multi_json/adapters/#{default_adapter}"
|
||||
MultiJson::Adapters.const_get(:"#{default_adapter.to_s.split('_').map{|s| s.capitalize}.join('')}")
|
||||
when Class
|
||||
new_adapter
|
||||
else
|
||||
raise "Did not recognize your adapter specification. Please specify either a symbol or a class."
|
||||
end
|
||||
end
|
||||
|
||||
# Decode a JSON string into Ruby.
|
||||
#
|
||||
# <b>Options</b>
|
||||
#
|
||||
# <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys.
|
||||
# <tt>:adapter</tt> :: If set, the selected engine will be used just for the call.
|
||||
def load(string, options={})
|
||||
adapter = current_adapter(options)
|
||||
begin
|
||||
adapter.load(string, options)
|
||||
rescue adapter::ParseError => exception
|
||||
raise DecodeError.new(exception.message, exception.backtrace, string)
|
||||
end
|
||||
end
|
||||
# :nodoc:
|
||||
alias :decode :load
|
||||
|
||||
def current_adapter(options)
|
||||
if new_adapter = (options || {}).delete(:adapter)
|
||||
load_adapter(new_adapter)
|
||||
else
|
||||
adapter
|
||||
end
|
||||
end
|
||||
|
||||
# Encodes a Ruby object as JSON.
|
||||
def dump(object, options={})
|
||||
adapter = current_adapter(options)
|
||||
adapter.dump(object, options)
|
||||
end
|
||||
# :nodoc:
|
||||
alias :encode :dump
|
||||
|
||||
end
|
||||
|
||||
end
|
25
vendor/ruby/1.9.1/gems/multi_json-1.4.0/lib/multi_json/adapters/json_common.rb
vendored
Normal file
25
vendor/ruby/1.9.1/gems/multi_json-1.4.0/lib/multi_json/adapters/json_common.rb
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
module MultiJson
|
||||
module Adapters
|
||||
module JsonCommon
|
||||
|
||||
def load(string, options={})
|
||||
string = string.read if string.respond_to?(:read)
|
||||
::JSON.parse(string, :symbolize_names => options[:symbolize_keys], :quirks_mode => true)
|
||||
end
|
||||
|
||||
def dump(object, options={})
|
||||
object.to_json(process_options(options))
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def process_options(options={})
|
||||
return options if options.empty?
|
||||
opts = {}
|
||||
opts.merge!(JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
|
||||
opts.merge!(options)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
require 'json' unless defined?(::JSON)
|
||||
require 'multi_json/adapters/json_common'
|
||||
|
||||
module MultiJson
|
||||
module Adapters
|
||||
# Use the JSON gem to dump/load.
|
||||
class JsonGem
|
||||
ParseError = ::JSON::ParserError
|
||||
extend JsonCommon
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue