Reflection in Ruby. Instantiate an object by given class name - ruby

I came to ruby from PHP.
How could i do the next thing in ruby?
$className = 'ArrayObject';
$arrayObject = new $className();

You can do this:
arrayObject = Object::const_get('Array').new

You can also use the following if you are using Ruby on Rails:
array_object = "Array".constantize.new

If you have a class, like for example String:
a = String
a.new("Geo")
would give you a string. The same thing applies to other classes ( number & type of parameters will differ of course ).

Related

How to use polymorphism to remove a switch statement which compares strings?

I am new to Ruby, so let me describe the context of my problem first:
I have a json as input which has the following key / value pair:
{
"service": "update"
}
The value has many different values for example: insert,delete etc.
Next there is a method x which handles the different requests:
def x(input)
case input[:service]
services = GenericService.new
when "update"
result = services.service(UpdateService.new,input)
when "insert"
result = services.service(InsertService.new,input)
when "delete"
result = services.service(DeleteService.new,input)
....
....
else
raise "Unknown service"
end
puts JSON.pretty_generate(result)
end
What is bothering me is that I still need to use a switch statement to check the String values (reminds me of 'instance of' ugh..). Is there a cleaner way (not need to use a switch)?
Finally I tried to search for an answer to my question and did not succeed, if however I missed it feel free to comment the related question.
Update: I was thinking to maybe cast the string to the related class name as follows: How do I create a class instance from a string name in ruby? and then call result = services.services(x.constantize.new,input) , then the class names ofcourse needs to match the input of the json.
You can try something like:
def x(input)
service_class_name = "#{input[:service].capitalize}Service"
service_class = Kernel.const_get(service_class_name)
service_class.new(input).process
end
In addition you might want to check if this is a valid Service class name at all.
I don't understand why you want to pass the service to GenericService this seems strange. let the service do it's job.
If you're trying to instatiate a class by it's name you're actually speaking about Reflection rather than Polymorphism.
In Ruby you can achieve this in this way:
byName = Object.const_get('YourClassName')
or if you are in a Rails app
byName= 'YourClassName'.constantize
Hope this helps
Just first thoughts, but you can do:
eval(services.service("#{input[:service].capitalize}Service.new, #{input})") if valid_service? input[:service]
def valid_service?
w%(delete update insert).include? input[:service]
end
As folks will no doubt shout, eval needs to be used with alot of care

How to get part of string after some word with Ruby?

I have a string containing a path:
/var/www/project/data/path/to/file.mp3
I need to get the substring starting with '/data' and delete all before it. So, I need to get only /data/path/to/file.mp3.
What would be the fastest solution?
'/var/www/project/data/path/to/file.mp3'.match(/\/data.*/)[0]
=> "/data/path/to/file.mp3"
could be as easy as:
string = '/var/www/project/data/path/to/file.mp3'
path = string[/\/data.*/]
puts path
=> /data/path/to/file.mp3
Using regular expression is a good way. Though I am not familiar with ruby, I think ruby should have some function like "substring()"(maybe another name in ruby).
Here is a demo by using javascript:
var str = "/var/www/project/data/path/to/file.mp3";
var startIndex = str.indexOf("/data");
var result = str.substring(startIndex );
And the link on jsfiddle demo
I think the code in ruby is similar, you can check the documentation. Hope it's helpful.
Please try this:
"/var/www/project/data/path/to/file.mp3".scan(/\/var\/www(\/.+)*/)
It should return you all occurrences.

DRY code by creating ruby objects/variables dynamically

I am fairly new to Ruby. I have few lines of code I want to DRY them.
foo_attributes = params[:foo]
params.delete(:foo)
bar_attributes = params[:bar]
params.delete(:bar)
I am trying to do something like this
["foo", "bar"].each do |par|
par_attribute = params[:par]
params.delete(:par)
end
Later in my method, I need to call other methods passing the objects foo_attribute, bar_attribute.
Like:
call_foo_method(foo_attribute)
How can I do this in ruby?
Why don't you just keep the params var? Then you don't have to assign any other variable at all?
You can also DRY the first (and second example) by combinig two lines:
foo_attributes = params.delete(:foo)
bar_attributes = params.delete(:bar)

OR operators and Ruby where clause

Probably really easy but im having trouble finding documentation online about this
I have two activerecord queries in Ruby that i want to join together via an OR operator
#pro = Project.where(:manager_user_id => current_user.id )
#proa = Project.where(:account_manager => current_user.id)
im new to ruby but tried this myself using ||
#pro = Project.where(:manager_user_id => current_user.id || :account_manager => current_user.id)
this didnt work, So 1. id like to know how to actually do this in Ruby and 2. if that person can also give me a heads up on the boolean syntax in a ruby statement like this altogether.
e.g. AND,OR,XOR...
You can't use the Hash syntax in this case.
Project.where("manager_user_id = ? OR account_manager = ?", current_user.id, current_user.id)
You should take a look at the API documentation and follow conventions, too. In this case for the code that you might send to the where method.
This should work:
#projects = Project.where("manager_user_id = '#{current_user.id}' or account_manager_id = '#{current_user.id}'")
This should be safe since I'm assuming current_user's id value comes from your own app and not from an external source such as form submissions. If you are using form submitted data that you intent to use in your queries you should use placeholders so that Rails creates properly escaped SQL.
# with placeholders
#projects = Project.where(["manager_user_id = ? or account_manager_id = ?", some_value_from_form1, some_value_from_form_2])
When you pass multiple parameters to the where method (the example with placeholders), the first parameter will be treated by Rails as a template for the SQL. The remaining elements in the array will be replaced at runtime by the number of placeholders (?) you use in the first element, which is the template.
Metawhere can do OR operations, plus a lot of other nifty things.

Ruby: How to get a class based on class name and how can I get object's field based on field name?

Question 1
How to get a class given a class name as a string ?
For example, say Product class has do_something method:
str = "product"
<what should be here based on str?>.do_something
Question 2
How to get object's field given a field name as a string ?
For example, say Product class has price field:
str = "price"
product = Product.new
product.<what should be here based on str?> = 1200
Jacob's answer to the first question assumes that you're using Rails and will work fine if you are. In case you're not you can call Kernel::const_get(str) to find an existing constant by name.
send is a pure ruby. There's no need to intern your strings with send though (convert them to symbols), straight strings work fine.
Use capitalize and constantize:
str.capitalize.constantize.do_something
Use send:
product.send(str + '=', 1200)

Resources