Ruby|Python в браузере, сделай сам

Зачем?

sidebar_gestaltКлиентскую часть в веб-приложениях принято создавать на JavaScript. Я считаю, что большинство разработчиков с огромным удовольствием бы отошли от этого правила и воспользовались своим любимым server-side языком. Ну что же, команда MIX Online предоставила любителям динамических языков такую возможность, подробнее об этом можно прочитать в “Проект Gestalt – пишите на Ruby, Python и XAML прямо в HTML на стороне клиента”. Ниже я предлагаю создать нечто подобное, но уже своими силами.

С помощью чего?

Посмотрев несколько примеров мне стало ясно, что реализован Gestalt на Silverlight + Dynamic Languages Runtime. Далее я прикинул, а на сколько сложно создать нечто своими руками? И сразу же решение: Silverlight умеет  взаимодействовать с DOM – значит я смогу получить код и интерпритировать его – дело за малым – реализация.

Приступим

Нам понадобятся:

  • Visual Studio >2008SP1 (при желании можно и другие IDE или средства редактирования текста)
  • Silverlight >2.0 Tools
  • Dynamic Languages SDK >0.5.0 (download)
  • 10 мин времени

Lets code

image

Открываем Visual Studio, создаём Silverlight Application, я назову проект “mygestalt”. Теперь я осознаю, что писать та надо будет совсем не много, мне понадобится экспериментальный Client-Script и его интерпритатор. Открываем страничку, на которой будет хоститься наш Silverlight, в моём случаем это mygestaltTestPage.aspx и добавляем туда наш client-side python code. Выглядеть это должно примерно так:

  1. <script type="python">
  2. def func():
  3.     HtmlPage.Window.Alert("Hello world!")
  4.    
  5. func()
  6. </script>

* This source code was highlighted with Source Code Highlighter.

Далее отправляемся в MainPage.xaml.cs, где будем заниматься поисками нашего скрипта:

  1. using System.Linq;
  2. using System.Windows.Browser;
  3.  
  4. namespace mygestalt
  5. {
  6.   public partial class MainPage
  7.   {
  8.     public MainPage()
  9.     {
  10.       InitializeComponent();
  11.       FindAndRunScript();
  12.     }
  13.  
  14.     private void FindAndRunScript()
  15.     {
  16.       var scripts = HtmlPage.Document.GetElementsByTagName("script");
  17.       var pythonScript = scripts.Where(x => x.GetProperty("type").ToString() == "python").First();
  18.       PythonEngine.Run(pythonScript.GetProperty("innerHtml").ToString());
  19.     }
  20.   }
  21. }

* This source code was highlighted with Source Code Highlighter.

Ну и реализация PythonEngine:

  1. using Microsoft.Scripting;
  2. using Microsoft.Scripting.Hosting;
  3. using Microsoft.Scripting.Silverlight;
  4.  
  5. namespace mygestalt
  6. {
  7.   public static class PythonEngine
  8.   {
  9.     public static ScriptScope Run(string source)
  10.     {
  11.       var setup = Configuration.LoadFromAssemblies(Package.GetManifestAssemblies());
  12.       setup.HostType = typeof(BrowserScriptHost);
  13.       setup.DebugMode = true;
  14.       var runtime = new ScriptRuntime(setup);
  15.       var engine = runtime.GetEngine("IronPython");
  16.       var scope = engine.CreateScope();
  17.       const string init = @"
  18. import clr
  19. clr.AddReference('System.Windows.Browser')
  20.  
  21. from System.Windows.Browser import *
  22.  
  23. "
  24. ;

  25.  
  26.       ScriptSource initSource = engine.CreateScriptSourceFromString(init, SourceCodeKind.Statements);
  27.       initSource.Execute(scope);
  28.       var script = engine.CreateScriptSourceFromString(source, SourceCodeKind.Statements);
  29.       script.Execute(scope);
  30.  
  31.       return scope;
  32.     }
  33.   }
  34. }

* This source code was highlighted with Source Code Highlighter.

Запускаем приложение и видим:

image

 

 

 

 

В заключение

Вот у нас и получился свой собственный Gestalt, самое интересное в том, что я посмотрел его исходники и нашёл там примерно такую же реализацию.

Мой проект можно найти на http://code.google.com/p/mygestalt/.

Всем спасибо!


Парсинг Get запроса и по значению параметра Category выбор в DropDownList

<script language=«javascript»>
var ddlist = document.getElementById(«ctl00_PlaceHolderMain_InitiationForm_ddlist»);

for (var i = 0; i < ddlist.length; i++) {

if (ddlist.options[i].text == decodeURIComponent(getQueryStringParam(«Category»)))
ddlist.options[i].selected = true;
}

function getQueryStringParam(name) {
name = name.replace(/[\[]/, «\\\[«).replace(/[\]]/, «\\\]»);
var regexS = «[\\?&]» + name + «=([^&#]*)»;
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);

if (results == null)
return «»;
else
return results[1];
}

</script>