Sha256: 0cc9686e5aa27e7314f1b263aa2dee45d197572d86a5c01e9b1d4e35bb086f1b

Contents?: true

Size: 1.52 KB

Versions: 1

Compression:

Stored size: 1.52 KB

Contents

require "rule_table/version"

module RuleTable

  def self.matcher(name, &block)
    matchers[name] = block
  end

  def self.matchers
    @matchers ||= {}
  end

  def self.new(&block)
    Table.new.tap { |table| TableDefiner.new(table, &block) }
  end

  class Table

    def initialize
      @rules = []
    end

    def add_rule_for(target, *matchers)
      @rules << [ target, matchers ]
    end

    def match(object)
      @rules.find { |(_target, matchers)|
        matchers.all? { |m| m.matches?(object) }
      }.first
    end

    def match_with_trace(object)
      trace = []
      result = @rules.find { |(target, matchers)|
        partial_trace = { target: target, matched: [] }
        matchers.all? { |m|
          m.matches?(object).tap { |match_result|
            partial_trace[:matched] << m.matcher_name if match_result
          }
        }.tap {
          trace << partial_trace
        }
      }.first
      [ result, trace ]
    end

  end

  class TableDefiner

    def initialize(table, &block)
      @table = table
      instance_eval(&block)
    end

    def rule(*args)
      @table.add_rule_for(*args)
    end

    def match(matcher_name, *args)
      ConfiguredMatcher.new(matcher_name, *args)
    end

  end

  class ConfiguredMatcher

    attr_reader :matcher_name

    def initialize(matcher_name, *args)
      @matcher_name = matcher_name
      @matcher = RuleTable.matchers.fetch(matcher_name)
      @args    = args
    end

    def matches?(object)
      object.instance_exec(*@args, &@matcher)
    end

  end

end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
rule_table-0.1.0 lib/rule_table.rb