Desenvolvimento - C#

Integração C# + Ruby

A linguagem Ruby vem ganhando muito espaço no mercado, talvez a linguagem dinâmica mais badalada atualmente, mas o objetivo do artigo não é ensinar Ruby, vuo mostrar como podemos integrar o C# com o Ruby.

por Márcio Fábio Althmann



A linguagem Ruby vem ganhando muito espaço no mercado, talvez a linguagem dinâmica mais badalada atualmente, mas o objetivo do artigo não é ensinar Ruby, vuo mostrar como podemos integrar o C# com o Ruby.

Como não vou ensinar Ruby aqui, vou deixar aqui uma dica de quem considero referência quando o assunto é .NET + Ruby, que é o site do Vinicius Quaiato, ele também está estudando bastante o assunto, e sempre conversamos a respeito. Muito do que mostrarei aqui ele postou no blog dele, e claro tenho autorização do mesmo para utilizar alguns códigos dele aqui.

Eu sempre pensei que algumas partes dos softwares que desenvolvemos, deveriam ser mais flexíveis, o que eu quero dizer como flexível é o usuário, ou alguém de um setor de suporte, ou mesmo desenvolvedores, alterarem uma regra de negócio da aplicação sem precisar recompilar o software, abrir o Visual Studio e por ai vai.

Não vou entra no mérito da questão se o usuário vai entender o código, vai saber o que escrever, não vem ao caso, criar um parser de ruby ou outra linguagem para algo mais simples não é tão complicado.

Chega de falar, e vamos ao que interessa.

O primeiro passo é instalar o IronRuby.

Depois de instalado, referênciar as 3 .dll´s abaixo, que ficam no diretório bin da instalação do IronRuby.

  • IronRuby.dll
  • IronRuby.Libraries.dll
  • Microsoft.Scripting.dll

A primeira classe que temos é chamada de EngineRuby que utiliza o padrão Singleton para armazenar uma instância da classe ScriptEngine que está disponível no namespace Microsoft.Scripting.Hosting.

A classe EngineRuby também tem um método ObterObjeto que recebe como parâmetro o nome do arquivo Ruby que contém a classe feita em Ruby que vamos utilizar, e o nome da classe feita com Ruby. Esse método retorna um tpo dinâmico do C#, atenção a keyword dynamic.

Para facilitar o entendimento, a idéia é ter uma pasta chamada Ruby no diretório da aplicação onde vamos armazenar os arquivos .rb do Ruby.

01public static class EngineRuby
02{
03private static ScriptEngine rubyEngine;
04
05private static ScriptEngine CriarEngine()
06{
07if(rubyEngine == null)
08rubyEngine = Ruby.CreateEngine();
09
10return rubyEngine;
11}
12
13public static dynamic ObterObjeto(string nomeDoArquivo, string nomeDaClasse)
14{
15var diretorioDaAplicacao = Path.GetDirectoryName(typeof (EngineRuby).Assembly.Location);
16var arquivo = Path.Combine(diretorioDaAplicacao, String.Format("Ruby\\{0}.rb", nomeDoArquivo));
17
18CriarEngine().ExecuteFile(arquivo);
19dynamic objeto = CriarEngine().Runtime.Globals.GetVariable(nomeDaClasse);
20return CriarEngine().Operations.CreateInstance(objeto);
21}
22}

Bom, antes de continuar vamos falar do arquivo Ruby, para desenvolvedor códigos em Ruby, eu utilizo o RubyMine da JetBrains. É o melhor editor que encontrei até o momento.

O código é simples, uma classe chamada Boletim que possui um método Media. Passo para o método nota para os 4 bimestres, e divido a soma por 4, uma média simples, o que faremos no decorrer do artigo é alterar essa regra de calculo da média diretamente pelo aplicativo de exemplo.

Segue o código.

1class Boletim
2def Media(primeiroBimestre, segundoBimestre, terceiroBimestre, quartoBimestre)
3(primeiroBimestre + segundoBimestre + terceiroBimestre + quartoBimestre) / 2
4end
5end

Agora teremos uma classe Boletim escrita em C#, que vai armazenar algumas informações como o nome do arquivo Ruby referente, e o nome da classe em Ruby.

01public class Boletim
02{
03private static string NomeDaClasse = "Boletim";
04private static string NomeDoArquivo = "Boletim";
05
06private static dynamic Objeto
07{
08get
09{
10return EngineRuby.ObterObjeto(NomeDoArquivo, NomeDaClasse);
11}
12}
13
14public static double Media(double primeiroBimestre, double segundoBimestre, double terceiroBimestre, double quartoBimestre)
15{
16return Objeto.Media(primeiroBimestre, segundoBimestre, terceiroBimestre, quartoBimestre);
17}
18}