[ANN] 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
     true
     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

   <========< 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.0

enjoy

-a

···

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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.

···

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
Sent: Tuesday, June 05, 2007 6:33 AM

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
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")

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

* 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

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

···

On Jun 5, 2007, at 12:55 PM, Victor Zverok Shepelev wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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 Gray II

···

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

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

* 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

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
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")

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

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.

···

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
Sent: Tuesday, June 05, 2007 11:03 PM

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

yes, i think so:

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

hash = {
:id => 42,
:send => 'ara.t.howard@gmail.com',
: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
"ara.t.howard@gmail.com"
"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:in `running'
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

···

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

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

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

* 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

Which is significantly better than:

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

?

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
Sent: Tuesday, June 05, 2007 11:03 PM

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
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")

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

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?

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!

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?

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:33 PM, Victor "Zverok" Shepelev wrote:

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

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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?

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

···

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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.

···

From: ara.t.howard [mailto:ara.t.howard@gmail.com]
Sent: Wednesday, June 06, 2007 12:49 AM