esod-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/VERSION +1 -1
  2. data/command_line_options.rb +3 -6
  3. data/esod-client.gemspec +29 -27
  4. data/lib/esod_client/esod_client.rb +2 -2
  5. data/lib/rest-client-1.4.2/README.rdoc +243 -0
  6. data/lib/rest-client-1.4.2/Rakefile +60 -0
  7. data/lib/rest-client-1.4.2/VERSION +1 -0
  8. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/bin/restclient +0 -0
  9. data/lib/rest-client-1.4.2/history.md +54 -0
  10. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/rest_client.rb +0 -0
  11. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient.rb +77 -21
  12. data/lib/rest-client-1.4.2/lib/restclient/abstract_response.rb +87 -0
  13. data/lib/rest-client-1.4.2/lib/restclient/exceptions.rb +146 -0
  14. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient/net_http_ext.rb +0 -0
  15. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient/payload.rb +15 -12
  16. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient/raw_response.rb +7 -6
  17. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient/request.rb +61 -89
  18. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/lib/restclient/resource.rb +11 -10
  19. data/lib/rest-client-1.4.2/lib/restclient/response.rb +46 -0
  20. data/lib/{rest-client-1.2.0/spec/mixin/response_spec.rb → rest-client-1.4.2/spec/abstract_response_spec.rb} +3 -12
  21. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/base.rb +0 -0
  22. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/exceptions_spec.rb +23 -9
  23. data/lib/rest-client-1.4.2/spec/integration_spec.rb +38 -0
  24. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/master_shake.jpg +0 -0
  25. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/payload_spec.rb +20 -6
  26. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/raw_response_spec.rb +1 -1
  27. data/lib/rest-client-1.4.2/spec/request_spec.rb +518 -0
  28. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/resource_spec.rb +24 -0
  29. data/lib/rest-client-1.4.2/spec/response_spec.rb +130 -0
  30. data/lib/{rest-client-1.2.0 → rest-client-1.4.2}/spec/restclient_spec.rb +21 -11
  31. metadata +38 -29
  32. data/lib/rest-client-1.2.0/README.rdoc +0 -102
  33. data/lib/rest-client-1.2.0/Rakefile +0 -57
  34. data/lib/rest-client-1.2.0/VERSION +0 -1
  35. data/lib/rest-client-1.2.0/lib/restclient/exceptions.rb +0 -89
  36. data/lib/rest-client-1.2.0/lib/restclient/mixin/response.rb +0 -48
  37. data/lib/rest-client-1.2.0/lib/restclient/response.rb +0 -20
  38. data/lib/rest-client-1.2.0/spec/request_spec.rb +0 -521
  39. data/lib/rest-client-1.2.0/spec/response_spec.rb +0 -21
@@ -9,12 +9,12 @@ rescue LoadError => e
9
9
  raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby"
10
10
  end
11
11
 
12
+ require File.dirname(__FILE__) + '/restclient/exceptions'
12
13
  require File.dirname(__FILE__) + '/restclient/request'
13
- require File.dirname(__FILE__) + '/restclient/mixin/response'
14
+ require File.dirname(__FILE__) + '/restclient/abstract_response'
14
15
  require File.dirname(__FILE__) + '/restclient/response'
15
16
  require File.dirname(__FILE__) + '/restclient/raw_response'
16
17
  require File.dirname(__FILE__) + '/restclient/resource'
17
- require File.dirname(__FILE__) + '/restclient/exceptions'
18
18
  require File.dirname(__FILE__) + '/restclient/payload'
19
19
  require File.dirname(__FILE__) + '/restclient/net_http_ext'
20
20
 
@@ -64,40 +64,38 @@ require File.dirname(__FILE__) + '/restclient/net_http_ext'
64
64
  #
65
65
  module RestClient
66
66
 
67
- def self.get(url, headers={})
68
- Request.execute(:method => :get, :url => url, :headers => headers)
67
+ def self.get(url, headers={}, &block)
68
+ Request.execute(:method => :get, :url => url, :headers => headers, &block)
69
69
  end
70
70
 
71
- def self.post(url, payload, headers={})
72
- Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
71
+ def self.post(url, payload, headers={}, &block)
72
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
73
73
  end
74
74
 
75
- def self.put(url, payload, headers={})
76
- Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
75
+ def self.put(url, payload, headers={}, &block)
76
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
77
77
  end
78
78
 
79
- def self.delete(url, headers={})
80
- Request.execute(:method => :delete, :url => url, :headers => headers)
79
+ def self.delete(url, headers={}, &block)
80
+ Request.execute(:method => :delete, :url => url, :headers => headers, &block)
81
81
  end
82
82
 
83
- def self.head(url, headers={})
84
- Request.execute(:method => :head, :url => url, :headers => headers)
83
+ def self.head(url, headers={}, &block)
84
+ Request.execute(:method => :head, :url => url, :headers => headers, &block)
85
85
  end
86
86
 
87
87
  class << self
88
88
  attr_accessor :proxy
89
89
  end
90
90
 
91
- # Print log of RestClient calls. Value can be stdout, stderr, or a filename.
91
+ # Setup the log for RestClient calls.
92
+ # Value should be a logger but can can be stdout, stderr, or a filename.
92
93
  # You can also configure logging by the environment variable RESTCLIENT_LOG.
93
- def self.log=(log)
94
- @@log = log
95
- end
96
-
97
- def self.log # :nodoc:
98
- return ENV['RESTCLIENT_LOG'] if ENV['RESTCLIENT_LOG']
99
- return @@log if defined? @@log
100
- nil
94
+ def self.log= log
95
+ if log.is_a? String
96
+ warn "[warning] You should set the log with a logger"
97
+ end
98
+ @@log = create_log log
101
99
  end
102
100
 
103
101
  def self.version
@@ -105,4 +103,62 @@ module RestClient
105
103
  return File.read(version_path).chomp if File.file?(version_path)
106
104
  "0.0.0"
107
105
  end
106
+
107
+ # Create a log that respond to << like a logger
108
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
109
+ def self.create_log param
110
+ if param
111
+ if param.is_a? String
112
+ if param == 'stdout'
113
+ stdout_logger = Class.new do
114
+ def << obj
115
+ STDOUT.puts obj
116
+ end
117
+ end
118
+ stdout_logger.new
119
+ elsif param == 'stderr'
120
+ stderr_logger = Class.new do
121
+ def << obj
122
+ STDERR.puts obj
123
+ end
124
+ end
125
+ stderr_logger.new
126
+ else
127
+ file_logger = Class.new do
128
+ attr_writer :target_file
129
+
130
+ def << obj
131
+ File.open(@target_file, 'a') { |f| f.puts obj }
132
+ end
133
+ end
134
+ logger = file_logger.new
135
+ logger.target_file = param
136
+ logger
137
+ end
138
+ else
139
+ param
140
+ end
141
+ end
142
+ end
143
+
144
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
145
+
146
+ @@log = nil
147
+
148
+ def self.log # :nodoc:
149
+ @@env_log || @@log
150
+ end
151
+
152
+ @@before_execution_procs = []
153
+
154
+ # Add a Proc to be called before each request in executed.
155
+ # The proc parameters will be the http request and the request params.
156
+ def self.add_before_execution_proc &proc
157
+ @@before_execution_procs << proc
158
+ end
159
+
160
+ def self.before_execution_procs # :nodoc:
161
+ @@before_execution_procs
162
+ end
163
+
108
164
  end
@@ -0,0 +1,87 @@
1
+ module RestClient
2
+
3
+ class AbstractResponse
4
+
5
+ attr_reader :net_http_res, :args
6
+
7
+ def initialize net_http_res, args
8
+ @net_http_res = net_http_res
9
+ @args = args
10
+ end
11
+
12
+ # HTTP status code
13
+ def code
14
+ @code ||= @net_http_res.code.to_i
15
+ end
16
+
17
+ # A hash of the headers, beautified with symbols and underscores.
18
+ # e.g. "Content-type" will become :content_type.
19
+ def headers
20
+ @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
21
+ end
22
+
23
+ # The raw headers.
24
+ def raw_headers
25
+ @raw_headers ||= @net_http_res.to_hash
26
+ end
27
+
28
+ # Hash of cookies extracted from response headers
29
+ def cookies
30
+ @cookies ||= (self.headers[:set_cookie] || []).inject({}) do |out, cookie_content|
31
+ # correctly parse comma-separated cookies containing HTTP dates (which also contain a comma)
32
+ cookie_content.split(/,\s*/).inject([""]) { |array, blob|
33
+ blob =~ /expires=.+?$/ ? array.push(blob) : array.last.concat(blob)
34
+ array
35
+ }.each do |cookie|
36
+ next if cookie.empty?
37
+ key, *val = cookie.split(";").first.split("=")
38
+ out[key] = val.join("=")
39
+ end
40
+ out
41
+ end
42
+ end
43
+
44
+ # Return the default behavior corresponding to the response code:
45
+ # the response itself for code in 200..206, redirection for 301 and 302 in get and head cases, redirection for 303 and an exception in other cases
46
+ def return! &block
47
+ if (200..206).include? code
48
+ self
49
+ elsif [301, 302].include? code
50
+ unless [:get, :head].include? args[:method]
51
+ raise Exceptions::EXCEPTIONS_MAP[code], self
52
+ else
53
+ follow_redirection &block
54
+ end
55
+ elsif code == 303
56
+ args[:method] = :get
57
+ args.delete :payload
58
+ follow_redirection &block
59
+ elsif Exceptions::EXCEPTIONS_MAP[code]
60
+ raise Exceptions::EXCEPTIONS_MAP[code], self
61
+ else
62
+ raise RequestFailed, self
63
+ end
64
+ end
65
+
66
+ def inspect
67
+ "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
68
+ end
69
+
70
+ # Follow a redirection
71
+ def follow_redirection &block
72
+ url = headers[:location]
73
+ if url !~ /^http/
74
+ url = URI.parse(args[:url]).merge(url).to_s
75
+ end
76
+ args[:url] = url
77
+ Request.execute args, &block
78
+ end
79
+
80
+ def AbstractResponse.beautify_headers(headers)
81
+ headers.inject({}) do |out, (key, value)|
82
+ out[key.gsub(/-/, '_').downcase.to_sym] = %w{set-cookie}.include?(key.downcase) ? value : value.first
83
+ out
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,146 @@
1
+ module RestClient
2
+
3
+ STATUSES = {100 => 'Continue',
4
+ 101 => 'Switching Protocols',
5
+ 200 => 'OK',
6
+ 201 => 'Created',
7
+ 202 => 'Accepted',
8
+ 203 => 'Non-Authoritative Information',
9
+ 204 => 'No Content',
10
+ 205 => 'Reset Content',
11
+ 206 => 'Partial Content',
12
+ 300 => 'Multiple Choices',
13
+ 301 => 'Moved Permanently',
14
+ 302 => 'Found',
15
+ 303 => 'See Other',
16
+ 304 => 'Not Modified',
17
+ 305 => 'Use Proxy',
18
+ 400 => 'Bad Request',
19
+ 401 => 'Unauthorized',
20
+ 403 => 'Forbidden',
21
+ 404 => 'Resource Not Found',
22
+ 405 => 'Method Not Allowed',
23
+ 406 => 'Not Acceptable',
24
+ 407 => 'Proxy Authentication Required',
25
+ 408 => 'Request Timeout',
26
+ 409 => 'Conflict',
27
+ 410 => 'Gone',
28
+ 411 => 'Length Required',
29
+ 412 => 'Precondition Failed',
30
+ 413 => 'Request Entity Too Large',
31
+ 414 => 'Request-URI Too Long',
32
+ 415 => 'Unsupported Media Type',
33
+ 416 => 'Requested Range Not Satisfiable',
34
+ 417 => 'Expectation Failed',
35
+ 500 => 'Internal Server Error',
36
+ 501 => 'Not Implemented',
37
+ 502 => 'Bad Gateway',
38
+ 503 => 'Service Unavailable',
39
+ 504 => 'Gateway Timeout',
40
+ 505 => 'HTTP Version Not Supported'}
41
+
42
+ # Compatibility : make the Response act like a Net::HTTPResponse when needed
43
+ module ResponseForException
44
+ def method_missing symbol, *args
45
+ if net_http_res.respond_to? symbol
46
+ warn "[warning] The response contained in an RestClient::Exception is now a RestClient::Response instead of a Net::HTTPResponse, please update your code"
47
+ net_http_res.send symbol, *args
48
+ else
49
+ super
50
+ end
51
+ end
52
+ end
53
+
54
+ # This is the base RestClient exception class. Rescue it if you want to
55
+ # catch any exception that your request might raise
56
+ # You can get the status code by e.http_code, or see anything about the
57
+ # response via e.response.
58
+ # For example, the entire result body (which is
59
+ # probably an HTML error page) is e.response.
60
+ class Exception < RuntimeError
61
+ attr_accessor :message, :response
62
+
63
+ def initialize response = nil
64
+ @response = response
65
+
66
+ # compatibility: this make the exception behave like a Net::HTTPResponse
67
+ response.extend ResponseForException if response
68
+ end
69
+
70
+ def http_code
71
+ # return integer for compatibility
72
+ @response.code.to_i if @response
73
+ end
74
+
75
+ def http_body
76
+ @response.body
77
+ end
78
+
79
+ def inspect
80
+ "#{self.class} : #{http_code} #{message}"
81
+ end
82
+
83
+ end
84
+
85
+ # Compatibility
86
+ class ExceptionWithResponse < Exception
87
+ end
88
+
89
+ # The request failed with an error code not managed by the code
90
+ class RequestFailed < ExceptionWithResponse
91
+
92
+ def message
93
+ "HTTP status code #{http_code}"
94
+ end
95
+
96
+ def to_s
97
+ message
98
+ end
99
+ end
100
+
101
+ # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
102
+ module Exceptions
103
+ # Map http status codes to the corresponding exception class
104
+ EXCEPTIONS_MAP = {}
105
+ end
106
+
107
+ STATUSES.each_pair do |code, message|
108
+
109
+ # Compatibility
110
+ superclass = ([304, 401, 404].include? code) ? ExceptionWithResponse : RequestFailed
111
+ klass = Class.new(superclass) do
112
+ send(:define_method, :message) {message}
113
+ end
114
+ klass_constant = const_set message.gsub(/ /, '').gsub(/-/, ''), klass
115
+ Exceptions::EXCEPTIONS_MAP[code] = klass_constant
116
+ end
117
+
118
+ # A redirect was encountered; caught by execute to retry with the new url.
119
+ class Redirect < Exception
120
+
121
+ message = 'Redirect'
122
+
123
+ attr_accessor :url
124
+
125
+ def initialize(url)
126
+ @url = url
127
+ end
128
+ end
129
+
130
+ # The server broke the connection prior to the request completing. Usually
131
+ # this means it crashed, or sometimes that your network connection was
132
+ # severed before it could complete.
133
+ class ServerBrokeConnection < Exception
134
+ message = 'Server broke connection'
135
+ end
136
+
137
+
138
+
139
+ end
140
+
141
+ # backwards compatibility
142
+ class RestClient::Request
143
+ Redirect = RestClient::Redirect
144
+ Unauthorized = RestClient::Unauthorized
145
+ RequestFailed = RestClient::RequestFailed
146
+ end
@@ -54,14 +54,17 @@ module RestClient
54
54
  # Flatten parameters by converting hashes of hashes to flat hashes
55
55
  # {keys1 => {keys2 => value}} will be transformed into {keys1[key2] => value}
56
56
  def flatten_params(params, parent_key = nil)
57
- result = {}
58
- params.keys.map do |key|
57
+ result = []
58
+ params.each do |key, value|
59
59
  calculated_key = parent_key ? "#{parent_key}[#{escape key}]" : escape(key)
60
- value = params[key]
61
60
  if value.is_a? Hash
62
- result.merge!(flatten_params(value, calculated_key))
61
+ result += flatten_params(value, calculated_key)
62
+ elsif value.is_a? Array
63
+ value.each do |elem|
64
+ result << ["#{calculated_key}[]", elem]
65
+ end
63
66
  else
64
- result[calculated_key] = value
67
+ result << [calculated_key, value]
65
68
  end
66
69
  end
67
70
  result
@@ -88,15 +91,15 @@ module RestClient
88
91
  end
89
92
 
90
93
  def short_inspect
91
- (size > 100 ? "#{size} byte length" : inspect)
94
+ (size > 100 ? "#{size} byte(s) length" : inspect)
92
95
  end
93
96
 
94
97
  end
95
98
 
96
99
  class UrlEncoded < Base
97
100
  def build_stream(params = nil)
98
- @stream = StringIO.new(flatten_params(params).map do |k, v|
99
- "#{k}=#{escape(v)}"
101
+ @stream = StringIO.new(flatten_params(params).collect do |entry|
102
+ "#{entry[0]}=#{escape(entry[1])}"
100
103
  end.join("&"))
101
104
  @stream.seek(0)
102
105
  end
@@ -116,9 +119,9 @@ module RestClient
116
119
  @stream.write(b + EOL)
117
120
 
118
121
  if params.is_a? Hash
119
- x = flatten_params(params).to_a
122
+ x = flatten_params(params)
120
123
  else
121
- x = params.to_a
124
+ x = params
122
125
  end
123
126
 
124
127
  last_index = x.length - 1
@@ -138,7 +141,7 @@ module RestClient
138
141
  end
139
142
 
140
143
  def create_regular_field(s, k, v)
141
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"")
144
+ s.write("Content-Disposition: form-data; name=\"#{k}\"")
142
145
  s.write(EOL)
143
146
  s.write(EOL)
144
147
  s.write(v)
@@ -146,7 +149,7 @@ module RestClient
146
149
 
147
150
  def create_file_field(s, k, v)
148
151
  begin
149
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
152
+ s.write("Content-Disposition: form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
150
153
  s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
151
154
  s.write(EOL)
152
155
  while data = v.read(8124)
@@ -1,5 +1,3 @@
1
- require File.dirname(__FILE__) + '/mixin/response'
2
-
3
1
  module RestClient
4
2
  # The response from RestClient on a raw request looks like a string, but is
5
3
  # actually one of these. 99% of the time you're making a rest call all you
@@ -11,13 +9,12 @@ module RestClient
11
9
  # In addition, if you do not use the response as a string, you can access
12
10
  # a Tempfile object at res.file, which contains the path to the raw
13
11
  # downloaded request body.
14
- class RawResponse
15
- include RestClient::Mixin::Response
12
+ class RawResponse < AbstractResponse
16
13
 
17
14
  attr_reader :file
18
15
 
19
- def initialize(tempfile, net_http_res)
20
- @net_http_res = net_http_res
16
+ def initialize tempfile, net_http_res, args
17
+ super net_http_res, args
21
18
  @file = tempfile
22
19
  end
23
20
 
@@ -26,5 +23,9 @@ module RestClient
26
23
  @file.read
27
24
  end
28
25
 
26
+ def size
27
+ File.size file
28
+ end
29
+
29
30
  end
30
31
  end