httparty-responsibly 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) 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 +509 -0
  10. data/Gemfile +24 -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 +668 -0
  41. data/lib/httparty/connection_adapter.rb +254 -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/headers_processor.rb +30 -0
  46. data/lib/httparty/logger/apache_formatter.rb +45 -0
  47. data/lib/httparty/logger/curl_formatter.rb +91 -0
  48. data/lib/httparty/logger/logger.rb +28 -0
  49. data/lib/httparty/logger/logstash_formatter.rb +59 -0
  50. data/lib/httparty/module_inheritable_attributes.rb +56 -0
  51. data/lib/httparty/net_digest_auth.rb +136 -0
  52. data/lib/httparty/parser.rb +150 -0
  53. data/lib/httparty/request.rb +386 -0
  54. data/lib/httparty/request/body.rb +84 -0
  55. data/lib/httparty/request/multipart_boundary.rb +11 -0
  56. data/lib/httparty/response.rb +140 -0
  57. data/lib/httparty/response/headers.rb +33 -0
  58. data/lib/httparty/response_fragment.rb +19 -0
  59. data/lib/httparty/text_encoder.rb +70 -0
  60. data/lib/httparty/utils.rb +11 -0
  61. data/lib/httparty/version.rb +3 -0
  62. data/script/release +42 -0
  63. data/website/css/common.css +47 -0
  64. data/website/index.html +73 -0
  65. metadata +138 -0
@@ -0,0 +1,11 @@
1
+ require 'securerandom'
2
+
3
+ module HTTParty
4
+ class Request
5
+ class MultipartBoundary
6
+ def self.generate
7
+ "------------------------#{SecureRandom.urlsafe_base64(12)}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,140 @@
1
+ module HTTParty
2
+ class Response < Object
3
+ def self.underscore(string)
4
+ string.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
5
+ end
6
+
7
+ def self._load(data)
8
+ req, resp, parsed_resp, resp_body = Marshal.load(data)
9
+
10
+ new(req, resp, -> { parsed_resp }, body: resp_body)
11
+ end
12
+
13
+ attr_reader :request, :response, :body, :headers
14
+
15
+ def initialize(request, response, parsed_block, options = {})
16
+ @request = request
17
+ @response = response
18
+ @body = options[:body] || response.body
19
+ @parsed_block = parsed_block
20
+ @headers = Headers.new(response.to_hash)
21
+
22
+ if request.options[:logger]
23
+ logger = ::HTTParty::Logger.build(
24
+ request.options[:logger],
25
+ request.options[:log_level],
26
+ request.options[:log_format]
27
+ )
28
+ logger.format(request, self)
29
+ end
30
+
31
+ throw_exception
32
+ end
33
+
34
+ def parsed_response
35
+ @parsed_response ||= @parsed_block.call
36
+ end
37
+
38
+ def code
39
+ response.code.to_i
40
+ end
41
+
42
+ def http_version
43
+ response.http_version
44
+ end
45
+
46
+ def tap
47
+ yield self
48
+ self
49
+ end
50
+
51
+ def inspect
52
+ inspect_id = ::Kernel::format "%x", (object_id * 2)
53
+ %(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
54
+ end
55
+
56
+ CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
57
+
58
+ CODES_TO_OBJ.each do |response_code, klass|
59
+ name = klass.name.sub("Net::HTTP", '')
60
+ name = "#{underscore(name)}?".to_sym
61
+
62
+ define_method(name) do
63
+ klass === response
64
+ end
65
+ end
66
+
67
+ # Support old multiple_choice? method from pre 2.0.0 era.
68
+ if ::RUBY_VERSION >= "2.0.0" && ::RUBY_PLATFORM != "java"
69
+ alias_method :multiple_choice?, :multiple_choices?
70
+ end
71
+
72
+ # Support old status codes method from pre 2.6.0 era.
73
+ if ::RUBY_VERSION >= "2.6.0" && ::RUBY_PLATFORM != "java"
74
+ alias_method :gateway_time_out?, :gateway_timeout?
75
+ alias_method :request_entity_too_large?, :payload_too_large?
76
+ alias_method :request_time_out?, :request_timeout?
77
+ alias_method :request_uri_too_long?, :uri_too_long?
78
+ alias_method :requested_range_not_satisfiable?, :range_not_satisfiable?
79
+ end
80
+
81
+ def nil?
82
+ response.nil? || response.body.nil? || response.body.empty?
83
+ end
84
+
85
+ def to_s
86
+ if !response.nil? && !response.body.nil? && response.body.respond_to?(:to_s)
87
+ response.body.to_s
88
+ else
89
+ inspect
90
+ end
91
+ end
92
+
93
+ def pretty_print(pp)
94
+ if !parsed_response.nil? && parsed_response.respond_to?(:pretty_print)
95
+ parsed_response.pretty_print(pp)
96
+ else
97
+ super
98
+ end
99
+ end
100
+
101
+ def display(port=$>)
102
+ if !parsed_response.nil? && parsed_response.respond_to?(:display)
103
+ parsed_response.display(port)
104
+ elsif !response.nil? && !response.body.nil? && response.body.respond_to?(:display)
105
+ response.body.display(port)
106
+ else
107
+ port.write(inspect)
108
+ end
109
+ end
110
+
111
+ def respond_to_missing?(name, *args)
112
+ return true if super
113
+ parsed_response.respond_to?(name) || response.respond_to?(name)
114
+ end
115
+
116
+ def _dump(_level)
117
+ Marshal.dump([request, response, parsed_response, body])
118
+ end
119
+
120
+ protected
121
+
122
+ def method_missing(name, *args, &block)
123
+ if parsed_response.respond_to?(name)
124
+ parsed_response.send(name, *args, &block)
125
+ elsif response.respond_to?(name)
126
+ response.send(name, *args, &block)
127
+ else
128
+ super
129
+ end
130
+ end
131
+
132
+ def throw_exception
133
+ if @request.options[:raise_on] && @request.options[:raise_on].include?(code)
134
+ ::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ require 'httparty/response/headers'
@@ -0,0 +1,33 @@
1
+ require 'delegate'
2
+
3
+ module HTTParty
4
+ class Response #:nodoc:
5
+ class Headers < ::SimpleDelegator
6
+ include ::Net::HTTPHeader
7
+
8
+ def initialize(header_values = nil)
9
+ @header = {}
10
+ if header_values
11
+ header_values.each_pair do |k,v|
12
+ if v.is_a?(Array)
13
+ v.each do |sub_v|
14
+ add_field(k, sub_v)
15
+ end
16
+ else
17
+ add_field(k, v)
18
+ end
19
+ end
20
+ end
21
+ super(@header)
22
+ end
23
+
24
+ def ==(other)
25
+ if other.is_a?(::Net::HTTPHeader)
26
+ @header == other.instance_variable_get(:@header)
27
+ elsif other.is_a?(Hash)
28
+ @header == other || @header == Headers.new(other).instance_variable_get(:@header)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ require 'delegate'
2
+
3
+ module HTTParty
4
+ # Allow access to http_response and code by delegation on fragment
5
+ class ResponseFragment < SimpleDelegator
6
+ attr_reader :http_response, :connection
7
+
8
+ def code
9
+ @http_response.code.to_i
10
+ end
11
+
12
+ def initialize(fragment, http_response, connection)
13
+ @fragment = fragment
14
+ @http_response = http_response
15
+ @connection = connection
16
+ super fragment
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ module HTTParty
2
+ class TextEncoder
3
+ attr_reader :text, :content_type, :assume_utf16_is_big_endian
4
+
5
+ def initialize(text, assume_utf16_is_big_endian: true, content_type: nil)
6
+ @text = text.dup
7
+ @content_type = content_type
8
+ @assume_utf16_is_big_endian = assume_utf16_is_big_endian
9
+ end
10
+
11
+ def call
12
+ if can_encode?
13
+ encoded_text
14
+ else
15
+ text
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def can_encode?
22
+ ''.respond_to?(:encoding) && charset
23
+ end
24
+
25
+ def encoded_text
26
+ if 'utf-16'.casecmp(charset) == 0
27
+ encode_utf_16
28
+ else
29
+ encode_with_ruby_encoding
30
+ end
31
+ end
32
+
33
+ def encode_utf_16
34
+ if text.bytesize >= 2
35
+ if text.getbyte(0) == 0xFF && text.getbyte(1) == 0xFE
36
+ return text.force_encoding("UTF-16LE")
37
+ elsif text.getbyte(0) == 0xFE && text.getbyte(1) == 0xFF
38
+ return text.force_encoding("UTF-16BE")
39
+ end
40
+ end
41
+
42
+ if assume_utf16_is_big_endian # option
43
+ text.force_encoding("UTF-16BE")
44
+ else
45
+ text.force_encoding("UTF-16LE")
46
+ end
47
+ end
48
+
49
+ def encode_with_ruby_encoding
50
+ # NOTE: This will raise an argument error if the
51
+ # charset does not exist
52
+ encoding = Encoding.find(charset)
53
+ text.force_encoding(encoding.to_s)
54
+ rescue ArgumentError
55
+ text
56
+ end
57
+
58
+ def charset
59
+ return nil if content_type.nil?
60
+
61
+ if (matchdata = content_type.match(/;\s*charset\s*=\s*([^=,;"\s]+)/i))
62
+ return matchdata.captures.first
63
+ end
64
+
65
+ if (matchdata = content_type.match(/;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i))
66
+ return matchdata.captures.first.gsub(/\\(.)/, '\1')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,11 @@
1
+ module HTTParty
2
+ module Utils
3
+ def self.stringify_keys(hash)
4
+ return hash.transform_keys(&:to_s) if hash.respond_to?(:transform_keys)
5
+
6
+ hash.each_with_object({}) do |(key, value), new_hash|
7
+ new_hash[key.to_s] = value
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module HTTParty
2
+ VERSION = "0.17.1"
3
+ end
@@ -0,0 +1,42 @@
1
+ #!/bin/sh
2
+ #/ Usage: release
3
+ #/
4
+ #/ Tag the version in the repo and push the gem.
5
+ #/
6
+
7
+ set -e
8
+ cd $(dirname "$0")/..
9
+
10
+ [ "$1" = "--help" -o "$1" = "-h" -o "$1" = "help" ] && {
11
+ grep '^#/' <"$0"| cut -c4-
12
+ exit 0
13
+ }
14
+
15
+ gem_name=httparty
16
+
17
+ # Build a new gem archive.
18
+ rm -rf $gem_name-*.gem
19
+ gem build -q $gem_name.gemspec
20
+
21
+ # Make sure we're on the master branch.
22
+ (git branch | grep -q '* master') || {
23
+ echo "Only release from the master branch."
24
+ exit 1
25
+ }
26
+
27
+ # Figure out what version we're releasing.
28
+ tag=v`ls $gem_name-*.gem | sed "s/^$gem_name-\(.*\)\.gem$/\1/"`
29
+
30
+ echo "Releasing $tag"
31
+
32
+ # Make sure we haven't released this version before.
33
+ git fetch -t origin
34
+
35
+ (git tag -l | grep -q "$tag") && {
36
+ echo "Whoops, there's already a '${tag}' tag."
37
+ exit 1
38
+ }
39
+
40
+ # Tag it and bag it.
41
+ gem push $gem_name-*.gem && git tag "$tag" &&
42
+ git push origin master && git push origin "$tag"
@@ -0,0 +1,47 @@
1
+ @media screen, projection {
2
+ /*
3
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4
+ Code licensed under the BSD License:
5
+ http://developer.yahoo.net/yui/license.txt
6
+ version: 2.2.0
7
+ */
8
+ 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;}
9
+ 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;}
10
+ /* end of yahoo reset and fonts */
11
+
12
+ body {color:#333; background:#4b1a1a; line-height:1.3;}
13
+ p {margin:0 0 20px;}
14
+ a {color:#4b1a1a;}
15
+ a:hover {text-decoration:none;}
16
+ strong {font-weight:bold;}
17
+ em {font-style:italics;}
18
+ h1,h2,h3,h4,h5,h6 {font-weight:bold;}
19
+ h1 {font-size:197%; margin:30px 0; color:#4b1a1a;}
20
+ h2 {font-size:174%; margin:20px 0; color:#b8111a;}
21
+ h3 {font-size:152%; margin:10px 0;}
22
+ h4 {font-size:129%; margin:10px 0;}
23
+ pre {background:#eee; margin:0 0 20px; padding:20px; border:1px solid #ccc; font-size:100%; overflow:auto;}
24
+ code {font-size:100%; margin:0; padding:0;}
25
+ ul, ol {margin:10px 0 10px 25px;}
26
+ ol li {margin:0 0 10px;}
27
+
28
+
29
+
30
+
31
+
32
+ div#wrapper {background:#fff; width:560px; margin:0 auto; padding:20px; border:10px solid #bc8c46; border-width:0 10px;}
33
+ div#header {position:relative; border-bottom:1px dotted; margin:0 0 10px; padding:0 0 10px;}
34
+ div#header p {margin:0; padding:0;}
35
+ div#header h1 {margin:0; padding:0;}
36
+ ul#nav {position:absolute; top:0; right:0; list-style:none; margin:0; padding:0;}
37
+ ul#nav li {display:inline; padding:0 0 0 5px;}
38
+ ul#nav li a {}
39
+ div#content {}
40
+ div#footer {margin:40px 0 0; border-top:1px dotted; padding:10px 0 0;}
41
+
42
+
43
+
44
+
45
+
46
+
47
+ }
@@ -0,0 +1,73 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
5
+ <title>HTTParty by John Nunemaker</title>
6
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
7
+ </head>
8
+ <body>
9
+
10
+ <div id="wrapper">
11
+ <div id="header">
12
+ <h1>HTTParty</h1>
13
+ <p>Tonight we're gonna HTTParty like it's 1999!</p>
14
+
15
+ <ul id="nav">
16
+ <li><a href="rdoc/">Docs</a></li>
17
+ <li><a href="http://github.com/jnunemaker/httparty">Github</a></li>
18
+ <li><a href="http://rubyforge.org/projects/httparty/">Rubyforge</a></li>
19
+ </ul>
20
+ </div>
21
+
22
+ <div id="content">
23
+ <h2>Install</h2>
24
+ <pre><code>$ sudo gem install httparty</code></pre>
25
+
26
+ <h2>Some Quick Examples</h2>
27
+
28
+ <p>The following is a simple example of wrapping Twitter's API for posting updates.</p>
29
+
30
+ <pre><code>class Twitter
31
+ include HTTParty
32
+ base_uri 'twitter.com'
33
+ basic_auth 'username', 'password'
34
+ end
35
+
36
+ Twitter.post('/statuses/update.json', query: {status: "It's an HTTParty and everyone is invited!"})</code></pre>
37
+
38
+ <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>
39
+
40
+ <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>
41
+
42
+ <pre><code>class Twitter
43
+ include HTTParty
44
+ base_uri 'twitter.com'
45
+
46
+ def initialize(u, p)
47
+ @auth = {username: u, password: p}
48
+ end
49
+
50
+ def post(text)
51
+ options = { query: {status: text}, basic_auth: @auth }
52
+ self.class.post('/statuses/update.json', options)
53
+ end
54
+ end
55
+
56
+ Twitter.new('username', 'password').post("It's an HTTParty and everyone is invited!")</code></pre>
57
+
58
+ <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>
59
+
60
+ <h2>Support</h2>
61
+ <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>
62
+
63
+
64
+ </div>
65
+
66
+ <div id="footer">
67
+ <p>Created by <a href="http://addictedtonew.com/about/">John Nunemaker</a> |
68
+ <a href="http://orderedlist.com/">Hire Me at Ordered List</a></p>
69
+ </div>
70
+ </div>
71
+
72
+ </body>
73
+ </html>