Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > The real Ruby vs. Python.

Thread Tools

The real Ruby vs. Python.

Posts: n/a
First of all, this email is written by me, Horacio López and doesn't
necessarily reflect the opinions of the RPA team.

> We added it because we wanted the user to have the choice to remove a
> package even if it might screw something up. I see it as being in the
> same vein as allowing a programmer to pass a String into a method that may
> usually expect something else.

I see these comments in the same vein as comparing oranges to apples.

> "Here's some can use it to tie
> knots, secure things, etc. or you can hang yourself with it.

it could read more like:
"here's a nice tool, you can use it to run production installations
without breaking stuff, streamlining the process and behaving in a
predictable manner... or you can use your former package management
system of choice"

> We trust that you'll make the right decision, because we don't think you're an
> idiot."

it could read more like:
"we ease the job because our focus is quality, and not everyone is
willing or have time to spend building decent packages that work
together well"

We don't call people "idiots".

Some people believe just a little policy is good for production
environments, nobody is going to die because of it, and you can
happily continue to design another system that has another policy (if
any) that suits your needs better.

I would still like to know what's the Rubygems manifesto, set of
guidelines, what's the purpose, big idea, right now, based on your
comments and diverging opinions from other Rubygems developers,
features that appear and disappear in the next release, it's hard to
tell and it feels like a bit of a moving target.

It's way much more difficult to start a decent analysis of a system if
you don't know what it will be like in 10 seconds from now, perhaps
it's not even worth the hassle.

On the other hand, it's very easy to drop FUD about a clearly defined
roadmap, for bad or good.


Reply With Quote
Guillaume Marcais
Posts: n/a
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

On Wed, 2004-10-27 at 17:53, Jamis Buck wrote:

> Besides which: Ruby/DL is often touted as a great way to write extension
> libraries. Are there any examples of libraries that have been written
> using Ruby/DL instead of C? I've never seen any, much to my own
> frustration when I would like a good example of Ruby/DL usage.

I wouldn't dare to brag about 'good example', but it at least is a
(mostly) working one. I say mostly as a good number of the settings for
a user are undocumented and I had to guess the return value type.
Anyway, the following code is a binding to the Merak mail server
library. It allowed may to automate the transition from our old mail
server to Merak. It is now a nice way to get the password in clear that
the stupid GUI shows as stars. The creation and basic settings of a
Domain and a User should work. The more exotic settings are untested.

Here is an example of a session using the created merak shell:

$ ssh Administrator@fakedomain irb -r merak_shell
Administrator@fakedomain's password:
Warning: Remote host denied X11 forwarding.
Merak 1:0> toto = Domain[""]
toto = Domain[""]
=> #<Domain; index=15>
Merak 2:0> user = toto["toto"]
user = toto["toto"]
=> #<User index=0>
Merak 3:0> user.password
=> "coucou"
Merak 4:0> user.password = "hello"
user.password = "hello"
=> "hello"
Merak 5:0>
=> #<User index=0>

In short, I would never have written it if I had to drop down to C. One
reason being that I don't have a compiler installed on any Windows
machine yet.


Content-Disposition: attachment; filename=merak.rb
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1

require 'Win32API'

module Merak
class Error < ScriptError; end
class APIError < Error; end
class Failure < APIError; CODE =3D -1; end
class License < APIError; CODE =3D -2; end
class Params < APIError; CODE =3D -3; end
class Paths < APIError; CODE =3D -4; end
class Config < APIError; CODE =3D -5; end

ERRORS =3D [nil, Failure, License, Params, Paths, Config]

# Call function in the DLL. Return an error object if an error occures.
class APIClass
attr_reader :winapis
DLL =3D 'API.dll'
ARGS =3D {
:Init =3D> ["P"],=20
:GetDomainCount =3D> [],
:GetDomainList =3D> ["P", "L"],
:AddDomain =3D> ["P", "P", "L"],
eleteDomain =3D> ["L"],
:GetDomainIndex =3D> ["P"],
:GetDomainName =3D> ["L", "P", "L"],
:LoadDomain =3D> ["L", "P", "L"],
:SaveDomain =3D> ["L", "P", "L"],
:SetDomainDefaults =3D> ["P", "L"],
:GetDomainIP =3D> ["L", "P", "L"],
:SetDomainIP =3D> ["L", "P", "L"],
:GetDomainSetting =3D> ["P", "L", "L", "P", "L"],
:SetDomainSetting =3D> ["P", "L", "L", "P", "L"],
:GetUserCount =3D> ["P"],
:GetUserList =3D> ["P", "P", "L"],
:GetUserIndex =3D> ["P", "P"],
:AddUser =3D> ["P", "P", "L"],
eleteUser =3D> ["P", "L"],
:SetUserDefaults =3D> ["P", "L"],
:LoadUser =3D> ["P", "L", "P", "L"],
:SaveUser =3D> ["P", "L", "P", "L"],
:GetUserSetting =3D> ["P", "L", "L", "P", "L"],
:SetUserSetting =3D> ["P", "L", "L", "P", "L"],

def initialize; @winapis =3D {}; end

def method_missing(call, *args)
winapi =3D @winapis[call]
if winapi.nil?
api_args =3D ARGS[call]
raise Error, "Unknown API call '#{call}'" if api_args.nil?
winapi =3D @winapis[call] =3D, call.to_s, api_args=
, "L")
param =3D args.last.kind_of?(Hash) ? args.pop : nil
r =3D*args)
if r < 0
msg =3D "Error calling #{call}(#{args.join(", ")})"
pmsg =3D param ? param[("err_%d" % (-r)).intern] : nil
msg <<=3D "\n#{pmsg}" if pmsg
raise ERRORS[-r], msg
end # API
# Different types to store in Merak fields
# Should implement pack, unpack, size and base_size
# The virtual type must be instanciate with a base_size argument
class BoolT
def self.pack(b); [b ? 1 : 0].pack("C"); end
def self.unpack(s); s.unpack("C")[0] !=3D 0; end
def self.size(s); 1; end
def self.base_size; 1; end
class NumT
def self.pack(n); [n].pack("L"); end
def self.unpack(s); s.unpack("L")[0]; end
def self.size(s); 4; end
def self.base_size; 4; end
class TimeT
def self.pack(n); nil; end
def self.unpack(s); nil; end
def self.size(s); 8; end
def self.base_size; 8; end
class StringTVirtual
attr_accessor :base_size
def initialize(base_size); @base_size =3D base_size; end
def pack(s); s; end
def unpack(s); s; end
def size(s); s.size; end
class ListTVirtual
attr_accessor :base_size
def initialize(base_size); @base_size =3D base_size; end
def pack(l); l.kind_of?(Array) ? l.join('; ') : l; end
def unpack(s); s.split(/[,;]/).collect { |x| x.strip }; end
def size(s); s.size; end

class TypeTVirtual
attr_reader :category
def initialize(category); @category =3D category; end
def pack(t); [@category.index(t)].pack("L"); end
def unpack(s); @category[s.unpack("L")[0]]; s.unpack("L")[0]; end
def size(s); 4; end
def base_size; 4; end

# Actual type of virtual definition
String32T =3D
String128T =3D
String1024T =3D
List128T =3D
List1024T =3D
# Get/Set settings for object
module Settings
class << self
alias :__append_features :append_features
def append_features(mod)
mod.const_get(:SETTINGS_DESC).each_key do |k|
mod.module_eval("def #{k}; get_setting(:#{k}); end")
mod.module_eval("def #{k}=3D(val); set_setting(:#{k}, val); end")

def get_setting(setting, b_size =3D nil)
s_desc =3D settings_desc[setting]
raise Error, "Unknown setting '#{setting}'" if s_desc.nil?
get_setting =3D settings_calls[:get_setting]
args =3D [@buffer, @buffer.size, s_desc[:val], :buffer, :size]
r, buffer, args =3D call_retry(get_setting, s_desc[:type].base_size, =
return s_desc[:type].unpack(buffer[0, r])
private :get_setting

def set_setting(setting, value)
s_desc =3D settings_desc[setting]
raise Error, "Unknown setting '#{setting}'" if s_desc.nil?
set_setting =3D settings_calls[:set_setting]

s_buf =3D s_desc[:type].pack(value)
r =3D API.send(set_setting, @buffer, @buffer.size, s_desc[:val],
s_buf, s_buf.size)
return value
private :set_setting
end # module Settings

module Utils
# Call an API methods, max attempts time, increasing the size of a buff=
# The buffer is located at :buffer.
# Return: [result, buffer, args]
def call_retry(call, size_base, args, attempts =3D 5)
b_index =3D args.index(:buffer)
s_index =3D args.index(:size)
return nil if b_index.nil?
i =3D 1
args[b_index] =3D buffer =3D " " * (i * size_base)
args[s_index] =3D buffer.size if s_index
r =3D API.__send__(call, *args)
rescue Params =3D> e
i +=3D 1
raise e if i > attempts
return [r, buffer, args]
module_function :call_retry

class Domain
include Utils

class << self
private :new
def names
count =3D API.GetDomainCount
base =3D count * 50
r, buf, args =3D Utils.call_retry(:GetDomainList, base, [:buffer, :=
buf[0, r].split("\0")

# Get by index or name
def get(ident)
case ident
when Integer
r, name, a =3D Utils.call_retry(:GetDomainName, 50,=20
[ident, :buffer, :size])
name =3D name[0, r]
rescue Params
raise Error, "No such domain with index '#{ident}'"
index =3D ident
when String
index =3D API.GetDomainIndex(ident,=20
:err_1 =3D> "No such domain '#{ident}'=
name =3D ident
res =3D new(index, nil, name)
alias :[] :get

def create(name)
r, buffer, args =3D Utils.call_retry(:SetDomainDefaults, 4192,=20
[:buffer, :size])
API.AddDomain(name, buffer, buffer.size)
index =3D API.GetDomainIndex(name)
new(index, buffer, name)

def delete(ident); get(ident).delete; end
end # class << Domain
attr_reader :index
def initialize(index, buffer =3D nil, name =3D nil)
@index, @buffer, @name =3D index, buffer, name
# Returns Virtual Binding IP, or nil if none
def ip
ip =3D " " * 16
r =3D API.GetDomainIP(@index, ip, ip.size)
return (r =3D=3D 0) ? nil : ip[0, r]

def ip=3D(ip)
ip ||=3D ""
API.SetDomainIP(@index, ip, ip.size,
:err_1 =3D> "Bad IP '#{ip}'")

def save
return true unless @buffer
API.SaveDomain(@index, @buffer, @buffer.size)

def delete; API.DeleteDomain(@index); self; end

def name
return @name if @name
r, name, args =3D call_retry(:GetDomainName, 50, [@index, :buffer, :s=
@name =3D name[0, r]

def inspect; "#<Domain name=3D#{name}; index=3D#{@index}>"; end

:description =3D> { :val =3D> 0, :type =3D> String1024T },
:type =3D> { :val =3D> 1, :type =3D> NumT },
:domain_value =3D> { :val =3D> 3, :type =3D> String1024T },
ostmaster =3D> { :val =3D> 4, :type =3D> List1024T },
:admin_forward =3D> { :val =3D> 5, :type =3D> String1024T },
:unknown_users_forward =3D> { :val =3D> 6, :type =3D> BoolT },
:unknown_forward_to =3D> { :val =3D> 7, :type =3D> List1024T },
:info_to_admin =3D> { :val =3D> 8, :type =3D> BoolT },
def settings_desc; SETTINGS_DESC; end
private :settings_desc
:get_setting =3D> :GetDomainSetting, :set_setting =3D> :SetDomainSett=
def settings_calls; SETTINGS_CALLS; end
private :settings_calls
include Settings
def reload
args =3D [@index, :buffer, :size]
r, buffer, args =3D call_retry(:LoadDomain, 4192, args)
@buffer =3D buffer

# User management
def users
count =3D API.GetUserCount(@name)
base =3D count * 50
r, buf, args =3D call_retry(:GetUserList, base, [@name, :buffer, :siz=
buf[0, r].split("\0")

def get_user(ident)
case ident
when Integer
index =3D ident
when String
index =3D API.GetUserIndex(@name, ident)

r, buf, args =3D call_retry(:LoadUser, 4192,=20
[@name, index, :buffer, :size]), index, buf)
alias :[] :get_user

def create_user(*aliases)
r, buffer, args =3D Utils.call_retry(:SetUserDefaults, 4192,=20
[:buffer, :size])
u =3D, nil, buffer)
u.alias =3D aliases unless aliases.empty?
alias :add_user :create_user
end # Domain

class User
include Utils
attr_reader :index, :buffer, :domain
def initialize(domain, index, buf)
@index, @buffer, @domain =3D index, buf, domain

def inspect
"#<User domain=3D#{@domain ? : @domain_index} index=3D#{=

# class POP3; end
# class IMAP; end
# class IMAPandPOP3; end
# UserTypeT =3D[POP3, IMAP, IMAPandPOP3])
:type =3D> { :val =3D> 0, :type =3D> NumT },
:anti_spam_index =3D> { :val =3D> 1, :type =3D> NumT },
:name =3D> { :val =3D> 2, :type =3D> String32T },
:alias =3D> { :val =3D> 3, :type =3D> List128T },
:mailbox =3D> { :val =3D> 16, :type =3D> String32T },
:account_disabled =3D> { :val =3D> 17, :type =3D> BoolT },
:account_valid =3D> { :val =3D> 18, :type =3D> BoolT },
:account_valid_till =3D> { :val =3D> 19, :type =3D> TimeT },
:check_virus =3D> { :val =3D> 20, :type =3D> BoolT },
:allow_remote =3D> { :val =3D> 21, :type =3D> BoolT },
:validity_report =3D> { :val =3D> 22, :type =3D> BoolT },
:validity_report_days =3D> { :val =3D> 23, :type =3D> NumT },
:nt_Password =3D> { :val =3D> 24, :type =3D> BoolT },
:imap =3D> { :val =3D> 25, :type =3D> BoolT },
:imap_mailbox =3D> { :val =3D> 26, :type =3D> String32T },
:max_message_size =3D> { :val =3D> 27, :type =3D> NumT },
:dont_show_messages =3D> { :val =3D> 28, :type =3D> BoolT },
:any_password =3D> { :val =3D> 29, :type =3D> BoolT },
:etrn =3D> { :val =3D> 30, :type =3D> BoolT },
:delete_expire =3D> { :val =3D> 31, :type =3D> BoolT },
:null =3D> { :val =3D> 32, :type =3D> BoolT },
assword =3D> { :val =3D> 33, :type =3D> String32T },
:nt_password_value =3D> { :val =3D> 34, :type =3D> String32T },
:domain_admin_index =3D> { :val =3D> 35, :type =3D> NumT },
:domain_admin =3D> { :val =3D> 36, :type =3D> BoolT },
:mail_box_path =3D> { :val =3D> 37, :type =3D> String128T },
:admin =3D> { :val =3D> 38, :type =3D> BoolT },
:max_box =3D> { :val =3D> 39, :type =3D> NumT },
:max_box_size =3D> { :val =3D> 40, :type =3D> NumT },
:force_from =3D> { :val =3D> 41, :type =3D> String32T },
:respond =3D> { :val =3D> 42, :type =3D> NumT },
nly_local_domain =3D> { :val =3D> 43, :type =3D> BoolT },
:use_remote_address =3D> { :val =3D> 44, :type =3D> String32T },
:forward_to =3D> { :val =3D> 45, :type =3D> String32T },
:respond_with =3D> { :val =3D> 46, :type =3D> String1024T },
:mail_in =3D> { :val =3D> 47, :type =3D> String32T },
:mail_out =3D> { :val =3D> 48, :type =3D> String32T },
:valid_report =3D> { :val =3D> 49, :type =3D> BoolT },
:delete_older =3D> { :val =3D> 50, :type =3D> BoolT },
:delete_older_days =3D> { :val =3D> 51, :type =3D> NumT },
:forward_older =3D> { :val =3D> 52, :type =3D> BoolT },
:forward_older_days =3D> { :val =3D> 53, :type =3D> NumT },
:forward_older_to =3D> { :val =3D> 54, :type =3D> String32T },
:remote_address =3D> { :val =3D> 55, :type =3D> String32T },
:force_from_address =3D> { :val =3D> 56, :type =3D> BoolT },
:megabyte_send_limit =3D> { :val =3D> 57, :type =3D> NumT },
:number_send_limit =3D> { :val =3D> 58, :type =3D> NumT },
def settings_desc; SETTINGS_DESC; end
private :settings_desc
:get_setting =3D> :GetUserSetting, :set_setting =3D> :SetUserSetting=20
def settings_calls; SETTINGS_CALLS; end
private :settings_calls
include Settings

def save
return true unless @buffer
if @index
API.SaveUser(, @index, @buffer, @buffer.size)
r =3D API.AddUser(, @buffer, @buffer.size)
@index =3D r
def delete; API.DeleteUser(, @index); end
end # User
def self.init(path)

Content-Disposition: attachment; filename=merak_shell.rb
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1

prompt =3D "Merak %3n:%i"
IRB.conf[ROMPT][:Merak_Prompt] =3D {
ROMPT_I =3D> "#{prompt}> ",
ROMPT_C =3D> "#{prompt}* ",
ROMPT_S =3D> "#{prompt}* ",
:RETURN =3D> "=3D> %s\n",
IRB.conf[ROMPT_MODE] =3D :Merak_Prompt

require 'merak'
include Merak
Merak.init('C:\Program Files\Merak')

Content-Disposition: attachment; filename="Merak Shell.bat"
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1

@echo OFF=0D
cd \cygwin\home\ADMINI~1=0D
irb -r merak_shell=0D


Reply With Quote
Eivind Eklund
Posts: n/a
On Thu, 28 Oct 2004 23:31:05 +0900, Chad Fowler <(E-Mail Removed)> wrote:
> An example of something that I believe is
> broken from an end-user perspective in rpa-base is that when I remove a
> package, it removes all of the dependencies. We _don't_ want to do that
> with RubyGems. I have Rails installed, and I've written scripts to use
> ActiveRecord, which was installed with Rails. If I decide I don't want
> Rails anymore, I don't want to have to go manually install ActiveRecord
> afterward.

Heh. This seems to be a preference issue: I strongly prefer that
dependencies are removed. This is especially important when libraries
are used for application support. I see extra dependencies being left
around as a significant problem when my use is scaled a little bit.

As an example, on one of my FreeBSD systems where I've experiemented
with different software packages and dependencies are not
automatically removed, I presently have 399 software packages
installed. I guess over 100 of these are presently unused
dependencies. These complicate my enviornment, but removing them is
work, and risk breaking things that have added implict dependencies on

In my ideal world (and the design I originally described for RPA), the
dependencies are *hidden* from the user until they are explictly
requested. Thus, your case above cannot happen.

> As for tracking reverse dependencies, it doesn't seem difficult to me:
> spec.dependent_gems
> The manual user intervention you were talking about is not _necessary_.

I don't get this. Do you mean there is a way to deinstall the
dependencies that the install of a gem auto-installed without manual
intervention? If so, how? I couldn't find it in the documentation -
I'll add it in the places I looked if there is a way.

> We added it because we wanted the user to have the choice to remove a
> package even if it might screw something up.

I don't see how this relate to the above - may we be talking past each other?

> I see it as being in the
> same vein as allowing a programmer to pass a String into a method that may
> usually expect something else. "Here's some can use it to tie
> knots, secure things, etc. or you can hang yourself with it. We trust
> that you'll make the right decision, because we don't think you're an
> idiot."

I'm an idiot, so I tend to presume that there are others out there, too

I work day-to-day with a package system (FreeBSD's) that do track
reverse dependencies and prevent dropping packages that has a
dependency, but do allow a force switch to override it.

I regularly try to de-install libraries that are in use. Roughly 70%
of those attempted de-installs are by accident, while 30% are ones
that I want to go through with anyway. So I definately appreciate
being caught by the safety-net.

Hazzle free packages for Ruby?
RPA is available from

Reply With Quote
Mauricio Fernández
Posts: n/a
On Thu, Oct 28, 2004 at 11:04:01PM +0900, Removed) wrote:
> >RubyGems' versioning model makes it difficult to track reverse
> >dependencies: currently user intervention is required to ensure no
> >dependencies are broken on uninstall, and the installation/removal
> >of a RubyGems package plus its dependencies isn't performed as a
> >transaction. There are also some essentially unsolvable issues at runtime
> >(unsatisfiable dependencies).

> when a package is installed - do you store dags of the dependancies
> somewhere
> then? i guess it would need to be a single dag (at least logically) so you
> could detect problems on uninstall huh?

It is easy to rebuild the graph on uninstall, based on the stored
dependency information. rpa-base also has a mark and sweep garbage
collector (like Ruby to reclaim unneeded packages. It is very useful
for "build dependencies", but that concept doesn't exist in RubyGems so
they're not in dire need of that.

Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Reply With Quote
Chad Fowler
Posts: n/a

On Fri, 29 Oct 2004, Bill Guindon wrote:

# On Thu, 28 Oct 2004 23:31:05 +0900, Chad Fowler <(E-Mail Removed)> wrote:
# > We trust that you'll make the right decision,
# > because we don't think you're an idiot."
# ... unlike Mauricio (and the rest of the RPA team).
# That last part didn't add much to the discussion, but it does add to
# the belief that the two teams are antagonistic.
# Perhaps I just read it the wrong way.

Yea, either that or I wrote it in the wrong way. I was expressing the
philosophy of RubyGems--not implying that the opposite was true of any
other specific developer.


Reply With Quote
David Ross
Posts: n/a
Curt Hibbs wrote:

>David Ross wrote:
>>Binary releases are sometimes a problem, most of us are unix users,
>>there are some windows users.

>I am a big proponent of being cross-platform *and* making things as easy as
>possible for end users to install and use. So, this is not intended to start
>any kind of competition or flame-war, mostly I'm just curious...
>When I see the statement "most of us are unix users, there are some windows
>users" it makes me wonder whether or not this is really true. I'm involved
>in two major cross-platform Ruby projects: FreeRIDE and wxRuby. In both
>cases the windows downloads are higher than all the other platforms
>It would be interesting if there was a more reliable way to gauge Ruby's use
>on various platforms, but I don't know how that could be done.

mmm... Perhaps we can have a long list to a wiki, I'd like to get an
actual headcount. The Ruby Window QA team is all setup. I'm curious if
there are more people who could possibly donate some time or hardware
for the progress of Windows QA support.

David Ross
Hazzle free packages for Ruby?
RPA is available from

Reply With Quote

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Detailsview shows real numbers with commata: Error converting data type nvarchar to real! Curious Trigger ASP .Net 2 09-09-2006 10:59 PM
OT: The Interview - Real, Funny...Real Funny The Rev [MCT] MCSE 42 05-31-2005 10:42 PM
call any usa REAL telephone number from the internet at pulver freeworld for .06 per minute - have your own real fone # for $10 month!! VOIP 0 06-09-2004 01:41 AM
product of real and (integer)(after converted to real one) value - vhdl found fatal error senthil VHDL 5 01-24-2004 04:37 AM