rc-rest 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: