camille 1.2.0 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/lib/camille/basic_type.rb +8 -0
- data/lib/camille/configuration.rb +3 -1
- data/lib/camille/controller.rb +23 -2
- data/lib/camille/generators/templates/configuration.rb +5 -0
- data/lib/camille/type.rb +8 -0
- data/lib/camille/types/array.rb +29 -20
- data/lib/camille/types/intersection.rb +24 -15
- data/lib/camille/types/object.rb +46 -0
- data/lib/camille/types/tuple.rb +29 -20
- data/lib/camille/types/union.rb +23 -14
- data/lib/camille/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f58ec63581094cce8faf1d3f9dd3e1909ebe3fb188e8c7ed59c09a74645793b
|
|
4
|
+
data.tar.gz: badb42b9b2bb52426060ba9c62544ac6660334784b458360e82594d09ea785d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd2e3eb6d0f629cf9eaacb6c8c8f09c92bd9b77a9815a7025717913d2542a6f38451a6f1c16b3cfdecc5c09c22f2949ab6b9cb77b9f349cec88bd22cef7ee375
|
|
7
|
+
data.tar.gz: 99177b3fe5a775615b8bf01cb88e23a3e6100409fee7a1a0af486ad918adf6de4c0c52d8e9b7c660f08110825ecd1609a713f9a7dc739cdb4a6ae67a13753af3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
* Added Camille::Controller::ParamsTypeError and Camille::Controller::ResponseTypeError to indicate source of TypeError.
|
|
8
|
+
|
|
9
|
+
## 1.3.0
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
* Added option to check controller params type: `config.check_params`.
|
|
14
|
+
|
|
3
15
|
## 1.2.0
|
|
4
16
|
|
|
5
17
|
### Added
|
data/Gemfile.lock
CHANGED
data/lib/camille/basic_type.rb
CHANGED
|
@@ -41,6 +41,10 @@ module Camille
|
|
|
41
41
|
raise NotImplementedError
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def check_params value
|
|
45
|
+
check value
|
|
46
|
+
end
|
|
47
|
+
|
|
44
48
|
def self.| other
|
|
45
49
|
Camille::Type.instance(self) | other
|
|
46
50
|
end
|
|
@@ -53,6 +57,10 @@ module Camille
|
|
|
53
57
|
Camille::Type.instance(self)[]
|
|
54
58
|
end
|
|
55
59
|
|
|
60
|
+
def self.check_params value
|
|
61
|
+
Camille::Type.instance(self).check_params value
|
|
62
|
+
end
|
|
63
|
+
|
|
56
64
|
def self.directly_instantiable?
|
|
57
65
|
instance_method(:initialize).arity == 0
|
|
58
66
|
end
|
|
@@ -3,7 +3,7 @@ module Camille
|
|
|
3
3
|
class Configuration
|
|
4
4
|
class << self
|
|
5
5
|
attr_reader :response_key_converter, :params_key_converter
|
|
6
|
-
attr_accessor :ts_header, :ts_location
|
|
6
|
+
attr_accessor :ts_header, :ts_location, :check_params
|
|
7
7
|
|
|
8
8
|
def load_default_configurations
|
|
9
9
|
self.response_key_converter = lambda do |string|
|
|
@@ -13,6 +13,8 @@ module Camille
|
|
|
13
13
|
self.params_key_converter = lambda do |string|
|
|
14
14
|
string.underscore
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
self.check_params = false
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def response_key_converter= lambda
|
data/lib/camille/controller.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Camille
|
|
2
2
|
module Controller
|
|
3
3
|
class TypeError < ::StandardError; end
|
|
4
|
+
class ParamsTypeError < TypeError; end
|
|
5
|
+
class ResponseTypeError < TypeError; end
|
|
4
6
|
class ArgumentError < ::ArgumentError; end
|
|
5
7
|
class MissingRenderError < ::StandardError; end
|
|
6
8
|
|
|
@@ -23,7 +25,7 @@ module Camille
|
|
|
23
25
|
if result.type_error?
|
|
24
26
|
string_io = StringIO.new
|
|
25
27
|
Camille::TypeErrorPrinter.new(result).print(string_io)
|
|
26
|
-
raise
|
|
28
|
+
raise ResponseTypeError.new("\nType check failed for response.\n#{string_io.string}")
|
|
27
29
|
else
|
|
28
30
|
rendered = result.render.json
|
|
29
31
|
super(json: rendered)
|
|
@@ -43,7 +45,26 @@ module Camille
|
|
|
43
45
|
Camille::Loader.check_and_raise_exception
|
|
44
46
|
if endpoint = camille_endpoint
|
|
45
47
|
begin
|
|
46
|
-
|
|
48
|
+
if Camille::Configuration.check_params
|
|
49
|
+
# New way: check params against the endpoint's params_type if it exists
|
|
50
|
+
if endpoint.params_type
|
|
51
|
+
params_to_check = params.to_unsafe_h
|
|
52
|
+
check_result = endpoint.params_type.check_params(params_to_check)
|
|
53
|
+
|
|
54
|
+
if check_result.type_error?
|
|
55
|
+
string_io = StringIO.new
|
|
56
|
+
Camille::TypeErrorPrinter.new(check_result).print(string_io)
|
|
57
|
+
raise ParamsTypeError.new("\nType check failed for params.\n#{string_io.string}")
|
|
58
|
+
else
|
|
59
|
+
# Use the checked value which already has snake_case keys
|
|
60
|
+
self.params = ActionController::Parameters.new(check_result.value)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
# Old way: just transform keys
|
|
65
|
+
params.deep_transform_keys!{|key| Camille::Configuration.params_key_converter.call(key.to_s)}
|
|
66
|
+
end
|
|
67
|
+
|
|
47
68
|
result = super
|
|
48
69
|
# When there's no `render` call, Rails will return status 204
|
|
49
70
|
if response.status == 204
|
|
@@ -4,4 +4,9 @@ Camille.configure do |config|
|
|
|
4
4
|
// DO NOT EDIT! This file is automatically generated.
|
|
5
5
|
import request from './request'
|
|
6
6
|
EOF
|
|
7
|
+
|
|
8
|
+
# Enable type checking for controller parameters.
|
|
9
|
+
# When enabled, params will be validated against the schema and automatically
|
|
10
|
+
# converted from camelCase to snake_case.
|
|
11
|
+
config.check_params = true
|
|
7
12
|
end
|
data/lib/camille/type.rb
CHANGED
|
@@ -23,10 +23,18 @@ module Camille
|
|
|
23
23
|
@underlying.check value
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def check_params value
|
|
27
|
+
@underlying.check_params value
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
def self.check value
|
|
27
31
|
new.check value
|
|
28
32
|
end
|
|
29
33
|
|
|
34
|
+
def self.check_params value
|
|
35
|
+
new.check_params value
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
def self.klass_name
|
|
31
39
|
name.gsub(/^Camille::Types::/, '')
|
|
32
40
|
end
|
data/lib/camille/types/array.rb
CHANGED
|
@@ -9,32 +9,41 @@ module Camille
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def check value
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[index, @content.check(element)]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
errors = results.map do |index, result|
|
|
18
|
-
if result.type_error?
|
|
19
|
-
["array[#{index}]", result]
|
|
20
|
-
else
|
|
21
|
-
nil
|
|
22
|
-
end
|
|
23
|
-
end.compact
|
|
12
|
+
check_with_method(value, :check)
|
|
13
|
+
end
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
Camille::TypeError.new(**errors.to_h)
|
|
29
|
-
end
|
|
30
|
-
else
|
|
31
|
-
Camille::TypeError.new("Expected array, got #{value.inspect}.")
|
|
32
|
-
end
|
|
15
|
+
def check_params value
|
|
16
|
+
check_with_method(value, :check_params)
|
|
33
17
|
end
|
|
34
18
|
|
|
35
19
|
def literal
|
|
36
20
|
"#{@content.literal}[]"
|
|
37
21
|
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
def check_with_method value, method_name
|
|
25
|
+
if value.is_a? ::Array
|
|
26
|
+
results = value.map.with_index do |element, index|
|
|
27
|
+
[index, @content.public_send(method_name, element)]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
errors = results.map do |index, result|
|
|
31
|
+
if result.type_error?
|
|
32
|
+
["array[#{index}]", result]
|
|
33
|
+
else
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end.compact
|
|
37
|
+
|
|
38
|
+
if errors.empty?
|
|
39
|
+
Camille::Checked.new(fingerprint, results.map{|_, checked| checked.value})
|
|
40
|
+
else
|
|
41
|
+
Camille::TypeError.new(**errors.to_h)
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
Camille::TypeError.new("Expected array, got #{value.inspect}.")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
38
47
|
end
|
|
39
48
|
end
|
|
40
49
|
end
|
|
@@ -12,27 +12,36 @@ module Camille
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def check value
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
else
|
|
21
|
-
right_result = @right.check left_result.value
|
|
22
|
-
if right_result.type_error?
|
|
23
|
-
Camille::TypeError.new(
|
|
24
|
-
'intersection.right' => right_result
|
|
25
|
-
)
|
|
26
|
-
else
|
|
27
|
-
Camille::Checked.new(fingerprint, right_result.value)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
15
|
+
check_with_method(value, :check)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def check_params value
|
|
19
|
+
check_with_method(value, :check_params)
|
|
30
20
|
end
|
|
31
21
|
|
|
32
22
|
def literal
|
|
33
23
|
"(#{@left.literal} & #{@right.literal})"
|
|
34
24
|
end
|
|
35
25
|
|
|
26
|
+
private
|
|
27
|
+
def check_with_method value, method_name
|
|
28
|
+
left_result = @left.public_send(method_name, value)
|
|
29
|
+
if left_result.type_error?
|
|
30
|
+
Camille::TypeError.new(
|
|
31
|
+
'intersection.left' => left_result
|
|
32
|
+
)
|
|
33
|
+
else
|
|
34
|
+
right_result = @right.public_send(method_name, left_result.value)
|
|
35
|
+
if right_result.type_error?
|
|
36
|
+
Camille::TypeError.new(
|
|
37
|
+
'intersection.right' => right_result
|
|
38
|
+
)
|
|
39
|
+
else
|
|
40
|
+
Camille::Checked.new(fingerprint, right_result.value)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
36
45
|
end
|
|
37
46
|
end
|
|
38
47
|
end
|
data/lib/camille/types/object.rb
CHANGED
|
@@ -47,6 +47,52 @@ module Camille
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def check_params value
|
|
51
|
+
if value.is_a? Hash
|
|
52
|
+
# Convert camelCase keys to snake_case
|
|
53
|
+
converted_value = value.transform_keys do |key|
|
|
54
|
+
Camille::KeyConverter.convert_params_key(key.to_s)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
fields_with_string_keys = @fields.transform_keys(&:to_s)
|
|
58
|
+
optional_keys_as_strings = @optional_keys.map(&:to_s)
|
|
59
|
+
|
|
60
|
+
# Now check using the regular check method which expects snake_case
|
|
61
|
+
keys = (fields_with_string_keys.keys + converted_value.keys).uniq
|
|
62
|
+
keys_to_check, keys_to_skip = keys.partition{|key| fields_with_string_keys[key]}
|
|
63
|
+
|
|
64
|
+
results = keys_to_check.map do |key|
|
|
65
|
+
type = fields_with_string_keys[key]
|
|
66
|
+
if optional_keys_as_strings.include?(key) && converted_value[key].nil?
|
|
67
|
+
nil
|
|
68
|
+
else
|
|
69
|
+
[key, type.check_params(converted_value[key])]
|
|
70
|
+
end
|
|
71
|
+
end.compact
|
|
72
|
+
|
|
73
|
+
errors = results.map do |key, result|
|
|
74
|
+
if result.type_error?
|
|
75
|
+
[key.to_s, result]
|
|
76
|
+
else
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
end.compact
|
|
80
|
+
|
|
81
|
+
skipped_pairs = keys_to_skip.map do |key|
|
|
82
|
+
[key, converted_value[key]]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if errors.empty?
|
|
86
|
+
object = Hash[results.map{|key, checked| [key, checked.value]}.concat(skipped_pairs).to_h]
|
|
87
|
+
Camille::Checked.new(fingerprint, object)
|
|
88
|
+
else
|
|
89
|
+
Camille::TypeError.new(**errors.to_h)
|
|
90
|
+
end
|
|
91
|
+
else
|
|
92
|
+
Camille::TypeError.new("Expected hash, got #{value.inspect}.")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
50
96
|
def literal
|
|
51
97
|
"{#{@fields.map{|k,v| "#{literal_key k}: #{v.literal}"}.join(', ')}}"
|
|
52
98
|
end
|
data/lib/camille/types/tuple.rb
CHANGED
|
@@ -9,32 +9,41 @@ module Camille
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def check value
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[index, type.check(value[index])]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
errors = results.map do |index, result|
|
|
18
|
-
if result.type_error?
|
|
19
|
-
["tuple[#{index}]", result]
|
|
20
|
-
else
|
|
21
|
-
nil
|
|
22
|
-
end
|
|
23
|
-
end.compact
|
|
12
|
+
check_with_method(value, :check)
|
|
13
|
+
end
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
Camille::TypeError.new(**errors.to_h)
|
|
29
|
-
end
|
|
30
|
-
else
|
|
31
|
-
Camille::TypeError.new("Expected array of size #{@elements.size}, got #{value.inspect}.")
|
|
32
|
-
end
|
|
15
|
+
def check_params value
|
|
16
|
+
check_with_method(value, :check_params)
|
|
33
17
|
end
|
|
34
18
|
|
|
35
19
|
def literal
|
|
36
20
|
"[#{elements.map(&:literal).join(', ')}]"
|
|
37
21
|
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
def check_with_method value, method_name
|
|
25
|
+
if value.is_a?(::Array) && value.size == @elements.size
|
|
26
|
+
results = @elements.map.with_index do |type, index|
|
|
27
|
+
[index, type.public_send(method_name, value[index])]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
errors = results.map do |index, result|
|
|
31
|
+
if result.type_error?
|
|
32
|
+
["tuple[#{index}]", result]
|
|
33
|
+
else
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end.compact
|
|
37
|
+
|
|
38
|
+
if errors.empty?
|
|
39
|
+
Camille::Checked.new(fingerprint, results.map{|_, checked| checked.value})
|
|
40
|
+
else
|
|
41
|
+
Camille::TypeError.new(**errors.to_h)
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
Camille::TypeError.new("Expected array of size #{@elements.size}, got #{value.inspect}.")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
38
47
|
end
|
|
39
48
|
end
|
|
40
49
|
end
|
data/lib/camille/types/union.rb
CHANGED
|
@@ -10,25 +10,34 @@ module Camille
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def check value
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'union.left' => left_result,
|
|
19
|
-
'union.right' => right_result
|
|
20
|
-
)
|
|
21
|
-
else
|
|
22
|
-
Camille::Checked.new(fingerprint, right_result.value)
|
|
23
|
-
end
|
|
24
|
-
else
|
|
25
|
-
Camille::Checked.new(fingerprint, left_result.value)
|
|
26
|
-
end
|
|
13
|
+
check_with_method(value, :check)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def check_params value
|
|
17
|
+
check_with_method(value, :check_params)
|
|
27
18
|
end
|
|
28
19
|
|
|
29
20
|
def literal
|
|
30
21
|
"(#{@left.literal} | #{@right.literal})"
|
|
31
22
|
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def check_with_method value, method_name
|
|
26
|
+
left_result = @left.public_send(method_name, value)
|
|
27
|
+
if left_result.type_error?
|
|
28
|
+
right_result = @right.public_send(method_name, value)
|
|
29
|
+
if right_result.type_error?
|
|
30
|
+
Camille::TypeError.new(
|
|
31
|
+
'union.left' => left_result,
|
|
32
|
+
'union.right' => right_result
|
|
33
|
+
)
|
|
34
|
+
else
|
|
35
|
+
Camille::Checked.new(fingerprint, right_result.value)
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
Camille::Checked.new(fingerprint, left_result.value)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
32
41
|
end
|
|
33
42
|
end
|
|
34
43
|
end
|
data/lib/camille/version.rb
CHANGED