Ilias Lazaridis said:
The above thread showed finally the need to split the evaluation down
into smaller chunks.
Here is a simple evaluation template (first part) which can be applied
to the Ruby language:
http://lazaridis.com/case/lang/index.html
Okay, that's a neat bit of work. Here's a quick solution (ruby makes
most of this fairly trivial):
# here's your basic talker class
class Talker
def sayHello
puts "Hello world"
end
end
# __FILE__ == $0 means that the program is being run directly
# rather than 'require'd from another file
if __FILE__ == $0
talker = Talker.new
talker.sayHello
end
# one-pass interpreter, and you can reopen classes
# so let's just continue
# here are the two instance variables added to the class, complete with
# autogenerated getters and setters
class Talker
attr_accessor :name, :age
def initialize(name, age)
@name, @age = name, age
end
# following the spec, though say_name is more rubyish
def sayYourName
puts @name
end
def sayYourAge
puts @age
end
end
# now note that our object 'talker' has access to the new methods in its
# class
if __FILE__ == $0
# note that we aren't breaking encapsulation and accessing the vars directly;
# the setter methods are called name= and age=, and the getters are called
# name and age
talker.name = "Just another talker"
talker.age = 1
talker.sayYourName
talker.sayYourAge
end
# reflection
class Talker
# simple
def sayYourClassName
puts self.class.name # the 'self' is optional here
end
# objects know nothing about the variables that are bound to them
# (a variable name is not the name of the instance anyway). The
# closest you can come to the "name" of an object is it's object id, so...
def sayYourInstanceName
puts object_id # again, you could say self.object_id if you prefer
end
# advanced
# caller returns a stack (array) of strings of the form
# file:linenumber in `method'
# so we extract the most recent one and parse the method name out
# code from PLEAC
def thisMethodName
caller[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)';
end
# string interpolation in action - the bit between the #{} can be
# any valid expression; to_s will be called on the result and
# interpolated into the string
def sayHelloAdvanced
puts "#{thisMethodName}: Hello World"
end
# expert
def sayYourClassDefinition
puts "Class:"
sayYourClassName
# %{} is another way to write a string literal
# (looks neat for multiline strings)
# we use the standard 'inspect' method to print out arrays of
# method names in a ["meth1", "meth2", ...] format
puts %{
Methods:
public:
#{public_methods.inspect}
protected
#{protected_methods.inspect}
private:
#{private_methods.inspect}
non-inherited:
#{(methods - self.class.superclass.instance_methods).inspect}
Instance Variables:
#{instance_variables.inspect}
}
# note that the instance variables belong to the *instance*, not
# to the class, so they're not technically part of the class
# definition. the following code is illustrative:
#
# class A
# attr_accessor :foo, :bar # defines getters and setters
# end
#
# a = A.new
# p a.instance_variables # => []
# a.foo = 10
# p a.instance_variables # => ["
@foo"]
# b = A.new
# p b.instance_variables # => []
end
def sayYourClassCode
puts "Sadly, you cannot introspect the source code from within a program"
# though see
http://rubyforge.org/projects/parsetree/
# for a way to get at the parsed AST
end
end
# testing it out
if __FILE__ == $0
talker.sayHelloAdvanced
talker.sayYourClassName
talker.sayYourClassDefinition
talker.sayYourClassCode
end
Hope this helps.
martin