Opinion: Scripting in a Ruby program

  • Thread starter Tristan Shelton
  • Start date
T

Tristan Shelton

Hello all, I'm working on a small program -- and learning to love Ruby
all over again -- but I've come across a small dilemma: What if you want
to make a Ruby program that can be extended without modifying the
original code? That is, a Ruby script that can itself be scripted.

What I'm thinking of is something that gives users the ability to do
basic math, access explicitly allowed methods and properties and maybe
even allow user defined variables available only to that script, while
disallowing any other use of the parent Ruby script. Something that is
to Ruby what Ruby, Perl and Python are to C/C++.

I considered loading chunks of Ruby script and using eval() in a safe
context, and also considered creating a very simple interpreted
scripting language in Ruby, but before I proceed with either option I
would like to pose this question to fellow Ruby enthusiasts: How would
you handle making a scriptable/extensible Ruby program like this?
 
T

Tristan Shelton

A small but important addendum: the scripting method should also include
conditionals of some sort.
 
R

Robert Klemme

Hello all, I'm working on a small program -- and learning to love Ruby
all over again -- but I've come across a small dilemma: What if you want
to make a Ruby program that can be extended without modifying the
original code? That is, a Ruby script that can itself be scripted.

What I'm thinking of is something that gives users the ability to do
basic math, access explicitly allowed methods and properties and maybe
even allow user defined variables available only to that script, while
disallowing any other use of the parent Ruby script. Something that is
to Ruby what Ruby, Perl and Python are to C/C++.

I considered loading chunks of Ruby script and using eval() in a safe
context, and also considered creating a very simple interpreted
scripting language in Ruby, but before I proceed with either option I
would like to pose this question to fellow Ruby enthusiasts: How would
you handle making a scriptable/extensible Ruby program like this?

It seems like you just create a bunch of documented (!) classes and let
users decide how they will use them. You can even go as far as
providing a full script where the user can provide a main class name and
invoke a method on that instead of your library provided main class.

Generally in the Ruby world we tend to impose less restrictions on class
and object usage. If someone abuses the code, then that's their
decision. If it does not work, well... You get the picture.

Kind regards

robert
 
M

Matt Neuburg

Tristan Shelton said:
Hello all, I'm working on a small program -- and learning to love Ruby
all over again -- but I've come across a small dilemma: What if you want
to make a Ruby program that can be extended without modifying the
original code? That is, a Ruby script that can itself be scripted.

Well, of course I could be misunderstanding the question, but isn't that
exactly what any Ruby-based Web framework is? What is Ruby on Rails, for
instance, but a Ruby script that you do not modify directly, but which
turns to you at predefined times and in predefined ways and says,
"extend me here if you wish!" So it's just a question of supplying
"hooks" and documenting them: here's when I'll turn to you, and here's
what you do and where you put your code in order for me to find it. (I
use Ruby on Rails as an example because it is well known, but in fact
the example that occurred to me when you asked this question was my own
RubyFrontier, a much smaller, simpler Web framework, because that is
exactly its philosophy and architecture.) m.
 
D

David Masover

Hello all, I'm working on a small program -- and learning to love Ruby
all over again -- but I've come across a small dilemma: What if you want
to make a Ruby program that can be extended without modifying the
original code? That is, a Ruby script that can itself be scripted.

Unless you have a problem with Ruby, the way to do this is generally to
provide a framework. As others have pointed out, Rails is the obvious example.

Indeed, one of the things that keeps me interested in Ruby, even when I keep
seeing other cool little languages like IO and Erlang, is how expressive it
is, particularly how easy it is to create DSLs.
What I'm thinking of is something that gives users the ability to do
basic math, access explicitly allowed methods and properties and maybe
even allow user defined variables available only to that script, while
disallowing any other use of the parent Ruby script. Something that is
to Ruby what Ruby, Perl and Python are to C/C++.

If you have a legitimate use of this -- for example, if your "scripts" are
coming from an untrusted source -- then your argument makes sense. Probably
the easiest approach is to take a language that's designed for this -- for
example, Javascript (so embed Spidermonkey). Probably the best approach is to
figure out how to sandbox Ruby -- look at the Try Ruby project for an example
(or at least an attempt).

On the other hand, if you're talking about a user running your Ruby app
locally, and potentially extending it themselves, what are you protecting them
from, or yourself from? Unless you're using JRuby, they already have the
source, so it's not an IP issue, right?

Anything else sounds a bit like protecting users from themselves -- for
example, it's like asking "How do you make a private method/variable that no
one else can see?" Well, instance_eval is there for a reason.
I considered loading chunks of Ruby script and using eval() in a safe
context,

That's why I'm thinking it might be an untrusted source.
and also considered creating a very simple interpreted
scripting language in Ruby,

Depends how simple it is. This could certainly be very easy -- but on the
other hand, it could grow faster than you mean, and if it's Turing-complete,
and your app is at all popular, people _will_ be writing applications in it.

Do you really want to be responsible for the next PHP, or VBA?

So again... easy way might be roll your own parser, or embed Javascript. Hard
(and right, IMO) way is to use Ruby -- eval in a safe context, or run it as a
separate (unprivileged, chrooted) process, etc.
 
T

Tristan Shelton

Thank you all for your input. I apologize, as it seems I caused some
confusion with my original post. I'm looking for something that allows
the user to perform a few simple operations in a sandbox context, rather
than a framework for programmers to build upon. Something that would
allow me to compile the main program with ruby2exe and then load -- and
reload without interrupting the execution of the main program -- small
bits of script from an external source (e.g. a file) with.

To bring things into context I have a game in which I would like certain
objects to be scriptable to some degree. Nothing extremely involved;
just a few methods, properties, and control structures. So essentially a
scripting "language" that can be provided a simple subset of the main
program's functionality in a sandbox context that doesn't allow file and
network I/O, shell access, and all those other nifty things Ruby
normally does.

Something comparable to Unrealscript or Actionscript (which as I
understand is essentially Javascript) would work fine, I'm just curious
how one would go about implementing such functionality in Ruby. Any
further suggestions are welcome, and no one solution may be best, but
I'm interested to know what's out there and what's possible.
 
R

Robert Klemme

Thank you all for your input. I apologize, as it seems I caused some
confusion with my original post. I'm looking for something that allows
the user to perform a few simple operations in a sandbox context, rather
than a framework for programmers to build upon. Something that would
allow me to compile the main program with ruby2exe and then load -- and
reload without interrupting the execution of the main program -- small
bits of script from an external source (e.g. a file) with.

To bring things into context I have a game in which I would like certain
objects to be scriptable to some degree. Nothing extremely involved;
just a few methods, properties, and control structures. So essentially a
scripting "language" that can be provided a simple subset of the main
program's functionality in a sandbox context that doesn't allow file and
network I/O, shell access, and all those other nifty things Ruby
normally does.

Something comparable to Unrealscript or Actionscript (which as I
understand is essentially Javascript) would work fine, I'm just curious
how one would go about implementing such functionality in Ruby. Any
further suggestions are welcome, and no one solution may be best, but
I'm interested to know what's out there and what's possible.

For one, you can do something like this:

class Shell
class Context
# custom commands for user code
def move
puts "moving..."
end
end

# interactive commands
def load(file)
c = Context.new
c.instance_eval(File.read(file))
nil
end
end

Then you can have a file which contains "move" on a line and you'll see
the move printed.

There is also $SAFE:
http://ruby-doc.org/docs/ProgrammingRuby/html/taint.html#S1

Typically you set up an environment and then start another thread which
restricts $SAFE to provide the sandbox environment.

Also, Try Ruby's source should contain sandboxing techniques as well
(see recent posts).

Kind regards

robert
 
D

David Masover

I'm looking for something that allows
the user to perform a few simple operations in a sandbox context,

The important question for me is, why does this need to be a sandbox?
Something that would
allow me to compile the main program with ruby2exe and then load -- and
reload without interrupting the execution of the main program -- small
bits of script from an external source (e.g. a file) with.

If ruby2exe allows for 'eval', you could easily do it that way -- unless,
again, you want to "save users from themselves" somehow, by ensuring that when
their "script" crashes, it doesn't bring down your script.

But unless they're deliberately doing that, I don't really see what's wrong
with simply creating a well-defined framework and re-evaling their script. As
an example, look at Rails in development mode.

If you were doing this for Unix, you'd also have the nice strategy of forking,
then evaling (or simply 'load' or 'require'-ing), and communicating with the
parent process via pipes. With a COW-friendly GC (which I think Ruby 1.9 has),
this would be lightning-fast and not really more memory than a thread.

But the advantage of the fork-eval strategy isn't that it's more of a sandbox,
it's that they start with a clean slate each time, with all the libraries
loaded.
To bring things into context I have a game in which I would like certain
objects to be scriptable to some degree. Nothing extremely involved;
just a few methods, properties, and control structures. So essentially a
scripting "language" that can be provided a simple subset of the main
program's functionality

Yes, you're still talking about something that would be satisfied by making it
a "framework", by doing things like eval, load, or require, and running that
Ruby code with full privileges.
in a sandbox context that doesn't allow file and
network I/O, shell access, and all those other nifty things Ruby
normally does.

So the question is, what's wrong with that? Let's compare:
Something comparable to Unrealscript

As I understand it, this is essentially meant to script a game, so there's no
reason you'd restrict it in any way.
or Actionscript

Which does allow network I/O, it's just restricted to certain IPs/ports.
(which as I
understand is essentially Javascript)

Not really. I think later versions may have tried to make it a superset of
Javascript, but definitely early on, it was a sad attempt to "improve" on
Javascript.

Robert Klemme mentioned some techniques if you really need to sandbox it --
$SAFE looks particularly interesting.

I've mentioned a few others -- probably the most Unix-y way you could do this
is to provide a pipe-based API, where you send text over a pipe to any program
they want, which replies over the same pipe, and is otherwise unprivileged and
chroot'ed. I have no idea how easy this is to do on Windows, though I think IE
now does something similar on Vista.

But the question you haven't answered yet is why you want it sandboxed at all.
Is the idea that people could be downloading these scripts from the Internet?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top