Multiline strings with no indent
In the RubyTapas Episode 249, Avdi Grimm describes a technique to strip leading whitespace from a multi-line string:
def unindent(s)
s.gsub(/^#{s.scan(/^[ \t]+(?=\S)/).min}/, '')
end
It is behavior compatible to other existing solutions to this problem, e.g. String#strip_heredoc in ActiveSupport / Rails or the standalone unindent gem.
You can use this method with a heredoc which is special syntax in ruby (and many other languages) to write multi-line strings.
module Something
def unindent(s)
s.gsub(/^#{s.scan(/^[ \t]+(?=\S)/).min}/, '')
end
def welcome
unindent(<<-TEXT)
Hello
This is an example. This multiline string works
- even with deeper nestings...
All is OK here :)
TEXT
end
end
Is there an easy way to do multiline indented strings in Ruby?
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
Ruby indented multiline strings
Personally, I think that Ruby's indented heredocs are useless and they should work more like Bash indented heredocs and also strip whitespace inside the string …
Anyway, there are a couple of libraries that try to deal with this situation. There is a wide array of libraries that try to fix this problem:
- Martin Aumont's Unindent library which is also part of the Facets library
- Facets also provides
String#margin
- Sunlight Labs' Unindentable library
- Samuel Dana's Indentation library
Ruby: Can I write multi-line string with no concatenation?
There are pieces to this answer that helped me get what I needed (easy multi-line concatenation WITHOUT extra whitespace), but since none of the actual answers had it, I'm compiling them here:
str = 'this is a multi-line string'\
' using implicit concatenation'\
' to prevent spare \n\'s'
=> "this is a multi-line string using implicit concatenation to eliminate spare
\\n's"
As a bonus, here's a version using funny HEREDOC syntax (via this link):
p <<END_SQL.gsub(/\s+/, " ").strip
SELECT * FROM users
ORDER BY users.id DESC
END_SQL
# >> "SELECT * FROM users ORDER BY users.id DESC"
The latter would mostly be for situations that required more flexibility in the processing. I personally don't like it, it puts the processing in a weird place w.r.t. the string (i.e., in front of it, but using instance methods that usually come afterward), but it's there. Note that if you are indenting the last END_SQL
identifier (which is common, since this is probably inside a function or module), you will need to use the hyphenated syntax (that is, p <<-END_SQL
instead of p <<END_SQL
). Otherwise, the indenting whitespace causes the identifier to be interpreted as a continuation of the string.
This doesn't save much typing, but it looks nicer than using + signs, to me.
Also (I say in an edit, several years later), if you're using Ruby 2.3+, the operator <<~ is also available, which removes extra indentation from the final string. You should be able to remove the .gsub
invocation, in that case (although it might depend on both the starting indentation and your final needs).
EDIT: Adding one more:
p %{
SELECT * FROM users
ORDER BY users.id DESC
}.gsub(/\s+/, " ").strip
# >> "SELECT * FROM users ORDER BY users.id DESC"
Whitespace with multiline string in ruby
Ruby 2.3.0 solves this nicely with the squiggly heredoc. Note the difference of the tilde/hyphen between examples.
hyphen_heredoc = <<-MULTILINE_STRING
One line
Second line
Indented two spaces
MULTILINE_STRING
squiggly_heredoc = <<~MULTILINE_STRING_WITH_TILDE
One line
Second line
Indented two spaces
MULTILINE_STRING_WITH_TILDE
2.3.0 :001 > puts hyphen_heredoc
One line
Second line
Indented two spaces
2.3.0 :002 > puts squiggly_heredoc
One line
Second line
Indented two spaces
With the squiggly heredoc, The indentation of the least-indented line will be removed from each line of the content.
Interpolate multiline string with correct indent
I woke up and saw this question and decided to make it a morning programming puzzle to solve. It was harder than I thought. I'm not thrilled with the API or the complexity, but I didn't want to spend any more time, and it does work. Maybe you'll find it useful. If not, perhaps it will at least inspire some other alternative approaches.
I do not know of any libraries or frameworks that meet your needs using plain Ruby Here Documents. Ruby 2.3 has a new feature that basically does what Rails' #strip_heredoc
does, but I haven't used it and I don't know how it handles multi-line interpolation. Here is the Ruby code for my custom solution based on your use case (using Ruby 2.0):
https://gist.github.com/shock/1d269a91f938bf1a1c3cba3856bedf19
Breaking up long strings on multiple lines in Ruby without stripping newlines
Three years later, there is now a solution in Ruby 2.3: The squiggly heredoc.
class Subscription
def warning_message
<<~HEREDOC
Subscription expiring soon!
Your free trial will expire in #{days_until_expiration} days.
Please update your billing information.
HEREDOC
end
end
Blog post link: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc
The indentation of the least-indented line will be
removed from each line of the content.
Related Topics
Why Doesn't Relative_Require Work on Ruby 1.8.6
How to Receive a JSON Object with Rack
Does Ruby Have Syntax for Safe Navigation Operator of Nil Values, Like in Groovy
Capistrano and API Keys in Env Variables
How to Upload a Text File and Parse Contents into Database in Ror
Removing or Overriding an Activerecord Validation Added by a Superclass or Mixin
Match Sequences of Consecutive Characters in a String
Ruby Regex Gsub a Line in a Text File
Handling Iframe with Capybara Ruby
Camelcase Column in Postgresql Database in Rails (Activerecord)
How to Stringize/Serialize Ruby Code
Changing Songs on Jplayer by Clicking a Link, Hosted on Amazon S3
Rails 4.1 Activerecord::Relation Is No More Like Array
How to Stop Rails' Built-In Server from Listening on 0.0.0.0 by Default
Ruby on Rails - Doesn't Create Script/Server
What Order Do Before Filters Occur In
Install Nokogiri 1.6.1 Under Ruby 2.0.0P353 (Rvm Based Installation) Fails (Osx Mavericks)