【问题标题】:Static local variables for methods in Ruby?Ruby中方法的静态局部变量?
【发布时间】:2011-11-02 08:40:48
【问题描述】:

我有这个:

def valid_attributes
  { :email => "some_#{rand(9999)}@thing.com" }
end

Rspec 测试对吗?但我想做这样的事情:

def valid_attributes
  static user_id = 0
  user_id += 1
  { :email => "some_#{user_id}@thing.com" }
end

我不希望 user_id 可以从除该方法之外的任何地方访问, Ruby 可以做到这一点吗?

【问题讨论】:

  • 简短的回答是否定的,Ruby 中没有 static 这样的东西。为什么不让数据库处理你的自增键呢?
  • 因为它是一种为Rspec测试生成有效属性的方法,有些东西必须是唯一的。

标签: ruby variables methods static local


【解决方案1】:

这是一个结案案例。试试这个

拉姆达{ 用户 ID = 0 self.class.send(:define_method, :valid_attributes) 做 用户 ID += 1 { :email => "some_#{user_id}@thing.com" } 结尾 }。称呼

在 lambda 中包装所有内容允许在 lambda 中定义的变量仅存在于作用域中。您也可以添加其他方法。祝你好运!

【讨论】:

  • 我在你的代码后面加了两个p valid_attributes,但我得到了Error NoMethodError: undefined method '+' for nil:NilClass。我猜user_id 里面的def 是一个初始化为nil 的局部变量。也许你可以用另一种方式使用闭包。 :)
  • 嗨索尼,我忘记了 def。我已经将它更改为define_method,所以它现在应该能够访问user_id。以这种方式在 lambda 中定义的其他方法也可以共享 user_id 变量。
  • 好的,但是你必须使用self.class.send :define_method, :valid_attributes,因为define_method是一个私有类方法。无论如何,我更喜欢您的解决方案而不是 mine,因为在我的情况下,valid_attributes 是一个过程(在 1.8.7 中必须使用 call[] 调用),而在您的情况下,它是一种真正的方法。
【解决方案2】:

这个答案的范围比你的问题要大一些,但我认为它是你想要做的事情的根源,并且将是最简单和最可维护的。

我认为您在这里真正寻找的是工厂。尝试使用 factory_girl 之类的东西,这将使很多测试变得更加容易。

首先,您将设置一个工厂来创建您正在测试的任何类型的对象,并为电子邮件属性使用序列:

FactoryGirl.define do
  factory :model do
    sequence(:email) {|n| "person#{n}@example.com" }
    # include whatever else is required to make your model valid
  end
end

然后,当你需要有效的属性时,你可以使用

Factory.attributes_for(:model)

您还可以使用Factory.createFactory.build 创建模型的已保存和未保存实例。

getting started document 中有更多功能的解释,以及如何将工厂添加到项目的说明。

【讨论】:

  • 谢谢!我会明确地检查那个宝石! ^^
【解决方案3】:

你可以使用闭包:

def validator_factory
  user_id = 0
  lambda do
    user_id += 1
    { :email => "some_#{user_id}@thing.com" }
  end
end

valid_attributes = validator_factory

valid_attributes.call  #=>  {:email=>"some_1@thing.com"}
valid_attributes.call  #=>  {:email=>"some_2@thing.com"}

这样user_id 将无法在外面访问。

【讨论】:

    【解决方案4】:

    我会使用实例变量:

    def valid_attributes
      @user_id ||= 0
      @user_id += 1
      { :email => "some_#{@user_id}@thing.com" }
    end
    

    【讨论】:

      【解决方案5】:

      Ruby 仅有的变量是局部变量、实例变量、类变量和全局变量。它们都不适合你的追求。

      您可能需要一个存储 user_id 并每次都为您提供新 ID 号的单例。否则,您的代码将不是线程安全的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-25
        • 1970-01-01
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-06
        相关资源
        最近更新 更多