- Orchard.Scripting namespace to manage ruby scripts.

- ScriptManager/ScriptRuntime implementations.
- Unit Tests.
- Adding IronRuby.dll, IronRuby.Libraries.dll, Microsoft.Dynamic.dll and Microsoft.Scripting.dll.

--HG--
branch : dev
This commit is contained in:
Suha Can
2010-10-01 16:33:16 -07:00
parent 36ebf9a95b
commit 5fca0e53e3
12 changed files with 229 additions and 1 deletions

View File

@@ -83,7 +83,21 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\fluentnhibernate\FluentNHibernate.dll</HintPath>
</Reference>
<Reference Include="IronRuby, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\dlr\IronRuby.dll</HintPath>
</Reference>
<Reference Include="IronRuby.Libraries">
<HintPath>..\..\lib\dlr\IronRuby.Libraries.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Dynamic, Version=1.1.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\dlr\Microsoft.Dynamic.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Scripting">
<HintPath>..\..\lib\dlr\Microsoft.Scripting.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\moq\Moq.dll</HintPath>
@@ -229,6 +243,7 @@
<Compile Include="Mvc\Routes\ShellRouteTests.cs" />
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
<Compile Include="Records\BigRecord.cs" />
<Compile Include="Scripting\ScriptingTests.cs" />
<Compile Include="Stubs\StubReportsCoordinator.cs" />
<Compile Include="Stubs\StubVirtualPathProvider.cs" />
<Compile Include="Stubs\StubFileSystem.cs" />

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using Autofac;
using ClaySharp;
using ClaySharp.Behaviors;
using NUnit.Framework;
using Orchard.Scripting;
namespace Orchard.Tests.Scripting {
[TestFixture]
public class ScriptingTests {
private IContainer _container;
private IScriptingRuntime _scriptingRuntime;
private IScriptingManager _scriptingManager;
private string _tempFolderName;
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
builder.RegisterType<ScriptingRuntime>().As<IScriptingRuntime>();
builder.RegisterType<ScriptingManager>().As<IScriptingManager>();
_container = builder.Build();
_scriptingRuntime = _container.Resolve<IScriptingRuntime>();
_scriptingManager = _container.Resolve<IScriptingManager>();
_tempFolderName = Path.GetTempFileName();
File.Delete(_tempFolderName);
Directory.CreateDirectory(_tempFolderName);
}
[TearDown]
public void Term() {
Directory.Delete(_tempFolderName, true);
}
[Test]
public void GetRubyEngineReturnsAWorkingRubyEngine() {
var ruby = _scriptingRuntime.GetRubyEngine();
Assert.IsNotNull(ruby);
Assert.That(ruby.Execute("21 + 21"), Is.EqualTo(42));
}
[Test]
public void ScriptingManagerCanGetAndSetRubyVariables() {
_scriptingManager.SetVariable("foo", 42);
Assert.That(_scriptingManager.GetVariable("foo"), Is.EqualTo(42));
}
[Test]
public void ScriptingManagerCanEvalExpression() {
_scriptingManager.SetVariable("foo", 21);
Assert.That(_scriptingManager.Eval("foo + 21"), Is.EqualTo(42));
}
[Test]
public void ScriptCanBeExecutedAndScopeProvidesContextIsolation() {
var scriptManager1 = new ScriptingManager(_scriptingRuntime);
var scriptManager2 = new ScriptingManager(_scriptingRuntime);
scriptManager1.SetVariable("foo", 1);
scriptManager2.SetVariable("foo", 2);
var result1 = scriptManager1.Eval("3 + foo");
var result2 = scriptManager2.Eval("3 + foo");
Assert.That(result1, Is.EqualTo(4));
Assert.That(result2, Is.EqualTo(5));
}
[Test]
public void ScriptingManagerCanExecuteFile() {
var targetPath = Path.Combine(_tempFolderName, "SampleMethodDefinition.rb");
File.WriteAllText(targetPath, "def f\r\nreturn 32\r\nend\r\n");
_scriptingManager.ExecuteFile(targetPath);
Assert.That(_scriptingManager.Eval("f / 4"), Is.EqualTo(8));
}
[Test]
public void GlobalObjectCanBeDynamic() {
dynamic global = new Clay(new PropBehavior());
_scriptingManager.SetScriptingScope(_scriptingRuntime.GetRubyEngine().CreateScope((IDynamicMetaObjectProvider)global));
global.foo = 5;
Assert.That(_scriptingManager.Eval("3 + foo"), Is.EqualTo(8));
}
[Test]
public void CanDeclareCallbackOnGlobalMethod() {
_scriptingManager.SetVariable("x", new Clay(new ReturnMethodNameLengthBehavior()));
Assert.That(_scriptingManager.Eval("3 + x.foo()"), Is.EqualTo(6));
}
public class ReturnMethodNameLengthBehavior : ClayBehavior {
public override object InvokeMemberMissing(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
Trace.WriteLine("Returning length of " + name);
return name.Length;
}
}
[Test]
public void CanDeclareCallbackOnInstanceEvalWithFile() {
var targetPath = Path.Combine(_tempFolderName, "CallbackOnInstanceEval.rb");
File.WriteAllText(targetPath, "class ExecContext\r\ndef initialize(callbacks)\r\n@callbacks = callbacks;\r\nend\r\ndef execute(text)\r\ninstance_eval(text.to_s);\r\nend\r\ndef method_missing(name, *args, &block)\r\n@callbacks.send(name, args, &block);\r\nend\r\nend\r\ndef execute(&block)\r\nExecContext.new(callbacks).instance_eval(&block);\r\nend\r\n");
_scriptingManager.ExecuteFile(targetPath);
_scriptingManager.SetVariable("callbacks", new CallbackApi());
Assert.That(_scriptingManager.Eval("execute { 1 + hello + world('yep') }"), Is.EqualTo(11));
}
public class CallbackApi {
public object send(string name, IList<object> args) {
Trace.WriteLine("Returning length of method " + name);
return name.Length;
}
}
}
}

View File

@@ -3,4 +3,4 @@
namespace Orchard.Widgets.Models {
public class WidgetPart : ContentPart<WidgetPartRecord> {
}
}
}

View File

@@ -89,7 +89,19 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\sharpziplib\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="IronRuby">
<HintPath>..\..\lib\dlr\IronRuby.dll</HintPath>
</Reference>
<Reference Include="IronRuby.Libraries">
<HintPath>..\..\lib\dlr\IronRuby.Libraries.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Dynamic">
<HintPath>..\..\lib\dlr\Microsoft.Dynamic.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Scripting">
<HintPath>..\..\lib\dlr\Microsoft.Scripting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\Microsoft.WebPages.dll</HintPath>
@@ -158,6 +170,10 @@
<Compile Include="Mvc\IOrchardViewPage.cs" />
<Compile Include="Mvc\Spooling\HtmlStringWriter.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngine.cs" />
<Compile Include="Scripting\IScriptingManager.cs" />
<Compile Include="Scripting\IScriptingRuntime.cs" />
<Compile Include="Scripting\ScriptingManager.cs" />
<Compile Include="Scripting\ScriptingRuntime.cs" />
<Compile Include="Security\CurrentUserWorkContext.cs" />
<Compile Include="Settings\CurrentSiteWorkContext.cs" />
<Compile Include="Settings\ResourceDebugMode.cs" />

View File

@@ -0,0 +1,11 @@
using Microsoft.Scripting.Hosting;
namespace Orchard.Scripting {
public interface IScriptingManager : IDependency {
dynamic GetVariable(string name);
void SetVariable(string name, object value);
dynamic Eval(string expression);
void ExecuteFile(string fileName);
void SetScriptingScope(ScriptScope scriptScope);
}
}

View File

@@ -0,0 +1,7 @@
using Microsoft.Scripting.Hosting;
namespace Orchard.Scripting {
public interface IScriptingRuntime : ISingletonDependency {
ScriptEngine GetRubyEngine();
}
}

View File

@@ -0,0 +1,38 @@
using Microsoft.Scripting.Hosting;
namespace Orchard.Scripting {
public class ScriptingManager : IScriptingManager {
private readonly IScriptingRuntime _scriptingRuntime;
private ScriptScope _scriptingScope;
public ScriptingManager(IScriptingRuntime scriptingRuntime) {
_scriptingRuntime = scriptingRuntime;
_scriptingScope = _scriptingRuntime.GetRubyEngine().CreateScope();
}
#region IScriptingContext Members
public dynamic GetVariable(string name) {
return _scriptingScope.GetVariable(name);
}
public void SetVariable(string name, object value) {
_scriptingScope.SetVariable(name, value);
}
public dynamic Eval(string expression) {
var script = _scriptingRuntime.GetRubyEngine().CreateScriptSourceFromString(expression);
return script.Execute(_scriptingScope);
}
public void ExecuteFile(string fileName) {
_scriptingRuntime.GetRubyEngine().ExecuteFile(fileName, _scriptingScope);
}
public void SetScriptingScope(ScriptScope scriptScope) {
_scriptingScope = scriptScope;
}
#endregion
}
}

View File

@@ -0,0 +1,18 @@
using IronRuby;
using Microsoft.Scripting.Hosting;
namespace Orchard.Scripting {
public class ScriptingRuntime : IScriptingRuntime {
private readonly ScriptRuntime _scriptingRuntime;
public ScriptingRuntime() {
var setup = new ScriptRuntimeSetup();
setup.LanguageSetups.Add(Ruby.CreateRubySetup());
_scriptingRuntime = new ScriptRuntime(setup);
}
public ScriptEngine GetRubyEngine() {
return _scriptingRuntime.GetEngine("ruby");
}
}
}