wrest 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +34 -0
  2. data/README.rdoc +16 -10
  3. data/Rakefile +361 -123
  4. data/VERSION.yml +2 -2
  5. data/examples/delicious.rb +17 -7
  6. data/examples/facebook.rb +101 -0
  7. data/examples/keep_alive.rb +37 -0
  8. data/examples/twitter.rb +3 -3
  9. data/examples/twitter_public_timeline.rb +11 -4
  10. data/examples/wow_realm_status.rb +8 -2
  11. data/{spec/functional/sample_rails_app/public/favicon.ico → init.rb} +0 -0
  12. data/lib/wrest/components/{attributes_container → container}/alias_accessors.rb +4 -4
  13. data/lib/wrest/components/{attributes_container → container}/typecaster.rb +1 -1
  14. data/lib/wrest/components/{attributes_container.rb → container.rb} +46 -16
  15. data/lib/wrest/components/mutators.rb +4 -4
  16. data/lib/wrest/components/translators/json.rb +2 -2
  17. data/lib/wrest/components/translators/xml.rb +3 -2
  18. data/lib/wrest/components/translators.rb +3 -3
  19. data/lib/wrest/components.rb +3 -3
  20. data/lib/wrest/core_ext/hash.rb +1 -1
  21. data/lib/wrest/core_ext/string.rb +1 -1
  22. data/lib/wrest/curl/delete.rb +23 -0
  23. data/lib/wrest/curl/get.rb +23 -0
  24. data/lib/wrest/curl/options.rb +16 -0
  25. data/lib/wrest/curl/post.rb +23 -0
  26. data/lib/wrest/curl/put.rb +23 -0
  27. data/lib/wrest/curl/request.rb +95 -0
  28. data/lib/wrest/curl/response.rb +63 -0
  29. data/lib/wrest/curl/session.rb +57 -0
  30. data/lib/wrest/curl.rb +49 -0
  31. data/lib/wrest/exceptions.rb +16 -1
  32. data/lib/wrest/http_shared/headers.rb +350 -0
  33. data/lib/wrest/http_shared/standard_headers.rb +21 -0
  34. data/lib/wrest/http_shared/standard_tokens.rb +18 -0
  35. data/lib/wrest/http_shared.rb +24 -0
  36. data/lib/wrest/native/connection_factory.rb +23 -0
  37. data/lib/wrest/{http → native}/delete.rb +1 -1
  38. data/lib/wrest/{http → native}/get.rb +1 -1
  39. data/lib/wrest/{http → native}/options.rb +1 -1
  40. data/lib/wrest/{http → native}/post.rb +1 -1
  41. data/lib/wrest/{http → native}/put.rb +1 -1
  42. data/lib/wrest/{http → native}/redirection.rb +4 -1
  43. data/lib/wrest/{http → native}/request.rb +32 -20
  44. data/lib/wrest/{http → native}/response.rb +12 -4
  45. data/lib/wrest/native/session.rb +57 -0
  46. data/lib/wrest/native.rb +32 -0
  47. data/lib/wrest/resource/base.rb +1 -1
  48. data/lib/wrest/resource.rb +1 -1
  49. data/lib/wrest/test/request_patches.rb +5 -0
  50. data/lib/wrest/test.rb +1 -0
  51. data/lib/wrest/uri.rb +31 -3
  52. data/lib/wrest/version.rb +2 -2
  53. data/lib/wrest.rb +52 -16
  54. data/spec/unit/spec_helper.rb +12 -3
  55. data/spec/unit/wrest/components/attributes_container/alias_accessors_spec.rb +2 -2
  56. data/spec/unit/wrest/components/attributes_container/typecaster_spec.rb +6 -6
  57. data/spec/unit/wrest/components/attributes_container_spec.rb +44 -12
  58. data/spec/unit/wrest/components/translators/xml_spec.rb +7 -3
  59. data/spec/unit/wrest/curl/request_spec.rb +19 -0
  60. data/spec/unit/wrest/curl/response_spec.rb +16 -0
  61. data/spec/unit/wrest/http/response_spec.rb +17 -38
  62. data/spec/unit/wrest/{http → native}/redirection_spec.rb +5 -5
  63. data/spec/unit/wrest/{http → native}/request_spec.rb +15 -14
  64. data/spec/unit/wrest/native/response_spec.rb +72 -0
  65. data/spec/unit/wrest/native/session_spec.rb +74 -0
  66. data/spec/unit/wrest/resource/base_spec.rb +2 -2
  67. data/spec/unit/wrest/uri_spec.rb +51 -11
  68. data/wrest.gemspec +164 -0
  69. metadata +51 -165
  70. data/lib/wrest/http.rb +0 -25
  71. data/spec/functional/sample_rails_app/README +0 -3
  72. data/spec/functional/sample_rails_app/Rakefile +0 -10
  73. data/spec/functional/sample_rails_app/app/controllers/application_controller.rb +0 -10
  74. data/spec/functional/sample_rails_app/app/controllers/lead_bottles_controller.rb +0 -7
  75. data/spec/functional/sample_rails_app/app/helpers/application_helper.rb +0 -3
  76. data/spec/functional/sample_rails_app/app/models/bottle.rb +0 -3
  77. data/spec/functional/sample_rails_app/app/models/glass_bottle.rb +0 -3
  78. data/spec/functional/sample_rails_app/app/models/lead_bottle.rb +0 -3
  79. data/spec/functional/sample_rails_app/config/boot.rb +0 -110
  80. data/spec/functional/sample_rails_app/config/database.yml +0 -16
  81. data/spec/functional/sample_rails_app/config/environment.rb +0 -42
  82. data/spec/functional/sample_rails_app/config/environments/development.rb +0 -17
  83. data/spec/functional/sample_rails_app/config/environments/production.rb +0 -28
  84. data/spec/functional/sample_rails_app/config/environments/test.rb +0 -28
  85. data/spec/functional/sample_rails_app/config/initializers/backtrace_silencers.rb +0 -7
  86. data/spec/functional/sample_rails_app/config/initializers/inflections.rb +0 -10
  87. data/spec/functional/sample_rails_app/config/initializers/mime_types.rb +0 -5
  88. data/spec/functional/sample_rails_app/config/initializers/new_rails_defaults.rb +0 -19
  89. data/spec/functional/sample_rails_app/config/initializers/session_store.rb +0 -15
  90. data/spec/functional/sample_rails_app/config/locales/en.yml +0 -5
  91. data/spec/functional/sample_rails_app/config/routes.rb +0 -3
  92. data/spec/functional/sample_rails_app/db/development.sqlite3 +0 -0
  93. data/spec/functional/sample_rails_app/db/migrate/20090319115628_create_bottle.rb +0 -13
  94. data/spec/functional/sample_rails_app/db/schema.rb +0 -20
  95. data/spec/functional/sample_rails_app/db/test.sqlite3 +0 -0
  96. data/spec/functional/sample_rails_app/log/development.log +0 -1
  97. data/spec/functional/sample_rails_app/public/404.html +0 -30
  98. data/spec/functional/sample_rails_app/public/422.html +0 -30
  99. data/spec/functional/sample_rails_app/public/500.html +0 -30
  100. data/spec/functional/sample_rails_app/public/images/rails.png +0 -0
  101. data/spec/functional/sample_rails_app/public/index.html +0 -275
  102. data/spec/functional/sample_rails_app/public/robots.txt +0 -5
  103. data/spec/functional/sample_rails_app/script/about +0 -4
  104. data/spec/functional/sample_rails_app/script/autospec +0 -6
  105. data/spec/functional/sample_rails_app/script/console +0 -3
  106. data/spec/functional/sample_rails_app/script/dbconsole +0 -3
  107. data/spec/functional/sample_rails_app/script/destroy +0 -3
  108. data/spec/functional/sample_rails_app/script/generate +0 -3
  109. data/spec/functional/sample_rails_app/script/performance/benchmarker +0 -3
  110. data/spec/functional/sample_rails_app/script/performance/profiler +0 -3
  111. data/spec/functional/sample_rails_app/script/plugin +0 -3
  112. data/spec/functional/sample_rails_app/script/runner +0 -3
  113. data/spec/functional/sample_rails_app/script/server +0 -3
  114. data/spec/functional/sample_rails_app/script/spec +0 -10
  115. data/spec/functional/sample_rails_app/script/spec_server +0 -9
  116. data/spec/functional/sample_rails_app/test/performance/browsing_test.rb +0 -9
  117. data/spec/functional/sample_rails_app/test/test_helper.rb +0 -38
  118. data/spec/functional/sample_rails_app/tmtags +0 -2559
  119. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/MIT-LICENSE +0 -20
  120. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/README.rdoc +0 -100
  121. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/Rakefile +0 -18
  122. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/init.rb +0 -5
  123. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/install.rb +0 -1
  124. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/base.rb +0 -140
  125. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources.rb +0 -16
  126. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources_controller.rb +0 -26
  127. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/routes_controller.rb +0 -16
  128. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/api.rb +0 -26
  129. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/exception.rb +0 -23
  130. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/from_json.rb +0 -15
  131. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/dispatch.rb +0 -235
  132. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/models/resourced_route.rb +0 -84
  133. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/query.rb +0 -337
  134. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/html.rb +0 -50
  135. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/json.rb +0 -75
  136. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/xml.rb +0 -65
  137. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render.rb +0 -63
  138. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/retrieve.rb +0 -74
  139. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/version.rb +0 -9
  140. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full.rb +0 -14
  141. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/base_spec.rb +0 -88
  142. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/controllers/resources_spec.rb +0 -29
  143. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/dispatch_spec.rb +0 -262
  144. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/models/resourced_route_spec.rb +0 -62
  145. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query/parameter_spec.rb +0 -57
  146. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query_spec.rb +0 -462
  147. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/html_spec.rb +0 -4
  148. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/json_spec.rb +0 -107
  149. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/xml_spec.rb +0 -98
  150. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render_spec.rb +0 -5
  151. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/retrieve_spec.rb +0 -173
  152. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/spec_helper.rb +0 -98
  153. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/uninstall.rb +0 -1
  154. data/spec/functional/spec_helper.rb +0 -0
@@ -0,0 +1,24 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at native://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest #:nodoc:
11
+
12
+ # Contains functionality the is independent of
13
+ # the underlying HTTP libs
14
+ module HttpShared
15
+ end
16
+ end
17
+
18
+ require "#{Wrest::Root}/wrest/http_shared/headers"
19
+ require "#{Wrest::Root}/wrest/http_shared/standard_headers"
20
+ require "#{Wrest::Root}/wrest/http_shared/standard_tokens"
21
+
22
+ # Set up a shorter convenience API for constants
23
+ Wrest::H = Wrest::HttpShared::StandardHeaders
24
+ Wrest::T = Wrest::HttpShared::StandardTokens
@@ -0,0 +1,23 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest::Native
11
+ module ConnectionFactory
12
+ def create_connection(timeout = 60)
13
+ timeout ||= 60
14
+ connection = Net::HTTP.new(self.host, self.port)
15
+ connection.read_timeout = timeout
16
+ if self.https?
17
+ connection.use_ssl = true
18
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
+ end
20
+ connection
21
+ end
22
+ end
23
+ end
@@ -7,7 +7,7 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  class Delete < Request
12
12
  def initialize(wrest_uri, parameters = {}, headers = {}, options = {})
13
13
  super(
@@ -7,7 +7,7 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  class Get < Request
12
12
  def initialize(wrest_uri, parameters = {}, headers = {}, options = {})
13
13
  follow_redirects = options[:follow_redirects]
@@ -7,7 +7,7 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  class Options < Request
12
12
  def initialize(wrest_uri, options = {})
13
13
  super(
@@ -7,7 +7,7 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  class Post < Request
12
12
  def initialize(wrest_uri, body = '', headers = {}, parameters = {}, options = {})
13
13
  super(
@@ -7,7 +7,7 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  class Put < Request
12
12
  def initialize(wrest_uri, body = '', headers = {}, parameters = {}, options = {})
13
13
  super(
@@ -8,9 +8,12 @@
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
10
  module Wrest #:nodoc:
11
- module Http #:nodoc:
11
+ module Native #:nodoc:
12
12
  # Constructed by Wrest::Response.new if the HTTP response code is 3xx
13
13
  # (http://en.wikipedia.org/wiki/300_Multiple_Choices#3xx_Redirection)
14
+ #
15
+ # This class is necessary because Net::HTTP doesn't seem to support
16
+ # redirection natively.
14
17
  class Redirection < Response
15
18
 
16
19
  # A get is invoked on the url stored in the response headers
@@ -7,13 +7,13 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Http
10
+ module Wrest::Native
11
11
  # This represents a HTTP request. Typically you will never need to instantiate
12
12
  # one of these yourself - you can use one of the more conveient APIs via Wrest::Uri
13
13
  # or Wrest::Http::Get etc. instead.
14
14
  class Request
15
- attr_reader :http_request, :uri, :body, :headers, :username, :password, :follow_redirects,
16
- :follow_redirects_limit, :follow_redirects_count, :timeout
15
+ attr_reader :http_request, :uri, :body, :headers, :username, :password, :follow_redirects,
16
+ :follow_redirects_limit, :follow_redirects_count, :timeout, :connection, :parameters
17
17
  # Valid tuples for the options are:
18
18
  # :username => String, defaults to nil
19
19
  # :password => String, defaults to nil
@@ -28,10 +28,13 @@ module Wrest::Http
28
28
  # until the follow_redirects_limit is hit. You should never set
29
29
  # this option yourself.
30
30
  # :timeout => The period, in seconds, after which a Timeout::Error is raised
31
- # in the event of a connection failing to open. Defaults to 60.
31
+ # in the event of a connection failing to open. Defaulted to 60 by Uri#create_connection.
32
+ # :connection => The HTTP Connection object to use. This is how a keep-alive connection can be
33
+ # used for multiple requests.
32
34
  def initialize(wrest_uri, http_request_klass, parameters = {}, body = nil, headers = {}, options = {})
33
35
  @uri = wrest_uri
34
36
  @headers = headers.stringify_keys
37
+ @parameters = parameters
35
38
  @http_request = http_request_klass.new(parameters.empty? ? wrest_uri.full_path : "#{wrest_uri.full_path}?#{parameters.to_query}", @headers)
36
39
  @body = body
37
40
  @options = options.clone
@@ -40,33 +43,42 @@ module Wrest::Http
40
43
  @follow_redirects = (@options[:follow_redirects] ||= false)
41
44
  @follow_redirects_count = (@options[:follow_redirects_count] ||= 0)
42
45
  @follow_redirects_limit = (@options[:follow_redirects_limit] ||= 5)
43
- @timeout = (@options[:timeout] ||= 60)
46
+ @timeout = @options[:timeout]
47
+ @connection = @options[:connection]
44
48
  end
45
49
 
46
- # Makes a request and returns a Wrest::Http::Response.
50
+ # Makes a request and returns a Wrest::Native::Response.
47
51
  # Data about the request is and logged to Wrest.logger
52
+ # The log entry contains the following information:
53
+ #
54
+ # --> indicates a request
55
+ # <-- indicates a response
56
+ #
57
+ # The type of request is mentioned in caps, followed by a hash
58
+ # uniquely uniquely identifying a particular request/response pair.
59
+ # In a multi-process or multi-threaded scenario, this can be used
60
+ # to identify request-response pairs.
61
+ #
62
+ # The request hash is followed by a connection hash; requests using the
63
+ # same connection (effectively a keep-alive connection) will have the
64
+ # same connection hash.
65
+ #
66
+ # This is followed by the response code, the payload size and the time taken.
48
67
  def invoke
49
68
  response = nil
50
-
51
- prefix = "#{http_request.method} #{http_request.hash}"
52
- http_connection = create_connection(timeout)
69
+
70
+ @connection ||= @uri.create_connection(timeout)
53
71
  http_request.basic_auth username, password
54
72
 
73
+ prefix = "#{http_request.method} #{http_request.hash} #{@connection.hash}"
74
+
55
75
  Wrest.logger.debug "--> (#{prefix}) #{@uri.protocol}://#{@uri.host}:#{@uri.port}#{@http_request.path}"
56
- time = Benchmark.realtime { response = Wrest::Http::Response.new( http_connection.request(@http_request, @body) ) }
76
+ time = Benchmark.realtime { response = Wrest::Native::Response.new( @connection.request(@http_request, @body) ) }
57
77
  Wrest.logger.debug "<-- (#{prefix}) %d %s (%d bytes %.2fs)" % [response.code, response.message, response.body ? response.body.length : 0, time]
58
78
 
59
79
  @follow_redirects ? response.follow(@options) : response
60
- end
61
-
62
- def create_connection(timeout)
63
- connection = Net::HTTP.new(@uri.host, @uri.port)
64
- connection.read_timeout = timeout
65
- if @uri.https?
66
- connection.use_ssl = true
67
- connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
68
- end
69
- connection
80
+ rescue Timeout::Error => e
81
+ raise Wrest::Exceptions::Timeout.new(e)
70
82
  end
71
83
  end
72
84
  end
@@ -8,10 +8,10 @@
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
10
  module Wrest #:nodoc:
11
- module Http #:nodoc:
11
+ module Native #:nodoc:
12
12
  # Decorates a response providing support for deserialisation.
13
13
  #
14
- # The following methods are also available (unlisted by rdoc because they're forwarded):
14
+ # The following methods are also available (unlisted by rdoc because they're forwarded to Net::HTTP::Response):
15
15
  #
16
16
  # <tt>:@Http_response, :code, :message, :body, :Http_version,
17
17
  # :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch,
@@ -19,15 +19,19 @@ module Wrest #:nodoc:
19
19
  #
20
20
  # They behave exactly like their Net::HttpResponse equivalents.
21
21
  class Response
22
+ attr_reader :http_response
23
+
22
24
  extend Forwardable
23
25
  def_delegators :@http_response, :code, :message, :body, :Http_version,
24
26
  :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch,
25
27
  :get_fields, :key?, :type_params
26
28
 
27
29
  # We're overriding :new to act as a factory so
28
- # we can build the appropriate Response instance
30
+ # we can build the appropriate Response instance based
31
+ # on th response code.
29
32
  def self.new(http_response)
30
- instance = ((300..399).include?(http_response.code.to_i) ? Wrest::Http::Redirection : self).allocate
33
+ code = http_response.code.to_i
34
+ instance = ((300..303).include?(code) || (305..399).include?(code) ? Wrest::Native::Redirection : self).allocate
31
35
  instance.send :initialize, http_response
32
36
  instance
33
37
  end
@@ -56,6 +60,10 @@ module Wrest #:nodoc:
56
60
  def follow(redirect_request_options = {})
57
61
  self
58
62
  end
63
+
64
+ def connection_closed?
65
+ self[Native::StandardHeaders::Connection].downcase == Native::StandardTokens::Close.downcase
66
+ end
59
67
  end
60
68
  end
61
69
  end
@@ -0,0 +1,57 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest::Native
11
+ # This class is a wrapper for a keep-alive HTTP connection. It simply passes the
12
+ # same connection instance as an option to all Wrest::Http::Request instances created using it.
13
+ #
14
+ # If at any point the server closes an existing connection during a Session by returning a
15
+ # Connection: Close header the current connection is destroyed and a fresh one created for the next
16
+ # request.
17
+ #
18
+ # The Session constructor can accept either a String URI or a Wrest::Uri as a parameter. If you
19
+ # need HTTP authentication, you should use a Wrest::Uri.
20
+ class Session
21
+ attr_reader :uri
22
+ def initialize(uri)
23
+ @uri = uri.is_a?(String) ? uri.to_uri : uri
24
+ @default_headers = { Wrest::Native::StandardHeaders::Connection => Wrest::Native::StandardTokens::KeepAlive }
25
+
26
+ yield(self) if block_given?
27
+ end
28
+
29
+ def connection
30
+ @connection ||= @uri.create_connection
31
+ end
32
+
33
+ def get(path = '', parameters = {}, headers = {})
34
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].get(parameters, headers.merge(@default_headers))
35
+ end
36
+
37
+ def post(path = '', body = '', headers = {}, params = {})
38
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].post(body, headers.merge(@default_headers), params)
39
+ end
40
+
41
+ def put(path = '', body = '', headers = {}, params = {})
42
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].put(body, headers.merge(@default_headers), params)
43
+ end
44
+
45
+ def delete(path = '', parameters = {}, headers = {})
46
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].delete(parameters, headers.merge(@default_headers))
47
+ end
48
+
49
+ def maybe_destroy_connection(response)
50
+ if response.connection_closed?
51
+ Wrest.logger.warn "Connection #{@connection.hash} has been closed by the server"
52
+ @connection = nil
53
+ end
54
+ response
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at native://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest #:nodoc:
11
+
12
+ # Contains all native protocol related classes such as
13
+ # Get, Post, Request, Response etc. and uses the native
14
+ # Ruby Net::native libraries.
15
+ module Native
16
+ include Wrest::HttpShared
17
+ end
18
+ end
19
+
20
+ require "#{Wrest::Root}/wrest/native/connection_factory"
21
+ require "#{Wrest::Root}/wrest/native/response"
22
+ require "#{Wrest::Root}/wrest/native/redirection"
23
+ require "#{Wrest::Root}/wrest/native/request"
24
+ require "#{Wrest::Root}/wrest/native/get"
25
+ require "#{Wrest::Root}/wrest/native/put"
26
+ require "#{Wrest::Root}/wrest/native/post"
27
+ require "#{Wrest::Root}/wrest/native/delete"
28
+ require "#{Wrest::Root}/wrest/native/options"
29
+ require "#{Wrest::Root}/wrest/native/session"
30
+
31
+ # default to using Native libs
32
+ Wrest::Http = Wrest::Native
@@ -11,7 +11,7 @@ module Wrest::Resource #:nodoc:
11
11
  # Resource::Base is the equivalent of ActiveResource::Base.
12
12
  # It is a REST client targetted at Rails REST apps.
13
13
  class Base
14
- include Wrest::Components::AttributesContainer
14
+ include Wrest::Components::Container
15
15
 
16
16
  always_has :id
17
17
  typecast :id => as_integer
@@ -15,4 +15,4 @@ module Wrest
15
15
  end
16
16
  end
17
17
 
18
- require "#{WREST_ROOT}/wrest/resource/base"
18
+ require "#{Wrest::Root}/wrest/resource/base"
@@ -0,0 +1,5 @@
1
+ class Wrest::Native::Request
2
+ def invoke
3
+ raise Wrest::Exceptions::RealRequestMadeInTestEnvironmet, 'A real HTTP request was made while running tests. Please avoid using live HTTP connections while testing and replace them with mocks.'
4
+ end
5
+ end
data/lib/wrest/test.rb ADDED
@@ -0,0 +1 @@
1
+ require "#{Wrest::Root}/wrest/test/request_patches"
data/lib/wrest/uri.rb CHANGED
@@ -22,14 +22,13 @@ module Wrest #:nodoc:
22
22
  #
23
23
  # You can find examples that use real APIs (like delicious) under the wrest/examples directory.
24
24
  class Uri
25
- attr_reader :uri, :username, :password
26
-
25
+ attr_reader :uri, :username, :password, :uri_string
26
+
27
27
  # See Wrest::Http::Request for the available options and their default values.
28
28
  def initialize(uri_string, options = {})
29
29
  @options = options
30
30
  @uri_string = uri_string.clone
31
31
  @uri = URI.parse(uri_string)
32
- @options = options
33
32
  @username = (@options[:username] ||= @uri.user)
34
33
  @password = (@options[:password] ||= @uri.password)
35
34
  end
@@ -53,6 +52,12 @@ module Wrest #:nodoc:
53
52
  Uri.new(@uri_string+path, options || @options)
54
53
  end
55
54
 
55
+ # Clones a Uri, building a new instance with exactly the same uri string.
56
+ # You can however change the Uri options or add new ones.
57
+ def clone(opts = {})
58
+ Uri.new(@uri_string, @options.merge(opts))
59
+ end
60
+
56
61
  def eql?(other)
57
62
  self == other
58
63
  end
@@ -66,6 +71,13 @@ module Wrest #:nodoc:
66
71
  @uri.hash + @username.hash + @password.hash + 20090423
67
72
  end
68
73
 
74
+ # This produces exactly the same string as the Wrest::Uri was constructed with.
75
+ # If the orignial URI contained a HTTP username and password, that too will
76
+ # show up, so be careful if using this for logging.
77
+ def to_s
78
+ uri_string
79
+ end
80
+
69
81
  # Make a GET request to this URI. This is a convenience API
70
82
  # that creates a Wrest::Http::Get, executes it and returns a Wrest::Http::Response.
71
83
  #
@@ -84,11 +96,25 @@ module Wrest #:nodoc:
84
96
 
85
97
  # Makes a POST request to this URI. This is a convenience API
86
98
  # that creates a Wrest::Http::Post, executes it and returns a Wrest::Http::Response.
99
+ # Note that sending an empty body will blow up if you're using libcurl.
87
100
  #
88
101
  # Remember to escape all parameter strings if necessary, using URI.escape
89
102
  def post(body = '', headers = {}, parameters = {})
90
103
  Http::Post.new(self, body.to_s, headers, parameters, @options).invoke
91
104
  end
105
+
106
+ # Makes a POST request to this URI. This is a convenience API
107
+ # that mimics a form being posted; some allegly RESTful APIs like FCBK
108
+ # require this to be used.
109
+ #
110
+ # Form encoding involves munging the parameters into a string and placing them
111
+ # in the body, as well as setting the Content-Type header to
112
+ # application/x-www-form-urlencoded
113
+ def post_form(parameters = {}, headers = {})
114
+ headers = headers.merge(Wrest::H::ContentType => Wrest::T::FormEncoded)
115
+ body = parameters.to_query
116
+ Http::Post.new(self, body, headers, {}, @options).invoke
117
+ end
92
118
 
93
119
  # Makes a DELETE request to this URI. This is a convenience API
94
120
  # that creates a Wrest::Http::Delete, executes it and returns a Wrest::Http::Response.
@@ -128,5 +154,7 @@ module Wrest #:nodoc:
128
154
  def port
129
155
  uri.port
130
156
  end
157
+
158
+ include Http::ConnectionFactory
131
159
  end
132
160
  end
data/lib/wrest/version.rb CHANGED
@@ -11,8 +11,8 @@ module Wrest
11
11
  module VERSION
12
12
  unless defined? MAJOR
13
13
  MAJOR = 0
14
- MINOR = 0
15
- TINY = 9
14
+ MINOR = 1
15
+ TINY = 0
16
16
 
17
17
  STRING = [MAJOR, MINOR, TINY].join('.')
18
18
 
data/lib/wrest.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # Copyright 2009 Sidu Ponnappa
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
5
- # Unless required by applicable law or agreed to in writing, software distributed under the License
6
- # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7
- # See the License for the specific language governing permissions and limitations under the License.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
5
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
6
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7
+ # See the License for the specific language governing permissions and limitations under the License.
8
8
 
9
9
  require 'rubygems'
10
- gem 'activesupport', '>= 2.3.2'
10
+ gem 'activesupport', '>= 2.3.5'
11
11
 
12
12
  require 'net/http'
13
13
  require 'net/https'
@@ -19,16 +19,25 @@ require 'logger'
19
19
  require 'benchmark'
20
20
  require 'active_support'
21
21
 
22
- WREST_ROOT = File.dirname(__FILE__)
23
22
 
24
23
  module Wrest #:nodoc:
24
+ Root = File.dirname(__FILE__)
25
25
  def self.logger=(logger)
26
26
  @logger = logger
27
27
  end
28
-
28
+
29
29
  def self.logger
30
30
  @logger
31
31
  end
32
+
33
+ def self.use_native
34
+ silence_warnings{ Wrest.const_set('Http', Wrest::Native) }
35
+ end
36
+
37
+ def self.use_curl
38
+ require "#{Wrest::Root}/wrest/curl"
39
+ silence_warnings{ Wrest.const_set('Http', Wrest::Curl) }
40
+ end
32
41
  end
33
42
 
34
43
  Wrest.logger = ActiveSupport::BufferedLogger.new(STDOUT)
@@ -38,13 +47,40 @@ begin
38
47
  gem 'libxml-ruby', '>= 1.1.3'
39
48
  ActiveSupport::XmlMini.backend='LibXML'
40
49
  rescue Gem::LoadError
41
- Wrest.logger.warn "LibXML >= 1.1.3 not found, falling back to #{ActiveSupport::XmlMini.backend}. To install LibXML run `sudo gem install ruby-libxml`"
50
+ Wrest.logger.debug "Warning: LibXML >= 1.1.3 not found, attempting to use Nokogiri. To install LibXML run `(sudo) gem install libxml-ruby` (libxml-ruby is not available on JRuby)"
51
+ begin
52
+ gem 'nokogiri', '>= 1.3.3'
53
+ ActiveSupport::XmlMini.backend='Nokogiri'
54
+ rescue Gem::LoadError
55
+ Wrest.logger.debug "Warning: Nokogiri >= 1.3.3 not found, falling back to #{ActiveSupport::XmlMini.backend} (which is probably significantly slower). To install Nokogiri run `(sudo) (jruby -S) gem install nokogiri`"
56
+ if RUBY_PLATFORM =~ /java/
57
+ begin
58
+ gem 'jrexml', '>= 0.5.3'
59
+ require 'jrexml'
60
+ Wrest.logger.debug "Detected JRuby, JREXML loaded."
61
+ rescue Gem::LoadError
62
+ Wrest.logger.debug "Warning: Detected JRuby, but failed to load JREXML. JREXML offers *some* performance improvement when using REXML on JRuby. To install JREXML run `(sudo) jruby -S gem install jrexml`"
63
+ end
64
+ end
65
+ end
42
66
  end
43
67
 
44
- source_dirs = ["/wrest/core_ext/*.rb", "/wrest/*.rb"]
68
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/wrest/core_ext/*.rb"].each { |file| require file }
69
+
70
+ # Load Wrest Core
71
+ require "#{Wrest::Root}/wrest/http_shared"
72
+ require "#{Wrest::Root}/wrest/native"
73
+
74
+ # Load Wrest Wrappers
75
+ require "#{Wrest::Root}/wrest/uri"
76
+ require "#{Wrest::Root}/wrest/uri_template"
77
+ require "#{Wrest::Root}/wrest/version"
78
+ require "#{Wrest::Root}/wrest/exceptions"
79
+ require "#{Wrest::Root}/wrest/components"
80
+
81
+ # Load Wrest::Resource
82
+ require "#{Wrest::Root}/wrest/resource"
45
83
 
46
- source_dirs.each{|directory|
47
- Dir["#{File.expand_path(File.dirname(__FILE__) + directory)}"].each { |file|
48
- require file
49
- }
50
- }
84
+ # if (ENV['RAILS_ENV'] == 'test' || (Kernel.const_defined?(:RAILS_ENV) && (RAILS_ENV == 'test')))
85
+ # require "#{Wrest::Root}/wrest/test"
86
+ # end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../../lib/wrest")
2
+ require "#{Wrest::Root}/wrest/curl" unless RUBY_PLATFORM =~ /java/
2
3
  require 'spec'
3
4
 
4
5
  ['/../custom_matchers/**/*.rb'].each{|directory|
@@ -7,7 +8,7 @@ require 'spec'
7
8
  }
8
9
  }
9
10
 
10
- Wrest.logger = Logger.new(File.open("#{WREST_ROOT}/../log/test.log", 'a'))
11
+ Wrest.logger = Logger.new(File.open("#{Wrest::Root}/../log/test.log", 'a'))
11
12
 
12
13
  def p(*args)
13
14
  # super *(args << caller[0])
@@ -17,10 +18,18 @@ end
17
18
 
18
19
  def puts(*args)
19
20
  # super *(args << caller[0])
20
- super *(args << '<br/>')
21
+ super *(['<pre>'] + args + ['</pre>'])
21
22
  # super *args
22
23
  end
23
24
 
24
25
  Spec::Runner.configure do |config|
25
26
  config.include(CustomMatchers)
26
- end
27
+ end
28
+
29
+ def build_ok_response(body = '')
30
+ returning mock(Net::HTTPOK) do |response|
31
+ response.stub!(:code).and_return('200')
32
+ response.stub!(:message).and_return('OK')
33
+ response.stub!(:body).and_return(body)
34
+ end
35
+ end
@@ -1,11 +1,11 @@
1
1
  require File.dirname(__FILE__) + '/../../../spec_helper'
2
2
 
3
3
  module Wrest::Components
4
- describe AttributesContainer::AliasAccessors do
4
+ describe Container::AliasAccessors do
5
5
  before :each do
6
6
  @Demon = Class.new
7
7
  @Demon.class_eval do
8
- include Wrest::Components::AttributesContainer
8
+ include Wrest::Components::Container
9
9
  end
10
10
  end
11
11
 
@@ -1,12 +1,12 @@
1
1
  require File.dirname(__FILE__) + '/../../../spec_helper'
2
2
 
3
3
  module Wrest::Components
4
- describe AttributesContainer::Typecaster do
4
+ describe Container::Typecaster do
5
5
  before :each do
6
6
  @Demon = Class.new
7
7
  @Demon.class_eval do
8
- include Wrest::Components::AttributesContainer
9
- include Wrest::Components::AttributesContainer::Typecaster
8
+ include Wrest::Components::Container
9
+ include Wrest::Components::Container::Typecaster
10
10
  end
11
11
  end
12
12
 
@@ -25,7 +25,7 @@ module Wrest::Components
25
25
 
26
26
  it "hash should not typecast" do
27
27
  class TestUser
28
- include Wrest::Components::AttributesContainer
28
+ include Wrest::Components::Container
29
29
  end
30
30
 
31
31
  @Demon.class_eval{ typecast :user => lambda{|user| TestUser.new(user)}}
@@ -58,8 +58,8 @@ module Wrest::Components
58
58
  before :each do
59
59
  @Sidhe = Class.new
60
60
  @Sidhe.class_eval do
61
- include Wrest::Components::AttributesContainer
62
- include Wrest::Components::AttributesContainer::Typecaster
61
+ include Wrest::Components::Container
62
+ include Wrest::Components::Container::Typecaster
63
63
 
64
64
  typecast :age => as_integer
65
65
  end