Ruby interpreted variables is_a? - ruby

I am looking to check a variabe for its type based on the value held in another variable but am struggling with it. I'm completely new to ruby but can anyone tell me how to have the value of a variable interpreted in the expression? My current code looks like:-
if variable.is_a?("#{variable_type}")
puts variable
end
Where variable could contain anything and variable_type contains the type of a variable like String or Fixnum. But currently this code gives me TypeError: Class or module required. Any thoughts?

Your code sends a String object to the #is_a? method and the #is_a method expects a Class.
For example, String vs. "String":
variable = "Hello!"
variable_type = String
"#{variable_type}" # => "String"
# your code:
if variable.is_a?("#{variable_type}")
puts variable
end
#is_a? expects the actual Class (String, Fixnum, etc') - as you can see in the documentation for #is_a?.
You can adjust your code in two ways:
pass the Class, without the string.
convert the string to the class using Module.const_get.
here is an example:
variable = "Hello!"
variable_type = String
"#{variable_type}" # => "String"
# passing the actual class:
if variable.is_a?(variable_type)
puts variable
end
# or,
# converting the string to a the type:
if variable.is_a?( Module.const_get( variable_type.to_s ) )
puts variable
end

Just a little example:
variable = 1
variable_type = String
puts variable if variable.is_a?(variable_type)
#=> nil
variable_type = Integer
puts variable if variable.is_a?(variable_type)
#=> 1
Or when your variable_type is a string:
variable_type = 'Integer'
puts variable if variable.is_a?(Object.const_get(variable_type))
#=> 1

TypeError: Class or module required
It means, that to use is_a? varibale_type should hold a class name (any).
Therefore if you hold anything else except for class name in variable_type it will give you this error.
a = :a
variable_type = Symbol
a if a.is_a? variable_type
# => :a
If variable type is a string, you will have to use Module#const_get:
variable_type = 'Symbol'
a if a.is_a? Object.const_get(variable_type)
# => :a

Related

How to do user-inputted string templating in Ruby?

I know writing like
a=23
p "the value of a is #{a}"
it will print: the value of a is 23.
but now I am actually receiving this string as a parameter like
def evaluate string
a=23
puts string
end
calling method pass that string as a parameter
evaluate "the value of a is #{a}"
Is there any way to evaluate this string inside the method? puts string has to interpolate the value a=23.
Edit:
I have to read and execute the program from Excel.
At the first line,
Excel entry is,
"id=something" setvalue a
So now corresponding program will read the value from locator id=something and set it into the instance variable #a.
and user's next excel entry would be
"the value of a is 23" compare "the value of a is #{a}"
Now the program will read "the value of a is 23" and this "the value of a is #{a}" for comparison, but before it compares, it has to replace the value a. That's all I want. I hope now my question is very clear.
For ruby you can change how you "format" your strings in Excel, than you can use "classic" formatting
a = 23
s = 'the value of a is %s'
def evaluate(text, value)
puts text % value
end
You can use different formatting keys, for example %d for integers, %f for float numbers
You can use named arguments
dynamic_text = 'the value of the %<product_name>s is %<product_price>0.2f'
def evaluate(text, args)
puts text % args
end
name = "Product"
price = 78.99
evaluate dynamic_text, product_name: name, product_price: price
Without names, use order of the given values
dynamic_text = 'the value of the %s is %0.2f'
def evaluate(text, args)
puts text % args
end
name = "Product"
price = 78.99
evaluate dynamic_text, [name, price]
You can make a block and then evaluate the string:
def evaluate &block
a=23
block.call(a)
end
evaluate { |a| "the value of a is #{a}" } #=> "the value of a is 23"
It's a very odd thing you're attempting to do. When you have some sort of a pattern with placeholders, you do it like:
def evaluate(string)
a=23
format string, a: a
end
evaluate "the value of a is %{a}"
String interpolation with #{..} is not meant for the case you're describing as the value is evaluated at the time of constructing the string, not later. You could do some regexp matching and replace the #{..} with %{..} as a workaround.
There's a few ways:
"Code" Dynamic
lazy evaluation with lambdas:
def evaluate(str_template)
a = 23
str_template.call(a)
end
user_input = gets
my_lambda = lambda do |str|
user_input.size > 10 ? "dynamic 1 #{str}" : "dynamic 2 #{str}"
end
evaluate(my_lambda)
# => "dynamic 1/2 23"
This is "code dynamic", but not "input dynamic", i.e. you can't receive the string template from the user.
"Input" Dynamic 1
ERB templating:
require 'erb'
user_input_erb = gets
puts user_input_erb # "Hello <%= name %>"
name = gets # also user input, e.g. "World"
ERB.new(user_input_erb).result
# => "Hello World"
Note that in general, getting string templates from the user and evaluating them is a potential security vulnerability. If there's any possibility user input can be adversarial, you'll want to see if you can find a "guaranteed to be safe against all user input" string templating library.
"Input" Dynamic 2
user_input_template = gets
puts user_input_template # "Hello %s"
name = gets # also user input, e.g. "World"
user_input_template % name
# => "Hello World"
"Input" Dynamic 3
Really dangerous, but:
user_input_ruby_code = gets
puts user_input_ruby_code # '"Hello #{name}"'
name = gets # also user input, e.g. "World"
eval user_input_ruby_code # DANGER
# => "Hello World"

Take name of variable as input and output its value - Ruby

I'd like to know if there is something Ruby that does something like this:
#my_var = "foo"
some_function_i_dont_know_name_of("#my_var")
=> "foo"
Seems like you are looking for instance_variable_get. From the docs:
Returns the value of the given instance variable, or nil if the instance variable is not set. The # part of the variable name should be included for regular instance variables. Throws a NameError exception if the supplied symbol is not valid as an instance variable name. String arguments are converted to symbols.
class Fred
def initialize(p1, p2)
#a, #b = p1, p2
end
end
fred = Fred.new('cat', 99)
fred.instance_variable_get(:#a) #=> "cat"
fred.instance_variable_get("#b") #=> 99
Yes, there is.
#my_var = "foo"
instance_variable_get("#my_var")
=> "foo"

What does this ruby snippet do?

As a ruby newbie I am trying to understand a snippet of code in our baseline. Could someone please do that for me ? The snippet appears below
%w{word1 word2}.each { |att| define_method(att.to_sym) { return nil }}
In the context where this line will be run, two methods will be defined
def word1
return nil
end
def word2
return nil
end
For example
class MyClass
%w{word1 word2}.each { |att| define_method(att.to_sym) { return nil }}
end
After my_class.rb file will be loaded you will be able to consume generated methods
test = MyClass.new
test.word1
# or
test.word2
Like jdv said in the comments, for tutorials you might be better of on other websites. Here are all references needed to understand the piece of code provided:
Percent strings, used in %w{word1 word2}
Percent Strings
Besides %(...) which creates a String, the % may
create other types of object. As with strings, an uppercase
letter allows interpolation and escaped characters while a
lowercase letter disables them.
These are the types of percent strings in ruby:
%i: Array of Symbols
%q: String
%r: Regular Expression
%s: Symbol
%w: Array of Strings
%x: Backtick (capture subshell result)
For the two array forms of percent string, if you wish to
include a space in one of the array entries you must escape
it with a “\” character:
%w[one one-hundred\ one]
#=> ["one", "one-hundred one"]
If you are using “(”, “[”, “{”, “<” you must close it with
“)”, “]”, “}”, “>” respectively. You may use most other
non-alphanumeric characters for percent string delimiters
such as “%”, “|”, “^”, etc.
Array#each
each {|item| block} → ary
each → Enumerator
Calls the given block once for each element in self,
passing that element as a parameter. Returns the array
itself.
If no block is given, an Enumerator is returned.
a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }
produces:
a -- b -- c --
Module#define_method
define_method(symbol, method) → symbol
define_method(symbol) { block } → symbol
Defines an instance method in the receiver. The method
parameter can be a Proc, a Method or an UnboundMethod
object. If a block is specified, it is used as the method
body. This block is evaluated using instance_eval.
class A
def fred
puts "In Fred"
end
def create_method(name, &block)
self.class.define_method(name, &block)
end
define_method(:wilma) { puts "Charge it!" }
end
class B < A
define_method(:barney, instance_method(:fred))
end
a = B.new
a.barney
a.wilma
a.create_method(:betty) { p self }
a.betty
produces:
In Fred
Charge it!
#<B:0x401b39e8>
String#to_sym
to_sym → symbol
Returns the Symbol corresponding to str, creating the
symbol if it did not previously exist. See Symbol#id2name.
"Koala".intern #=> :Koala
s = 'cat'.to_sym #=> :cat
s == :cat #=> true
s = '#cat'.to_sym #=> :#cat
s == :#cat #=> true
This can also be used to create symbols that cannot be
represented using the :xxx notation.
'cat and dog'.to_sym #=> :"cat and dog"
%w{word1 word2} = creating an array that looks like this ['word1', 'word2']
.each = iterating through each value in the array
{} = this is a code block each value in the array will be run through this block
|attr| = block parameter. each value in the array will be placed here
define_method = define a method from the argument
(att.to_sym) = the name of the new method. this will be word1 and then word2
{ return nil } = the body of the new method
So what is happening is you are defining two new methods. One method called word1 and another called word2. Each of these methods will have a body of return nil. They will look like this:
def word1
return nil
end
def word2
return nil
end

Ruby set an argument variable in an object

I need a quick hack for a ruby script which parse a json file for some variables. It stores in #{name} the name string from the json file where the id is the input for the argument.
The issue is that I cannot set the ID argument which is #{b} in the object data-on_day_you_want. If I put it in "#{b}" it won't match with the value from the json file.If I hardcoded it with 281 it works perfectly.
ps:Please find below the a small part from the json.
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
a, b = ARGV #(environment and ID arguments)
file = File.read('file.json')
data_hash = JSON.parse(file)
data_on_day_you_want = data_hash["tenantAuthzProfiles"].detect{ |h| h["id"] == #{b} } # HERE IS THE ISSUE
name = data_on_day_you_want["name"]
puts "NAME is: #{name}"
the json:
{
"name": "Production Environment",
"roles": ["Host Admin"],
"id": 281
}
Do you have any suggestions?
I believe you want to parse b as integer:
data_on_day_you_want = data_hash["tenantAuthzProfiles"].detect do |h|
h["id"] == b.to_i
end
In your code, b receives the value "281" which is a string. When you compare string to integer, it'll always be false:
"281" == 281
# => false
The to_i method parses the string, and returns the integer value it represents:
"281".to_i == 281
# => true
(note that, contrary to other languages' parse methods, to_i is very lenient, so you might get surprising results "surprise".to_i == 0)
The notation of #{} is relevant to String interpolation, and is only valid inside a string (surrounded by double-quoutes)

ruby regex named and group

I am trying to use a named group in a regex but it doesn't work:
module Parser
def fill(line, pattern)
if /\s#{pattern}\:\s*(\w+)\s*\;/ =~ line
puts Regexp.last_match[1]
#self.send("#{pattern}=", value)
end
if /\s#{pattern}\:\s*(?<value>\w+)\s*\;/ =~ line
puts value
#self.send("#{pattern}=", value)
end
end
end
As you can see I first test my regex then I try to use the same regex with a named group.
class Test
attr_accessor :name, :type, :visible
include Parser #add instance method (use extend if we need class method)
def initialize(name)
#name = name
#type = "image"
#visible = true
end
end
t = Test.new("toto")
s='desciption{ name: "toto.test"; type: RECT; mouse_events: 0;'
puts t.type
t.fill(s, "type")
puts t.type
When I execute this, the first regex work but not the second with the named group.
Here is the output:
./ruby_mixin_test.rb
image
RECT
./ruby_mixin_test.rb:11:in `fill': undefined local variable or method `value' for
#<Test:0x00000001a572c8> (NameError)
from ./ruby_mixin_test.rb:34:in `<main>'
If =~ is used with a regexp literal with named captures, captured strings (or nil) is assigned to local variables named by the capture names.
/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ " x = y "
p lhs #=> "x"
p rhs #=> "y"
But - A regexp interpolation, #{}, also disables the assignment.
rhs_pat = /(?<rhs>\w+)/
/(?<lhs>\w+)\s*=\s*#{rhs_pat}/ =~ "x = y"
lhs # undefined local variable
In your case from the below code :
if /\s#{pattern}\:\s*(?<value>\w+)\s*\;/ =~ line
puts value
#self.send("#{pattern}=", value)
end
Look at the line below, you use interpolation
/\s#{pattern}\:\s*(?<value>\w+)\s*\;/ =~ line
~~^
Thus local variable assignment didn't happen and you got the error as you reported undefined local variable or method 'value'.
You have not defined value in the module
if /\s#{pattern}\:\s*(?<value>\w+)\s*\;/ =~ line
puts value # This is not defined anywhere
[..]

Resources