rc-rest 1.0.0 → 2.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.
@@ -0,0 +1,10 @@
1
+ = 2.0.0
2
+
3
+ * Added +method+ parameter to RCRest#make_url to add path components
4
+ to a generic endpoint.
5
+ * Added RCRest#post.
6
+
7
+ = 1.0.0
8
+
9
+ * Birthday!
10
+
File without changes
@@ -1,7 +1,9 @@
1
- LICENSE
1
+ History.txt
2
+ LICENSE.txt
2
3
  Manifest.txt
3
- README
4
+ README.txt
4
5
  Rakefile
5
6
  lib/rc_rest.rb
7
+ lib/rc_rest/net_http_stub.rb
6
8
  lib/rc_rest/uri_stub.rb
7
9
  test/test_rc_rest.rb
@@ -10,8 +10,7 @@ http://dev.robotcoop.com/Libraries/rc-rest/
10
10
 
11
11
  == About
12
12
 
13
- This is an abstract class for REST web service APIs. By itself it isn't at all
14
- useful.
13
+ This is an abstract class for creating wrappers for REST web service APIs.
15
14
 
16
15
  == Installing rc-rest
17
16
 
@@ -25,3 +24,9 @@ rc-rest is used by gems such as yahoo-search, google-geocode and geocoder-us.
25
24
  If you'd like to write bindings a web service using rc-rest see RCRest, its
26
25
  tests or the above-mentioned gems for examples.
27
26
 
27
+ == Upgrading from 1.x
28
+
29
+ RCRest#get and RCRest#make_url now accept a method argument as the
30
+ first parameter. To use 2.x, pass the last component of the path to
31
+ RCRest#get or RCRest#make_url.
32
+
data/Rakefile CHANGED
@@ -1,66 +1,25 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'rake/testtask'
4
- require 'rake/rdoctask'
5
- require 'rake/gempackagetask'
1
+ require 'hoe'
2
+ require './lib/rc_rest'
6
3
 
7
- $VERBOSE = nil
4
+ DEV_DOC_PATH = 'Libraries/rc_rest'
8
5
 
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'
6
+ hoe = Hoe.new 'rc-rest', RCRest::VERSION do |p|
7
+ p.summary = 'Robot Co-op REST web services base class'
8
+ p.description = 'This library makes it easy to implement REST-like web services APIs.'
9
+ p.author = 'Eric Hodel'
10
+ p.email = 'eric@robotcoop.com'
11
+ p.url = "http://dev.robotcoop.com/#{DEV_DOC_PATH}"
12
+ p.rubyforge_name = 'rctools'
16
13
 
17
- s.has_rdoc = true
18
- s.files = File.read('Manifest.txt').split($/)
19
- s.require_path = 'lib'
14
+ p.changes = File.read('History.txt').scan(/\A(=.*?)^=/m).first.first
20
15
  end
21
16
 
22
- desc 'Run tests'
23
- task :default => [ :test ]
17
+ SPEC = hoe.spec
24
18
 
25
- Rake::TestTask.new('test') do |t|
26
- t.libs << 'test'
27
- t.pattern = 'test/test_*.rb'
28
- t.verbose = true
19
+ begin
20
+ require '../tasks'
21
+ rescue RuntimeError
29
22
  end
30
23
 
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
24
  # vim: syntax=Ruby
66
25
 
@@ -1,3 +1,4 @@
1
+ require 'net/http'
1
2
  require 'open-uri'
2
3
  require 'rexml/document'
3
4
 
@@ -21,16 +22,16 @@ require 'rexml/document'
21
22
  #
22
23
  # def initialize(appid)
23
24
  # @appid = appid
24
- # @url = URI.parse 'http://example.com/test'
25
+ # @url = URI.parse 'http://example.com/api/'
25
26
  # end
26
27
  #
27
28
  # def check_error(xml)
28
29
  # raise Error, xml.elements['error'].text if xml.elements['error']
29
30
  # end
30
31
  #
31
- # def make_url(params)
32
+ # def make_url(method, params)
32
33
  # params[:appid] = @appid
33
- # super params
34
+ # super method, params
34
35
  # end
35
36
  #
36
37
  # def parse_response(xml)
@@ -38,7 +39,7 @@ require 'rexml/document'
38
39
  # end
39
40
  #
40
41
  # def test(query)
41
- # get :q => query
42
+ # get :test, :q => query
42
43
  # end
43
44
  #
44
45
  # end
@@ -46,7 +47,12 @@ require 'rexml/document'
46
47
  class RCRest
47
48
 
48
49
  ##
49
- # Error class.
50
+ # You are using this version of RCRest
51
+
52
+ VERSION = '2.0.0'
53
+
54
+ ##
55
+ # Abstract Error class.
50
56
 
51
57
  class Error < RuntimeError; end
52
58
 
@@ -57,24 +63,24 @@ class RCRest
57
63
  # variable which must be a URI.
58
64
 
59
65
  def initialize
60
- raise NotImplementedError
66
+ raise NotImplementedError, 'need to implement #intialize and set @url'
61
67
  end
62
68
 
63
69
  ##
64
70
  # Must extract and raise an error from +xml+, an REXML::Document, if any.
65
- # Must returns if no error could be found.
71
+ # Must return if no error could be found.
66
72
 
67
73
  def check_error(xml)
68
74
  raise NotImplementedError
69
75
  end
70
76
 
71
77
  ##
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.
78
+ # Performs a GET request for method +method+ with +params+. Calls
79
+ # #parse_response on the concrete class with an REXML::Document instance and
80
+ # returns its result.
75
81
 
76
- def get(params = {})
77
- url = make_url params
82
+ def get(method, params = {})
83
+ url = make_url method, params
78
84
 
79
85
  url.open do |xml|
80
86
  res = REXML::Document.new xml.read
@@ -90,15 +96,53 @@ class RCRest
90
96
  end
91
97
 
92
98
  ##
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.
99
+ # Creates a URI for method +method+ and a Hash of parameters +params+.
100
+ # Override this then call super if you need to add extra params like an
101
+ # application id, output type, etc.
102
+ #
103
+ # If the value of a parameter responds to #each, make_url creates a
104
+ # key-value pair per value in the param.
105
+ #
106
+ # Examples:
107
+ #
108
+ # If the URL base is:
109
+ #
110
+ # http://example.com/api/
111
+ #
112
+ # then:
113
+ #
114
+ # make_url nil, :a => '1 2', :b => [4, 3]
115
+ #
116
+ # creates the URL:
117
+ #
118
+ # http://example.com/api/?a=1%202&b=3&b=4
119
+ #
120
+ # and
121
+ #
122
+ # make_url :method, :a => '1'
123
+ #
124
+ # creates the URL:
125
+ #
126
+ # http://example.com/api/method?a=1
95
127
 
96
- def make_url(params)
97
- escaped_params = params.sort_by { |k,v| k.to_s }.map do |k,v|
128
+ def make_url(method, params = nil)
129
+ expanded_params = []
130
+
131
+ params.each do |k,v|
132
+ if v.respond_to? :each then
133
+ v.each { |v| expanded_params << [k, v] }
134
+ else
135
+ expanded_params << [k, v]
136
+ end
137
+ end
138
+
139
+ sorted_params = expanded_params.sort_by { |k,v| [k.to_s, v.to_s] }
140
+
141
+ escaped_params = sorted_params.map do |k,v|
98
142
  "#{URI.escape k.to_s}=#{URI.escape v.to_s}"
99
143
  end
100
144
 
101
- url = @url.dup
145
+ url = @url + "./#{method}"
102
146
  url.query = escaped_params.join '&'
103
147
  return url
104
148
  end
@@ -111,5 +155,34 @@ class RCRest
111
155
  raise NotImplementedError
112
156
  end
113
157
 
158
+ ##
159
+ # Performs a POST request for method +method+ with +params+. Calls
160
+ # #parse_response on the concrete class with an REXML::Document instance and
161
+ # returns its result.
162
+
163
+ def post(method, params = {})
164
+ url = make_url method, params
165
+ query = url.query
166
+ url.query = nil
167
+
168
+ req = Net::HTTP::Post.new url.path
169
+ req.body = query
170
+ req.content_type = 'application/x-www-form-urlencoded'
171
+
172
+ res = Net::HTTP.start url.host, url.port do |http|
173
+ http.request req
174
+ end
175
+
176
+ xml = REXML::Document.new res.body
177
+
178
+ check_error xml
179
+
180
+ return parse_response(xml)
181
+ rescue Net::HTTPError => e
182
+ xml = REXML::Document.new e.res.body
183
+ check_error xml
184
+ raise
185
+ end
186
+
114
187
  end
115
188
 
@@ -0,0 +1,60 @@
1
+ require 'net/http'
2
+
3
+ class Net::HTTPResponse
4
+
5
+ ##
6
+ # Setter for body content
7
+
8
+ attr_accessor :body
9
+
10
+ end
11
+
12
+ class Net::HTTP
13
+
14
+ @params = nil
15
+ @paths = nil
16
+ @responses = nil
17
+
18
+ class << self
19
+
20
+ ##
21
+ # Records submitted POST params
22
+
23
+ attr_accessor :params
24
+
25
+ ##
26
+ # Records POST paths
27
+
28
+ attr_accessor :paths
29
+
30
+ ##
31
+ # Holds POST body responses
32
+
33
+ attr_accessor :responses
34
+
35
+ remove_method :start
36
+
37
+ end
38
+
39
+ ##
40
+ # Override Net::HTTP::start to not connect
41
+
42
+ def self.start(host, port)
43
+ yield Net::HTTP.new(host)
44
+ end
45
+
46
+ remove_method :request
47
+
48
+ ##
49
+ # Override Net::HTTP#request to fake its results
50
+
51
+ def request(req)
52
+ self.class.paths << req.path
53
+ self.class.params << req.body
54
+ res = Net::HTTPResponse.new '1.0', 200, 'OK'
55
+ res.body = self.class.responses.shift
56
+ res
57
+ end
58
+
59
+ end
60
+
@@ -1,5 +1,8 @@
1
1
  require 'test/unit'
2
+ require 'rubygems'
3
+ require 'test/zentest_assertions'
2
4
  require 'rc_rest/uri_stub'
5
+ require 'rc_rest/net_http_stub'
3
6
  require 'rc_rest'
4
7
 
5
8
  class FakeService < RCRest
@@ -14,8 +17,12 @@ class FakeService < RCRest
14
17
  raise Error, xml.elements['error'].text if xml.elements['error']
15
18
  end
16
19
 
17
- def test
18
- get
20
+ def do_get
21
+ get :method
22
+ end
23
+
24
+ def do_post
25
+ post :method, :param => 'value'
19
26
  end
20
27
 
21
28
  def parse_response(xml)
@@ -30,6 +37,10 @@ class TestFakeService < Test::Unit::TestCase
30
37
  URI::HTTP.responses = []
31
38
  URI::HTTP.uris = []
32
39
 
40
+ Net::HTTP.params = []
41
+ Net::HTTP.paths = []
42
+ Net::HTTP.responses = []
43
+
33
44
  @fs = FakeService.new
34
45
  end
35
46
 
@@ -44,16 +55,17 @@ class TestFakeService < Test::Unit::TestCase
44
55
  flunk 'expected an error'
45
56
  end
46
57
 
47
- def test_get
58
+ def test_do_get
48
59
  xml = '<result>stuff</result>'
49
60
  URI::HTTP.responses << xml
50
61
 
51
- result = @fs.test
62
+ result = @fs.do_get
52
63
 
53
64
  assert_equal xml, result.to_s
65
+ assert_equal 'http://example.com/method?', URI::HTTP.uris.first
54
66
  end
55
67
 
56
- def test_get_error
68
+ def test_do_get_error
57
69
  def @fs.make_url(*args) # HACK extend uri_stub with error raising ability
58
70
  u = Object.new
59
71
  def u.open
@@ -63,7 +75,23 @@ class TestFakeService < Test::Unit::TestCase
63
75
  return u
64
76
  end
65
77
 
66
- assert_raise FakeService::Error do @fs.test end
78
+ assert_raise FakeService::Error do @fs.do_get end
79
+ end
80
+
81
+ def test_do_post
82
+ xml = '<result>stuff</result>'
83
+ Net::HTTP.responses << xml
84
+
85
+ result = @fs.do_post
86
+
87
+ assert_equal xml, result.to_s
88
+
89
+ assert_equal 1, Net::HTTP.params.length
90
+ assert_equal 1, Net::HTTP.paths.length
91
+ assert_empty Net::HTTP.responses
92
+
93
+ assert_equal 'param=value', Net::HTTP.params.first
94
+ assert_equal '/method', Net::HTTP.paths.first
67
95
  end
68
96
 
69
97
  end
@@ -71,7 +99,11 @@ end
71
99
  class TestRCRest < Test::Unit::TestCase
72
100
 
73
101
  def test_initialize
74
- assert_raise NotImplementedError do RCRest.new end
102
+ RCRest.new
103
+ rescue NotImplementedError => e
104
+ assert_equal 'need to implement #intialize and set @url', e.message
105
+ else
106
+ flunk 'expected NotImplementedError'
75
107
  end
76
108
 
77
109
  def test_check_error
@@ -83,9 +115,10 @@ class TestRCRest < Test::Unit::TestCase
83
115
  r = RCRest.allocate
84
116
  r.instance_variable_set :@url, URI.parse('http://example.com/')
85
117
 
86
- url = r.make_url :a => 'b c', :x => 'y z'
118
+ url = r.make_url :method, :a => 'b c', :x => 'y z', :array => ['v2', 'v1']
87
119
 
88
- assert_equal 'http://example.com/?a=b%20c&x=y%20z', url.to_s
120
+ assert_equal 'http://example.com/method?a=b%20c&array=v1&array=v2&x=y%20z',
121
+ url.to_s
89
122
  end
90
123
 
91
124
  def test_parse_response
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.99
2
+ rubygems_version: 0.9.0.6
3
3
  specification_version: 1
4
4
  name: rc-rest
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.0
7
- date: 2006-06-15 00:00:00 -07:00
6
+ version: 2.0.0
7
+ date: 2006-11-27 00:00:00 -08:00
8
8
  summary: Robot Co-op REST web services base class
9
9
  require_paths:
10
10
  - lib
11
11
  email: eric@robotcoop.com
12
- homepage:
13
- rubyforge_project:
12
+ homepage: http://dev.robotcoop.com/Libraries/rc_rest
13
+ rubyforge_project: rctools
14
14
  description: This library makes it easy to implement REST-like web services APIs.
15
15
  autorequire:
16
16
  default_executable:
@@ -29,15 +29,17 @@ post_install_message:
29
29
  authors:
30
30
  - Eric Hodel
31
31
  files:
32
- - LICENSE
32
+ - History.txt
33
+ - LICENSE.txt
33
34
  - Manifest.txt
34
- - README
35
+ - README.txt
35
36
  - Rakefile
36
37
  - lib/rc_rest.rb
38
+ - lib/rc_rest/net_http_stub.rb
37
39
  - lib/rc_rest/uri_stub.rb
38
40
  - test/test_rc_rest.rb
39
- test_files: []
40
-
41
+ test_files:
42
+ - test/test_rc_rest.rb
41
43
  rdoc_options: []
42
44
 
43
45
  extra_rdoc_files: []
@@ -48,5 +50,13 @@ extensions: []
48
50
 
49
51
  requirements: []
50
52
 
51
- dependencies: []
52
-
53
+ dependencies:
54
+ - !ruby/object:Gem::Dependency
55
+ name: hoe
56
+ version_requirement:
57
+ version_requirements: !ruby/object:Gem::Version::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.4
62
+ version: