ruby - 有没有办法访问 block 外 block 内定义的局部变量?

标签 ruby

我编写了一个简单的代码来评估一段代码并将输出写入文件。这样它减少了我的一些,因为我需要很多很多文件,每一行都包含返回值!

无论如何,我正在使用的代码是:

#!/usr/bin/ruby -w

def create(file, code)
    f = code.strip.each_line.map { |cd| cd.strip.then { |c| [c, "# => #{binding.eval(c)}"] } }
    max_length = f.map { |x| x[0].length }.max + 4
    f.map { |v| v[0].ljust(max_length) << v[1] }.join("\n").tap { |data| File.write(file, data + "\n") }
end

puts create(
    File.join(__dir__, 'p.rb'),
    <<~'EOF'
        foo = 1
        bar = 2
        baz, qux = 5, 3
    EOF
)

在这种情况下,文件 p.rb 被写入。 p.rb的内容是:

foo = 1            # => 1
bar = 2            # => 2
baz, qux = 5, 3    # => [5, 3]

但是当我想要一个变量的值时,问题就出现了。 例如:

puts create(
    File.join(__dir__, 'p.rb'),
    <<~'EOF'
        baz, qux = 5, 3
        [baz, qux]
    EOF
)

输出:

/tmp/aa.rb:4:in `block (2 levels) in create': undefined local variable or method `baz' for main:Object (NameError)
    from /tmp/aa.rb:4:in `eval'
    from /tmp/aa.rb:4:in `block (2 levels) in create'
    from /tmp/aa.rb:4:in `then'
    from /tmp/aa.rb:4:in `block in create'
    from /tmp/aa.rb:4:in `each_line'
    from /tmp/aa.rb:4:in `each'
    from /tmp/aa.rb:4:in `map'
    from /tmp/aa.rb:4:in `create'
    from /tmp/aa.rb:9:in `<main>'

以前我在一些图形游戏中工作,在读取配置文件后也会做这种事情,但是在那里,我习惯于将变量定义为全局变量(只需在变量声明之前附加 $)或只使用实例变量顶级 self 对象。

但是有没有办法解决我目前面临的问题呢?我可以在绑定(bind)中定义变量或像这样的一些 hack 吗?

最佳答案

binding 每次调用它时都会返回一个新实例。您必须将 eval 发送到相同的绑定(bind)才能访问您之前创建的局部变量:

def create(code, b = binding)
  width = code.each_line.map(&:length).max
  code.each_line.map do |line|
    '%-*s   #=> %s' % [width, line.chomp, b.eval(line)]
  end
end

puts create <<~'RUBY'
  baz, qux = 5, 3
  baz
  qux
RUBY

输出:

baz, qux = 5, 3    #=> [5, 3]
baz                #=> 5
qux                #=> 3

请注意,在上面的示例中,绑定(bind) 将使方法的局部变量可用于 block :

create 'local_variables'
#=> ["local_variables   #=> [:code, :b, :width]"]

您可能想要创建一个更受限制的评估上下文,例如(复制 Ruby 的 main)

def empty_binding
  Object.allocate.instance_eval do
    class << self
      def to_s
        'main'
      end
      alias inspect to_s
    end
    return binding
  end
end

def create(code, b = empty_binding)
  # ...
end

关于ruby - 有没有办法访问 block 外 block 内定义的局部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56645225/

相关文章:

ruby-on-rails - Bundle Install 不会更新 eventmachine gem

ruby-on-rails - Ruby,具有 6 个随机数的用户 ID

ruby - rake 文件中未定义的方法

html - 未显示 Logo 背景图像(Rails 应用程序)

ruby - 如何在 Ruby 中以编程方式检测证书问题

ruby - 如何删除 ruby​​ 中包含可见字符的字符串的最后一行?

Ruby IMAP 库 : How can I show all messages in a folder?

ruby-on-rails - 在 Ruby 中加载 YAML 配置但设置默认值的好方法是什么?

ruby - Datamapper:报告为什么我不能销毁记录

ruby - 在 Ruby 中引发异常与抛出异常有什么区别?