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

如何在Ruby中实现无逗号、纯单词参数的优雅DSL

实现无逗号分隔参数的Ruby DSL方案

需求与解析

我想实现这样的Ruby DSL代码:

something.configure do
  on arg1 arg2 "real_arg" do
    
  end
end

不需要用逗号分隔参数。我清楚Ruby会把这段代码解析成:

something.configure do
  on(arg1)(arg2 "real_arg") do

  end
end

最终目标是让.on方法能接收*args(包含:arg1、:arg2、"real_arg")以及&block。一开始尝试用method_missing返回符号,但发现Ruby会把单独的单词当成方法调用;想过用匿名函数链式包裹参数,但Ruby的Proc需要.call调用,所以需要更优雅的实现方式。

解决方案

核心思路是让on方法返回一个参数收集器对象,通过method_missing捕获后续所有参数(包括符号、字符串),直到块调用触发最终的参数汇总。具体实现如下:

1. 实现配置上下文与参数收集器

class Something
  class ConfigContext
    def initialize
      @handlers = []
    end

    def on(*initial_args, &block)
      # 直接传块时,说明参数已收集完成
      if block_given?
        @handlers << { args: initial_args, block: block }
        return
      end

      # 否则返回参数收集器,继续捕获后续参数
      ParameterCollector.new(initial_args) do |final_args, final_block|
        @handlers << { args: final_args, block: final_block }
      end
    end

    # 捕获arg1这类无参方法调用,返回对应符号
    def method_missing(name, *args)
      args.empty? ? name : super
    end

    def respond_to_missing?(name, include_private = false)
      true
    end
  end

  class ParameterCollector
    def initialize(initial_args, &callback)
      @collected_args = initial_args
      @callback = callback
    end

    # 捕获后续参数调用,把方法名转符号、附带参数都加入列表
    def method_missing(name, *args)
      @collected_args << name
      @collected_args += args
      self # 返回自身,支持链式收集
    end

    def respond_to_missing?(name, include_private = false)
      true
    end

    # 块调用时触发,完成参数收集
    def call(&block)
      @callback.call(@collected_args, block)
    end
  end

  def self.configure(&block)
    context = ConfigContext.new
    context.instance_eval(&block)
    # 这里可以自定义处理收集到的handlers,比如打印测试
    context.instance_variable_get(:@handlers).each do |handler|
      puts "捕获参数: #{handler[:args]}"
      puts "已存储对应处理块"
    end
  end
end

2. 测试目标DSL

直接使用无逗号分隔的DSL形式:

Something.configure do
  on arg1 arg2 "real_arg" do
    puts "执行处理逻辑"
  end
end

原理说明

  • on方法分支:传块则直接存储参数与块;不传块则返回收集器,继续捕获后续输入。
  • method_missing的双重作用:
    • 上下文类中把arg1这类无参调用转为符号。
    • 收集器类中把后续的方法名(比如arg2)转为符号加入参数列表,同时接收字符串这类直接参数,返回自身实现链式收集。
  • 块的自动触发:Ruby允许把块直接附加到对象调用后,等效于调用.call(&block),此时收集器会把所有参数汇总并回调存储。

运行结果

执行测试代码后会输出:

捕获参数: [:arg1, :arg2, "real_arg"]
已存储对应处理块

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:16:04