There's a very interesting article here about metaprogramming in Ruby: <a href="http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html">http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html</a><br>
<br>The final section is titled Dwemthy's Array and links to the original code here: <a href="http://poignantguide.net/dwemthy/">http://poignantguide.net/dwemthy/</a><br>
<br>
I've inlined the most interesting code from that page below. <br>
<br>
In a nutshell what it does is dynamically add fields to subclasses of
the Creature class. The 'traits' line about halfway down says
call the class method 'traits' passing a array of symbols.<br>
Creature.traits is a class method. @traits is an instance
variable I think, my Ruby isn't that great and the fact that it's being
accessed from a class method is confusing me..<br>
<br>
My question is, is this kind of metaprogramming possible in Smalltalk?<br>
<br>
Regards,<br>
<br>
-Darren<br>
<br><span style="font-family: courier new,monospace;"># The guts of life force within Dwemthy's Array</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">class Creature
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> # Advanced metaprogramming code for nice, clean traits</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
def Creature.traits( *arr )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> return @traits if arr.empty?</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> attr_accessor *arr</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> arr.each do |a|</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> class_eval %{</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> class << self</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> def #{a}( val )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> @traits ||= {}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> @traits[#{a.inspect}] = val</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> class_eval %{</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> def initialize</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> self.class.traits.each do |k,v|</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> instance_variable_set( "@" + k.id2name, v )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
}</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
# Creature attributes are read-only</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> traits :life, :strength, :charisma, :weapon</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> # This method applies a hit taken during a fight.</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
def hit( damage )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> p_up = rand( charisma )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
if p_up % 9 == 7</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> p_up /= 4</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
puts "[#{ self.class } magick powers up #{ p_up }!]"</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end </span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> @life -= damage</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> puts "[#{ self.class } has died.]" if @life <= 0
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
# This method takes one turn in a fight.</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> def fight( enemy, weapon )</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if life <= 0</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> puts "[#{ self.class } is too dead to fight!]"
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> return</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
end</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> # Attack the opponent</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> your_hit = rand( strength + weapon )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> puts "[You hit with #{ your_hit } points of damage!]"
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> enemy.hit( your_hit )</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> # Retaliation</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> p enemy</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if enemy.life > 0</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> enemy_hit = rand( enemy.strength + enemy.weapon
)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> puts "[Your enemy hit with #{ enemy_hit } points of damage!]"</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> self.hit( enemy_hit )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">end</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">class DwemthysArray < Array</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
alias _inspect inspect</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> def inspect; "#<#{ self.class }#{ _inspect }>"; end</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> def method_missing( meth, *args )</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> answer = first.send( meth, *args )
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> if first.life <= 0</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
shift</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> if empty?</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
puts "[Whoa. You decimated Dwemthy's Array!]"</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> else</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> puts "[Get ready. #{ first.class } has emerged.]"</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
answer || 0</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
end</span>