diff --git a/lib/datacaster/runtimes/user_context.rb b/lib/datacaster/runtimes/user_context.rb index e04f610..2fc1eb1 100644 --- a/lib/datacaster/runtimes/user_context.rb +++ b/lib/datacaster/runtimes/user_context.rb @@ -4,6 +4,10 @@ module Datacaster module Runtimes class UserContext < Base class ContextStruct + def self.context_has_key?(context, key) + context.respond_to?(:key?) && context.key?(key) || context.to_h.key?(key.to_sym) + end + def initialize(context, node) @context = context @node = node @@ -14,10 +18,7 @@ def method_missing(m, *args) return super end - key_present = @context.respond_to?(:key?) && @context.key?(m) || - @context.to_h.key?(m.to_sym) - - if key_present && args.empty? + if self.class.context_has_key?(@context, m) && args.empty? return @context[m] end @@ -31,6 +32,12 @@ def method_missing(m, *args) raise NoMethodError.new("Key #{m.inspect} is not found in the context") end end + + def has_key?(key) + self.class.context_has_key?(@context, key) || @node.class.send_to_parent(@node, :context).has_key?(key) + rescue NoMethodError + false + end end def initialize(parent, user_context) diff --git a/spec/user_context_spec.rb b/spec/user_context_spec.rb index c877415..b0cb2f0 100644 --- a/spec/user_context_spec.rb +++ b/spec/user_context_spec.rb @@ -79,4 +79,29 @@ expect(schema.with_context(d: 2, e: 3).({a: 1, b: {c: {d: 10}}, e: [3]}).to_dry_result).to eq Failure({b: {c: {d: ["is invalid"]}}}) end end + + describe "using #has_key?" do + it "works with deep nesting" do + schema = described_class.schema do + check { context.has_key?(:b) && context.has_key?(:c) && context.has_key?(:d) && !context.has_key?(:e) }. + with_context(b: 1). + with_context(c: 2). + with_context(d: 3) + end + + expect(schema.with_context(a: 1).(1).to_dry_result).to eq Success(1) + end + + it "works with complex schemas" do + schema = described_class.schema do + hash_schema( + a: check { context.has_key?(:a) && context.has_key?(:d) && context.has_key?(:e) && !context.has_key?(:f) }, + b: {c: {d: check { context.has_key?(:a) && context.has_key?(:d) && context.has_key?(:e) && !context.has_key?(:t) }}}, + e: [check { |v| context.has_key?(:a) && context.has_key?(:d) && context.has_key?(:e) && !context.has_key?(:p) }] + ).with_context(a: 1) + end + + expect(schema.with_context(d: 2, e: 3).({a: 1, b: {c: {d: 10}}, e: [3]}).to_dry_result).to eq Success({:a=>1, :b=>{:c=>{:d=>10}}, :e=>[3]}) + end + end end