在 ruby​​ DSL 实现中捕获规范文件名?

Posted

技术标签:

【中文标题】在 ruby​​ DSL 实现中捕获规范文件名?【英文标题】:Capturing the spec filename in a ruby DSL implementation? 【发布时间】:2013-04-24 15:12:53 【问题描述】:

我正在编写一个 ruby DSL,它将用于代码生成许多 Objective-C++ 函数。我希望每个函数的名称都源自其 ruby DSL 源文件的名称。

例如,给定这个源文件clusterOptions.rb

require './vMATCodeMonkey'

VMATCodeMonkey.new(:print).options_processor <<EOS
  -cutoff:    flag: set('useCutoff', true), arg: vector('double')
  -depth:     flag: set('useInconsistent', true), arg: scalar('double', default: 2.0)
  -maxclust:  flag: set('useCutoff', false), arg: vector('index')
EOS

VMATCodeMonkey.new(:print) 表达式被评估时,我会理想地以某种方式让新对象捕获clusterOptions.rb 源文件名。这可能吗?

如果(我怀疑)它不是,是否有一个很好的习惯用法来完成这个功能[例如在ruby中使源文件名有效地成为DSL捕获的规范的一部分?

[虽然我怀疑不可能完全按照我所描述的那样做,但我还是要问,因为我对ruby感到惊讶strong> 的晦涩能力不止一次。]

编辑:我知道__FILE__;我正在寻找的是一些以 DSL 为中心的方法来捕获 DSL 源文件的名称​​在 DSL 源中明确提及 __FILE__。嗯,现在我正试图解释它,也许从类initialize 方法中爬取堆栈跟踪?

解决方案

感谢 tadman,这是我的 VMATCodeMonkey#initialize 方法:

def initialize(out_opt = :print)
    @caller_file = caller(1)[0].split(':')[0]
    case out_opt
      when :pbcopy
        @out = IO.popen('pbcopy', 'w')
      when :print
        @out = $stdout
      else
        raise ArgumentError, "#out_opt is not an option!"
    end
    @out.puts "// vMATCodeMonkey's work; do not edit by hand!\n\n"
    initialize_options_processor
  end

这就是它捕获的内容:

@caller_file = "/Users/Shared/Source/vMAT/ruby/clusterOptions.rb"

【问题讨论】:

【参考方案1】:

正在评估的源文件的完整路径存储在__FILE__ 中。如果你只想要文件名,你会使用:

File.basename(__FILE__)

__FILE__ 常量在 C、C++、Perl 和 Python 等中很常见。

如果您需要知道哪个文件调用了当前正在运行的例程,这可以工作:

caller(1)[0].split(':')[0]

这假定您的文件名中没有:,但在大多数情况下,这应该是一个相当安全的假设。您还需要在库的入口点调用它。如果它是堆栈中更深的方法,请测试 caller(2) 等等。

【讨论】:

我应该澄清一下,我已经尝试使用 __FILE__,但它捕获的是 vMATCodeMonkey.rb 而不是 clusterOptions.rb

以上是关于在 ruby​​ DSL 实现中捕获规范文件名?的主要内容,如果未能解决你的问题,请参考以下文章

Ruby 中的简单 DSL

您将如何在 Ruby 中设计这样的 DSL?

是否可以从管道中的 sh DSL 命令捕获标准输出

ruby 关于自定义DSL的演示

DSL-让你的 Ruby 代码更优秀

带参数的 Ruby DSL 定义方法