Ruby新手的可变范围问题

时间:2011-02-12 03:45:10

标签: ruby-on-rails ruby ruby-on-rails-3 rspec

我正在阅读“Ruby on Rails 3 Tutorial”一书,并且遇到了我必须为静态页面编写一些基本单元测试的部分。我注意到代码只复制了一些文本,因此我将其更改为以下内容:

require 'spec_helper'

describe PagesController do
  render_views

  pages = ['home', 'contact', 'about', 'help']

  before(:each) do
    @base_title = "Ruby on Rails Tutorial Sample App | "
  end

  pages.each do |page|
    describe "GET '#{page}'" do
      it "should be successful" do
        get "#{page}"
        response.should be_success
      end

      it "should have the right title" do
        get "#{page}"
        response.should have_selector("title", :content => @base_title + page.capitalize)
      end
    end
  end

end

我在上面的例子中感到困惑的是,我可以将'pages'变量替换为:

@pages = ['home', 'contact', 'about', 'help']

它仍然有效。这是为什么? '@pages'和'pages'有何不同?

另一个令人困惑的事情是,这两个都会导致测试失败:

pages = ['home', 'contact', 'about', 'help']
@base_title = "Ruby on Rails Tutorial Sample App | "

before(:each) do
  pages = ['home', 'contact', 'about', 'help']
  @base_title = "Ruby on Rails Tutorial Sample App | "
end

为什么以上两个例子失败了?为什么代码看起来必须像我在第一个代码片段中发布的那样?我认为这与变量范围有关,但我仍然是Ruby的新手,所以我正在寻求更深入的理解。

FWIW,我是一位经验丰富的C#开发人员,因此获得可比较的Java或C#代码将有助于我理解这一点或写得好的描述。

感谢您的支持。

编辑: 我将@base_title移到'before'块之外时添加了错误消息。

Failure/Error: response.should have_selector("title", :content => @base_title + page.capitalize)
NoMethodError:
   You have a nil object when you didn't expect it!
   You might have expected an instance of Array.
   The error occurred while evaluating nil.+
 # ./spec/controllers/pages_controller_spec.rb:21:in `block (4 levels) in <top (required)>'

2 个答案:

答案 0 :(得分:4)

K,我将按顺序回答你的问题......

1。当您从

进行更改时
pages = ['home', 'contact', 'about', 'help']

为...

@pages = ['home', 'contact', 'about', 'help']

您只是将局部变量更改为实例变量...这应该不起作用,并且应该导致测试中断......

2。以下代码不起作用。

pages = ['home', 'contact', 'about', 'help']
@base_title = "Ruby on Rails Tutorial Sample App | "

这是因为@base_title将无法用于你的'it'“do”块。变量页面将在范围内......但是你有@base_title错误条件。

3。这也无效。

before(:each) do
  pages = ['home', 'contact', 'about', 'help']
  @base_title = "Ruby on Rails Tutorial Sample App | "
end

此处定义的变量页面超出了您拥有的每个循环的范围。 @base_title会很好,并且会完美地完成你的所有方法。

- 结论 -

您发布的最终样本是正确的。您只需要每个循环的局部变量和一个实例变量(@base_title),以便在测试运行时它可用于整个实例化的类。希望这对你有所帮助。我建议在线查看其他一些ruby教程,我个人喜欢将人们送到http://rubykoans.com/ =)

最后一点,RSpec是一个复杂的范围,因为它使用了大量的块并且代码可以移动很多代码来完成它需要的工作。基本上你在街区内有块......事情很快就会变得棘手。我将从一些更简单的例子开始。

答案 1 :(得分:2)

在Ruby中,您创建一个访问器方法以允许外部代码访问实例变量:

class Foo
  def pages
    @pages
  end

  def pages=(value)
    @pages = value
  end
end

如果您正在课程中访问@pages,则与在课程中访问pages的内容相同,后者将调用self.pages,返回{{1} }}