params_ready 0.0.1
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 +7 -0
- data/lib/arel/cte_name.rb +20 -0
- data/lib/params_ready.rb +36 -0
- data/lib/params_ready/builder.rb +140 -0
- data/lib/params_ready/error.rb +31 -0
- data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
- data/lib/params_ready/extensions/collection.rb +43 -0
- data/lib/params_ready/extensions/delegation.rb +25 -0
- data/lib/params_ready/extensions/finalizer.rb +26 -0
- data/lib/params_ready/extensions/freezer.rb +49 -0
- data/lib/params_ready/extensions/hash.rb +46 -0
- data/lib/params_ready/extensions/late_init.rb +38 -0
- data/lib/params_ready/extensions/registry.rb +44 -0
- data/lib/params_ready/extensions/undefined.rb +15 -0
- data/lib/params_ready/format.rb +130 -0
- data/lib/params_ready/helpers/arel_builder.rb +68 -0
- data/lib/params_ready/helpers/conditional_block.rb +31 -0
- data/lib/params_ready/helpers/find_in_hash.rb +22 -0
- data/lib/params_ready/helpers/key_map.rb +176 -0
- data/lib/params_ready/helpers/memo.rb +42 -0
- data/lib/params_ready/helpers/options.rb +39 -0
- data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
- data/lib/params_ready/helpers/parameter_storage_class_methods.rb +36 -0
- data/lib/params_ready/helpers/parameter_user_class_methods.rb +31 -0
- data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
- data/lib/params_ready/helpers/rule.rb +57 -0
- data/lib/params_ready/helpers/storage.rb +30 -0
- data/lib/params_ready/helpers/usage_rule.rb +18 -0
- data/lib/params_ready/input_context.rb +31 -0
- data/lib/params_ready/intent.rb +70 -0
- data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
- data/lib/params_ready/marshaller/builder_module.rb +9 -0
- data/lib/params_ready/marshaller/collection.rb +165 -0
- data/lib/params_ready/marshaller/definition_module.rb +63 -0
- data/lib/params_ready/marshaller/hash_marshallers.rb +100 -0
- data/lib/params_ready/marshaller/hash_set_marshallers.rb +96 -0
- data/lib/params_ready/marshaller/parameter_module.rb +11 -0
- data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
- data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
- data/lib/params_ready/ordering/column.rb +60 -0
- data/lib/params_ready/ordering/ordering.rb +276 -0
- data/lib/params_ready/output_parameters.rb +127 -0
- data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
- data/lib/params_ready/pagination/cursor.rb +171 -0
- data/lib/params_ready/pagination/direction.rb +148 -0
- data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
- data/lib/params_ready/pagination/keysets.rb +70 -0
- data/lib/params_ready/pagination/nulls.rb +31 -0
- data/lib/params_ready/pagination/offset_pagination.rb +130 -0
- data/lib/params_ready/pagination/tendency.rb +28 -0
- data/lib/params_ready/parameter/abstract_hash_parameter.rb +204 -0
- data/lib/params_ready/parameter/array_parameter.rb +197 -0
- data/lib/params_ready/parameter/definition.rb +264 -0
- data/lib/params_ready/parameter/hash_parameter.rb +63 -0
- data/lib/params_ready/parameter/hash_set_parameter.rb +101 -0
- data/lib/params_ready/parameter/parameter.rb +456 -0
- data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
- data/lib/params_ready/parameter/state.rb +132 -0
- data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
- data/lib/params_ready/parameter/value_parameter.rb +182 -0
- data/lib/params_ready/parameter_definer.rb +14 -0
- data/lib/params_ready/parameter_user.rb +43 -0
- data/lib/params_ready/query/array_grouping.rb +68 -0
- data/lib/params_ready/query/custom_predicate.rb +102 -0
- data/lib/params_ready/query/exists_predicate.rb +103 -0
- data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
- data/lib/params_ready/query/grouping.rb +177 -0
- data/lib/params_ready/query/join_clause.rb +87 -0
- data/lib/params_ready/query/nullness_predicate.rb +71 -0
- data/lib/params_ready/query/polymorph_predicate.rb +77 -0
- data/lib/params_ready/query/predicate.rb +203 -0
- data/lib/params_ready/query/predicate_operator.rb +132 -0
- data/lib/params_ready/query/relation.rb +337 -0
- data/lib/params_ready/query/structured_grouping.rb +58 -0
- data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
- data/lib/params_ready/query_context.rb +21 -0
- data/lib/params_ready/restriction.rb +252 -0
- data/lib/params_ready/result.rb +109 -0
- data/lib/params_ready/value/coder.rb +181 -0
- data/lib/params_ready/value/constraint.rb +198 -0
- data/lib/params_ready/value/custom.rb +56 -0
- data/lib/params_ready/value/validator.rb +68 -0
- metadata +181 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../extensions/undefined'
|
2
|
+
require_relative '../extensions/hash'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module ParamsReady
|
7
|
+
module Helpers
|
8
|
+
class Memo
|
9
|
+
def initialize(slots = 1)
|
10
|
+
raise ParamsReadyError, "Expected positive value for number of slots, got: '#{slots}'" unless slots > 0
|
11
|
+
@slots = slots
|
12
|
+
@cache = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def cached_value(key)
|
16
|
+
cache = @cache
|
17
|
+
return Extensions::Undefined if cache.nil?
|
18
|
+
return Extensions::Undefined unless cache.key? key
|
19
|
+
|
20
|
+
cache[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_value(value, key)
|
24
|
+
|
25
|
+
stale = @cache
|
26
|
+
return if stale&.key? key
|
27
|
+
|
28
|
+
frozen = Extensions::Hash.try_deep_freeze(value)
|
29
|
+
|
30
|
+
fresh = if stale.nil? || @slots == 1
|
31
|
+
{ key => frozen }
|
32
|
+
else
|
33
|
+
kept = stale.to_a.last(@slots - 1)
|
34
|
+
|
35
|
+
[*kept, [key, frozen]].to_h
|
36
|
+
end
|
37
|
+
|
38
|
+
@cache = fresh.freeze
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'storage'
|
2
|
+
require_relative 'usage_rule'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
module Helpers
|
6
|
+
class Options < Storage
|
7
|
+
attr_reader :parameters, :relations
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@parameter_rules = Hash.new
|
12
|
+
@relation_rules = Hash.new
|
13
|
+
@state = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def use_parameter(param, rule_args = :all)
|
17
|
+
rule = UsageRule.new(param, rule_args)
|
18
|
+
@parameter_rules[param.name] = rule
|
19
|
+
end
|
20
|
+
|
21
|
+
def use_relation(relation, rule_args = :all)
|
22
|
+
rule = UsageRule.new(relation, rule_args)
|
23
|
+
@relation_rules[relation.name] = rule
|
24
|
+
end
|
25
|
+
|
26
|
+
def parameter_rules
|
27
|
+
@parameter_rules.each_value do |rule|
|
28
|
+
yield rule
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def relation_rules
|
33
|
+
@relation_rules.each_value do |rule|
|
34
|
+
yield rule
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'relation_builder_wrapper'
|
2
|
+
require_relative '../builder'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
module Helpers
|
6
|
+
module ParameterDefinerClassMethods
|
7
|
+
def define_relation(*args, **opts, &block)
|
8
|
+
wrapper = ParamsReady::Helpers::RelationBuilderWrapper.new self, *args, **opts
|
9
|
+
wrapper.instance_eval(&block) unless block.nil?
|
10
|
+
relation = wrapper.build
|
11
|
+
params_ready_storage.add_relation relation
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_parameter(type, *args, **opts, &block)
|
15
|
+
full_name = "define_#{type}"
|
16
|
+
parameter = Builder.send(full_name, *args, **opts, &block)
|
17
|
+
params_ready_storage.add_parameter parameter
|
18
|
+
end
|
19
|
+
|
20
|
+
def all_relations
|
21
|
+
relations = if superclass.respond_to? :all_relations
|
22
|
+
superclass.all_relations
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
relations.merge(params_ready_storage.relations)
|
27
|
+
end
|
28
|
+
|
29
|
+
def all_parameters
|
30
|
+
parameters = if superclass.respond_to? :all_parameters
|
31
|
+
superclass.all_parameters
|
32
|
+
else
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
parameters.merge(params_ready_storage.parameters)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'storage'
|
2
|
+
require_relative '../error'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
module Helpers
|
6
|
+
module ParameterStorageClassMethods
|
7
|
+
def params_ready_storage
|
8
|
+
@params_ready_storage ||= Storage.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def relation_definition(key)
|
12
|
+
relations = params_ready_storage.relations
|
13
|
+
sym_key = key.to_sym
|
14
|
+
if relations.key?(sym_key)
|
15
|
+
relations[sym_key]
|
16
|
+
elsif superclass.respond_to? :relation_definition
|
17
|
+
superclass.relation_definition sym_key
|
18
|
+
else
|
19
|
+
raise ParamsReadyError, "Unknown relation '#{sym_key}'"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def parameter_definition(key)
|
24
|
+
parameters = params_ready_storage.parameters
|
25
|
+
sym_key = key.to_sym
|
26
|
+
if parameters.key? sym_key
|
27
|
+
parameters[sym_key]
|
28
|
+
elsif superclass.respond_to? :parameter_definition
|
29
|
+
superclass.parameter_definition sym_key
|
30
|
+
else
|
31
|
+
raise ParamsReadyError, "Unknown parameter '#{sym_key}'"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ParamsReady
|
2
|
+
module Helpers
|
3
|
+
module ParameterUserClassMethods
|
4
|
+
def params_ready_storage
|
5
|
+
@params_ready_storage ||= ParamsReady::Helpers::Options.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def use_parameter(name, rule = :all)
|
9
|
+
parameter = parameter_definition name
|
10
|
+
params_ready_storage.use_parameter parameter, rule
|
11
|
+
end
|
12
|
+
|
13
|
+
def use_relation(name, rule = :all)
|
14
|
+
relation = relation_definition name
|
15
|
+
params_ready_storage.use_relation relation, rule
|
16
|
+
end
|
17
|
+
|
18
|
+
def include_parameters(parameter_definer)
|
19
|
+
parameter_definer.all_parameters.values.each do |p|
|
20
|
+
params_ready_storage.add_parameter(p)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def include_relations(parameter_definer)
|
25
|
+
parameter_definer.all_relations.values.each do |d|
|
26
|
+
params_ready_storage.add_relation(d)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../query/relation'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
module Helpers
|
5
|
+
class RelationBuilderWrapper
|
6
|
+
def initialize(cache, *args, **opts)
|
7
|
+
@cache = cache
|
8
|
+
@builder = Query::RelationParameterBuilder.instance *args, **opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def capture(*names)
|
12
|
+
names.each do |name|
|
13
|
+
definition = @cache.parameter_definition(name)
|
14
|
+
@builder.add definition
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
ruby2_keywords def method_missing(name, *args, &block)
|
19
|
+
if @builder.respond_to? name
|
20
|
+
@builder.send name, *args, &block
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(name, include_private = false)
|
27
|
+
if @builder.respond_to? name
|
28
|
+
true
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
module Helpers
|
5
|
+
def self.Rule(input)
|
6
|
+
return input if input.nil?
|
7
|
+
return input if input.is_a? Rule
|
8
|
+
|
9
|
+
Rule.new(input).freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
class Rule
|
13
|
+
attr_reader :hash
|
14
|
+
|
15
|
+
def initialize(value)
|
16
|
+
@mode, @values = case value
|
17
|
+
when :none, :all then [value, nil]
|
18
|
+
when Hash
|
19
|
+
if value.length > 1 || value.length < 1
|
20
|
+
raise ParamsReadyError, "Unexpected hash for rule: '#{value}'"
|
21
|
+
end
|
22
|
+
key, values = value.first
|
23
|
+
case key
|
24
|
+
when :except, :only then [key, values.to_set.freeze]
|
25
|
+
else
|
26
|
+
raise ParamsReadyError, "Unexpected mode for rule: '#{key}'"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise ParamsReadyError, "Unexpected input for rule: '#{value}'"
|
30
|
+
end
|
31
|
+
@values.freeze
|
32
|
+
@hash = [@mode, @values].hash
|
33
|
+
freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
def include?(name)
|
37
|
+
case @mode
|
38
|
+
when :none then false
|
39
|
+
when :all then true
|
40
|
+
when :only then @values.member? name
|
41
|
+
when :except
|
42
|
+
!@values.member? name
|
43
|
+
else
|
44
|
+
raise ParamsReadyError, "Unexpected mode for rule: '#{@mode}'"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ==(other)
|
49
|
+
return false unless other.is_a? Rule
|
50
|
+
return true if object_id == other.object_id
|
51
|
+
return false unless @mode == other.instance_variable_get(:@mode)
|
52
|
+
|
53
|
+
@values == other.instance_variable_get(:@values)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ParamsReady
|
2
|
+
module Helpers
|
3
|
+
class Storage
|
4
|
+
attr_reader :parameters, :relations
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@parameters = Hash.new
|
8
|
+
@relations = Hash.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_relation?(name)
|
12
|
+
relations.key? name
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_parameter?(name)
|
16
|
+
parameters.key? name
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_relation(relation)
|
20
|
+
raise ParamsReadyError, "Relation already exists: #{relation.name}" if self.has_relation?(relation.name)
|
21
|
+
@relations[relation.name] = relation
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_parameter(param)
|
25
|
+
raise ParamsReadyError, "Parameter already exists: #{param.name}" if self.has_parameter?(param.name)
|
26
|
+
@parameters[param.name] = param
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'rule'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
module Helpers
|
5
|
+
class UsageRule
|
6
|
+
attr_reader :parameter_definition
|
7
|
+
|
8
|
+
def initialize(parameter_definition, rule = :all)
|
9
|
+
@parameter_definition = parameter_definition
|
10
|
+
@rule = ParamsReady::Helpers::Rule(rule)
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_for(method)
|
14
|
+
@rule.include? method
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative 'format'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
class InputContext
|
6
|
+
include Format::Wrapper
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :data
|
10
|
+
|
11
|
+
def_delegator :data, :[]
|
12
|
+
|
13
|
+
def initialize(format, data = {})
|
14
|
+
@format = Format.resolve(format).freeze
|
15
|
+
@data = data.freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.resolve(unknown)
|
19
|
+
case unknown
|
20
|
+
when nil
|
21
|
+
Format.instance(:frontend)
|
22
|
+
when InputContext, Format
|
23
|
+
unknown
|
24
|
+
when Symbol
|
25
|
+
Format.instance(unknown)
|
26
|
+
else
|
27
|
+
raise ParamsReadyError, "Unexpected type for InputContext: #{unknown.class.name}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative 'restriction'
|
3
|
+
require_relative 'format'
|
4
|
+
require_relative 'parameter/parameter'
|
5
|
+
|
6
|
+
module ParamsReady
|
7
|
+
class Intent
|
8
|
+
extend Forwardable
|
9
|
+
include Restriction::Wrapper
|
10
|
+
include Format::Wrapper
|
11
|
+
|
12
|
+
def clone(restriction:)
|
13
|
+
Intent.new @format, restriction, data: @data
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :data, :hash
|
17
|
+
|
18
|
+
def initialize(format, restriction = Restriction.blanket_permission, data: nil)
|
19
|
+
@format = Format.resolve(format).freeze
|
20
|
+
raise ParamsReadyError, "Restriction expected, got: #{restriction.inspect}" unless restriction.is_a? Restriction
|
21
|
+
@restriction = restriction
|
22
|
+
@data = check_data(data)
|
23
|
+
@hash = [@format, @restriction, @data].hash
|
24
|
+
freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_data(data)
|
28
|
+
return if data.nil?
|
29
|
+
# The reason we require data object to be
|
30
|
+
# a Parameter is that it must be deep frozen
|
31
|
+
# for the output memoizing feature to work properly.
|
32
|
+
raise 'Data object must be a parameter' unless data.is_a? Parameter::Parameter
|
33
|
+
raise 'Data object must be frozen' unless data.frozen?
|
34
|
+
|
35
|
+
data
|
36
|
+
end
|
37
|
+
|
38
|
+
def omit?(parameter)
|
39
|
+
return true unless permitted?(parameter)
|
40
|
+
@format.omit?(parameter)
|
41
|
+
end
|
42
|
+
|
43
|
+
def preserve?(parameter)
|
44
|
+
!omit?(parameter)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.instance(name)
|
48
|
+
format = Format.instance(name)
|
49
|
+
Intent.new(format)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.resolve(intent_or_name)
|
53
|
+
if intent_or_name.is_a? Intent
|
54
|
+
intent_or_name
|
55
|
+
else
|
56
|
+
instance(intent_or_name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ==(other)
|
61
|
+
return false unless other.is_a?(Intent)
|
62
|
+
return true if object_id == other.object_id
|
63
|
+
restriction == other.restriction && format == other.format && data == other.data
|
64
|
+
end
|
65
|
+
|
66
|
+
def eql?(other)
|
67
|
+
self == other
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative 'collection'
|
2
|
+
require_relative '../extensions/undefined'
|
3
|
+
require_relative '../extensions/hash'
|
4
|
+
require_relative '../helpers/find_in_hash'
|
5
|
+
|
6
|
+
module ParamsReady
|
7
|
+
module Marshaller
|
8
|
+
class ArrayMarshallers
|
9
|
+
module AbstractMarshaller
|
10
|
+
def marshal(parameter, intent)
|
11
|
+
array = parameter.send(:bare_value)
|
12
|
+
definition = parameter.definition
|
13
|
+
compact = definition.compact?
|
14
|
+
|
15
|
+
elements = array.map do |element|
|
16
|
+
if element.eligible_for_output?(intent)
|
17
|
+
element.format_self_permitted(intent)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
elements = elements.compact if compact
|
21
|
+
do_marshal(elements, intent, compact)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ArrayMarshaller
|
26
|
+
extend AbstractMarshaller
|
27
|
+
|
28
|
+
def self.canonicalize(definition, array, context, validator, freeze: false)
|
29
|
+
canonical = array.map do |value|
|
30
|
+
next if definition.compact? && value.nil?
|
31
|
+
|
32
|
+
element = definition.prototype.create
|
33
|
+
element.set_from_input(value, context, validator)
|
34
|
+
next if definition.compact? && element.is_nil?
|
35
|
+
|
36
|
+
element.freeze if freeze
|
37
|
+
element
|
38
|
+
end.compact
|
39
|
+
|
40
|
+
[canonical, validator]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.do_marshal(array, _, _)
|
44
|
+
array
|
45
|
+
end
|
46
|
+
|
47
|
+
freeze
|
48
|
+
end
|
49
|
+
|
50
|
+
module HashMarshaller
|
51
|
+
extend AbstractMarshaller
|
52
|
+
|
53
|
+
def self.canonicalize(definition, hash, context, validator)
|
54
|
+
if definition.compact?
|
55
|
+
ArrayMarshaller.canonicalize(definition, hash.values, context, validator)
|
56
|
+
else
|
57
|
+
count_key = :cnt
|
58
|
+
found, count = Helpers::FindInHash.find_in_hash hash, count_key
|
59
|
+
raise ParamsReadyError, "Count not found" unless found
|
60
|
+
|
61
|
+
count = Integer(count)
|
62
|
+
array = (0...count).map do |index|
|
63
|
+
found, value = Helpers::FindInHash.find_in_hash hash, index
|
64
|
+
element = definition.prototype.create
|
65
|
+
element.set_from_input(value, context, validator) if found
|
66
|
+
element
|
67
|
+
end
|
68
|
+
[array, validator]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.do_marshal(array, _, compact)
|
73
|
+
return array if compact
|
74
|
+
|
75
|
+
result = array.each_with_index.reduce({}) do |result, (element, index)|
|
76
|
+
index = index.to_s
|
77
|
+
result[index] = element
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
result['cnt'] = array.length.to_s
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
freeze
|
86
|
+
end
|
87
|
+
|
88
|
+
class StringMarshaller
|
89
|
+
include AbstractMarshaller
|
90
|
+
|
91
|
+
attr_reader :separator
|
92
|
+
|
93
|
+
def self.instance(separator:, split_pattern: nil)
|
94
|
+
instance = new separator, split_pattern
|
95
|
+
[String, instance.freeze]
|
96
|
+
end
|
97
|
+
|
98
|
+
def initialize(separator, split_pattern)
|
99
|
+
@separator = separator.to_s.freeze
|
100
|
+
@split_pattern = split_pattern.freeze
|
101
|
+
end
|
102
|
+
|
103
|
+
def split_pattern
|
104
|
+
@split_pattern || @separator
|
105
|
+
end
|
106
|
+
|
107
|
+
def canonicalize(definition, string, context, validator)
|
108
|
+
array = string.split(split_pattern).map(&:strip).reject(&:empty?)
|
109
|
+
ArrayMarshaller.canonicalize(definition, array, context, validator)
|
110
|
+
end
|
111
|
+
|
112
|
+
def do_marshal(array, _, _)
|
113
|
+
array.join(separator)
|
114
|
+
end
|
115
|
+
|
116
|
+
freeze
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.collection
|
120
|
+
@collection ||= begin
|
121
|
+
c = ClassCollection.new Array
|
122
|
+
c.add_instance Array, ArrayMarshaller
|
123
|
+
c.add_instance Hash, HashMarshaller
|
124
|
+
c.add_factory :string, StringMarshaller
|
125
|
+
c.default!(Hash)
|
126
|
+
c.freeze
|
127
|
+
c
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|