jimson 0.3.1 → 0.4.0

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/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Jimson
2
+ ### JSON-RPC 2.0 Client and Server for Ruby
3
+
4
+ ## Client: Quick Start
5
+ require 'jimson'
6
+ client = Jimson::Client.new("http://www.example.com:8999") # the URL for the JSON-RPC 2.0 server to connect to
7
+ result = client.sum(1,2) # call the 'sum' method on the RPC server and save the result '3'
8
+
9
+ ## Server: Quick Start
10
+ require 'jimson'
11
+
12
+ class MyHandler
13
+ extend Jimson::Handler
14
+
15
+ def sum(a,b)
16
+ a + b
17
+ end
18
+ end
19
+
20
+ server = Jimson::Server.new(MyHandler.new)
21
+ server.start # serve with webrick on http://0.0.0.0:8999/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
data/lib/jimson.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'jimson/handler'
2
3
  require 'jimson/server'
3
4
  require 'jimson/client'
4
5
 
data/lib/jimson/client.rb CHANGED
@@ -1,6 +1,11 @@
1
+ require 'blankslate'
2
+ module Jimson
3
+ class Client < BlankSlate
4
+ end
5
+ end
6
+
1
7
  require 'rest-client'
2
- require 'jimson/server_error'
3
- require 'jimson/client_error'
8
+ require 'jimson/client/error'
4
9
  require 'jimson/request'
5
10
  require 'jimson/response'
6
11
 
@@ -24,10 +29,14 @@ module Jimson
24
29
  begin
25
30
  data = JSON.parse(resp)
26
31
  rescue
27
- raise Jimson::ClientError::InvalidJSON.new(resp)
32
+ raise Client::Error::InvalidJSON.new(resp)
28
33
  end
29
34
 
30
35
  return process_single_response(data)
36
+
37
+ rescue Exception, StandardError => e
38
+ e.extend(Client::Error) unless e.is_a?(Client::Error)
39
+ raise e
31
40
  end
32
41
 
33
42
  def send_single_request(method, args)
@@ -39,20 +48,17 @@ module Jimson
39
48
  }.to_json
40
49
  resp = RestClient.post(@url, post_data, :content_type => 'application/json')
41
50
  if resp.nil? || resp.body.nil? || resp.body.empty?
42
- raise Jimson::ClientError::InvalidResponse.new
51
+ raise Client::Error::InvalidResponse.new
43
52
  end
44
53
 
45
54
  return resp.body
46
-
47
- rescue Exception, StandardError
48
- raise Jimson::ClientError::InternalError.new($!)
49
55
  end
50
56
 
51
57
  def send_batch_request(batch)
52
58
  post_data = batch.to_json
53
59
  resp = RestClient.post(@url, post_data, :content_type => 'application/json')
54
60
  if resp.nil? || resp.body.nil? || resp.body.empty?
55
- raise Jimson::ClientError::InvalidResponse.new
61
+ raise Client::Error::InvalidResponse.new
56
62
  end
57
63
 
58
64
  return resp.body
@@ -61,29 +67,21 @@ module Jimson
61
67
  def process_batch_response(responses)
62
68
  responses.each do |resp|
63
69
  saved_response = @batch.map { |r| r[1] }.select { |r| r.id == resp['id'] }.first
64
- raise Jimson::ClientError::InvalidResponse.new unless !!saved_response
70
+ raise Client::Error::InvalidResponse.new if saved_response.nil?
65
71
  saved_response.populate!(resp)
66
72
  end
67
73
  end
68
74
 
69
75
  def process_single_response(data)
70
- raise Jimson::ClientError::InvalidResponse.new if !valid_response?(data)
76
+ raise Client::Error::InvalidResponse.new if !valid_response?(data)
71
77
 
72
78
  if !!data['error']
73
79
  code = data['error']['code']
74
- if Jimson::ServerError::CODES.keys.include?(code)
75
- raise Jimson::ServerError::CODES[code].new
76
- else
77
- raise Jimson::ClientError::UnknownServerError.new(code, data['error']['message'])
78
- end
80
+ msg = data['error']['message']
81
+ raise Client::Error::ServerError.new(code, msg)
79
82
  end
80
83
 
81
84
  return data['result']
82
-
83
- rescue Jimson::ClientError::Generic, Jimson::ServerError::Generic => e
84
- raise e
85
- rescue Exception, StandardError => e
86
- raise Jimson::ClientError::InternalError.new(e)
87
85
  end
88
86
 
89
87
  def valid_response?(data)
@@ -113,7 +111,7 @@ module Jimson
113
111
 
114
112
  def push_batch_request(request)
115
113
  request.id = self.class.make_id
116
- response = Jimson::Response.new(request.id)
114
+ response = Response.new(request.id)
117
115
  @batch << [request, response]
118
116
  return response
119
117
  end
@@ -125,7 +123,7 @@ module Jimson
125
123
  begin
126
124
  responses = JSON.parse(response)
127
125
  rescue
128
- raise Jimson::ClientError::InvalidJSON.new(json)
126
+ raise Client::Error::InvalidJSON.new(json)
129
127
  end
130
128
 
131
129
  process_batch_response(responses)
@@ -134,7 +132,7 @@ module Jimson
134
132
 
135
133
  end
136
134
 
137
- class BatchClient
135
+ class BatchClient < BlankSlate
138
136
 
139
137
  def initialize(helper)
140
138
  @helper = helper
@@ -147,7 +145,10 @@ module Jimson
147
145
 
148
146
  end
149
147
 
150
- class Client
148
+ class Client < BlankSlate
149
+ reveal :instance_variable_get
150
+ reveal :inspect
151
+ reveal :to_s
151
152
 
152
153
  def self.batch(client)
153
154
  helper = client.instance_variable_get(:@helper)
@@ -161,7 +162,11 @@ module Jimson
161
162
  end
162
163
 
163
164
  def method_missing(sym, *args, &block)
164
- @helper.process_call(sym, args)
165
+ self[sym, args]
166
+ end
167
+
168
+ def [](method, *args)
169
+ @helper.process_call(method, args.flatten)
165
170
  end
166
171
 
167
172
  end
@@ -0,0 +1,23 @@
1
+ module Jimson
2
+ class Client
3
+ module Error
4
+ class InvalidResponse < StandardError
5
+ def initialize()
6
+ super('Invalid or empty response from server.')
7
+ end
8
+ end
9
+
10
+ class InvalidJSON < StandardError
11
+ def initialize(json)
12
+ super("Couldn't parse JSON string received from server:\n#{json}")
13
+ end
14
+ end
15
+
16
+ class ServerError < StandardError
17
+ def initialize(code, message)
18
+ super("Server error #{code}: #{message}")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Jimson
2
+ module Handler
3
+
4
+ def jimson_default_methods
5
+ self.instance_methods.map(&:to_s) - Object.methods.map(&:to_s)
6
+ end
7
+
8
+ def jimson_expose(*methods)
9
+ @jimson_exposed_methods ||= []
10
+ @jimson_exposed_methods += methods.map(&:to_s)
11
+ end
12
+
13
+ def jimson_exclude(*methods)
14
+ @jimson_excluded_methods ||= []
15
+ @jimson_excluded_methods += methods.map(&:to_s)
16
+ end
17
+
18
+ def jimson_exposed_methods
19
+ @jimson_exposed_methods ||= []
20
+ @jimson_excluded_methods ||= []
21
+ (jimson_default_methods - @jimson_excluded_methods + @jimson_exposed_methods).sort.map(&:to_sym)
22
+ end
23
+
24
+ end
25
+ end
data/lib/jimson/server.rb CHANGED
@@ -2,10 +2,28 @@ require 'rack'
2
2
  require 'rack/request'
3
3
  require 'rack/response'
4
4
  require 'json'
5
+ require 'jimson/handler'
6
+ require 'jimson/server/error'
5
7
 
6
8
  module Jimson
7
9
  class Server
8
10
 
11
+ class System
12
+ extend Handler
13
+
14
+ def initialize(handler)
15
+ @handler = handler
16
+ end
17
+
18
+ def listMethods
19
+ @handler.class.jimson_exposed_methods
20
+ end
21
+
22
+ def isAlive
23
+ true
24
+ end
25
+ end
26
+
9
27
  JSON_RPC_VERSION = '2.0'
10
28
 
11
29
  attr_accessor :handler, :host, :port
@@ -52,17 +70,17 @@ module Jimson
52
70
  begin
53
71
  request = parse_request(content)
54
72
  if request.is_a?(Array)
55
- raise Jimson::ServerError::InvalidRequest.new if request.empty?
73
+ raise Server::Error::InvalidRequest.new if request.empty?
56
74
  response = request.map { |req| handle_request(req) }
57
75
  else
58
76
  response = handle_request(request)
59
77
  end
60
- rescue Jimson::ServerError::ParseError, Jimson::ServerError::InvalidRequest => e
78
+ rescue Server::Error::ParseError, Server::Error::InvalidRequest => e
61
79
  response = error_response(e)
62
- rescue Jimson::ServerError::Generic => e
80
+ rescue Server::Error => e
63
81
  response = error_response(e, request)
64
- rescue StandardError, Exception
65
- response = error_response(Jimson::ServerError::InternalError.new)
82
+ rescue StandardError, Exception => e
83
+ response = error_response(Server::Error::InternalError.new(e))
66
84
  end
67
85
 
68
86
  response.compact! if response.is_a?(Array)
@@ -76,11 +94,11 @@ module Jimson
76
94
  response = nil
77
95
  begin
78
96
  if !validate_request(request)
79
- response = error_response(Jimson::ServerError::InvalidRequest.new)
97
+ response = error_response(Server::Error::InvalidRequest.new)
80
98
  else
81
99
  response = create_response(request)
82
100
  end
83
- rescue Jimson::ServerError::Generic => e
101
+ rescue Server::Error => e
84
102
  response = error_response(e, request)
85
103
  end
86
104
 
@@ -112,20 +130,9 @@ module Jimson
112
130
  end
113
131
 
114
132
  def create_response(request)
133
+ method = request['method']
115
134
  params = request['params']
116
- begin
117
- if params.is_a?(Hash)
118
- result = @handler.send(request['method'], params)
119
- else
120
- result = @handler.send(request['method'], *params)
121
- end
122
- rescue NoMethodError
123
- raise Jimson::ServerError::MethodNotFound.new
124
- rescue ArgumentError
125
- raise Jimson::ServerError::InvalidParams.new
126
- rescue
127
- raise Jimson::ServerError::ApplicationError.new($!)
128
- end
135
+ result = dispatch_request(method, params)
129
136
 
130
137
  response = success_response(request, result)
131
138
 
@@ -134,7 +141,42 @@ module Jimson
134
141
  # that are within a batch request.
135
142
  response = nil if !request.has_key?('id')
136
143
 
137
- response
144
+ return response
145
+
146
+ rescue Server::Error => e
147
+ raise e
148
+ rescue ArgumentError
149
+ raise Server::Error::InvalidParams.new
150
+ rescue Exception, StandardError => e
151
+ raise Server::Error::ApplicationError.new(e)
152
+ end
153
+
154
+ def dispatch_request(method, params)
155
+ # normally route requests to the user-suplied handler
156
+ handler = @handler
157
+
158
+ # switch to the System handler if a system method was called
159
+ sys_regex = /^system\./
160
+ if method =~ sys_regex
161
+ handler = System.new(@handler)
162
+ # remove the 'system.' prefix before from the method name
163
+ method.gsub!(sys_regex, '')
164
+ end
165
+
166
+ method = method.to_sym
167
+
168
+ if !handler.class.jimson_exposed_methods.include?(method) \
169
+ || !handler.respond_to?(method)
170
+ raise Server::Error::MethodNotFound.new(method)
171
+ end
172
+
173
+ if params.nil?
174
+ return handler.send(method)
175
+ elsif params.is_a?(Hash)
176
+ return handler.send(method, params)
177
+ else
178
+ return handler.send(method, *params)
179
+ end
138
180
  end
139
181
 
140
182
  def error_response(error, request = nil)
@@ -162,7 +204,7 @@ module Jimson
162
204
  def parse_request(post)
163
205
  data = JSON.parse(post)
164
206
  rescue
165
- raise Jimson::ServerError::ParseError.new
207
+ raise Server::Error::ParseError.new
166
208
  end
167
209
 
168
210
  end
@@ -0,0 +1,64 @@
1
+ module Jimson
2
+ class Server
3
+ class Error < StandardError
4
+ attr_accessor :code, :message
5
+
6
+ def initialize(code, message)
7
+ @code = code
8
+ @message = message
9
+ super(message)
10
+ end
11
+
12
+ def to_h
13
+ {
14
+ 'code' => @code,
15
+ 'message' => @message
16
+ }
17
+ end
18
+
19
+ class ParseError < Error
20
+ def initialize
21
+ super(-32700, 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.')
22
+ end
23
+ end
24
+
25
+ class InvalidRequest < Error
26
+ def initialize
27
+ super(-32600, 'The JSON sent is not a valid Request object.')
28
+ end
29
+ end
30
+
31
+ class MethodNotFound < Error
32
+ def initialize(method)
33
+ super(-32601, "Method '#{method}' not found.")
34
+ end
35
+ end
36
+
37
+ class InvalidParams < Error
38
+ def initialize
39
+ super(-32602, 'Invalid method parameter(s).')
40
+ end
41
+ end
42
+
43
+ class InternalError < Error
44
+ def initialize(e)
45
+ super(-32603, "Internal server error: #{e}")
46
+ end
47
+ end
48
+
49
+ class ApplicationError < Error
50
+ def initialize(err)
51
+ super(-32099, "Application error: #{err} #{err.backtrace.join("\n")}")
52
+ end
53
+ end
54
+
55
+ CODES = {
56
+ -32700 => ParseError,
57
+ -32600 => InvalidRequest,
58
+ -32601 => MethodNotFound,
59
+ -32602 => InvalidParams,
60
+ -32603 => InternalError
61
+ }
62
+ end
63
+ end
64
+ end
data/spec/client_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  module Jimson
2
4
  describe Client do
3
5
  BOILERPLATE = {'jsonrpc' => '2.0', 'id' => 1}
@@ -10,6 +12,42 @@ module Jimson
10
12
  after(:each) do
11
13
  end
12
14
 
15
+ describe "hidden methods" do
16
+ it "should reveal inspect" do
17
+ Client.new(SPEC_URL).inspect.should match /Jimson::Client/
18
+ end
19
+
20
+ it "should reveal to_s" do
21
+ Client.new(SPEC_URL).to_s.should match /Jimson::Client/
22
+ end
23
+ end
24
+
25
+ describe "#[]" do
26
+ before(:each) do
27
+ expected = {
28
+ 'jsonrpc' => '2.0',
29
+ 'method' => 'foo',
30
+ 'params' => [1,2,3],
31
+ 'id' => 1
32
+ }.to_json
33
+ response = BOILERPLATE.merge({'result' => 42}).to_json
34
+ RestClient.should_receive(:post).with(SPEC_URL, expected, {:content_type => 'application/json'}).and_return(@resp_mock)
35
+ @resp_mock.should_receive(:body).at_least(:once).and_return(response)
36
+ @client = Client.new(SPEC_URL)
37
+ end
38
+
39
+ context "when using an array of args" do
40
+ it "sends a request with the correct method and args" do
41
+ @client['foo', [1,2,3]].should == 42
42
+ end
43
+ end
44
+ context "when using a splat for args" do
45
+ it "sends a request with the correct method and args" do
46
+ @client['foo', 1, 2, 3].should == 42
47
+ end
48
+ end
49
+ end
50
+
13
51
  describe "sending a single request" do
14
52
  context "when using positional parameters" do
15
53
  before(:each) do
@@ -73,5 +111,17 @@ module Jimson
73
111
  end
74
112
  end
75
113
 
114
+ describe "error handling" do
115
+ context "when an error occurs in the Jimson::Client code" do
116
+ it "tags the raised exception with Jimson::Client::Error" do
117
+ client_helper = ClientHelper.new(SPEC_URL)
118
+ ClientHelper.stub!(:new).and_return(client_helper)
119
+ client = Client.new(SPEC_URL)
120
+ client_helper.stub!(:send_single_request).and_raise "intentional error"
121
+ lambda { client.foo }.should raise_error(Jimson::Client::Error)
122
+ end
123
+ end
124
+ end
125
+
76
126
  end
77
127
  end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module Jimson
4
+ describe Handler do
5
+
6
+ class FooHandler
7
+ extend Jimson::Handler
8
+
9
+ jimson_expose :to_s, :bye
10
+
11
+ jimson_exclude :hi, :bye
12
+
13
+ def hi
14
+ 'hi'
15
+ end
16
+
17
+ def bye
18
+ 'bye'
19
+ end
20
+
21
+ def to_s
22
+ 'foo'
23
+ end
24
+
25
+ def so_exposed
26
+ "I'm so exposed!"
27
+ end
28
+ end
29
+
30
+ let(:foo) { FooHandler.new }
31
+
32
+ describe "#jimson_expose" do
33
+ it "exposes a method even if it was defined on Object" do
34
+ foo.class.jimson_exposed_methods.should include(:to_s)
35
+ end
36
+ end
37
+
38
+ describe "#jimson_exclude" do
39
+ context "when a method was not explicitly exposed" do
40
+ it "excludes the method" do
41
+ foo.class.jimson_exposed_methods.should_not include(:hi)
42
+ end
43
+ end
44
+ context "when a method was explicitly exposed" do
45
+ it "does not exclude the method" do
46
+ foo.class.jimson_exposed_methods.should include(:bye)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#jimson_exposed_methods" do
52
+ it "doesn't include methods defined on Object" do
53
+ foo.class.jimson_exposed_methods.should_not include(:object_id)
54
+ end
55
+ it "includes methods defined on the extending class but not on Object" do
56
+ foo.class.jimson_exposed_methods.should include(:so_exposed)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+
data/spec/server_spec.rb CHANGED
@@ -1,7 +1,37 @@
1
1
  require 'spec_helper'
2
+ require 'rack/test'
2
3
 
3
4
  module Jimson
4
5
  describe Server do
6
+ include Rack::Test::Methods
7
+
8
+ class TestHandler
9
+ extend Jimson::Handler
10
+
11
+ def subtract(a, b = nil)
12
+ if a.is_a?(Hash)
13
+ return a['minuend'] - a['subtrahend']
14
+ else
15
+ return a - b
16
+ end
17
+ end
18
+
19
+ def sum(a,b,c)
20
+ a + b + c
21
+ end
22
+
23
+ def notify_hello(*args)
24
+ # notification, doesn't do anything
25
+ end
26
+
27
+ def update(*args)
28
+ # notification, doesn't do anything
29
+ end
30
+
31
+ def get_data
32
+ ['hello', 5]
33
+ end
34
+ end
5
35
 
6
36
  INVALID_RESPONSE_EXPECTATION = {
7
37
  'jsonrpc' => '2.0',
@@ -11,6 +41,14 @@ module Jimson
11
41
  },
12
42
  'id' => nil
13
43
  }
44
+ def app
45
+ Server.new(TestHandler.new)
46
+ end
47
+
48
+ def post_json(hash)
49
+ post '/', hash.to_json, {'Content-Type' => 'application/json'}
50
+ end
51
+
14
52
  before(:each) do
15
53
  @url = SPEC_URL
16
54
  end
@@ -24,7 +62,10 @@ module Jimson
24
62
  'params' => [24, 20],
25
63
  'id' => 1
26
64
  }
27
- resp = JSON.parse(RestClient.post(@url, req.to_json).body)
65
+ post_json(req)
66
+
67
+ last_response.should be_ok
68
+ resp = JSON.parse(last_response.body)
28
69
  resp.should == {
29
70
  'jsonrpc' => '2.0',
30
71
  'result' => 4,
@@ -43,7 +84,10 @@ module Jimson
43
84
  'params' => {'subtrahend'=> 20, 'minuend' => 24},
44
85
  'id' => 1
45
86
  }
46
- resp = JSON.parse(RestClient.post(@url, req.to_json).body)
87
+ post_json(req)
88
+
89
+ last_response.should be_ok
90
+ resp = JSON.parse(last_response.body)
47
91
  resp.should == {
48
92
  'jsonrpc' => '2.0',
49
93
  'result' => 4,
@@ -61,8 +105,8 @@ module Jimson
61
105
  'method' => 'update',
62
106
  'params' => [1,2,3,4,5]
63
107
  }
64
- resp = RestClient.post(@url, req.to_json).body
65
- resp.should be_empty
108
+ post_json(req)
109
+ last_response.body.should be_empty
66
110
  end
67
111
  end
68
112
  end
@@ -74,12 +118,35 @@ module Jimson
74
118
  'method' => 'foobar',
75
119
  'id' => 1
76
120
  }
77
- resp = JSON.parse(RestClient.post(@url, req.to_json).body)
121
+ post_json(req)
122
+
123
+ resp = JSON.parse(last_response.body)
124
+ resp.should == {
125
+ 'jsonrpc' => '2.0',
126
+ 'error' => {
127
+ 'code' => -32601,
128
+ 'message' => "Method 'foobar' not found."
129
+ },
130
+ 'id' => 1
131
+ }
132
+ end
133
+ end
134
+
135
+ describe "receiving a call for a method which exists but is not exposed" do
136
+ it "returns an error response" do
137
+ req = {
138
+ 'jsonrpc' => '2.0',
139
+ 'method' => 'object_id',
140
+ 'id' => 1
141
+ }
142
+ post_json(req)
143
+
144
+ resp = JSON.parse(last_response.body)
78
145
  resp.should == {
79
146
  'jsonrpc' => '2.0',
80
147
  'error' => {
81
148
  'code' => -32601,
82
- 'message' => 'Method not found.'
149
+ 'message' => "Method 'object_id' not found."
83
150
  },
84
151
  'id' => 1
85
152
  }
@@ -94,7 +161,9 @@ module Jimson
94
161
  'params' => [1,2,3],
95
162
  'id' => 1
96
163
  }
97
- resp = JSON.parse(RestClient.post(@url, req.to_json).body)
164
+ post_json(req)
165
+
166
+ resp = JSON.parse(last_response.body)
98
167
  resp.should == {
99
168
  'jsonrpc' => '2.0',
100
169
  'error' => {
@@ -114,7 +183,9 @@ module Jimson
114
183
  'id' => 1
115
184
  }.to_json
116
185
  req += '}' # make the json invalid
117
- resp = JSON.parse(RestClient.post(@url, req).body)
186
+ post '/', req, {'Content-type' => 'application/json'}
187
+
188
+ resp = JSON.parse(last_response.body)
118
189
  resp.should == {
119
190
  'jsonrpc' => '2.0',
120
191
  'error' => {
@@ -132,24 +203,27 @@ module Jimson
132
203
  req = {
133
204
  'jsonrpc' => '2.0',
134
205
  'method' => 1 # method as int is invalid
135
- }.to_json
136
- resp = JSON.parse(RestClient.post(@url, req).body)
206
+ }
207
+ post_json(req)
208
+ resp = JSON.parse(last_response.body)
137
209
  resp.should == INVALID_RESPONSE_EXPECTATION
138
210
  end
139
211
  end
140
212
 
141
213
  context "when the request is an empty batch" do
142
214
  it "returns an error response" do
143
- req = [].to_json
144
- resp = JSON.parse(RestClient.post(@url, req).body)
215
+ req = []
216
+ post_json(req)
217
+ resp = JSON.parse(last_response.body)
145
218
  resp.should == INVALID_RESPONSE_EXPECTATION
146
219
  end
147
220
  end
148
221
 
149
222
  context "when the request is an invalid batch" do
150
223
  it "returns an error response" do
151
- req = [1,2].to_json
152
- resp = JSON.parse(RestClient.post(@url, req).body)
224
+ req = [1,2]
225
+ post_json(req)
226
+ resp = JSON.parse(last_response.body)
153
227
  resp.should == [INVALID_RESPONSE_EXPECTATION, INVALID_RESPONSE_EXPECTATION]
154
228
  end
155
229
  end
@@ -165,13 +239,14 @@ module Jimson
165
239
  {'foo' => 'boo'},
166
240
  {'jsonrpc' => '2.0', 'method' => 'foo.get', 'params' => {'name' => 'myself'}, 'id' => '5'},
167
241
  {'jsonrpc' => '2.0', 'method' => 'get_data', 'id' => '9'}
168
- ].to_json
169
- resp = JSON.parse(RestClient.post(@url, reqs).body)
242
+ ]
243
+ post_json(reqs)
244
+ resp = JSON.parse(last_response.body)
170
245
  resp.should == [
171
246
  {'jsonrpc' => '2.0', 'result' => 7, 'id' => '1'},
172
247
  {'jsonrpc' => '2.0', 'result' => 19, 'id' => '2'},
173
248
  {'jsonrpc' => '2.0', 'error' => {'code' => -32600, 'message' => 'The JSON sent is not a valid Request object.'}, 'id' => nil},
174
- {'jsonrpc' => '2.0', 'error' => {'code' => -32601, 'message' => 'Method not found.'}, 'id' => '5'},
249
+ {'jsonrpc' => '2.0', 'error' => {'code' => -32601, 'message' => "Method 'foo.get' not found."}, 'id' => '5'},
175
250
  {'jsonrpc' => '2.0', 'result' => ['hello', 5], 'id' => '9'}
176
251
  ]
177
252
  end
@@ -191,11 +266,51 @@ module Jimson
191
266
  'params' => [1,2,3,4,5]
192
267
  }
193
268
  ]
194
- resp = RestClient.post(@url, req.to_json).body
195
- resp.should be_empty
269
+ post_json(req)
270
+ last_response.body.should be_empty
196
271
  end
197
272
  end
198
273
  end
199
274
 
275
+ describe "receiving a 'system.' request" do
276
+ context "when the request is 'isAlive'" do
277
+ it "returns response 'true'" do
278
+ req = {
279
+ 'jsonrpc' => '2.0',
280
+ 'method' => 'system.isAlive',
281
+ 'params' => [],
282
+ 'id' => 1
283
+ }
284
+ post_json(req)
285
+
286
+ last_response.should be_ok
287
+ resp = JSON.parse(last_response.body)
288
+ resp.should == {
289
+ 'jsonrpc' => '2.0',
290
+ 'result' => true,
291
+ 'id' => 1
292
+ }
293
+ end
294
+ end
295
+ context "when the request is 'listMethods'" do
296
+ it "returns response with all listMethods on the handler as strings" do
297
+ req = {
298
+ 'jsonrpc' => '2.0',
299
+ 'method' => 'system.listMethods',
300
+ 'params' => [],
301
+ 'id' => 1
302
+ }
303
+ post_json(req)
304
+
305
+ last_response.should be_ok
306
+ resp = JSON.parse(last_response.body)
307
+ resp.should == {
308
+ 'jsonrpc' => '2.0',
309
+ 'result' => ['subtract', 'sum', 'notify_hello', 'update', 'get_data'].sort,
310
+ 'id' => 1
311
+ }
312
+ end
313
+ end
314
+ end
200
315
  end
201
316
  end
data/spec/spec_helper.rb CHANGED
@@ -2,18 +2,6 @@ require 'rubygems'
2
2
  $:.unshift(File.dirname(__FILE__) + '/../lib/')
3
3
  require 'jimson/server'
4
4
  require 'jimson/client'
5
- require 'open-uri'
6
5
  require 'json'
7
6
 
8
7
  SPEC_URL = 'http://localhost:8999'
9
-
10
- pid = Process.spawn(File.dirname(__FILE__) + '/server_helper.rb')
11
-
12
- RSpec.configure do |config|
13
- config.after(:all) do
14
- Process.kill(9, pid)
15
- end
16
- end
17
-
18
- sleep 1
19
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jimson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-11 00:00:00.000000000Z
12
+ date: 2011-09-07 00:00:00.000000000Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: blankslate
16
+ requirement: &13756100 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.1.2.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *13756100
14
25
  - !ruby/object:Gem::Dependency
15
26
  name: rest-client
16
- requirement: &12229180 !ruby/object:Gem::Requirement
27
+ requirement: &13755420 !ruby/object:Gem::Requirement
17
28
  none: false
18
29
  requirements:
19
30
  - - ! '>='
@@ -21,10 +32,10 @@ dependencies:
21
32
  version: 1.6.3
22
33
  type: :runtime
23
34
  prerelease: false
24
- version_requirements: *12229180
35
+ version_requirements: *13755420
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: json
27
- requirement: &12228700 !ruby/object:Gem::Requirement
38
+ requirement: &13754820 !ruby/object:Gem::Requirement
28
39
  none: false
29
40
  requirements:
30
41
  - - ! '>='
@@ -32,10 +43,10 @@ dependencies:
32
43
  version: 1.5.1
33
44
  type: :runtime
34
45
  prerelease: false
35
- version_requirements: *12228700
46
+ version_requirements: *13754820
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: rack
38
- requirement: &12225120 !ruby/object:Gem::Requirement
49
+ requirement: &13754200 !ruby/object:Gem::Requirement
39
50
  none: false
40
51
  requirements:
41
52
  - - ! '>='
@@ -43,29 +54,30 @@ dependencies:
43
54
  version: '1.3'
44
55
  type: :runtime
45
56
  prerelease: false
46
- version_requirements: *12225120
57
+ version_requirements: *13754200
47
58
  description:
48
59
  email:
49
60
  executables: []
50
61
  extensions: []
51
62
  extra_rdoc_files:
52
- - README.rdoc
63
+ - README.md
53
64
  files:
54
65
  - VERSION
55
66
  - LICENSE.txt
56
67
  - CHANGELOG.rdoc
57
- - README.rdoc
68
+ - README.md
58
69
  - Rakefile
59
70
  - lib/jimson.rb
60
- - lib/jimson/client_error.rb
71
+ - lib/jimson/server/error.rb
72
+ - lib/jimson/handler.rb
61
73
  - lib/jimson/server.rb
62
- - lib/jimson/server_error.rb
63
74
  - lib/jimson/response.rb
75
+ - lib/jimson/client/error.rb
64
76
  - lib/jimson/request.rb
65
77
  - lib/jimson/client.rb
78
+ - spec/handler_spec.rb
66
79
  - spec/server_spec.rb
67
80
  - spec/client_spec.rb
68
- - spec/server_helper.rb
69
81
  - spec/spec_helper.rb
70
82
  homepage: http://www.github.com/chriskite/jimson
71
83
  licenses: []
@@ -92,7 +104,7 @@ signing_key:
92
104
  specification_version: 3
93
105
  summary: JSON-RPC 2.0 client and server
94
106
  test_files:
107
+ - spec/handler_spec.rb
95
108
  - spec/server_spec.rb
96
109
  - spec/client_spec.rb
97
- - spec/server_helper.rb
98
110
  - spec/spec_helper.rb
data/README.rdoc DELETED
File without changes
@@ -1,31 +0,0 @@
1
- module Jimson
2
- module ClientError
3
- class Generic < Exception
4
- end
5
-
6
- class InvalidResponse < Generic
7
- def initialize()
8
- super('Invalid or empty response from server.')
9
- end
10
- end
11
-
12
- class InvalidJSON < Generic
13
- def initialize(json)
14
- super("Couldn't parse JSON string received from server:\n#{json}")
15
- end
16
- end
17
-
18
- class InternalError < Generic
19
- def initialize(e)
20
- super("An internal client error occurred when processing the request: #{e}\n#{e.backtrace.join("\n")}")
21
- end
22
- end
23
-
24
- class UnknownServerError < Generic
25
- def initialize(code, message)
26
- super("The server specified an error the client doesn't know about: #{code} #{message}")
27
- end
28
- end
29
-
30
- end
31
- end
@@ -1,64 +0,0 @@
1
- module Jimson
2
- module ServerError
3
- class Generic < Exception
4
- attr_accessor :code, :message
5
-
6
- def initialize(code, message)
7
- @code = code
8
- @message = message
9
- super(message)
10
- end
11
-
12
- def to_h
13
- {
14
- 'code' => @code,
15
- 'message' => @message
16
- }
17
- end
18
- end
19
-
20
- class ParseError < Generic
21
- def initialize
22
- super(-32700, 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.')
23
- end
24
- end
25
-
26
- class InvalidRequest < Generic
27
- def initialize
28
- super(-32600, 'The JSON sent is not a valid Request object.')
29
- end
30
- end
31
-
32
- class MethodNotFound < Generic
33
- def initialize
34
- super(-32601, 'Method not found.')
35
- end
36
- end
37
-
38
- class InvalidParams < Generic
39
- def initialize
40
- super(-32602, 'Invalid method parameter(s).')
41
- end
42
- end
43
-
44
- class InternalError < Generic
45
- def initialize
46
- super(-32603, 'Internal server error.')
47
- end
48
- end
49
-
50
- class ApplicationError < Generic
51
- def initialize(err)
52
- super(-32099, "The application being served raised an error: #{err}")
53
- end
54
- end
55
-
56
- CODES = {
57
- -32700 => ParseError,
58
- -32600 => InvalidRequest,
59
- -32601 => MethodNotFound,
60
- -32602 => InvalidParams,
61
- -32603 => InternalError
62
- }
63
- end
64
- end
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- $:.unshift(File.dirname(__FILE__) + '/../lib/')
5
- require 'jimson'
6
-
7
- class TestHandler
8
- def subtract(a, b = nil)
9
- if a.is_a?(Hash)
10
- return a['minuend'] - a['subtrahend']
11
- else
12
- return a - b
13
- end
14
- end
15
-
16
- def sum(a,b,c)
17
- a + b + c
18
- end
19
-
20
- def notify_hello(*args)
21
- # notification, doesn't do anything
22
- end
23
-
24
- def update(*args)
25
- # notification, doesn't do anything
26
- end
27
-
28
- def get_data
29
- ['hello', 5]
30
- end
31
- end
32
-
33
- server = Jimson::Server.new(TestHandler.new)
34
- server.start