Forum: Ruby Could someone please explain the magic in this code

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
44a43e7fef8e933e802a7802b4bd3525?d=identicon&s=25 John Small (johnsmall)
on 2009-02-01 21:16
I need to use erb templates so I went to look at the documentation. It
all seems straight forwards until I get to the example where a lot of
new coding concepts are pulled in and I'm left totally mystified about
what's going on.

The code, from the api documentation is
<pre>
 require "erb"

 # build data class
 class Listings
   PRODUCT = { :name => "Chicken Fried Steak",
               :desc => "A well messages pattie, breaded and fried.",
               :cost => 9.95 }

   attr_reader :product, :price

   def initialize( product = "", price = "" )
     @product = product
     @price = price
   end

   def build
     b = binding
     # create and run templates, filling member data variebles
     ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "",
"@product").result b
       <%= PRODUCT[:name] %>
       <%= PRODUCT[:desc] %>
     END_PRODUCT
     ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@price").result b
       <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
       <%= PRODUCT[:desc] %>
     END_PRICE
   end
 end

 # setup template data
 listings = Listings.new
 listings.build

 puts listings.product + "\n" + listings.price

</pre>
My questions are;-

(1) what does "<<-" do just before 'END_PRODUCT'
(2) how do the lines after .result b get substituted into END_PRODUCT
and why is there a gsub there. My understanding of the order things are
happening is clearly deficient because the gsub to remove white space
will have no effect on 'END_PRODUCT' since there's no white space in it.
So somehow 'END_PRODUCT' is getting replaced by the lines below, which
aren't in quotes, before the gsub happens. wtf is going on here?

(3) How does binding work? The documentation is pretty opaque. What is
it doing in this context and why is it required?

All explanations welcome
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2009-02-01 22:05
(Received via mailing list)
On Feb 1, 2009, at 3:15 PM, John Small wrote:

> class Listings
>
>       <%= PRODUCT[:desc] %>
> </pre>
> My questions are;-
>
> (1) what does "<<-" do just before 'END_PRODUCT'

That's a "here document".  <<-'END_PRODUCT' means to take the
following lines up until a line begins with END_PRODUCT as if they
were a string.  The - let's END_PRODUCT be indented from the beginning
of the line.  The single quotes say that no interpolation is to be
done on the string (that is, it should act like a string literal with
single quotes).

>
> (2) how do the lines after .result b get substituted into END_PRODUCT

I hope (1) answers that ...

>
> and why is there a gsub there.

The gsub is removing the leading whitespace /^\s+/ from each line.
This lets the here-document contents be intended to where code would
normally be.

> My understanding of the order things are
> happening is clearly deficient because the gsub to remove white space
> will have no effect on 'END_PRODUCT' since there's no white space in
> it.
> So somehow 'END_PRODUCT' is getting replaced by the lines below, which
> aren't in quotes, before the gsub happens. wtf is going on here?

Do you get it now?

The equivalent would look like:
     ERB.new("<%= PRODUCT[:name] %>\n<%= PRODUCT[:desc] %>\n",
             0, "", "@product").result b
If the here-document were not used.

>
> (3) How does binding work? The documentation is pretty opaque. What is
> it doing in this context and why is it required?

You want the PRODUCT, @product, and @price to be evaluated in the
context of the Listings object rather than the new ERB object just
created.

>
>
> All explanations welcome
> --
> Posted via http://www.ruby-forum.com/.
>


I hope this helps.

-Rob

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-02-01 22:10
John Small wrote:
> (1) what does "<<-" do just before 'END_PRODUCT'
> (2) how do the lines after .result b get substituted into END_PRODUCT

Search for "here document" in
http://www.ruby-doc.org/docs/ProgrammingRuby/html/...

It's essentially an inline string literal, from the line following
<<-FOO until the line which has FOO.

> (3) How does binding work? The documentation is pretty opaque. What is
> it doing in this context and why is it required?

A binding is the environment in which variables are evaluated. If you
pass a binding, it allows the local variables in your environment to be
accessed from elsewhere.

irb(main):001:0> def foo(b)
irb(main):002:1> puts "x is #{eval("x",b)}"
irb(main):003:1> end
=> nil
irb(main):004:0> x = 4
=> 4
irb(main):005:0> foo(binding)
x is 4
=> nil

Note that normally the local variable x would not be accessible inside
foo, which has its own scope.
44a43e7fef8e933e802a7802b4bd3525?d=identicon&s=25 John Small (johnsmall)
on 2009-02-02 08:22
Ok thanks for that, I've got it now.

John Small
44a43e7fef8e933e802a7802b4bd3525?d=identicon&s=25 John Small (johnsmall)
on 2009-02-02 08:23
Rob

Ok thanks for that, I've got it now.

John Small
This topic is locked and can not be replied to.