Explain Iterator Syntax on Ruby on Rails

前端 未结 7 1059
慢半拍i
慢半拍i 2021-01-20 03:25

I started learning Ruby on Rails and found myself confounded by the syntax, so I had to read about somet of the Ruby syntax. I learned the syntax from http://www.cs.auckland

相关标签:
7条回答
  • 2021-01-20 04:02

    What you see there is a block of code, the syntax is a bit awkward when you first see it.

    So, basically, with iterators your have a "thing" that may be repeated, and it receives a block to know what to do.

    For instance the Range class has a method called "each" which receives the block of code to execute on each element in the range.

    Let's say you want to print it:

    range = 1..10 #range literal 
    range.each {|i|
        puts i
    }
    

    The code: {|i| puts i} is a block that says what to do when this range iterates over each one of its elements. The alternate syntax is the one you posted:

     range.each do |i|
          puts i 
     end
    

    These blocks are used with iterators, but they are not limited to "iteration" code, you can use them in other scenarios, for instance:

    class Person 
      def initialize( with_name ) 
        @name = with_name
      end
      # executes a block 
      def greet 
          yield @name #passes private attribute name to the block 
      end 
    end 
    
    p = Person.new "Oscar" 
    p.greet { |n|
         puts "Name length = #{n.length}"
         puts "Hello, #{n}"
    }
    

    Prints:

    Name length = 5
    Hello, Oscar
    

    So, instead of having a greet method with a fixed behavior, using block let the developer specify what to do, which is very helpful with iterators, but as you have just witness not the only place. In your case, that block is letting you specify what to do in the respond_to method.

    0 讨论(0)
  • 2021-01-20 04:03
    <function> do |<temp variable>|
        <code to operate on temp variable>
    end
    

    This creates a temporary anonymous function which accepts an item into a temporary variable, and then lets things operate on that item. The anonymous function is passed in to the original <function> specified to operate on the items yielded by that function.

    0 讨论(0)
  • 2021-01-20 04:03

    I think you could call it iterator, because often, the block function is called more than once. As in:

    5.times do |i|
      puts "#{i} "
    end
    

    "Behind the scenes", the following steps are made:

    • The method times of the object instance 5 is called, passing the code puts "#{i} " in a Proc object instance.
    • Inside the times method, this code is called inside a loop, passing the current index as a parameter. That's what times could look like (it's in C, actually):

    class Fixnum
      def times_2(&block) # Specifying &block as a parameter is optional
        return self unless block_given?
        i = 0
        while(i < self) do
          yield i # Here the proc instance "block" is called
          i += 1
        end
        return self
      end
    end

    Note that the scope (i.e. local variables etc.) is copied into the block function:

    x = ' '
    5.times do { |i| puts "#{i}" + x }
    
    0 讨论(0)
  • 2021-01-20 04:04

    The documentation you are reading is ancient -- practically prehistoric. If it were possible for web pages to gather dust, that one would have a thick layer.

    Try the reference material at the ruby-lang website. Also, the Programming Ruby (pickaxe) book is an essential reference.

    0 讨论(0)
  • 2021-01-20 04:08
    method_call do [`|' expr...`|'] expr...end
    

    Is not limited to iteration functions.

    In ruby, any method can take a block as an argument. The block can then be called by the method. In the case of an iterator, the method looks something like this:

    def iter
      for i in [:x,:y,:z]
        yield i
      end
    end
    

    If you call iter with a block, it will loop over [:x, :y, :z] and yield each of them to the block, which can then do whatever you want. e.g. to print them out:

    iter { |z| puts z }
    

    You can also use this to hide init and cleanup steps, like opening and closing files. e.g. File.open. File.open, if it were implemented in pure ruby(it's in C for performance) would do something like this.

    def File.open filename, opts
      f = File.new filename, opts
      yield f
      f.close
    end
    

    Which is why you can use

    File.open 'foobar', 'w' do |f|
      f.write 'awesome'
    end
    

    respond_to is similar. It works something like this:( check out the real implementation here)

       def respond_to
         responder = Responder.new(self)
         block.call(responder)
         responder.respond
       end
    

    It creates a responder object that has methods like html that take a block and passes it to you. This turns out to be really handy, because it lets you do things like:

    def action
      @foo = Foo.new params[:foo]
      respond_to do |format|
        if @foo.save
          format.html { redirect_to foo_path @foo }
          format.xml { render :xml => @foo.to_xml }
        else
          flash[:error] = "Foo could not be saved!"
          format.html { render :new }
          format.xml { render :xml => {:errors => @foo.errors }.to_xml}
        end
      end
    end
    

    See how I change the behavior dependent on save inside the block? Doing this would be much more annoying without it.

    0 讨论(0)
  • 2021-01-20 04:09

    Methods can take a construct called "Blocks". These are anonymous methods that get passed into the method.

    Another syntax for this is:

    method_call { |var| do_something(var) }
    

    Basically, you are saying that for each item in an iteration, name it "var" and do something with that item. The method simply calls your block that you passed in as it "yields" items to it.

    Does this help?

    edit: In your example, you they are using the iterator pattern in a funny way... probably only passing one format object into your block, so you can then tell it which formats to handle, and what to do when you see it.

    In other words, they are using the pattern to create a DSL of sorts that lets you configure what you respond to.

    0 讨论(0)
提交回复
热议问题