jimson 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,13 @@
1
+ == 0.7.0 / 2012-04-13
2
+
3
+ * Major enhancements
4
+
5
+ * Add namespaced routing
6
+
7
+ * Bug fixes
8
+
9
+ * Fix deprecation warning about RDoc task in Rakefile
10
+
1
11
  == 0.6.0 / 2012-03-14
2
12
 
3
13
  * Minor enhancements
data/Rakefile CHANGED
@@ -14,7 +14,12 @@ end
14
14
 
15
15
  task :default => :rspec
16
16
 
17
- require 'rake/rdoctask'
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.6.0
1
+ 0.7.0
data/lib/jimson.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'jimson/handler'
3
+ require 'jimson/router'
3
4
  require 'jimson/server'
4
5
  require 'jimson/client'
5
6
 
@@ -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(handler)
15
- @handler = handler
15
+ def initialize(router)
16
+ @router = router
16
17
  end
17
18
 
18
19
  def listMethods
19
- @handler.class.jimson_exposed_methods
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 :handler, :host, :port, :opts
30
+ attr_accessor :router, :host, :port, :opts
30
31
 
31
32
  #
32
- # +handler+ is an instance of the class to expose as a JSON-RPC server
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(handler, opts = {})
42
- @handler = handler
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
- # normally route requests to the user-suplied handler
157
- handler = @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 !handler.class.jimson_exposed_methods.include?(method) \
170
- || !handler.respond_to?(method)
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(method)
177
+ return handler.send(method_name)
176
178
  elsif params.is_a?(Hash)
177
- return handler.send(method, params)
179
+ return handler.send(method_name, params)
178
180
  else
179
- return handler.send(method, *params)
181
+ return handler.send(method_name, *params)
180
182
  end
181
183
  end
182
184
 
@@ -48,7 +48,7 @@ module Jimson
48
48
 
49
49
  class ApplicationError < Error
50
50
  def initialize(err)
51
- super(-32099, "Application error: #{err} #{err.backtrace.join("\n")}")
51
+ super(-32099, "Server application error")
52
52
  end
53
53
  end
54
54
 
@@ -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
- def app
45
- Server.new(TestHandler.new, :environment => "production")
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 listMethods on the handler as strings" do
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
- 'jsonrpc' => '2.0',
331
- 'result' => ['subtract', 'sum', 'notify_hello', 'update', 'get_data'].sort,
332
- 'id' => 1
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
@@ -1,7 +1,6 @@
1
1
  require 'rubygems'
2
2
  $:.unshift(File.dirname(__FILE__) + '/../lib/')
3
- require 'jimson/server'
4
- require 'jimson/client'
3
+ require 'jimson'
5
4
  require 'bundler/setup'
6
5
  require 'multi_json'
7
6
 
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.6.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-03-14 00:00:00.000000000Z
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: &18659080 !ruby/object:Gem::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: *18659080
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: &18658140 !ruby/object:Gem::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: *18658140
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: &18657580 !ruby/object:Gem::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: *18657580
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: &18656860 !ruby/object:Gem::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: *18656860
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.15
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