views:

87

answers:

1

If I had a list of objects eg. List<Foo> where Foo has a couple of properties, could I then create one or more ironruby or ironpython scripts that run for each row.

Here is some pseudo code:

var items = new List<Foo>();
foreach(var item in items) {
   var pythonfunc = getPythonFunc("edititem.py");
   item = pythonfunc(item);
}

I need a dynamic way to modify the list where the code is stored in a db or file.

If you think there is a better way to do this, or have an alternative so that a custom routine can be written for a client that can extract the client-specific data out of a database (an export), please comment or leave a suggestion.

Thanks

+1  A: 

I've used this approach before, both saving IronPython scripts in a database and in files. The pattern I like is to store Python functions with names known by convention. In other words, if you are processing an object of type Foo, you might have a Python function named "foo_filter" in your .py file or table. Ultimately, you can execute a Python file and parse out the functions into a dictionary of function references.

A quick sample app...

Your foo class:

public class Foo {
    public string Bar { get; set; }
}

Setting up Foo and calling getPythonFunc(i);

var items = new List<Foo>() {
    new Foo() { Bar = "connecticut" },
    new Foo() { Bar = "new york" },
    new Foo() { Bar = "new jersey" }                    
};

items.ForEach((i) => { getPythonFunc(i); Console.WriteLine(i.Bar); });

A quick and dirty getPythonFun implementation... The ScriptXXX object graph should obviously be cached, as should the variables retrieved by GetVariable().

static void getPythonFunc(Foo foo) {

    ScriptRuntimeSetup setup = ScriptRuntimeSetup.ReadConfiguration();
    ScriptRuntime runtime = new ScriptRuntime(setup);
    runtime.LoadAssembly(Assembly.GetExecutingAssembly());
    ScriptEngine engine = runtime.GetEngine("IronPython");
    ScriptScope scope = engine.CreateScope();

    engine.ExecuteFile("filter.py", scope);

    var filterFunc = scope.GetVariable("filter_item");
    scope.Engine.Operations.Invoke(filterFunc, foo);
}

The contents of filter.py:

def filter_item(item):
    item.Bar = item.Bar.title()

A simple way to apply rules based on a property (not the addition of the Size property on Foo):

var items = new List<Foo>() {
    new Foo() { Bar = "connecticut", Size = "Small" },
    new Foo() { Bar = "new york", Size = "Large" },
    new Foo() { Bar = "new jersey", Size = "Medium" }
};

Change the line in getPythonFun() that calls ScriptScope's GetVariable():

var filterFunc = scope.GetVariable("filter_" + foo.Size.ToLower());

And the new contents of filter.py

def filter_small(item):
    item.Bar = item.Bar.lower()

def filter_medium(item):
    item.Bar = item.Bar.title()

def filter_large(item):
    item.Bar = item.Bar.upper()

I have a bunch of more complete samples available at http://www.codevoyeur.com/Articles/Tags/ironpython.aspx.

John Zablocki
Thats wicked awesome! thanks!
Schotime
It's the least I could do for a NoRM contributer...
John Zablocki