Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set ruby 2.0 keyword arguments with attr_accessor on initialize

Tags:

ruby

How can I dynamically set without having to write the same code all over.

Right now the code looks like this:

def initialize(keywords: keywords, title: title, url: url, adsetting: adsetting)
  self.keywords = keywords
  self.title = title
  self.url = url
  self.adsetting = adsetting
end

If the list gets longer this quickly gets out of hand.

With ruby 1.9 I'd just pass a hash to the method. Like this:

def initialize(args)
  args.each do |k,v|
    instance_variable_set("@#{k}", v) unless v.nil?
  end
end

But I rather use the Ruby 2.0 keyword arguments. Can something similar be achieved?

def initialize(keywords: keywords, title: title, url: url, adsetting: adsetting)
  args.each do |k,v|
    instance_variable_set("@#{k}", v) unless v.nil?
  end
end
like image 644
Hendrik Avatar asked Sep 18 '13 15:09

Hendrik


2 Answers

def initialize(keywords: nil, title: nil, url: nil, adsetting: nil)
  local_variables.each do |k|
    v = eval(k.to_s)
    instance_variable_set("@#{k}", v) unless v.nil?
  end
end

or following John Ledbetter and Cary Swoveland's suggestion:

def initialize(keywords: nil, title: nil, url: nil, adsetting: nil)
  method(__method__).parameters.each do |type, k|
    next unless type == :key
    v = eval(k.to_s)
    instance_variable_set("@#{k}", v) unless v.nil?
  end
end
like image 57
sawa Avatar answered Oct 16 '22 11:10

sawa


Here is a working example based on Sawa's answer. Option number #1 is not working right with inheritance.

class CsvOutline
  def initialize( headers: [],
                  body: [],
                  folder: 'tmp',
                  file_prefix: 'test',
                  filename: "#{file_prefix}_#{Time.zone.now.strftime("%Y%m%d%H%M%S")}.csv",
                  path: File.join(folder, filename))
    # Set instance variables and attribute accessors based on named parameters in initialize
    local_variables.each do |k|
      class_eval do
        attr_accessor k
      end
      v = eval(k.to_s)
      instance_variable_set("@#{k}", v) unless v.nil?
    end
  end
end

now if I was to create a child class

class ReportCsv < CsvOutline
  def initialize
     super(folder: 'reports', file_prefix: 'Report')
  end
end 

Now the child will initialize with the proper folder and file_prefix. If I was to use the second option - they'll be initialized to nil.

like image 38
konung Avatar answered Oct 16 '22 11:10

konung