Ruby pass method (?) As a parameter?
In Ruby, I have a whole bunch of methods that return information from a database: lists of states, countries, languages, ethnic groups, etc. for application form options. I know the selected ids from the form and write methods to get names from ids:
def state_name(state_id)
Db.states.select{ |s| s['id'] == state_id.to_i }.first['name']
end
def country_name(country_id)
Db.countries.select{ |c| c['id'] == country_id.to_i }.first['name']
end
etc .. There are a lot of them. How can I simplify with 1 method that is passed in the name of the item type (state, country, etc.). I want to get a name and not repeat myself over and over again?
source to share
You can solve the metaprogramming problem:
class SomeClass
def self.define_name_method(thing, plural)
define_method :"#{thing}_name" do |id|
Db.send(plural).select {|x| x['id'] == id.to_i }.first['name']
end
end
define_name_method :state, :states
define_name_method :country, :countries
end
SomeClass.new.state_name(19749387) #=> "Oregon"
Or with a more general method:
class SomeClass
def thing_name(plural, id)
Db.send(plural).select{|x| x['id'] == id.to_i }.first['name']
end
end
SomeClass.new.thing_name(:countries, 1239394) #=> "Estonia"
source to share
Well, you can use Object#public_send
to call one of the methods of the current object based on the type name you passed as a parameter:
def name(type, id)
public_send(:"#{type}_name", id)
end
# Call like this:
name(:state, 1)
Or alternatively, you can drop the method definition entirely #{type}_name
and just ask the method to name
call the appropriate method on your Db object:
def name(type, id)
Db.public_send(type).select{ |c| c['id'] == id.to_i }.first['name']
end
# Call like this:
name(:countries, 1)
source to share
Something like this could work using an array of strings %w(country state)
and use define_method
both .send
to dynamically create methods and attributes calls onDb
%w(country state language).each do |entity|
define_method("#{entity}_name") do |id|
Db.send(entity.pluralize).select{ |o| o['id'] == id.to_i }.first['name']
end
end
( require 'active_support/inflector'
if not using Rails for .pluralize
)
which dynamically creates
def state_name(id)
Db.states.select{ |o| o['id'] == id.to_i }.first['name']
end
etc. for country_name
andlanguage_name
source to share