There is an example in the book:
"Seconds/day: #{24*60*60}" # => Seconds/day: 86400
"#{'Ho! '*3}Merry Christmas!" # => Ho! Ho! Ho! Merry Christmas!
"This is line #$." # => This is line 3
But when I try to implement the third line's symbol #$ it in a separate file, it prints smth strange. Here's my file str2.rb:
puts "Hello, World #$."
puts "Hello, World #$"
puts "#$"
Now I run it (in Win XP console):
C:\ruby\sbox>ruby str2.rb
Hello, World 0
Hello, World ["enumerator.so", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/i386-mingw32/enc/encdb.so", "C:/Rai
lsInstaller/Ruby1.9.3/lib/ruby/1.9.1/i386-mingw32/enc/windows_1251.so", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/
1.9.1/i386-mingw32/enc/trans/transdb.so", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/rubygems/defau
lts.rb", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/i386-mingw32/rbconfig.rb", "C:/RailsInstaller/Ruby1.9.3/l
ib/ruby/site_ruby/1.9.1/rubygems/deprecate.rb", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/rubygems
/exceptions.rb", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/rubygems/defaults/operating_system.rb",
"C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb", "C:/RailsInstaller/Ruby1.9
.3/lib/ruby/site_ruby/1.9.1/rubygems.rb", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/i386-mingw32/enc/utf_16l
e.so", "C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/i386-mingw32/enc/trans/utf_16_32.so", "C:/RailsInstaller/Ru
by1.9.3/lib/ruby/1.9.1/i386-mingw32/enc/trans/single_byte.so"]
puts
I've found that #$. (the period is mandatory) shows the line number only in Interactive Ruby Console. Used in file it produces 0 on any line. But why all that text is printed if I use symbols like this "#$" \n "#$"?
Also such a code in a file:
puts "Hello, World #$" ## without period at the end
produces such an error:
C:\ruby\sbox>ruby str2.rb
str2.rb:3: unterminated string meets end of file
What does #$ mean? Where and how to use it?
"#$." is shorthand for "#{$.}", or the interpolation of a global variable. Similarly there is ## for an instance variable & ### for a class variable.
The problem with what you have is that the second " in "#$" is not interpreted as the closing quote for the string, but instead as part of the global variable name being interpolated ($"). To make it more clear how your code is actually being interpreted, I’ll use string literals in place of what Ruby thinks are string delimiters:
puts %(Hello, World #$.)
puts %(Hello, World #$"
puts )#$"
As you can see, this is where the array printed comes from (it’s the contents of $") as well as the “puts” string at the end. The #$" at the end of your code is interpreted as a comment. (Note that the second string is spanning—and including—the newline between lines two and three.)
If you actually want to print #$ as a string, you have to escape part of it or use a single-quoted string:
"\#$" #=> "#$"
"#\$" #=> "#$"
'#$' #=> "#$"
Simply placing #$ in an interpolated string without escaping is not valid, as can be seen by using string literals:
%(#$) #=> #<SyntaxError: (eval):2: syntax error, unexpected $undefined
# %(#$)
# ^>
In Ruby a global variables are defined using dollar sign.
$foo = "bar"
There are some pre-defined globals such as
# last line number seen by interpreter
$.
I think you are just missing the period. You can insert a variable into a string using -
"line #{$.}"
or shorthand
"line #$."
Related
data = File.read("data.txt")
if(data.to_s.eql? "hello")
...
end
My data.txt is filled with "hello" as well, so the if-loop should get active but it doesn't. What do I do wrong?
When reading data from a file, it's likely you get a newline tagged on to the end of your data.
For example, if I run the following in the terminal to create a file containing only the word 'hello':
echo hello > data.txt
And the read this in the terminal, I see:
cat data.txt
# => hello
However, jumping into irb, I get the following:
File.read("data.txt")
# => "hello\n"
The \n is the newline operator.
To solve your question, you can use:
if data.chomp == "hello"
...
end
chomp removes any record separator from the end of the string, giving you the comparison you're after.
If you just want to know whether the file contains the specified string, you can also use:
data['hello']
This will return the truthy value in the square brackets if present, or nil if not.
if data["hello"]
...
end
I have a question about the need for the use of \n\n to make a newline.
Please see below examples.
If I do ..
puts "hello"
puts "hi"
or
puts "hello\n"
puts "hi"
The output is..
hello
hi
If I do ..
puts "hello\n\n"
puts "hi"
The output is..
hello
hi
Why do I need \n\n to make one extra newline?
Why doesn't the single \n make any difference?
From the documentation:
puts(obj, ...) → nil
Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line. If called without arguments, outputs a single record separator.
The purpose of puts is to ensure the string ends with the newline character.
If there is none, then one newline character will be appended.
If there is one or more, no newline character will be appended.
The other answers here nailed it.
If you want to avoid the magic handling of \n, try using print instead of puts. print outputs your string literally, with no line ending unless you put it there.
> 3.times { print 'Zap' }
ZapZapZap=> 3
> 3.times { puts 'Zap' }
Zap
Zap
Zap
=> 3
I've recently been coding in Ruby and have come from Python, where single and double quotes made no difference to how the code worked as far as I know.
I moved to Ruby to see how it worked, and to investigate the similarities between Ruby and Python.
I was using single-quoted strings once and noticed this:
hello = 'hello'
x = '#{hello} world!'
puts x
It returned '#{hello} world!' rather than 'hello world!'.
After noticing this I tried double quotes and the problem was fixed. Now I'm not sure why that is.
Do single and double quotes change this or is it because of my editor (Sublime text 3)? I'm also using Ruby version 2.0 if it works differently in previous versions.
In Ruby, double quotes are interpolated, meaning the code in #{} is evaluated as Ruby. Single quotes are treated as literals (meaning the code isn't evaluated).
var = "hello"
"#{var} world" #=> "hello world"
'#{var} world' #=> "#{var} world"
For some extra-special magic, Ruby also offers another way to create strings:
%Q() # behaves like double quotes
%q() # behaves like single quotes
For example:
%Q(#{var} world) #=> "hello world"
%q(#{var} world) #=> "#{var} world"
You should read the Literals section of the official Ruby documentation.
It is very concise, so you need to read carefully. But it explains the difference between double-quoted and single-quoted strings, and how they are equivalent to %Q/.../ and %q/.../ respectively.
If you enclose Ruby string in single qoutes, you can't use interpolation. That's how Ruby works.
Single-quoted strings don't process escape sequence \ and they don't do string interpolation.
For a better understanding, take a look at String concatenation vs. interpolation
To answer your question, you have to use "" when you want to do string interpolation:
name = 'world'
puts "Hello #{name}" # => "Hello world"
Using escape sequence:
puts 'Hello\nworld' # => "Hello\nworld"
puts "Hello\nworld" # => "Hello
world"
Ruby supports single-quoted string, for many uses like as follow:
>> 'foo'
=> "foo"
>> 'foo' + 'bar'
=> "foobar"
In above example, those two types of strings are identical. We can use double quote in place of single quote and we will get same output like above example.
As you face problem, while using interpolation in single quoted string because Ruby do not interpolate into single-quoted string. I am taking one example for more understanding:
>> '#{foo} bar'
=> "\#{foo} bar"
Here you can see that return values using double-quoted strings, which requires backslash to escape special characters such as #.
Single quoted string often useful because they are truly literal.
In the string interpolation concept, the essential difference between using single or double quotes is that double quotes allow for escape sequences while single quotes do not.
Let's take an example:
name = "Mike"
puts "Hello #{name} \n How are you?"
The above ruby code with string interpolation will interpolate the variable called name which is written inside brackets with its original value which is Mike. And it will also print the string How are you? in a separate line since we already placed an escape sequence there.
Output:
Hello Mike
How are you?
If you do the same with single quotes, it will treat the entire string as a text and it will print as it is including the escape sequence as well.
name = Mike'
puts 'Hello #{name} \n How are you'?
Output:
Hello #{name} \n How are you?
I am having trouble with named captures in regular expressions in Ruby 2.0. I have a string variable and an interpolated regular expression:
str = "hello world"
re = /\w+/
/(?<greeting>#{re})/ =~ str
greeting
It raises the following exception:
prova.rb:4:in <main>': undefined local variable or methodgreeting' for main:Object (NameError)
shell returned 1
However, the interpolated expression works without named captures. For example:
/(#{re})/ =~ str
$1
# => "hello"
Named Captures Must Use Literals
You are encountering some limitations of Ruby's regular expression library. The Regexp#=~ method limits named captures as follows:
The assignment does not occur if the regexp is not a literal.
A regexp interpolation, #{}, also disables the assignment.
The assignment does not occur if the regexp is placed on the right hand side.
You'll need to decide whether you want named captures or interpolation in your regular expressions. You currently cannot have both.
Assign the result of #match; this will be accessible as a hash that allows you to look up your named capture groups:
> matches = "hello world".match(/(?<greeting>\w+)/)
=> #<MatchData "hello" greeting:"hello">
> matches[:greeting]
=> "hello"
Alternately, give #match a block, which will receive the match results:
> "hello world".match(/(?<greeting>\w+)/) {|matches| matches[:greeting] }
=> "hello"
As an addendum to both answers in order to make it crystal clear:
str = "hello world"
# => "hello world"
re = /\w+/
# => /\w+/
re2 = /(?<greeting>#{re})/
# => /(?<greeting>(?-mix:\w+))/
md = re2.match str
# => #<MatchData "hello" greeting:"hello">
md[:greeting]
# => "hello"
Interpolation is fine with named captures, just use the MatchData object, most easily returned via match.
x = "hello" " world".to_sym
puts x.class
This works and allows me to concatenate the two strings into a symbol, producing the output:
Symbol
But if I change it slightly to use a + instead of a space separating the hello and world strings, I get an error:
x = "hello" + " world".to_sym
puts x.class
This produces the following error - I think this is because it's trying to 'cast' the "world".to_sym call back to a string before concatenating it onto the "hello" string:
in `+': can't convert Symbol into String (TypeError)
I'm wondering what makes the first example work? Does anyone know what the order of operations is here? I suspect the two strings are actually treated as one, that the space between them is ignored and they are concatenated before the to_sym method is called. I actually would have expected it to work no differently than the second example because I thought the to_sym would be called on the "world" string BEFORE any attempt is made to join the contents of "hello" and "world".
The first example is syntactic sugar, normally you see this written like:
x = "Here is a string that " \
"I want to split across " \
"several lines..."
So this happens first, before to_sym. In the second example you are literally calling:
x = "hello".+( "world".to_sym )
Which is obviously not going to work since String#+ can't do anything useful with a symbol as an argument.
In short, don't do the first one, if you want to do "hello world".to_sym and you can't just write it like that for whatever reason then just use parenthesis: ("hello" + " world").to_sym
Two or more string literals put right beside each other like that are immediately treated as a single string literal. When the Ruby interpreter converts your code to tokens, it converts
"hello" " world"
to the single token string "hello world" and it converts
"hello" + " world"
to three tokens: string "hello", method +, and string " world". It would then concatenate the strings together later on when actually executing the code.