Permalink
Browse files

change semantics to svc.call.mod.fun

  • Loading branch information...
1 parent 6342e49 commit 4904d5521ac37661d4e66429cd0000b5e87a480f @mojombo committed Aug 13, 2009
View
@@ -26,7 +26,7 @@ Example
require 'bertrpc'
svc = BERTRPC::Service.new('localhost', 9999)
- svc.calc.add.call(1, 2)
+ svc.call.calc.add(1, 2)
# => 3
This generates a BERT-RPC request like so:
View
@@ -2,6 +2,8 @@
require 'socket'
require 'bertrpc/service'
+require 'bertrpc/call_proxy'
require 'bertrpc/mod'
-require 'bertrpc/fun'
+require 'bertrpc/encodes'
+require 'bertrpc/call'
require 'bertrpc/errors'
View
@@ -0,0 +1,33 @@
+module BERTRPC
+ class Call
+ include Encodes
+
+ def initialize(svc, mod, fun, args)
+ @svc = svc
+ @mod = mod
+ @fun = fun
+ @args = args
+ end
+
+ def execute
+ bert_request = encode_ruby_request([:call, @mod, @fun, @args])
+ bert_response = sync_request(bert_request)
+ decode_bert_response(bert_response)
+ end
+
+ #private
+
+ def sync_request(bert_request)
+ sock = TCPSocket.new(@svc.host, @svc.port)
+ sock.write([bert_request.length].pack("N"))
+ sock.write(bert_request)
+ lenheader = sock.read(4)
+ raise ProtocolError.new("Unable to read length header from server.") unless lenheader
+ len = lenheader.unpack('N').first
+ bert_response = sock.read(len)
+ raise ProtocolError.new("Unable to read data from server.") unless bert_response
+ sock.close
+ bert_response
+ end
+ end
+end
View
@@ -0,0 +1,11 @@
+module BERTRPC
+ class CallProxy
+ def initialize(svc)
+ @svc = svc
+ end
+
+ def method_missing(cmd, *args)
+ Mod.new(@svc, Call, cmd)
+ end
+ end
+end
@@ -1,33 +1,5 @@
module BERTRPC
- class Fun
- def initialize(svc, mod, fun)
- @svc = svc
- @mod = mod
- @fun = fun
- end
-
- def call(*args)
- args = [*args]
- bert_request = encode_ruby_request([:call, @mod, @fun, args])
- bert_response = sync_request(bert_request)
- decode_bert_response(bert_response)
- end
-
- # private
-
- def sync_request(bert_request)
- sock = TCPSocket.new(@svc.host, @svc.port)
- sock.write([bert_request.length].pack("N"))
- sock.write(bert_request)
- lenheader = sock.read(4)
- raise ProtocolError.new("Unable to read length header from server.") unless lenheader
- len = lenheader.unpack('N').first
- bert_response = sock.read(len)
- raise ProtocolError.new("Unable to read data from server.") unless bert_response
- sock.close
- bert_response
- end
-
+ module Encodes
def encode_ruby_request(ruby_request)
ruby_payload = convert(ruby_request)
Erlectricity::Encoder.encode(ruby_payload)
View
@@ -1,12 +1,14 @@
module BERTRPC
class Mod
- def initialize(svc, mod)
+ def initialize(svc, type, mod)
@svc = svc
+ @type = type
@mod = mod
end
def method_missing(cmd, *args)
- Fun.new(@svc, @mod, cmd)
+ args = [*args]
+ @type.new(@svc, @mod, cmd, args).execute
end
end
end
View
@@ -7,8 +7,8 @@ def initialize(host, port)
@port = port
end
- def method_missing(cmd, *args)
- Mod.new(self, cmd)
+ def call
+ CallProxy.new(self)
end
end
end
View
@@ -0,0 +1,24 @@
+require 'test_helper'
+
+class CallProxyTest < Test::Unit::TestCase
+ context "A CallProxy" do
+ setup do
+ @svc = BERTRPC::Service.new('localhost', 9941)
+ end
+
+ should "be created with a Service" do
+ assert BERTRPC::CallProxy.new(@svc).is_a?(BERTRPC::CallProxy)
+ end
+ end
+
+ context "A CallProxy instance" do
+ setup do
+ svc = BERTRPC::Service.new('localhost', 9941)
+ @cp = BERTRPC::CallProxy.new(@svc)
+ end
+
+ should "return a Mod instance" do
+ assert @cp.myfun.is_a?(BERTRPC::Mod)
+ end
+ end
+end
View
@@ -0,0 +1,85 @@
+require 'test_helper'
+
+class CallTest < Test::Unit::TestCase
+ context "A Call" do
+ setup do
+ @svc = BERTRPC::Service.new('localhost', 9941)
+ end
+
+ should "be created with a Service, module name, fun name, and args" do
+ assert BERTRPC::Call.new(@svc, :mymod, :myfun, [1, 2]).is_a?(BERTRPC::Call)
+ end
+ end
+
+ context "A Call instance" do
+ setup do
+ @svc = BERTRPC::Service.new('localhost', 9941)
+ @enc = Enc.new
+ end
+
+ should "call with single-arity" do
+ req = @enc.encode_ruby_request([:call, :mymod, :myfun, [1]])
+ res = @enc.encode_ruby_request([:reply, 2])
+ call = BERTRPC::Call.new(@svc, :mymod, :myfun, [1])
+ call.expects(:sync_request).with(req).returns(res)
+ assert_equal 2, call.execute
+ end
+
+ should "call with single-arity array" do
+ req = @enc.encode_ruby_request([:call, :mymod, :myfun, [[1, 2, 3]]])
+ res = @enc.encode_ruby_request([:reply, [4, 5, 6]])
+ call = BERTRPC::Call.new(@svc, :mymod, :myfun, [[1, 2, 3]])
+ call.expects(:sync_request).with(req).returns(res)
+ assert_equal [4, 5, 6], call.execute
+ end
+
+ should "call with multi-arity" do
+ req = @enc.encode_ruby_request([:call, :mymod, :myfun, [1, 2, 3]])
+ res = @enc.encode_ruby_request([:reply, [4, 5, 6]])
+ call = BERTRPC::Call.new(@svc, :mymod, :myfun, [1, 2, 3])
+ call.expects(:sync_request).with(req).returns(res)
+ assert_equal [4, 5, 6], call.execute
+ end
+
+ context "sync_request" do
+ setup do
+ @svc = BERTRPC::Service.new('localhost', 9941)
+ @call = BERTRPC::Call.new(@svc, :mymod, :myfun, [])
+ end
+
+ should "read and write BERT-Ps from the socket" do
+ io = stub()
+ io.expects(:write).with("\000\000\000\003")
+ io.expects(:write).with("foo")
+ io.expects(:read).with(4).returns("\000\000\000\003")
+ io.expects(:read).with(3).returns("bar")
+ io.expects(:close)
+ TCPSocket.expects(:new).returns(io)
+ assert_equal "bar", @call.sync_request("foo")
+ end
+
+ should "raise a ProtocolError when the length is invalid" do
+ io = stub()
+ io.expects(:write).with("\000\000\000\003")
+ io.expects(:write).with("foo")
+ io.expects(:read).with(4).returns(nil)
+ TCPSocket.expects(:new).returns(io)
+ assert_raises(BERTRPC::ProtocolError) do
+ @call.sync_request("foo")
+ end
+ end
+
+ should "raise a ProtocolError when the data is invalid" do
+ io = stub()
+ io.expects(:write).with("\000\000\000\003")
+ io.expects(:write).with("foo")
+ io.expects(:read).with(4).returns("\000\000\000\003")
+ io.expects(:read).with(3).returns(nil)
+ TCPSocket.expects(:new).returns(io)
+ assert_raises(BERTRPC::ProtocolError) do
+ @call.sync_request("foo")
+ end
+ end
+ end
+ end
+end
View
@@ -0,0 +1,80 @@
+require 'test_helper'
+
+class EncodesTest < Test::Unit::TestCase
+ context "An Encodes includer" do
+ setup do
+ @enc = Enc.new
+ end
+
+ context "converter" do
+ should "convert top level hashes to BERT-RPC dict form" do
+ assert_equal([:dict, [:foo, 1], [:bar, 2]], @enc.convert({:foo => 1, :bar => 2}))
+ end
+
+ should "convert nested hashes in the same way" do
+ assert_equal([1, 2, [:dict, [:foo, 1]]], @enc.convert([1, 2, {:foo => 1}]))
+ end
+
+ should "keep everything else the same" do
+ assert_equal [1, 2, "foo", :bar, 3.14], @enc.convert([1, 2, "foo", :bar, 3.14])
+ end
+ end
+
+ context "deconverter" do
+ should "convert top level BERT-RPC dict forms to hashes" do
+ assert_equal({:foo => 1, :bar => 2}, @enc.deconvert([:dict, [:foo, 1], [:bar, 2]]))
+ end
+
+ should "convert nested dicts in the same way" do
+ assert_equal([1, 2, {:foo => 1}], @enc.deconvert([1, 2, [:dict, [:foo, 1]]]))
+ end
+
+ should "keep everything else the same" do
+ assert_equal [1, 2, "foo", :bar, 3.14], @enc.deconvert([1, 2, "foo", :bar, 3.14])
+ end
+ end
+
+ context "ruby request encoder" do
+ should "return BERT-RPC encoded request" do
+ bert = "\203h\004d\000\004calld\000\005mymodd\000\005myfunh\003a\001a\002a\003"
+ assert_equal bert, @enc.encode_ruby_request([:call, :mymod, :myfun, [1, 2, 3]])
+ end
+ end
+
+ context "bert response decoder" do
+ should "return response when successful" do
+ req = @enc.encode_ruby_request([:reply, [1, 2, 3]])
+ res = @enc.decode_bert_response(req)
+ assert_equal [1, 2, 3], res
+ end
+
+ should "raise a ProtocolError error when protocol level error is returned" do
+ req = @enc.encode_ruby_request([:error, [:protocol, 1, "invalid"]])
+ assert_raises(BERTRPC::ProtocolError) do
+ @enc.decode_bert_response(req)
+ end
+ end
+
+ should "raise a ServerError error when server level error is returned" do
+ req = @enc.encode_ruby_request([:error, [:server, 1, "invalid"]])
+ assert_raises(BERTRPC::ServerError) do
+ @enc.decode_bert_response(req)
+ end
+ end
+
+ should "raise a UserError error when user level error is returned" do
+ req = @enc.encode_ruby_request([:error, [:user, 1, "invalid"]])
+ assert_raises(BERTRPC::UserError) do
+ @enc.decode_bert_response(req)
+ end
+ end
+
+ should "raise a ProxyError error when proxy level error is returned" do
+ req = @enc.encode_ruby_request([:error, [:proxy, 1, "invalid"]])
+ assert_raises(BERTRPC::ProxyError) do
+ @enc.decode_bert_response(req)
+ end
+ end
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 4904d55

Please sign in to comment.