params_ready 0.0.2 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/params_ready/builder.rb +21 -0
  3. data/lib/params_ready/extensions/delegation.rb +1 -0
  4. data/lib/params_ready/extensions/freezer.rb +2 -0
  5. data/lib/params_ready/extensions/undefined.rb +8 -0
  6. data/lib/params_ready/format.rb +4 -2
  7. data/lib/params_ready/helpers/arel_builder.rb +96 -35
  8. data/lib/params_ready/helpers/callable.rb +14 -0
  9. data/lib/params_ready/helpers/interface_definer.rb +48 -0
  10. data/lib/params_ready/helpers/memo.rb +0 -1
  11. data/lib/params_ready/helpers/options.rb +77 -9
  12. data/lib/params_ready/helpers/parameter_storage_class_methods.rb +27 -0
  13. data/lib/params_ready/helpers/parameter_user_class_methods.rb +18 -14
  14. data/lib/params_ready/helpers/rule.rb +30 -11
  15. data/lib/params_ready/helpers/usage_rule.rb +21 -3
  16. data/lib/params_ready/marshaller/array_marshallers.rb +4 -3
  17. data/lib/params_ready/marshaller/{hash_set_marshallers.rb → enum_set_marshallers.rb} +5 -5
  18. data/lib/params_ready/marshaller/polymorph_marshallers.rb +2 -2
  19. data/lib/params_ready/marshaller/{hash_marshallers.rb → struct_marshallers.rb} +5 -5
  20. data/lib/params_ready/marshaller/tuple_marshallers.rb +2 -2
  21. data/lib/params_ready/ordering/column.rb +1 -1
  22. data/lib/params_ready/output_parameters.rb +13 -2
  23. data/lib/params_ready/pagination/keyset_pagination.rb +5 -5
  24. data/lib/params_ready/parameter/{abstract_hash_parameter.rb → abstract_struct_parameter.rb} +6 -6
  25. data/lib/params_ready/parameter/array_parameter.rb +2 -2
  26. data/lib/params_ready/parameter/definition.rb +48 -40
  27. data/lib/params_ready/parameter/{hash_set_parameter.rb → enum_set_parameter.rb} +11 -10
  28. data/lib/params_ready/parameter/parameter.rb +48 -29
  29. data/lib/params_ready/parameter/state.rb +4 -4
  30. data/lib/params_ready/parameter/{hash_parameter.rb → struct_parameter.rb} +11 -10
  31. data/lib/params_ready/parameter/tuple_parameter.rb +1 -1
  32. data/lib/params_ready/parameter/value_parameter.rb +14 -10
  33. data/lib/params_ready/parameter_user.rb +7 -15
  34. data/lib/params_ready/query/array_grouping.rb +4 -4
  35. data/lib/params_ready/query/exists_predicate.rb +3 -3
  36. data/lib/params_ready/query/grouping.rb +8 -2
  37. data/lib/params_ready/query/join_clause.rb +91 -28
  38. data/lib/params_ready/query/predicate.rb +3 -3
  39. data/lib/params_ready/query/relation.rb +29 -14
  40. data/lib/params_ready/query/structured_grouping.rb +4 -4
  41. data/lib/params_ready/query/variable_operator_predicate.rb +12 -12
  42. data/lib/params_ready/value/coder.rb +36 -8
  43. data/lib/params_ready/version.rb +7 -0
  44. data/lib/params_ready.rb +3 -11
  45. metadata +56 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e0db6411b802c544350d14eb54c921ae019ac7b2365fc2639b4f2f1b77ee40a
4
- data.tar.gz: 3811299181627e888b1ac97970a4264f850db87f0475be355a138a30aa825eb1
3
+ metadata.gz: f153e27fbce45bc4e81a566ef856825db2dea6a144e2122202728e6f937e7b9f
4
+ data.tar.gz: 1d5c56bcc909fa607022cb1f236a91ab4707dbf6753cd4f8ed1d1702a80be997
5
5
  SHA512:
6
- metadata.gz: f2f339b6dd2a649244d53c94168ad3e3b238a42268632175c08c3928e01861d75c5c19d7fc3c29b8e0482e8658ed6e5f3a17d9ccda34d0b63808b5e1538b4870
7
- data.tar.gz: 355252607fd9c47d58acf4cf1176bc5d35677390bbfeecfe1e24d881f9303be23d20dbcc8611b9c4cff25ff277944e0a2ad9e85aef7ccf0e7174a0a02856f1c3
6
+ metadata.gz: a8f822219c2fa60a422bf9afb4d483e882eb61aa25a16491534feadf351c8eae8648576e3efcd9bc4e45889701946d8c48a1b5870b440d8e2eb2692cb9368c9a
7
+ data.tar.gz: 93ce29aafd6b755cc9a628f8ee7ff58c4d2b7c8f5f0b9dede9a75f8fb67e1255dd6e89ae9890ab61ef3737dcdf1d4d9c847dcab9ddd371250ed71a729f135e39
@@ -28,6 +28,23 @@ module ParamsReady
28
28
  register_builder(name, self)
29
29
  end
30
30
 
31
+ def self.register_deprecated(name, use:)
32
+ raise ParamsReadyError, 'Recommended replacement must not be nil' if use.nil?
33
+ @deprecated ||= {}
34
+ @deprecated[name] = use.to_s.freeze
35
+ register_builder(name, self)
36
+ end
37
+
38
+ class << self
39
+ alias_method :fetch_builder, :builder
40
+ end
41
+
42
+ def self.builder(name)
43
+ use = @deprecated[name] if @deprecated&.key? name
44
+ warn "Builder name deprecated: #{name}, use: #{use}" unless use.nil?
45
+ fetch_builder(name)
46
+ end
47
+
31
48
  def self.define_parameter(type, *args, **opts, &block)
32
49
  builder_class = builder(type)
33
50
  builder = builder_class.instance(*args, **opts)
@@ -94,6 +111,10 @@ module ParamsReady
94
111
  @definition.set_no_output Helpers::Rule(rule) || true
95
112
  end
96
113
 
114
+ def no_input(*arr, rule: nil)
115
+ @definition.set_no_input *arr, rule: rule
116
+ end
117
+
97
118
  def local(*arr, rule: nil)
98
119
  @definition.set_local *arr, rule: rule
99
120
  end
@@ -10,6 +10,7 @@ module ParamsReady
10
10
  super name, *args, &block
11
11
  end
12
12
  end
13
+ mod.send(:ruby2_keywords, :method_missing)
13
14
 
14
15
  mod.define_method :respond_to_missing? do |name, include_private = false|
15
16
  delegee = instance_eval(&to)
@@ -25,6 +25,8 @@ module ParamsReady
25
25
  next if frozen?
26
26
  self.class.variables_to_freeze.each do |(ivar, block)|
27
27
  variable = instance_variable_get ivar
28
+ next if Extensions::Undefined.value_indefinite?(variable)
29
+
28
30
  block.call(variable) unless block.nil?
29
31
  variable.freeze
30
32
  end
@@ -5,6 +5,14 @@ module ParamsReady
5
5
  self
6
6
  end
7
7
 
8
+ def self.present?
9
+ false
10
+ end
11
+
12
+ def self.blank?
13
+ true
14
+ end
15
+
8
16
  def self.value_indefinite?(value)
9
17
  value == self || value.nil?
10
18
  end
@@ -100,8 +100,10 @@ module ParamsReady
100
100
  @names = {
101
101
  backend: Format.new(marshal: :none, omit: [], naming_scheme: :standard, remap: false, local: true, name: :backend),
102
102
  frontend: Format.new(marshal: :all, omit: OMIT_ALL, naming_scheme: :alternative, remap: false, local: false, name: :frontend),
103
- attributes: Format.new(marshal: :none, omit: %i(undefined), naming_scheme: :standard, remap: false, local: true, name: :attributes),
104
- json: Format.new(marshal: { except: [:array, :tuple, :boolean, :number] }, omit: [], naming_scheme: :alternative, remap: true, local: false, name: :json)
103
+ create: Format.new(marshal: :none, omit: [], naming_scheme: :standard, remap: false, local: true, name: :create),
104
+ update: Format.new(marshal: :none, omit: %i(undefined), naming_scheme: :standard, remap: false, local: true, name: :update),
105
+ json: Format.new(marshal: { except: [:array, :tuple, :boolean, :number] }, omit: [], naming_scheme: :alternative, remap: true, local: false, name: :json),
106
+ inspect: Format.new(marshal: :none, omit: [], naming_scheme: :standard, remap: false, local: false, name: :inspect)
105
107
  }.freeze
106
108
 
107
109
  def self.define(name, format)
@@ -2,26 +2,7 @@ require_relative '../error'
2
2
 
3
3
  module ParamsReady
4
4
  module Helpers
5
- class ArelBuilder
6
- def self.instance(object, arel_table: nil)
7
- case object
8
- when Arel::Nodes::Node, Arel::Nodes::SqlLiteral, Arel::Attribute
9
- raise ParamsReadyError, "Arel table unexpected" unless arel_table.nil? || arel_table == :none
10
- ArelObject.new(object)
11
- when Proc
12
- raise ParamsReadyError, "Arel table unexpected" unless arel_table.nil? || arel_table == :none
13
- Callable.new(object)
14
- when String, Symbol
15
- Literal.new(object, arel_table)
16
- else
17
- raise ParamsReadyError, "Unexpected type for arel builder: #{object.class.name}"
18
- end
19
- end
20
-
21
- def self.safe_name(name)
22
- name[0...64]
23
- end
24
-
5
+ module ArelBuilder
25
6
  class Callable
26
7
  def initialize(proc)
27
8
  @proc = proc
@@ -31,38 +12,118 @@ module ParamsReady
31
12
  result = @proc.call(*args)
32
13
  case result
33
14
  when String, Symbol
34
- Helpers::ArelBuilder.instance(result).to_arel(*args)
15
+ to_literal(result).to_arel(*args)
35
16
  else
36
17
  result
37
18
  end
38
19
  end
20
+
21
+ def to_literal(*)
22
+ raise ParamsReadyError, "Unimplemented: #{self.class.name}##{__callee__}"
23
+ end
24
+ end
25
+
26
+ class ArelObject
27
+ def initialize(node)
28
+ @node = node
29
+ end
30
+
31
+ def to_arel(*)
32
+ @node
33
+ end
34
+ end
35
+
36
+ def self.safe_name(name)
37
+ name[0...64]
39
38
  end
40
39
 
41
40
  class Literal
42
- def initialize(literal, arel_table)
43
- @literal = literal.to_s
44
- @arel_table = arel_table
41
+ def initialize(literal)
42
+ @literal = literal.to_s.freeze
45
43
  end
46
44
 
47
- def to_arel(default_table, _, _)
48
- arel_table = @arel_table || default_table
49
- if arel_table == :none
50
- Arel::Nodes::SqlLiteral.new(@literal)
45
+ def to_arel(*)
46
+ Arel::Nodes::SqlLiteral.new(@literal)
47
+ end
48
+ end
49
+
50
+ class Attribute
51
+ def self.instance(object, arel_table: nil)
52
+ case object
53
+ when Arel::Nodes::Node, Arel::Nodes::SqlLiteral, Arel::Attribute
54
+ raise ParamsReadyError, "Arel table unexpected" unless arel_table.nil? || arel_table == :none
55
+ ArelObject.new(object)
56
+ when Proc
57
+ raise ParamsReadyError, "Arel table unexpected" unless arel_table.nil? || arel_table == :none
58
+ Callable.new(object)
59
+ when String, Symbol
60
+ Literal.new(object, arel_table)
51
61
  else
52
- arel_table[@literal]
62
+ raise ParamsReadyError, "Unexpected type for arel builder: #{object.class.name}"
63
+ end
64
+ end
65
+
66
+ class Callable < ArelBuilder::Callable
67
+ def to_literal(string)
68
+ Helpers::ArelBuilder::Attribute.instance(string)
69
+ end
70
+ end
71
+
72
+ class Literal < ArelBuilder::Literal
73
+ def initialize(literal, arel_table)
74
+ super literal
75
+ @arel_table = arel_table
76
+ end
77
+
78
+ def to_arel(default_table, *args)
79
+ arel_table = @arel_table || default_table
80
+ if arel_table == :none
81
+ super(*args)
82
+ else
83
+ arel_table[@literal]
84
+ end
53
85
  end
54
86
  end
55
87
  end
56
88
 
57
- class ArelObject
58
- def initialize(node)
59
- @node = node
89
+ class Table
90
+ def self.instance(object, table_alias: nil)
91
+ case object
92
+ when Arel::Table, Arel::Nodes::TableAlias
93
+ raise ParamsReadyError, "Table alias unexpected" unless table_alias.nil?
94
+ ArelObject.new(object)
95
+ when Proc
96
+ Callable.new(object, table_alias)
97
+ when String, Symbol
98
+ Literal.new(object, table_alias)
99
+ else
100
+ raise ParamsReadyError, "Unexpected type for arel builder: #{object.class.name}"
101
+ end
60
102
  end
61
103
 
62
- def to_arel(_, _, _)
63
- @node
104
+ class Callable < ArelBuilder::Callable
105
+ def initialize(proc, table_alias)
106
+ super proc
107
+ @table_alias = table_alias
108
+ end
109
+
110
+ def to_literal(string)
111
+ Helpers::ArelBuilder::Table.instance(string, table_alias: @table_alias)
112
+ end
113
+ end
114
+
115
+ class Literal < ArelBuilder::Literal
116
+ def initialize(literal, table_alias)
117
+ super literal
118
+ raise "Table alias must be present" if table_alias.nil?
119
+ @table_alias = table_alias.to_s.freeze
120
+ end
121
+
122
+ def to_arel(*)
123
+ Arel::Table.new(@literal).as(@table_alias)
124
+ end
64
125
  end
65
126
  end
66
127
  end
67
128
  end
68
- end
129
+ end
@@ -0,0 +1,14 @@
1
+ module ParamsReady
2
+ module Helpers
3
+ class Callable
4
+ def initialize(&block)
5
+ @block = block
6
+ freeze
7
+ end
8
+
9
+ def call
10
+ @block.call
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module ParamsReady
2
+ module Helpers
3
+ class InterfaceDefiner
4
+ def initialize(action_names, user)
5
+ @action_names = action_names
6
+ @user = user
7
+ end
8
+
9
+ def parameters(*names)
10
+ names.each do |name|
11
+ parameter(name)
12
+ end
13
+ end
14
+
15
+ def relations(*names)
16
+ names.each do |name|
17
+ relation(name)
18
+ end
19
+ end
20
+
21
+ def parameter(name)
22
+ @user.use_parameter(name, only: @action_names)
23
+ end
24
+
25
+ def relation(name)
26
+ @user.use_relation(name, only: @action_names)
27
+ end
28
+
29
+ def define(parameter: nil, relation: nil, parameters: [], relations: [], &block)
30
+ parameters = self.class.complete_list(parameter, parameters)
31
+ parameters(*parameters)
32
+ relations = self.class.complete_list(relation, relations)
33
+ relations(*relations)
34
+ instance_eval(&block) unless block.nil?
35
+ @option
36
+ end
37
+
38
+ def self.complete_list(singular, plural)
39
+ list = singular.nil? ? plural : [singular, *plural]
40
+ normalize_list(list)
41
+ end
42
+
43
+ def self.normalize_list(list)
44
+ list.map(&:to_sym)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -21,7 +21,6 @@ module ParamsReady
21
21
  end
22
22
 
23
23
  def cache_value(value, key)
24
-
25
24
  stale = @cache
26
25
  return if stale&.key? key
27
26
 
@@ -3,37 +3,105 @@ require_relative 'usage_rule'
3
3
 
4
4
  module ParamsReady
5
5
  module Helpers
6
- class Options < Storage
6
+ class Options
7
7
  attr_reader :parameters, :relations
8
8
 
9
9
  def initialize
10
- super
11
10
  @parameter_rules = Hash.new
12
11
  @relation_rules = Hash.new
13
- @state = nil
12
+ @memo = { definitions: {} }
13
+ end
14
+
15
+ def reset_memo!(*args)
16
+ args.each do |key|
17
+ @memo[key].clear
18
+ end
19
+ end
20
+
21
+ def dup
22
+ duplicate = Options.new
23
+ @parameter_rules.each do |_, rule|
24
+ duplicate.merge_parameter_rule(rule)
25
+ end
26
+ @relation_rules.each do |_, rule|
27
+ duplicate.merge_relation_rule(rule)
28
+ end
29
+ duplicate
30
+ end
31
+
32
+ def relation_definitions_for(name)
33
+ definitions_for(name, relation_rules)
34
+ end
35
+
36
+ def parameter_definitions_for(name)
37
+ definitions_for(name, parameter_rules)
38
+ end
39
+
40
+ def definitions_for(name, rules)
41
+ rules.each_with_object([]) do |(_, rule), result|
42
+ next unless rule.valid_for?(name)
43
+
44
+ result << rule.parameter_definition
45
+ end
14
46
  end
15
47
 
16
48
  def use_parameter(param, rule_args = :all)
17
49
  rule = UsageRule.new(param, rule_args)
18
- @parameter_rules[param.name] = rule
50
+ merge_parameter_rule(rule)
51
+ end
52
+
53
+ def merge_parameter_rule(rule)
54
+ reset_memo!(:definitions)
55
+ @parameter_rules = self.class.merge_rule(rule, @parameter_rules)
19
56
  end
20
57
 
21
58
  def use_relation(relation, rule_args = :all)
22
59
  rule = UsageRule.new(relation, rule_args)
23
- @relation_rules[relation.name] = rule
60
+ merge_relation_rule(rule)
61
+ end
62
+
63
+ def merge_relation_rule(rule)
64
+ reset_memo!(:definitions)
65
+ @relation_rules = self.class.merge_rule(rule, @relation_rules)
24
66
  end
25
67
 
26
68
  def parameter_rules
27
- @parameter_rules.each_value do |rule|
28
- yield rule
69
+ if block_given?
70
+ @parameter_rules.each_value do |rule|
71
+ yield rule
72
+ end
29
73
  end
74
+ @parameter_rules
30
75
  end
31
76
 
32
77
  def relation_rules
33
- @relation_rules.each_value do |rule|
34
- yield rule
78
+ if block_given?
79
+ @relation_rules.each_value do |rule|
80
+ yield rule
81
+ end
82
+ end
83
+ @relation_rules
84
+ end
85
+
86
+ def create_state_for(key)
87
+ @memo[:definitions][key] ||= begin
88
+ builder = Parameter::StateBuilder.instance
89
+ parameter_definitions_for(key).each do |definition|
90
+ builder.add definition
91
+ end
92
+ relation_definitions_for(key).each do |definition|
93
+ builder.relation definition
94
+ end
95
+ builder.build
35
96
  end
36
97
  end
98
+
99
+ def self.merge_rule(rule, rules)
100
+ existing = rules[rule.name]
101
+ merged = rule.merge(existing)
102
+ rules[rule.name] = merged
103
+ rules
104
+ end
37
105
  end
38
106
  end
39
107
  end
@@ -1,5 +1,6 @@
1
1
  require_relative 'storage'
2
2
  require_relative '../error'
3
+ require_relative 'rule'
3
4
 
4
5
  module ParamsReady
5
6
  module Helpers
@@ -31,6 +32,32 @@ module ParamsReady
31
32
  raise ParamsReadyError, "Unknown parameter '#{sym_key}'"
32
33
  end
33
34
  end
35
+
36
+ def include_parameters(parameter_definer, rule = nil)
37
+ rule = Helpers::Rule(rule)
38
+ parameter_definer.all_parameters.each do |key, definition|
39
+ next if rule && !rule.include?(key)
40
+
41
+ add_parameter(definition)
42
+ end
43
+ end
44
+
45
+ def add_parameter(definition)
46
+ params_ready_storage.add_parameter(definition)
47
+ end
48
+
49
+ def include_relations(parameter_definer, rule = nil)
50
+ rule = Helpers::Rule(rule)
51
+ parameter_definer.all_relations.each do |key, definition|
52
+ next if rule && !rule.include?(key)
53
+
54
+ add_relation(definition)
55
+ end
56
+ end
57
+
58
+ def add_relation(definition)
59
+ params_ready_storage.add_relation(definition)
60
+ end
34
61
  end
35
62
  end
36
63
  end
@@ -1,31 +1,35 @@
1
+ require_relative 'interface_definer'
2
+
1
3
  module ParamsReady
2
4
  module Helpers
3
5
  module ParameterUserClassMethods
4
- def params_ready_storage
5
- @params_ready_storage ||= ParamsReady::Helpers::Options.new
6
+ def params_ready_option
7
+ @params_ready_option ||= begin
8
+ if superclass.respond_to? :params_ready_option
9
+ # This works on assumption that superclass
10
+ # definition doesn't change during execution
11
+ superclass.params_ready_option.dup
12
+ else
13
+ ParamsReady::Helpers::Options.new
14
+ end
15
+ end
6
16
  end
7
17
 
8
18
  def use_parameter(name, rule = :all)
9
19
  parameter = parameter_definition name
10
- params_ready_storage.use_parameter parameter, rule
20
+ params_ready_option.use_parameter parameter, rule
11
21
  end
12
22
 
13
23
  def use_relation(name, rule = :all)
14
24
  relation = relation_definition name
15
- params_ready_storage.use_relation relation, rule
25
+ params_ready_option.use_relation relation, rule
16
26
  end
17
27
 
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
28
+ def action_interface(*action_names, **opts, &block)
29
+ definer = InterfaceDefiner.new(action_names, self)
23
30
 
24
- def include_relations(parameter_definer)
25
- parameter_definer.all_relations.values.each do |d|
26
- params_ready_storage.add_relation(d)
27
- end
31
+ definer.define(**opts, &block)
28
32
  end
29
33
  end
30
34
  end
31
- end
35
+ end
@@ -6,33 +6,52 @@ module ParamsReady
6
6
  return input if input.nil?
7
7
  return input if input.is_a? Rule
8
8
 
9
- Rule.new(input).freeze
9
+ Rule.instance(input).freeze
10
10
  end
11
11
 
12
- class Rule
13
- attr_reader :hash
12
+ class Rule
13
+ attr_reader :hash, :mode, :values
14
14
 
15
- def initialize(value)
16
- @mode, @values = case value
17
- when :none, :all then [value, nil]
15
+ def self.instance(input)
16
+ mode, values = case input
17
+ when :none, :all then [input, nil]
18
18
  when Hash
19
- if value.length > 1 || value.length < 1
20
- raise ParamsReadyError, "Unexpected hash for rule: '#{value}'"
19
+ if input.length > 1 || input.length < 1
20
+ raise ParamsReadyError, "Unexpected hash for rule: '#{input}'"
21
21
  end
22
- key, values = value.first
22
+ key, values = input.first
23
23
  case key
24
24
  when :except, :only then [key, values.to_set.freeze]
25
25
  else
26
26
  raise ParamsReadyError, "Unexpected mode for rule: '#{key}'"
27
27
  end
28
28
  else
29
- raise ParamsReadyError, "Unexpected input for rule: '#{value}'"
29
+ raise ParamsReadyError, "Unexpected input for rule: '#{input}'"
30
30
  end
31
- @values.freeze
31
+ new(mode, values)
32
+ end
33
+
34
+ def initialize(mode, values)
35
+ @mode = mode
36
+ @values = values.freeze
32
37
  @hash = [@mode, @values].hash
33
38
  freeze
34
39
  end
35
40
 
41
+ def merge(other)
42
+ return self if other.nil?
43
+ raise ParamsReadyError, "Can't merge with #{other.class.name}" unless other.is_a? Rule
44
+ raise ParamsReadyError, "Can't merge incompatible rules: #{mode}/#{other.mode}" if other.mode != mode
45
+
46
+ case mode
47
+ when :all, :none
48
+ self
49
+ when :only, :except
50
+ values = self.values + other.values
51
+ Rule.new(mode, values)
52
+ end
53
+ end
54
+
36
55
  def include?(name)
37
56
  case @mode
38
57
  when :none then false
@@ -3,16 +3,34 @@ require_relative 'rule'
3
3
  module ParamsReady
4
4
  module Helpers
5
5
  class UsageRule
6
- attr_reader :parameter_definition
6
+ attr_reader :parameter_definition, :rule
7
7
 
8
8
  def initialize(parameter_definition, rule = :all)
9
9
  @parameter_definition = parameter_definition
10
10
  @rule = ParamsReady::Helpers::Rule(rule)
11
+ freeze
11
12
  end
12
13
 
13
- def valid_for(method)
14
+ def valid_for?(method)
14
15
  @rule.include? method
15
16
  end
17
+
18
+ def name
19
+ parameter_definition.name
20
+ end
21
+
22
+ def merge(other)
23
+ return self if other.nil?
24
+ raise ParamsReadyError, "Can't merge into #{other.class.name}" unless other.is_a? UsageRule
25
+
26
+ unless parameter_definition == other.parameter_definition
27
+ message = "Can't merge incompatible rules: #{parameter_definition.name}/#{other.parameter_definition.name}"
28
+ raise ParamsReadyError, message
29
+ end
30
+
31
+ rule = self.rule.merge(other.rule)
32
+ UsageRule.new(parameter_definition, rule)
33
+ end
16
34
  end
17
35
  end
18
- end
36
+ end
@@ -47,7 +47,7 @@ module ParamsReady
47
47
  freeze
48
48
  end
49
49
 
50
- module HashMarshaller
50
+ module StructMarshaller
51
51
  extend AbstractMarshaller
52
52
 
53
53
  def self.canonicalize(definition, hash, context, validator)
@@ -58,7 +58,8 @@ module ParamsReady
58
58
  found, count = Helpers::FindInHash.find_in_hash hash, count_key
59
59
  raise ParamsReadyError, "Count not found" unless found
60
60
 
61
- count = Integer(count)
61
+ base = 10 if count.is_a? String
62
+ count = Integer(count, base)
62
63
  array = (0...count).map do |index|
63
64
  found, value = Helpers::FindInHash.find_in_hash hash, index
64
65
  element = definition.prototype.create
@@ -120,7 +121,7 @@ module ParamsReady
120
121
  @collection ||= begin
121
122
  c = ClassCollection.new Array
122
123
  c.add_instance Array, ArrayMarshaller
123
- c.add_instance Hash, HashMarshaller
124
+ c.add_instance Hash, StructMarshaller
124
125
  c.add_factory :string, StringMarshaller
125
126
  c.default!(Hash)
126
127
  c.freeze