[EVALUATION] - E03 - jamLang Evaluation Case Applied to Ruby

I

Ilias Lazaridis

[EVALUATION] - E02 - Nitro, a Ruby Based WebFramework
http://groups-beta.google.com/group/comp.lang.ruby/msg/0fb8b0824d4fbaec

-

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

If you like, please post the most elegant solutions (either to sections
or to the whole document).

I will collect the results and write them down in a document, which will
compare ruby with other languages.

This document can serve as an flash-start (for people which simply like
to take a look on ruby).

http://lazaridis.com/case/lang/ruby.html

..
 
M

Martin DeMello

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
 
I

Ilias Lazaridis

Martin said:
Okay, that's a neat bit of work. Here's a quick solution (ruby makes
most of this fairly trivial):

I apologize for the late answer.
# here's your basic talker class

class Talker
def sayHello
puts "Hello world"
end
end
ok

# __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

Assuming I placethe code into the file "talker.rb".

from the command-line, i like to start it, e.g. with "ruby talker.rb"

I miss a "main" directive / function / object.

something like:

def main
talker = Talker.new
talker.sayHello
end
# one-pass interpreter, and you can reopen classes
# so let's just continue

[sidenote: I don't understand this]
# here are the two instance variables added to the class, complete with
# autogenerated getters and setters

very nice!
class Talker
attr_accessor :name, :age

can I write?:

attr_accessor :name
attr_accessor :age
def initialize(name, age)
@name, @age = name, age
end

Is this the constructor?

I assume I can write

def initialize(name, age)
@name = name
@age = age
end
# following the spec, though say_name is more rubyish
def sayYourName
puts @name
end

can I write?: def sayYourName puts @name end
def sayYourAge
puts @age
end
end
ok

# 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

very(!) nice!
talker.name = "Just another talker"
talker.age = 1
talker.sayYourName
talker.sayYourAge
end
ok

# reflection
[...]

seperate message will follow.

..
 
D

Douglas Livingstone

Assuming I placethe code into the file "talker.rb".

from the command-line, i like to start it, e.g. with "ruby talker.rb"

I miss a "main" directive / function / object.

You can think of the whole file as "main". The code will be read from
top to bottom.
# one-pass interpreter, and you can reopen classes
# so let's just continue

[sidenote: I don't understand this]

Example:

# first time setting the class
class Talker
attr_accessor :name

def initialize(name)
@name = name
end

end

talker = Talker.new('Bob')
puts talker.name

# reopen the class to add sayYourName
class Talker
def sayYourName
puts @name
end
end

talker.sayYourName


The output is:

Bob
Bob

can I write?:

attr_accessor :name
attr_accessor :age
yes


Is this the constructor?

I assume I can write

def initialize(name, age)
@name = name
@age = age
end
yes


can I write?: def sayYourName puts @name end

You need to add semicolons if you want to put more than one line on a line:

def sayYourName; puts @name; end

hth,
Douglas
 
M

Martin DeMello

Ilias Lazaridis said:
# one-pass interpreter, and you can reopen classes
# so let's just continue

[sidenote: I don't understand this]

The ruby interpreter is one-pass insofar as it takes a single pass through
the file, from top to bottom, building and executing an abstract syntax tree
as it goes. Anything enclosed in a def...end block (and a few other
delayed-evaluation constructs like lambda) gets converted into a 'callable'
block of code, the rest is just executed. That's how attr_accessor works,
incidentally - it's just a piece of code that runs inside a class's context
and generates methods when it's executed. Try the following:

class Foo
def say_hello
puts "hello world"
end

puts "hi, this is the reader"
end

a = Foo.new
a.say_hello

the first puts statement gets executed when say_hello is called; the second
one is not inside a def statement, and so gets executed when the interpreter
gets to it.

Hence the lack of a main() method - in a sense, the whole fine is a main(),
since the entry point is the top of the file (comes in real handy when
writing quick imperative scripts - you aren't forced to define a class just
because Ruby is a pure OO language).

Hence the if __FILE__ == $0 blocks - if the file is not being run directly,
the condition fails, and the whole block is skipped.

As for reopening classes, you can modify a class at runtime (add/delete
methods, mix in a module), and any objects belonging to the class inherit
those modifications (rather trivially, since they look up methods in the
class). But, since this is a one pass interpreter, those changes come into
effect at the time the reader reads them, and so the object "changes" in the
middle of its lifecycle.

martin
 
I

Ilias Lazaridis

Douglas said:
You can think of the whole file as "main". The code will be read from
top to bottom.

I understand.

This means that ruby is _not_ strictly Object Oriented.

And this means that I can drop the "if __FILE__ [...]" construct.

I like both points.

-

I assume I can launch my application with "ruby talker.rb".
# one-pass interpreter, and you can reopen classes
# so let's just continue

[sidenote: I don't understand this]

Example:

# first time setting the class
class Talker
attr_accessor :name

def initialize(name)
@name = name
end

end

talker = Talker.new('Bob')
puts talker.name

# reopen the class to add sayYourName
class Talker
def sayYourName
puts @name
end
end

talker.sayYourName


The output is:

Bob
Bob

[I think I understand, but will postpone this construct]
ok


ok


You need to add semicolons if you want to put more than one line on a line:

def sayYourName; puts @name; end
ok

hth,
Douglas

..
 
I

Ilias Lazaridis

Martin said:
Ilias Lazaridis said:
# one-pass interpreter, and you can reopen classes
# so let's just continue

[sidenote: I don't understand this]

The ruby interpreter is one-pass insofar as it takes a single pass through
[...] - (interpreter, dynamic mixins, ...)

Thank you for you explanations.

I've understood now everything.

Altough I'm excited about some contructs, I must postpone their discussion.

I'll come back to them soon.

..
 
M

Martin Ankerl

You can think of the whole file as "main". The code will be read from
top to bottom.
[...]
This means that ruby is _not_ strictly Object Oriented.

Ruby is not strictly OO, but not for the reason you think. Here is a
nice explenation why:
http://www.rubycentral.com/book/classes.html#S3
And this means that I can drop the "if __FILE__ [...]" construct.

__FILE__ is the name of the current source file.
$0 is the name of the top-level ruby program being executed.

So this construct just checks if this the source file is the file that
is executed directly with e.g. 'ruby talker.rb', and only if this is the
case, the codeblock will be executed.


martinus
 
I

Ilias Lazaridis

Martin said:
You can think of the whole file as "main". The code will be read from
top to bottom.
[...]

This means that ruby is _not_ strictly Object Oriented.

Ruby is not strictly OO, but not for the reason you think. Here is a
nice explenation why:
http://www.rubycentral.com/book/classes.html#S3
impressive.
And this means that I can drop the "if __FILE__ [...]" construct.

__FILE__ is the name of the current source file.

ok, here i guessed right (intuitive naming).
$0 is the name of the top-level ruby program being executed.

here i thought that "$0" represents "NULL".

$0 => main-file (or entry-file, or top-level file, or top-level program)
So this construct just checks if this the source file is the file that
is executed directly with e.g. 'ruby talker.rb', and only if this is the
case, the codeblock will be executed.

Ok, now it's clear.

..
 
I

Ilias Lazaridis

Ilias said:
[EVALUATION] - E02 - Nitro, a Ruby Based WebFramework
http://groups-beta.google.com/group/comp.lang.ruby/msg/0fb8b0824d4fbaec

-

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

If you like, please post the most elegant solutions (either to sections
or to the whole document).

I will collect the results and write them down in a document, which will
compare ruby with other languages.

This document can serve as an flash-start (for people which simply like
to take a look on ruby).

http://lazaridis.com/case/lang/ruby.html

The first result is available.

I would like to setup ruby at this point, to add the installation steps
to the document.

Can one suggest me the simplest possible installation (one-click)?

One for Windows and one for Linux (if possible similar in content)?

..
 
I

Ilias Lazaridis

Martin said:
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

I will make a slight addition:

The application main code will be alternatively entered in a seperate
file, main.rb:
talker = Talker.new
talker.sayHello

How does "main.rb" gets knowledge about "talker.rb" ?

-

[...]
# 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
[...]

"#" is used as a comment marker _and_ partly within code.

Can I use another comment marker?

Can I write "puts "#{thisMethodName}: Hello World"" in an different
manner, without the use of "#"?

..
 
J

Jacob Fugal

I will make a slight addition:

The application main code will be alternatively entered in a seperate
file, main.rb:


How does "main.rb" gets knowledge about "talker.rb" ?

Put the code for the Talker class in a separate file then 'require'
that file in main.rb. For example, if the Talker class were in
talker.rb then I'd have:

require 'talker'

talker = Talker.new
talker.sayHello

for my main.rb. Note that the require statement does not need the .rb
suffix on the file containing the class.

"#" is used as a comment marker _and_ partly within code.

Can I use another comment marker?

No. To my knowledge there is only the one comment syntax in ruby.
Can I write "puts "#{thisMethodName}: Hello World"" in an different
manner, without the use of "#"?

Sure. #{thisMethodName} in a string literal simply calls .to_s on the
enclosed expression and inserts it at the designated location. So we
can pull that out such:

puts thisMethodName.to_s + ": Hello World"

The + operator performs concatenation when its arguments are strings.

Jacob Fugal
 
J

James Edward Gray II

No. To my knowledge there is only the one comment syntax in ruby.

Ruby has a multiline comment syntax:

=begin
This is a comment.
=end

Just FYI.

James Edward Gray II
 
I

Ilias Lazaridis

Martin said:
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
[...]

preliminary draft:

http://lazaridis.com/case/lang/ruby.html
# reflection
class Talker

# simple

def sayYourClassName
puts self.class.name # the 'self' is optional here
end

omitting "self" (puts class.name) leads to an error
# 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
ok

# 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

I understand the concept.

is there possibly a more direct solution available, with cleaner code
and a stable/higher execution speed?
# 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
ok

# expert
def sayYourClassDefinition
puts "Class:"
sayYourClassName

puts "Class #{self.class.name}" >> Class Talker

but

puts "Class #{sayYourClassName}" >> Talker Class
puts "Class " + sayYourClassName.to_s >> Talker Class

why?
# %{} is another way to write a string literal

#{} - inside strings
%{} - outside of strings
# (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}
}

Can I get somehow a more precise reflection of the class definition
(output similar to the original class-def, excluding code)?
# 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
ok

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
ok

end

# testing it out

if __FILE__ == $0
talker.sayHelloAdvanced
talker.sayYourClassName
talker.sayYourClassDefinition
talker.sayYourClassCode
end

Hope this helps.

very much!

thank you for your efforts.

..
 
I

Ilias Lazaridis

[from an answer which showed up as a seperate thread]
Begin forwarded message:
omitting "self" (puts class.name) leads to an error

I checked this one myself, because it surprised me when you said it.
You're right of course. I'm assuming it's because class is a method
name and a Ruby keyword.
ok
# 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

I understand the concept.

is there possibly a more direct solution available, with cleaner code
and a stable/higher execution speed?

Have you measured it and proven it too slow? Remember, premature
optimization is the root of all evil in programming. ;)

I'm not sure what you consider "clean", but getting rid of the ternary
operator may make it a little more readable:

if caller[0] =~ /in `([^']+)'/ then $1 else '(anonymous)' end

I meant something direct like:

caller.active_method
In the first example, you're asking Ruby for the class name, which you
add to a string that gets printed by the local call to puts. In the
other two, you're calling a method that prints the class name
immediately.

Of course [I've overseen the print statements].
Then the local puts prints "Class " and the return value
from the method call, which isn't meaningful in this context.
ok


No, these are not equivalent. #{...} is for interpolating Ruby code
inside a string. %{...} defined a double quoted string, without the
quotes:

%{This is a string. I can use "quotes" in here. And #{"interpolate"}
values.}

ok, now I understand.

%{} => string
#{} => string interpolation of code
# (looks neat for multiline strings) [...]
}

Can I get somehow a more precise reflection of the class definition
(output similar to the original class-def, excluding code)?

I don't believe so, no. Remember that a Ruby class can be reopened
and definitions added to it. That means a class could be built up
from many places.

Ruby does have a means to get it to store the source code it reads,
but I don't believe that's what you were asking for.

you're right.

-

I will try to work this out myself.

Where can I find the following information?:

* An UML diagramm (or another visual representation) of the ruby
class-model.

* A deep (but compact) description of the reflection/introspection api's.
James Edward Gray II

..
 
F

Florian Gross

Ilias said:
Where can I find the following information?:

* An UML diagramm (or another visual representation) of the ruby
class-model.

I've generated this one automatically:

http://flgr.0x42.net/class-graph.png

Note that it is quite large and not too pretty, though.
* A deep (but compact) description of the reflection/introspection api's.

Well, the Pickaxe book (slightly outdated version is available online
for free, new issue with lots of new material can be ordered online)
contains that among much other information and is a pretty interesting
read. See

http://www.rubycentral.com/book/ (first issue)
http://phrogz.net/ProgrammingRuby/ (first issue with Wiki for changes)
http://www.pragmaticprogrammer.com/titles/ruby/index.html (second issue)
http://www.amazon.com/exec/obidos/tg/detail/-/0974514055/ (second issue)

I'd recommend ordering the second issue from the pragmatic guys as it
contains detailed information that will be useful for evaluating Ruby in
depth.
 
I

Ilias Lazaridis

Florian said:
I've generated this one automatically:

http://flgr.0x42.net/class-graph.png

with which tool have you generated this?
Note that it is quite large and not too pretty, though.

This is a nice overview.

Does anyone has the detailed model of the core class-model?
Well, the Pickaxe book (slightly outdated version is available online
for free, new issue with lots of new material can be ordered online)
contains that among much other information and is a pretty interesting
read. See

http://www.rubycentral.com/book/ (first issue)
http://phrogz.net/ProgrammingRuby/ (first issue with Wiki for changes)
http://www.pragmaticprogrammer.com/titles/ruby/index.html (second issue)
http://www.amazon.com/exec/obidos/tg/detail/-/0974514055/ (second issue)

I'd recommend ordering the second issue from the pragmatic guys as it
contains detailed information that will be useful for evaluating Ruby in
depth.

thank you for the information.

I need at this point only reference of the reflection/introspection api.

I cannot locate it.

..
 
F

Florian Gross

Ilias said:
with which tool have you generated this?

Graphviz and a custom Ruby script which uses Ruby's introspection for
finding out the class and module relationships.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top