test if two strings are different in rake file - ruby

In a rake task, I want to execute a commande conditionally, but the string comparison does not work as expected. Here is what I have in my rake task:
puts "compare ('#{fetch(:stage)}' != 'production')"
if fetch(:stage) != 'production' then
puts 'they are different'
end
I expect that puts 'they are different' is skipped, since the two strings are equal. But the statement is executed nonetheless, as the output proves:
compare ('production' != 'production')
they are different
I guess this is because the first is a variable of type sting while the second is a constant ? Obviously string comparisons work differently in ruby. What is the 'ruby way' to do it ?

Related

Can `nil` be matched on a `case/when` statement, with an explicit `when nil` branch?

I have a Ruby case/when statement, which takes different options for a parameter.
There are three valid cases: symbols, integers, and nil; anything else is invalid.
In the most obvious form, there are four cases:
case param
when Symbol
run_symbol_code
when Integer
run_integer_code
when nil
# do nothing
else
raise_error
end
now, I was wondering: is there any way to avoid the nil case? Originally I thought about:
case param
when Symbol
run_symbol_code
when Integer
run_integer_code
when Object
raise_error
end
however, this doesn't work, because nil is actually an object. There's also the option to use raise_error if param in the last case, but I don't find it very appealing.
Is there any way to use only three cases?
In cases like this in which nil results in do nothing I would prefer a Guard Clause because it is easy to read and understand.
def method(param)
return if param.nil?
case param
when Symbol
run_symbol_code
when Integer
run_integer_code
else
raise_error
end
end
Of course, it doesn't reduce the number of checks.
In ruby you can add condition at the end of case, iterators statements.
like following
case param
when Symbol
run_symbol_code
when Integer
run_integer_code
else
raise_error
end unless param.nil?
Note:- end unless param.nil? in such cases 'case', iterator will run only when condition permits i.e Case will run only when param is not nil.

Ruby Conditionals/Case Expression

I'm fairly new to code and I have a quick question on Ruby conditionals, specifically Case Expressions. I have a method in which I want to return a string "odd" if the string length is odd and "even" if the string length is even.
Simple stuff I know and I can get the results using a if/else conditional, however the case expression just returns 'nil'. Any help would be greatly appreciated.
def odd_or_even(string)
case string
when string.length.even? then "even"
when string.length.odd? then "odd"
end
end
odd_or_even("Ruby") # Wanting to return even rather than nil
odd_or_even("Rails") # Wanting to return odd rather than nil
You've written your case statement wrong. It takes two forms, which is unusual compared to other languages. The first form takes an argument, and that argument is compared to all possible cases. The second form is without argument and each case is evaluated independently.
The most minimal fix is this:
def odd_or_even(string)
case
when string.length.even? then "even"
when string.length.odd? then "odd"
end
end
This was because to Ruby your code looked like this when calling with the argument "Ruby":
def odd_or_even(string)
case string
when true then "even"
when false then "odd"
end
end
Your string value does not match true or false so you get nil from a non-matching situation.
You can clean up your code considerably. Consider: Can something be not even and not odd? Not really:
def odd_or_even(string)
string.length.even? ? 'even' : 'odd'
end
case something
when condition1
expression1
when condition2
expression2
else
default_expression
end
is equivalent to
if condition1 === something
expression1
elsif condition2 === something
expression2
else
default_expression
end
Note that case-when internally uses ===, an operator (method) which can be overridden.

Ruby's && logic behaving inconsistently when RSpec tested

I have a method that includes (among subsequent lines) the following code:
candidate_lines.each do |line|
return line if priority_1?(line) && line.marked_by?(self)
end
The methods in it, as far as I can tell, are irrelevant. What's driving me up the wall, is I have a test that should be skipping that part of the method simply by the specification I've given:
it "without any priority 1 lines, returns all priority 2 lines marked by itself" do
line1 = double :line, marked_by?: true
line2 = double :line, marked_by?: true
allow(joshua).to receive(:priority_1?).and_return(:false)
expect(joshua).to receive(:candidate_lines).and_return([line1, line2])
expect(joshua.tiebreak_lines).to eq [line1, line2]
end
Yet when I run the test, the return statement is getting triggered. I've tested it manually with puts statements immediately before the 'return line...' line, and it turns out that, while 'priority_1?(line)' returns false, for some reason 'priority_1?(line) && line.marked_by?(self)' is evaluating to true.
What's happening here?
You're confusing the symbol :false with the boolean value false
Because :false is neither false nor nil, it is truthy, that is as far as things like && or if are concerned, it is true.

Ruby if statement multiline condition syntax?

Hi all new to ruby is this if statement valid syntax?
if (verify_login_id = Login.where(params[:email_address], "active" =>1).select('id')# => [#<Login id: 767>]
verify_admin_id = Admin.where("login_id" => verify_login_id.first.id).exists? #=> true)
puts "trueee"
else
raise(ActiveRecord::RecordNotFound.new("Authorization is required to access this endpoint!"))
end
Although setting variable values within an if statement is syntactically valid, it is very problematic.
It can be mistakenly read as a comparison rather than assignment, and in many cases it is a result of someone trying to make a comparison and confusing the equals predicate == with the assignment operator =. That's why a lot of IDEs today mark such code as a warning and a probable error.
In your code it also seems quite unneeded... Break it into two more readable lines:
verified_login = Login.where(params[:email_address], "active" =>1).select('id').first # => [#<Login id: 767>]
if verified_login && Admin.where("login_id" => verified_login.id).exists? #=> true
puts "trueee"
else
raise(ActiveRecord::RecordNotFound.new("Authorization is required to access this endpoint!"))
end
Some more observations - your assignment to verify_login_id is not an id, but a Login object, and your assignment to verify_admin_id is not an id either - but a boolean (and you are not using it anyway). This might seem besides the point - but it adds up to an unreadable and an unmaintainable code.
No it is not a valid code. In the second line, it contains an invalid #-comment that has removed a single ) from the code. (exact snip is #=>true) and should be ) #=>true)
I've removed the comments from the code, added the missing parenthesis and the parser seems to accept it. I couldn't run it of course. So, try this one, it might work:
if (verify_login_id = Login.where(params[:email_address], "active" =>1).select('id')
verify_admin_id = Admin.where("login_id" => verify_login_id.first.id).exists?)
puts "trueee"
else
raise(ActiveRecord::RecordNotFound.new("Authorization is required to access this endpoint!"))
end
Regarding multiline condition in the if - yes, it is possible. Sometimes directly, sometimes with a small trick. Try this:
if (1+2 >=
3)
puts "as"
end
It works (at least on Ruby 1.9.3). However, this will not:
if (1+2
>=
3)
puts "as"
end
This is because of some internal specific of how Ruby interpreter/compiler is designed. In the last example, to make it work, you need to inform Ruby that the line has not ended. The following example works:
if (1+2 \
>=
3)
puts "as"
end
Note the \ added at the end of problematic line

How do I execute Rake tasks with arguments multiple times?

It's not possible to invoke the same rake task from within a loop more than once. But, I want to be able to call rake first and loop through an array and invoke second on each iteration with different arguments. Since invoke only gets executed the first time around, I tried to use execute, but Rake::Task#execute doesn't use the splat (*) operator and only takes a single argument.
desc "first task"
task :first do
other_arg = "bar"
[1,2,3,4].each_with_index do |n,i|
if i == 0
Rake::Task["foo:second"].invoke(n,other_arg)
else
# this doesn't work
Rake::Task["foo:second"].execute(n,other_arg)
end
end
end
task :second, [:first_arg, :second_arg] => :prerequisite_task do |t,args|
puts args[:first_arg]
puts args[:second_arg]
# ...
end
One hack around it is to put the arguments to execute into an array and in second examine the structure of args, but that seems, well, hackish. Is there another (better?) way to accomplish what I'd like to do?
You can use Rake::Task#reenable to allow it to be invoked again.
desc "first task"
task :first do
other_arg = "bar"
[1,2,3,4].each_with_index do |n,i|
if i == 0
Rake::Task["second"].invoke(n,other_arg)
else
# this does work
Rake::Task["second"].reenable
Rake::Task["second"].invoke(n,other_arg)
end
end
end
task :second, [:first_arg, :second_arg] do |t,args|
puts args[:first_arg]
puts args[:second_arg]
# ...
end
$ rake first
1
bar
2
bar
3
bar
4
bar
The execute function asks for a Rake::TaskArguments as a parameter, this is why it only accepts one argument.
You could use
stuff_args = {:match => "HELLO", :freq => '100' }
Rake::Task["stuff:sample"].execute(Rake::TaskArguments.new(stuff_args.keys, stuff_args.values))
However there is another difference between invoke and execute, execute doesn't run the :prerequisite_task when invoke does this first, so invoke and reenable or execute doesn't have exactly the same meaning.
FWIW this might help someone so I'll post it.
I wanted to be able to run one command from the CLI to run one Rake task multiple times (each time with new arguments, but that's not important).
Example:
rake my_task[x] my_task[y] my_task[z]
However, since Rake sees all my_task as the same task regardless of the args, it will only invoke the first time my_task[x] and will not invoke my_task[y] and my_task[z].
Using the Rake::Task#reenable method as mentioned in the other answers, I wrote a reenable Rake task which you can position to run after a task to allow it to run again.
Result:
rake my_task[x] reenable[my_task] my_task[y] reenable[my_task] my_task[z]
I wouldn't say this is ideal but it works for my case.
reenable Rake task source:
task :reenable, [:taskname] do |_task, args|
Rake::Task[args[:taskname]].reenable
Rake::Task[:reenable].reenable
end
This worked for me, it's quite easy to understand you just need to loop you bash command.
task :taskname, [:loop] do |t, args|
$i = 0
$num = args.loop.to_i
while $i < $num do
sh 'your bash command''
$i +=1
end
end

Resources