How to simplify CustomKeywords calls? - methods

There is a way to simplified CustomKeywords calls into Test case?
Indeed, use CustomKeywords.'package.class.method'(param1, param2) everytime is not ideal.
So I'm looking to find a way to do something like :
line 1 : CustomKeywords.package.class as EasyCall
line W : ...
line X : def result = EasyCall.method(param1, param2)
line Y : ...
line Z : def result2 = EasyCall.method(param1, param2)
instead of
line W : ...
line X : def result = CustomKeywords.'package.class.method'(param1, param2)
line Y : ...
line Z : def result2 = CustomKeywords.'package.class.method'(param1, param2)
Does someone have any idea?

"Custom Keyword" in Katalon is just a plain old method. So, everything you might do in Groovy or Java applies here as well.
So, to simplify method calls, you need to import
import package.class as EasyCall
and your method inside of the package needs to be static:
package package
#Keyword
def static method1(param1, param2){
// body of method1
}
Then you simply call the method within your test script with:
EasyCall.method1(param1, param2)

Related

How to store a value in a conditional statement and call it in ruby

Method
def myname(generate_name)
if generate_name
name = SecureRandom.urlsafe_base64(6)
name //ex:abcdef
Call
myname(true) //output abcdef
myname(false) //expected output abcdef
In my code, I have to use myname(true) to generate unique name every time the function is referred.
Question: I need the value "abcdef" to be the output when I call myname(false)
I would do something like this:
def myname(re_generate = false)
#_myname = SecureRandom.urlsafe_base64(6) if #name.nil? || re_generate
#_myname
end
Store this value as an instance variable:
def myname(generate_name)
return #name unless generate_name
#name = SecureRandom.urlsafe_base64(6)
end
Try the method like below -
def myname(generate_name)
return SecureRandom.urlsafe_base64(6) if generate_name
'abcdef'
end

Cannot call a method using a shortcut

I have a module that defines a method to log some output in an html file. The module looks like this:
module Htmllog
#htmllogfile = "htmllog/myproject" + Time.now.strftime('%Y%m%d-%H%M%S') + '.html'
def self.add(text, tag)
if tag.length == 0
formattedlog = text
else
formattedlog = "<#{tag}>#{text}</#{tag}>"
puts text
end
File.open(#htmllogfile, "a") do |f|
f.puts formattedlog
end
end
end
I call it in my main.rb file and it works just fine if I call it like this:
Htmllog.add "Hello world!", "h1"
Since I have to log a lot of stuff, I want to add a shortcut to reduce the number of digits and I tried this:
l = Htmllog.add
l "Hello world!", "h1"
But I get this error.
`add': wrong number of arguments (0 for 2) (ArgumentError)
Can't figure out what's wrong.
Do as below using Object#method and Method#call:
l = Htmllog.method(:add)
l.call("Hello world!", "h1")
l.("Hello world!", "h1") # which is same l.call("Hello world!", "h1")
l = Htmllog.add is not valid as per the your method definition of add. So you got error.
If you want l to be available globally, then you should define that as a method on Kernel.
module Kernel
def l *args; Htmllog.add(*args) end
end
l "Hello world!", "h1"
Be careful not to have a conflict with existing methods.
1 When ruby sees l = Htmllog.add , it will first run Htmllog.add with no argument, and then give the result to variable l. That's why you have this error.
2 One way you can do it is to use an anonymous function :
l = ->(text, tag) { Htmllog.add(text, tag) }

method= with multiple parameters

if I have a method with the equal sign at the end:
class A
def property= name, value
...
end
end
how do I invoke the method property= and pass arguments to it?
Ruby already has a special setter syntax for key-value pairs. You can see it in use with Hash:
phone_numbers = { Bob: "555-555-1234", Francine: "555-555-5678"}
phone_numbers[:Jenny] = "555-867-5309"
To get this syntax for your own class, you just do
def []=(key, value)
# set the value however you like
end
here is what I ended up with (thanks to #LeeJarvis for his/her comment):
class A
def property= value
x, y = value
p [x, y]
end
end
A.new.property = 1, 2

Recursion in yield

So i am trying to do something like this:
def func(x,y)
if x.length == 1 then
n = x.pop()
yield(n,y)
else
n = x.pop()
yield(n,func(x,y))
end
end
calling it like:
a = func([1,2,3,4,5],0) do |x,y|
x+y
end
Is it possible to do something like this? I keep getting no block given (yield) (LocalJumpError).
I even tried doing something a little different:
def func(x,y)
func(x,y) do |tail|
..
end
end
but no luck
Thanks.
Yes, you can take the block as an argument explicitly:
def func(x, y, &block)
You can still yield to it with the yield keyword, but you can also pass it as you recurse:
yield(n, func(x, y, &block))
The & in both cases means that the block argument is not a normal argument, but represents the block that can be attached to any Ruby method call.
You are missing to pass the block in the recursive call.
The recursive call should be like as below:-
yield(n,func(x,y)) { |x,y| x+y})
Since you missed to pass the block in the recursive call, when the code hits:-
if x.length == 1 then
n = x.pop()
yield(n,y) <<<< Here
the method func doesn't have block passed as argument,in the recursive call, but ruby tries to call a non-existent block and hence the error.

Passing a method as a parameter in Ruby

I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
I have here the method
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
ArgumentError: wrong number of arguments (0 for 1)
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method to get the method and .call to call it:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
You want a proc object:
gaussian = Proc.new do |dist, *args|
sigma = args.first || 10.0
...
end
def weightedknn(data, vec1, k = 5, weightf = gaussian)
...
weight = weightf.call(dist)
...
end
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send with object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
def weightedknn(data, vec1, k = 5)
...
weight =
if block_given?
yield(dist)
else
gaussian.call(dist)
end
end
...
end
weightedknn(foo, bar) do |dist|
# square the dist
dist * dist
end
But it sounds like you would like more reusable chunks of code here.
You can pass a method as parameter with method(:function) way. Below is a very simple example:
def double(a)
return a * 2
end
=> nil
def method_with_function_as_param( callback, number)
callback.call(number)
end
=> nil
method_with_function_as_param( method(:double) , 10 )
=> 20
The normal Ruby way to do this is to use a block.
So it would be something like:
def weightedknn(data, vec1, k = 5)
foo
weight = yield(dist)
foo
end
And used like:
weightedknn(data, vec1) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
You can use the & operator on the Method instance of your method to convert the method to a block.
Example:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
You have to call the method "call" of the function object:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
# Returns a valid hash for html form select element, combined of all entities
# for the given +model+, where only id and name attributes are taken as
# values and keys correspondingly. Provide block returning boolean if you
# need to select only specific entities.
#
# * *Args* :
# - +model+ -> ORM interface for specific entities'
# - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
# * *Returns* :
# - hash of {entity.id => entity.name}
#
def make_select_list( model, &cond )
cond ||= proc { true } # cond defaults to proc { true }
# Entities filtered by cond, followed by filtration by (id, name)
model.all.map do |x|
cond.( x ) ? { x.id => x.name } : {}
end.reduce Hash.new do |memo, e| memo.merge( e ) end
end
Afterwerds, you can call this function like this:
#contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == #current_user
end
If you don't need to filter your selection, you simply omit the block:
#categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Similarly to a Proc or a method call, you can also pass a lambda as weightf parameter :
def main
gaussian = -> (params) {
...
}
weightedknn(data, vec1, k = 5, gaussian, params)
# Use symbol :gaussian if method exists instead
end
def weightedknn(data, vec1, k = 5, weightf, params)
...
weight = weightf.call(params)
...
end
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.

Resources