File: builder.rb

package info (click to toggle)
ruby-dry-logic 1.2.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 728 kB
  • sloc: ruby: 4,929; makefile: 6
file content (91 lines) | stat: -rw-r--r-- 2,261 bytes parent folder | download
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