lib/datacaster/predefined.rb in datacaster-3.1.2 vs lib/datacaster/predefined.rb in datacaster-3.1.3
- old
+ new
@@ -87,10 +87,30 @@
error_keys = ['.any', 'datacaster.errors.any']
error_keys.unshift(error_key) if error_key
check { |x| x != Datacaster.absent }.i18n_key(*error_keys)
end
+ def attribute(*keys)
+ if keys.empty? || keys.any? { |k| !Datacaster::Utils.pickable?(k) }
+ raise RuntimeError, "each argument should be String, Symbol, Integer or an array thereof", caller
+ end
+
+ transform do |input|
+ result =
+ keys.map do |key|
+ Array(key).reduce(input) do |result, k|
+ if result.respond_to?(k)
+ result.public_send(k)
+ else
+ break Datacaster.absent
+ end
+ end
+ end
+ keys.length == 1 ? result.first : result
+ end
+ end
+
def default(value, on: nil)
transform do |x|
if x == Datacaster.absent ||
(!on.nil? && x.respond_to?(on) && x.public_send(on))
value
@@ -98,50 +118,112 @@
x
end
end
end
- def transform_to_value(value)
- transform { value }
+ def merge_message_keys(*keys)
+ MessageKeysMerger.new(keys)
end
- # min_amount: has_relation(:min_amount, :>, :max_amount)
+ def must_be(klass, error_key = nil)
+ error_keys = ['.must_be', 'datacaster.errors.must_be']
+ error_keys.unshift(error_key) if error_key
+ check { |x| x.is_a?(klass) }.i18n_key(*error_keys, reference: klass.name)
+ end
+ def optional(base, on: nil)
+ return absent | base if on == nil
+ cast do |x|
+ if x == Datacaster.absent ||
+ (!on.nil? && x.respond_to?(on) && x.public_send(on))
+ Datacaster.ValidResult(Datacaster.absent)
+ else
+ base.(x)
+ end
+ end
+ end
+
+ def pass
+ transform(&:itself)
+ end
+
+ def pass_if(base)
+ ContextNodes::PassIf.new(base)
+ end
+
+ def pick(*keys)
+ if keys.empty? || keys.any? { |k| !Datacaster::Utils.pickable?(k) }
+ raise RuntimeError, "each argument should be String, Symbol, Integer or an array thereof", caller
+ end
+
+ retrieve_key = -> (from, key) do
+ if from.respond_to?(:key?) && !from.key?(key)
+ Datacaster.absent
+ elsif from.respond_to?(:length) && key.is_a?(Integer) && key > 0 && key >= from.length
+ Datacaster.absent
+ elsif !from.respond_to?(:[])
+ Datacaster.absent
+ else
+ from[key]
+ end
+ end
+
+ must_be(Enumerable) & transform { |input|
+ result =
+ keys.map do |key|
+ Array(key).reduce(input) do |result, k|
+ result = retrieve_key.(result, k)
+ break result if result == Datacaster.absent
+ result
+ end
+ end
+ keys.length == 1 ? result.first : result
+ }
+ end
+
def relate(left, op, right, error_key: nil)
error_keys = ['.relate', 'datacaster.errors.relate']
additional_vars = {}
+ left_caster = left
+ if Datacaster::Utils.pickable?(left)
+ left_caster = pick(left)
+ elsif !Datacaster.instance?(left)
+ raise RuntimeError, "provide String, Symbol, Integer or array thereof instead of #{left.inspect}", caller
+ end
+
+ right_caster = right
+ if Datacaster::Utils.pickable?(right)
+ right_caster = pick(right)
+ elsif !Datacaster.instance?(right)
+ raise RuntimeError, "provide String, Symbol, Integer or array thereof instead of #{right.inspect}", caller
+ end
+
+ op_caster = op
+ if op.is_a?(String) || op.is_a?(Symbol)
+ op_caster = check { |(l, r)| l.respond_to?(op) && l.public_send(op, r) }
+ elsif !Datacaster.instance?(left)
+ raise RuntimeError, "provide String or Symbol instead of #{op.inspect}", caller
+ end
+
{left: left, op: op, right: right}.each do |k, v|
if [String, Symbol, Integer].any? { |c| v.is_a?(c) }
additional_vars[k] = v
- elsif !Datacaster.instance?(v)
- raise RuntimeError, "expected #{k} to be String, Symbol, Integer or Datacaster::Base, but got #{v.inspect}", caller
end
end
- if op.is_a?(Integer)
- raise RuntimeError, "expected op to be String, Symbol or Datacaster::Base, but got #{op.inspect}", caller
- end
-
- if [left, op, right].none? { |x| Datacaster.instance?(x) }
+ if additional_vars.length == 3
error_keys.unshift(".#{left}.#{op}.#{right}")
end
error_keys.unshift(error_key) if error_key
- left = pick(left) unless Datacaster.instance?(left)
- right = pick(right) unless Datacaster.instance?(right)
- op_caster = op
- unless Datacaster.instance?(op_caster)
- op_caster = check { |(l, r)| l.respond_to?(op) && l.public_send(op, r) }
- end
-
cast do |value|
- left_result = left.(value)
+ left_result = left_caster.(value)
next left_result unless left_result.valid?
i18n_var!(:left, left_result.value) unless additional_vars.key?(:left)
- right_result = right.(value)
+ right_result = right_caster.(value)
next right_result unless right_result.valid?
i18n_var!(:right, right_result.value) unless additional_vars.key?(:right)
result = op_caster.([left_result.value, right_result.value])
next Datacaster.ErrorResult([I18nValues::Key.new(error_keys)]) unless result.valid?
@@ -152,74 +234,24 @@
def remove
transform { Datacaster.absent }
end
- def pass
- transform(&:itself)
- end
-
- def switch(*base, **on_clauses)
- switch =
- if base.length == 0
- SwitchNode.new
- else
- SwitchNode.new(base)
- end
- on_clauses.reduce(switch) do |result, (k, v)|
- result.on(k, v)
- end
- end
-
- def pass_if(base)
- ContextNodes::PassIf.new(base)
- end
-
- def pick(*keys, strict: false)
- raise RuntimeError.new("provide keys to pick, e.g. pick(:key)") if keys.empty?
-
- must_be(Enumerable) & transform { |value|
- result =
- keys.map do |key|
- if value.respond_to?(:key?) && !value.key?(key)
- Datacaster.absent
- elsif value.respond_to?(:length) && key.is_a?(Integer) && key > 0 && key >= value.length
- Datacaster.absent
- else
- value[key]
- end
- end
-
- keys.length == 1 ? result.first : result
- }
- end
-
- def merge_message_keys(*keys)
- MessageKeysMerger.new(keys)
- end
-
def responds_to(method, error_key = nil)
error_keys = ['.responds_to', 'datacaster.errors.responds_to']
error_keys.unshift(error_key) if error_key
check { |x| x.respond_to?(method) }.i18n_key(*error_keys, reference: method.to_s)
end
- def must_be(klass, error_key = nil)
- error_keys = ['.must_be', 'datacaster.errors.must_be']
- error_keys.unshift(error_key) if error_key
- check { |x| x.is_a?(klass) }.i18n_key(*error_keys, reference: klass.name)
+ def switch(base = nil, **on_clauses)
+ switch = SwitchNode.new(base)
+ on_clauses.reduce(switch) do |result, (k, v)|
+ result.on(k, v)
+ end
end
- def optional(base, on: nil)
- return absent | base if on == nil
- cast do |x|
- if x == Datacaster.absent ||
- (!on.nil? && x.respond_to?(on) && x.public_send(on))
- Datacaster.ValidResult(Datacaster.absent)
- else
- base.(x)
- end
- end
+ def transform_to_value(value)
+ transform { value }
end
# Strict types
def decimal(digits = 8, error_key = nil)