typhoeus 0.4.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +26 -0
  5. data/CHANGELOG.md +341 -28
  6. data/CONTRIBUTING.md +20 -0
  7. data/Gemfile +31 -2
  8. data/Guardfile +9 -0
  9. data/LICENSE +1 -1
  10. data/README.md +486 -357
  11. data/Rakefile +21 -12
  12. data/UPGRADE.md +55 -0
  13. data/lib/rack/typhoeus/middleware/params_decoder/helper.rb +76 -0
  14. data/lib/rack/typhoeus/middleware/params_decoder.rb +57 -0
  15. data/lib/rack/typhoeus.rb +1 -0
  16. data/lib/typhoeus/adapters/faraday.rb +180 -0
  17. data/lib/typhoeus/cache/dalli.rb +28 -0
  18. data/lib/typhoeus/cache/rails.rb +28 -0
  19. data/lib/typhoeus/cache/redis.rb +35 -0
  20. data/lib/typhoeus/config.rb +69 -0
  21. data/lib/typhoeus/easy_factory.rb +180 -0
  22. data/lib/typhoeus/errors/no_stub.rb +12 -0
  23. data/lib/typhoeus/errors/typhoeus_error.rb +8 -0
  24. data/lib/typhoeus/errors.rb +9 -0
  25. data/lib/typhoeus/expectation.rb +217 -0
  26. data/lib/typhoeus/hydra/addable.rb +23 -0
  27. data/lib/typhoeus/hydra/before.rb +31 -0
  28. data/lib/typhoeus/hydra/block_connection.rb +35 -0
  29. data/lib/typhoeus/hydra/cacheable.rb +15 -0
  30. data/lib/typhoeus/hydra/memoizable.rb +56 -0
  31. data/lib/typhoeus/hydra/queueable.rb +83 -0
  32. data/lib/typhoeus/hydra/runnable.rb +19 -0
  33. data/lib/typhoeus/hydra/stubbable.rb +28 -0
  34. data/lib/typhoeus/hydra.rb +84 -236
  35. data/lib/typhoeus/pool.rb +70 -0
  36. data/lib/typhoeus/railtie.rb +12 -0
  37. data/lib/typhoeus/request/actions.rb +125 -0
  38. data/lib/typhoeus/request/before.rb +30 -0
  39. data/lib/typhoeus/request/block_connection.rb +52 -0
  40. data/lib/typhoeus/request/cacheable.rb +38 -0
  41. data/lib/typhoeus/request/callbacks.rb +151 -0
  42. data/lib/typhoeus/request/marshal.rb +22 -0
  43. data/lib/typhoeus/request/memoizable.rb +38 -0
  44. data/lib/typhoeus/request/operations.rb +40 -0
  45. data/lib/typhoeus/request/responseable.rb +29 -0
  46. data/lib/typhoeus/request/streamable.rb +34 -0
  47. data/lib/typhoeus/request/stubbable.rb +30 -0
  48. data/lib/typhoeus/request.rb +186 -231
  49. data/lib/typhoeus/response/cacheable.rb +14 -0
  50. data/lib/typhoeus/response/header.rb +105 -0
  51. data/lib/typhoeus/response/informations.rb +248 -0
  52. data/lib/typhoeus/response/status.rb +106 -0
  53. data/lib/typhoeus/response.rb +60 -115
  54. data/lib/typhoeus/version.rb +3 -1
  55. data/lib/typhoeus.rb +126 -39
  56. data/perf/profile.rb +14 -0
  57. data/perf/vs_nethttp.rb +64 -0
  58. data/spec/rack/typhoeus/middleware/params_decoder/helper_spec.rb +156 -0
  59. data/spec/rack/typhoeus/middleware/params_decoder_spec.rb +31 -0
  60. data/spec/spec_helper.rb +29 -0
  61. data/spec/support/localhost_server.rb +94 -0
  62. data/spec/support/memory_cache.rb +15 -0
  63. data/spec/support/server.rb +116 -0
  64. data/spec/typhoeus/adapters/faraday_spec.rb +339 -0
  65. data/spec/typhoeus/cache/dalli_spec.rb +41 -0
  66. data/spec/typhoeus/cache/redis_spec.rb +41 -0
  67. data/spec/typhoeus/config_spec.rb +15 -0
  68. data/spec/typhoeus/easy_factory_spec.rb +143 -0
  69. data/spec/typhoeus/errors/no_stub_spec.rb +13 -0
  70. data/spec/typhoeus/expectation_spec.rb +280 -0
  71. data/spec/typhoeus/hydra/addable_spec.rb +22 -0
  72. data/spec/typhoeus/hydra/before_spec.rb +98 -0
  73. data/spec/typhoeus/hydra/block_connection_spec.rb +18 -0
  74. data/spec/typhoeus/hydra/cacheable_spec.rb +88 -0
  75. data/spec/typhoeus/hydra/memoizable_spec.rb +53 -0
  76. data/spec/typhoeus/hydra/queueable_spec.rb +98 -0
  77. data/spec/typhoeus/hydra/runnable_spec.rb +137 -0
  78. data/spec/typhoeus/hydra/stubbable_spec.rb +48 -0
  79. data/spec/typhoeus/hydra_spec.rb +22 -0
  80. data/spec/typhoeus/pool_spec.rb +137 -0
  81. data/spec/typhoeus/request/actions_spec.rb +19 -0
  82. data/spec/typhoeus/request/before_spec.rb +93 -0
  83. data/spec/typhoeus/request/block_connection_spec.rb +75 -0
  84. data/spec/typhoeus/request/cacheable_spec.rb +94 -0
  85. data/spec/typhoeus/request/callbacks_spec.rb +91 -0
  86. data/spec/typhoeus/request/marshal_spec.rb +60 -0
  87. data/spec/typhoeus/request/memoizable_spec.rb +34 -0
  88. data/spec/typhoeus/request/operations_spec.rb +101 -0
  89. data/spec/typhoeus/request/responseable_spec.rb +13 -0
  90. data/spec/typhoeus/request/stubbable_spec.rb +45 -0
  91. data/spec/typhoeus/request_spec.rb +232 -0
  92. data/spec/typhoeus/response/header_spec.rb +147 -0
  93. data/spec/typhoeus/response/informations_spec.rb +283 -0
  94. data/spec/typhoeus/response/status_spec.rb +256 -0
  95. data/spec/typhoeus/response_spec.rb +100 -0
  96. data/spec/typhoeus_spec.rb +105 -0
  97. data/typhoeus.gemspec +25 -0
  98. metadata +146 -158
  99. data/lib/typhoeus/curl.rb +0 -453
  100. data/lib/typhoeus/easy/auth.rb +0 -14
  101. data/lib/typhoeus/easy/callbacks.rb +0 -33
  102. data/lib/typhoeus/easy/ffi_helper.rb +0 -61
  103. data/lib/typhoeus/easy/infos.rb +0 -90
  104. data/lib/typhoeus/easy/options.rb +0 -115
  105. data/lib/typhoeus/easy/proxy.rb +0 -20
  106. data/lib/typhoeus/easy/ssl.rb +0 -82
  107. data/lib/typhoeus/easy.rb +0 -115
  108. data/lib/typhoeus/filter.rb +0 -28
  109. data/lib/typhoeus/form.rb +0 -61
  110. data/lib/typhoeus/header.rb +0 -54
  111. data/lib/typhoeus/hydra/callbacks.rb +0 -24
  112. data/lib/typhoeus/hydra/connect_options.rb +0 -61
  113. data/lib/typhoeus/hydra/stubbing.rb +0 -68
  114. data/lib/typhoeus/hydra_mock.rb +0 -131
  115. data/lib/typhoeus/multi.rb +0 -146
  116. data/lib/typhoeus/param_processor.rb +0 -43
  117. data/lib/typhoeus/remote.rb +0 -306
  118. data/lib/typhoeus/remote_method.rb +0 -108
  119. data/lib/typhoeus/remote_proxy_object.rb +0 -50
  120. data/lib/typhoeus/utils.rb +0 -50
@@ -1,131 +0,0 @@
1
- module Typhoeus
2
- class HydraMock
3
- attr_reader :url, :method, :requests, :uri
4
-
5
- def initialize(url, method, options = {})
6
- @url = url
7
- @uri = URI.parse(url) if url.kind_of?(String)
8
- @method = method
9
- @requests = []
10
- @options = options
11
- if @options[:headers]
12
- @options[:headers] = Typhoeus::Header.new(@options[:headers])
13
- end
14
-
15
- @current_response_index = 0
16
- end
17
-
18
- def body
19
- @options[:body]
20
- end
21
-
22
- def body?
23
- @options.has_key?(:body)
24
- end
25
-
26
- def headers
27
- @options[:headers]
28
- end
29
-
30
- def headers?
31
- @options.has_key?(:headers)
32
- end
33
-
34
- def add_request(request)
35
- @requests << request
36
- end
37
-
38
- def and_return(val)
39
- if val.respond_to?(:each)
40
- @responses = val
41
- else
42
- @responses = [val]
43
- end
44
-
45
- # make sure to mark them as a mock.
46
- @responses.each { |r| r.mock = true }
47
-
48
- val
49
- end
50
-
51
- def response
52
- if @current_response_index == (@responses.length - 1)
53
- @responses.last
54
- else
55
- value = @responses[@current_response_index]
56
- @current_response_index += 1
57
- value
58
- end
59
- end
60
-
61
- def matches?(request)
62
- if !method_matches?(request) or !url_matches?(request)
63
- return false
64
- end
65
-
66
- if body?
67
- return false unless body_matches?(request)
68
- end
69
-
70
- if headers?
71
- return false unless headers_match?(request)
72
- end
73
-
74
- true
75
- end
76
-
77
- private
78
- def method_matches?(request)
79
- self.method == :any or self.method == request.method
80
- end
81
-
82
- def url_matches?(request)
83
- if url.kind_of?(String)
84
- request_uri = URI.parse(request.url)
85
- request_uri == self.uri
86
- else
87
- self.url =~ request.url
88
- end
89
- end
90
-
91
- def body_matches?(request)
92
- !request.body.nil? && !request.body.empty? && request.body == self.body
93
- end
94
-
95
- def headers_match?(request)
96
- request_headers = Header.new(request.headers)
97
-
98
- if empty_headers?(self.headers)
99
- empty_headers?(request_headers)
100
- else
101
- return false if empty_headers?(request_headers)
102
-
103
- headers.each do |key, value|
104
- return false unless header_value_matches?(value, request_headers[key])
105
- end
106
-
107
- true
108
- end
109
- end
110
-
111
- def header_value_matches?(mock_value, request_value)
112
- mock_arr = mock_value.is_a?(Array) ? mock_value : [mock_value]
113
- request_arr = request_value.is_a?(Array) ? request_value : [request_value]
114
-
115
- return false unless mock_arr.size == request_arr.size
116
- mock_arr.all? do |value|
117
- request_arr.any? { |a| value === a }
118
- end
119
- end
120
-
121
- def empty_headers?(headers)
122
- # We consider the default User-Agent header to be empty since
123
- # Typhoeus always adds that.
124
- headers.nil? || headers.empty? || default_typhoeus_headers?(headers)
125
- end
126
-
127
- def default_typhoeus_headers?(headers)
128
- headers.size == 1 && headers['User-Agent'] == Typhoeus::USER_AGENT
129
- end
130
- end
131
- end
@@ -1,146 +0,0 @@
1
- module Typhoeus
2
- class Multi
3
- attr_reader :easy_handles
4
-
5
- def initialize
6
- Curl.init
7
-
8
- @handle = Curl.multi_init
9
- @active = 0
10
- @running = 0
11
- @easy_handles = []
12
-
13
- @timeout = ::FFI::MemoryPointer.new(:long)
14
- @timeval = Curl::Timeval.new
15
- @fd_read = Curl::FDSet.new
16
- @fd_write = Curl::FDSet.new
17
- @fd_excep = Curl::FDSet.new
18
- @max_fd = ::FFI::MemoryPointer.new(:int)
19
-
20
- ObjectSpace.define_finalizer(self, self.class.finalizer(self))
21
- end
22
-
23
- def self.finalizer(multi)
24
- proc { Curl.multi_cleanup(multi.handle) }
25
- end
26
-
27
- def add(easy)
28
- raise "trying to add easy handle twice" if @easy_handles.include?(easy)
29
- easy.set_headers() if easy.headers.empty?
30
-
31
- code = Curl.multi_add_handle(@handle, easy.handle)
32
- raise RuntimeError.new("An error occured adding the handle: #{code}: #{Curl.multi_strerror(code)}") if code != :call_multi_perform and code != :ok
33
-
34
- do_perform if code == :call_multi_perform
35
-
36
- @active += 1
37
- @easy_handles << easy
38
- easy
39
- end
40
-
41
- def remove(easy)
42
- if @easy_handles.include?(easy)
43
- @active -= 1
44
- Curl.multi_remove_handle(@handle, easy.handle)
45
- @easy_handles.delete(easy)
46
- end
47
- end
48
-
49
- def perform
50
- while @active > 0
51
- run
52
- while @running > 0
53
- # get the curl-suggested timeout
54
- code = Curl.multi_timeout(@handle, @timeout)
55
- raise RuntimeError.new("an error occured getting the timeout: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
56
- timeout = @timeout.read_long
57
- if timeout == 0 # no delay
58
- run
59
- next
60
- elsif timeout < 0
61
- timeout = 1
62
- end
63
-
64
- # load the fd sets from the multi handle
65
- @fd_read.clear
66
- @fd_write.clear
67
- @fd_excep.clear
68
- code = Curl.multi_fdset(@handle, @fd_read, @fd_write, @fd_excep, @max_fd)
69
- raise RuntimeError.new("an error occured getting the fdset: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
70
-
71
- max_fd = @max_fd.read_int
72
- if max_fd == -1
73
- # curl is doing something special so let it run for a moment
74
- sleep(0.001)
75
- else
76
- @timeval[:sec] = timeout / 1000
77
- @timeval[:usec] = (timeout * 1000) % 1000000
78
-
79
- code = Curl.select(max_fd + 1, @fd_read, @fd_write, @fd_excep, @timeval)
80
- raise RuntimeError.new("error on thread select: #{::FFI.errno}") if code < 0
81
- end
82
-
83
- run
84
- end
85
- end
86
- reset_easy_handles
87
- end
88
-
89
- def fire_and_forget
90
- run
91
- end
92
-
93
- # check for finished easy handles and remove from the multi handle
94
- def read_info
95
- msgs_left = ::FFI::MemoryPointer.new(:int)
96
- while not (msg = Curl.multi_info_read(@handle, msgs_left)).null?
97
- next if msg[:code] != :done
98
-
99
- easy = @easy_handles.find {|easy| easy.handle == msg[:easy_handle] }
100
- next if not easy
101
-
102
- response_code = ::FFI::MemoryPointer.new(:long)
103
- response_code.write_long(-1)
104
- Curl.easy_getinfo(easy.handle, :response_code, response_code)
105
- response_code = response_code.read_long
106
- remove(easy)
107
-
108
- easy.curl_return_code = msg[:data][:code]
109
- if easy.curl_return_code != 0 then easy.failure
110
- elsif (200..299).member?(response_code) or response_code == 0 then easy.success
111
- else easy.failure
112
- end
113
- end
114
- end
115
-
116
- def cleanup
117
- Curl.multi_cleanup(@handle)
118
- @active = 0
119
- @running = 0
120
- @easy_handles = []
121
- end
122
-
123
- def reset_easy_handles
124
- @easy_handles.dup.each do |easy|
125
- remove(easy)
126
- yield easy if block_given?
127
- end
128
- end
129
-
130
- private
131
-
132
- # called by perform and fire_and_forget
133
- def run
134
- begin code = do_perform end while code == :call_multi_perform
135
- raise RuntimeError.new("an error occured while running perform: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
136
- read_info
137
- end
138
-
139
- def do_perform
140
- running = ::FFI::MemoryPointer.new(:int)
141
- code = Curl.multi_perform(@handle, running)
142
- @running = running.read_int
143
- code
144
- end
145
- end
146
- end
@@ -1,43 +0,0 @@
1
- require 'tempfile'
2
-
3
- module Typhoeus
4
- class ParamProcessor
5
- class << self
6
- def traverse_params_hash(hash, result = nil, current_key = nil)
7
- result ||= { :files => [], :params => [] }
8
-
9
- hash.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |key|
10
- new_key = (current_key ? "#{current_key}[#{key}]" : key).to_s
11
- current_value = hash[key]
12
- process_value current_value, :result => result, :new_key => new_key
13
- end
14
- result
15
- end
16
-
17
- def process_value(current_value, options)
18
- result = options[:result]
19
- new_key = options[:new_key]
20
-
21
- case current_value
22
- when Hash
23
- traverse_params_hash(current_value, result, new_key)
24
- when Array
25
- current_value.each do |v|
26
- result[:params] << [new_key, v.to_s]
27
- end
28
- when File, Tempfile
29
- filename = File.basename(current_value.path)
30
- types = MIME::Types.type_for(filename)
31
- result[:files] << [
32
- new_key,
33
- filename,
34
- types.empty? ? 'application/octet-stream' : types[0].to_s,
35
- File.expand_path(current_value.path)
36
- ]
37
- else
38
- result[:params] << [new_key, current_value.to_s]
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,306 +0,0 @@
1
- module Typhoeus
2
- USER_AGENT = "Typhoeus - http://github.com/dbalatero/typhoeus/tree/master"
3
-
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
7
-
8
- class MockExpectedError < StandardError; end
9
-
10
- module ClassMethods
11
- def allow_net_connect
12
- @allow_net_connect = true if @allow_net_connect.nil?
13
- @allow_net_connect
14
- end
15
-
16
- def allow_net_connect=(value)
17
- @allow_net_connect = value
18
- end
19
-
20
- def mock(method, args = {})
21
- @remote_mocks ||= {}
22
- @remote_mocks[method] ||= {}
23
- args[:code] ||= 200
24
- args[:body] ||= ""
25
- args[:headers] ||= ""
26
- args[:time] ||= 0
27
- url = args.delete(:url)
28
- url ||= :catch_all
29
- params = args.delete(:params)
30
-
31
- key = mock_key_for(url, params)
32
-
33
- @remote_mocks[method][key] = args
34
- end
35
-
36
- # Returns a key for a given URL and passed in
37
- # set of Typhoeus options to be used to store/retrieve
38
- # a corresponding mock.
39
- def mock_key_for(url, params = nil)
40
- if url == :catch_all
41
- url
42
- else
43
- key = url
44
- if params and !params.empty?
45
- key += flatten_and_sort_hash(params).to_s
46
- end
47
- key
48
- end
49
- end
50
-
51
- def flatten_and_sort_hash(params)
52
- params = params.dup
53
-
54
- # Flatten any sub-hashes to a single string.
55
- params.keys.each do |key|
56
- if params[key].is_a?(Hash)
57
- params[key] = params[key].sort_by { |k, v| k.to_s.downcase }.to_s
58
- end
59
- end
60
-
61
- params.sort_by { |k, v| k.to_s.downcase }
62
- end
63
-
64
- def get_mock(method, url, options)
65
- return nil unless @remote_mocks
66
- if @remote_mocks.has_key? method
67
- extra_response_args = { :requested_http_method => method,
68
- :requested_url => url,
69
- :start_time => Time.now }
70
- mock_key = mock_key_for(url, options[:params])
71
- if @remote_mocks[method].has_key? mock_key
72
- get_mock_and_run_handlers(method,
73
- @remote_mocks[method][mock_key].merge(
74
- extra_response_args),
75
- options)
76
- elsif @remote_mocks[method].has_key? :catch_all
77
- get_mock_and_run_handlers(method,
78
- @remote_mocks[method][:catch_all].merge(
79
- extra_response_args),
80
- options)
81
- else
82
- nil
83
- end
84
- else
85
- nil
86
- end
87
- end
88
-
89
- def enforce_allow_net_connect!(http_verb, url, params = nil)
90
- if !allow_net_connect
91
- message = "Real HTTP connections are disabled. Unregistered request: " <<
92
- "#{http_verb.to_s.upcase} #{url}\n" <<
93
- " Try: mock(:#{http_verb}, :url => \"#{url}\""
94
- if params
95
- message << ",\n :params => #{params.inspect}"
96
- end
97
-
98
- message << ")"
99
-
100
- raise MockExpectedError, message
101
- end
102
- end
103
-
104
- def check_expected_headers!(response_args, options)
105
- missing_headers = {}
106
-
107
- response_args[:expected_headers].each do |key, value|
108
- if options[:headers].nil?
109
- missing_headers[key] = [value, nil]
110
- elsif ((options[:headers][key] && value != :anything) &&
111
- options[:headers][key] != value)
112
-
113
- missing_headers[key] = [value, options[:headers][key]]
114
- end
115
- end
116
-
117
- unless missing_headers.empty?
118
- raise headers_error_summary(response_args, options, missing_headers, 'expected')
119
- end
120
- end
121
-
122
- def check_unexpected_headers!(response_args, options)
123
- bad_headers = {}
124
- response_args[:unexpected_headers].each do |key, value|
125
- if (options[:headers][key] && value == :anything) ||
126
- (options[:headers][key] == value)
127
- bad_headers[key] = [value, options[:headers][key]]
128
- end
129
- end
130
-
131
- unless bad_headers.empty?
132
- raise headers_error_summary(response_args, options, bad_headers, 'did not expect')
133
- end
134
- end
135
-
136
- def headers_error_summary(response_args, options, missing_headers, lead_in)
137
- error = "#{lead_in} the following headers: #{response_args[:expected_headers].inspect}, but received: #{options[:headers].inspect}\n\n"
138
- error << "Differences:\n"
139
- error << "------------\n"
140
- missing_headers.each do |key, values|
141
- error << " - #{key}: #{lead_in} #{values[0].inspect}, got #{values[1].inspect}\n"
142
- end
143
-
144
- error
145
- end
146
- private :headers_error_summary
147
-
148
- def get_mock_and_run_handlers(method, response_args, options)
149
- response = Response.new(response_args)
150
-
151
- if response_args.has_key? :expected_body
152
- raise "#{method} expected body of \"#{response_args[:expected_body]}\" but received #{options[:body]}" if response_args[:expected_body] != options[:body]
153
- end
154
-
155
- if response_args.has_key? :expected_headers
156
- check_expected_headers!(response_args, options)
157
- end
158
-
159
- if response_args.has_key? :unexpected_headers
160
- check_unexpected_headers!(response_args, options)
161
- end
162
-
163
- if response.code >= 200 && response.code < 300 && options.has_key?(:on_success)
164
- response = options[:on_success].call(response)
165
- elsif options.has_key?(:on_failure)
166
- response = options[:on_failure].call(response)
167
- end
168
-
169
- encode_nil_response(response)
170
- end
171
-
172
- [:get, :post, :put, :delete].each do |method|
173
- line = __LINE__ + 2 # get any errors on the correct line num
174
- code = <<-SRC
175
- def #{method.to_s}(url, options = {})
176
- mock_object = get_mock(:#{method.to_s}, url, options)
177
- unless mock_object.nil?
178
- decode_nil_response(mock_object)
179
- else
180
- enforce_allow_net_connect!(:#{method.to_s}, url, options[:params])
181
- remote_proxy_object(url, :#{method.to_s}, options)
182
- end
183
- end
184
- SRC
185
- module_eval(code, "./lib/typhoeus/remote.rb", line)
186
- end
187
-
188
- def remote_proxy_object(url, method, options)
189
- easy = Typhoeus.get_easy_object
190
-
191
- easy.url = url
192
- easy.method = method
193
- easy.headers = options[:headers] if options.has_key?(:headers)
194
- easy.headers["User-Agent"] = (options[:user_agent] || Typhoeus::USER_AGENT)
195
- easy.params = options[:params] if options[:params]
196
- easy.request_body = options[:body] if options[:body]
197
- easy.timeout = options[:timeout] if options[:timeout]
198
- easy.set_headers
199
-
200
- proxy = Typhoeus::RemoteProxyObject.new(clear_memoized_proxy_objects, easy, options)
201
- set_memoized_proxy_object(method, url, options, proxy)
202
- end
203
-
204
- def remote_defaults(options)
205
- @remote_defaults ||= {}
206
- @remote_defaults.merge!(options) if options
207
- @remote_defaults
208
- end
209
-
210
- # If we get subclassed, make sure that child inherits the remote defaults
211
- # of the parent class.
212
- def inherited(child)
213
- child.__send__(:remote_defaults, @remote_defaults)
214
- end
215
-
216
- def call_remote_method(method_name, args)
217
- m = @remote_methods[method_name]
218
-
219
- base_uri = args.delete(:base_uri) || m.base_uri || ""
220
-
221
- if args.has_key? :path
222
- path = args.delete(:path)
223
- else
224
- path = m.interpolate_path_with_arguments(args)
225
- end
226
- path ||= ""
227
-
228
- http_method = m.http_method
229
- url = base_uri + path
230
- options = m.merge_options(args)
231
-
232
- # proxy_object = memoized_proxy_object(http_method, url, options)
233
- # return proxy_object unless proxy_object.nil?
234
- #
235
- # if m.cache_responses?
236
- # object = @cache.get(get_memcache_response_key(method_name, args))
237
- # if object
238
- # set_memoized_proxy_object(http_method, url, options, object)
239
- # return object
240
- # end
241
- # end
242
-
243
- proxy = memoized_proxy_object(http_method, url, options)
244
- unless proxy
245
- if m.cache_responses?
246
- options[:cache] = @cache
247
- options[:cache_key] = get_memcache_response_key(method_name, args)
248
- options[:cache_timeout] = m.cache_ttl
249
- end
250
- proxy = send(http_method, url, options)
251
- end
252
- proxy
253
- end
254
-
255
- def set_memoized_proxy_object(http_method, url, options, object)
256
- @memoized_proxy_objects ||= {}
257
- @memoized_proxy_objects["#{http_method}_#{url}_#{options.to_s}"] = object
258
- end
259
-
260
- def memoized_proxy_object(http_method, url, options)
261
- @memoized_proxy_objects ||= {}
262
- @memoized_proxy_objects["#{http_method}_#{url}_#{options.to_s}"]
263
- end
264
-
265
- def clear_memoized_proxy_objects
266
- lambda { @memoized_proxy_objects = {} }
267
- end
268
-
269
- def get_memcache_response_key(remote_method_name, args)
270
- result = "#{remote_method_name.to_s}-#{args.to_s}"
271
- (Digest::SHA2.new << result).to_s
272
- end
273
-
274
- def cache=(cache)
275
- @cache = cache
276
- end
277
-
278
- def define_remote_method(name, args = {})
279
- @remote_defaults ||= {}
280
- args[:method] ||= @remote_defaults[:method]
281
- args[:on_success] ||= @remote_defaults[:on_success]
282
- args[:on_failure] ||= @remote_defaults[:on_failure]
283
- args[:base_uri] ||= @remote_defaults[:base_uri]
284
- args[:path] ||= @remote_defaults[:path]
285
- m = RemoteMethod.new(args)
286
-
287
- @remote_methods ||= {}
288
- @remote_methods[name] = m
289
-
290
- class_eval <<-SRC
291
- def self.#{name.to_s}(args = {})
292
- call_remote_method(:#{name.to_s}, args)
293
- end
294
- SRC
295
- end
296
-
297
- private
298
- def encode_nil_response(response)
299
- response == nil ? :__nil__ : response
300
- end
301
-
302
- def decode_nil_response(response)
303
- response == :__nil__ ? nil : response
304
- end
305
- end # ClassMethods
306
- end