使用全局变量ruby

时间:2013-07-08 13:43:01

标签: ruby

我有一种情况,我在脚本的顶部定义一个变量,并希望在方法中引用。

#############
# Variables #
#############
tmp_dir = '/path/to/tmp/dir'

###########
# Methods #
###########
def cache(page)
  begin
    %x[wget -q -O #{tmp_dir}/page #{page}]
  rescue => msg
    puts "error: #{msg}"
    exit
  end
 end

cache("http://somepage.com")

我收到此错误:

undefined local variable or method `tmp_dir' for main:Object

所以......我猜我需要让tmp_dir成为一个全局变量?我讨厌使用全局变量。有没有红宝石的方法来做到这一点?

5 个答案:

答案 0 :(得分:4)

tmp_dir被定义为类定义中的变量,但在实例函数中,您要查找在类的实例上定义的tmp_dir 。这就是函数内未定义tmp_dir的原因。

您可以将其设为全局或将其作为快速修复的类变量。我认为有一个更好的选择:将它包装在自己的知道如何缓存的类中,然后初始化tmp_dir而不使其成为全局或类变量:

class Cacher
    def initialize(tmp_dir)
        @tmp_dir = tmp_dir
    end

    def cache(page)
        wget "#{@tmp_dir}/page"
    end
end

# in your main file:
cacher = Cacher.new('/path/to/tmp/dir') # here's your configuration line, but with no global!

# later

cacher.cache("index.html")

答案 1 :(得分:3)

你是对的。应避免使用全局变量。自然选择是类的实例变量,或常量。

在您的情况下,看起来您在脚本执行过程中有一些不会改变的东西。然后,常数是最合适的。您可以在适当的模块中定义此常量。

TmpDir = "/path/to/tmp/dir"

另请注意,Ruby有一种内置的方式来引用tmp目录。

require "tmpdir"
Dir.tmpdir # => "/tmp" (depending on the environment)

答案 2 :(得分:1)

你是对的。您需要通过在$前添加变量来使变量成为全局变量。例如:

$tmp_dir = '/path/to/tmp/dir'

除了这样做之外,您还可以将其设为实例变量,或者您可以重构以使其成为类。我建议做Riley Lark所说的。

答案 3 :(得分:1)

除了其他答案之外,要使类定义范围中的局部变量集在方法定义中起作用,您可以使用define_method这是一种采用块的方法。 Ruby中的块是闭包,因此它们与设置的环境一起使用:

define_method(:cache) do |page|
  begin
    %x[wget -q -O #{tmp_dir}/page #{page}]
  rescue => msg
    puts "error: #{msg}"
    exit
  end
end

答案 4 :(得分:0)

简短回答

听起来你正在写一个简短的剧本。如果是这种情况,则没有理由不能使用可修改的全局变量,如$tmp_dir。但是如果你不需要修改它,你应该使用@ sawa的全局常量解决方案,如TMP_DIR。在这种情况下,您应该在字符串上调用.freeze以避免意外修改。

更长的答案

如果脚本变得更长或更复杂,您应该重构为类。在这种情况下,TMP_DIR解决方案仍然有效。但是,如果您需要修改该值,则可以创建一个ConfigObject类来对这些变量进行分组。

示例:

ConfigObject = Struct.new(:tmp_dir, :file_limit)
# it's a good idea to create this before everything else
$config = ConfigObject.new('/tmp/dir', 10)

class Foo
  def do_something
    $config.file_limit  # use this somehow
    $config.file_limit = 5  # change
  end
end

类似的技术使用类变量来完成同样的事情:

class ConfigObject
  class << self
    attr_accessor :tmp_dir, :file_limit
  end
  @tmp_dir = '/tmp/dir'
  @file_limit = 10
end

class Foo
  def do_something
    ConfigObject.file_limit  # use this somehow
    ConfigObject.file_limit = 5  # change
  end
end

ConfigObject视为其他类使用的“服务”。如果您的应用程序变得复杂到需要多个交互服务,您可能需要设置一种服务注册表来保存对服务的引用(谷歌“依赖注入”以获取更多信息)。

注意:您不应该为您的班级Config命名,因为它已经是内置类。