(Static) Constructors/Destructors in Ruby

:slight_smile: It's such a fresh beautiful day outside... and here I am talking tech, when spring is springing :slight_smile:

It really is!

Ok, in Ruby, each of those resources could easily be turned in to a method that will run a block. What you want to be able to do then, is easily compose those methods in to one, and have that run something within the context of resources being available?

Something along the lines of (unchecked code warning!)...?

def run_with_resources(*resources, &block)
  if resources ==
    yield
  else
    send(resources.slice(0)) {run_with_resources(*resources, &block)}

That was supposed to be:
  send(resources.slice!(0)) {run_with_resources(*resources, &block)}

The ! after slice is vital!

···

On 1 Apr 2006, at 11:25, Benjohn Barnes wrote:

From: Benjohn Barnes [mailto:benjohn@fysh.org]
Sent: Saturday, April 01, 2006 1:25 PM
To: ruby-talk ML
Subject: Re: (Static) Constructors/Destructors in Ruby

> I like block idea, but must say that blocks can't give full
> replacement for
> C++'s RAII ideom:
>
> C++:
>
> {
> File f1,f2,f3;
> Socket s1,s2;
> Database d;
> } //here all f1,f2,f3,s1,s2,d being closed
>
> Ruby:
>
> ???

:slight_smile: It's such a fresh beautiful day outside... and here I am talking
tech, when spring is springing :slight_smile:

Hmmm... Not so beautiful/springy day in Kharkov, Ukraine :slight_smile:

Ok, in Ruby, each of those resources could easily be turned in to a
method that will run a block. What you want to be able to do then, is
easily compose those methods in to one, and have that run something
within the context of resources being available?

Something along the lines of (unchecked code warning!)...?

def run_with_resources(*resources, &block)
  if resources ==
    yield
  else
    send(resources.slice(0)) {run_with_resources(*resources,
&block)}
  end
end

You can then do...

run_with_resources
(:file_handle, :db_connection, :socket_and_things, :other_groovy_bits) d
o
  #Wooo - look at all these resources!
end

It wouldn't be a big extension to collect up the resources passed in,
and pop them in a map, or something. I don't think it would be hard
to give the resources arguments either.

Yes, I know all those trick (I'm not a VERY newbie :slight_smile: - my point was "blocks
not always good alternative for RAII".

BTW, I recalled I saw some library at RAA, which does the stuff. But I don't
remember it's name (because in real life it is not as necessary as in dumb
examples :wink:

Cheers,
  Ben

Victor.

···

-----Original Message-----
On 1 Apr 2006, at 11:10, Victor Shepelev wrote:

Jim Weirich wrote:

I'm still unclear on how static methods do anything to support
meta-progarmming. Perhaps an example might prove illuminating.

I am not sure this will be compelling enough, but here we go:

require 'dbi'

class Connection
  @@driver = 'DBI:ADO:Provider=SQLOLEDB;Data Source=...;Initial
Catalog=...;User Id=...;Password=...;trusted_connection=yes'

  def initialize
    @dbh = DBI.connect(@@driver)
    @is_closed=false
  end

  def close
    @dbh.disconnect
    @is_closed=true
  end

  def closed?
    @is_closed
  end

  # MSSQL Server specific
  def columns(table_name)
    table_name = table_name.to_s if table_name.is_a?(Symbol)
    table_name = table_name.split('.')[-1] unless table_name.nil?
    sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue,
DATA_TYPE as ColType, " +
       "COL_LENGTH('#{table_name}', COLUMN_NAME) as Length,
COLUMNPROPERTY(OBJECT_ID('#{table_name}'), " +
       "COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale "

···

+
       "FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"
    columns =
    result = @dbh.select_all(sql)
    result.each { |field| columns << field }
    columns
  end
end

class MyClass
  # Static "constructor"
  def self.create(table)
    @@table = table
    @@connection = Connection.new

    columns = @@connection.columns(table)
    columns.each { |column|
          property = 'fld'+column[0]
          self.class_eval(%Q[
      def #{property}
        @#{property}
      end
      def #{property}=(value)
        @#{property} = value
      end
          ])
    }
  end

  # Static "destructor"
  def self.destroy()
    @@connection.close unless @@connection.closed?
  end
end

MyClass.create('USERS')

table1 = MyClass.new
table2 = MyClass.new

table1.methods.each {|m| puts m if m =~ /^fld/ }

MyClass.destroy

--
Posted via http://www.ruby-forum.com/\.

Yes, I know all those trick (I'm not a VERY newbie :slight_smile: - my point was "blocks
not always good alternative for RAII".

:slight_smile: I thought it was quite clever, I was feeling very pleased with myself :slight_smile:

BTW, I recalled I saw some library at RAA, which does the stuff. But I don't
remember it's name (because in real life it is not as necessary as in dumb
examples :wink:

Well, that's the thing though, really :slight_smile:

···

On 1 Apr 2006, at 11:36, Victor Shepelev wrote:

Victor Shepelev wrote:

Hmmm... Not so beautiful/springy day in Kharkov, Ukraine :slight_smile:

Nor in Northern California. It's so wet the sidewalks are turning green.

Ok, in Ruby, each of those resources could easily be turned in to a
method that will run a block. What you want to be able to do then, is
easily compose those methods in to one, and have that run something
within the context of resources being available?

Here's an idea:

require 'socket'

class ResourceMgr
  def (*resources)
    @resources = resources
  end

  def cleanup
    @resources.reverse_each do |resource, cleanup_method|
      resource.__send__ cleanup_method || :close
    end
  end
end

def with_resources
  res = ResourceMgr.new
  yield res
ensure
  res.cleanup
end

rl_test = nil

with_resources do |res|
  res[
    f = File.open("/tmp/file", "w"),
    s = UDPSocket.open,
    [t = Thread.new {sleep}, :kill]
  ]

  rl_test = [f,s,t]
  p rl_test
  # use resources here
end

p rl_test

__END__

Output:

[#<File:/tmp/file>, #<UDPSocket:0xb7dca598>, [#<Thread:0xb7dca4e4

, :kill]]

[#<File:/tmp/file (closed)>, #<UDPSocket:0xb7dca598>,
[#<Thread:0xb7dca4e4 dead>, :kill]]

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407