Initialize a Ruby class from an arbitrary hash, but only keys with matching accessories

Is there an easy way to list accessories / readers that were installed in the Ruby class?

class Test
  attr_reader :one, :two

  def initialize
    # Do something
  end

  def three
  end
end

Test.new
=> [one,two]

What I'm really trying to do is allow initializations to accept a hash with any number of attributes, but only commit those that are already defined by readers. Sort of:

def initialize(opts)
  opts.delete_if{|opt,val| not the_list_of_readers.include?(opt)}.each do |opt,val|
    eval("@#{opt} = \"#{val}\"")
  end
end

Any other suggestions?

+5
source share
6 answers

This is what I use (I call this idiom hash init).

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map { |(k, v)| send("#{k}=", v) }
 end

If you're on Ruby 1.9, you can make it even cleaner (sending allows private methods):

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map { |(k, v)| public_send("#{k}=", v) }
 end

NoMethodError, foo "foo =" . ( attrs, ),

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map do |(k, v)| 
    writer_m = "#{k}="
    send(writer_m, v) if respond_to?(writer_m) }
  end
 end

, (, ), , , - . NoMethodError - ( ).

( ),

 some_object.methods.grep(/\w=$/)

grep , .

  eval("@#{opt} = \"#{val}\"")

val - - , .

+9

attr_reader, attr_writer attr_accessor, - , .

:

class Class
  alias_method :attr_reader_without_tracking, :attr_reader
  def attr_reader(*names)
    attr_readers.concat(names)
    attr_reader_without_tracking(*names)
  end

  def attr_readers
    @attr_readers ||= [ ]
  end

  alias_method :attr_writer_without_tracking, :attr_writer
  def attr_writer(*names)
    attr_writers.concat(names)
    attr_writer_without_tracking(*names)
  end

  def attr_writers
    @attr_writers ||= [ ]
  end

  alias_method :attr_accessor_without_tracking, :attr_accessor
  def attr_accessor(*names)
    attr_readers.concat(names)
    attr_writers.concat(names)
    attr_accessor_without_tracking(*names)
  end
end

:

class Foo
  attr_reader :foo, :bar
  attr_writer :baz
  attr_accessor :foobar
end

puts "Readers: " + Foo.attr_readers.join(', ')
# => Readers: foo, bar, foobar
puts "Writers: " + Foo.attr_writers.join(', ')
# => Writers: baz, foobar
+4

- :

class Test
  attr_accessor :foo, :bar

  def initialize(opts = {})
    opts.each do |opt, val|
      send("#{opt}=", val) if respond_to? "#{opt}="
    end
  end
end

test = Test.new(:foo => "a", :bar => "b", :baz => "c")

p test.foo # => nil
p test.bar # => nil
p test.baz # => undefined method `baz' for #<Test:0x1001729f0 @bar="b", @foo="a"> (NoMethodError)

, Rails, params new. , , , attr_accessor, .

, , ( ), , .

+2

- . , , . , , -, , :

def initialize(opts)
  opts.each do |opt,val|
    instance_variable_set("@#{opt}", val.to_s) if respond_to? opt
  end
end

, , , , (, {:object_id => 42}). attr_accessor, . , instance_variable_set, , .

0

. attr_* , . , , , . Object#instance_variable_defined? Module#public_method_defined?.

, eval, :

def initialize(opts)
  opts.delete_if{|opt,val| not the_list_of_readers.include?(opt)}.each do |opt,val|
    instance_variable_set "@#{opt}", val
  end
end
0

, ( Object#methods), , ( - =), 100% , weren 't , .

However, it Foo.new.methods.grep(/=$/)will provide you with a printed list of properties. Or, since you already have a hash, you can try:

def initialize(opts)
  opts.each do |opt,val|
    instance_variable_set("@#{opt}", val.to_s) if respond_to? "#{opt}="
  end
end
0
source

All Articles