21

Say I wanted to have a very large block of pretty printed html code strait inline with my ruby code. What is the cleanest way to do this without losing any formatting in my string or having to remember some sort of gsub regex.

Encoding it all in one line is easy to do but hard to read:

1.times do
  # Note that the spaces have been changed to _ so that they are easy to see here.
  doc = "\n<html>\n__<head>\n____<title>\n______Title\n____</title>\n__</head>\n__<body>\n____Body\n__</body>\n</html>\n"
  ans = "Your document: %s" % [doc]
  puts ans
end

Multiline text in ruby is easier to read but the string can't be indented with the rest of the code:

1.times do
  doc = "
<html>
  <head>
    <title>
      Title
    </title>
  </head>
  <body>
    Body
  </body>
</html>
"
  ans = "Your document: %s" % [doc]
  puts ans
end

For example the following is indented with my code, but the string now has four extra spaces in front of every line:

1.times do
  doc = <<-EOM

    <html>
      <head>
        <title>
          Title
        </title>
      </head>
      <body>
        Body
      </body>
    </html>
  EOM
  ans = "Your document: %s" % [doc]
  puts ans
end

Most people go with the HEREDOC code above, and do a regex replace on the result to take out the extra whitespace at the beginning of each line. I would like a way where I don't have to go through the trouble of regexing each time.

Vanson Samuel
  • 1,953
  • 2
  • 17
  • 30
  • 1
    Check out - http://stackoverflow.com/questions/3350648/ruby-indented-multiline-strings – theglauber Apr 05 '13 at 16:52
  • 1
    Also - http://stackoverflow.com/questions/3772864/how-do-i-remove-leading-whitespace-chars-from-ruby-heredoc – theglauber Apr 05 '13 at 17:00
  • `I have a string ("when \n the\n clock\n strikes\n ten\n") that would be much cleaner if it can be typed in with actual newline characters.` doesn't make sense. `"\n"` are actual newline characters. – the Tin Man Apr 05 '13 at 19:10
  • @(the Tin Man) I rewrote the question. – Vanson Samuel Apr 06 '13 at 18:25
  • @theglauber I would like to use something off the shelf, and I don't want to memorize some regex. – Vanson Samuel Apr 06 '13 at 18:26
  • @VansonSamuel Why would you need to memorize some regex? You could store it in a constant at the beginning of your code and use it through-out. I use a lot of regex in my code and I never memorize it. – Charles Caldwell Apr 06 '13 at 23:27
  • @(Charles Caldwell) I find myself having to do this type of thing once in a while in different projects, and I figure it would be nice to have a standard way of doing this. – Vanson Samuel Apr 07 '13 at 01:46

4 Answers4

31

Since Ruby 2.3, the <<~ heredoc strips leading content whitespace:

def make_doc(body)
  <<~EOF
  <html>
    <body>
      #{body}
    </body>
  </html>
  EOF
end

puts make_doc('hello')

For older Ruby versions, the following is more verbose than the solutions presented in the other answers, but there's almost no performance overhead. It's about as fast as a single long string literal:

def make_doc(body)
  "<html>\n"       \
  "  <body>\n"     \
  "    #{body}\n"  \
  "  </body>\n"    \
  "</html>"
end
ens
  • 1,068
  • 13
  • 14
20
string = %q{This
    is
        indented
  and
    has
         newlines}

Here is a blog with some examples of %q{}, %Q{} and others.

As far as having it easy to remember, think 'Q' for `Quotation Marks'.

Sidenote: Technically you don't need the 'q' while doing quotation.

string = %{This
   also
      is indented
  and
     has
   newlines
      and handles interpolation like 1 + 1 = #{1+1}
}

However, it is best practice and more readable to use %Q{}.

Charles Caldwell
  • 16,649
  • 4
  • 40
  • 47
5

The "|" in YAML allows you to create multiline strings that can be indented. The whitespace is only counted if it is in columns after the first non-whitespace character on the first line. In this way you can have multiline string that have indentation, but are also indented in the code.

require 'yaml'

1.times do
  doc = YAML::load(<<-EOM)
  |

     <html>
       <head>
         <title>
           Title
         </title>
       </head>
       <body>
         Body
       </body>
     </html>  
  EOM
  ans = "Your document: %s" % [doc]
  puts ans
end
Vanson Samuel
  • 1,953
  • 2
  • 17
  • 30
3

It's not real obvious what you're asking for. If I wanted to generate strings like:

"when \n the\n clock\n strikes\n ten\n"

on the fly, I'd build them dynamically:

%w[when the clock strikes ten].join("\n ")
=> "when\n the\n clock\n strikes\n ten"

Concatenating a trailing "\n" will add the trailing carriage return:

%w[when the clock strikes ten].join("\n ") + "\n"
=> "when\n the\n clock\n strikes\n ten\n"

If I am dealing with sub-strings that have embedded spaces, I'd adjust the array to:

['when the', 'clock strikes', 'ten'].join("\n ") + "\n"
=> "when the\n clock strikes\n ten\n"
the Tin Man
  • 158,662
  • 42
  • 215
  • 303