Ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since
i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to
my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when
ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a
    trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given
    a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

Thanks Dotan.

Personally, I have a bit of a hacky solution:

I have a wrapper class with 2 functions SetScriptInput and
GetScriptOutput.
These pass and retrieve 2 scope level variables “callerInput” and
“callerOutput” (names are arbitrary)

The internal scripts expect and deal with these variables calling them
through:
self.callerInput and self.callerOutput.

It works just fine, but I think I’ll give your method a try as well.
It looks like there will be less artifacts in the script using it
(which would be nice)

Best Regards,
Kevin

Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.

On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S. <

A better way of exposing application objects to the scripts and vice
versa is to use ScriptScope:

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@"
my_app_object.declare ‘version 1’

def do_stuff
‘success’
end
", scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Top level Ruby methods defined in the executed script are published to
the scope so that the host can read it via GetVariable method. Also,
Ruby methods are convertible to delegates, so you can get the variable
as Func and call the delegate later.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 1:54 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.

On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S.
<[email protected]mailto:[email protected]>
wrote:
Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From:
[email protected]mailto:[email protected]
[mailto:[email protected]mailto:[email protected]]
On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]mailto:[email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

Tomas,

Will “my_app_object” be accessible in the do_stuff method? I think not,
since our scope variables are just local ruby variables, right? What
he’d really want is to define a method called “my_app_object” on the
Script class, so then his “.s” files can use “my_app_object” anywhere,
like:

engine Execute(@"class Script
def my_app_object
# do whatever you need to get the app object
end

<script1.s content>
end")

But I still don’t like wrapping the user script in a class like that.
The preferred way would be to create an instance of script and call
instance_eval with the contents of the script1.s file:

~js

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday, November 06, 2009 4:09 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

A better way of exposing application objects to the scripts and vice
versa is to use ScriptScope:

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@"
my_app_object.declare ‘version 1’

def do_stuff
‘success’
end
", scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Top level Ruby methods defined in the executed script are published to
the scope so that the host can read it via GetVariable method. Also,
Ruby methods are convertible to delegates, so you can get the variable
as Func and call the delegate later.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 1:54 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.
On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S.
<[email protected]mailto:[email protected]>
wrote:
Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From:
[email protected]mailto:[email protected]
[mailto:[email protected]mailto:[email protected]]
On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]mailto:[email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

It actually works. Any method call on top-level “self” object will fall
back to the scope (we inject method_missing to the top-level object if
the code is executed from hosting code).
It is implemented like instance_eval against the scope.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Jimmy
Schementi
Sent: Friday, November 06, 2009 4:48 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Tomas,

Will “my_app_object” be accessible in the do_stuff method? I think not,
since our scope variables are just local ruby variables, right? What
he’d really want is to define a method called “my_app_object” on the
Script class, so then his “.s” files can use “my_app_object” anywhere,
like:

engine Execute(@"class Script
def my_app_object
# do whatever you need to get the app object
end

<script1.s content>
end")

But I still don’t like wrapping the user script in a class like that.
The preferred way would be to create an instance of script and call
instance_eval with the contents of the script1.s file:

~js

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday, November 06, 2009 4:09 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

A better way of exposing application objects to the scripts and vice
versa is to use ScriptScope:

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@"
my_app_object.declare ‘version 1’

def do_stuff
‘success’
end
", scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Top level Ruby methods defined in the executed script are published to
the scope so that the host can read it via GetVariable method. Also,
Ruby methods are convertible to delegates, so you can get the variable
as Func and call the delegate later.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 1:54 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.
On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S.
<[email protected]mailto:[email protected]>
wrote:
Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From:
[email protected]mailto:[email protected]
[mailto:[email protected]mailto:[email protected]]
On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]mailto:[email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

Just to be clear, this works:

public class App { public string Name = “hello”; }

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@"
def do_stuff
my_app_object.name
end
", scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday, November 06, 2009 7:53 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

It actually works. Any method call on top-level “self” object will fall
back to the scope (we inject method_missing to the top-level object if
the code is executed from hosting code).
It is implemented like instance_eval against the scope.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Jimmy
Schementi
Sent: Friday, November 06, 2009 4:48 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Tomas,

Will “my_app_object” be accessible in the do_stuff method? I think not,
since our scope variables are just local ruby variables, right? What
he’d really want is to define a method called “my_app_object” on the
Script class, so then his “.s” files can use “my_app_object” anywhere,
like:

engine Execute(@"class Script
def my_app_object
# do whatever you need to get the app object
end

<script1.s content>
end")

But I still don’t like wrapping the user script in a class like that.
The preferred way would be to create an instance of script and call
instance_eval with the contents of the script1.s file:

~js

From: [email protected]
[mailto:[email protected]] On Behalf Of Tomas M.
Sent: Friday, November 06, 2009 4:09 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

A better way of exposing application objects to the scripts and vice
versa is to use ScriptScope:

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@"
my_app_object.declare ‘version 1’

def do_stuff
‘success’
end
", scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Top level Ruby methods defined in the executed script are published to
the scope so that the host can read it via GetVariable method. Also,
Ruby methods are convertible to delegates, so you can get the variable
as Func and call the delegate later.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 1:54 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.
On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S.
<[email protected]mailto:[email protected]>
wrote:
Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From:
[email protected]mailto:[email protected]
[mailto:[email protected]mailto:[email protected]]
On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]mailto:[email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    = a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!

Tomas, is this new, or changed? I couldn’t seem to call a method using
what you showed.
Because “do_stuff” is a function that returns a list (in my case) I
couldn’t do:

var execute = scope.GetVariable<Func>(“do_stuff”);

But instead, had to do something like this:

return engine.Execute(“do_stuff”, scope);

In any case, it worked. Just wondering if it won’t allow for some
reason because I am expecting a complex type back (IList)

Thanks, -Kevin

On Fri, Nov 6, 2009 at 8:59 PM, Tomas M.

This is essentially how we implemented our rules script engine. It works
really well.


Chuck Durfee
Lead Software Architect, CentreSuite
TSYS iSolutions, Golden
Email [email protected]

Tomas M. [email protected]
Sent by: [email protected]
11/06/2009 05:10 PM
Please respond to
[email protected]

To
[email protected][email protected]
cc

Subject
Re: [Ironruby-core] ironruby hosting as scripting engine

A better way of exposing application objects to the scripts and vice
versa
is to use ScriptScope:

var engine = IronRuby.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable(“my_app_object”, new App());

engine.Execute(@“
my_app_object.declare ‘version 1’

def do_stuff
‘success’
end
”, scope);

var execute = scope.GetVariable<Func>(“do_stuff”);
Console.WriteLine(execute());

Top level Ruby methods defined in the executed script are published to
the
scope so that the host can read it via GetVariable method. Also, Ruby
methods are convertible to delegates, so you can get the variable as
Func and call the delegate later.

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 1:54 PM
To: [email protected]
Subject: Re: [Ironruby-core] ironruby hosting as scripting engine

Kevin,
Yep i also needed to support input output but it all goes through the
“$script” variable back to the backing C# object. for now, it makes it
easier to have events and debugging. all in all the end result is that i
provide an “API” exposed through $script.

Jimmy,
Thanks, I clearly overlooked that.

On Fri, Nov 6, 2009 at 11:16 PM, Jimmy S. <
[email protected]> wrote:
Your solution sounds fine. To answer you first question though:
engine.Execute(“class Script; end”) will always give you nil; classes
return nil when defined:

class Foo
… end
=> nil

You’ll have to do this to get the actual class object:

engine.Execute(“class Script; end; Script”)

~Jimmy

From: [email protected] [mailto:
[email protected]] On Behalf Of Dotan N.
Sent: Friday, November 06, 2009 11:17 AM
To: [email protected]
Subject: [Ironruby-core] ironruby hosting as scripting engine

Hi guys sorry for the lengthy mail but i believe this is interesting
since
i’ve found a solution that someone else could use.

just had a session of trying to embed IR in my application.
I’m defining a user script which contains some initialization code and a
special worker function ‘execute’

this is the “user script”:

script1.s --------------------------------------------------------
$script.declare “version 1”

def execute
$script.report “success”
end

what i’m doing is setting “script” as a global variable that is a
gateway
to my application.
I’ve tried this way first:

wrapping script1.s with “class Script <scriopt1.s content> end”
and doing Engine.Execute on it.

I expected to get a RubyObject as a result, which is the Script class.

then with the RubyObject i would do ObjectOperations.Invoke(“execute”);
when ever i wish.

I had 2 problems:

  1. the RubyObject was always null. any idea why?
  2. I couldn’t really define a global variable properly (i’ve used the $a
    =
    a trick from the forum)

eventually i’ve realized this solution:

  1. set global variable via RubyContext.DefineGlobalVariable
  2. i run everything on my script scope and Execute script1.s directly
    given a ScriptScope
  3. do InvokeMember on the ScriptScope itself

from googling i’ve noticed the solution changed a lot along time.
so what is the proper way to do it?

Thanks!


Ironruby-core mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


Ironruby-core mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core


The information contained in this communication (including any
attachments hereto) is confidential and is intended solely for the
personal and confidential use of the individual or entity to whom
it is addressed. If the reader of this message is not the intended
recipient or an agent responsible for delivering it to the intended
recipient, you are hereby notified that you have received this
communication in error and that any review, dissemination, copying,
or unauthorized use of this information, or the taking of any
action in reliance on the contents of this information is strictly
prohibited. If you have received this communication in error,
please notify us immediately by e-mail, and delete the original
message. Thank you

Tomas, I wasn’t reading your snippet right, the execute automatically
executes…
But with the variable, you have to call it, I didn’t notice that in
your example you are actually calling it with () after you retrieve as
a var.
Sorry for the trouble. Works now, and is obvious why I was mistaken,
Thanks

Best Regards, Kevin

On Wed, Nov 11, 2009 at 2:28 PM, Tomas M.

GetVariable and Execute should do the same conversion. Could you
send the snippet that doesn’t work?

Tomas