tech-angels-typhoeus 0.1.36

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 (44) hide show
  1. data/.gitignore +2 -0
  2. data/README.textile +312 -0
  3. data/Rakefile +39 -0
  4. data/VERSION +1 -0
  5. data/benchmarks/profile.rb +25 -0
  6. data/benchmarks/vs_nethttp.rb +35 -0
  7. data/examples/twitter.rb +21 -0
  8. data/ext/typhoeus/.gitignore +5 -0
  9. data/ext/typhoeus/Makefile +157 -0
  10. data/ext/typhoeus/extconf.rb +65 -0
  11. data/ext/typhoeus/native.c +11 -0
  12. data/ext/typhoeus/native.h +21 -0
  13. data/ext/typhoeus/typhoeus_easy.c +207 -0
  14. data/ext/typhoeus/typhoeus_easy.h +19 -0
  15. data/ext/typhoeus/typhoeus_multi.c +225 -0
  16. data/ext/typhoeus/typhoeus_multi.h +16 -0
  17. data/lib/typhoeus.rb +55 -0
  18. data/lib/typhoeus/.gitignore +1 -0
  19. data/lib/typhoeus/easy.rb +329 -0
  20. data/lib/typhoeus/filter.rb +28 -0
  21. data/lib/typhoeus/hydra.rb +235 -0
  22. data/lib/typhoeus/multi.rb +35 -0
  23. data/lib/typhoeus/remote.rb +306 -0
  24. data/lib/typhoeus/remote_method.rb +108 -0
  25. data/lib/typhoeus/remote_proxy_object.rb +48 -0
  26. data/lib/typhoeus/request.rb +159 -0
  27. data/lib/typhoeus/response.rb +49 -0
  28. data/lib/typhoeus/service.rb +20 -0
  29. data/profilers/valgrind.rb +24 -0
  30. data/spec/fixtures/result_set.xml +60 -0
  31. data/spec/servers/app.rb +73 -0
  32. data/spec/spec.opts +2 -0
  33. data/spec/spec_helper.rb +11 -0
  34. data/spec/typhoeus/easy_spec.rb +236 -0
  35. data/spec/typhoeus/filter_spec.rb +35 -0
  36. data/spec/typhoeus/hydra_spec.rb +311 -0
  37. data/spec/typhoeus/multi_spec.rb +74 -0
  38. data/spec/typhoeus/remote_method_spec.rb +141 -0
  39. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  40. data/spec/typhoeus/remote_spec.rb +695 -0
  41. data/spec/typhoeus/request_spec.rb +169 -0
  42. data/spec/typhoeus/response_spec.rb +63 -0
  43. data/typhoeus.gemspec +112 -0
  44. metadata +203 -0
@@ -0,0 +1,108 @@
1
+ module Typhoeus
2
+ class RemoteMethod
3
+ attr_accessor :http_method, :options, :base_uri, :path, :on_success, :on_failure, :cache_ttl
4
+
5
+ def initialize(options = {})
6
+ @http_method = options.delete(:method) || :get
7
+ @options = options
8
+ @base_uri = options.delete(:base_uri)
9
+ @path = options.delete(:path)
10
+ @on_success = options[:on_success]
11
+ @on_failure = options[:on_failure]
12
+ @cache_responses = options.delete(:cache_responses)
13
+ @memoize_responses = options.delete(:memoize_responses) || @cache_responses
14
+ @cache_ttl = @cache_responses == true ? 0 : @cache_responses
15
+ @keys = nil
16
+
17
+ clear_cache
18
+ end
19
+
20
+ def cache_responses?
21
+ @cache_responses
22
+ end
23
+
24
+ def memoize_responses?
25
+ @memoize_responses
26
+ end
27
+
28
+ def args_options_key(args, options)
29
+ "#{args.to_s}+#{options.to_s}"
30
+ end
31
+
32
+ def calling(args, options)
33
+ @called_methods[args_options_key(args, options)] = true
34
+ end
35
+
36
+ def already_called?(args, options)
37
+ @called_methods.has_key? args_options_key(args, options)
38
+ end
39
+
40
+ def add_response_block(block, args, options)
41
+ @response_blocks[args_options_key(args, options)] << block
42
+ end
43
+
44
+ def call_response_blocks(result, args, options)
45
+ key = args_options_key(args, options)
46
+ @response_blocks[key].each {|block| block.call(result)}
47
+ @response_blocks.delete(key)
48
+ @called_methods.delete(key)
49
+ end
50
+
51
+ def clear_cache
52
+ @response_blocks = Hash.new {|h, k| h[k] = []}
53
+ @called_methods = {}
54
+ end
55
+
56
+ def merge_options(new_options)
57
+ merged = options.merge(new_options)
58
+ if options.has_key?(:params) && new_options.has_key?(:params)
59
+ merged[:params] = options[:params].merge(new_options[:params])
60
+ end
61
+ argument_names.each {|a| merged.delete(a)}
62
+ merged.delete(:on_success) if merged[:on_success].nil?
63
+ merged.delete(:on_failure) if merged[:on_failure].nil?
64
+ merged
65
+ end
66
+
67
+ def interpolate_path_with_arguments(args)
68
+ interpolated_path = @path
69
+ argument_names.each do |arg|
70
+ interpolated_path = interpolated_path.gsub(":#{arg}", args[arg].to_s)
71
+ end
72
+ interpolated_path
73
+ end
74
+
75
+ def argument_names
76
+ return @keys if @keys
77
+ pattern, keys = compile(@path)
78
+ @keys = keys.collect {|k| k.to_sym}
79
+ end
80
+
81
+ # rippped from Sinatra. clean up stuff we don't need later
82
+ def compile(path)
83
+ path ||= ""
84
+ keys = []
85
+ if path.respond_to? :to_str
86
+ special_chars = %w{. + ( )}
87
+ pattern =
88
+ path.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
89
+ case match
90
+ when "*"
91
+ keys << 'splat'
92
+ "(.*?)"
93
+ when *special_chars
94
+ Regexp.escape(match)
95
+ else
96
+ keys << $2[1..-1]
97
+ "([^/?&#]+)"
98
+ end
99
+ end
100
+ [/^#{pattern}$/, keys]
101
+ elsif path.respond_to? :match
102
+ [path, keys]
103
+ else
104
+ raise TypeError, path
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ module Typhoeus
2
+ class RemoteProxyObject
3
+ instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
4
+
5
+ def initialize(clear_memoized_store_proc, easy, options = {})
6
+ @clear_memoized_store_proc = clear_memoized_store_proc
7
+ @easy = easy
8
+ @success = options[:on_success]
9
+ @failure = options[:on_failure]
10
+ @cache = options.delete(:cache)
11
+ @cache_key = options.delete(:cache_key)
12
+ @timeout = options.delete(:cache_timeout)
13
+ Typhoeus.add_easy_request(@easy)
14
+ end
15
+
16
+ def method_missing(sym, *args, &block)
17
+ unless @proxied_object
18
+ if @cache && @cache_key
19
+ @proxied_object = @cache.get(@cache_key) rescue nil
20
+ end
21
+
22
+ unless @proxied_object
23
+ Typhoeus.perform_easy_requests
24
+ response = Response.new(:code => @easy.response_code,
25
+ :headers => @easy.response_header,
26
+ :body => @easy.response_body,
27
+ :time => @easy.total_time_taken,
28
+ :requested_url => @easy.url,
29
+ :requested_http_method => @easy.method,
30
+ :start_time => @easy.start_time)
31
+ if @easy.response_code >= 200 && @easy.response_code < 300
32
+ Typhoeus.release_easy_object(@easy)
33
+ @proxied_object = @success.nil? ? response : @success.call(response)
34
+
35
+ if @cache && @cache_key
36
+ @cache.set(@cache_key, @proxied_object, @timeout)
37
+ end
38
+ else
39
+ @proxied_object = @failure.nil? ? response : @failure.call(response)
40
+ end
41
+ @clear_memoized_store_proc.call
42
+ end
43
+ end
44
+
45
+ @proxied_object.__send__(sym, *args, &block)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,159 @@
1
+ module Typhoeus
2
+ class Request
3
+ attr_accessor :method, :params, :body, :headers, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification, :ssl_cert, :ssl_cert_type, :ssl_key, :ssl_key_type, :ssl_key_password, :ssl_cacert, :ssl_capath, :verbose
4
+
5
+
6
+ attr_reader :url
7
+
8
+ # Initialize a new Request
9
+ #
10
+ # Options:
11
+ # * +url+ : Endpoint (URL) of the request
12
+ # * +options+ : A hash containing options among :
13
+ # ** +:method+ : :get (default) / :post / :put
14
+ # ** +:params+ : params as a Hash
15
+ # ** +:body+
16
+ # ** +:timeout+ : timeout (ms)
17
+ # ** +:headers+ : headers as Hash
18
+ # ** +:user_agent+ : user agent (string)
19
+ # ** +:cache_timeout+ : cache timeout (ms)
20
+ # ** +:follow_location
21
+ # ** +:max_redirects
22
+ # ** +:proxy
23
+ # ** +:disable_ssl_peer_verification
24
+ # ** +:ssl_cert
25
+ # ** +:ssl_cert_type
26
+ # ** +:ssl_key
27
+ # ** +:ssl_key_type
28
+ # ** +:ssl_key_password
29
+ # ** +:ssl_cacert
30
+ # ** +:ssl_capath
31
+ # ** +:verbose
32
+ #
33
+ def initialize(url, options = {})
34
+ @method = options[:method] || :get
35
+ @params = options[:params]
36
+ @body = options[:body]
37
+ @timeout = options[:timeout]
38
+ @headers = options[:headers] || {}
39
+ @user_agent = options[:user_agent] || Typhoeus::USER_AGENT
40
+ @cache_timeout = options[:cache_timeout]
41
+ @follow_location = options[:follow_location]
42
+ @max_redirects = options[:max_redirects]
43
+ @proxy = options[:proxy]
44
+ @disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
45
+ @ssl_cert = options[:ssl_cert]
46
+ @ssl_cert_type = options[:ssl_cert_type]
47
+ @ssl_key = options[:ssl_key]
48
+ @ssl_key_type = options[:ssl_key_type]
49
+ @ssl_key_password = options[:ssl_key_password]
50
+ @ssl_cacert = options[:ssl_cacert]
51
+ @ssl_capath = options[:ssl_capath]
52
+ @verbose = options[:verbose]
53
+
54
+ if @method == :post
55
+ @url = url
56
+ else
57
+ @url = @params ? "#{url}?#{params_string}" : url
58
+ end
59
+ @on_complete = nil
60
+ @after_complete = nil
61
+ @handled_response = nil
62
+ end
63
+
64
+ def host
65
+ slash_location = @url.index('/', 8)
66
+ if slash_location
67
+ @url.slice(0, slash_location)
68
+ else
69
+ query_string_location = @url.index('?')
70
+ return query_string_location ? @url.slice(0, query_string_location) : @url
71
+ end
72
+ end
73
+
74
+ def headers
75
+ @headers["User-Agent"] = @user_agent
76
+ @headers
77
+ end
78
+
79
+ def params_string
80
+ params.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |k|
81
+ value = params[k]
82
+ if value.is_a? Hash
83
+ value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
84
+ elsif value.is_a? Array
85
+ key = Rack::Utils.escape(k.to_s)
86
+ value.collect { |v| "#{key}=#{Rack::Utils.escape(v.to_s)}" }.join('&')
87
+ else
88
+ "#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(params[k].to_s)}"
89
+ end
90
+ end.flatten.join("&")
91
+ end
92
+
93
+ def on_complete(&block)
94
+ @on_complete = block
95
+ end
96
+
97
+ def on_complete=(proc)
98
+ @on_complete = proc
99
+ end
100
+
101
+ def after_complete(&block)
102
+ @after_complete = block
103
+ end
104
+
105
+ def after_complete=(proc)
106
+ @after_complete = proc
107
+ end
108
+
109
+ def call_handlers
110
+ if @on_complete
111
+ @handled_response = @on_complete.call(response)
112
+ call_after_complete
113
+ end
114
+ end
115
+
116
+ def call_after_complete
117
+ @after_complete.call(@handled_response) if @after_complete
118
+ end
119
+
120
+ def handled_response=(val)
121
+ @handled_response = val
122
+ end
123
+
124
+ def handled_response
125
+ @handled_response || response
126
+ end
127
+
128
+ def cache_key
129
+ Digest::SHA1.hexdigest(url)
130
+ end
131
+
132
+ def self.run(url, params)
133
+ r = new(url, params)
134
+ Typhoeus::Hydra.hydra.queue r
135
+ Typhoeus::Hydra.hydra.run
136
+ r.response
137
+ end
138
+
139
+ def self.get(url, params = {})
140
+ run(url, params.merge(:method => :get))
141
+ end
142
+
143
+ def self.post(url, params = {})
144
+ run(url, params.merge(:method => :post))
145
+ end
146
+
147
+ def self.put(url, params = {})
148
+ run(url, params.merge(:method => :put))
149
+ end
150
+
151
+ def self.delete(url, params = {})
152
+ run(url, params.merge(:method => :delete))
153
+ end
154
+
155
+ def self.head(url, params = {})
156
+ run(url, params.merge(:method => :head))
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,49 @@
1
+ module Typhoeus
2
+ class Response
3
+ attr_accessor :request
4
+ attr_reader :code, :headers, :body, :time,
5
+ :requested_url, :requested_remote_method,
6
+ :requested_http_method, :start_time,
7
+ :effective_url
8
+
9
+ def initialize(params = {})
10
+ @code = params[:code]
11
+ @headers = params[:headers]
12
+ @body = params[:body]
13
+ @time = params[:time]
14
+ @requested_url = params[:requested_url]
15
+ @requested_http_method = params[:requested_http_method]
16
+ @start_time = params[:start_time]
17
+ @request = params[:request]
18
+ @effective_url = params[:effective_url]
19
+ end
20
+
21
+ def headers_hash
22
+ headers.split("\n").map {|o| o.strip}.inject({}) do |hash, o|
23
+ if o.empty?
24
+ hash
25
+ else
26
+ i = o.index(":") || o.size
27
+ key = o.slice(0, i)
28
+ value = o.slice(i + 1, o.size)
29
+ value = value.strip unless value.nil?
30
+ if hash.has_key? key
31
+ hash[key] = [hash[key], value].flatten
32
+ else
33
+ hash[key] = value
34
+ end
35
+
36
+ hash
37
+ end
38
+ end
39
+ end
40
+
41
+ def success?
42
+ @code >= 200 && @code < 300
43
+ end
44
+
45
+ def modified?
46
+ @code != 304
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ module Typhoeus
2
+ class Service
3
+ def initialize(host, port)
4
+ @host = host
5
+ @port = port
6
+ end
7
+
8
+ def get(resource, params)
9
+ end
10
+
11
+ def put(resource, params)
12
+ end
13
+
14
+ def post(resource, params)
15
+ end
16
+
17
+ def delete(resource, params)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # go to ext/typhoeus and run ruby extconf.rb && make before running
3
+ # this.
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../ext")
6
+ require File.dirname(__FILE__) + "/../lib/typhoeus"
7
+
8
+ klass = Class.new { include Typhoeus }
9
+
10
+ loops = ENV['LOOPS'].to_i
11
+ url = ARGV.first || (raise "requires URL!")
12
+
13
+ loops.times do |i|
14
+ puts "On loop #{i}" if i % 10 == 0
15
+ results = []
16
+ 5.times do
17
+ results << klass.get(url)
18
+ end
19
+
20
+ # fire requests
21
+ results[0].code
22
+ end
23
+
24
+ puts "Ran #{loops} loops on #{url}!"
@@ -0,0 +1,60 @@
1
+ <result_set>
2
+ <ttl>20</ttl>
3
+ <result>
4
+ <id>1</id>
5
+ <name>hello</name>
6
+ <description>
7
+ this is a long description for a text field of some kind.
8
+ this is a long description for a text field of some kind.
9
+ this is a long description for a text field of some kind.
10
+ this is a long description for a text field of some kind.
11
+ this is a long description for a text field of some kind.
12
+ this is a long description for a text field of some kind.
13
+ this is a long description for a text field of some kind.
14
+ this is a long description for a text field of some kind.
15
+ this is a long description for a text field of some kind.
16
+ this is a long description for a text field of some kind.
17
+ this is a long description for a text field of some kind.
18
+ this is a long description for a text field of some kind.
19
+ this is a long description for a text field of some kind.
20
+ </description>
21
+ </result>
22
+ <result>
23
+ <id>2</id>
24
+ <name>hello</name>
25
+ <description>
26
+ this is a long description for a text field of some kind.
27
+ this is a long description for a text field of some kind.
28
+ this is a long description for a text field of some kind.
29
+ this is a long description for a text field of some kind.
30
+ this is a long description for a text field of some kind.
31
+ this is a long description for a text field of some kind.
32
+ this is a long description for a text field of some kind.
33
+ this is a long description for a text field of some kind.
34
+ this is a long description for a text field of some kind.
35
+ this is a long description for a text field of some kind.
36
+ this is a long description for a text field of some kind.
37
+ this is a long description for a text field of some kind.
38
+ this is a long description for a text field of some kind.
39
+ </description>
40
+ </result>
41
+ <result>
42
+ <id>3</id>
43
+ <name>hello</name>
44
+ <description>
45
+ this is a long description for a text field of some kind.
46
+ this is a long description for a text field of some kind.
47
+ this is a long description for a text field of some kind.
48
+ this is a long description for a text field of some kind.
49
+ this is a long description for a text field of some kind.
50
+ this is a long description for a text field of some kind.
51
+ this is a long description for a text field of some kind.
52
+ this is a long description for a text field of some kind.
53
+ this is a long description for a text field of some kind.
54
+ this is a long description for a text field of some kind.
55
+ this is a long description for a text field of some kind.
56
+ this is a long description for a text field of some kind.
57
+ this is a long description for a text field of some kind.
58
+ </description>
59
+ </result>
60
+ </result_set>