ree_lib 1.0.36 → 1.0.38
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -2
- data/lib/ree_lib/Packages.schema.json +8 -0
- data/lib/ree_lib/packages/ree_actions/.gitignore +0 -0
- data/lib/ree_lib/packages/ree_actions/.rspec +2 -0
- data/lib/ree_lib/packages/ree_actions/Package.schema.json +20 -0
- data/lib/ree_lib/packages/ree_actions/bin/console +5 -0
- data/lib/ree_lib/packages/ree_actions/package/ree_actions/action.rb +10 -0
- data/lib/ree_lib/packages/ree_actions/package/ree_actions/action_builder.rb +65 -0
- data/lib/ree_lib/packages/ree_actions/package/ree_actions/action_dsl.rb +60 -0
- data/lib/ree_lib/packages/ree_actions/package/ree_actions/dsl.rb +102 -0
- data/lib/ree_lib/packages/ree_actions/package/ree_actions.rb +12 -0
- data/lib/ree_lib/packages/ree_actions/spec/package_schema_spec.rb +14 -0
- data/lib/ree_lib/packages/ree_actions/spec/ree_actions/action_dsl_spec.rb +62 -0
- data/lib/ree_lib/packages/ree_actions/spec/ree_actions/dsl_spec.rb +93 -0
- data/lib/ree_lib/packages/ree_actions/spec/spec_helper.rb +3 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/functions/build_mapper_factory.rb +4 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +17 -10
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb +73 -35
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/any.rb +23 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/abstract_wrapper.rb +8 -0
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/{types → wrappers}/array.rb +10 -17
- data/lib/ree_lib/packages/ree_mapper/package/ree_mapper.rb +5 -1
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_factory_spec.rb +62 -2
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/any_spec.rb +47 -0
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb +4 -4
- data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/{types → wrappers}/array_spec.rb +7 -7
- data/lib/ree_lib/packages/ree_roda/.gitignore +0 -0
- data/lib/ree_lib/packages/ree_roda/.rspec +2 -0
- data/lib/ree_lib/packages/ree_roda/Package.schema.json +58 -0
- data/lib/ree_lib/packages/ree_roda/bin/console +5 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/app.rb +46 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_actions.rb +150 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_logger.rb +66 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_action_errors.rb +76 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_swagger_from_actions.rb +55 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/status_from_error.rb +25 -0
- data/lib/ree_lib/packages/ree_roda/package/ree_roda.rb +19 -0
- data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/build_action_errors.schema.json +28 -0
- data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/build_swagger_from_actions.schema.json +63 -0
- data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/status_from_error.schema.json +28 -0
- data/lib/ree_lib/packages/ree_roda/spec/package_schema_spec.rb +14 -0
- data/lib/ree_lib/packages/ree_roda/spec/ree_roda/app_spec.rb +84 -0
- data/lib/ree_lib/packages/ree_roda/spec/spec_helper.rb +3 -0
- data/lib/ree_lib/packages/ree_swagger/package/ree_swagger/beans/type_definitions_repo.rb +1 -1
- data/lib/ree_lib/packages/ree_swagger/spec/functions/build_parameters_spec.rb +1 -1
- data/lib/ree_lib/packages/ree_swagger/spec/functions/build_serializer_schema_spec.rb +3 -3
- data/lib/ree_lib/version.rb +1 -1
- metadata +65 -4
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class ReeMapper::MapperFactory
|
4
4
|
class << self
|
5
|
-
attr_reader :types, :strategies
|
5
|
+
attr_reader :types, :strategies, :wrappers
|
6
6
|
end
|
7
7
|
|
8
8
|
contract(Symbol => Nilor[ReeMapper::MapperStrategy])
|
@@ -18,9 +18,9 @@ class ReeMapper::MapperFactory
|
|
18
18
|
)
|
19
19
|
end
|
20
20
|
|
21
|
-
contract(Symbol, ReeMapper::Mapper =>
|
21
|
+
contract(Symbol, ReeMapper::Mapper => SubclassOf[self]).throws(ArgumentError)
|
22
22
|
def self.register_mapper(name, type)
|
23
|
-
raise ArgumentError, "
|
23
|
+
raise ArgumentError, "mapper registration name should not end with `?`" if name.to_s.end_with?('?')
|
24
24
|
|
25
25
|
defined_strategy_method = types[name]&.flat_map(&:strategy_methods)&.detect { type.find_strategy(_1) }
|
26
26
|
raise ArgumentError, "type :#{name} with `#{defined_strategy_method}` strategy already registered" if defined_strategy_method
|
@@ -35,7 +35,7 @@ class ReeMapper::MapperFactory
|
|
35
35
|
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
36
36
|
def #{name}(field_name = nil, optional: false, **opts)
|
37
37
|
raise ReeMapper::Error, "invalid DSL usage" unless @mapper
|
38
|
-
raise ArgumentError, "
|
38
|
+
raise ArgumentError, "wrapped item can't be optional" if field_name.nil? && optional
|
39
39
|
|
40
40
|
type = self.class.types.fetch(:#{name}).detect { (@mapper.strategy_methods - _1.strategy_methods).empty? }
|
41
41
|
|
@@ -43,9 +43,11 @@ class ReeMapper::MapperFactory
|
|
43
43
|
raise ReeMapper::UnsupportedTypeError, "type :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
field = ReeMapper::Field.new(type, field_name, optional: optional, **opts)
|
47
47
|
|
48
|
-
|
48
|
+
return field unless field_name
|
49
|
+
|
50
|
+
@mapper.add_field(field)
|
49
51
|
end
|
50
52
|
|
51
53
|
def #{name}?(field_name, **opts)
|
@@ -56,6 +58,68 @@ class ReeMapper::MapperFactory
|
|
56
58
|
self
|
57
59
|
end
|
58
60
|
|
61
|
+
contract(Symbol, SubclassOf[ReeMapper::AbstractWrapper] => SubclassOf[self])
|
62
|
+
def self.register_wrapper(name, wrapper)
|
63
|
+
raise ArgumentError, "wrapper registration name should not end with `?`" if name.to_s.end_with?('?')
|
64
|
+
raise ArgumentError, "method :#{name} already defined" if !wrappers.key?(name) && method_defined?(name)
|
65
|
+
|
66
|
+
wrappers[name] ||= []
|
67
|
+
wrappers[name] << wrapper
|
68
|
+
|
69
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
70
|
+
contract(
|
71
|
+
Nilor[Symbol, ReeMapper::Field],
|
72
|
+
Nilor[ReeMapper::Field],
|
73
|
+
Kwargs[optional: Bool, dto: Nilor[Class]],
|
74
|
+
Ksplat[RestKeys => Any],
|
75
|
+
Optblock => Nilor[ReeMapper::Field]
|
76
|
+
).throws(ReeMapper::Error, ArgumentError, ReeMapper::UnsupportedTypeError)
|
77
|
+
def #{name}(field_name = nil, subject = nil, optional: false, dto: nil, **opts, &blk)
|
78
|
+
raise ReeMapper::Error, "invalid DSL usage" unless @mapper
|
79
|
+
raise ArgumentError, 'wrapped type does not permit :dto without :block' if dto && !blk
|
80
|
+
|
81
|
+
if field_name.is_a?(ReeMapper::Field)
|
82
|
+
raise ArgumentError, "field_name should be a Symbol" if subject
|
83
|
+
|
84
|
+
subject = field_name
|
85
|
+
field_name = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
raise ArgumentError, "wrapped item can't be optional" if field_name.nil? && optional
|
89
|
+
raise ArgumentError, "wrapped type should use either :subject or :block" if subject && blk || !subject && !blk
|
90
|
+
|
91
|
+
if blk
|
92
|
+
subject = ReeMapper::Field.new(
|
93
|
+
hash_from_blk(dto: dto, &blk)
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
wrapper = self.class.wrappers.fetch(:#{name}).detect do |wrapper|
|
98
|
+
@mapper.strategy_methods.all? { wrapper.method_defined?(_1) }
|
99
|
+
end
|
100
|
+
|
101
|
+
unless wrapper
|
102
|
+
raise ReeMapper::UnsupportedTypeError, "wrapper :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
|
103
|
+
end
|
104
|
+
|
105
|
+
type = ReeMapper::Mapper.build(@mapper.strategies, wrapper.new(subject))
|
106
|
+
type.name = :#{name}
|
107
|
+
|
108
|
+
field = ReeMapper::Field.new(type, field_name, optional: optional, **opts)
|
109
|
+
|
110
|
+
return field unless field_name
|
111
|
+
|
112
|
+
@mapper.add_field(field)
|
113
|
+
end
|
114
|
+
|
115
|
+
def #{name}?(*args, **opts, &blk)
|
116
|
+
#{name}(*args, optional: true, **opts, &blk)
|
117
|
+
end
|
118
|
+
RUBY
|
119
|
+
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
59
123
|
contract(
|
60
124
|
Kwargs[
|
61
125
|
register_as: Nilor[Symbol]
|
@@ -71,41 +135,15 @@ class ReeMapper::MapperFactory
|
|
71
135
|
@mapper = mapper
|
72
136
|
end
|
73
137
|
|
74
|
-
contract(Nilor[Symbol], Kwargs[each: Nilor[ReeMapper::Field], optional: Bool, dto: Nilor[Class]], Ksplat[RestKeys => Any], Optblock => Nilor[ReeMapper::Field])
|
75
|
-
def array(field_name = nil, each: nil, optional: false, dto: nil, **opts, &blk)
|
76
|
-
raise ReeMapper::Error, "invalid DSL usage" unless @mapper
|
77
|
-
raise ArgumentError, "array item can't be optional" if field_name.nil? && optional
|
78
|
-
raise ArgumentError, 'array type should use either :each or :block' if each && blk || !each && !blk
|
79
|
-
raise ArgumentError, 'array does not permit :dto without :block' if dto && !blk
|
80
|
-
raise ArgumentError, 'array does not permit :only and :except keys' if opts.key?(:only) || opts.key?(:except)
|
81
|
-
|
82
|
-
if blk
|
83
|
-
each = ReeMapper::Field.new(
|
84
|
-
hash_from_blk(dto: dto, &blk)
|
85
|
-
)
|
86
|
-
end
|
87
|
-
|
88
|
-
type = ReeMapper::Mapper.build(@mapper.strategies, ReeMapper::Array.new(each))
|
89
|
-
|
90
|
-
return ReeMapper::Field.new(type, optional: optional, **opts) unless field_name
|
91
|
-
|
92
|
-
@mapper.add_field(type, field_name, optional: optional, **opts)
|
93
|
-
end
|
94
|
-
|
95
|
-
contract(Symbol, Kwargs[each: Nilor[ReeMapper::Field]], Ksplat[RestKeys => Any], Optblock => Nilor[ReeMapper::Field])
|
96
|
-
def array?(field_name, each: nil, **opts, &blk)
|
97
|
-
raise ArgumentError if opts.key?(:optional)
|
98
|
-
|
99
|
-
array(field_name, each: each, optional: true, **opts, &blk)
|
100
|
-
end
|
101
|
-
|
102
138
|
contract(Symbol, Kwargs[dto: Nilor[Class]], Ksplat[RestKeys => Any], Block => nil)
|
103
139
|
def hash(field_name, dto: nil, **opts, &blk)
|
104
140
|
raise ReeMapper::Error, "invalid DSL usage" unless @mapper
|
105
141
|
|
106
142
|
type = hash_from_blk(dto: dto, &blk)
|
107
143
|
|
108
|
-
|
144
|
+
field = ReeMapper::Field.new(type, field_name, **opts)
|
145
|
+
|
146
|
+
@mapper.add_field(field)
|
109
147
|
end
|
110
148
|
|
111
149
|
contract(Symbol, Ksplat[RestKeys => Any], Block => nil)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReeMapper::Any < ReeMapper::AbstractType
|
4
|
+
contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
|
5
|
+
def serialize(value, name:, role: nil)
|
6
|
+
value
|
7
|
+
end
|
8
|
+
|
9
|
+
contract(Any , Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
|
10
|
+
def cast(value, name:, role: nil)
|
11
|
+
value
|
12
|
+
end
|
13
|
+
|
14
|
+
contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
|
15
|
+
def db_dump(value, name:, role: nil)
|
16
|
+
value
|
17
|
+
end
|
18
|
+
|
19
|
+
contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
|
20
|
+
def db_load(value, name:, role: nil)
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
@@ -1,22 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class ReeMapper::Array < ReeMapper::
|
4
|
-
attr_reader :of
|
5
|
-
|
6
|
-
contract ReeMapper::Field => Any
|
7
|
-
def initialize(of)
|
8
|
-
@of = of
|
9
|
-
end
|
10
|
-
|
3
|
+
class ReeMapper::Array < ReeMapper::AbstractWrapper
|
11
4
|
contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]], fields_filters: ArrayOf[ReeMapper::FieldsFilter]] => Array)
|
12
5
|
.throws(ReeMapper::TypeError)
|
13
6
|
def serialize(value, name:, role: nil, fields_filters: [])
|
14
7
|
if value.is_a?(Array)
|
15
8
|
value.map.with_index {
|
16
|
-
if _1.nil? &&
|
9
|
+
if _1.nil? && subject.null
|
17
10
|
_1
|
18
11
|
else
|
19
|
-
|
12
|
+
subject.type.serialize(_1, name: "#{name}[#{_2}]", role: role, fields_filters: fields_filters + [subject.fields_filter])
|
20
13
|
end
|
21
14
|
}
|
22
15
|
else
|
@@ -29,10 +22,10 @@ class ReeMapper::Array < ReeMapper::AbstractType
|
|
29
22
|
def cast(value, name:, role: nil, fields_filters: [])
|
30
23
|
if value.is_a?(Array)
|
31
24
|
value.map.with_index {
|
32
|
-
if _1.nil? &&
|
25
|
+
if _1.nil? && subject.null
|
33
26
|
_1
|
34
27
|
else
|
35
|
-
|
28
|
+
subject.type.cast(_1, name: "#{name}[#{_2}]", role: role, fields_filters: fields_filters + [subject.fields_filter])
|
36
29
|
end
|
37
30
|
}
|
38
31
|
else
|
@@ -45,10 +38,10 @@ class ReeMapper::Array < ReeMapper::AbstractType
|
|
45
38
|
def db_dump(value, name:, role: nil, fields_filters: [])
|
46
39
|
if value.is_a?(Array)
|
47
40
|
value.map.with_index {
|
48
|
-
if _1.nil? &&
|
41
|
+
if _1.nil? && subject.null
|
49
42
|
_1
|
50
43
|
else
|
51
|
-
|
44
|
+
subject.type.db_dump(_1, name: "#{name}[#{_2}]", role: role, fields_filters: fields_filters + [subject.fields_filter])
|
52
45
|
end
|
53
46
|
}
|
54
47
|
else
|
@@ -61,14 +54,14 @@ class ReeMapper::Array < ReeMapper::AbstractType
|
|
61
54
|
def db_load(value, name:, role: nil, fields_filters: [])
|
62
55
|
if value.is_a?(Array)
|
63
56
|
value.map.with_index {
|
64
|
-
if _1.nil? &&
|
57
|
+
if _1.nil? && subject.null
|
65
58
|
_1
|
66
59
|
else
|
67
|
-
|
60
|
+
subject.type.db_load(_1, name: "#{name}[#{_2}]", role: role, fields_filters: fields_filters + [subject.fields_filter])
|
68
61
|
end
|
69
62
|
}
|
70
63
|
else
|
71
64
|
raise ReeMapper::TypeError, "`#{name}` should be an array"
|
72
65
|
end
|
73
66
|
end
|
74
|
-
end
|
67
|
+
end
|
@@ -22,14 +22,18 @@ module ReeMapper
|
|
22
22
|
require_relative 'ree_mapper/fields_filter'
|
23
23
|
require_relative 'ree_mapper/field'
|
24
24
|
|
25
|
+
|
26
|
+
require_relative 'ree_mapper/wrappers/abstract_wrapper'
|
27
|
+
require_relative 'ree_mapper/wrappers/array'
|
28
|
+
|
25
29
|
require_relative 'ree_mapper/types/bool'
|
30
|
+
require_relative 'ree_mapper/types/any'
|
26
31
|
require_relative 'ree_mapper/types/date_time'
|
27
32
|
require_relative 'ree_mapper/types/time'
|
28
33
|
require_relative 'ree_mapper/types/date'
|
29
34
|
require_relative 'ree_mapper/types/float'
|
30
35
|
require_relative 'ree_mapper/types/integer'
|
31
36
|
require_relative 'ree_mapper/types/string'
|
32
|
-
require_relative 'ree_mapper/types/array'
|
33
37
|
|
34
38
|
require_relative 'ree_mapper/strategy_outputs/strategy_output'
|
35
39
|
require_relative 'ree_mapper/strategy_outputs/object_output'
|
@@ -43,7 +43,7 @@ RSpec.describe ReeMapper::MapperFactory do
|
|
43
43
|
).to eq({ val: { id: 1 } })
|
44
44
|
}
|
45
45
|
|
46
|
-
it 'allow to register caster and serializer with same name' do
|
46
|
+
it 'allow to register caster and serializer with the same name' do
|
47
47
|
caster = mapper_factory.call.use(:cast) { string :name }
|
48
48
|
|
49
49
|
mapper_factory.register_mapper(:new_type, serializer)
|
@@ -69,7 +69,7 @@ RSpec.describe ReeMapper::MapperFactory do
|
|
69
69
|
it 'raise an error if the mapper name is ended by ?' do
|
70
70
|
expect {
|
71
71
|
mapper_factory.register_mapper(:new_type?, serializer)
|
72
|
-
}.to raise_error(ArgumentError, '
|
72
|
+
}.to raise_error(ArgumentError, 'mapper registration name should not end with `?`')
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'raise an error if the mapper name is reserved' do
|
@@ -79,6 +79,66 @@ RSpec.describe ReeMapper::MapperFactory do
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
describe '.register_wrapper' do
|
83
|
+
let(:round_wrapper) {
|
84
|
+
Class.new(ReeMapper::AbstractWrapper) do
|
85
|
+
def serialize(value, name:, **opts)
|
86
|
+
raise ReeMapper::TypeError, "`#{name}` should be a number" if !value.is_a?(Numeric)
|
87
|
+
|
88
|
+
subject.type.serialize(value.round, name: name, **opts)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
}
|
92
|
+
|
93
|
+
it {
|
94
|
+
mapper_factory.register_wrapper(:round, round_wrapper)
|
95
|
+
|
96
|
+
expect(
|
97
|
+
mapper_factory.call.use(:serialize) { round :val, integer }.serialize({ val: 1.1 })
|
98
|
+
).to eq({ val: 1 })
|
99
|
+
}
|
100
|
+
|
101
|
+
it 'allow to register caster and serializer with the same name' do
|
102
|
+
caster_round_wrapper = Class.new(ReeMapper::AbstractWrapper) do
|
103
|
+
def cast(value, name:, **opts)
|
104
|
+
value = subject.type.cast(value, name: name, **opts)
|
105
|
+
|
106
|
+
raise ReeMapper::TypeError, "`#{name}` should be a number" if !value.is_a?(Numeric)
|
107
|
+
value.round
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
mapper_factory.register_wrapper(:round, round_wrapper)
|
112
|
+
mapper_factory.register_wrapper(:round, caster_round_wrapper)
|
113
|
+
|
114
|
+
expect(
|
115
|
+
mapper_factory.call.use(:serialize) { round :val, integer }.serialize({ val: 1.1 })
|
116
|
+
).to eq({ val: 1 })
|
117
|
+
|
118
|
+
expect(
|
119
|
+
mapper_factory.call.use(:cast) { round :val, float }.cast({ val: '1.1' })
|
120
|
+
).to eq({ val: 1 })
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'raise an error if the registration wrapper name is ended by ?' do
|
124
|
+
expect {
|
125
|
+
mapper_factory.register_wrapper(:new_type?, round_wrapper)
|
126
|
+
}.to raise_error(ArgumentError, 'wrapper registration name should not end with `?`')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'raise an error if name is reserved' do
|
130
|
+
expect {
|
131
|
+
mapper_factory.register_wrapper(:hash, round_wrapper)
|
132
|
+
}.to raise_error(ArgumentError, 'method :hash already defined')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'raise an error if name is reserved by mapper' do
|
136
|
+
expect {
|
137
|
+
mapper_factory.register_wrapper(:integer, round_wrapper)
|
138
|
+
}.to raise_error(ArgumentError, 'method :integer already defined')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
82
142
|
describe '.use' do
|
83
143
|
it {
|
84
144
|
mapper = mapper_factory.call.use(:cast) do
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe 'ReeMapper::Bool' do
|
4
|
+
link :build_mapper_factory, from: :ree_mapper
|
5
|
+
link :build_mapper_strategy, from: :ree_mapper
|
6
|
+
|
7
|
+
let(:mapper_factory) {
|
8
|
+
build_mapper_factory(
|
9
|
+
strategies: [
|
10
|
+
build_mapper_strategy(method: :cast, dto: Hash),
|
11
|
+
build_mapper_strategy(method: :serialize, dto: Hash),
|
12
|
+
build_mapper_strategy(method: :db_dump, dto: Hash),
|
13
|
+
build_mapper_strategy(method: :db_load, dto: Hash)
|
14
|
+
]
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:mapper) {
|
19
|
+
mapper_factory.call.use(:cast).use(:serialize).use(:db_dump).use(:db_load) {
|
20
|
+
any :any
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
describe '#serialize' do
|
25
|
+
it {
|
26
|
+
expect(mapper.serialize({ any: true })).to eq({ any: true })
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#cast' do
|
31
|
+
it {
|
32
|
+
expect(mapper.cast({ 'any' => true })).to eq({ any: true })
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#db_dump' do
|
37
|
+
it {
|
38
|
+
expect(mapper.db_dump(OpenStruct.new({ any: true }))).to eq({ any: true })
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#db_load' do
|
43
|
+
it {
|
44
|
+
expect(mapper.db_load({ 'any' => true })).to eq({ any: true })
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
@@ -21,7 +21,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
|
|
21
21
|
integer :x
|
22
22
|
integer :y
|
23
23
|
integer :z
|
24
|
-
}
|
24
|
+
}
|
25
25
|
}
|
26
26
|
|
27
27
|
context 'with only' do
|
@@ -71,7 +71,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
|
|
71
71
|
point :y, except: [:x, :z]
|
72
72
|
end
|
73
73
|
|
74
|
-
array :points,
|
74
|
+
array :points, point(only: [:x, :y])
|
75
75
|
}
|
76
76
|
}
|
77
77
|
|
@@ -169,7 +169,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
|
|
169
169
|
integer :number
|
170
170
|
integer? :opt_number
|
171
171
|
integer :opt_number_long, optional: true
|
172
|
-
array? :opt_array,
|
172
|
+
array? :opt_array, integer
|
173
173
|
array? :opt_array_with_blk do
|
174
174
|
integer :id
|
175
175
|
end
|
@@ -278,7 +278,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
|
|
278
278
|
integer :for_all
|
279
279
|
integer :for_admin, role: :admin
|
280
280
|
}
|
281
|
-
|
281
|
+
|
282
282
|
mapper_factory.call.use(:cast) {
|
283
283
|
nested_type :my_field
|
284
284
|
}
|
@@ -17,8 +17,8 @@ RSpec.describe 'ReeMapper::Array' do
|
|
17
17
|
|
18
18
|
let(:mapper) {
|
19
19
|
mapper_factory.call.use(:cast).use(:serialize).use(:db_dump).use(:db_load) {
|
20
|
-
array :tags,
|
21
|
-
array? :ary_of_ary,
|
20
|
+
array :tags, integer
|
21
|
+
array? :ary_of_ary, array(integer)
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
@@ -73,7 +73,7 @@ RSpec.describe 'ReeMapper::Array' do
|
|
73
73
|
context 'with array of array' do
|
74
74
|
let(:mapper) {
|
75
75
|
mapper_factory.call.use(:serialize) {
|
76
|
-
array :coords,
|
76
|
+
array :coords, array(integer)
|
77
77
|
}
|
78
78
|
}
|
79
79
|
|
@@ -85,7 +85,7 @@ RSpec.describe 'ReeMapper::Array' do
|
|
85
85
|
context 'with nullable element of array' do
|
86
86
|
let(:mapper) {
|
87
87
|
mapper_factory.call.use(:serialize) {
|
88
|
-
array :tags,
|
88
|
+
array :tags, integer(null: true)
|
89
89
|
}
|
90
90
|
}
|
91
91
|
|
@@ -98,7 +98,7 @@ RSpec.describe 'ReeMapper::Array' do
|
|
98
98
|
it {
|
99
99
|
expect {
|
100
100
|
mapper_factory.call.use(:serialize) {
|
101
|
-
array :tags,
|
101
|
+
array :tags, integer?
|
102
102
|
}
|
103
103
|
}.to raise_error(ArgumentError)
|
104
104
|
}
|
@@ -106,7 +106,7 @@ RSpec.describe 'ReeMapper::Array' do
|
|
106
106
|
it {
|
107
107
|
expect {
|
108
108
|
mapper_factory.call.use(:serialize) {
|
109
|
-
array :tags,
|
109
|
+
array :tags, integer(optional: true)
|
110
110
|
}
|
111
111
|
}.to raise_error(ArgumentError)
|
112
112
|
}
|
@@ -114,7 +114,7 @@ RSpec.describe 'ReeMapper::Array' do
|
|
114
114
|
it {
|
115
115
|
expect {
|
116
116
|
mapper_factory.call.use(:serialize) {
|
117
|
-
array :tags,
|
117
|
+
array :tags, array(integer, optional: true)
|
118
118
|
}
|
119
119
|
}.to raise_error(ArgumentError)
|
120
120
|
}
|
File without changes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
{
|
2
|
+
"schema_type": "package",
|
3
|
+
"schema_version": "1.1",
|
4
|
+
"name": "ree_roda",
|
5
|
+
"entry_path": "packages/ree_roda/package/ree_roda.rb",
|
6
|
+
"tags": [
|
7
|
+
"ree_roda"
|
8
|
+
],
|
9
|
+
"depends_on": [
|
10
|
+
{
|
11
|
+
"name": "ree_actions"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"name": "ree_errors"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"name": "ree_hash"
|
18
|
+
},
|
19
|
+
{
|
20
|
+
"name": "ree_json"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"name": "ree_logger"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"name": "ree_object"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"name": "ree_swagger"
|
30
|
+
}
|
31
|
+
],
|
32
|
+
"env_vars": [
|
33
|
+
|
34
|
+
],
|
35
|
+
"objects": [
|
36
|
+
{
|
37
|
+
"name": "build_action_errors",
|
38
|
+
"schema": "packages/ree_roda/schemas/ree_roda/services/build_action_errors.schema.json",
|
39
|
+
"tags": [
|
40
|
+
"fn"
|
41
|
+
]
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"name": "build_swagger_from_actions",
|
45
|
+
"schema": "packages/ree_roda/schemas/ree_roda/services/build_swagger_from_actions.schema.json",
|
46
|
+
"tags": [
|
47
|
+
"fn"
|
48
|
+
]
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"name": "status_from_error",
|
52
|
+
"schema": "packages/ree_roda/schemas/ree_roda/services/status_from_error.schema.json",
|
53
|
+
"tags": [
|
54
|
+
"fn"
|
55
|
+
]
|
56
|
+
}
|
57
|
+
]
|
58
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
package_require("ree_errors/error")
|
2
|
+
package_require("ree_mapper/errors/type_error")
|
3
|
+
|
4
|
+
class ReeRoda::App < Roda
|
5
|
+
include Ree::LinkDSL
|
6
|
+
|
7
|
+
link :logger, from: :ree_logger
|
8
|
+
link :status_from_error
|
9
|
+
link :to_json, from: :ree_json
|
10
|
+
|
11
|
+
plugin :error_handler
|
12
|
+
plugin :json_parser
|
13
|
+
plugin :type_routing, default_type: :json
|
14
|
+
|
15
|
+
error do |e|
|
16
|
+
response["Content-Type"] = "application/json"
|
17
|
+
|
18
|
+
if e.is_a?(ReeErrors::Error)
|
19
|
+
body = {
|
20
|
+
code: e.code,
|
21
|
+
message: e.message,
|
22
|
+
type: e.type,
|
23
|
+
}
|
24
|
+
|
25
|
+
response.status = status_from_error(e.type)
|
26
|
+
response.write(to_json(body))
|
27
|
+
response.finish
|
28
|
+
elsif e.is_a?(ReeMapper::TypeError) || e.is_a?(ReeMapper::CoercionError)
|
29
|
+
body = {
|
30
|
+
code: "param",
|
31
|
+
message: e.message,
|
32
|
+
type: :invalid_param,
|
33
|
+
}
|
34
|
+
|
35
|
+
response.status = 400
|
36
|
+
response.write(to_json(body))
|
37
|
+
response.finish
|
38
|
+
else
|
39
|
+
logger.error(e.message, {}, e)
|
40
|
+
response["Content-Type"] = "text/plain"
|
41
|
+
response.status = 500
|
42
|
+
response.write("unhandled server error")
|
43
|
+
response.finish
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|