I'd like to try Ruby for something I did in Python. In Python it has the r"""
syntax to support raw strings, which is nice as it allows one to have raw strings in-line with the code and to concatenate them in more natural way and with no special indentation needed. In Ruby, when using raw strings, one has to use <<'EOT'
followed by EOT
in separate line which breaks the code layout.
You might ask, why not then use Ruby's %q{}
? Well, because %q{}
has limitations compared to Python's r"""
as it does not escape multiple \\\
and only handles single \
.
I am generating Latex code on the fly and write to a file, which later is compiled with pdflatex. The Latex code contain things like \\\
in many places. If I use Ruby's %q{}
syntax, then it will not work. So I have to use Ruby's <<'EOT'
but I do not want to do this, as it makes the code harder to read in the Ruby source file due to having to break it for indentation to make EOT
happy.
I am asking if there is a way to make syntax similar to %q{}
, or some function that take string and return same result as if one used EOT
, that handles raw strings without the limitation of EOT
.
I do not need interpolation. So single quoted strings only. No double quoted. double quotes causes interpolation, which I do not want.
Here is a small example in Python, and then I show what I have to do in Ruby to generate the same output.
my_file = open("py_latex.tex", 'w')
x = r"""\\\hline is a raw string"""+r""" another one \\\hline and so on"""
my_file.write(x)
When I open the Latex text file written to in the above, I see the correct result
Now to do the same thing in Ruby. I can't write the following (even though I'd like to)
file = File.open('rb_latex.tex','w')
x=%q{\\\hline is a raw string}+%q{ another one \\\hline and so on}
file.write(x)
The above ofcourse is not what I want. When it is written to latex file, it shows up as
Using EOT
works, as follows
file = File.open('rb_latex.tex','w')
x=<<-'EOT1'+<<-'EOT2'
\\\hline is a raw string
EOT1
another one \\\hline and so on
EOT2
file.write(x)
And the file now is
ps. it makes the second string on new line, this is a side-issue for me now, and will try to find solution for this after I solve the main problem at hand.
How to make %q{}
like syntax for Ruby that works similar to Python r"""
?
If someone wants to try the above code in Ruby, make sure there is no space after EOT
. I also include below the full source code.
Python full source
import os
os.chdir(" direct to change to here ")
my_file = open("py_latex.tex", 'w')
x = r"""\\\hline is a raw string"""+r""" another one \\\hline and so on"""
my_file.write(x)
my_file.close()
Ruby source code
#!/usr/local/bin/ruby -w
Dir.chdir("/home/....")
file = File.open('rb_latex.tex','w')
#x=%q{\\\hline is a raw string}+%q{ another one \\\hline and so on}
x=<<-'EOT1'+<<-'EOT2'
\\\hline is a raw string
EOT1
another one \\\hline and so on
EOT2
file.write(x)
file.close
Update
To answer comment below:
The idea is that it is supposed to act exactly like HERE-DOCUMENT, but with the nice syntax of %q{} to allow one to more easier format the string in the ruby source code. i.e. anything inside should be written to the file as is, no matter what it is.
I tested the solution provided below, but it does not work for all cases. Here is a test case:
#!/usr/local/bin/ruby -w
class String
def raw
gsub('\\'*2) { '\\'*3 }
end
end
class Array
def raw(separator = $,)
map(&:raw).join(separator)
end
end
Dir.chdir("/home/me")
file = File.open('rb_latex.tex','w')
x=%q{'\\'\hline \\\\\\ (6 of them) // some stuff follows. All should be raw string
<!DOCTYPE html>
\[ stuff \]
<html>
<head>
<title>title</title>
<style>
video {
width: 100% !important;
eight: auto !important;
}
</html> \"quotes\" (did you see this?)
\\\hline $\sin(x)$
</style>' //notice this ' is in the raw string!, ok!
\begin{tabular}{c}\\\hline '''''' (6 of them)
x\\\hline
\end{tabular}}.raw+%q{another '''one \\\hline and so on'}.raw
file.write(x)
file.close
Looking at the file written, it is not the same as the raw string:
Now compare with Python r"""
import os
os.chdir("/home/me")
my_file = open("py_latex.tex", 'w')
x =r"""\\'\hline \\\\\\ (6 of them) // some stuff follows. All should be raw string
<!DOCTYPE html>
\[ stuff \]
<html>
<head>
<title>title</title>
<style>
video {
width: 100% !important;
eight: auto !important;
}
</html> \"quotes\" (did you see this?)
\\\hline $\sin(x)$
</style>' //notice this ' is in the raw string!, ok!
\begin{tabular}{c}\\\hline '''''' (6 of them)
x\\\hline
\end{tabular}}"""+r"""{another '''one \\\hline and so on'"""
my_file.write(x)
my_file.close()
Here is the output
And the above is what I want to obtain from Ruby as well.
Use the + Operator for Writing Multi-Line String in Ruby The string concatenation operator is naive to write multi-line strings in Ruby. Unlike the above method, using + does not preserve whitespaces or newlines.
We can use string literal concatenation. Multiple string literals in a row are joined together: char* my_str = "Here is the first line." "Here is the second line."; But wait!
Strings are most often created with a String literal. A literal is a special syntax in the Ruby language that creates an object of a specific type. For example, 23 is a literal that creates a Fixnum object. As for String literals, there are several forms.
Alternate double quotes The %Q operator (notice the case of Q in %Q ) allows you to create a string literal using double-quoting rules, but without using the double quote as a delimiter. It works much the same as the %q operator.
To deal with indentation issues in here documents, one approach is to monkey-patch the core String
class, adding an instance method String#undent
:
class String
def undent
indentation = slice(/^\s+/).length
gsub(/^.{#{ indentation }}/, '')
end
end
Then you could rewrite your code like this:
x = <<-'EOT'.undent
\\\hline is a raw string
another one \\\hline and so on
EOT
Note: Patching core classes is generally considered bad style and might compromise stability and maintainability. That said, I feel that patching String
to add #undent
is a sensible exception. That method just has so many benefits and it is not really that invasive.
Ultimately, it’s up to you to weigh the pros and cons.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With