diff --git a/lib/jsonrpc/client.rb b/lib/jsonrpc/client.rb index 0c59e89..76fef0b 100644 --- a/lib/jsonrpc/client.rb +++ b/lib/jsonrpc/client.rb @@ -25,12 +25,25 @@ def self.decode_options @decode_options = {} class Helper + NAMED = :named + POSITIONAL = :positional + def initialize(options) @options = options @options[:content_type] ||= 'application/json' + @params_type = POSITIONAL + @params_type = NAMED if @options.delete(:named_params) == true @connection = @options.delete(:connection) end + def positional_params? + @params_type == POSITIONAL + end + + def named_params? + @params_type == NAMED + end + def options(additional_options = nil) if additional_options additional_options.merge(@options) @@ -91,7 +104,11 @@ def initialize(url, opts = {}) def method_missing(sym, *args, &block) if @alive - request = ::JSONRPC::Request.new(sym.to_s, args) + if @helper.named_params? && args.size == 1 && args.first.is_a?(::Hash) + request = ::JSONRPC::Request.new(sym.to_s, *args) + else + request = ::JSONRPC::Request.new(sym.to_s, args) + end push_batch_request(request) else super @@ -141,7 +158,11 @@ def send_batch class Client < Base def method_missing(method, *args, &block) - invoke(method, args) + if @helper.named_params? && args.size == 1 && args.first.is_a?(::Hash) + invoke(method, *args) + else + invoke(method, args) + end end def invoke(method, args, options = nil) diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 3a79cf5..0a39bce 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -88,51 +88,125 @@ module JSONRPC client.foo(1,2,3).should == 42 end end + context "when using named parameters" do + before(:each) do + @expected = MultiJson.encode({ + 'jsonrpc' => '2.0', + 'method' => 'foo', + 'params' => {:p1 => 1, :p2 => 2, :p3 => 3}, + 'id' => 1 + }) + end + it "sends a valid JSON-RPC request and returns the result" do + response = MultiJson.encode(BOILERPLATE.merge({'result' => 42})) + connection.should_receive(:post).with(SPEC_URL, @expected, {:content_type => 'application/json'}).and_return(@resp_mock) + @resp_mock.should_receive(:body).at_least(:once).and_return(response) + client = Client.new(SPEC_URL, :connection => connection, :named_params => true) + result = client.foo({:p1 => 1, :p2 => 2, :p3 => 3}) + result.should == 42 + end + end end describe "sending a batch request" do - it "sends a valid JSON-RPC batch request and puts the results in the response objects" do - batch = MultiJson.encode([ - {"jsonrpc" => "2.0", "method" => "sum", "params" => [1,2,4], "id" => "1"}, - {"jsonrpc" => "2.0", "method" => "subtract", "params" => [42,23], "id" => "2"}, - {"jsonrpc" => "2.0", "method" => "foo_get", "params" => [{"name" => "myself"}], "id" => "5"}, - {"jsonrpc" => "2.0", "method" => "get_data", "id" => "9"} - ]) - - response = MultiJson.encode([ - {"jsonrpc" => "2.0", "result" => 7, "id" => "1"}, - {"jsonrpc" => "2.0", "result" => 19, "id" => "2"}, - {"jsonrpc" => "2.0", "error" => {"code" => -32601, "message" => "Method not found."}, "id" => "5"}, - {"jsonrpc" => "2.0", "result" => ["hello", 5], "id" => "9"} - ]) - - Base.stub(:make_id).and_return('1', '2', '5', '9') - connection.should_receive(:post).with(SPEC_URL, batch, {:content_type => 'application/json'}).and_return(@resp_mock) - @resp_mock.should_receive(:body).at_least(:once).and_return(response) - client = Client.new(SPEC_URL, :connection => connection) - - sum = subtract = foo = data = nil - client = BatchClient.new(SPEC_URL, :connection => connection) do |batch| - sum = batch.sum(1,2,4) - subtract = batch.subtract(42,23) - foo = batch.foo_get('name' => 'myself') - data = batch.get_data - end + context "when using positional parameters" do + it "sends a valid JSON-RPC batch request and puts the results in the response objects" do + batch = MultiJson.encode([ + {"jsonrpc" => "2.0", "method" => "sum", "params" => [1,2,4], "id" => "1"}, + {"jsonrpc" => "2.0", "method" => "subtract", "params" => [42,23], "id" => "2"}, + {"jsonrpc" => "2.0", "method" => "foo_get", "params" => [{"name" => "myself"}], "id" => "5"}, + {"jsonrpc" => "2.0", "method" => "get_data", "id" => "9"} + ]) + + response = MultiJson.encode([ + {"jsonrpc" => "2.0", "result" => 7, "id" => "1"}, + {"jsonrpc" => "2.0", "result" => 19, "id" => "2"}, + {"jsonrpc" => "2.0", "error" => {"code" => -32601, "message" => "Method not found."}, "id" => "5"}, + {"jsonrpc" => "2.0", "result" => ["hello", 5], "id" => "9"} + ]) + + Base.stub(:make_id).and_return('1', '2', '5', '9') + connection.should_receive(:post).with(SPEC_URL, batch, {:content_type => 'application/json'}).and_return(@resp_mock) + @resp_mock.should_receive(:body).at_least(:once).and_return(response) + client = Client.new(SPEC_URL, :connection => connection) + + sum = subtract = foo = data = nil + client = BatchClient.new(SPEC_URL, :connection => connection) do |batch| + sum = batch.sum(1,2,4) + subtract = batch.subtract(42,23) + foo = batch.foo_get('name' => 'myself') + data = batch.get_data + end - sum.succeeded?.should be_true - sum.is_error?.should be_false - sum.result.should == 7 + sum.succeeded?.should be_true + sum.is_error?.should be_false + sum.result.should == 7 - subtract.result.should == 19 + subtract.result.should == 19 - foo.is_error?.should be_true - foo.succeeded?.should be_false - foo.error['code'].should == -32601 + foo.is_error?.should be_true + foo.succeeded?.should be_false + foo.error['code'].should == -32601 - data.result.should == ['hello', 5] + data.result.should == ['hello', 5] - expect { client.sum(1, 2) }.to raise_error(NoMethodError) + expect { client.sum(1, 2) }.to raise_error(NoMethodError) + end + context "when using named parameters" do + it "sends a valid JSON-RPC batch request and puts the results in the response objects" do + batch = MultiJson.encode([ + {"jsonrpc" => "2.0", "method" => "sum", "params" => [1,2,4], "id" => "1"}, + {"jsonrpc" => "2.0", "method" => "subtract", "params" => [42,23], "id" => "2"}, + {"jsonrpc" => "2.0", "method" => "hello", "params" => ['world'], "id" => "3"}, + {"jsonrpc" => "2.0", "method" => "foo_get", "params" => {"name" => "myself"}, "id" => "5"}, + {"jsonrpc" => "2.0", "method" => "foo", "params" => [[1,2,3]], "id" => "7"}, + {"jsonrpc" => "2.0", "method" => "foo", "params" => {:some => { :nested => :hash }}, "id" => "8"}, + {"jsonrpc" => "2.0", "method" => "get_data", "id" => "9"} + ]) + + response = MultiJson.encode([ + {"jsonrpc" => "2.0", "result" => 7, "id" => "1"}, + {"jsonrpc" => "2.0", "result" => 19, "id" => "2"}, + {"jsonrpc" => "2.0", "result" => 'world', "id" => "3"}, + {"jsonrpc" => "2.0", "error" => {"code" => -32601, "message" => "Method not found."}, "id" => "5"}, + {"jsonrpc" => "2.0", "result" => [2,4,6], "id" => "7"}, + {"jsonrpc" => "2.0", "result" => "I can handle this!", "id" => "8"}, + {"jsonrpc" => "2.0", "result" => ["hello", 5], "id" => "9"} + ]) + + Base.stub(:make_id).and_return('1', '2', '3', '5', '7', '8', '9') + connection.should_receive(:post).with(SPEC_URL, batch, {:content_type => 'application/json'}).and_return(@resp_mock) + @resp_mock.should_receive(:body).at_least(:once).and_return(response) + client = Client.new(SPEC_URL, :connection => connection) + + sum = subtract = foo = data = nil + client = BatchClient.new(SPEC_URL, :connection => connection, :named_params => true) do |batch| + sum = batch.sum(1,2,4) + subtract = batch.subtract(42,23) + str = batch.hello('world') + foo = batch.foo_get('name' => 'myself') + arr = batch.foo([1,2,3]) + nested = batch.foo({:some => { :nested => :hash }}) + data = batch.get_data + end + + sum.succeeded?.should be_true + sum.is_error?.should be_false + sum.result.should == 7 + + subtract.result.should == 19 + + foo.is_error?.should be_true + foo.succeeded?.should be_false + foo.error['code'].should == -32601 + + data.result.should == ['hello', 5] + + + expect { client.sum(1, 2) }.to raise_error(NoMethodError) + end + end end end