esod-client 0.2.1 → 0.3.0

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 (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