Check if method's parameter was set by user - ruby

Is there a way to check if the parameter of the method was set by the default value set in the method itself or by the user who called the method?
Here's what I want to do in my method, for example
def json_prop(key, value = nil)
json_data = {} if json_data.nil?
return json_data[key] if value.set_by_user? # i.e. User did not set value to nil himself
json_data[key] = value # Set to the value inserted by the user when calling the method
end

There is a standard trick to do this, and it relies on two features of the Ruby programming language:
The default argument value for an optional parameter is a Ruby expression and thus can contain any arbitrary Ruby code and
Local variables defined in the default argument value expression are in scope in the method's body.
Therefore, all we need to do is set a variable in the default argument value expression, and we know: if the variable is set, the default argument value expression was evaluated and thus no argument value was passed:
def json_prop(key, value = (no_value_set_by_user = true; nil))
json_data = {} if json_data.nil?
return json_data[key] if no_value_set_by_user
json_data[key] = value
end
or
def json_prop(key, value = (
no_value_set_by_user = true
nil
))
json_data = {} if json_data.nil?
return json_data[key] if no_value_set_by_user
json_data[key] = value
end

Related

how return true or false in a method in ruby?

I need to find a key in a hash then return true if this key already exist or false if doesn't exist but for some reason I have an error in the terminal.
this is my method:
def key_no_exist (hash,key)
hash.each do |clave,valor|
if clave == key
return false
end
end
return true
end
and after I use that return in this code:
when "set"
key = sep[1] #string who contain my key
client.puts "SEND DATABLOCK: "
resp = client.gets.chomp
datablock = resp.scan(/\w+/)
if key_no_exist(data,key) #if the key doesn't exist, add the data block into the hash
data[:key] = datablock
client.puts"STORED: \r\n "
else
client.puts "CLIENT_ERROR [key already exists]\r\n"
end
by after all when I running the code in the terminal I this problem:
:22: warning: assigned but unused variable - data
:75: warning: parentheses after method name is interpreted as an argument list, not a decomposed argument
in block (2 levels) in run':undefined local variable or method data' for #Server:0x00007fdd0695d8d8 (NameError)
firstable I create a hash named data:
class Server
def initialize(port,ip)
#server = TCPServer.open(ip,port)
#connections = Hash.new
#clients = Hash.new
#connections[:server] = #server
#connections[:clients] = #clients
data = Hash.new
run
end
I think you are confusing the method declaration syntax and method calling syntax. Your method declaration def key_no_exist(data,key) is fine, this method expects two arguments, the first is the hash, the second is the key. When you then call this method, you need to pass in the actual hash, and the actual key you are checking. I am not sure which of your variables (client or resp or something else) is the hash, but say its called your_hash, you will call this method likeif key_no_exist(your_hash, key).
The error you are getting undefined local variable or method data is saying there is no variable called data, ie there is no data = something.
As for the actual method you are using, ruby comes with a hash method .has_key? which returns true if the key is there, else returns false. So instead of writing your own method, you could just do something like if your_hash.has_key?(key).

Ruby method call, element.send(), throws ArgumentError

When I run this Ruby code I get an ArgumentError: wrong number of arguments calling ``method`` (0 for 1).
def method(element)
return element + 2
end
array = Array.[](1,2,3,4,5)
def map(array, method)
result_array = []
array.each do |element|
# Call the method on the object
value = element.send(method)
# Add to array
result_array.push(value)
end
return result_array
end
map(array, :method)
Calling the method this way works.
value = method(element)
What is wrong with the element.send(method) syntax?
With send you need to pass a method argument value = send(method, element). To call it on element is unnecessary. By the way, Ruby already has a method called method it is better to not override it. Rename it to something more meaningful like add_two.
Calling the method this way works.
value = method(element)
What is wrong with the element.send(method) syntax?
In your example, element is an integer, and method is a symbol, e.g. 1 and :method.
So value = method(element) is equivalent to:
value = method(1)
whereas value = element.send(method) is equivalent to:
value = 1.send(:method)
which is basically:
value = 1.method
It should be obvious that method(1) and 1.method is not the same.

How to chain a method call to a `do ... end` block in Ruby?

I'm doing the following:
array_variable = collection.map do |param|
some value with param
end
return array_variable.compact
Can I call map and compact in one statement somehow, so I can return the result instantly?
I'm thinking on something like this (it may be invalid, however):
array_variable = block_code param.compact
# block_code here is a method for example which fills the array
yes, you can call a method here.
In your case,
array_variable = collection.map do |param|
# some value with param
end.compact
OR
array_variable = collection.map{ |param| some value with param }.compact
As pointed out by #Stefan, assignment is not required, you can directly use return and if that's the last line of method you can omit return too..

Optional argument syntax

I found this code under this question, which checks if any argument is passed to a method:
def foo(bar = (bar_set = true; :baz))
if bar_set
# optional argument was supplied
end
end
What is the purpose of the ; :baz in this default value, and in what case would I use it?
The idea is that = (bar_set = true; :baz) will be evaluated only if a value is not passed to the bar parameter.
In Ruby, the return value of multiple consecutive expressions is the value of the last expression. Hence = (bar_set = true; :baz) assigns the value true to bar_set, and then sets :baz as the value for bar (because the code in the parentheses will evaluate to :baz, it being the last expression).
If a parameter was passed, bar_set will be nil and the value of bar would be whatever was given.

Ruby block's result as an argument

There are many examples how to pass Ruby block as an argument, but these solutions pass the block itself.
I need a solution that takes some variable, executes an inline code block passing this variable as a parameter for the block, and the return value as an argument to the calling method. Something like:
a = 555
b = a.some_method { |value|
#Do some stuff with value
return result
}
or
a = 555
b = some_method(a) { |value|
#Do some stuff with value
return result
}
I could imagine a custom function:
class Object
def some_method(&block)
block.call(self)
end
end
or
def some_method(arg, &block)
block.call(arg)
end
but are there standard means present?
I think, you are looking for instance_eval.
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables. In the version of instance_eval that takes a String, the optional second and third parameters supply a filename and starting line number that are used when reporting compilation errors.
a = 55
a.instance_eval do |obj|
# some operation on the object and stored it to the
# variable and then returned it back
result = obj / 5 # last stament, and value of this expression will be
# returned which is 11
end # => 11
This is exactly how #Arup Rakshit commented. Use tap
def compute(x)
x + 1
end
compute(3).tap do |val|
logger.info(val)
end # => 4

Resources