Variable scope issue for Ruby Newbie

I look through the book "Ruby on Rails 3 Tutorial" and stumbled upon the part where I have to write some basic unit tests for my static pages. I noticed that the code only replicates with some text changes, so I modify it like this:

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 

In the above example, I am confused by the fact that I can replace the variable "pages" as follows:

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

And it still works. Why is this? How are "pages and pages" different?

Another confusing thing is that both of these causes test failures:

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

and

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

Why don't the above examples work? Why should the code look like I wrote in my first piece of code? I assume this has something to do with the scope variable, but I'm still new to Ruby, so I'm looking for a deeper understanding.

FWIW, I am an experienced C # developer, so getting comparable Java or C # code will help me understand this or a well-written description.

Thanks for any support.

Edit: Added error message when I move @base_title outside the "before" block.

 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)>' 
+4
source share
2 answers

K, I'm going to answer your questions in order ...

1. If you make changes from

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

to ...

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

You just change the local variable to an instance variable ... this should not work and should lead to the interruption of your tests ...

2. The following code should not work.

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

This is because @base_title will not be available for your "it" "do" blocks. The page variables will be in scope ... but you have the @base_title error condition.

3. This will not work either.

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

The page variables defined here are not available for each cycle that you have. @base_title will be fine, and it will be perfectly portable to all your methods.

- Conclusion -

Your final sample is correct. You just need a local variable for each loop and an instance variable (@base_title) so that it is available to the whole instance of the class when you run the tests. Hope this helps you. I would suggest looking at a few other ruby ​​textbooks online, I personally like to send people to http://rubykoans.com/ =)

One final note: RSpec is a tricky case for defining a scope, since it uses a lot of blocks and moves code pretty quickly to do what it needs. Basically you have blocks inside blocks ... things can quickly become complicated. I would start with simpler examples.

+4
source

In Ruby, you create an access method that allows external code to access instance variables:

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

If you access @pages from a class, it will be the same as accessing pages from a class, which will call self.pages , returning @pages .

+2
source

Source: https://habr.com/ru/post/1339443/


All Articles