wrest 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +24 -17
- data/Rakefile +5 -4
- data/VERSION.yml +1 -1
- data/examples/delicious.rb +7 -3
- data/examples/redirection.rb +27 -0
- data/examples/twitter.rb +78 -0
- data/{spec/wrest/http/request_spec.rb → examples/twitter_public_timeline.rb} +15 -12
- data/examples/wow_realm_status.rb +7 -3
- data/lib/wrest/components/attributes_container/alias_accessors.rb +66 -0
- data/lib/wrest/components/attributes_container/typecaster.rb +44 -38
- data/lib/wrest/components/attributes_container.rb +23 -5
- data/lib/wrest/components/mutators/base.rb +1 -1
- data/lib/wrest/components/translators.rb +1 -1
- data/lib/wrest/core_ext/string/conversions.rb +1 -1
- data/lib/wrest/exceptions.rb +14 -2
- data/lib/wrest/http/get.rb +2 -0
- data/lib/wrest/http/redirection.rb +35 -0
- data/lib/wrest/http/request.rb +37 -13
- data/lib/wrest/http/response.rb +17 -0
- data/lib/wrest/http.rb +1 -0
- data/lib/wrest/resource/base.rb +1 -2
- data/lib/wrest/uri.rb +2 -0
- data/lib/wrest/version.rb +1 -1
- data/spec/functional/sample_rails_app/README +3 -0
- data/spec/functional/sample_rails_app/Rakefile +10 -0
- data/spec/functional/sample_rails_app/app/controllers/application_controller.rb +10 -0
- data/spec/functional/sample_rails_app/app/controllers/lead_bottles_controller.rb +7 -0
- data/spec/functional/sample_rails_app/app/helpers/application_helper.rb +3 -0
- data/spec/functional/sample_rails_app/app/models/bottle.rb +3 -0
- data/spec/functional/sample_rails_app/app/models/glass_bottle.rb +3 -0
- data/spec/functional/sample_rails_app/app/models/lead_bottle.rb +3 -0
- data/spec/functional/sample_rails_app/config/boot.rb +110 -0
- data/spec/functional/sample_rails_app/config/database.yml +16 -0
- data/spec/functional/sample_rails_app/config/environment.rb +42 -0
- data/spec/functional/sample_rails_app/config/environments/development.rb +17 -0
- data/spec/functional/sample_rails_app/config/environments/production.rb +28 -0
- data/spec/functional/sample_rails_app/config/environments/test.rb +28 -0
- data/spec/functional/sample_rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/functional/sample_rails_app/config/initializers/inflections.rb +10 -0
- data/spec/functional/sample_rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/functional/sample_rails_app/config/initializers/new_rails_defaults.rb +19 -0
- data/spec/functional/sample_rails_app/config/initializers/session_store.rb +15 -0
- data/spec/functional/sample_rails_app/config/locales/en.yml +5 -0
- data/spec/functional/sample_rails_app/config/routes.rb +3 -0
- data/spec/functional/sample_rails_app/db/development.sqlite3 +0 -0
- data/spec/functional/sample_rails_app/db/migrate/20090319115628_create_bottle.rb +13 -0
- data/spec/functional/sample_rails_app/db/schema.rb +20 -0
- data/spec/functional/sample_rails_app/db/test.sqlite3 +0 -0
- data/spec/functional/sample_rails_app/log/development.log +1 -0
- data/spec/functional/sample_rails_app/public/404.html +30 -0
- data/spec/functional/sample_rails_app/public/422.html +30 -0
- data/spec/functional/sample_rails_app/public/500.html +30 -0
- data/spec/functional/sample_rails_app/public/favicon.ico +0 -0
- data/spec/functional/sample_rails_app/public/images/rails.png +0 -0
- data/spec/functional/sample_rails_app/public/index.html +275 -0
- data/spec/functional/sample_rails_app/public/robots.txt +5 -0
- data/spec/functional/sample_rails_app/script/about +4 -0
- data/spec/functional/sample_rails_app/script/autospec +6 -0
- data/spec/functional/sample_rails_app/script/console +3 -0
- data/spec/functional/sample_rails_app/script/dbconsole +3 -0
- data/spec/functional/sample_rails_app/script/destroy +3 -0
- data/spec/functional/sample_rails_app/script/generate +3 -0
- data/spec/functional/sample_rails_app/script/performance/benchmarker +3 -0
- data/spec/functional/sample_rails_app/script/performance/profiler +3 -0
- data/spec/functional/sample_rails_app/script/plugin +3 -0
- data/spec/functional/sample_rails_app/script/runner +3 -0
- data/spec/functional/sample_rails_app/script/server +3 -0
- data/spec/functional/sample_rails_app/script/spec +10 -0
- data/spec/functional/sample_rails_app/script/spec_server +9 -0
- data/spec/functional/sample_rails_app/test/performance/browsing_test.rb +9 -0
- data/spec/functional/sample_rails_app/test/test_helper.rb +38 -0
- data/spec/functional/sample_rails_app/tmtags +2559 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/MIT-LICENSE +20 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/README.rdoc +100 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/Rakefile +18 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/init.rb +5 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/install.rb +1 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/base.rb +140 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources.rb +16 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources_controller.rb +26 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/routes_controller.rb +16 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/api.rb +26 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/exception.rb +23 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/from_json.rb +15 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/dispatch.rb +235 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/models/resourced_route.rb +84 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/query.rb +337 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/html.rb +50 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/json.rb +75 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/xml.rb +65 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render.rb +63 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/retrieve.rb +74 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/version.rb +9 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full.rb +14 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/base_spec.rb +88 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/controllers/resources_spec.rb +29 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/dispatch_spec.rb +262 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/models/resourced_route_spec.rb +62 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query/parameter_spec.rb +57 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query_spec.rb +462 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/html_spec.rb +4 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/json_spec.rb +107 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/xml_spec.rb +98 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render_spec.rb +5 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/retrieve_spec.rb +173 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/spec_helper.rb +98 -0
- data/spec/functional/sample_rails_app/vendor/plugins/resource_full/uninstall.rb +1 -0
- data/spec/functional/spec_helper.rb +0 -0
- data/spec/{spec_helper.rb → unit/spec_helper.rb} +2 -2
- data/spec/unit/wrest/components/attributes_container/alias_accessors_spec.rb +49 -0
- data/spec/{wrest → unit/wrest}/components/attributes_container/typecaster_spec.rb +28 -8
- data/spec/{wrest → unit/wrest}/components/attributes_container_spec.rb +42 -15
- data/spec/{wrest → unit/wrest}/components/mutators/base_spec.rb +1 -1
- data/spec/{wrest → unit/wrest}/components/mutators/camel_to_snake_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/components/mutators/xml_mini_type_caster_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/components/mutators/xml_simple_type_caster_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/components/mutators_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/components/translators/xml_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/components/translators_spec.rb +1 -1
- data/spec/{wrest → unit/wrest}/core_ext/hash/conversions_spec.rb +0 -0
- data/spec/{wrest → unit/wrest}/core_ext/string/conversions_spec.rb +14 -0
- data/spec/unit/wrest/http/redirection_spec.rb +42 -0
- data/spec/unit/wrest/http/request_spec.rb +70 -0
- data/spec/unit/wrest/http/response_spec.rb +45 -0
- data/spec/{wrest → unit/wrest}/resource/base_spec.rb +5 -4
- data/spec/{wrest → unit/wrest}/uri_spec.rb +68 -67
- data/spec/{wrest → unit/wrest}/uri_template_spec.rb +0 -0
- metadata +187 -38
- data/lib/wrest/exceptions/method_not_overridden_exception.rb +0 -17
- data/lib/wrest/exceptions/unsupported_content_type_exception.rb +0 -17
- data/spec/wrest/http/response_spec.rb +0 -21
data/README.rdoc
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
= Wrest
|
1
|
+
= Wrest 0.0.9
|
2
2
|
|
3
3
|
(c) Copyright 2009 {Sidu Ponnappa}[http://blog.sidu.in]. All Rights Reserved.
|
4
4
|
|
5
|
-
Wrest is a ruby REST client library which allows you to quickly build object oriented wrappers around any web service. It has two components - Wrest Core and Wrest::Resource.
|
5
|
+
Wrest is a ruby REST client library which allows you to quickly build object oriented wrappers around any web service. It has two components - Wrest Core and Wrest::Resource. If you want to be notified whenever new features are added to Wrest, you can subscribe to my {twitter feed}[http://twitter.com/ponnappa].
|
6
6
|
|
7
|
-
If you were wondering why the words 'demon', 'chi' and 'puppies' (among others) show up in nearly every example and spec, it's because they all refer to characters and ideas from {Roger Zelazny's}[http://en.wikipedia.org/wiki/Roger_Zelazny] last book, 'Lord Demon.'
|
7
|
+
If you were wondering why the words 'demon', 'chi' and 'fu-puppies' (among others) show up in nearly every example and spec, it's because they all refer to characters and ideas from {Roger Zelazny's}[http://en.wikipedia.org/wiki/Roger_Zelazny] last book, 'Lord Demon.'
|
8
8
|
|
9
9
|
== Wrest Core: Features
|
10
10
|
|
11
|
-
* Provides convenient HTTP wrappers, serialisation and deserialisation with caching
|
12
|
-
* Designed to be used as a library, not just a command line REST client (fewer class methods, more object oriented)
|
11
|
+
* Provides convenient HTTP wrappers, redirect handling, serialisation and deserialisation with response caching in the works.
|
12
|
+
* Designed to be used as a library, not just a command line REST client (fewer class/static methods, more object oriented)
|
13
13
|
* Isn't coupled to Rails (usable in a pure Ruby application to consume any HTTP/REST api)
|
14
14
|
* Can be used both stand alone as well as to build object oriented abstractions around resources and web services (Wrest::Resource is an example of the latter)
|
15
15
|
|
@@ -23,8 +23,9 @@ The source is available at git://github.com/kaiwren/wrest.git
|
|
23
23
|
|
24
24
|
To install as a Rails plugin, do <tt>script/plugin install git://github.com/kaiwren/wrest.git</tt>
|
25
25
|
|
26
|
-
To install the Wrest gem, do <tt>(sudo) gem install wrest</tt
|
27
|
-
|
26
|
+
To install the Wrest gem, do <tt>(sudo) gem install wrest</tt>. Wrest supports both Ruby 1.8 and 1.9.
|
27
|
+
|
28
|
+
Wrest is also available as a gem for JRuby; you can install it by running <tt>(sudo) jruby -S gem install wrest</tt>.
|
28
29
|
|
29
30
|
=== Usage: Shell
|
30
31
|
|
@@ -89,24 +90,26 @@ To find out what actions are permitted on a URI:
|
|
89
90
|
|
90
91
|
=== Usage: Attributes Container
|
91
92
|
|
92
|
-
Allows any class to hold an attributes hash, somewhat like ActiveResource. It also supports several extensions to this base fuctionality such as support for typecasting attribute values.
|
93
|
+
Allows any class to hold an attributes hash, somewhat like ActiveResource. It also supports several extensions to this base fuctionality such as support for typecasting attribute values. See examples/twitter.rb and examples/wow_realm_status.rb for more samples.
|
93
94
|
|
94
95
|
Example:
|
95
96
|
|
96
97
|
class Demon
|
97
98
|
include Wrest::Components::AttributesContainer
|
98
|
-
include Wrest::Components::AttributesContainer::Typecaster
|
99
99
|
|
100
|
-
always_has
|
100
|
+
always_has :id
|
101
101
|
typecast :age => as_integer,
|
102
102
|
:chi => lambda{|chi| Chi.new(chi)}
|
103
|
+
|
104
|
+
alias_accessors :chi => :energy
|
103
105
|
end
|
104
106
|
|
105
|
-
kai_wren = Demon.new('id => '1', 'age' => '1500', 'chi' => '1024', 'teacher' => 'Viss')
|
106
|
-
kai_wren.id
|
107
|
-
kai_wren.age
|
108
|
-
kai_wren.chi
|
109
|
-
kai_wren.
|
107
|
+
kai_wren = Demon.new('id' => '1', 'age' => '1500', 'chi' => '1024', 'teacher' => 'Viss')
|
108
|
+
kai_wren.id # => '1'
|
109
|
+
kai_wren.age # => 1500
|
110
|
+
kai_wren.chi # => #<Chi:0x113af8c @count="1024">
|
111
|
+
kai_wren.energy # => #<Chi:0x113af8c @count="1024">
|
112
|
+
kai_wren.teacher # => 'Viss'
|
110
113
|
|
111
114
|
=== Usage: Logging
|
112
115
|
|
@@ -125,6 +128,8 @@ Wrest RDocs can be found at http://wrest.rubyforge.org
|
|
125
128
|
|
126
129
|
Wrest::Resource is an alternative to Rails' ActiveResource. It targets Rails REST (well, POX, since Rails isn't really RESTful) services and is currently under development. Since no single REST library can provide an object oriented wrapper suitable for _all_ available web services, it follows that Wrest should focus on providing you with the tools to help you roll your own. Wrest::Resource is an example of this - an object oriented wrapper for the kind of REST APIs exposed by Rails applications, that you would otherwise use ActiveResource to consume.
|
127
130
|
|
131
|
+
If you're looking for help doing this on Rails on the server side, take a look at {resource_full}[http://github.com/bguthrie/resource_full], a Rails plugin that makes RESTful Rails a whole order of magnitude easier. resource_full is a stable project and is currently in use in production.
|
132
|
+
|
128
133
|
|
129
134
|
* No more pretending that REST resources are the same as records in a database (yeah, no more freaking ActiveResource::Connection)
|
130
135
|
* Treat put as 'create or update,' not just 'update'
|
@@ -147,19 +152,21 @@ Wrest::Resource is an alternative to Rails' ActiveResource. It targets Rails RES
|
|
147
152
|
== Dependencies
|
148
153
|
|
149
154
|
=== Source
|
155
|
+
|
150
156
|
* gems
|
151
157
|
* json (json-jruby on JRuby)
|
152
158
|
* active_support
|
153
159
|
* ruby-libxml (Recommended, will fall back to REXML if absent; be aware that Wrest uses ActiveSupport::XmlMini, so if you're using Wrest as a plugin in a Rails application, all xml parsing across the application will switch to using libxml if it's available. You're free to change this by hand by using the ActiveSupport::XmlMini.backend= method.)
|
154
160
|
|
155
161
|
=== Build
|
162
|
+
|
156
163
|
* rspec
|
157
164
|
* rcov (unsupported on JRuby)
|
158
165
|
* jeweler
|
159
166
|
|
160
|
-
==
|
167
|
+
== Roadmap
|
161
168
|
|
162
|
-
|
169
|
+
Features that are planned, in progress or already implemented are documented in the {CHANGELOG}[http://github.com/kaiwren/wrest/tree/master/CHANGELOG] starting from version 0.0.8.
|
163
170
|
|
164
171
|
== Licence
|
165
172
|
|
data/Rakefile
CHANGED
@@ -31,7 +31,7 @@ task :default => :spec
|
|
31
31
|
|
32
32
|
desc "Run all specs"
|
33
33
|
Spec::Rake::SpecTask.new(:spec) do |task|
|
34
|
-
task.spec_files = FileList['spec/wrest/**/*_spec.rb']
|
34
|
+
task.spec_files = FileList['spec/unit/wrest/**/*_spec.rb']
|
35
35
|
task.spec_opts = ['--options', 'spec/spec.opts']
|
36
36
|
end
|
37
37
|
|
@@ -56,7 +56,7 @@ begin
|
|
56
56
|
desc "Run all specs in spec directory with RCov"
|
57
57
|
Spec::Rake::SpecTask.new(:rcov) do |t|
|
58
58
|
t.spec_opts = ['--options', "spec/spec.opts"]
|
59
|
-
t.spec_files = FileList["spec/wrest/**/*_spec.rb"]
|
59
|
+
t.spec_files = FileList["spec/unit/wrest/**/*_spec.rb"]
|
60
60
|
t.rcov = true
|
61
61
|
t.rcov_opts = lambda do
|
62
62
|
IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
@@ -80,8 +80,8 @@ begin
|
|
80
80
|
gemspec.rubyforge_project = 'wrest'
|
81
81
|
gemspec.executables = ['wrest', 'jwrest']
|
82
82
|
gemspec.require_path = "lib"
|
83
|
-
gemspec.files.exclude 'spec/wrest/meh_spec.rb'
|
84
|
-
gemspec.test_files.exclude 'spec/wrest/meh_spec.rb'
|
83
|
+
gemspec.files.exclude 'spec/unit/wrest/meh_spec.rb'
|
84
|
+
gemspec.test_files.exclude 'spec/unit/wrest/meh_spec.rb'
|
85
85
|
gemspec.add_dependency('activesupport', '>= 2.3.2')
|
86
86
|
case RUBY_PLATFORM
|
87
87
|
when /java/
|
@@ -94,6 +94,7 @@ begin
|
|
94
94
|
end
|
95
95
|
rescue LoadError
|
96
96
|
puts "Jeweler not available. Install it with: gem install technicalpickles-jeweler -s http://gems.github.com"
|
97
|
+
puts "If you're using JRuby and are having trouble installing jeweler, try installing the git (gem install git) and rubyforge (gem install rubyforge) gems by hand. Also remember to update gems itself (jruby -S gem update --system)."
|
97
98
|
end
|
98
99
|
|
99
100
|
begin
|
data/VERSION.yml
CHANGED
data/examples/delicious.rb
CHANGED
@@ -13,6 +13,10 @@ require 'pp'
|
|
13
13
|
Wrest.logger = Logger.new(STDOUT)
|
14
14
|
Wrest.logger.level = Logger::DEBUG # Set this to Logger::INFO or higher to disable request logging
|
15
15
|
|
16
|
+
# This example demonstrates the usage of GET, POST, PUT and
|
17
|
+
# DELETE over HTTPS. Its also shows how Wrest::Uris can have
|
18
|
+
# paths extended making accessing an API easy as pie.
|
19
|
+
#
|
16
20
|
# API reference: http://delicious.com/help/api
|
17
21
|
class Delicious
|
18
22
|
def initialize(options)
|
@@ -45,14 +49,14 @@ pp account.bookmark(
|
|
45
49
|
:tags => 'ruby hacking'
|
46
50
|
).deserialise
|
47
51
|
|
48
|
-
puts '
|
52
|
+
puts '', '*'*70, ''
|
49
53
|
|
50
54
|
pp account.bookmarks(:tag => 'rails', :dt => '20090712').deserialise
|
51
55
|
|
52
|
-
puts '
|
56
|
+
puts '', '*'*70, ''
|
53
57
|
|
54
58
|
pp recently_saved_uris = account.recent(:tag => 'ruby').deserialise["posts"]["post"].collect{|bookmark| bookmark['href']}
|
55
59
|
|
56
|
-
puts '
|
60
|
+
puts '', '*'*70, ''
|
57
61
|
|
58
62
|
pp account.delete(:url => 'http://blog.sidu.in/search/label/ruby').deserialise
|
@@ -0,0 +1,27 @@
|
|
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
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/wrest")
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
Wrest.logger = Logger.new(STDOUT)
|
14
|
+
Wrest.logger.level = Logger::DEBUG # Set this to Logger::INFO or higher to disable request logging
|
15
|
+
|
16
|
+
# google.com redirects to www.google.com so this is live test for redirection
|
17
|
+
pp 'http://google.com'.to_uri.get.body
|
18
|
+
|
19
|
+
puts '', '*'*70, ''
|
20
|
+
|
21
|
+
# Do a get with auto follow redirects turned off
|
22
|
+
pp 'http://google.com'.to_uri(:follow_redirects => false).get.body
|
23
|
+
|
24
|
+
puts '', '*'*70, ''
|
25
|
+
|
26
|
+
# Do a get with auto follow redirects limited, causing an exception.
|
27
|
+
'http://google.com'.to_uri(:follow_redirects_limit => 1).get.body
|
data/examples/twitter.rb
ADDED
@@ -0,0 +1,78 @@
|
|
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
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/wrest")
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
Wrest.logger = Logger.new(STDOUT)
|
14
|
+
Wrest.logger.level = Logger::DEBUG # Set this to Logger::INFO or higher to disable request logging
|
15
|
+
|
16
|
+
# This example shows a more object oriented approach
|
17
|
+
# to accessing Twitter using Wrest.
|
18
|
+
#
|
19
|
+
# Twitter is your twitter account. Every tweet is wrapped in
|
20
|
+
# an instance of Tweet. Every Tweet has one TwitterUser.
|
21
|
+
|
22
|
+
class Twitter
|
23
|
+
def initialize(options)
|
24
|
+
@uri = "https://twitter.com".to_uri(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# which can be :friends, :user or :public
|
28
|
+
# options[:query] can be things like since, since_id, count, etc.
|
29
|
+
def timeline(which = :friends, options={})
|
30
|
+
@uri["/statuses/#{which}_timeline.json"].get(options).deserialise.collect{|tweet| Tweet.new(tweet)}
|
31
|
+
end
|
32
|
+
|
33
|
+
def post(text)
|
34
|
+
Tweet.new @uri['/statuses/update.json'].post('', {'User-Agent' => "Wrest/#{Wrest::VERSION::STRING}"}, {:status => text}).deserialise
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class TwitterUser
|
39
|
+
# This will turn this class into a wrapper
|
40
|
+
# for the deserialised data from a response.
|
41
|
+
#
|
42
|
+
# All the keys in the hash are exposed as methods.
|
43
|
+
include Wrest::Components::AttributesContainer
|
44
|
+
|
45
|
+
# We'd prefer the user's profile url to be
|
46
|
+
# a Wrest::Uri rather than a String, wouldn't we?
|
47
|
+
#
|
48
|
+
# Remember, using typecasting _will_
|
49
|
+
# slow down instance construction marginally, so turn it on
|
50
|
+
# only if you need it.
|
51
|
+
typecast :url => lambda{|url| url.to_uri}
|
52
|
+
end
|
53
|
+
|
54
|
+
class Tweet
|
55
|
+
include Wrest::Components::AttributesContainer
|
56
|
+
|
57
|
+
typecast :user => lambda{|user| TwitterUser.new(user) }
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
twitter = Twitter.new(:username => 'ponnappa', :password => 'ha!likeImchecking*that*in')
|
62
|
+
|
63
|
+
pp twitter.post("This tweet via the Twitter example in #wrest #{Wrest::VERSION::STRING}, http://github.com/kaiwren/wrest")
|
64
|
+
|
65
|
+
puts '', '*'*70, ''
|
66
|
+
|
67
|
+
tweets = twitter.timeline(:friends, :since_id => 20751449)
|
68
|
+
|
69
|
+
# Print the name of the first user in my timeline.
|
70
|
+
puts tweets.first.user.name
|
71
|
+
|
72
|
+
puts '', '*'*70, ''
|
73
|
+
|
74
|
+
# Just remember that not everyone on Twitter has a
|
75
|
+
# url. On the other hand, some have more than one.
|
76
|
+
# This is just a cute little example that deals with
|
77
|
+
# the simple case of a single url.
|
78
|
+
puts tweets.first.user.url.get.body
|
@@ -7,16 +7,19 @@
|
|
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
|
-
require File.dirname(__FILE__) +
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/wrest")
|
11
|
+
require 'pp'
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
Wrest.logger = Logger.new(STDOUT)
|
14
|
+
Wrest.logger.level = Logger::DEBUG # Set this to Logger::INFO or higher to disable request logging
|
15
|
+
|
16
|
+
|
17
|
+
# This is a basic example demonstrating GET and json deserialisation.
|
18
|
+
|
19
|
+
response = 'http://twitter.com/statuses/public_timeline.json'.to_uri.get
|
20
|
+
|
21
|
+
puts "Code: #{response.code}"
|
22
|
+
puts "Message: #{response.message}"
|
23
|
+
puts "Headers: #{response.headers.inspect}"
|
24
|
+
puts "Body: #{response.body.inspect}"
|
25
|
+
puts "Deserialised: #{response.deserialise.inspect}"
|
@@ -16,7 +16,6 @@ include Wrest
|
|
16
16
|
|
17
17
|
class Realm
|
18
18
|
include Components::AttributesContainer
|
19
|
-
include Components::AttributesContainer::Typecaster
|
20
19
|
|
21
20
|
typecast :t => lambda{|type|
|
22
21
|
case type
|
@@ -40,6 +39,11 @@ class Realm
|
|
40
39
|
when '4' then 'Max'
|
41
40
|
end
|
42
41
|
}
|
42
|
+
|
43
|
+
alias_accessors :t => :type,
|
44
|
+
:s => :status,
|
45
|
+
:l => :load,
|
46
|
+
:n => :name
|
43
47
|
|
44
48
|
def available?
|
45
49
|
self.s == 'Available'
|
@@ -48,10 +52,10 @@ end
|
|
48
52
|
|
49
53
|
realms = "http://www.worldofwarcraft.com/realmstatus/status.xml".to_uri.get.deserialise['page']['rs']['r'].collect{|data| Realm.new(data)}
|
50
54
|
|
51
|
-
puts "Status of Nagrand: #{realms.find{|realm| realm.
|
55
|
+
puts "Status of Nagrand: #{realms.find{|realm| realm.name == 'Nagrand'}.status}"
|
52
56
|
puts
|
53
57
|
puts "All Available Realms:"
|
54
58
|
puts
|
55
59
|
puts "Realm\tLoad\tType"
|
56
60
|
puts "-----------"
|
57
|
-
realms.select(&:available?).each{|realm| puts "#{realm.
|
61
|
+
realms.select(&:available?).each{|realm| puts "#{realm.name}\t#{realm.load}\t#{realm.type}" }
|
@@ -0,0 +1,66 @@
|
|
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
|
11
|
+
module Components::AttributesContainer
|
12
|
+
module AliasAccessors
|
13
|
+
def self.included(klass) #:nodoc:
|
14
|
+
klass.extend AliasAccessors::ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.build_aliased_attribute_getter(attribute_name, alias_name) #:nodoc:
|
18
|
+
"def #{alias_name};#{attribute_name};end;"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build_aliased_attribute_setter(attribute_name, alias_name) #:nodoc:
|
22
|
+
"def #{alias_name}=(value);self.#{attribute_name}=value;end;"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build_aliased_attribute_queryer(attribute_name, alias_name) #:nodoc:
|
26
|
+
"def #{alias_name}?;self.#{attribute_name}?;end;"
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
# Creates an alias set of getter, setter and query methods for
|
31
|
+
# attributes that aren't quite the way you'd like them to be; this
|
32
|
+
# is especially useful when you have no control over the source web
|
33
|
+
# sevice/resource.
|
34
|
+
#
|
35
|
+
# For example, lets say that a particular resource exposes a
|
36
|
+
# User's age as 'a' and sex as s. Typically, you'd have to access it as
|
37
|
+
# user.a and user.s whereas you's like to access it as user.age and user.sex.
|
38
|
+
# This is where alias_accessors comes into the picture. Your User class would
|
39
|
+
# look somethig like this:
|
40
|
+
#
|
41
|
+
# class User
|
42
|
+
# include Wrest::Components::AttributesContainer
|
43
|
+
#
|
44
|
+
# alias_accessors :a => :age,
|
45
|
+
# :s => :sex
|
46
|
+
# end
|
47
|
+
# This would create the methods user.age, user.age= and user.age? which delegate
|
48
|
+
# to user.a, user.a= and user.a? respectively. Ditto for s to sex.
|
49
|
+
#
|
50
|
+
# See examples/wow_realm_status.rb for a working example.
|
51
|
+
#
|
52
|
+
# WARNING: If you try to create an alias with the same name as the attribute,
|
53
|
+
# and then use it, you _will_ cause an infinite loop.
|
54
|
+
def alias_accessors(alias_map)
|
55
|
+
alias_map.each do |attribute_name, alias_name|
|
56
|
+
self.class_eval(
|
57
|
+
AliasAccessors.build_aliased_attribute_getter(attribute_name, alias_name) +
|
58
|
+
AliasAccessors.build_aliased_attribute_setter(attribute_name, alias_name) +
|
59
|
+
AliasAccessors.build_aliased_attribute_queryer(attribute_name, alias_name)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -26,19 +26,61 @@ module Wrest
|
|
26
26
|
klass.class_eval{ include Typecaster::InstanceMethods }
|
27
27
|
klass.alias_method_chain :initialize, :typecasting
|
28
28
|
end
|
29
|
+
|
30
|
+
module Helpers
|
31
|
+
def as_base64Binary
|
32
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['base64Binary']
|
33
|
+
end
|
34
|
+
|
35
|
+
def as_boolean
|
36
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['boolean']
|
37
|
+
end
|
38
|
+
|
39
|
+
def as_decimal
|
40
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['decimal']
|
41
|
+
end
|
42
|
+
|
43
|
+
def as_date
|
44
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['date']
|
45
|
+
end
|
46
|
+
|
47
|
+
def as_datetime
|
48
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['datetime']
|
49
|
+
end
|
50
|
+
|
51
|
+
def as_float
|
52
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['float']
|
53
|
+
end
|
54
|
+
|
55
|
+
def as_integer
|
56
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['integer']
|
57
|
+
end
|
29
58
|
|
59
|
+
def as_symbol
|
60
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['symbol']
|
61
|
+
end
|
62
|
+
|
63
|
+
def as_yaml
|
64
|
+
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['yaml']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
30
68
|
module ClassMethods
|
31
69
|
# Accepts a set of attribute-name/lambda pairs which are used
|
32
70
|
# to typecast string values injected through the constructor.
|
33
71
|
# Typically needed when populating an +AttributesContainer+
|
34
72
|
# directly from request params. Typecasting kicks in for
|
35
|
-
# a given value _only_ if it is a
|
73
|
+
# a given value _only_ if it is a String, Hash or Array, the
|
74
|
+
# three classes that deserilisation can produce.
|
36
75
|
#
|
37
76
|
# Typecast information is inherited by subclasses; however be
|
38
77
|
# aware that explicitly invoking +typecast+ in a subclass will
|
39
78
|
# discard inherited typecast information leaving only the casts
|
40
79
|
# defined in the subclass.
|
41
80
|
#
|
81
|
+
# Note that this _will_ increase the time needed to initialize
|
82
|
+
# instances.
|
83
|
+
#
|
42
84
|
# Common typecasts such as integer, float, datetime etc. are
|
43
85
|
# available through predefined helpers. See TypecastHelpers
|
44
86
|
# for a full list.
|
@@ -69,42 +111,6 @@ module Wrest
|
|
69
111
|
{}
|
70
112
|
end
|
71
113
|
end
|
72
|
-
|
73
|
-
def as_base64Binary
|
74
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['base64Binary']
|
75
|
-
end
|
76
|
-
|
77
|
-
def as_boolean
|
78
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['boolean']
|
79
|
-
end
|
80
|
-
|
81
|
-
def as_decimal
|
82
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['decimal']
|
83
|
-
end
|
84
|
-
|
85
|
-
def as_date
|
86
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['date']
|
87
|
-
end
|
88
|
-
|
89
|
-
def as_datetime
|
90
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['datetime']
|
91
|
-
end
|
92
|
-
|
93
|
-
def as_float
|
94
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['float']
|
95
|
-
end
|
96
|
-
|
97
|
-
def as_integer
|
98
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['integer']
|
99
|
-
end
|
100
|
-
|
101
|
-
def as_symbol
|
102
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['symbol']
|
103
|
-
end
|
104
|
-
|
105
|
-
def as_yaml
|
106
|
-
ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['yaml']
|
107
|
-
end
|
108
114
|
end
|
109
115
|
|
110
116
|
module InstanceMethods # :nodoc:
|
@@ -112,7 +118,7 @@ module Wrest
|
|
112
118
|
initialize_without_typecasting(attributes)
|
113
119
|
self.class.typecast_map.each do |key, typecaster|
|
114
120
|
value = @attributes[key]
|
115
|
-
@attributes[key] = typecaster.call(value) if value.is_a?(String)
|
121
|
+
@attributes[key] = typecaster.call(value) if (value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array))
|
116
122
|
end
|
117
123
|
end
|
118
124
|
end
|
@@ -13,6 +13,7 @@ module Wrest
|
|
13
13
|
end
|
14
14
|
|
15
15
|
require "#{WREST_ROOT}/wrest/components/attributes_container/typecaster"
|
16
|
+
require "#{WREST_ROOT}/wrest/components/attributes_container/alias_accessors"
|
16
17
|
|
17
18
|
module Wrest::Components
|
18
19
|
|
@@ -57,7 +58,11 @@ module Wrest::Components
|
|
57
58
|
module AttributesContainer
|
58
59
|
def self.included(klass) #:nodoc:
|
59
60
|
klass.extend AttributesContainer::ClassMethods
|
60
|
-
klass.
|
61
|
+
klass.extend AttributesContainer::Typecaster::Helpers
|
62
|
+
klass.class_eval do
|
63
|
+
include AttributesContainer::InstanceMethods
|
64
|
+
include AttributesContainer::AliasAccessors
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
68
|
def self.build_attribute_getter(attribute_name) #:nodoc:
|
@@ -74,9 +79,9 @@ module Wrest::Components
|
|
74
79
|
|
75
80
|
module ClassMethods
|
76
81
|
# This macro explicitly creates getter, setter and query methods on
|
77
|
-
#
|
78
|
-
# This can be used when attribute names clash with method names;
|
79
|
-
# an example would be Rails REST
|
82
|
+
# an AttributesContainer, overriding any exisiting methods with the same names.
|
83
|
+
# This can be used when attribute names clash with existing method names;
|
84
|
+
# an example would be Rails REST resources which frequently make use
|
80
85
|
# an attribute named <tt>id</tt> which clashes with Object#id. Also,
|
81
86
|
# this can be used as a performance optimisation if the incoming
|
82
87
|
# attributes are known beforehand.
|
@@ -89,6 +94,19 @@ module Wrest::Components
|
|
89
94
|
)
|
90
95
|
end
|
91
96
|
end
|
97
|
+
|
98
|
+
# This is a convenience macro which includes
|
99
|
+
# Wrest::Components::AttributesContainer::Typecaster into
|
100
|
+
# the class (effectively overwriting this method) before delegating to
|
101
|
+
# the actual typecast method that is a part of that module.
|
102
|
+
# This saves us the effort of explicitly doing the include. Easy to use API is king.
|
103
|
+
#
|
104
|
+
# Remember that using typecast carries a performance penalty.
|
105
|
+
# See Wrest::Components::AttributesContainer::Typecaster for the actual docs.
|
106
|
+
def typecast(cast_map)
|
107
|
+
self.class_eval{ include Wrest::Components::AttributesContainer::Typecaster }
|
108
|
+
self.typecast cast_map
|
109
|
+
end
|
92
110
|
end
|
93
111
|
|
94
112
|
module InstanceMethods
|
@@ -119,7 +137,7 @@ module Wrest::Components
|
|
119
137
|
def method_missing(method_sym, *arguments)
|
120
138
|
method_name = method_sym.to_s
|
121
139
|
attribute_name = method_name.gsub(/(\?$)|(=$)/, '')
|
122
|
-
if @attributes.include?(attribute_name.to_sym) || method_name.last == '='
|
140
|
+
if @attributes.include?(attribute_name.to_sym) || method_name.last == '=' || method_name.last == '?'
|
123
141
|
case method_name.last
|
124
142
|
when '='
|
125
143
|
self.instance_eval AttributesContainer.build_attribute_setter(attribute_name)
|
@@ -17,7 +17,7 @@ module Wrest
|
|
17
17
|
# the content type
|
18
18
|
def self.lookup(content_type)
|
19
19
|
translator = CONTENT_TYPES[content_type]
|
20
|
-
translator || (raise Wrest::Exceptions::
|
20
|
+
translator || (raise Wrest::Exceptions::UnsupportedContentType.new("Unsupported content type #{content_type}"))
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/lib/wrest/exceptions.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
module Wrest
|
2
2
|
module Exceptions #:nodoc:
|
3
|
+
# Raised when a base method that should be overriden
|
4
|
+
# is invoked on a subclass that has not implemented it.
|
5
|
+
class MethodNotOverridden < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Raised when a translator for an unregisterd response content type
|
9
|
+
# is requested. See Translators.
|
10
|
+
class UnsupportedContentType < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
# Raised when a request auto redirects more times than are allowed
|
14
|
+
# by its follow_redirects_limit. See Wrest::Http::Redirection.
|
15
|
+
class AutoRedirectLimitExceeded < StandardError
|
16
|
+
end
|
3
17
|
end
|
4
18
|
end
|
5
|
-
require "#{WREST_ROOT}/wrest/exceptions/unsupported_content_type_exception"
|
6
|
-
require "#{WREST_ROOT}/wrest/exceptions/method_not_overridden_exception"
|
data/lib/wrest/http/get.rb
CHANGED
@@ -10,6 +10,8 @@
|
|
10
10
|
module Wrest::Http
|
11
11
|
class Get < Request
|
12
12
|
def initialize(wrest_uri, parameters = {}, headers = {}, options = {})
|
13
|
+
follow_redirects = options[:follow_redirects]
|
14
|
+
options[:follow_redirects] = (follow_redirects == nil ? true : follow_redirects)
|
13
15
|
super(
|
14
16
|
wrest_uri,
|
15
17
|
Net::HTTP::Get,
|