I thought that (in a while...do loop)
gets.chomp != ''
might match a carriage return from a terminal. It doesn't. What am I not understanding? Thank you.
String#chomp removes carriage returns from the string it is being called on.
If you remove chomp it should give you the expected output. See below:
2.1.2 :001 > def foo
2.1.2 :002?> while true do
2.1.2 :003 > puts gets != ''
2.1.2 :004?> end
2.1.2 :005?> end
=> :foo
2.1.2 :006 > foo
a
true
b
true
c
true
1
true
2
true
# about to press enter
true
true
Hope this helps
Related
Is it possible to intercept IRB inputs? Specifically for class#Fixnum?
Example:
5
=> 5
What I need to do is: (pseudo code)
if IRB.input.is_a?(Fixnum)
some_method(IRB.input) # some_method(5)
end
Look at this file.
You can find Irb#eval_input method and patch them:
# code before
#scanner.set_input(#context.io) do
signal_status(:IN_INPUT) do
if l = #context.io.gets
if l.match(/^\d+$/)
puts 'Integer found!'
end
print l if #context.verbose?
else
if #context.ignore_eof? and #context.io.readable_after_eof?
l = "\n"
if #context.verbose?
printf "Use \"exit\" to leave %s\n", #context.ap_name
end
else
print "\n"
end
end
l
end
end
# code after
Irb output example:
spark#think:~$ irb
2.1.5 :001 > 123
Integer found!
=> 123
2.1.5 :002 > "string"
=> "string"
def starts_with_consonant?(s)
if /^(a|e|i|o|u).*/i =~ s
true
else
false
end
end
# prints out true
puts starts_with_consonant?('aa')
# prints out false
puts starts_with_consonant?('da')
If I change the code just to
def starts_with_consonant?(s)
/^(a|e|i|o|u).*/i =~ s
end
Is that same functionality because
puts starts_with_consonant?('aa').inspect
prints out 0 (Shouldn't it be 1?)
puts starts_with_consonant?('da').inspect
prints out nil
# both print out 0
puts starts_with_consonant?('aa').to_i
puts starts_with_consonant?('da').to_i
What gives?
The =~ operator returns the first match index if the String and Regexp match, otherwise nil is returned:
'foo' =~ /bar/ # => nil
'foo bar' =~ /bar/ # => 4
Your first method, with the if/else statement, is treating the result of the =~ check as "truthy value or not?". If the match is found in the string, it returns the index (in your case, 0) or if it is not found, it returns nil.
0 is a truthy value; nil is not.
Therefore, even though it's returning the same result in each of your methods containing the /.../ =~ s expression, you get different return values out of the methods, depending on what you do with that result.
In the if/else statement, you get true when it's the truthy value of 0, and false when it's the non-truthy value of nil.
In the bare return statement, you get the plain return values of 0 and nil.
well the #=~ method actually returns the index where the first match occurs.
You can't do nil.to_i because that produces zero.
[6] pry(main)> nil.to_i
=> 0
puts starts_with_consonant?('aa').inspect
prints out 0 (Shouldn't it be 1?)
No, it should be 0. Strings are zero-indexed, the pattern has been found on the zeroth position. 0 is a truthy value, triggering the if clause if evaluated there. 'da' =~ /a/ would return 1, since a is the 1st character in the string (d being 0th).
puts starts_with_consonant?('da').inspect
prints out nil
There is no position that matches the pattern, so the return value is nil, a falsy value, which triggers the else clause if evaluated as an if condition.
# both print out 0
puts starts_with_consonant?('aa').to_i
puts starts_with_consonant?('da').to_i
Because both 0.to_i and nil.to_i result in 0.
Your getting back truthy. You can't print it but you can use it, e.g.
2.0.0-p247 :007 > if "aaaabcd" =~ /a/ then puts "true" end
true
=> nil
2.0.0-p247 :008 > if "aaaabcd" =~ /aaa/ then puts "true" end
true
=> nil
2.0.0-p247 :009 > if "aaaabcd" =~ /z/ then puts "true" end
=> nil
Similarly you can set a variable based on the evaluation, i.e.
2.0.0-p247 :013 > if "aaaabcd" =~ /a/ then b=1 end
=> 1
2.0.0-p247 :014 > if "aaaabcd" =~ /aaa/ then b=1 end
=> 1
2.0.0-p247 :015 > if "aaaabcd" =~ /zzz/ then b=1 end
=> nil
Below is the code which I tried in ruby console. Can anyone tell me why the output is different in this two cases for the same input.
2.1.4 :014 > def a_method
2.1.4 :015?> puts "enter"
2.1.4 :016?> a = gets.chomp
2.1.4 :018?> puts a
2.1.4 :019?> puts a.to_i
2.1.4 :020?> end
=> :a_method
2.1.4 :021 > a_method
enter
"12"
"12"
0 (output of a.to_i)
=> nil
2.1.4 :022 > "12".to_i
=> 12
Here I'm just converting a string number into integer by reading from console using gets, which is giving 0 as output. If I do the same by just giving "12".to_i then I'm getting proper output. Why is that?
Inspect the intermediate variable a when entering "12" (with quotes)
a = gets.chomp
# a => "\"12\""
a.to_i # => 0
"\"12\"".to_i # => 0
If you want to enter the actual number, not a string representation of it, do not use the quotes.
This output might help explain the issue:
2.1.1 :001 > def a_method
2.1.1 :002?> puts "enter"
2.1.1 :003?> a = gets.chomp
2.1.1 :004?> puts a.class.name
2.1.1 :005?> puts a
2.1.1 :006?> puts a.to_i
2.1.1 :007?> end
=> :a_method
2.1.1 :008 > a_method
enter
"12"
String
"12"
0
=> nil
2.1.1 :009 > a_method
enter
12
String
12
12
=> nil
gets is short for get string, so if you enter 12 it turns it into "12". As Jiří Pospíšil pointed out, if you enter "12", it turns it into "\"12\"", which to_i is unable to understand.
Is it possible to write this excerpt of code without using an assignment?
self.name = self.name.to_s.squeeze(' ').strip
I have tried using bang versions of the methods, but couldn't use very well since they return nil if the operation didn't perform any changes (instead of returning self).
You'd have to tap the whole thing. So it would be something like:
str.tap {|x| x.squeeze!(' ')}.tap(&:strip!)
This is not something I would generally recommend doing. Even if you have a dire need for mutation, the best code clarity comes from using the methods the way they were designed:
str.squeeze!(' ')
str.strip!
If this is inconvenient, consider whether you really need the mutation.
If you really want to avoid assignment you could do this:
self.name = 'This is a test '
[['squeeze!', ' '], 'strip!'].each { |cmd| self.name.send(*cmd) }
self.name
# => "This is a test"
For a one-liner with no (Ruby) attributions and without tap:
a.name && (a.name.squeeze!(' ') || a.name).strip!
e.g.:
$ irb
2.1.1 :001 > class A
2.1.1 :002?> def name=(name)
2.1.1 :003?> puts "setting name=#{name.inspect}"
2.1.1 :004?> #name = name
2.1.1 :005?> end
2.1.1 :006?> attr_reader :name
2.1.1 :007?> end
=> nil
2.1.1 :008 > a = A.new
=> #<A:0x007fdc909d6df8>
2.1.1 :009 > a.name = ' and she was '
setting name=" and she was "
=> " and she was "
2.1.1 :010 > a.name && (a.name.squeeze!(' ') || a.name).strip!
=> "and she was"
2.1.1 :011 > a.name
=> "and she was"
2.1.1 :012 > a.name = 'and she was'
setting name="and she was"
=> "and she was"
2.1.1 :013 > a.name && (a.name.squeeze!(' ') || a.name).strip!
=> nil
2.1.1 :014 > a.name = 'and she was '
setting name="and she was "
=> "and she was "
2.1.1 :015 > a.name && (a.name.squeeze!(' ') || a.name).strip!
=> "and she was"
I have a ruby hash which looks like
{"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
But I can't manage to check if a certain string is already in the Hash. I tried has_value?, getting array of values using values then using include? to check if it contains it, but always returns false, when I know that it exists. For example, I try to add "172.16.10.252"=>"nick" to the hash and I do:
class SomeClass
def initialize(*args)
super(*args)
#nicks = Hash.new
end
def serve(io)
loop do
line = io.readline
ip = io.peeraddr[3]
begin
if /NICK (.*)/ =~ line
nick = $1
if #nicks.has_value?(nick) # it fails here
puts "New nick #{$1}"
#nicks[ip] = nick.gsub("\r", "")
io.puts "Your new nick is #{nick}"
else
message = {:ERROR => "100", :INFO=>"#{nick}"}.to_json
io.puts message
end
end
rescue Exception => e
puts "Exception! #{e}-#{e.backtrace}"
end
end
end
end
On irb it works fine, but on my script it doesn't
1.9.3p125 :001 > h = {"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
=> {"10.1.1.6"=>"nick", "127.0.0.1"=>"nick1"}
1.9.3p125 :002 > h.has_value?('nick')
=> true
1.9.3p125 :003 > if h.has_value?('nick')
1.9.3p125 :004?> puts "yes"
1.9.3p125 :005?> else
1.9.3p125 :006 > puts "no"
1.9.3p125 :007?> end
yes
=> nil
1.9.3p125 :008 >
What I'm doing wrong?
I'm not sure if you're using "$1" the way you intend to.
In your code at this line:
if /NICK (.*)/ =~ line
nick = $1
if #nicks.has_value?(nick) # it fails here
puts "New nick #{$1}"
if line is "NICK says a bunch of things", $1 will be "says a bunch of things". So you're not really looking for the value 'nick' in your hash, but for 'says a bunch of things'.
You should check how your regex is working, I wouldn't say anything is wrong with a hash.