1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
# frozen_string_literal: true
require "dry/logic"
require "singleton"
require "delegate"
module Dry
module Logic
autoload :Operations, "dry/logic/operations"
autoload :Predicates, "dry/logic/predicates"
module Builder
IGNORED_OPERATIONS = %i[
Abstract
Binary
Unary
].freeze
IGNORED_PREDICATES = [
:predicate
].freeze
# Predicate and operation builder
#
# @block [Proc]
# @return [Builder::Result]
# @example Check if input is zero
# is_zero = Dry::Logic::Builder.call do
# negation { lt?(0) ^ gt?(0) }
# end
#
# p is_zero.call(1) # => false
# p is_zero.call(0) # => true
# p is_zero.call(-1) # => false
def call(&context)
Context.instance.call(&context)
end
module_function :call
alias_method :build, :call
public :call, :build
class Context
include Dry::Logic
include Singleton
module Predicates
include Logic::Predicates
end
# @see Builder#call
def call(&context)
instance_eval(&context)
end
# Defines custom predicate
#
# @name [Symbol] Name of predicate
# @Context [Proc]
def predicate(name, &context)
if singleton_class.method_defined?(name)
singleton_class.undef_method(name)
end
prerdicate = Rule::Predicate.new(context)
define_singleton_method(name) do |*args|
prerdicate.curry(*args)
end
end
# Defines methods for operations and predicates
def initialize
Operations.constants(false).each do |name|
next if IGNORED_OPERATIONS.include?(name)
operation = Operations.const_get(name)
define_singleton_method(name.downcase) do |*args, **kwargs, &block|
operation.new(*call(&block), *args, **kwargs)
end
end
Predicates::Methods.instance_methods(false).each do |name|
unless IGNORED_PREDICATES.include?(name)
predicate(name, &Predicates[name])
end
end
end
end
end
end
end
|