rc-rest 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright 2006 Eric Hodel, The Robot Co-op. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
data/Manifest.txt ADDED
@@ -0,0 +1,7 @@
1
+ LICENSE
2
+ Manifest.txt
3
+ README
4
+ Rakefile
5
+ lib/rc_rest.rb
6
+ lib/rc_rest/uri_stub.rb
7
+ test/test_rc_rest.rb
data/README ADDED
@@ -0,0 +1,27 @@
1
+ = rc-rest
2
+
3
+ Rubyforge Project:
4
+
5
+ http://rubyforge.org/projects/rctools/
6
+
7
+ Documentation:
8
+
9
+ http://dev.robotcoop.com/Libraries/rc-rest/
10
+
11
+ == About
12
+
13
+ This is an abstract class for REST web service APIs. By itself it isn't at all
14
+ useful.
15
+
16
+ == Installing rc-rest
17
+
18
+ Just install the gem:
19
+
20
+ $ sudo gem install rc-rest
21
+
22
+ == Using rc-rest
23
+
24
+ rc-rest is used by gems such as yahoo-search, google-geocode and geocoder-us.
25
+ If you'd like to write bindings a web service using rc-rest see RCRest, its
26
+ tests or the above-mentioned gems for examples.
27
+
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+
7
+ $VERBOSE = nil
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'rc-rest'
11
+ s.version = '1.0.0'
12
+ s.summary = 'Robot Co-op REST web services base class'
13
+ s.description = 'This library makes it easy to implement REST-like web services APIs.'
14
+ s.author = 'Eric Hodel'
15
+ s.email = 'eric@robotcoop.com'
16
+
17
+ s.has_rdoc = true
18
+ s.files = File.read('Manifest.txt').split($/)
19
+ s.require_path = 'lib'
20
+ end
21
+
22
+ desc 'Run tests'
23
+ task :default => [ :test ]
24
+
25
+ Rake::TestTask.new('test') do |t|
26
+ t.libs << 'test'
27
+ t.pattern = 'test/test_*.rb'
28
+ t.verbose = true
29
+ end
30
+
31
+ desc 'Update Manifest.txt'
32
+ task :update_manifest do
33
+ sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
34
+ end
35
+
36
+ desc 'Generate RDoc'
37
+ Rake::RDocTask.new :rdoc do |rd|
38
+ rd.rdoc_dir = 'doc'
39
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
40
+ rd.main = 'README'
41
+ rd.options << '-d' if `which dot` =~ /\/dot/
42
+ rd.options << '-t Robot Co-op REST Web Services'
43
+ end
44
+
45
+ desc 'Generate RDoc for dev.robotcoop.com'
46
+ Rake::RDocTask.new :dev_rdoc do |rd|
47
+ rd.rdoc_dir = '../../../www/trunk/dev/html/Libraries/rc-rest'
48
+ rd.rdoc_files.add 'lib', 'README', 'LICENSE'
49
+ rd.main = 'README'
50
+ rd.options << '-d' if `which dot` =~ /\/dot/
51
+ rd.options << '-t Robot Co-op REST Web Services'
52
+ end
53
+
54
+ desc 'Build Gem'
55
+ Rake::GemPackageTask.new spec do |pkg|
56
+ pkg.need_tar = true
57
+ end
58
+
59
+ desc 'Clean up'
60
+ task :clean => [ :clobber_rdoc, :clobber_package ]
61
+
62
+ desc 'Clean up'
63
+ task :clobber => [ :clean ]
64
+
65
+ # vim: syntax=Ruby
66
+
data/lib/rc_rest.rb ADDED
@@ -0,0 +1,115 @@
1
+ require 'open-uri'
2
+ require 'rexml/document'
3
+
4
+ ##
5
+ # Abstract class for implementing REST APIs.
6
+ #
7
+ # === Example
8
+ #
9
+ # The following methods must be implemented in sublcasses:
10
+ #
11
+ # +initialize+:: Sets @url to the service enpoint.
12
+ # +check_error+:: Checks for errors in the server response.
13
+ # +parse_response+:: Extracts information from the server response.
14
+ #
15
+ # If you have extra URL paramaters (application id, output type) or need to
16
+ # perform URL customization, override +make_url+.
17
+ #
18
+ # class FakeService < RCRest
19
+ #
20
+ # class Error < RCRest::Error; end
21
+ #
22
+ # def initialize(appid)
23
+ # @appid = appid
24
+ # @url = URI.parse 'http://example.com/test'
25
+ # end
26
+ #
27
+ # def check_error(xml)
28
+ # raise Error, xml.elements['error'].text if xml.elements['error']
29
+ # end
30
+ #
31
+ # def make_url(params)
32
+ # params[:appid] = @appid
33
+ # super params
34
+ # end
35
+ #
36
+ # def parse_response(xml)
37
+ # return xml
38
+ # end
39
+ #
40
+ # def test(query)
41
+ # get :q => query
42
+ # end
43
+ #
44
+ # end
45
+
46
+ class RCRest
47
+
48
+ ##
49
+ # Error class.
50
+
51
+ class Error < RuntimeError; end
52
+
53
+ ##
54
+ # Web services initializer.
55
+ #
56
+ # Concrete web services implementations must set the +url+ instance
57
+ # variable which must be a URI.
58
+
59
+ def initialize
60
+ raise NotImplementedError
61
+ end
62
+
63
+ ##
64
+ # Must extract and raise an error from +xml+, an REXML::Document, if any.
65
+ # Must returns if no error could be found.
66
+
67
+ def check_error(xml)
68
+ raise NotImplementedError
69
+ end
70
+
71
+ ##
72
+ # Performs a GET request with +params+. Calls the parse_response method on
73
+ # the concrete class with an REXML::Document instance and returns its
74
+ # result.
75
+
76
+ def get(params = {})
77
+ url = make_url params
78
+
79
+ url.open do |xml|
80
+ res = REXML::Document.new xml.read
81
+
82
+ check_error res
83
+
84
+ return parse_response(res)
85
+ end
86
+ rescue OpenURI::HTTPError => e
87
+ xml = REXML::Document.new e.io.read
88
+ check_error xml
89
+ raise
90
+ end
91
+
92
+ ##
93
+ # Creates a URI from the Hash +params+. Override this then call super if
94
+ # you need to add extra params like an application id or output type.
95
+
96
+ def make_url(params)
97
+ escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
98
+ "#{URI.escape k.to_s}=#{URI.escape v.to_s}"
99
+ end
100
+
101
+ url = @url.dup
102
+ url.query = escaped_params.join '&'
103
+ return url
104
+ end
105
+
106
+ ##
107
+ # Must parse results from +xml+, an REXML::Document, into something sensible
108
+ # for the API.
109
+
110
+ def parse_response(xml)
111
+ raise NotImplementedError
112
+ end
113
+
114
+ end
115
+
@@ -0,0 +1,51 @@
1
+ require 'open-uri'
2
+
3
+ module URI # :nodoc:
4
+ end
5
+
6
+ ##
7
+ # This stub overrides OpenURI's open method to allow programs that use OpenURI
8
+ # to be easily tested.
9
+ #
10
+ # == Usage
11
+ #
12
+ # require 'rc_rest/uri_stub'
13
+ #
14
+ # class TestMyClass < Test::Unit::TestCase
15
+ #
16
+ # def setup
17
+ # URI::HTTP.responses = []
18
+ # URI::HTTP.uris = []
19
+ #
20
+ # @obj = MyClass.new
21
+ # end
22
+ #
23
+ # def test_my_method
24
+ # URI::HTTP.responses << 'some text open would ordinarily return'
25
+ #
26
+ # result = @obj.my_method
27
+ #
28
+ # assert_equal :something_meaninfgul, result
29
+ #
30
+ # assert_equal true, URI::HTTP.responses.empty?
31
+ # assert_equal 1, URI::HTTP.uris.length
32
+ # assert_equal 'http://example.com/path', URI::HTTP.uris.first
33
+ # end
34
+ #
35
+ # end
36
+
37
+ class URI::HTTP # :nodoc:
38
+
39
+ class << self
40
+ attr_accessor :responses, :uris
41
+ end
42
+
43
+ alias original_open open
44
+
45
+ def open
46
+ self.class.uris << self.to_s
47
+ yield StringIO.new(self.class.responses.shift)
48
+ end
49
+
50
+ end
51
+
@@ -0,0 +1,97 @@
1
+ require 'test/unit'
2
+ require 'rc_rest/uri_stub'
3
+ require 'rc_rest'
4
+
5
+ class FakeService < RCRest
6
+
7
+ class Error < RCRest::Error; end
8
+
9
+ def initialize
10
+ @url = URI.parse 'http://example.com/test'
11
+ end
12
+
13
+ def check_error(xml)
14
+ raise Error, xml.elements['error'].text if xml.elements['error']
15
+ end
16
+
17
+ def test
18
+ get
19
+ end
20
+
21
+ def parse_response(xml)
22
+ return xml
23
+ end
24
+
25
+ end
26
+
27
+ class TestFakeService < Test::Unit::TestCase
28
+
29
+ def setup
30
+ URI::HTTP.responses = []
31
+ URI::HTTP.uris = []
32
+
33
+ @fs = FakeService.new
34
+ end
35
+
36
+ def test_check_error
37
+ xml = REXML::Document.new '<error>you broked it</error>'
38
+ @fs.check_error xml
39
+
40
+ rescue FakeService::Error => e
41
+ assert_equal 'you broked it', e.message
42
+
43
+ else
44
+ flunk 'expected an error'
45
+ end
46
+
47
+ def test_get
48
+ xml = '<result>stuff</result>'
49
+ URI::HTTP.responses << xml
50
+
51
+ result = @fs.test
52
+
53
+ assert_equal xml, result.to_s
54
+ end
55
+
56
+ def test_get_error
57
+ def @fs.make_url(*args) # HACK extend uri_stub with error raising ability
58
+ u = Object.new
59
+ def u.open
60
+ xml = '<error>you did the bad thing</error>'
61
+ raise OpenURI::HTTPError.new('400 Bad Request', StringIO.new(xml))
62
+ end
63
+ return u
64
+ end
65
+
66
+ assert_raise FakeService::Error do @fs.test end
67
+ end
68
+
69
+ end
70
+
71
+ class TestRCRest < Test::Unit::TestCase
72
+
73
+ def test_initialize
74
+ assert_raise NotImplementedError do RCRest.new end
75
+ end
76
+
77
+ def test_check_error
78
+ r = RCRest.allocate
79
+ assert_raise NotImplementedError do r.check_error nil end
80
+ end
81
+
82
+ def test_make_url
83
+ r = RCRest.allocate
84
+ r.instance_variable_set :@url, URI.parse('http://example.com/')
85
+
86
+ url = r.make_url :a => 'b c', :x => 'y z'
87
+
88
+ assert_equal 'http://example.com/?a=b%20c&x=y%20z', url.to_s
89
+ end
90
+
91
+ def test_parse_response
92
+ r = RCRest.allocate
93
+ assert_raise NotImplementedError do r.parse_response nil end
94
+ end
95
+
96
+ end
97
+
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.99
3
+ specification_version: 1
4
+ name: rc-rest
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2006-06-15 00:00:00 -07:00
8
+ summary: Robot Co-op REST web services base class
9
+ require_paths:
10
+ - lib
11
+ email: eric@robotcoop.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description: This library makes it easy to implement REST-like web services APIs.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Eric Hodel
31
+ files:
32
+ - LICENSE
33
+ - Manifest.txt
34
+ - README
35
+ - Rakefile
36
+ - lib/rc_rest.rb
37
+ - lib/rc_rest/uri_stub.rb
38
+ - test/test_rc_rest.rb
39
+ test_files: []
40
+
41
+ rdoc_options: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ executables: []
46
+
47
+ extensions: []
48
+
49
+ requirements: []
50
+
51
+ dependencies: []
52
+