Prototype-2.0.0

NAME
prototype.rb

INSTALL
gem install prototype

URIS
http://rubyforge.org/projects/codeforpeople/
http://codeforpeople.com/lib/ruby/

SYNOPSIS
prototype.rb facilitates a prototype based coding style

 http://en.wikipedia.org/wiki/Prototype-based_programming

for ruby

WHY
prototype based programming looks very nice :wink:

also, there are many problems that a genuine singleton object with
cloning
abilities can illuminate clearly

it’s the basis of a new rendering model for rails

HISTORY
2.0.0
completely gutted the prototype library and re-implemented with a
module/singleton_class/include approach.

 note that this version increases a major number because it is NOT
 compatible with past releases.  the incompatible change is that

‘clone’
now returns an object that does not reflect changes made to the
parent: it
is completely independant.

1.0.0

 cleanup up a small error where bareword syntax errors in a

prototype block
were silently ignored

SAMPLES

<========< samples/a.rb >========>

~ > cat samples/a.rb

 require 'prototype'

 singleton = Prototype.new{
   @a, @b = 40, 2

   def answer() @a + @b end
 }

 p singleton.answer #=> 42

~ > ruby samples/a.rb

 42

<========< samples/b.rb >========>

~ > cat samples/b.rb

 require 'prototype'

 DB = Prototype.new{
   host 'localhost'
   port 4242

   conn_string [host, port].join(':')

   def connect() p [host, port] end
 }

 p DB.host               #=> "localhost"
 p DB.port               #=> 4242
 p DB.conn_string        #=> "localhost:4242"

 DB.connect              #=> ["locahost", 4242]

~ > ruby samples/b.rb

 "localhost"
 4242
 "localhost:4242"
 ["localhost", 4242]

<========< samples/c.rb >========>

~ > cat samples/c.rb

 require 'prototype'

 a = Prototype.new{
   def method() 42 end
 }

 b = a.clone

 p a.method                #=> 42
 p b.method                #=> 42

 a.extend{
   def method2() '42' end
 }

 p a.respond_to?(:method2) #=> true
 p b.respond_to?(:method2) #=> false

 b.extend{
   def method3() 42.0 end
 }

 p a.respond_to?(:method3) #=> false
 p b.respond_to?(:method3) #=> true

~ > ruby samples/c.rb

 42
 42
 true
 false
 false
 true

<========< samples/d.rb >========>

~ > cat samples/d.rb

 require 'prototype'

 proto = prototype{ attributes 'a' => 1, 'b' => 2, 'c' => 3 }
 proto = prototype{ a 1; b 2; c 3 }

 %w( a b c ).each{|attr| p proto.send(attr)} #=> 1, 2, 3

 clone = proto.clone
 proto.c = 42

 %w( a b c ).each{|attr| p proto.send(attr)} #=> 1, 2, 42
 %w( a b c ).each{|attr| p clone.send(attr)} #=> 1, 2, 3

~ > ruby samples/d.rb

 1
 2
 3
 1
 2
 42
 1
 2
 3

<========< samples/e.rb >========>

~ > cat samples/e.rb

 require 'prototype'

 proto = Object.prototype{
   @a = 40
   @b = 2
 }

 p(proto.a + proto.b) #=> 42

~ > ruby samples/e.rb

 42

<========< samples/f.rb >========>

~ > cat samples/f.rb

 require 'prototype'

 a = Object.prototype{ attributes 'a' => 4, 'b' => 10, 'c' => 2}

 b = Object.prototype{ a 4; b 10; c 2 }

 c = Object.prototype{ @a = 4; @b = 10; @c = 2 }

 [a, b, c].each{|obj| p(obj.a * obj.b + obj.c) } #=> 42, 42, 42

~ > ruby samples/f.rb

 42
 42
 42

<========< samples/g.rb >========>

~ > cat samples/g.rb

 require 'prototype'

 a = prototype{ @a, @b, @c = 4, 10, 2 }

 b = a.clone

 b.extend{ def answer() a * b + c end }

 p b.answer #=> 42

~ > ruby samples/g.rb

 42

<========< samples/h.rb >========>

~ > cat samples/h.rb

 require 'prototype'

 proto = prototype{
   a 1
   b 1
   c 40

   sum { a + b + c }
 }

 p proto.sum #=> 42

~ > ruby samples/h.rb

 42

<========< samples/i.rb >========>

~ > cat samples/i.rb

 require 'prototype'

 o = Object.new

 o.prototyping do
   @a = 42
   attr 'a'
 end
 p o.a

 o = prototype do
   @a = 42
   attr 'a'
 end
 p o.a

 o.prototyping do
   @b = 42
   attr 'b'
 end
 p o.b
 o.prototyping do
   @b = 42.0
 end
 p o.b

~ > ruby samples/i.rb

 42
 42
 42
 42.0

enjoy

-a

From: ara.t.howard [mailto:[email protected]]
Sent: Tuesday, June 05, 2007 6:33 AM

NAME
prototype.rb

Several small questions about the library:

  • Does cloned object has some connections with it’s prototype (as per
    Io:
    “prototype is something knowing how to process messages I don’t know”)

  • If so, can object’s prototype be changed dynamically? (I mean, b.proto
    =
    c)

  • And what about Io-like “prototype is context for code blocks?”:

block = lambda{puts a + b}

block.call #=> undefined local variable or method `a’

p = Prototype.new{
@a = 40
@b = 2
}

block.proto = p

bloc.call #=> 42

BTW, Markaby uses complicated hack to “setup context variables, while
building HTML” - which is very close to the above example.

  • Does anybody uses it in real projects? I mean, does prototype-based
    approach in not prototype-based language have proved to be useful? The
    question is not about “throw the library away”, but about “who can say,
    what
    features in library are useful”, “who can recommend library for some
    tasks?”

V.

On Jun 5, 2007, at 12:55 PM, Victor Zverok S. wrote:

  • Does cloned object has some connections with it’s prototype (as
    per Io:
    “prototype is something knowing how to process messages I don’t know”)

yes. if one does

clone = Object.prototype{ @a = 42 }.clone

the clone has a #a method from parent and @a instance var if it’s own

  • If so, can object’s prototype be changed dynamically? (I mean,
    b.proto =
    c)

no. but they can be extended

proto = Object.prototype

proto.prototyping do
@a = 42

 def a() @a end

end

block.proto = p

bloc.call #=> 42

sortof.

cfp:~ > cat a.rb
require ‘prototype’

block = lambda{ puts a + b }

proto = Object.prototype

proto.prototyping do
a 40
b 2
c &block
end

proto.c

cfp:~ > ruby a.rb
42

i think your exact example would be quite easy to impliment

BTW, Markaby uses complicated hack to “setup context variables, while
building HTML” - which is very close to the above example.

check out prototype.rb impl - it’s very clean imho. nothing is off
limits - you can have attribute ‘id’, ‘name’, ‘object_id’, etc and
everything works.

  • Does anybody uses it in real projects? I mean, does prototype-based
    approach in not prototype-based language have proved to be useful? The
    question is not about “throw the library away”, but about “who can
    say, what
    features in library are useful”, “who can recommend library for
    some tasks?”

example

Config = Object.prototype{
YAML.load(IO.read(‘config’)).each do |key, value|
attribute key => value
end
}

p Config.host
p Config.port

i’m using it in several project where one might instead use a
singleton. the advantage prototype gives you is basically that you
can have a hierarchy of singletons, each inheriting state and
behavior from it’s parent. i’m currently building a model->view (no
controller) system for rails called ‘magnetic’ that hinges upon the
ability to specify a hierarchy of properties and behavior over those
properties and also that requires that each set of properties be a
singleton (for performance reasons) and it’s filling that roll
nicely. look for a release in the next few weeks.

kind regards.

-a

From: ara.t.howard [mailto:[email protected]]
Sent: Tuesday, June 05, 2007 11:03 PM

Several small questions about the library:
the clone has a #a method from parent and @a instance var if it’s own
It’s understandable. I’ve meant the case

a = Object.prototype{ @x = 42 }

b = a.clone

a.extend {
def my_new_method; puts “here!” end
}

b.my_new_method #will b have ALL the methods of it’s prototype?

assert_equal b.prototype, a #is there a way to obtain b’s prototype?

#we also can think this way:
def b.method_missing(:sym)
self.prototype.send(:sym)
end

I’m not prototype-based guru, of course.

What I want to say. I’ve started to think about prototype-based
programming
from Io and JavaScript. My very first impression was “I create objects,
I
clone objects, that’s all”. But further I’ve found, the more experienced
people think about prototype-based as “each object has it’s prototype”
first
of all (which becames “object’s prototype processes all unknown
signals”,
“object’s prototype can be changed” and even Io’s “prototype defines
lexical
scope”).

It seems prototype.rb now does something like “my first impression”, not
“prototype-based entirely”.

Am I wrong?

V.

On Jun 5, 2007, at 3:03 PM, ara.t.howard wrote:

example

Config = Object.prototype{
YAML.load(IO.read(‘config’)).each do |key, value|
attribute key => value
end
}

p Config.host
p Config.port

Which is significantly better than:

require “ostruct”
Config = OpenStruct.new(
File.open(“config”) { |file| YAML.load(file) }
)

?

I guess the difference comes in how they are used, right? Can you
show an example of that?

I realize I’m just not prototype enlightened yet. No offense intended.

James Edward G. II

On Jun 5, 2007, at 2:33 PM, Victor “Zverok” Shepelev wrote:

a.extend {
def my_new_method; puts “here!” end
}

b.my_new_method #will b have ALL the methods of it’s prototype?

the first impl did indeed to that. the latest does not. i found it
flew in the face of ‘normal’ ruby design patterns - which is where
i’m using it after all! :wink:

assert_equal b.prototype, a #is there a way to obtain b’s prototype?

hmmm. i think the closest thing would be

assert a.class === b

prototype sets up what you would consider a ‘normal’ ruby hierarchy.
that is to say clones are created from a subclass of the cloner’s class.

#we also can think this way:
def b.method_missing(:sym)
self.prototype.send(:sym)
end

I’m not prototype-based guru, of course.

me neither!

“object’s prototype can be changed” and even Io’s “prototype
defines lexical
scope”).

It seems prototype.rb now does something like “my first
impression”, not
“prototype-based entirely”.

Am I wrong?

you are right. i may look into making it closer to the latter in the
future.

kind regards.

-a

On Jun 5, 2007, at 2:19 PM, James Edward G. II wrote:

can say, what

?
yes, i think so:

cfp:~ > cat a.rb
require ‘rubygems’
require ‘prototype’
require ‘ostruct’
require ‘yaml’

hash = {
:id => 42,
:send => ‘[email protected]’,
:class => ‘first’,
}

running ‘prototype’ do
config = prototype.configured hash
p config.id
p config.send
p config.class
end

running ‘ostruct’ do
config = OpenStruct.new hash
p config.id
p config.send
p config.class
end

BEGIN {
def running name
puts “<======== #{ name } ========”
begin
yield
rescue => e
m, c, b = e.message, e.class, e.backtrace.join("\n")
puts “#{ m }(#{ c })\n#{ b }”
ensure
puts
end
end
}

cfp:~ > ruby a.rb
<======== prototype ========
42
[email protected]
“first”

<======== ostruct ========
a.rb:21: warning: Object#id will be deprecated; use Object#object_id
125270
no method name given(ArgumentError)
a.rb:22:in send' a.rb:22 a.rb:31:inrunning’
a.rb:19

realize too that using a prototype for a Config class is but a tiny
tiny sample of where it might benefit someone. anywhere you have a
singleton or a copy constructor it’s worth considering.

i’ll have some magnetic code posted soon - you can look at that for
an example of grittier prototype use.

kind regards.

-a

of all (which becames “object’s prototype processes all unknown
signals”,
“object’s prototype can be changed” and even Io’s “prototype
defines lexical
scope”).

It seems prototype.rb now does something like “my first
impression”, not
“prototype-based entirely”.

Am I wrong?

on second thought it’s a hybrid. in prototype.rb’s case you merely
have to consider each object’s class as it’s ‘prototype’ - all
methods are defined/intercepted there. this a symptom of the fact
that ruby only allows method definitions to reside in modules.

-a

From: ara.t.howard [mailto:[email protected]]
Sent: Wednesday, June 06, 2007 12:49 AM

b.my_new_method #will b have ALL the methods of it’s prototype?

the first impl did indeed to that. the latest does not. i found it
flew in the face of ‘normal’ ruby design patterns - which is where
i’m using it after all! :wink:

OK, that’s why I’ve asked about library usage.

Io (prototype-only) looks cool, when you reading tutorials, guides and
examples. But I’m wondering, where “prototype-also” language (Ruby +
prototype.rb) can be more effective than “prototype-neither” (Ruby
without
prototype.rb). It’s completely possible that advanced
prototype-orientation
(dynamic prototype changing and prototype-based lexical scopes) would
have
no use in Ruby.

V.