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

"Ilias Lazaridis" <ilias@lazaridis.com> schrieb im Newsbeitrag news:d2oki2$4m$1@usenet.otenet.gr...

Robert Klemme wrote:
[...]

So, the last question for this part:

how can I add runtime-accessible [meta]data to a ruby function definition?

[...]

I don't understand.

def talker

  def sayHello
    puts "Hello World"
  end

  def sayYourName
    puts @name
  end

end

how do I put a "hash" which keeps metadata to each _function_?

class Module
def meta() @meta ||= {} end
end

class Foo
def bar() end
meta[:bar] = "bar_meta"
end

[...]

the above is essentially "class metadata".

but it gives me the basic idea:

class Object
  def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

[i like this language *very* much]

-

But to understand this fully, can someone please decrypt this:

  def meta()
    @meta ||= {}
  end

If @meta is something false (i.e. nil or false) then the expression on the right hand side is evaluated and the result is assigned to @meta. It's short for any of these

@meta = {} unless @meta
@meta || (@meta = {})
@meta or @meta = {}

{} creates a hash (synonym for Hash.new, but you can also put values there like {"foo"=>"bar"}).

HTH

    robert

def talker

  def sayHello
    puts "Hello World"
  end

  def sayYourName
    puts @name
  end

end

[snip]

but it gives me the basic idea:

class Object
   def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

What seems to be feasible is implementing one of the following
behaviours:

talker.meta[:sayYourName][:author] # => "it's just me"

or

talker.method(:sayYourName).meta[:author] # => "it's just me"

or if you are on steroids, maybe

talker.meta[:sayYourName].author

or

talker.method(:sayYourName).meta.author

(FYI, Object#method takes a symbol or a string, and returns the method
named thusly as an obejct.)

Csaba

···

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

Florian Gross wrote:

Ilias Lazaridis wrote:

I've generated this one automatically:

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

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.

if it is not very long, can you please post it here?

···

-

btw:

found this ppt-presentation about the object-model (but would prefere an UML diagramm):

http://rubyforge.org/docman/view.php/251/96/ChrisPine_UROM.ppt

..

--
http://lazaridis.com

Robert Klemme wrote:
[...]

[i like this language *very* much]

-

But to understand this fully, can someone please decrypt this:

  def meta()
    @meta ||= {}
  end

If @meta is something false (i.e. nil or false) then the expression on the right hand side is evaluated and the result is assigned to @meta. It's short for any of these

@meta = {} unless @meta
@meta || (@meta = {})
@meta or @meta = {}

{} creates a hash (synonym for Hash.new, but you can also put values there like {"foo"=>"bar"}).

ok

you answer together with the other answer => i got it:

def meta() # use of "()" is optional
   unless @meta # if @meta == nil ("unless" is the same as "if not")
     @meta = {} # creates a new hash
   end
   @meta # returns the hash
end

..

···

--
http://lazaridis.com

Anders Engström wrote:

[snipp]

But to understand this fully, can someone please decrypt this:

def meta()
   @meta ||= {}
end

That's lazy initialization of the @meta variable. Another (and more
verbose) way to write it would be:

def meta()
    unless @meta #If not defined, set the value
        @meta = {}
    end
    @meta # Return Meta
end

def meta() # use of "()" is optional
   unless @meta # if @meta == nil (unless = if not)
     @meta = {} # creates a new hash
   end
   @meta # returns the (existing or new) hash
end

"@meta ||= {}" evaluates to "@meta = @meta || {}" and since the returned

"||=" similar to "+="

"||" means: if left operand is nil, pick right operand.

value from a method is the last evaluated expression "@meta ||= {}"
works.

ok, got it!

[will update the document soon - and hopefully can soon take the next round]

//Anders

..

···

On Sun, Apr 03, 2005 at 08:39:42PM +0900, Ilias Lazaridis wrote:

--
http://lazaridis.com

Csaba Henk wrote:

···

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

def talker

def sayHello
   puts "Hello World"
end

def sayYourName
   puts @name
end

end

[snip]

but it gives me the basic idea:

class Object
  def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

What seems to be feasible is implementing one of the following
behaviours:

[...] - (several other suggestions)

I like the extracted construct - and it works in practice.

Thus I'm covered in this point.

Thank you for your suggestions.

..

--
http://lazaridis.com

Csaba Henk wrote:
[...]

but it gives me the basic idea:

class Object
  def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

[...]

after the other message and some more tests I understood you objections and suggestion.

I sincerly apologize for rejecting them without further and deeper evaluating them, trusting a little bit your experience.

I will continue tomorrow, as I've a blackout now.

..

···

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

--
http://lazaridis.com

if it is not very long, can you please post it here?

I have a quite similar script here:
http://martinus.geekisp.com/rublog.cgi/Projects/RubyToDot/rubytodot.html

martinus

Csaba Henk wrote:

def talker

def sayHello
   puts "Hello World"
end

def sayYourName
   puts @name
end

end

[snip]

but it gives me the basic idea:

class Object
  def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

What seems to be feasible is implementing one of the following
behaviours:

[...] - (several other suggestions)

I like the extracted construct - and it works in practice.

Thus I'm covered in this point.

Thank you for your suggestions.

Just to make sure there is no confusion:

talker.sayYourName.meta[:author] = "it's just me"

sayYourName, when evaluated, returns nil. Therefore,
your meta structure is actually in the instance of
NilClass, not Talker. You should be able to test it
by trying nil.meta[:author] after you execute the
above code.

You would want to follow the original example,
or do something like this (you can elaborate
on the documentation notation):

class Object
  def doc(str)
    @doc_data ||= {}
    # caller[1] will be the method name doc() was called from.
    @doc_data[caller[1]] = str
  end
end

class SomeClass
  # Some method
  def some_method
    doc "This method does something."
    # ...
  end
end

http://lazaridis.com

E

No-one expects the Solaris POSIX implementation!

···

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

Martin Ankerl wrote:

if it is not very long, can you please post it here?

I have a quite similar script here:
http://martinus.geekisp.com/rublog.cgi/Projects/RubyToDot/rubytodot.html

martinus

very nice work.

..

···

--
http://lazaridis.com

Saynatkari wrote:

Csaba Henk wrote:

[...]

but it gives me the basic idea:

class Object
def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

[...]

I like the extracted construct - and it works in practice.

[...]

Just to make sure there is no confusion:

talker.sayYourName.meta[:author] = "it's just me"

sayYourName, when evaluated, returns nil.

This behaviour seems non logical.

talker.sayYourName.meta

talker_object->sayYourName_object->meta_object
Class object Method object Hash object

The sayYourName Method Object is not executed, it's just a part of the nested datastructure.

Therefore,
your meta structure is actually in the instance of
NilClass, not Talker. You should be able to test it
by trying nil.meta[:author] after you execute the
above code.

yes, i've verified this (with the quick test it seemed to work).

I've understood the example you give below.

But I like to have the metadata directly on my function.

And this without further indirection (at least not visual).

You would want to follow the original example,
or do something like this (you can elaborate
on the documentation notation):

class Object
  def doc(str)
    @doc_data ||= {}
    # caller[1] will be the method name doc() was called from.
    @doc_data[caller[1]] = str
  end
end

class SomeClass
  # Some method
  def some_method
    doc "This method does something."
    # ...
  end
end

..

···

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

--
http://lazaridis.com

Saynatkari wrote:

Csaba Henk wrote:

[...]

but it gives me the basic idea:

class Object
def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

[...]

I like the extracted construct - and it works in practice.

[...]

Just to make sure there is no confusion:

talker.sayYourName.meta[:author] = "it's just me"

sayYourName, when evaluated, returns nil.

This behaviour seems non logical.

talker.sayYourName.meta

talker_object->sayYourName_object->meta_object
Class object Method object Hash object

The sayYourName Method Object is not executed, it's just a part of the
nested datastructure.

You are not accessing the method, you are _calling_ the method.
As mentioned earlier, talker.method(:sayYourName).meta would
work.

Therefore,
your meta structure is actually in the instance of
NilClass, not Talker. You should be able to test it
by trying nil.meta[:author] after you execute the
above code.

yes, i've verified this (with the quick test it seemed to work).

I've understood the example you give below.

But I like to have the metadata directly on my function.

And this without further indirection (at least not visual).

This would require changes to the parser, so I do not see
it happening at least before 2.0. On the other hand, zenspider
promised on IRC to pay $50.00 to anyone who will patch the parser
to read comments into the AST, so...

In the interim, I think a fairly robust solution would be to
just write normal offline rdoc documentation for the source
code and then write some sort of a bridge that reads the
metadata in from the rdoc and either creates a .rb file that
can be included in one's program or directly extracts the
information from rdoc at runtime.

You would want to follow the original example,
or do something like this (you can elaborate
on the documentation notation):

class Object
  def doc(str)
    @doc_data ||= {}
    # caller[1] will be the method name doc() was called from.
    @doc_data[caller[1]] = str
  end
end

class SomeClass
  # Some method
  def some_method
    doc "This method does something."
    # ...
  end
end

..

--
http://lazaridis.com

E

No-one expects the Solaris POSIX implementation!

···

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

"Saynatkari" <ruby-ml@magical-cat.org> schrieb im Newsbeitrag news:8yz1QGr1.1112552007.2231070.ruerue@bidwell.textdrive.com...

Saynatkari wrote:

Csaba Henk wrote:

[...]

but it gives me the basic idea:

class Object
def meta() @meta ||= {} end
end

talker.sayYourName.meta[:author] = "it's just me"
puts talker.sayYourName.meta[:author]
=> it's just me

If you want metadata for the _function_, then it's not exactly the way
to go.

The sayYourName method, as defined above, is a side-effecting one,
writes out @name, then returns nil, which is a unique object, without
any reference to talker. That is, it's not a possible carrier of
metainformation.

[...]

I like the extracted construct - and it works in practice.

[...]

Just to make sure there is no confusion:

talker.sayYourName.meta[:author] = "it's just me"

sayYourName, when evaluated, returns nil.

This behaviour seems non logical.

talker.sayYourName.meta

talker_object->sayYourName_object->meta_object
Class object Method object Hash object

The sayYourName Method Object is not executed, it's just a part of the
nested datastructure.

You are not accessing the method, you are _calling_ the method.
As mentioned earlier, talker.method(:sayYourName).meta would
work.

No, it doesn't. Method instances are not suited to carrying meta data:

class Foo; def bar() end end

=> nil

Foo.new.method(:bar).meta[:test]="I'm here"

=> "I'm here"

f=Foo.new

=> #<Foo:0x10184008>

f.method(:bar).meta[:test]="I'm here"

=> "I'm here"

f.method(:bar).meta[:test]

=> nil

The reason is that Method instances are created on each request:

f.method(:bar).__id__

=> 134967116

f.method(:bar).__id__

=> 134950544

f.method(:bar).__id__

=> 134664456

f.method(:bar).__id__

=> 134636916

You have to stick to the class or object as point where meta data is stored. If you want to store a hash per method you can do

class Object
  def meta() @meta ||= Hash.new{|h,k| h[k]={}} end
end

f=Foo.new

=> #<Foo:0x101acf88>

f.meta[:bar][:info]="test"

=> "test"

f.meta[:bar]

=> {:info=>"test"}

f.meta[:bar][:info]

=> "test"

Kind regards

    robert

···

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

Le 3/4/2005, "Ilias Lazaridis" <ilias@lazaridis.com> a écrit:

On 2005-04-03, Ilias Lazaridis <ilias@lazaridis.com> wrote:

"Saynatkari" <ruby-ml@magical-cat.org> schrieb im Newsbeitrag

You are not accessing the method, you are _calling_ the method.
As mentioned earlier, talker.method(:sayYourName).meta would
work.

No, it doesn't. Method instances are not suited to carrying meta data:

[snip]

The reason is that Method instances are created on each request:

Hmm, that's interesting. Good to know of it. So then methods are not
objects per se, they just can be objectified.

Then really talker.meta[:sayYourName][:author] is the way to go. Of
course, if the metadata is not intended/needed to be instance-specific,
then it's better to be appended to the class.

Csaba

···

On 2005-04-04, Robert Klemme <bob.news@gmx.net> wrote:

Csaba Henk wrote:

···

On 2005-04-04, Robert Klemme <bob.news@gmx.net> wrote:

"Saynatkari" <ruby-ml@magical-cat.org> schrieb im Newsbeitrag

You are not accessing the method, you are _calling_ the method.
As mentioned earlier, talker.method(:sayYourName).meta would
work.

No, it doesn't. Method instances are not suited to carrying meta data:

[snip]

The reason is that Method instances are created on each request:

Hmm, that's interesting. Good to know of it. So then methods are not
objects per se, they just can be objectified.

Then really talker.meta[:sayYourName][:author] is the way to go. Of
course, if the metadata is not intended/needed to be instance-specific,
then it's better to be appended to the class.

Csaba

Thank's to all replies.

I've understood now the problem.

-

The Ruby Object Model does not contain reflective MetaClasses, which would enable to apply metadata even to methods.

-

I would like to know how a class which i've defined is represented in memory, and how I can access it.

-

A Visual representation of the Relevant Ruby Object Model (e.g. with UML) would be very helpfull to understand this immediately.

..

--
http://lazaridis.com

If the metadata has anything to do with method execution, say tracking running time for example, you could implement accessors in Object and call them in the method itself. From that call, caller() can be used to index into some global hash that tracks the data.

Just thinking out loud here...

James Edward Gray II

···

On Apr 4, 2005, at 3:54 AM, Csaba Henk wrote:

Then really talker.meta[:sayYourName][:author] is the way to go. Of
course, if the metadata is not intended/needed to be instance-specific,
then it's better to be appended to the class.

"Ilias Lazaridis" <ilias@lazaridis.com> schrieb im Newsbeitrag
news:d2r96v$c9c$1@usenet.otenet.gr...

Csaba Henk wrote:
>
>>"Saynatkari" <ruby-ml@magical-cat.org> schrieb im Newsbeitrag
>>
>>>You are not accessing the method, you are _calling_ the method.
>>>As mentioned earlier, talker.method(:sayYourName).meta would
>>>work.
>>
>>No, it doesn't. Method instances are not suited to carrying meta

data:

>
> [snip]
>
>>The reason is that Method instances are created on each request:
>
> Hmm, that's interesting. Good to know of it. So then methods are not
> objects per se, they just can be objectified.
>
> Then really talker.meta[:sayYourName][:author] is the way to go. Of
> course, if the metadata is not intended/needed to be

instance-specific,

> then it's better to be appended to the class.
>
> Csaba

Thank's to all replies.

I've understood now the problem.

-

The Ruby Object Model does not contain reflective MetaClasses, which
would enable to apply metadata even to methods.

I'm not sure what exactly you mean by this. You can indeed access classes
in Ruby. So I'd say there *are* MetaClasses. It's just that there is no
persistent representation of methods which you could augment with
additional data.

I would like to know how a class which i've defined is represented in
memory, and how I can access it.

You just access them like any object, only that class instances are
assigned to constants:

class Foo;end

=> nil

Foo.instance_variables

=>

class Foo
class <<self
attr_accessor :bar
end
end

=> nil

Foo.bar = "test"

=> "test"

Foo.bar

=> "test"

Foo.instance_variables

=> ["@bar"]

o=Foo

=> Foo

o.new

=> #<Foo:0x10185728>

A Visual representation of the Relevant Ruby Object Model (e.g. with
UML) would be very helpfull to understand this immediately.

I don't know whether such thing exists, but the concept is usually easy
grasped IMHO. Try to play a bit with classes in IRB - that helped me a
lot. Note especially methods #class, #ancestors and #superclass.

Kind regards

    robert

···

> On 2005-04-04, Robert Klemme <bob.news@gmx.net> wrote:

You can find something like this at
class Class - RDoc Documentation -- though not UML just
simple ascii art.

You might as well enjoy "A Little Ruby, A Lot of Objects" by Brian
Marick (http://www.visibleworkings.com/little-ruby/\). In the 3rd chapter
a visualization of the Ruby object model is worked out in a
step-by-step, deductive way (which is the methodology of the whole
work).

Csaba

···

On 2005-04-04, Ilias Lazaridis <ilias@lazaridis.com> wrote:

A Visual representation of the Relevant Ruby Object Model (e.g. with
UML) would be very helpfull to understand this immediately.

There are nice diagrams of this relationship in Programming Ruby (Chapter 24: Objects and Classes).

James Edward Gray II

···

On Apr 4, 2005, at 6:44 AM, Ilias Lazaridis wrote:

A Visual representation of the Relevant Ruby Object Model (e.g. with UML) would be very helpfull to understand this immediately.

You can attach metadata to a certain method object, it's just not what
you will want. Why? Because you refer to a method via the object to which
it belongs, and this always give you a fresh objectification of the
method, as we have discussed.

But. If you stick to refer to methods via their carrier objects (which
you seem to do, and which seems to make sense), then why can't you just
use the object itself as the basic reference point, without further
considerations? Why would be talker.meta[:sayYourName] worse (in any
sense) than what the (disfunctional) talker.method(:sayYourName) could
be?

I mean, the certain object gives the namespace via which you can access
the method as an object. Then why not use the same namespace for storing
the metainformation of the method (without any bitterness)?

Even better, you could make the class or module carry the
metainformation, to which the method belongs as an instance method (each
method is registered as an instance method of some class or module --
singleton methods of an object are instance methods of the metaclass of
the object [accessible as in

class << "a"; self; end

and it is a permanent object, unlike methods]).

This has the advantage that method objects then determine their proposed
metainformation, as they hold a reference to the class/module to which
they belong as an instance method. Alas, in present ruby you can't get
this information explicitly, and now if you say it's a flaw in Ruby, I'd
say I agree (although one which doesn't seem to cause great problems).

For example,
  
[1].method(:at).inspect

gives the string "#<Method: Array#at>", but there is no method of the
method object [1].method(:at) which would give you Array, the class. In
this particular case, as a clumsy workaround, you could parse out Array
from the above string, but this won't work if the method in question
belongs to an anonymous class (like objects' metaclasses).

Huh, I hope it's not too messy.

Csaba

···

On 2005-04-04, Ilias Lazaridis <ilias@lazaridis.com> wrote:

The Ruby Object Model does not contain reflective MetaClasses, which
would enable to apply metadata even to methods.