Could you tell me if this is good meta programming style?

Hi everyone,

I finished playing yet another game of Chrono Trigger the other day,
and I thought I would look at how I could implement a simple Character
system in Ruby. I have the following initialize method, but I would
like to be sure it's not extremely bad style:

class Character
  attr_accessor :strength, :magic, :defense, :magic_defense

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

    methods.grep(/\w=$/).each { |setter|
      getter = setter[0..-2]
      if send(getter).nil?
        send(setter, 0)
      end
    }
  end
end

So, if I added a :critical_rate accessor, I wouldn't need to modify
anything else in the initialize method. Also, I don't want nil in any
attribute. Is this good style? Are there other (maybe better) ways to
accomplish this? Thank you.

using my attributes module this would be

   harp:~ > cat a.rb
   require 'yaml'
   require 'attributes'

   class Character
     attributes %w( strength magic defense magic_defense )

     def initialize args = {}
       args.each{|k,v| send k, v if respond_to? k}
       reader_attributes.each{|at| send at, 0 unless send at}
     end
   end

   c = Character::new 'strength' => 4, 'magic' => 2
   y c

   harp:~ > ruby a.rb
   --- !ruby/object:Character
   defense: 0
   magic: 2
   magic_defense: 0
   strength: 4

this works because an attribute's reader delegates to the writer if called with
an argument (send at, 0).

not sure if this is 'better' but it's shorter :wink:

cheers.

-a

···

On Fri, 29 Apr 2005, Vincent Foley wrote:

Hi everyone,

I finished playing yet another game of Chrono Trigger the other day,
and I thought I would look at how I could implement a simple Character
system in Ruby. I have the following initialize method, but I would
like to be sure it's not extremely bad style:

class Character
attr_accessor :strength, :magic, :defense, :magic_defense

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

   methods.grep(/\w=$/).each { |setter|
     getter = setter[0..-2]
     if send(getter).nil?
       send(setter, 0)
     end
   }
end
end

So, if I added a :critical_rate accessor, I wouldn't need to modify
anything else in the initialize method. Also, I don't want nil in any
attribute. Is this good style? Are there other (maybe better) ways to
accomplish this? Thank you.

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

la, 2005-04-30 kello 00:14, Vincent Foley kirjoitti:

Hi everyone,

I finished playing yet another game of Chrono Trigger the other day,
and I thought I would look at how I could implement a simple Character
system in Ruby. I have the following initialize method, but I would
like to be sure it's not extremely bad style:

class Character
  attr_accessor :strength, :magic, :defense, :magic_defense

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

    methods.grep(/\w=$/).each { |setter|
      getter = setter[0..-2]
      if send(getter).nil?
        send(setter, 0)
      end
    }
  end
end

So, if I added a :critical_rate accessor, I wouldn't need to modify
anything else in the initialize method. Also, I don't want nil in any
attribute. Is this good style? Are there other (maybe better) ways to
accomplish this? Thank you.

Hello,
I've been using a pretty similar class for my config needs, maybe the
biggest difference is that I'm using a default_config method to get the
default values and to make it work properly with subclassing.

I quite like the respond_to?-check you've got there, think I'll extend
mine by raising a name error if the setter doesn't exist.. or just use a
config block more often :expressionless:

Anyhow, here's the class:

class Configurable

  def initialize(config = {}, &optional_config_block)
    config = default_config.merge(config)
    config.each{|k,v| instance_variable_set("@#{k}", v)}
    optional_config_block.call(self) if block_given?
  end

  def default_config
    {}
  end

end

#subclassing:

class Foo < Configurable
  attr_accessor :foo

  def default_config
    super.merge({
      :foo => 10
    })
  end
end

Foo.new :foo => 5
Foo.new{|f| f.foo = 5 }

class FooBar < Foo
  attr_accessor :bar

  def default_config
    super.merge({
      :bar => 20
    })
  end
end

fb = FooBar.new
fb.foo #=> 10
fb.bar #=> 20