Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby HEREDOC syntax interprets string

Tags:

ruby

I wanted to do a little regex testing using irb with a HTML page I'm trying to gsub something off of.

However, the HEREDOC syntax we all know and love seems to be different in Ruby:

irb(main):140:0> text = <<-FUNUNU <p class="firstpara">
irb(main):141:0" FUNUNU
irb(main):142:0*
irb(main):143:0* puts text
SyntaxError: compile error
(irb):140: syntax error, unexpected kCLASS, expecting kDO or '{' or '('
text = <<-FUNUNU <p class="firstpara">
                         ^
(irb):143: syntax error, unexpected tIDENTIFIER, expecting kDO or '{' or '('
        from (irb):143
        from :0

It seems to complain about the contents of the string, trying to interpret it. From all the documentation I could find on the HEREDOC syntax, all point out that everything between the keywords should be part of the variable. But it doesn't seem so.

Are there formatting restrictions about the contents of the string, other than that the HEREDOC string ends with the 2nd expression of the HEREDOC indicator?

like image 736
0xCAFEBABE Avatar asked Jun 13 '13 13:06

0xCAFEBABE


2 Answers

You can't put the string on the same line of the heredoc delimiter, because after the delimiter, on the same line, it is allowed to put Ruby code, i.e.

irb> text = <<-FOO # Ruby code allowed here...
irb*   <a class="foo">
irb* FOO
# => "<a class=\"foo\">\n" 
irb> text
# => "<a class=\"foo\">\n"

This is because you can write something like this:

irb> instance_eval(<<-CODE)
irb* def foo
irb*   "foo"
irb* end
irb* CODE

Or even:

def foo(a, b, c)
  [a, b, c]
end

foo(<<-A, <<-B, <<-C)
foo
A
bar
B
baz
C
# => ["foo\n", "bar\n", "baz\n"]
like image 192
toro2k Avatar answered Oct 20 '22 22:10

toro2k


As has been pointed out, the heredoc text begins on the next line after the heredoc terminator. This is not meant to replace those answers but rather provide a possibly better alternative to the typical heredoc syntax.

I personally prefer to use %q{}. It equates to using single quotes. The following give the same output:

text = %q{ <a class="foo"> }
text = ' <a class="foo"> '

If you would like to use string interpolation:

text = %Q{ <a class="#{class_name}">}

You can also switch out the {} for other terminators. The following two lines give exactly the same output:

text = %Q[ <a class="#{class_name}">] 
text = %Q| <a class="#{class_name}">|

And they support multiple lines:

text = %q{<p>
Some text
</p>}

There are some good answers on this SO question in reference to different uses for this syntax.

like image 41
Charles Caldwell Avatar answered Oct 20 '22 21:10

Charles Caldwell