Sha256: 4e8880a41acfeed5d16137c99d1ba99bbdeec8d32c3e8a0f2e32500c5601ec46

Contents?: true

Size: 1.87 KB

Versions: 1

Compression:

Stored size: 1.87 KB

Contents

module Ataulfo
  class PatternMatching
    class Var < Struct.new(:value);
    end

    class Body
      def initialize(vars, other_self)
        @other_self = other_self
        vars.each do |k, v|
          define_singleton_method(k) { v.value }
        end
      end

      def method_missing(method_name, *args, &block)
        @other_self.send method_name, *args, &block
      end
    end

    class Matcher
      def initialize(object, pattern)
        @object                      = object
        @pattern_vars                = pattern.select { |_, v| v.is_a? Var }
        inner_matches                = pattern.select { |_, v| v.is_a? Hash }
        fixed_values                 = pattern.select { |_, v| !v.is_a?(Var) && !v.is_a?(Hash) }
        @object_respond_to_methods   = pattern.keys.all? { |k| @object.respond_to? k }
        @object_answers_right_values = fixed_values.all? { |k, v| @object.send(k) == v }

        @matchers = inner_matches.map { |k, v| Matcher.new(object.send(k), v) }
      end

      def matches?
        @matchers.all?(&:matches?) if @object_respond_to_methods && @object_answers_right_values
      end

      def fill_vars
        @pattern_vars.each { |k, v| v.value = @object.send k }
        @matchers.each(&:fill_vars)
      end
    end

    def initialize(object, other_self)
      @object       = object
      @other_self   = other_self
      @context_vars = { }
    end

    def like(pattern, &block)
      matcher = Matcher.new(@object, pattern)
      return unless matcher.matches?

      matcher.fill_vars

      Body.new(@context_vars, @other_self).instance_eval(&block)
      @context_vars = { }
    end

    def method_missing(method_name, *_)
      # The line below also returns the "Var" to the
      # pattern. That makes it a collector parameter
      # already distributed where it belongs to.
      @context_vars[method_name] = Var.new
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
ataulfo-1.0.1 lib/ataulfo/pattern_matching.rb