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.
public static class EngineRuby
{
private static ScriptEngine rubyEngine;
private static ScriptEngine CriarEngine()
{
if(rubyEngine == null)
rubyEngine = Ruby.CreateEngine();
return rubyEngine;
}
public static dynamic ObterObjeto(string nomeDoArquivo, string nomeDaClasse)
{
var diretorioDaAplicacao = Path.GetDirectoryName(typeof (EngineRuby).Assembly.Location);
var arquivo = Path.Combine(diretorioDaAplicacao, String.Format("Ruby\\{0}.rb", nomeDoArquivo));
CriarEngine().ExecuteFile(arquivo);
dynamic objeto = CriarEngine().Runtime.Globals.GetVariable(nomeDaClasse);
return CriarEngine().Operations.CreateInstance(objeto);
}
}
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.
class Boletim
def Media(primeiroBimestre, segundoBimestre, terceiroBimestre, quartoBimestre)
(primeiroBimestre + segundoBimestre + terceiroBimestre + quartoBimestre) / 4
end
end
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.
public class Boletim
{
private static string NomeDaClasse = "Boletim";
private static string NomeDoArquivo = "Boletim";
private static dynamic Objeto
{
get
{
return EngineRuby.ObterObjeto(NomeDoArquivo, NomeDaClasse);
}
}
public static double Media(double primeiroBimestre, double segundoBimestre, double terceiroBimestre, double quartoBimestre)
{
return Objeto.Media(primeiroBimestre, segundoBimestre, terceiroBimestre, quartoBimestre);
}
}
Bom para quem viu o artigo do Vinicius Quaiato, eu modifiquei a propriedade Objeto, no caso dele, novamente ele utilizar o padrão Singleton eu não faço isso aqui por que quero alterar o código Ruby rodando meu aplicativo, e a próxima vez que o mesmo for executado quero executar as alterações no código.
Agora a parte fácil, crio uma tela onde consigo informar as notas para cadas bimestre, um botão para calcular a média e mostro o restultando.
O código que é executado quando o botão Calcular é pressionado é simples.
private void button1_Click(object sender, RoutedEventArgs e)
{
txtMedia.Text = Boletim.Media(
double.Parse(txtPrimeiroBimestre.Text),
double.Parse(txtSegundoBimestre.Text),
double.Parse(txtTerceiroBimestre.Text),
double.Parse(txtQuartoBimestre.Text)
).ToString();
}
Reparem na imagem acima, que ao lado do botão Calcular tem outro botão, clicando nesse botão uma tela será aberta mostrando o código do arquivo Ruby que possui a regra para a média do boletim.
O código dessa tela é simples, segue o código completo, mas basicamente só possui leitura e escrita de arquivo
.
public partial class EditorDeCodigo : Window
{
public string NomeDoArquivo { get; set; }
public EditorDeCodigo()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
LerArquivo();
}
private void btnCancelar_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void btnGravarAlteracoes_Click(object sender, RoutedEventArgs e)
{
SalvarArquivo();
Close();
}
private string ObterArquivo()
{
var diretorioDaAplicacao = System.IO.Path.GetDirectoryName(typeof(EngineRuby).Assembly.Location);
return System.IO.Path.Combine(diretorioDaAplicacao, String.Format("Ruby\\{0}.rb", NomeDoArquivo));
}
private void LerArquivo()
{
using (var textReader = new StreamReader(ObterArquivo()))
{
txtCodigo.Text = textReader.ReadToEnd();
textReader.Close();
}
}
private void SalvarArquivo()
{
using (var textWriter = new StreamWriter(ObterArquivo()))
{
textWriter.Write(txtCodigo.Text);
textWriter.Close();
}
}
}
Abaixo imagem da edição do código Ruby durante a execução do aplicativo.
Acho que um vídeo é o ideal para mostrar a idéia funcionando, então vejam abaixo um pequeno vídeo com a execução do aplicativo.
Integração C# + Ruby from Márcio Fábio Althmann on Vimeo.
Essa foi uma pequena amostra de como podemos utilizar essa integração do C# + Ruby, o download da solução pode ser feito abaixo.
Abraços.




Pingback: IronPyton, IronRuby, DLR e o que isso influencia na minha vida:??: « Felipe Pedroti Raymundo