jimson 0.6.0 → 0.7.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/CHANGELOG.rdoc +10 -0
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/lib/jimson.rb +1 -0
- data/lib/jimson/router.rb +24 -0
- data/lib/jimson/router/map.rb +73 -0
- data/lib/jimson/server.rb +26 -24
- data/lib/jimson/server/error.rb +1 -1
- data/spec/router_spec.rb +67 -0
- data/spec/server_spec.rb +48 -9
- data/spec/spec_helper.rb +1 -2
- metadata +35 -11
data/CHANGELOG.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -14,7 +14,12 @@ end
|
|
14
14
|
|
15
15
|
task :default => :rspec
|
16
16
|
|
17
|
-
|
17
|
+
begin
|
18
|
+
require 'rdoc/task'
|
19
|
+
rescue LoadError
|
20
|
+
require 'rake/rdoctask'
|
21
|
+
end
|
22
|
+
|
18
23
|
Rake::RDocTask.new do |rdoc|
|
19
24
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
20
25
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/lib/jimson.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'jimson/router/map'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Jimson
|
5
|
+
class Router
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@map, :handler_for_method,
|
9
|
+
:root,
|
10
|
+
:namespace,
|
11
|
+
:jimson_methods,
|
12
|
+
:strip_method_namespace
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@map = Map.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw(&block)
|
19
|
+
@map.instance_eval &block
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Jimson
|
2
|
+
class Router
|
3
|
+
|
4
|
+
#
|
5
|
+
# Provides a DSL for routing method namespaces to handlers.
|
6
|
+
# Only handles root-level and non-nested namespaces, e.g. 'foo.bar' or 'foo'.
|
7
|
+
#
|
8
|
+
class Map
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@routes = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Set the root handler, i.e. the handler used for a bare method like 'foo'
|
16
|
+
#
|
17
|
+
def root(handler)
|
18
|
+
@routes[''] = handler
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Define the handler for a namespace
|
23
|
+
#
|
24
|
+
def namespace(ns, handler = nil, &block)
|
25
|
+
if !!handler
|
26
|
+
@routes[ns.to_s] = handler
|
27
|
+
else
|
28
|
+
# passed a block for nested namespacing
|
29
|
+
map = Jimson::Router::Map.new
|
30
|
+
@routes[ns.to_s] = map
|
31
|
+
map.instance_eval &block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Return the handler for a (possibly namespaced) method name
|
37
|
+
#
|
38
|
+
def handler_for_method(method)
|
39
|
+
parts = method.split('.')
|
40
|
+
ns = (method.index('.') == nil ? '' : parts.first)
|
41
|
+
handler = @routes[ns]
|
42
|
+
if handler.is_a?(Jimson::Router::Map)
|
43
|
+
return handler.handler_for_method(parts[1..-1].join('.'))
|
44
|
+
end
|
45
|
+
handler
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Strip off the namespace part of a method and return the bare method name
|
50
|
+
#
|
51
|
+
def strip_method_namespace(method)
|
52
|
+
method.split('.').last
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Return an array of all methods on handlers in the map, fully namespaced
|
57
|
+
#
|
58
|
+
def jimson_methods
|
59
|
+
arr = @routes.keys.map do |ns|
|
60
|
+
prefix = (ns == '' ? '' : "#{ns}.")
|
61
|
+
handler = @routes[ns]
|
62
|
+
if handler.is_a?(Jimson::Router::Map)
|
63
|
+
handler.jimson_methods
|
64
|
+
else
|
65
|
+
handler.class.jimson_exposed_methods.map { |method| prefix + method }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
arr.flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/jimson/server.rb
CHANGED
@@ -3,6 +3,7 @@ require 'rack/request'
|
|
3
3
|
require 'rack/response'
|
4
4
|
require 'multi_json'
|
5
5
|
require 'jimson/handler'
|
6
|
+
require 'jimson/router'
|
6
7
|
require 'jimson/server/error'
|
7
8
|
|
8
9
|
module Jimson
|
@@ -11,12 +12,12 @@ module Jimson
|
|
11
12
|
class System
|
12
13
|
extend Handler
|
13
14
|
|
14
|
-
def initialize(
|
15
|
-
@
|
15
|
+
def initialize(router)
|
16
|
+
@router = router
|
16
17
|
end
|
17
18
|
|
18
19
|
def listMethods
|
19
|
-
@
|
20
|
+
@router.jimson_methods
|
20
21
|
end
|
21
22
|
|
22
23
|
def isAlive
|
@@ -26,10 +27,10 @@ module Jimson
|
|
26
27
|
|
27
28
|
JSON_RPC_VERSION = '2.0'
|
28
29
|
|
29
|
-
attr_accessor :
|
30
|
+
attr_accessor :router, :host, :port, :opts
|
30
31
|
|
31
32
|
#
|
32
|
-
# +
|
33
|
+
# +router_or_handler+ is an instance of Jimson::Router or extends Jimson::Handler
|
33
34
|
#
|
34
35
|
# +opts+ may include:
|
35
36
|
# * :host - the hostname or ip to bind to
|
@@ -38,8 +39,17 @@ module Jimson
|
|
38
39
|
#
|
39
40
|
# Remaining options are forwarded to the underlying Rack server.
|
40
41
|
#
|
41
|
-
def initialize(
|
42
|
-
|
42
|
+
def initialize(router_or_handler, opts = {})
|
43
|
+
if !router_or_handler.is_a?(Router)
|
44
|
+
# arg is a handler, wrap it in a Router
|
45
|
+
@router = Router.new
|
46
|
+
@router.root router_or_handler
|
47
|
+
else
|
48
|
+
# arg is a router
|
49
|
+
@router = router_or_handler
|
50
|
+
end
|
51
|
+
@router.namespace 'system', System.new(@router)
|
52
|
+
|
43
53
|
@host = opts.delete(:host) || '0.0.0.0'
|
44
54
|
@port = opts.delete(:port) || 8999
|
45
55
|
@opts = opts
|
@@ -153,30 +163,22 @@ module Jimson
|
|
153
163
|
end
|
154
164
|
|
155
165
|
def dispatch_request(method, params)
|
156
|
-
|
157
|
-
handler = @
|
158
|
-
|
159
|
-
# switch to the System handler if a system method was called
|
160
|
-
sys_regex = /^system\./
|
161
|
-
if method =~ sys_regex
|
162
|
-
handler = System.new(@handler)
|
163
|
-
# remove the 'system.' prefix before from the method name
|
164
|
-
method.gsub!(sys_regex, '')
|
165
|
-
end
|
166
|
-
|
167
|
-
method = method.to_s
|
166
|
+
method_name = method.to_s
|
167
|
+
handler = @router.handler_for_method(method_name)
|
168
|
+
method_name = @router.strip_method_namespace(method_name)
|
168
169
|
|
169
|
-
if
|
170
|
-
|
170
|
+
if handler.nil? \
|
171
|
+
|| !handler.class.jimson_exposed_methods.include?(method_name) \
|
172
|
+
|| !handler.respond_to?(method_name)
|
171
173
|
raise Server::Error::MethodNotFound.new(method)
|
172
174
|
end
|
173
175
|
|
174
176
|
if params.nil?
|
175
|
-
return handler.send(
|
177
|
+
return handler.send(method_name)
|
176
178
|
elsif params.is_a?(Hash)
|
177
|
-
return handler.send(
|
179
|
+
return handler.send(method_name, params)
|
178
180
|
else
|
179
|
-
return handler.send(
|
181
|
+
return handler.send(method_name, *params)
|
180
182
|
end
|
181
183
|
end
|
182
184
|
|
data/lib/jimson/server/error.rb
CHANGED
data/spec/router_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Jimson
|
4
|
+
describe Router do
|
5
|
+
|
6
|
+
let(:router) { Router.new }
|
7
|
+
|
8
|
+
class RouterFooHandler
|
9
|
+
extend Jimson::Handler
|
10
|
+
|
11
|
+
def hi
|
12
|
+
'hi'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class RouterBarHandler
|
17
|
+
extend Jimson::Handler
|
18
|
+
|
19
|
+
def bye
|
20
|
+
'bye'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
describe '#draw' do
|
26
|
+
context 'when given non-nested namespaces' do
|
27
|
+
it 'takes a block with a DSL to set the root and namespaces' do
|
28
|
+
router.draw do
|
29
|
+
root 'foo'
|
30
|
+
namespace 'ns', 'bar'
|
31
|
+
end
|
32
|
+
|
33
|
+
router.handler_for_method('hi').should == 'foo'
|
34
|
+
router.handler_for_method('ns.hi').should == 'bar'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when given nested namespaces' do
|
39
|
+
it 'takes a block with a DSL to set the root and namespaces' do
|
40
|
+
router.draw do
|
41
|
+
root 'foo'
|
42
|
+
namespace 'ns1' do
|
43
|
+
root 'blah'
|
44
|
+
namespace 'ns2', 'bar'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
router.handler_for_method('hi').should == 'foo'
|
49
|
+
router.handler_for_method('ns1.hi').should == 'blah'
|
50
|
+
router.handler_for_method('ns1.ns2.hi').should == 'bar'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#jimson_methods' do
|
56
|
+
it 'returns an array of namespaced method names from all registered handlers' do
|
57
|
+
router.draw do
|
58
|
+
root RouterFooHandler.new
|
59
|
+
namespace 'foo', RouterBarHandler.new
|
60
|
+
end
|
61
|
+
|
62
|
+
router.jimson_methods.should == ['hi', 'foo.bye']
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/spec/server_spec.rb
CHANGED
@@ -31,6 +31,18 @@ module Jimson
|
|
31
31
|
def get_data
|
32
32
|
['hello', 5]
|
33
33
|
end
|
34
|
+
|
35
|
+
def ugly_method
|
36
|
+
raise RuntimeError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class OtherHandler
|
41
|
+
extend Jimson::Handler
|
42
|
+
|
43
|
+
def multiply(a,b)
|
44
|
+
a * b
|
45
|
+
end
|
34
46
|
end
|
35
47
|
|
36
48
|
INVALID_RESPONSE_EXPECTATION = {
|
@@ -41,8 +53,15 @@ module Jimson
|
|
41
53
|
},
|
42
54
|
'id' => nil
|
43
55
|
}
|
44
|
-
|
45
|
-
|
56
|
+
let(:router) do
|
57
|
+
router = Router.new.draw do
|
58
|
+
root TestHandler.new
|
59
|
+
namespace 'other', OtherHandler.new
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:app) do
|
64
|
+
Server.new(router, :environment => "production")
|
46
65
|
end
|
47
66
|
|
48
67
|
def post_json(hash)
|
@@ -197,6 +216,27 @@ module Jimson
|
|
197
216
|
end
|
198
217
|
end
|
199
218
|
|
219
|
+
describe "receiving a call for ugly method" do
|
220
|
+
it "returns only global error without stack trace" do
|
221
|
+
req = {
|
222
|
+
'jsonrpc' => '2.0',
|
223
|
+
'method' => 'ugly_method',
|
224
|
+
'id' => 1
|
225
|
+
}
|
226
|
+
post_json(req)
|
227
|
+
|
228
|
+
resp = MultiJson.decode(last_response.body)
|
229
|
+
resp.should == {
|
230
|
+
'jsonrpc' => '2.0',
|
231
|
+
'error' => {
|
232
|
+
'code' => -32099,
|
233
|
+
'message' => 'Server application error'
|
234
|
+
},
|
235
|
+
'id' => 1
|
236
|
+
}
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
200
240
|
describe "receiving invalid JSON" do
|
201
241
|
it "returns an error response" do
|
202
242
|
req = MultiJson.encode({
|
@@ -314,8 +354,8 @@ module Jimson
|
|
314
354
|
}
|
315
355
|
end
|
316
356
|
end
|
317
|
-
context "when the request is 'listMethods'" do
|
318
|
-
it "returns response with all
|
357
|
+
context "when the request is 'system.listMethods'" do
|
358
|
+
it "returns response with all jimson_exposed_methods on the handler(s) as strings" do
|
319
359
|
req = {
|
320
360
|
'jsonrpc' => '2.0',
|
321
361
|
'method' => 'system.listMethods',
|
@@ -326,11 +366,10 @@ module Jimson
|
|
326
366
|
|
327
367
|
last_response.should be_ok
|
328
368
|
resp = MultiJson.decode(last_response.body)
|
329
|
-
resp.should ==
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
}
|
369
|
+
resp['jsonrpc'].should == '2.0'
|
370
|
+
resp['id'].should == 1
|
371
|
+
expected = ['get_data', 'notify_hello', 'subtract', 'sum', 'ugly_method', 'update', 'system.isAlive', 'system.listMethods', 'other.multiply']
|
372
|
+
(resp['result'] - expected).should == []
|
334
373
|
end
|
335
374
|
end
|
336
375
|
end
|
data/spec/spec_helper.rb
CHANGED
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.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: blankslate
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: 2.1.2.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.1.2.3
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rest-client
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: 1.6.3
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.6.3
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: multi_json
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: 1.1.0
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.1.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rack
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,7 +69,12 @@ dependencies:
|
|
54
69
|
version: '1.3'
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.3'
|
58
78
|
description:
|
59
79
|
email:
|
60
80
|
executables: []
|
@@ -68,7 +88,9 @@ files:
|
|
68
88
|
- README.md
|
69
89
|
- Rakefile
|
70
90
|
- lib/jimson/request.rb
|
91
|
+
- lib/jimson/router.rb
|
71
92
|
- lib/jimson/response.rb
|
93
|
+
- lib/jimson/router/map.rb
|
72
94
|
- lib/jimson/server.rb
|
73
95
|
- lib/jimson/client/error.rb
|
74
96
|
- lib/jimson/client.rb
|
@@ -76,6 +98,7 @@ files:
|
|
76
98
|
- lib/jimson/server/error.rb
|
77
99
|
- lib/jimson.rb
|
78
100
|
- spec/spec_helper.rb
|
101
|
+
- spec/router_spec.rb
|
79
102
|
- spec/client_spec.rb
|
80
103
|
- spec/handler_spec.rb
|
81
104
|
- spec/server_spec.rb
|
@@ -99,12 +122,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
122
|
version: '0'
|
100
123
|
requirements: []
|
101
124
|
rubyforge_project:
|
102
|
-
rubygems_version: 1.8.
|
125
|
+
rubygems_version: 1.8.21
|
103
126
|
signing_key:
|
104
127
|
specification_version: 3
|
105
128
|
summary: JSON-RPC 2.0 client and server
|
106
129
|
test_files:
|
107
130
|
- spec/spec_helper.rb
|
131
|
+
- spec/router_spec.rb
|
108
132
|
- spec/client_spec.rb
|
109
133
|
- spec/handler_spec.rb
|
110
134
|
- spec/server_spec.rb
|