httparty-responsibly 0.17.0.r1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +18 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +92 -0
  5. data/.rubocop_todo.yml +124 -0
  6. data/.simplecov +1 -0
  7. data/.travis.yml +11 -0
  8. data/CONTRIBUTING.md +23 -0
  9. data/Changelog.md +502 -0
  10. data/Gemfile +23 -0
  11. data/Guardfile +16 -0
  12. data/MIT-LICENSE +20 -0
  13. data/README.md +78 -0
  14. data/Rakefile +10 -0
  15. data/bin/httparty +123 -0
  16. data/cucumber.yml +1 -0
  17. data/docs/README.md +106 -0
  18. data/examples/README.md +86 -0
  19. data/examples/aaws.rb +32 -0
  20. data/examples/basic.rb +28 -0
  21. data/examples/body_stream.rb +14 -0
  22. data/examples/crack.rb +19 -0
  23. data/examples/custom_parsers.rb +68 -0
  24. data/examples/delicious.rb +37 -0
  25. data/examples/google.rb +16 -0
  26. data/examples/headers_and_user_agents.rb +10 -0
  27. data/examples/logging.rb +36 -0
  28. data/examples/microsoft_graph.rb +52 -0
  29. data/examples/multipart.rb +22 -0
  30. data/examples/nokogiri_html_parser.rb +19 -0
  31. data/examples/peer_cert.rb +9 -0
  32. data/examples/rescue_json.rb +17 -0
  33. data/examples/rubyurl.rb +14 -0
  34. data/examples/stackexchange.rb +24 -0
  35. data/examples/stream_download.rb +26 -0
  36. data/examples/tripit_sign_in.rb +44 -0
  37. data/examples/twitter.rb +31 -0
  38. data/examples/whoismyrep.rb +10 -0
  39. data/httparty-responsibly.gemspec +27 -0
  40. data/lib/httparty.rb +684 -0
  41. data/lib/httparty/connection_adapter.rb +244 -0
  42. data/lib/httparty/cookie_hash.rb +21 -0
  43. data/lib/httparty/exceptions.rb +33 -0
  44. data/lib/httparty/hash_conversions.rb +69 -0
  45. data/lib/httparty/logger/apache_formatter.rb +45 -0
  46. data/lib/httparty/logger/curl_formatter.rb +91 -0
  47. data/lib/httparty/logger/logger.rb +28 -0
  48. data/lib/httparty/logger/logstash_formatter.rb +59 -0
  49. data/lib/httparty/module_inheritable_attributes.rb +56 -0
  50. data/lib/httparty/net_digest_auth.rb +136 -0
  51. data/lib/httparty/parser.rb +150 -0
  52. data/lib/httparty/request.rb +386 -0
  53. data/lib/httparty/request/body.rb +84 -0
  54. data/lib/httparty/request/multipart_boundary.rb +11 -0
  55. data/lib/httparty/response.rb +140 -0
  56. data/lib/httparty/response/headers.rb +33 -0
  57. data/lib/httparty/response_fragment.rb +19 -0
  58. data/lib/httparty/text_encoder.rb +70 -0
  59. data/lib/httparty/utils.rb +11 -0
  60. data/lib/httparty/version.rb +3 -0
  61. data/script/release +42 -0
  62. data/website/css/common.css +47 -0
  63. data/website/index.html +73 -0
  64. metadata +138 -0
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require File.join(dir, 'httparty')
6
+ require 'pp'
7
+ config = YAML.load(File.read(File.join(ENV['HOME'], '.aaws')))
8
+
9
+ module AAWS
10
+ class Book
11
+ include HTTParty
12
+ base_uri 'http://ecs.amazonaws.com'
13
+ default_params Service: 'AWSECommerceService', Operation: 'ItemSearch', SearchIndex: 'Books'
14
+
15
+ def initialize(key)
16
+ self.class.default_params AWSAccessKeyId: key
17
+ end
18
+
19
+ def search(options = {})
20
+ raise ArgumentError, 'You must search for something' if options[:query].blank?
21
+
22
+ # amazon uses nasty camelized query params
23
+ options[:query] = options[:query].inject({}) { |h, q| h[q[0].to_s.camelize] = q[1]; h }
24
+
25
+ # make a request and return the items (NOTE: this doesn't handle errors at this point)
26
+ self.class.get('/onca/xml', options)['ItemSearchResponse']['Items']
27
+ end
28
+ end
29
+ end
30
+
31
+ aaws = AAWS::Book.new(config[:access_key])
32
+ pp aaws.search(query: { title: 'Ruby On Rails' })
@@ -0,0 +1,28 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ # You can also use post, put, delete, head, options in the same fashion
6
+ response = HTTParty.get('https://api.stackexchange.com/2.2/questions?site=stackoverflow')
7
+ puts response.body, response.code, response.message, response.headers.inspect
8
+
9
+ # An example post to a minimal rails app in the development environment
10
+ # Note that "skip_before_filter :verify_authenticity_token" must be set in the
11
+ # "pears" controller for this example
12
+
13
+ class Partay
14
+ include HTTParty
15
+ base_uri 'http://localhost:3000'
16
+ end
17
+
18
+ options = {
19
+ body: {
20
+ pear: { # your resource
21
+ foo: '123', # your columns/data
22
+ bar: 'second',
23
+ baz: 'last thing'
24
+ }
25
+ }
26
+ }
27
+
28
+ pp Partay.post('/pears.xml', options)
@@ -0,0 +1,14 @@
1
+ # To upload file to a server use :body_stream
2
+
3
+ HTTParty.put(
4
+ 'http://localhost:3000/train',
5
+ body_stream: File.open('sample_configs/config_train_server_md.yml', 'r')
6
+ )
7
+
8
+
9
+ # Actually, it works with any IO object
10
+
11
+ HTTParty.put(
12
+ 'http://localhost:3000/train',
13
+ body_stream: StringIO.new('foo')
14
+ )
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'crack'
3
+
4
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require File.join(dir, 'httparty')
6
+ require 'pp'
7
+
8
+ class Rep
9
+ include HTTParty
10
+
11
+ parser(
12
+ proc do |body, format|
13
+ Crack::XML.parse(body)
14
+ end
15
+ )
16
+ end
17
+
18
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php?zip=46544')
19
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', query: { zip: 46544 })
@@ -0,0 +1,68 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class ParseAtom
6
+ include HTTParty
7
+
8
+ # Support Atom along with the default parsers: xml, json, etc.
9
+ class Parser::Atom < HTTParty::Parser
10
+ SupportedFormats.merge!({"application/atom+xml" => :atom})
11
+
12
+ protected
13
+
14
+ # perform atom parsing on body
15
+ def atom
16
+ body.to_atom
17
+ end
18
+ end
19
+
20
+ parser Parser::Atom
21
+ end
22
+
23
+ class OnlyParseAtom
24
+ include HTTParty
25
+
26
+ # Only support Atom
27
+ class Parser::OnlyAtom < HTTParty::Parser
28
+ SupportedFormats = { "application/atom+xml" => :atom }
29
+
30
+ protected
31
+
32
+ # perform atom parsing on body
33
+ def atom
34
+ body.to_atom
35
+ end
36
+ end
37
+
38
+ parser Parser::OnlyAtom
39
+ end
40
+
41
+ class SkipParsing
42
+ include HTTParty
43
+
44
+ # Parse the response body however you like
45
+ class Parser::Simple < HTTParty::Parser
46
+ def parse
47
+ body
48
+ end
49
+ end
50
+
51
+ parser Parser::Simple
52
+ end
53
+
54
+ class AdHocParsing
55
+ include HTTParty
56
+ parser(
57
+ proc do |body, format|
58
+ case format
59
+ when :json
60
+ body.to_json
61
+ when :xml
62
+ body.to_xml
63
+ else
64
+ body
65
+ end
66
+ end
67
+ )
68
+ end
@@ -0,0 +1,37 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+ config = YAML.load(File.read(File.join(ENV['HOME'], '.delicious')))
5
+
6
+ class Delicious
7
+ include HTTParty
8
+ base_uri 'https://api.del.icio.us/v1'
9
+
10
+ def initialize(u, p)
11
+ @auth = { username: u, password: p }
12
+ end
13
+
14
+ # query params that filter the posts are:
15
+ # tag (optional). Filter by this tag.
16
+ # dt (optional). Filter by this date (CCYY-MM-DDThh:mm:ssZ).
17
+ # url (optional). Filter by this url.
18
+ # ie: posts(query: {tag: 'ruby'})
19
+ def posts(options = {})
20
+ options.merge!({ basic_auth: @auth })
21
+ self.class.get('/posts/get', options)
22
+ end
23
+
24
+ # query params that filter the posts are:
25
+ # tag (optional). Filter by this tag.
26
+ # count (optional). Number of items to retrieve (Default:15, Maximum:100).
27
+ def recent(options = {})
28
+ options.merge!({ basic_auth: @auth })
29
+ self.class.get('/posts/recent', options)
30
+ end
31
+ end
32
+
33
+ delicious = Delicious.new(config['username'], config['password'])
34
+ pp delicious.posts(query: { tag: 'ruby' })
35
+ pp delicious.recent
36
+
37
+ delicious.recent['posts']['post'].each { |post| puts post['href'] }
@@ -0,0 +1,16 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class Google
6
+ include HTTParty
7
+ format :html
8
+ end
9
+
10
+ # google.com redirects to www.google.com so this is live test for redirection
11
+ pp Google.get('http://google.com')
12
+
13
+ puts '', '*' * 70, ''
14
+
15
+ # check that ssl is requesting right
16
+ pp Google.get('https://www.google.com')
@@ -0,0 +1,10 @@
1
+ # 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.
2
+
3
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require File.join(dir, 'httparty')
5
+ require 'pp'
6
+
7
+ response = HTTParty.get('http://example.com', {
8
+ headers: {"User-Agent" => "Httparty"},
9
+ debug_output: STDOUT, # To show that User-Agent is Httparty
10
+ })
@@ -0,0 +1,36 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'logger'
4
+ require 'pp'
5
+
6
+ my_logger = Logger.new STDOUT
7
+
8
+ my_logger.info "Logging can be used on the main HTTParty class. It logs redirects too."
9
+ HTTParty.get "http://google.com", logger: my_logger
10
+
11
+ my_logger.info '*' * 70
12
+
13
+ my_logger.info "It can be used also on a custom class."
14
+
15
+ class Google
16
+ include HTTParty
17
+ logger ::Logger.new STDOUT
18
+ end
19
+
20
+ Google.get "http://google.com"
21
+
22
+ my_logger.info '*' * 70
23
+
24
+ my_logger.info "The default formatter is :apache. The :curl formatter can also be used."
25
+ my_logger.info "You can tell which method to call on the logger too. It is info by default."
26
+ HTTParty.get "http://google.com", logger: my_logger, log_level: :debug, log_format: :curl
27
+
28
+ my_logger.info '*' * 70
29
+
30
+ my_logger.info "These configs are also available on custom classes."
31
+ class Google
32
+ include HTTParty
33
+ logger ::Logger.new(STDOUT), :debug, :curl
34
+ end
35
+
36
+ Google.get "http://google.com"
@@ -0,0 +1,52 @@
1
+ require 'httparty'
2
+
3
+ class MicrosoftGraph
4
+ MS_BASE_URL = "https://login.microsoftonline.com".freeze
5
+ TOKEN_REQUEST_PATH = "oauth2/v2.0/token".freeze
6
+
7
+ def initialize(tenant_id)
8
+ @tenant_id = tenant_id
9
+ end
10
+
11
+ # Make a request to the Microsoft Graph API, for instance https://graph.microsoft.com/v1.0/users
12
+ def request(url)
13
+ return false unless (token = bearer_token)
14
+
15
+ response = HTTParty.get(
16
+ url,
17
+ headers: {
18
+ Authorization: "Bearer #{token}"
19
+ }
20
+ )
21
+
22
+ return false unless response.code == 200
23
+
24
+ return JSON.parse(response.body)
25
+ end
26
+
27
+ private
28
+
29
+ # A post to the Microsoft Graph to get a bearer token for the specified tenant. In this example
30
+ # our Rails application has already been given permission to request these tokens by the admin of
31
+ # the specified tenant_id.
32
+ #
33
+ # See here for more information https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service
34
+ #
35
+ # This request also makes use of the multipart/form-data post body.
36
+ def bearer_token
37
+ response = HTTParty.post(
38
+ "#{MS_BASE_URL}/#{@tenant_id}/#{TOKEN_REQUEST_PATH}",
39
+ multipart: true,
40
+ body: {
41
+ client_id: Rails.application.credentials[Rails.env.to_sym][:microsoft_client_id],
42
+ client_secret: Rails.application.credentials[Rails.env.to_sym][:microsoft_client_secret],
43
+ scope: 'https://graph.microsoft.com/.default',
44
+ grant_type: 'client_credentials'
45
+ }
46
+ )
47
+
48
+ return false unless response.code == 200
49
+
50
+ JSON.parse(response.body)['access_token']
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ # If you are uploading file in params, multipart will used as content-type automatically
2
+
3
+ HTTParty.post(
4
+ 'http://localhost:3000/user',
5
+ body: {
6
+ name: 'Foo Bar',
7
+ email: 'example@email.com',
8
+ avatar: File.open('/full/path/to/avatar.jpg')
9
+ }
10
+ )
11
+
12
+
13
+ # However, you can force it yourself
14
+
15
+ HTTParty.post(
16
+ 'http://localhost:3000/user',
17
+ multipart: true,
18
+ body: {
19
+ name: 'Foo Bar',
20
+ email: 'example@email.com'
21
+ }
22
+ )
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+
4
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require File.join(dir, 'httparty')
6
+ require 'pp'
7
+
8
+ class HtmlParserIncluded < HTTParty::Parser
9
+ def html
10
+ Nokogiri::HTML(body)
11
+ end
12
+ end
13
+
14
+ class Page
15
+ include HTTParty
16
+ parser HtmlParserIncluded
17
+ end
18
+
19
+ pp Page.get('http://www.google.com')
@@ -0,0 +1,9 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+
4
+ peer_cert = nil
5
+ HTTParty.get("https://www.example.com") do |fragment|
6
+ peer_cert ||= fragment.connection.peer_cert
7
+ end
8
+
9
+ puts "The server's certificate expires #{peer_cert.not_after}"
@@ -0,0 +1,17 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+
4
+ # Take note of the "; 1" at the end of the following line. It's required only if
5
+ # running this in IRB, because IRB will try to inspect the variable named
6
+ # "request", triggering the exception.
7
+ request = HTTParty.get 'https://rubygems.org/api/v1/versions/doesnotexist.json' ; 1
8
+
9
+ # Check an exception due to parsing the response
10
+ # because HTTParty evaluate the response lazily
11
+ begin
12
+ request.inspect
13
+ # This would also suffice by forcing the request to be parsed:
14
+ # request.parsed_response
15
+ rescue => e
16
+ puts "Rescued #{e.inspect}"
17
+ end
@@ -0,0 +1,14 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class Rubyurl
6
+ include HTTParty
7
+ base_uri 'rubyurl.com'
8
+
9
+ def self.shorten(website_url)
10
+ post('/api/links.json', query: { link: { website_url: website_url } })
11
+ end
12
+ end
13
+
14
+ pp Rubyurl.shorten('http://istwitterdown.com/')
@@ -0,0 +1,24 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class StackExchange
6
+ include HTTParty
7
+ base_uri 'api.stackexchange.com'
8
+
9
+ def initialize(service, page)
10
+ @options = { query: { site: service, page: page } }
11
+ end
12
+
13
+ def questions
14
+ self.class.get("/2.2/questions", @options)
15
+ end
16
+
17
+ def users
18
+ self.class.get("/2.2/users", @options)
19
+ end
20
+ end
21
+
22
+ stack_exchange = StackExchange.new("stackoverflow", 1)
23
+ pp stack_exchange.questions
24
+ pp stack_exchange.users
@@ -0,0 +1,26 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ # download file linux-4.6.4.tar.xz without using the memory
6
+ response = nil
7
+ filename = "linux-4.6.4.tar.xz"
8
+ url = "https://cdn.kernel.org/pub/linux/kernel/v4.x/#{filename}"
9
+
10
+ File.open(filename, "w") do |file|
11
+ response = HTTParty.get(url, stream_body: true) do |fragment|
12
+ if [301, 302].include?(fragment.code)
13
+ print "skip writing for redirect"
14
+ elsif fragment.code == 200
15
+ print "."
16
+ file.write(fragment)
17
+ else
18
+ raise StandardError, "Non-success status code while streaming #{fragment.code}"
19
+ end
20
+ end
21
+ end
22
+ puts
23
+
24
+ pp "Success: #{response.success?}"
25
+ pp File.stat(filename).inspect
26
+ File.unlink(filename)