clamo 0.9.0 → 0.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/README.md +18 -40
- data/lib/clamo/jsonrpc.rb +18 -16
- data/lib/clamo/server.rb +101 -70
- data/lib/clamo/version.rb +1 -1
- metadata +2 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7596405122290bf9bce3c04760bbb5e03eef24f8e5e6b3c6e99105c8faa7d14e
|
|
4
|
+
data.tar.gz: 219e2f1f54ffd99c03dcde0c18508d24625904daa2aa65f5c7c1aabbfacee11c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7d6a2c1407df2fc1427a7c95500d07f4873660c2322bcd4ae1a4f642550e89d6a723e7854f2126404f985446432a8e59e2690873d28ff25b218e1f01e260898a
|
|
7
|
+
data.tar.gz: eb941c6f05333536695f9f3d6531de593b592653b17c6fb5a10e18c5cca693c6cb2fe3e922a25f17c5a1bf3d90fae8b518674b14fc78b7b2926deff1f3d7223b
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.12.0] - 2026-03-14
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Extracted `error_for` helper to centralize notification-aware error responses, replacing scattered `request.key?("id") ? error : nil` pattern.
|
|
12
|
+
- Split `validate_request_structure` into envelope validation and `validate_params_type`, making the single-request pipeline a clear 5-stage chain.
|
|
13
|
+
- Removed `method_not_found_error` and `arity_mismatch_error` one-liner wrappers (replaced by `error_for` calls).
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `server_error_response` test helper, completing the error response helper set.
|
|
18
|
+
- Test for arity-mismatch notification returning nil.
|
|
19
|
+
|
|
20
|
+
## [0.11.0] - 2026-03-14
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **Breaking:** `dispatch` is now the canonical name for `parsed_dispatch_to_object`. The old name remains as a deprecated alias.
|
|
25
|
+
- **Breaking:** `dispatch_json` is now the canonical name for `unparsed_dispatch_to_object`. The old name remains as a deprecated alias.
|
|
26
|
+
- **Breaking:** `handle_json` is now the canonical name for `handle`. The old name remains as a deprecated alias.
|
|
27
|
+
|
|
28
|
+
## [0.10.0] - 2026-03-14
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- **Breaking:** `timeout` configuration and `Timeout.timeout` wrapping — Ruby's `Timeout.timeout` is unsafe (can fire during `ensure`, IO, or lock acquisition). Callers who need timeouts should wrap dispatch externally.
|
|
33
|
+
- **Breaking:** `before_dispatch` and `after_dispatch` hooks — callers can wrap `dispatch` calls directly for the same effect with less coupling.
|
|
34
|
+
- `parallel` as a runtime dependency — it is now loaded on demand. Batch requests fall back to sequential `map` when the gem is not installed.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **Arity validation** — parameter count and keyword names are checked against the Ruby method signature before dispatch. Mismatches return `-32602 Invalid params` instead of the previous `-32603 Internal error`.
|
|
39
|
+
- `Clamo::Server.dispatch` — alias for `parsed_dispatch_to_object`.
|
|
40
|
+
- `Clamo::Server.dispatch_json` — alias for `unparsed_dispatch_to_object`.
|
|
41
|
+
- Concurrency tests for thread-safe dispatch.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- `Config` simplified to `Data.define(:on_error)` (was `Data.define(:timeout, :on_error, :before_dispatch, :after_dispatch)`).
|
|
46
|
+
- `parsed_dispatch_to_object` signature reduced to `(request:, object:, on_error:, **opts)`.
|
|
47
|
+
|
|
7
48
|
## [0.9.0] - 2026-03-14
|
|
8
49
|
|
|
9
50
|
### Changed
|
data/README.md
CHANGED
|
@@ -28,30 +28,32 @@ end
|
|
|
28
28
|
|
|
29
29
|
# JSON string in, JSON string out — the primary entry point for HTTP/socket integrations.
|
|
30
30
|
# Returns nil for notifications (no response expected).
|
|
31
|
-
json_response = Clamo::Server.
|
|
31
|
+
json_response = Clamo::Server.handle_json(
|
|
32
32
|
request: '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}',
|
|
33
33
|
object: MyService
|
|
34
34
|
)
|
|
35
35
|
# => '{"jsonrpc":"2.0","result":3,"id":1}'
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
If you need the parsed hash instead of a JSON string, use the lower-level methods:
|
|
38
|
+
If you need the parsed hash instead of a JSON string, use the lower-level methods directly or via their shorter aliases:
|
|
39
39
|
|
|
40
40
|
```ruby
|
|
41
41
|
# From a JSON string
|
|
42
|
-
response = Clamo::Server.
|
|
42
|
+
response = Clamo::Server.dispatch_json(
|
|
43
43
|
request: '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}',
|
|
44
44
|
object: MyService
|
|
45
45
|
)
|
|
46
46
|
# => {"jsonrpc" => "2.0", "result" => 3, "id" => 1}
|
|
47
47
|
|
|
48
48
|
# From a pre-parsed hash
|
|
49
|
-
response = Clamo::Server.
|
|
49
|
+
response = Clamo::Server.dispatch(
|
|
50
50
|
request: { "jsonrpc" => "2.0", "method" => "add", "params" => [1, 2], "id" => 1 },
|
|
51
51
|
object: MyService
|
|
52
52
|
)
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
The longer names `parsed_dispatch_to_object`, `unparsed_dispatch_to_object`, and `handle` still work as deprecated aliases.
|
|
56
|
+
|
|
55
57
|
### Handling Different Parameter Types
|
|
56
58
|
|
|
57
59
|
Clamo supports both positional (array) and named (object/hash) parameters:
|
|
@@ -76,7 +78,7 @@ batch_request = <<~JSON
|
|
|
76
78
|
]
|
|
77
79
|
JSON
|
|
78
80
|
|
|
79
|
-
batch_response = Clamo::Server.
|
|
81
|
+
batch_response = Clamo::Server.dispatch_json(
|
|
80
82
|
request: batch_request,
|
|
81
83
|
object: MyService
|
|
82
84
|
)
|
|
@@ -91,7 +93,7 @@ Notifications are requests without an ID field. They don't produce a response:
|
|
|
91
93
|
|
|
92
94
|
```ruby
|
|
93
95
|
notification = '{"jsonrpc": "2.0", "method": "add", "params": [1, 2]}'
|
|
94
|
-
response = Clamo::Server.
|
|
96
|
+
response = Clamo::Server.dispatch_json(
|
|
95
97
|
request: notification,
|
|
96
98
|
object: MyService
|
|
97
99
|
)
|
|
@@ -124,24 +126,17 @@ Clamo follows the JSON-RPC 2.0 specification for error handling:
|
|
|
124
126
|
| -32700 | Parse error | Invalid JSON was received |
|
|
125
127
|
| -32600 | Invalid request | The JSON sent is not a valid Request object |
|
|
126
128
|
| -32601 | Method not found | The method does not exist / is not available |
|
|
127
|
-
| -32602 | Invalid params | Invalid method parameter(s)
|
|
129
|
+
| -32602 | Invalid params | Invalid method parameter(s) or arity mismatch |
|
|
128
130
|
| -32603 | Internal error | Internal JSON-RPC error |
|
|
129
|
-
| -32000 | Server error |
|
|
130
|
-
|
|
131
|
-
## Configuration
|
|
132
|
-
|
|
133
|
-
### Timeout
|
|
131
|
+
| -32000 | Server error | Exception raised by dispatched method |
|
|
134
132
|
|
|
135
|
-
|
|
133
|
+
Parameter arity is validated before dispatch. If the number of positional arguments or keyword arguments doesn't match the Ruby method signature, a `-32602 Invalid params` error is returned.
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
Clamo::Server.timeout = 10 # seconds
|
|
139
|
-
Clamo::Server.timeout = nil # disable timeout
|
|
140
|
-
```
|
|
135
|
+
## Configuration
|
|
141
136
|
|
|
142
137
|
### Error Callback
|
|
143
138
|
|
|
144
|
-
Errors during dispatch are reported through `on_error
|
|
139
|
+
Errors during dispatch are reported through `on_error`, which is called for both requests and notifications. Notifications are silent by default (no response is sent to the client, but `on_error` still fires); requests return a generic `-32000 Server error` without leaking exception details. Use `on_error` to capture the full exception for logging:
|
|
145
140
|
|
|
146
141
|
```ruby
|
|
147
142
|
Clamo::Server.on_error = ->(exception, method, params) {
|
|
@@ -149,32 +144,15 @@ Clamo::Server.on_error = ->(exception, method, params) {
|
|
|
149
144
|
}
|
|
150
145
|
```
|
|
151
146
|
|
|
152
|
-
### Dispatch Hooks
|
|
153
|
-
|
|
154
|
-
`before_dispatch` and `after_dispatch` run around every method call (requests and notifications). Raise in `before_dispatch` to halt execution:
|
|
155
|
-
|
|
156
|
-
```ruby
|
|
157
|
-
Clamo::Server.before_dispatch = ->(method, params) {
|
|
158
|
-
raise "unauthorized" unless allowed?(method)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
Clamo::Server.after_dispatch = ->(method, params, result) {
|
|
162
|
-
Rails.logger.info("#{method} completed")
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
147
|
### Per-Call Configuration
|
|
167
148
|
|
|
168
|
-
|
|
149
|
+
Configuration can be overridden per-call. Module-level settings serve as defaults:
|
|
169
150
|
|
|
170
151
|
```ruby
|
|
171
|
-
Clamo::Server.
|
|
152
|
+
Clamo::Server.handle_json(
|
|
172
153
|
request: body,
|
|
173
154
|
object: MyService,
|
|
174
|
-
|
|
175
|
-
on_error: ->(e, method, params) { MyLogger.error(e) },
|
|
176
|
-
before_dispatch: ->(method, params) { authorize!(method) },
|
|
177
|
-
after_dispatch: ->(method, params, result) { track(method) }
|
|
155
|
+
on_error: ->(e, method, params) { MyLogger.error(e) }
|
|
178
156
|
)
|
|
179
157
|
```
|
|
180
158
|
|
|
@@ -184,10 +162,10 @@ Per-call config is snapshotted at the start of each dispatch, so concurrent muta
|
|
|
184
162
|
|
|
185
163
|
### Parallel Processing
|
|
186
164
|
|
|
187
|
-
Batch requests are processed in parallel
|
|
165
|
+
Batch requests are processed in parallel when the [parallel](https://github.com/grosser/parallel) gem is available. If `parallel` is not installed, batches fall back to sequential processing. You can pass options to `Parallel.map`:
|
|
188
166
|
|
|
189
167
|
```ruby
|
|
190
|
-
Clamo::Server.
|
|
168
|
+
Clamo::Server.dispatch(
|
|
191
169
|
request: batch_request,
|
|
192
170
|
object: MyService,
|
|
193
171
|
in_processes: 4 # Parallel processing option
|
data/lib/clamo/jsonrpc.rb
CHANGED
|
@@ -14,22 +14,6 @@ module Clamo
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class << self
|
|
17
|
-
def proper_params_if_any?(request)
|
|
18
|
-
if key_indifferent?(request, "params")
|
|
19
|
-
params = fetch_indifferent(request, "params")
|
|
20
|
-
params.is_a?(Array) || params.is_a?(Hash)
|
|
21
|
-
else
|
|
22
|
-
true
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def valid_request?(request)
|
|
27
|
-
request.is_a?(Hash) &&
|
|
28
|
-
proper_pragma?(request) &&
|
|
29
|
-
proper_method?(request) &&
|
|
30
|
-
proper_id_if_any?(request)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
17
|
def build_request(**opts)
|
|
34
18
|
raise ArgumentError, "method is required" unless opts.key?(:method)
|
|
35
19
|
|
|
@@ -77,6 +61,24 @@ module Clamo
|
|
|
77
61
|
)
|
|
78
62
|
end
|
|
79
63
|
|
|
64
|
+
# Used internally by Clamo::Server — not part of the public API.
|
|
65
|
+
def proper_params_if_any?(request)
|
|
66
|
+
if key_indifferent?(request, "params")
|
|
67
|
+
params = fetch_indifferent(request, "params")
|
|
68
|
+
params.is_a?(Array) || params.is_a?(Hash)
|
|
69
|
+
else
|
|
70
|
+
true
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Used internally by Clamo::Server — not part of the public API.
|
|
75
|
+
def valid_request?(request)
|
|
76
|
+
request.is_a?(Hash) &&
|
|
77
|
+
proper_pragma?(request) &&
|
|
78
|
+
proper_method?(request) &&
|
|
79
|
+
proper_id_if_any?(request)
|
|
80
|
+
end
|
|
81
|
+
|
|
80
82
|
private
|
|
81
83
|
|
|
82
84
|
def proper_pragma?(request)
|
data/lib/clamo/server.rb
CHANGED
|
@@ -1,40 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
-
require "parallel"
|
|
5
|
-
require "timeout"
|
|
6
4
|
|
|
7
5
|
module Clamo
|
|
8
6
|
module Server
|
|
9
|
-
Config = Data.define(:
|
|
7
|
+
Config = Data.define(:on_error)
|
|
10
8
|
|
|
11
9
|
class << self
|
|
12
|
-
|
|
13
|
-
# dispatch call, so mutations mid-request do not affect in-flight work.
|
|
14
|
-
# All four can be overridden per-call via keyword arguments.
|
|
15
|
-
attr_accessor :on_error, :before_dispatch, :after_dispatch
|
|
16
|
-
attr_writer :timeout
|
|
17
|
-
|
|
18
|
-
def timeout
|
|
19
|
-
return @timeout if defined?(@timeout)
|
|
20
|
-
|
|
21
|
-
30
|
|
22
|
-
end
|
|
10
|
+
attr_accessor :on_error
|
|
23
11
|
|
|
24
12
|
# JSON string in, JSON string out. Full round-trip for HTTP/socket integrations.
|
|
25
13
|
#
|
|
26
|
-
# Clamo::Server.
|
|
14
|
+
# Clamo::Server.handle_json(request: body, object: MyService)
|
|
27
15
|
#
|
|
28
|
-
def
|
|
29
|
-
response =
|
|
16
|
+
def handle_json(request:, object:, **)
|
|
17
|
+
response = dispatch_json(request: request, object: object, **)
|
|
30
18
|
response&.to_json
|
|
31
19
|
end
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
|
|
21
|
+
alias handle handle_json
|
|
22
|
+
|
|
23
|
+
# JSON string in, parsed response out.
|
|
24
|
+
#
|
|
25
|
+
# Clamo::Server.dispatch_json(request: json_string, object: MyModule)
|
|
26
|
+
#
|
|
27
|
+
def dispatch_json(request:, object:, **)
|
|
38
28
|
raise ArgumentError, "object is required" unless object
|
|
39
29
|
|
|
40
30
|
begin
|
|
@@ -43,26 +33,30 @@ module Clamo
|
|
|
43
33
|
return JSONRPC.build_error_response_parse_error
|
|
44
34
|
end
|
|
45
35
|
|
|
46
|
-
|
|
36
|
+
dispatch(request: parsed, object: object, **)
|
|
47
37
|
end
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
alias unparsed_dispatch_to_object dispatch_json
|
|
40
|
+
|
|
41
|
+
# Parsed hash in, parsed response out.
|
|
42
|
+
#
|
|
43
|
+
# Clamo::Server.dispatch(request: hash_or_array, object: MyModule)
|
|
44
|
+
#
|
|
45
|
+
def dispatch(request:, object:,
|
|
46
|
+
on_error: self.on_error,
|
|
47
|
+
**opts)
|
|
55
48
|
raise ArgumentError, "object is required" unless object
|
|
56
49
|
|
|
57
50
|
request = normalize_request_keys(request)
|
|
58
|
-
config = Config.new(
|
|
59
|
-
before_dispatch: before_dispatch, after_dispatch: after_dispatch)
|
|
51
|
+
config = Config.new(on_error: on_error)
|
|
60
52
|
|
|
61
53
|
response_for(request: request, object: object, config: config, **opts) do |method, params|
|
|
62
54
|
dispatch_to_ruby(object: object, method: method, params: params)
|
|
63
55
|
end
|
|
64
56
|
end
|
|
65
57
|
|
|
58
|
+
alias parsed_dispatch_to_object dispatch
|
|
59
|
+
|
|
66
60
|
private
|
|
67
61
|
|
|
68
62
|
def normalize_request_keys(request)
|
|
@@ -109,8 +103,15 @@ module Clamo
|
|
|
109
103
|
error = validate_request_structure(request)
|
|
110
104
|
return error if error
|
|
111
105
|
|
|
106
|
+
error = validate_params_type(request)
|
|
107
|
+
return error if error
|
|
108
|
+
|
|
112
109
|
unless method_known?(object: object, method: request["method"])
|
|
113
|
-
return request
|
|
110
|
+
return error_for(request, JSONRPC::ProtocolErrors::METHOD_NOT_FOUND)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
unless params_match_arity?(object: object, method: request["method"], params: request["params"])
|
|
114
|
+
return error_for(request, JSONRPC::ProtocolErrors::INVALID_PARAMS)
|
|
114
115
|
end
|
|
115
116
|
|
|
116
117
|
return dispatch_notification(request, block, config) unless request.key?("id")
|
|
@@ -128,38 +129,44 @@ module Clamo
|
|
|
128
129
|
return result ? [result] : nil
|
|
129
130
|
end
|
|
130
131
|
|
|
131
|
-
result =
|
|
132
|
+
result = map_batch(request, **opts) do |item|
|
|
132
133
|
response_for_single_request(request: item, object: object, block: block, config: config)
|
|
133
134
|
end.compact
|
|
134
135
|
result.empty? ? nil : result
|
|
135
136
|
end
|
|
136
137
|
|
|
137
|
-
def
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
138
|
+
def map_batch(items, **, &)
|
|
139
|
+
require "parallel"
|
|
140
|
+
Parallel.map(items, **, &)
|
|
141
|
+
rescue LoadError
|
|
142
|
+
items.map(&)
|
|
143
|
+
end
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
def error_for(request, descriptor)
|
|
146
|
+
return unless request.key?("id")
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
JSONRPC.build_error_response_from(id: request["id"], descriptor: descriptor)
|
|
149
|
+
end
|
|
149
150
|
|
|
150
|
-
|
|
151
|
+
def validate_request_structure(request)
|
|
152
|
+
return if JSONRPC.valid_request?(request)
|
|
153
|
+
|
|
154
|
+
JSONRPC.build_error_response_from(
|
|
155
|
+
id: request.is_a?(Hash) ? request["id"] : nil,
|
|
156
|
+
descriptor: JSONRPC::ProtocolErrors::INVALID_REQUEST
|
|
157
|
+
)
|
|
151
158
|
end
|
|
152
159
|
|
|
153
|
-
def
|
|
154
|
-
JSONRPC.
|
|
160
|
+
def validate_params_type(request)
|
|
161
|
+
return if JSONRPC.proper_params_if_any?(request)
|
|
162
|
+
|
|
163
|
+
error_for(request, JSONRPC::ProtocolErrors::INVALID_PARAMS)
|
|
155
164
|
end
|
|
156
165
|
|
|
157
166
|
def dispatch_notification(request, block, config)
|
|
158
167
|
method = request["method"]
|
|
159
168
|
params = request["params"]
|
|
160
|
-
|
|
161
|
-
result = with_timeout(config.timeout) { block.yield(method, params) }
|
|
162
|
-
config.after_dispatch&.call(method, params, result)
|
|
169
|
+
block.yield(method, params)
|
|
163
170
|
nil
|
|
164
171
|
rescue StandardError => e
|
|
165
172
|
config.on_error&.call(e, method, params)
|
|
@@ -169,35 +176,59 @@ module Clamo
|
|
|
169
176
|
def dispatch_request(request, block, config)
|
|
170
177
|
method = request["method"]
|
|
171
178
|
params = request["params"]
|
|
172
|
-
|
|
173
|
-
result = with_timeout(config.timeout) { block.yield(method, params) }
|
|
174
|
-
config.after_dispatch&.call(method, params, result)
|
|
179
|
+
result = block.yield(method, params)
|
|
175
180
|
JSONRPC.build_result_response(id: request["id"], result: result)
|
|
176
|
-
rescue Timeout::Error
|
|
177
|
-
timeout_error(request)
|
|
178
181
|
rescue StandardError => e
|
|
179
182
|
config.on_error&.call(e, method, params)
|
|
180
|
-
JSONRPC.build_error_response_from(id: request["id"], descriptor: JSONRPC::ProtocolErrors::
|
|
183
|
+
JSONRPC.build_error_response_from(id: request["id"], descriptor: JSONRPC::ProtocolErrors::SERVER_ERROR)
|
|
181
184
|
end
|
|
182
185
|
|
|
183
|
-
def
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
error: {
|
|
187
|
-
code: JSONRPC::ProtocolErrors::SERVER_ERROR.code,
|
|
188
|
-
message: JSONRPC::ProtocolErrors::SERVER_ERROR.message,
|
|
189
|
-
data: "Request timed out"
|
|
190
|
-
}
|
|
191
|
-
)
|
|
192
|
-
end
|
|
186
|
+
def params_match_arity?(object:, method:, params:)
|
|
187
|
+
ruby_method = resolve_method(object, method)
|
|
188
|
+
return true unless ruby_method
|
|
193
189
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
190
|
+
parameters = ruby_method.parameters
|
|
191
|
+
|
|
192
|
+
case params
|
|
193
|
+
when Array then array_params_match?(parameters, params.size)
|
|
194
|
+
when Hash then hash_params_match?(parameters, params.keys.map(&:to_sym))
|
|
195
|
+
when nil then nil_params_match?(parameters)
|
|
196
|
+
else true
|
|
199
197
|
end
|
|
200
198
|
end
|
|
199
|
+
|
|
200
|
+
def resolve_method(object, method_name)
|
|
201
|
+
object.method(method_name.to_sym)
|
|
202
|
+
rescue NameError
|
|
203
|
+
nil
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def array_params_match?(parameters, count)
|
|
207
|
+
by_type = parameters.group_by(&:first)
|
|
208
|
+
|
|
209
|
+
return false if by_type.key?(:keyreq)
|
|
210
|
+
return true if by_type.key?(:rest)
|
|
211
|
+
|
|
212
|
+
required = by_type.fetch(:req, []).size
|
|
213
|
+
count.between?(required, required + by_type.fetch(:opt, []).size)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def hash_params_match?(parameters, keys)
|
|
217
|
+
by_type = parameters.group_by(&:first)
|
|
218
|
+
required = by_type.fetch(:keyreq, []).map(&:last)
|
|
219
|
+
allowed = required + by_type.fetch(:key, []).map(&:last)
|
|
220
|
+
|
|
221
|
+
return false if by_type.key?(:req)
|
|
222
|
+
return false unless (required - keys).empty?
|
|
223
|
+
|
|
224
|
+
by_type.key?(:keyrest) || (keys - allowed).empty?
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def nil_params_match?(parameters)
|
|
228
|
+
by_type = parameters.group_by(&:first)
|
|
229
|
+
|
|
230
|
+
by_type.fetch(:req, []).empty? && !by_type.key?(:keyreq)
|
|
231
|
+
end
|
|
201
232
|
end
|
|
202
233
|
end
|
|
203
234
|
end
|
data/lib/clamo/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: clamo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andriy Tyurnikov
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
12
|
-
- !ruby/object:Gem::Dependency
|
|
13
|
-
name: parallel
|
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
|
15
|
-
requirements:
|
|
16
|
-
- - "~>"
|
|
17
|
-
- !ruby/object:Gem::Version
|
|
18
|
-
version: '1.27'
|
|
19
|
-
type: :runtime
|
|
20
|
-
prerelease: false
|
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
-
requirements:
|
|
23
|
-
- - "~>"
|
|
24
|
-
- !ruby/object:Gem::Version
|
|
25
|
-
version: '1.27'
|
|
11
|
+
dependencies: []
|
|
26
12
|
description: Minimal, spec-compliant JSON-RPC 2.0 server for Ruby with request validation,
|
|
27
13
|
method dispatch, batch processing, and notification support.
|
|
28
14
|
email:
|