What is heredoc?
Heredoc allows us to specify a string as a block of texts where new lines and indentations are maintained.
This is useful in Ruby for various cases like specifying multiline text strings, multiline method dynamic definitions and more.
There are many ways to use Heredoc in Ruby and in Rails, with different utilities. This can be confusing at times where to use which version. Let’s do a run-down of different ways to use it.
How to define?
We can define multiline strings in Ruby in the following ways:
> str = <<HEREDOC
> This is
> a sample
> text.
>HEREDOC
=> " This is\n a sample\n text.\n"
> str = <<-HEREDOC
> This is
> a sample
> text.
> HEREDOC
=> " This is\n a sample\n text.\n"
Here HEREDOC
is the start and end marker. It can be any string.
This can be used in embedding the code snippets like SQL statements or HTML. For Example:
> query = <<-SQL
> Select * from users
> where name = 'John'
> SQL
=> "Select * from users\nwhere name = 'John'\n"
There is a very subtle difference between <<
and <<-
.
<<
expects end marker(HEREDOC
in our case) should be at the start of the line.
Whitespace before the marker at the end of the line is invalid syntax.
We can use <<-
instead if we need to add more spaces for better reading of the text.
> str = <<-HEREDOC
> Notice the spaces immediately before
> the end.
> HEREDOC
=> "Notice the space immediately before\nthe end.\n"
Input Redirection
<<
can be used for input redirection in Ruby.
Below is an example of heredoc
with input redirection.
> File.open('test.rb', 'w') do |f|
> f << <<-HEREDOC
> This is a test
> File
> HEREDOC
end
Now let’s read the content of the test.rb
file.
> f = File.open('test.rb', 'r')
> f.read
=> " This is a test\n File\n"
We can also use %Q
instead of heredoc
.
The following example will add a new line at the start and end of the string.
>str = %Q(
> This is
> a sample
> text.
>)
=> "\nThis is\na sample\ntext.\n"
Interpolation
Strings inside heredoc
are treated as double-quoted strings,
hence string interpolation is possible with heredoc.
> name = 'John'
> str = <<-HEREDOC
My Name is
#{name}.
HEREDOC
=> " My Name is\n John.\n"
> name = 'John'
> str = <<-"HEREDOC"
My Name is
#{name}.
HEREDOC
=> " My Name is\n John.\n"
We can opt-out the interpolation by using
single-quoted heredoc
start marker string.
For example:
> name = 'John'
> str = <<-'HEREDOC'
My Name is
#{name}.
HEREDOC
=> " My Name is\n #{name}.\n"
How to remove unwanted spaces?
We can remove unwanted spaces using gsub
.
> str = <<-HEREDOC.gsub(/^\s+/, "")
This is a
sample text.
HEREDOC
=> "This is a\nsample text.\n"
In Rails, there is a method strip_heredoc
which we can use to remove the unwanted spaces.
> str = <<-HEREDOC.strip_heredoc
This is a
sample text.
HEREDOC
=> "This is a\nsample text.\n"
Squiggly heredoc
Ruby 2.3 introduced the squiggly heredoc <<~
to remove the spaces due to indentation.
> str = <<~HEREDOC
This is a
sample text.
HEREDOC
=> "This is a\nsample text.\n"
Let’s take a look at another example:
> str = <<~HEREDOC
Hello,\nGood Morning
My name is John.
HEREDOC
=> "Hello,\nGood Morning\nMy name is John.\n"
> puts str
=> Hello,
=> Good Morning
=> My name is John.
Now, we will use strip_heredoc
instead of <<~
.
> str = <<-HEREDOC.strip_heredoc
Hello,\nGood Morning
My name is John.
HEREDOC
=> " Hello,\nGood Morning\n My name is John.\n"
> puts str
=> Hello,
=> Good Morning
=> My name is John.
As we can see that strip_heredoc
didn’t remove the leading spaces in the above example
because the strip_heredoc
documentation says
It looks for the least indented non-empty line in the whole string and removes that amount of leading whitespace.
This is the only difference between strip_heredoc
and <<~
.
Convert multiline into one line
In Rails, we can use String#squish
to convert multiline into one line.
> str = <<~HEREDOC.squish
This is a
sample text.
HEREDOC
=> "This is a sample text."
Shell Command
To execute shell commands, we can use backticks.
> str = <<~`HEREDOC`
date
HEREDOC
=> "Wed Mar 25 18:51:08 IST 2020\n"
Summary
We looked at the different ways of defining
multiline string in Ruby and Rails using heredoc
.
Hopefully, it will be less confusing next time we need to make use of one of the heredoc versions.