Roman2K-web-service 0.1.1
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 +7 -0
- data/README.mdown +147 -0
- data/Rakefile +39 -0
- data/lib/web_service.rb +36 -0
- data/lib/web_service/attribute_accessors.rb +147 -0
- data/lib/web_service/core_ext.rb +36 -0
- data/lib/web_service/crud_operations.rb +114 -0
- data/lib/web_service/named_request_methods.rb +19 -0
- data/lib/web_service/remote_collection.rb +155 -0
- data/lib/web_service/resource.rb +177 -0
- data/lib/web_service/response_handling.rb +148 -0
- data/lib/web_service/site.rb +40 -0
- data/test/test_helper.rb +59 -0
- data/test/web_service/attribute_accessors_test.rb +236 -0
- data/test/web_service/core_ext_test.rb +13 -0
- data/test/web_service/crud_operations_test.rb +61 -0
- data/test/web_service/named_request_methods_test.rb +34 -0
- data/test/web_service/remote_collection_test.rb +114 -0
- data/test/web_service/resource_test.rb +200 -0
- data/test/web_service/response_handling_test.rb +66 -0
- data/test/web_service/site_test.rb +62 -0
- data/web-service.gemspec +44 -0
- metadata +137 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module WebService
|
2
|
+
class Site
|
3
|
+
def initialize(url)
|
4
|
+
@url = URI(url)
|
5
|
+
end
|
6
|
+
|
7
|
+
# Returns a URI.
|
8
|
+
def url(options={})
|
9
|
+
@url
|
10
|
+
end
|
11
|
+
|
12
|
+
def credentials
|
13
|
+
[url.user, url.password] if url.user
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns a String.
|
17
|
+
def url_for(path, options={})
|
18
|
+
url_to_path = url(options)
|
19
|
+
url_to_path.path = path
|
20
|
+
return url_to_path.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def root
|
24
|
+
url_for '/'
|
25
|
+
end
|
26
|
+
|
27
|
+
# This class is supposed to be used within a Rails app.
|
28
|
+
class Switch < Site
|
29
|
+
def initialize(public, local)
|
30
|
+
@public, @local = URI.parse(public), URI.parse(local)
|
31
|
+
end
|
32
|
+
|
33
|
+
def url(options={})
|
34
|
+
url = (Rails.env.production? || options[:public] ? @public : @local).dup
|
35
|
+
url.port = @local.port if options[:public] && !Rails.env.production?
|
36
|
+
return url
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha'
|
3
|
+
require 'test_unit_ext'
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
Net::HTTP.class_eval do
|
7
|
+
undef :start if method_defined? :start
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'web_service'
|
11
|
+
WebService::Resource.site = WebService::Site.new("http://example.com")
|
12
|
+
WebService.logger = Logger.new(STDERR)
|
13
|
+
WebService.logger.level = Logger::ERROR
|
14
|
+
|
15
|
+
class Foo < WebService::Resource
|
16
|
+
has_many :bars
|
17
|
+
has_one :bar
|
18
|
+
has_one :details
|
19
|
+
end
|
20
|
+
class Bar < WebService::Resource
|
21
|
+
belongs_to :foo
|
22
|
+
end
|
23
|
+
class Details < WebService::Resource
|
24
|
+
end
|
25
|
+
|
26
|
+
Test::Unit::TestCase.class_eval do
|
27
|
+
include TestUnitExt
|
28
|
+
|
29
|
+
def expect_request(resource_or_collection, method, path, details)
|
30
|
+
connection = stub
|
31
|
+
response = Net::HTTPResponse::CODE_TO_OBJ[details[:return][:status].to_s].new(*[stub_everything] * 3)
|
32
|
+
body = nil
|
33
|
+
|
34
|
+
collection =
|
35
|
+
case resource_or_collection
|
36
|
+
when WebService::RemoteCollection
|
37
|
+
resource_or_collection
|
38
|
+
else
|
39
|
+
resource_or_collection.ieval { remote_collection }
|
40
|
+
end
|
41
|
+
|
42
|
+
collection.
|
43
|
+
stubs(:open_http_connection_to).
|
44
|
+
yields(connection).
|
45
|
+
returns(response)
|
46
|
+
|
47
|
+
connection.expects(:request).with { |req, body|
|
48
|
+
assert_equal(method.to_s.upcase, req.method)
|
49
|
+
assert_equal(path, req.path)
|
50
|
+
assert_equal(details[:body], ActiveSupport::JSON.decode(body || "null"))
|
51
|
+
true
|
52
|
+
}.returns(response)
|
53
|
+
|
54
|
+
response.metaclass.instance_eval do
|
55
|
+
define_method(:code) { details[:return][:status].to_s }
|
56
|
+
define_method(:data) { details[:return][:body] }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class WebService::AttributeAccessorsTest < Test::Unit::TestCase
|
4
|
+
class Resource
|
5
|
+
def self.element_name() "resource" end
|
6
|
+
include WebService::AttributeAccessors
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@res = Resource.new(:foo => :bar, :baz => nil, :void => " ")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_attributes
|
14
|
+
res = Resource.new(:foo => :bar, "baz" => :foo)
|
15
|
+
|
16
|
+
assert_equal({"foo" => :bar, "baz" => :foo}, res.attributes)
|
17
|
+
|
18
|
+
hash = res.attributes
|
19
|
+
hash[:hijack] = :value
|
20
|
+
assert !res.respond_to?(:hijack)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_attributes=
|
24
|
+
res = Resource.new(:foo => :bar)
|
25
|
+
res.attributes = {:bar => :foo}
|
26
|
+
assert !res.respond_to?(:foo)
|
27
|
+
assert_equal :foo, res.bar
|
28
|
+
|
29
|
+
# ID is set first
|
30
|
+
res = Resource.new
|
31
|
+
class << res
|
32
|
+
def assigned() @assigned ||= [] end
|
33
|
+
def id=(id) assigned << :id end
|
34
|
+
def foo=(foo) assigned << :foo end
|
35
|
+
def bar=(bar) assigned << :bar end
|
36
|
+
end
|
37
|
+
# a) Symbol
|
38
|
+
res.assigned.clear
|
39
|
+
res.attributes = {:bar => :foo, :id => 1, :foo => :bar}
|
40
|
+
assert_equal [:bar, :foo, :id], res.assigned.sort_by(&:to_s)
|
41
|
+
# b) String
|
42
|
+
res.assigned.clear
|
43
|
+
res.attributes = {:bar => :foo, "id" => 1, :foo => :bar}
|
44
|
+
assert_equal [:bar, :foo, :id], res.assigned.sort_by(&:to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_methods
|
48
|
+
res = Resource.new(:foo => :bar)
|
49
|
+
|
50
|
+
if RUBY_VERSION < '1.9'
|
51
|
+
assert_equal ["foo", "foo=", "foo?"], res.methods - Resource.instance_methods
|
52
|
+
else
|
53
|
+
assert_equal [:foo, :foo=, :foo?], res.methods - Resource.instance_methods
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_respond_to
|
58
|
+
res = Resource.new(:foo => :bar)
|
59
|
+
|
60
|
+
# Still responds to regular methods
|
61
|
+
assert_respond_to(res, :object_id)
|
62
|
+
|
63
|
+
# Respond to attribute accessor methods
|
64
|
+
assert_respond_to(res, :foo)
|
65
|
+
assert_respond_to(res, :foo=)
|
66
|
+
assert_respond_to(res, :foo?)
|
67
|
+
|
68
|
+
# Doesn't respond to other methods
|
69
|
+
assert !res.respond_to?(:bar)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_querying
|
73
|
+
assert @res.foo? # present
|
74
|
+
assert !@res.baz? # blank
|
75
|
+
assert !@res.void? # blank
|
76
|
+
|
77
|
+
# wrong number of arguments
|
78
|
+
assert_raise ArgumentError do
|
79
|
+
@res.foo?(:extra)
|
80
|
+
end
|
81
|
+
|
82
|
+
# inexistent
|
83
|
+
assert_raise NoMethodError do
|
84
|
+
@res.bar?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_readers
|
89
|
+
assert_equal :bar, @res.foo
|
90
|
+
assert_equal nil, @res.baz
|
91
|
+
assert_raise NoMethodError do
|
92
|
+
@res.unknown_attribute
|
93
|
+
end
|
94
|
+
|
95
|
+
# wrong number of arguments
|
96
|
+
assert_raise ArgumentError do
|
97
|
+
@res.foo("a")
|
98
|
+
end
|
99
|
+
|
100
|
+
@res.write_attribute("bool?", :value)
|
101
|
+
assert_equal :value, @res.bool?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_writers
|
105
|
+
res = Resource.new
|
106
|
+
|
107
|
+
# first value
|
108
|
+
res.foo = :bar
|
109
|
+
assert_equal(:bar, res.foo)
|
110
|
+
assert_equal({"foo" => :bar}, res.attributes)
|
111
|
+
|
112
|
+
# reset to nil...
|
113
|
+
res.foo = nil
|
114
|
+
assert_equal(nil, res.foo)
|
115
|
+
assert_equal({"foo" => nil}, res.attributes)
|
116
|
+
|
117
|
+
# ...and back to a value
|
118
|
+
res.foo = :bar
|
119
|
+
assert_equal(:bar, res.foo)
|
120
|
+
assert_equal({"foo" => :bar}, res.attributes)
|
121
|
+
|
122
|
+
# second value
|
123
|
+
res.foo = :foo
|
124
|
+
assert_equal(:foo, res.foo)
|
125
|
+
assert_equal({"foo" => :foo}, res.attributes)
|
126
|
+
|
127
|
+
# wrong number of arguments
|
128
|
+
assert_raise ArgumentError do
|
129
|
+
res.send(:foo=, "a", "b")
|
130
|
+
end
|
131
|
+
|
132
|
+
# first value is nil
|
133
|
+
res = Resource.new
|
134
|
+
res.nothing = nil
|
135
|
+
assert_equal(nil, res.nothing)
|
136
|
+
assert_equal({"nothing" => nil}, res.attributes)
|
137
|
+
end
|
138
|
+
|
139
|
+
##########################
|
140
|
+
# Association accessors
|
141
|
+
##########################
|
142
|
+
|
143
|
+
Object.class_eval %q{
|
144
|
+
class NotResource
|
145
|
+
end
|
146
|
+
}
|
147
|
+
|
148
|
+
def test_association_querying
|
149
|
+
bar = Bar.new
|
150
|
+
|
151
|
+
assert !bar.respond_to?(:foo?)
|
152
|
+
|
153
|
+
bar.foo = Foo.new('id' => 1)
|
154
|
+
assert bar.foo?
|
155
|
+
assert bar.foo_id?
|
156
|
+
|
157
|
+
bar.foo = nil
|
158
|
+
assert !bar.foo?
|
159
|
+
assert !bar.foo_id?
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_association_writers
|
163
|
+
bar = Resource.new
|
164
|
+
|
165
|
+
bar.foo = nil
|
166
|
+
bar.foo = {"id" => 1}
|
167
|
+
assert_equal Foo.new('id' => 1), bar.foo
|
168
|
+
assert_equal 1, bar.foo_id
|
169
|
+
|
170
|
+
bar.foo = nil
|
171
|
+
bar.foo = {"foo" => {"id" => 1}}
|
172
|
+
assert_equal Foo.new('id' => 1), bar.foo
|
173
|
+
assert_equal 1, bar.foo_id
|
174
|
+
|
175
|
+
bar.foo = nil
|
176
|
+
bar.foo = {"bar" => {"id" => 1}}
|
177
|
+
assert_equal Bar.new('id' => 1), bar.foo
|
178
|
+
assert_equal 1, bar.foo_id
|
179
|
+
|
180
|
+
bar.foo = nil
|
181
|
+
bar.foo = [{"bar" => {"id" => 1}}, 'other-value']
|
182
|
+
assert_equal [Bar.new('id' => 1), 'other-value'], bar.foo
|
183
|
+
assert_equal nil, bar.foo_id
|
184
|
+
|
185
|
+
bar.foo = {"id" => 1}
|
186
|
+
bar.foo = nil
|
187
|
+
assert_equal nil, bar.foo
|
188
|
+
assert_equal nil, bar.foo_id
|
189
|
+
|
190
|
+
bar.foo = {"id" => 1}
|
191
|
+
bar.foo_id = nil
|
192
|
+
assert_equal nil, bar.foo
|
193
|
+
assert_equal nil, bar.foo_id
|
194
|
+
|
195
|
+
bar.foo = {"id" => 1}
|
196
|
+
bar.foo_id = 1
|
197
|
+
Foo.stubs(:find).with(1).returns("reset").once
|
198
|
+
assert_equal "reset", bar.foo
|
199
|
+
assert_equal 1, bar.foo_id
|
200
|
+
|
201
|
+
foo = Foo.new('id' => 2)
|
202
|
+
bar.foo = foo
|
203
|
+
assert_equal foo.object_id, bar.foo.object_id
|
204
|
+
assert_equal 2, bar.foo_id
|
205
|
+
|
206
|
+
bar.foo = nil
|
207
|
+
assert_raise WebService::ResourceNotSaved do
|
208
|
+
bar.foo = Foo.new('id' => nil)
|
209
|
+
end
|
210
|
+
assert_equal nil, bar.foo
|
211
|
+
|
212
|
+
bar.foo = Foo.new('id' => 2)
|
213
|
+
bar.foo_id = 3
|
214
|
+
Foo.expects(:find).with(3).returns("fetched").once
|
215
|
+
assert_equal "fetched", bar.foo
|
216
|
+
assert_equal "fetched", bar.foo
|
217
|
+
|
218
|
+
bar.not_resource = {"id" => 4}
|
219
|
+
assert_equal({"id" => 4}, bar.not_resource)
|
220
|
+
|
221
|
+
bar.noclass_id = 5
|
222
|
+
assert_raise NameError, "uninitialized constant Noclass" do
|
223
|
+
bar.noclass
|
224
|
+
end
|
225
|
+
|
226
|
+
bar.not_resource_id = 6
|
227
|
+
expected_message = "class NotResource found for association `not_resource' is not a resource class"
|
228
|
+
assert_raise WebService::NotResourceClass, expected_message do
|
229
|
+
bar.not_resource
|
230
|
+
end
|
231
|
+
|
232
|
+
not_resource = NotResource.new
|
233
|
+
bar.attributes = {:not_resource => not_resource}
|
234
|
+
assert_equal not_resource, bar.not_resource
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CoreExtTest < Test::Unit::TestCase
|
4
|
+
def test_uri_obfuscate
|
5
|
+
assert_equal "http://example.com", URI("http://example.com").obfuscate.to_s
|
6
|
+
assert_equal "http://***@example.com", URI("http://foo@example.com").obfuscate.to_s
|
7
|
+
assert_equal "http://***:***@example.com", URI("http://foo:secret@example.com").obfuscate.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_cgi_escape
|
11
|
+
assert_equal "example%2ecom", CGI.escape("example.com")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class WebService::CRUDOperationsTest < Test::Unit::TestCase
|
4
|
+
def test_all
|
5
|
+
will_return = expect_request_for_foos_index_with_param_bar_equals_baz
|
6
|
+
foos = Foo.all(:bar => :baz)
|
7
|
+
assert_equal will_return, foos
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_cache
|
11
|
+
collection = Foo.new('id' => 1).bars
|
12
|
+
|
13
|
+
collection.cache = [{'id' => 1}, {'bar' => {'id' => 2}}, Bar.new('id' => 3)]
|
14
|
+
expected = [Bar.new('id' => 1), Bar.new('id' => 2), Bar.new('id' => 3)]
|
15
|
+
assert_equal expected, collection.all
|
16
|
+
|
17
|
+
collection.flush_cache
|
18
|
+
expect_request collection,
|
19
|
+
:get, "/foos/1/bars", :return => {:status => "200", :body => []}
|
20
|
+
assert_equal [], collection.all
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_first
|
24
|
+
will_return = expect_request_for_foos_index_with_param_bar_equals_baz
|
25
|
+
assert_equal will_return.first, Foo.first(:bar => :baz)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_last
|
29
|
+
will_return = expect_request_for_foos_index_with_param_bar_equals_baz
|
30
|
+
assert_equal will_return.last, Foo.last(:bar => :baz)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_find
|
34
|
+
expect_request Foo,
|
35
|
+
:get, "/foos/1?bar=baz",
|
36
|
+
:return => {:status => "200", :body => {"foo" => {"id" => 1}}}
|
37
|
+
assert_equal Foo.new('id' => 1), Foo.find(1, :bar => :baz)
|
38
|
+
|
39
|
+
expect_request Foo,
|
40
|
+
:get, "/foos/1", :return => {:status => "404"}
|
41
|
+
assert_raise WebService::ResourceNotFound do
|
42
|
+
Foo.find(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_build
|
47
|
+
type_foo = Class.new(Foo)
|
48
|
+
def type_foo.implicit_attributes; {:a => :b, :c => :d} end
|
49
|
+
foo = type_foo.build("a" => :overridden, "e" => "f")
|
50
|
+
assert_equal({"a" => :overridden, "c" => :d, "e" => "f"}, foo.attributes)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def expect_request_for_foos_index_with_param_bar_equals_baz
|
56
|
+
expect_request Foo,
|
57
|
+
:get, "/foos?bar=baz",
|
58
|
+
:return => {:status => "200", :body => [{"foo" => {"id" => 1}}, {"foo" => {"id" => 2}}]}
|
59
|
+
[Foo.new("id" => 1), Foo.new("id" => 2)]
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class WebService::NamedRequestMethodsTest < Test::Unit::TestCase
|
4
|
+
def test_collection_actions
|
5
|
+
expect_request Foo,
|
6
|
+
:get, "/foos/bar",
|
7
|
+
:return => {:status => "200", :body => "bar"}
|
8
|
+
assert_equal "bar", Foo.get(:bar)
|
9
|
+
|
10
|
+
expect_request Foo,
|
11
|
+
:get, "/foos/bar?a=b",
|
12
|
+
:return => {:status => "200", :body => "bar"}
|
13
|
+
assert_equal "bar", Foo.get(:bar, :a => :b)
|
14
|
+
|
15
|
+
expect_request Foo,
|
16
|
+
:put, "/foos/bar",
|
17
|
+
:return => {:status => "200", :body => "bar"}
|
18
|
+
assert_equal "bar", Foo.put(:bar)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_member_actions
|
22
|
+
foo = Foo.new("id" => 1)
|
23
|
+
|
24
|
+
expect_request foo,
|
25
|
+
:put, "/foos/1/bar",
|
26
|
+
:return => {:status => "200", :body => "bar"}
|
27
|
+
assert_equal "bar", foo.put(:bar)
|
28
|
+
|
29
|
+
expect_request foo,
|
30
|
+
:put, "/foos/1/bar",
|
31
|
+
:return => {:status => "200", :body => "bar"}
|
32
|
+
assert_equal "bar", foo.put("/bar")
|
33
|
+
end
|
34
|
+
end
|