Ruby 生成现有类的近亲类时“堆栈级别太深”

Ruby 生成现有类的近亲类时“堆栈级别太深”,ruby,metaprogramming,stack-overflow,Ruby,Metaprogramming,Stack Overflow,我正在为约束处理编写一个ruby模块 作为我的一点经验,主要是关于使用给定域实例化变量以及搜索和修剪 我的意图 约束实例将使用一组变量名和一个块进行初始化。将对块进行评估,以检查初始化是否满足约束 它的类方法Constraint.subclass返回Constraint的子类,比如subclass 1 在子类1中,有一个具有预定义块的初始值设定项(一个提供给Constraint.subclass的块)和一个类方法Subclass1.invert。后者通过再次使用Constraint.subcla

我正在为约束处理编写一个ruby模块

作为我的一点经验,主要是关于使用给定域实例化变量以及搜索和修剪

我的意图 约束实例将使用一组变量名和一个块进行初始化。将对块进行评估,以检查初始化是否满足约束

它的类方法Constraint.subclass返回Constraint的子类,比如subclass 1

在子类1中,有一个具有预定义块的初始值设定项(一个提供给Constraint.subclass的块)和一个类方法Subclass1.invert。后者通过再次使用Constraint.subclass返回约束的另一个子类,比如subclass 2

子类2中的预定义块应该是子类1中预定义块的反转版本

现状 这段代码或多或少符合我的意图。Constraint.subclass起作用,但subclass.invert似乎只有在预定义块具有确定的算术性时才起作用。否则会出现堆栈级别太深的情况

#worked
EQ = Constraint.subclass {|a,b| a == b }
NE = EQ.invert
ALL_DISTINCT = Constraint.subclass {|*args| args.uniq.size == args.size}

#raised stackoverflow
HAVE_DUPLICATE = ALL_DISTINCT.invert
来源 在ruby1.9中列出了以下内容。省略了不太相关的方法,完整版本可在


您有单元测试来显示当前的工作方式吗?@OscarDelBen感谢您的提醒。令我惊讶的是,Constraint及其所有子类共享同一个类变量@@block。
module Solver
  class Constraint # class method for a subclass
    def self.subclass &block
      Class.new(self) do
        @@block = block
        def initialize *args
          super *args, &@@block
        end

        def self.invert # class method for a cousin class of current subclass
          p "#{self}.invert"
          new_block = proc {|*args| not @@block.call(*args)}
          self.superclass.subclass &new_block
        end
      end
    end

    def initialize *vars, &block
      # block will be substituted with variable in vars
      raise ArgumentError "array of variable names is required"unless vars.is_a? Array
      raise ArgumentError "block is expected" unless block_given?
      @vars = vars.freeze
      @proc = block.freeze
    end

    # less related methods
  end

  # predefined constraint schema
  EQ = Constraint.subclass {|a,b| a == b }
  NE = EQ.invert

  GT = Constraint.subclass {|a,b| a > b }
  NGT = GT.invert

  LT = Constraint.subclass {|a,b| a < b }
  NLT = LT.invert

  ALL_DISTINCT = Constraint.subclass {|*args| args.uniq.size == args.size}
  #HAVE_DUPLICATE = ALL_DISTINCT.invert
end