Module#class_eval

I have been playing around with implementing Module#class_eval, partly
because I wanted to use it in a test case and partly because I thought
it
would help my understanding of the guts of IronRuby. I managed to get
the
following code to work but it is not pretty.

    [RubyMethod("class_eval")]

    public static object Evaluate(CodeContext/*!*/ context,

RubyModule/!/ module, MutableString code) {

        // Create a new context for running the code string - not 

sure
if this is necessary.

        CodeContext context2 = new CodeContext(context);

        // We need a localscope for GetRfc.

        RubyScope localScope = RubyUtils.GetScope(context);

        // Create a local scope for this module definition.

        // (This has a side-effect that context2 has the new module

scope attached in its LocalScope property.)

        RubyScope moduleScope = RubyOps.CreateModuleScope(context2,

localScope.RuntimeFlowControl, module);

        // Compile up the code in the new context

        SourceUnit sourceUnit =

context2.LanguageContext.CreateSnippet(code);

        ScriptCode scriptCode =

sourceUnit.Compile(context2.LanguageContext.GetModuleCompilerOptions(context
2.Scope), null);

        // Run the code in the new context.

        // (This overload is currently private but we need to be 

able to
pass in the new context).

        return scriptCode.Run(context2, false);

    }

I added superfluous comments for the benefit of posting it her. The
main
issue, as noted at the bottom of the code, is that the overload of
ScriptCode.Run that is called is currently private. All the public
overloads create a new CodeContext and you lose the LocalScope which is
needed to ensure that the code is run in the context of the module being
defined.

Any comments on this? I assume that as the Hosting spec evolves this
could
get a lot cleaner. Is there a better way right now to achieve the same
result?

Also, one thing that really messed my head up for quite a while is the
use
of the word scope. It took me a while to come to terms with the fact
that
there are numerous completely separate scopes: Scope, ScopeExtension
(which
contains a Scope property), ScriptScope (which implements IScriptScope)
and
RubyScope (which derives from LocalScope).

Am I right in saying:

Scope is the global scope in which the current Ruby program is running
(with
ScopeExtension just wrapping that and ScriptScope being a container for
code
being run within that scope)?

RubyScope is the local scope within a Ruby program that tells you things
like what the current self object is and what variables are accessible?

Regards,

Pete

Peter Bacon D.:

sure if this is necessary.

able to pass in the new context).

Any comments on this? I assume that as the Hosting spec evolves this
could get a lot cleaner. Is there a better way right now to achieve
the same result?

Nice that you got that working!

I think the main issue you’re running into is that hosting APIs are in
flux. That’s been a delaying factor on getting all the string-based
“evals” working. Also, there might be some more work in the compiler
too; e.g. are we burning in references where we should be looking them
up dynamically, etc. There might be other things that Tomas has in mind
that need to be changed. Anyway, I think it makes sense for us to do all
the eval-related stuff in one push.

container for code being run within that scope)?

RubyScope is the local scope within a Ruby program that tells you
things like what the current self object is and what variables are
accessible?

I think that’s correct. Scope is the DLR global scope thing, while
ScriptScope is the hosting API version. RubyScope will probably end up
roughly equivalent to a binding (but it doesn’t have all the stuff
yet–e.g. locals)

  • John

Well, evals are actually not blocked by hosting API (rather the opposite
is true for Ruby hosting in console). There is some other stuff that
needs to be done in DLR and also in Ruby compiler to make eval happen.
I’m on it, but it will take some time.

Tomas