Player = Struct.new(:reference, :name, :state, :items, :location)
# Setting game initials
game_condition = 0
player = Player.new(:player, "Amr Koritem", :alive, [:knife, :gun])
puts player.name
player.location = :jail5
class Dungeon
attr_accessor :player, :rooms, :prisoners, :gangsmen, :policemen
##counter = 0
def initialize(player)
#player = player
end
end
my_dungeon = Dungeon.new(player)
if my_dungeon.player.location.to_s.scan(/\D+/) == "jail"
puts "yes"
end
This code is supposed to print "yes" on the screen, but it doesn't. I changed the == sign to != and surprisingly it printed "yes" !
I thought may be I understood the regular expression wrong so I typed this code:
puts my_dungeon.player.location.to_s.scan(/\D+/)
It prints "jail" on the screen, which means I wasn't wrong, was I ?
Can anyone explain this please ?
As Wiktor's comment says, arrays are always truthy, and scan always returns an array, even if there are no matches. Instead you can use any of the following methods:
str = "jail5"
if str[/\D+/] # => nil or the match contents
if str.match /\D+/ # => nil or MatchData object
if str =~ /\D+/ # => nil or index of the match
unless str.scan(/\D+/).empty?
if str.scan(/\D+/).length > 0
In general when you come across surprising behavior like this you should do a bit of introspection - check what the result value is using print or a breakpoint.
Related
I need a function, is_an_integer, where
"12".is_an_integer? returns true.
"blah".is_an_integer? returns false.
How can I do this in Ruby? I would write a regex but I'm assuming there is a helper for this that I am not aware of.
Well, here's the easy way:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
I don't agree with the solutions that provoke an exception to convert the string - exceptions are not control flow, and you might as well do it the right way. That said, my solution above doesn't deal with non-base-10 integers. So here's the way to do with without resorting to exceptions:
class String
def integer?
[ # In descending order of likeliness:
/^[-+]?[1-9]([0-9]*)?$/, # decimal
/^0[0-7]+$/, # octal
/^0x[0-9A-Fa-f]+$/, # hexadecimal
/^0b[01]+$/ # binary
].each do |match_pattern|
return true if self =~ match_pattern
end
return false
end
end
You can use regular expressions. Here is the function with #janm's suggestions.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
An edited version according to comment from #wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
In case you only need to check positive numbers
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
You can use Integer(str) and see if it raises:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
It should be pointed out that while this does return true for "01", it does not for "09", simply because 09 would not be a valid integer literal. If that's not the behaviour you want, you can add 10 as a second argument to Integer, so the number is always interpreted as base 10.
Ruby 2.6.0 enables casting to an integer without raising an exception, and will return nil if the cast fails. And since nil mostly behaves like false in Ruby, you can easily check for an integer like so:
if Integer(my_var, exception: false)
# do something if my_var can be cast to an integer
end
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
You can do a one liner:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
or even
int = Integer(str) rescue false
Depending on what you are trying to do you can also directly use a begin end block with rescue clause:
begin
str = ...
i = Integer(str)
i.times do |j|
puts j
end
rescue ArgumentError
puts "Not an int, doing something else"
end
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
It isn't prefixed with is_. I find that silly on questionmark methods, I like "04".integer? a lot better than "foo".is_integer?.
It uses the sensible solution by sepp2k, which passes for "01" and such.
Object oriented, yay.
The Best and Simple way is using Float
val = Float "234" rescue nil
Float "234" rescue nil #=> 234.0
Float "abc" rescue nil #=> nil
Float "234abc" rescue nil #=> nil
Float nil rescue nil #=> nil
Float "" rescue nil #=> nil
Integer is also good but it will return 0 for Integer nil
I prefer:
config/initializers/string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
and then:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
or check phone number:
"+34 123 456 789 2".gsub(/ /, '').number?
A much simpler way could be
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
Personally I like the exception approach although I would make it a little more terse:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
However, as others have already stated, this doesn't work with Octal strings.
This might not be suitable for all cases simplely using:
"12".to_i => 12
"blah".to_i => 0
might also do for some.
If it's a number and not 0 it will return a number. If it returns 0 it's either a string or 0.
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
Here's my solution:
# /initializers/string.rb
class String
IntegerRegex = /^(\d)+$/
def integer?
!!self.match(IntegerRegex)
end
end
# any_model_or_controller.rb
'12345'.integer? # true
'asd34'.integer? # false
And here's how it works:
/^(\d)+$/is regex expression for finding digits in any string. You can test your regex expressions and results at http://rubular.com/.
We save it in a constant IntegerRegex to avoid unnecessary memory allocation everytime we use it in the method.
integer? is an interrogative method which should return true or false.
match is a method on string which matches the occurrences as per the given regex expression in argument and return the matched values or nil.
!! converts the result of match method into equivalent boolean.
And declaring the method in existing String class is monkey patching, which doesn't change anything in existing String functionalities, but just adds another method named integer? on any String object.
Ruby 2.4 has Regexp#match?: (with a ?)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
For older Ruby versions, there's Regexp#===. And although direct use of the case equality operator should generally be avoided, it looks very clean here:
def integer?(str)
/\A[+-]?\d+\z/ === str
end
integer? "123" # true
integer? "-123" # true
integer? "+123" # true
integer? "a123" # false
integer? "123b" # false
integer? "1\n2" # false
Expanding on #rado's answer above one could also use a ternary statement to force the return of true or false booleans without the use of double bangs. Granted, the double logical negation version is more terse, but probably harder to read for newcomers (like me).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
For more generalised cases (including numbers with decimal point),
you can try the following method:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
You can test this method in an irb session:
(irb)
>> number?(7)
=> #<MatchData "7" 1:nil>
>> !!number?(7)
=> true
>> number?(-Math::PI)
=> #<MatchData "-3.141592653589793" 1:".141592653589793">
>> !!number?(-Math::PI)
=> true
>> number?('hello world')
=> nil
>> !!number?('hello world')
=> false
For a detailed explanation of the regex involved here, check out this blog article :)
One liner in string.rb
def is_integer?; true if Integer(self) rescue false end
I'm not sure if this was around when this question is asked but
for anyone that stumbles across this post, the simplest way is:
var = "12"
var.is_a?(Integer) # returns false
var.is_a?(String) # returns true
var = 12
var.is_a?(Integer) # returns true
var.is_a?(String) # returns false
.is_a? will work with any object.
I created a method to count a substring 'e' in a string passed as an argument. If there isn't a substring 'e' in the string, it should return "There is no \"e\"." I am trying to achieve this:
How many times 'e' is in a string.
If given string doesn't contain any "e", return "There is no "e"."
if given string is empty, return empty string.
if given string is nil, return nil.
This is my code:
def find_e(s)
if !s.include?("e")
"There is no \"e\"."
elsif s.empty?
""
else s.nil?
nil
end
s.count("e").to_s
end
find_e("Bnjamin")
It skips the if statement and it still uses the method count. Why is this?
To achieve what you want you could move your string.count to the else statement in your if, because actually you're making your method return the quantity of e passed in the count method over your string, but what happens inside the if isn't being used:
def find_e(s)
if s.nil?
nil
elsif s.empty?
''
elsif !s.include?("e")
"There is no \"e\"."
else
s.count("e").to_s
end
end
p find_e("Bnjamin") # => "There is no \"e\"."
p find_e("Benjamin") # => "1"
p find_e(nil) # => nil
p find_e('') # => ""
And also your validations must be in order, first check nil values, then empty values, and then the rest, if you don't then you'll get some undefined method ___ for nil:NilClass errors.
You might have a hard time using the method you wrote. In the next method, you'll need a new case statement to test if find_e returned nil, an empty string, a string with a number or "no e".
This method would be a bit more consistent:
def count_e(string_or_nil)
count = string_or_nil.to_s.count("e")
if count == 0
"There is no \"e\"."
else
count
end
end
puts count_e("Covfefe")
# 2
puts count_e("Bnjamin")
# There is no "e".
puts count_e("")
# There is no "e".
puts count_e(nil)
# There is no "e".
But really, if there's no e in the input, just returning 0 would be the most logical behaviour.
You need to put your count method in a branch of the if/else statement, or else it will be evaluated last every time. Without an explicit return statement Ruby will return the last statement, so putting the method outside the if/else branch on the last line guarantees it will always be hit. Also, nil can be converted to an empty string by calling #to_s, so you can remove one of your branches by converting s.to_s, calling empty? and returning s
def find_e(s)
if s.to_s.empty?
s
elsif !s.include?("e")
"There is no \"e\"."
else
s.count("e").to_s
end
end
If you just return 0 whether you get nil, an empty string, or a string without e, you can make it one line
def find_e(s)
s.to_s.count("e").to_s
end
If it were me I'd probably return an Integer, which can always be converted to a String later. puts and "#{}" will implicitly call to_s for you anway. Then you can use that integer return in your presentation logic.
def count_e(input)
input.to_s.count("e")
end
def check_for_e(input)
count = count_e(input)
count > 0 ? count.to_s : "There's no \"e\"."
end
check_for_e("Covfefe") # => "2"
check_for_e("Bnjamin") # => "There's no \"e\"."
check_for_e(nil) # => "There's no \"e\"."
check_for_e("") # => "There's no \"e\"."
In Ruby, methods return the last statement in their body. Your method's last statement is always s.count("e").to_s, since that lies outside of the if statements.
I need to write a ruby method that reverses a string only if it has less than four characters.
# Write a method that reverses
# a string ONLY if it's shorter than
# 4 letters.
# Otherwise, the string is
# returned as-is.
# (Hint: strings have
# a built-in .length method!)
# conditional_reverse("yo")
# => "oy"
# conditional_reverse("hello")
# => "hello"
Here is the code I came up with.
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
puts conditional_reverse("cat")
end
When I run it in repl I get the following response
:conditional_reverse
I have no idea what i'm doing wrong.
just put puts conditional_reverse("cat") out side our def
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
end
conditional_reverse("cat")
You are callind your method in its definition. Avoid it if you are not writing a recursive method.
def conditional_reverse(s)
s.length < 4 ? s.reverse : s
end
The answer provided by #Ursus is perfect, but in case you want to go with your way the change you have to do is this;
def conditional_reverse(string)
good = string.length
if good < 4
puts string.reverse
else
puts string
end
end
puts conditional_reverse("cat")
What the others said, plus...
You get that response from irb because in recent versions of Ruby, a method definition returns the method name as a symbol.
Also, your problem specifies that the string should be reversed, not that the string should be output reversed; so you should remove the puts calls and just manipulate the string.
For the benefit of your readers, I recommend being specific with your names. good = string.length could be changed to needs_reversing = string.length < 4, for example.
What's the best way to check if a variable is not blank in an else if condition in Ruby (not Rails)?
elsif not variable.to_s.empty?
# do something
end
or
elsif !variable.to_s.empty?
# do something
end
or
elsif variable.to_s.length > 0
# do something
end
string = ""
unless string.to_s.strip.empty?
# ...
end
I just found out that ''.empty? returns true but ' '.empty? returns false. Even to_s.length for ' ' is not zero.
Maybe it is better to use strip as ' '.strip.empty?
You can use either
unless var.empty?
#do sth
end
or
unless var == ""
#do sth
end
or all of these with if and a negator !.
The source of the empty? method is analogous to the following:
def empty?
return length == 0
end
So, you can safely use
any_string.length != 0
Anyway, using that code inside an else if is a bit verbose, I would encourage you to define the present? method inside the String class.
class String
def present?
!empty?
end
end
Now you can write your code the following way:
if some_condition
# do something
elsif variable.to_s.present?
# do something else
end
This way you get a clear code, without using negations or unless who are hard to read.
Of course, there is one problem here, I took the present? name (and method) from Rails. present? returns true if the object is not blank, but strings with tabs or spaces (white characters) are considered blanks. So, this present? will return true to for the following strings:
"".present? # => false
" ".present? # => true
"\t\n\r".present? # => true
" blah ".present? # => true
It depends on what you want, high chances are that you want to get true for the first 3 strings, and false for the later. You could use #RamanSM approach and use strip to avoid empty spaces
class String
def present?
!strip.empty?
end
end
now, present? returns false for strings with white spaces
"".present? # => false
" ".present? # => false
"\t\n\r".present? # => false
" blah ".present? # => true
Note: Consider that String.present? is present in the ActiveSupport library (which ships with rails) if you add ActiveSupport or use Rails you should use ActiveSupport implementation instead.
If you prefer if to unless...
If you know your variable will be a String...if str[0]
With nil check...if str && str[0] OR if str&.[](0) (I prefer the latter but it might look odd to some people and requires Ruby >= 2.3).
Also...I'd be very careful about calling #to_s on anything because you could end up with unexpected results. If str turns out to be something that you weren't expecting...
str = false
str.to_s[0] # => 'f' (i.e. truthy)
str.to_s.empty? # => false
str = nil
str.to_s[0] # => nil (i.e. falsey)
str.to_s.empty? # => true
I think this caution applies to usage of #to_s in the other answer here as well. Exceptions can be your friend.
For the string (say abc) which is not defined/undefined we should check for abc.nil?
otherwise abc.blank? will throw (NoMethodError) undefined method empty? for nil:NilClass error
I am trying to write fast and concise code. I'd appreciate your thoughts on which is the best way to write the following code and why:
Option #1
def get_title
title = check_in_place_one
if title.empty?
title = check_in_place_two
if title.empty?
title = check_in_place_three
end
end
return title
end
Option #2
def get_title
title = check_in_place_one
title = check_in_place_two unless !title.empty?
title = check_in_place_three unless !title.empty?
return title
end
I think Option #1 is better since if the title is found by check_in_place_one, we test title.empty? once and then skip the rest of the code in the method and return. But, it looks too long. Option #2 appears better, but processes title.empty? one extra time, and unnecessary time before returning. Also, am I missing a third option?
From performance, there is no difference between the two versions of your code (besides very minor difference that may come from parsing, which should be ignorable). The control structures are the same.
From readability, if you can get away with nesting, doing so is better. Your second option is better.
It is usually better to get rid of any case that does not need further processing. That is done by return.
def get_title
title = check_in_place_one
return title unless title.empty?
title = check_in_place_two
return title unless title.empty?
title = check_in_place_three
return title
end
The last title = and return in the code above are redundant, but I put them there for consistency, which improves readability.
You can further compact the code using tap like this:
def get_title
check_in_place_one.tap{|s| return s unless s.empty?}
check_in_place_two.tap{|s| return s unless s.empty?}
check_in_place_three
end
tap is a pretty much fast method, and unlike instance_eval, its performance penalty is usually ignorable.
The following approach could be used for any number of sequential tests. Moreover, it is completely general. The return condition could be changed, arguments could easily be assigned to the test methods, etc.
tests = %w[check_in_place_one check_in_place_two check_in_place_three]
def do_tests(tests)
title = nil # Define title outside block
tests.each do |t|
title = send(t)
break unless title.empty?
end
title
end
Let's try it:
def check_in_place_one
puts "check 1"
[]
end
def check_in_place_two
puts "check 2"
''
end
def check_in_place_three
puts "check 3"
[3]
end
do_tests(tests) #=> [3]
check 1
check 2
check 3
#=> [3]
Now change one of the tests:
def check_in_place_two
puts "check 2"
'cat'
end
do_tests(tests) #=> 'cat'
check 1
check 2
#=> "cat"
If there were more tests, it might be convenient to put them in a module which would be included into a class. Mixed-in methods behave the same as those that you define for the class. For example, they have access to instance variables. I will demonstrate that with the definition of the first test method. We probably want to make the test methods private. We could do it like this:
module TestMethods
private
def check_in_place_one
puts "#pet => #{#pet}"
puts "check 1"
[]
end
def check_in_place_two
puts "check 2"
''
end
def check_in_place_three
puts "check 3"
[3]
end
end
class MyClass
##tests = TestMethods.private_instance_methods(false)
puts "##tests = #{##tests}"
def initialize
#pet = 'dog'
end
def do_tests
title = nil # Define title outside block
##tests.each do |t|
title = send(t)
break unless title.empty?
end
title
end
include TestMethods
end
The following is displayed when the code is parsed:
##tests = [:check_in_place_one, :check_in_place_two, :check_in_place_three]
Now we perform the tests:
MyClass.new.do_tests #=> [3]
#pet => dog
check 1
check 2
check 3
Confirm the test methods are private:
MyClass.new.check_in_place_one
#=> private method 'check_in_place_one' called for...'
The advantage of using a module is that you can add, delete, rearrange and rename the test methods without making any changes to the class.
Well, here's a few other alternatives.
Option 1: Return first non-empty check.
def get_title
return check_in_place_one unless check_in_place_one.empty?
return check_in_place_two unless check_in_place_two.empty?
return check_in_place_three
end
Option 2: Helper method with short-circuit evaluation.
def get_title
check_place("one") || check_place("two") || check_place("three")
end
private
def check_place(place)
result = send("check_in_place_#{place}")
result.empty? ? nil : result
end
Option 3: Check all places then find the first that's non-empty.
def get_title
[
check_in_place_one,
check_in_place_two,
check_in_place_three,
].find{|x| !x.empty? }
end
Option 2 looks good although you did a 360 degree turn with the unless !title.empty?. You can shorten that to if title.empty? since unless is equivalent to an if ! so doing an unless ! takes you back to just if.
If you're only ever going to have 3 places to look in then option 2 is the best. It's short, concise, and easy to read (easier once you fix the aforementioned whoopsie). If you might add on to the places you look for a title in you can get a bit more dynamic:
def get_title(num_places = 4)
title, cur_place = nil, 0
title = check_in_place(cur_place += 1) while title.nil? && cur_place < num_places
end
def check_in_place(place_num)
# some code to check in the place # given by place_num
end
The tricky line is that one with the while in it. What's happening is that the while will check the expression title.nil? && cur_place < num_places and return true because the title is still nil and 0 is less than 4.
Then we'll call the check_in_place method and pass in a value of 1 because the cur_place += 1 expression will increment its value to 1 and then return it, giving it to the method (assuming we want to start checking in place 1, of course).
This will repeat until either check_in_place returns a non nil value, or we run out of places to check.
Now the get_title method is shorter and will automatically support checking in num_places places given that your check_in_place method can also look in more places.
One more thing, you might like to give https://codereview.stackexchange.com/ a look, this question seems like it'd be a good fit for it.
I don't think there's any reason to get too clever:
def get_title
check_in_place_one || check_in_place_two || check_in_place_three
end
Edit: if the check_in_place_X methods are indeed returning an empty string on failure it would be better (and more idiomatic) to have them instead return nil. Not only does it allow for truthy comparisons like the above code, return "" results in the construction of a new and unnecessary String object.