These are chat archives for dry-rb/chat

3rd
Sep 2016
Andrew Kozin
@nepalez
Sep 03 2016 13:17

Hi folks, I need some help with calling predicates from other predicate definitions.

What I want is to define custom predicate to check duck type of the value:

# check whether value responds to :call with 2 params and given options
accept_method? [:call, params: 2, options: [:foo, :bar, :baz]]

# check whether <class> value has instance method :call without params and options
accept_instance_method? [:call]

My code is the following (I comment places I not sure how to make correctly).
At first I define 2 predicates for [Method] object, then I want to use them to check an object's method.

schema = Dry::Validation.Schema do
  configure do
    def accept_options?(keys)
      keys      = Array(keys).map(&:to_sym)
      arguments = value.parameters

      any_option  = arguments.any? { |item| item[0] == :keyrest }
      req_options = arguments.select { |item| item[0] == :keyreq }.map(&:last)
      opt_options = arguments.select { |item| item[0] == :key }.map(&:last)

      return false if (req_options - keys).any?
      return true  if any_option
      (keys - req_options - opt_options).empty?
    end

    def accept_params?(number)
      number    = number.to_i
      arguments = value.parameters

      any_param   = arguments.any?  { |item| item[0] == :rest }
      req_params  = arguments.count { |item| item[0] == :req }
      opt_params  = arguments.count { |item| item[0] == :opt }

      return false if req_params > number
      return true  if any_param
      number <= req_params + opt_params
    end

    def accept_method?(list)
      name      = list[0].to_sym
      signature = list[1].to_h
      params    = signature[:params]
      options   = signature[:options]

      return false unless value.respond_to? name
      meth = value.method(name)

      # here I need to check whether method (not value) 
      # accepts options and params
      # using predicates accept_options?(options) and accept_params?(params)
    end

    def accept_instance_method?(list)
      name      = list[0].to_sym
      signature = list[1].to_h
      params    = signature[:params]
      options   = signature[:options]

      return false unless Class === value
      return false unless value.instance_methods.include? name
      meth = value.instance_method(name)

      # here I need to check whether method (not value) 
      # accepts options and params
      # using predicates accept_options?(options) and accept_params?(params)
    end
  end
end
Piotr Solnica
@solnic
Sep 03 2016 18:59
@nepalez could you post a message on discuss.dry-rb.org with this question and make the example a bit simpler? :)
@fran-worley hey, so I made it…I re-added results and added hints to dry-logic, so hint compiler in dry-v is gone…this allowed me to finally make various pending specs pass in dry-v…furthermore, dry-v is equally fast as AM::V for valid input…and 5 x faster with invalid input…crazy. I’ll be wrapping this up and pushing 0.10.0 in few days :)