Ruby在运行时将变量转换为常量

时间:2013-12-10 01:14:00

标签: ruby-on-rails ruby

我正在尝试创建一个将包含在许多不同类中的模块。它需要记录调用者到类文件的路径 所以我可以在后面的代码中引用该路径。此代码尝试向调用类添加方法,但失败,因为它只返回@@ x的当前值。

# /home/eric/FindMe.rb
class FindMe
  include GladeGUI
end

# /home/eric/GladeGUI.rb
module GladeGUI

 def self.included(obj)
    @@x, = caller[0].partition(":") # this works @@x = "/home/eric/FindMe.rb"
    obj.class_eval do
      def my_class_file_path
        return ????? # I want to return "/home/eric/FindMe.rb"
      end
    end
  end

end

GladeGUI模块将“包含”在许多不同的类中,因此我不能只将代码添加到调用类中。我需要一种方法将@@ x编译成一个常量值,因此存储在类中的方法如下所示:

      def my_class_file_path
        return "/home/eric/FindMe.rb"
      end

如何在代码中将变量转换为常量?

感谢。

1 个答案:

答案 0 :(得分:2)

看起来你实际上并不需要它是一个“常量” - 你只需要一些方法让方法始终返回正确的值而不允许其他代码出现并更改值(使用当前的@@x解决方案,有人可以修改@@x并且它会破坏)

解决方案是将数据存储在局部变量而不是类或实例变量中,然后通过闭包访问该局部变量。
没有其他代码可以“查看”局部变量,因此无法更改。

但问题变成了当你在class_eval中使用def时,调用者的范围没有被捕获,因此代码无法看到你的局部变量。您可以使用define_method代替

这是一个例子

# /home/eric/GladeGUI.rb
module GladeGUI

 def self.included(obj)
    caller_file_path = caller[0].split(":").first
    obj.class_eval do
      define_method :my_class_file_path do
        return caller_file_path
      end
    end
  end

end

# /home/eric/FindMe.rb
class FindMe
  include GladeGUI
end

puts FindMe.new.my_class_file_path # prints the correct path

但是 - 如果您希望my_class_file_path成为方法而非实例方法,请使用define_singleton_method代替:

module GladeGUI
 def self.included(obj)
    caller_file_path = caller[0].split(":").first
    obj.class_eval do
      define_singleton_method :my_class_file_path do
        return caller_file_path
      end
    end
  end
end

...
puts FindMe.my_class_file_path

有趣的旁注:这是你在javascript中假冒“私人变量”的方法: - )