Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions lib/jsonrpc/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
146 changes: 110 additions & 36 deletions spec/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down