Embedding Ruby, part 2

Thanks Guy and Kent. Working perfectly. I have the 3d program maya
running ruby code and ruby also running MEL code (maya’s scripting
language).
Now, what I would like to do is to see if I can make the syntax of
mixing ruby and mel a tad nicer.
Currently, I have a ruby C routine ( MEL(*args) ) that is able to
execute any command of MEL with ruby parameters and tranform its
return values to equivalent ruby constructs (String, arrays, etc).

Thus, (dummy) user code now looks like:

b = "joint"
1000.times()
{
a = MEL(“ls -type”, b)
}

What I would like to do would be to hide the use of the MEL() command,
in as seamless way as possible. What I ideally would like the user
type would be something like:

b = "joint"
1000.times()
{
a = ls -type b # or a = “ls -type b”
}

which would then call something like (or even better a callback on the
= operator, as I have about 200 commands like ls):

def ls(*args)
MEL(“ls”,*args)
end

For example, in Perl, I could do:

perl -e “sub ls($) { print @_,”\n"; “aa” }; $a = ls -type; print
$a"

Output:
-type
aa

In the above example, ls -type would be interpreted as a string
parameter to be passed to ls, which is what I would like. The user
would be unaware he is calling a routine and external command (nor
would he have to learn a new syntax).
Is there any way I can achieve this sort of seamless add-on to ruby?

Currently, I have a ruby C routine ( MEL(*args) ) that is able to
execute any command of MEL with ruby parameters and tranform its
return values to equivalent ruby constructs (String, arrays, etc).

Thus, (dummy) user code now looks like:

b = “joint”
1000.times()
{
a = MEL(“ls -type”, b)
}

What I would like to do would be to hide the use of the MEL() command,
in as seamless way as possible. What I ideally would like the user
type would be something like:

b = “joint”
1000.times()
{
a = ls -type b # or a = “ls -type b”
}

what about the following :
b = “joint”
1000.times()
{
a = ls(:type => b)
}
It would be more like standard Ruby and will certainly will be simpler
to do.

And to be able to call the MEL methods inside Ruby, you could do
something like that :
module Kernel
def method_missing( symbol, *args )
# call the corresponding MEL function
end
end

And if you do not want to ‘pollute’ the Kernel module, juste create a
new module called MEL for example with method_missing. You would just
have to call MEL.ls(:type => b)

PS : I am not very good in Ruby and I am replying without having the
time to check anything on a Ruby interpreter. I just hope it will be
of some use :-).

···


Vincent ISAMBART
Maintainer of Ruby/GtkGLExt which is part of Ruby-GNOME2 -
http://ruby-gnome2.sourceforge.jp/

1000.times()
{
a = ls(:type => b)
}
It would be more like standard Ruby and will certainly will be simpler
to do.

Sadly, it’s not a good solution, for a bunch of reasons.
MEL has over 200 commands just like “ls”, all allowing multiple dash options.
These tend to change/be added among Maya versions, too. The syntax above more
or less implies I’ll be parsing the options myself, which is insane work and
kind of silly as MEL will do its own error checking for those.
Another big feature of MEL is that it can display commands on a console from
user mouse input. These follow MEL’s syntax ( ie. CMD -OPTION OPT; ), and the
user can easily cut/paste to repeat operations. Changing the syntax too much
would make that cut/paste feature disappear for the embedded ruby.

The beauty of the perl solution is that the MEL syntax is kept transparently,
while all the beneftis of perl over MEL are kept. Of course, I then have to
stick to perl.

The third issue is a practical one. The users using ruby embedded will most
likely be very familiar with MEL, but not many will be familiar with Ruby.
Changing things also too much difficults the transition and the adoption for
them.

module Kernel
def method_missing( symbol, *args )

call the corresponding MEL function

end
end

Yes, this sounds like one of the improvements I was looking for. Thanks!

Now, if I could somehow trick the ruby parser into passing args from the list
of tokens following the command, I’d be in business as with perl.

1000.times()
{
a = ls(:type => b)
}
It would be more like standard Ruby and will certainly will be simpler
to do.

Sadly, it’s not a good solution, for a bunch of reasons.
MEL has over 200 commands just like “ls”, all allowing multiple dash options.
These tend to change/be added among Maya versions, too. The syntax above more
or less implies I’ll be parsing the options myself, which is insane work and
kind of silly as MEL will do its own error checking for those.

FYI, you can convert symbols (like :type) to strings, so it’s simple to use
the method_missing command described belore to convert the ruby
parameters “:type => b” to “-type b”. That doesn’t fix your other two
objections, though.

module Kernel
def method_missing( symbol, *args )

call the corresponding MEL function

end
end

Yes, this sounds like one of the improvements I was looking for. Thanks!

I worry about the consequences of this. Sounds like a huge security
hole, but I guess if you trust MEL it’s not so bad. One problem is you
can’t call any MEL functions that are named the same as Ruby methods.
You’ll want to keep your general MEL() function for emergencies, at
least. (Just have method_missing convert it’s args to a string and then
call MEL() to do the rest of the work.)

I like the syntax “MEL.ls -type b”, but that might mess up the
cut-and-pasting you mentioned.

Joe

···

In article 20040315092252.09144.00001411@mb-m14.aol.com, GGarramuno wrote:

Joe Mason joe@notcharles.ca wrote in message news:slrnc5cbq5.a3e.joe@gate.notcharles.ca

1000.times()
{
a = ls(:type => b)
}
It would be more like standard Ruby and will certainly will be simpler
to do.

Sadly, it’s not a good solution, for a bunch of reasons.
MEL has over 200 commands just like “ls”, all allowing multiple dash options.
These tend to change/be added among Maya versions, too. The syntax above more
or less implies I’ll be parsing the options myself, which is insane work and
kind of silly as MEL will do its own error checking for those.

FYI, you can convert symbols (like :type) to strings, so it’s simple to use
the method_missing command described belore to convert the ruby
parameters “:type => b” to “-type b”. That doesn’t fix your other two
objections, though.

It was the reason why I suggested this solution. But the problem is
that after the first parameter with a value, all others must also be
given a value… And you cannot just copy/paste the MEL code… But
you could easily make in Ruby a MEL to RubyMEL converter (I just hope
the order of the arguments is not important.

I worry about the consequences of this. Sounds like a huge security
hole, but I guess if you trust MEL it’s not so bad. One problem is you
can’t call any MEL functions that are named the same as Ruby methods.
You’ll want to keep your general MEL() function for emergencies, at
least. (Just have method_missing convert it’s args to a string and then
call MEL() to do the rest of the work.)

I like the syntax “MEL.ls -type b”, but that might mess up the
cut-and-pasting you mentioned.

You could use MEL.instance_eval { }, it would
allow you to put many lines of code… But the other problems are
still there… I do not see how you could use something like ls -type
directly in Ruby… I think ‘ls -type’ will always be seen as
ls(-(type)) with type ‘beeing’ a variable and ‘-’ the minus
operator…

···

In article 20040315092252.09144.00001411@mb-m14.aol.com, GGarramuno wrote:

Joe Mason joe@notcharles.ca wrote in message:

I like the syntax “MEL.ls -type b”, but that might mess up the
cut-and-pasting you mentioned.

Me too, but the -type afaik cannot be parsed appropiately, right?
Also, as you mentioned, running MEL commands that have equivalent in ruby would
be an issue (not a big one, really, but still…).

Well, what I did eventually was this:

I provided Object.toMEL() which like to_s() returns a string object, with the
object turned into MEL syntax for each of the basic ruby types.

I left a MEL() command supporting one or multiple parameters. The first
parameter is just sent as is, while the others are parsed based on type,
calling toMEL() appropiately.

This allows writing:

MEL(“ls -type time”)

MEL(<<“EOF”)
ls -type time:
select -r time;
EOF

objtype = “time”
MEL("ls -type ", objtype)

objtype = “time”
MEL(<<“EOF”)
ls -type #{objtype.toMEL}:
select -r #{objtype.toMEL};
EOF

I think some of my objections remain, but I think this is the best compromise
so far.
This still allows the user to cut/paste code (he just has to go thru the pain
to put it it in an << block or MEL()).
This also allows you to write MEL code with conflicting commands to ruby (ie.
for, etc). It also makes it obvious which variables are MEL variables and
which are ruby ones.

Not a perfect solution but not much to ask users to remember, I guess.

Now if I could only get FOX to exit properly, I think we would have a real
winner here.