You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现可通过方法链动态创建新方法的Ruby DSL

实现方案

你现有代码无法支持is_the场景的核心问题是:is_a、is_not_a返回的代理对象在第一次触发method_missing时就直接完成方法定义、终止调用链,而is_the需要多一层调用才能拿到目标方法的返回值。
可以通过拆分不同职责的代理类实现所有DSL需求,同时消除原有代码中重复定义匿名类的冗余:

class Thing
  attr_reader :name

  def initialize(name)
    @name = name
  end

  # is_a/is_not_a 通用布尔代理
  class BooleanProxy
    def initialize(base, return_value)
      @base = base
      @return_value = return_value
    end

    def method_missing(method_name)
      @base.define_singleton_method(:"#{method_name}?") { @return_value }
    end
  end

  # is_the 第一层代理:收集要定义的方法名
  class TheProxy
    def initialize(base)
      @base = base
    end

    def method_missing(method_name)
      TheValueProxy.new(@base, method_name)
    end
  end

  # is_the 第二层代理:接收方法返回值,完成方法定义
  class TheValueProxy
    def initialize(base, method_name)
      @base = base
      @method_name = method_name
    end

    def method_missing(value_name)
      @base.define_singleton_method(@method_name) { value_name }
    end
  end

  def is_a
    BooleanProxy.new(self, true)
  end

  def is_not_a
    BooleanProxy.new(self, false)
  end

  def is_the
    TheProxy.new(self)
  end
end
测试验证

运行以下测试代码,所有场景均符合预期:

jane = Thing.new('Jane')

# 测试is_a逻辑
jane.is_a.person
puts jane.person? #=> true

jane.is_a.woman
puts jane.woman? #=> true

# 测试is_not_a逻辑
jane.is_not_a.man
puts jane.man? #=> false

# 测试is_the逻辑
jane.is_the.parent_of.joe
puts jane.parent_of #=> :joe

如果需要返回字符串格式的值而不是符号,只需要把TheValueProxy中的定义改为@base.define_singleton_method(@method_name) { value_name.to_s }即可。如果需要支持更长的方法名链式定义(比如jane.is_the.grand_parent_of.father_of.tom定义grand_parent_of_father_of方法返回对应值),只需要修改TheProxy逻辑增加方法名片段累积能力,持续返回代理实例直到最后一步完成方法定义即可,核心逻辑和上述实现一致。

内容的提问来源于stack exchange,提问作者Kiran Kumawat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:03:19