image[2]

Esse é o terceiro post sobre como rodar Ruby no .Net, com IronRuby, e integrado ao C#. Estou usando o Visual Studio 2010 que é onde as coisas funcionam mais bem integradas, mas o primeiro post dá pra trabalhar ainda com o Visual Studio 2008. Os posts anteriores estão aqui:

  1. Rodando Ruby com C#: Parte 1
  2. Rodando Ruby com C#: Parte 2 – chamando uma classe Ruby no C#

No primeiro post eu mostrei como configurar o ambiente, e no post seguinte executamos código Ruby via .Net, inclusive passando parâmetros, e pegamos o retorno e utilizamos no C#. Utilizamos classes Ruby no C# normalmente com as novas capacidades dinâmicas do C# 4.

Neste post vou mostrar como fazer o contrário: tenho uma classe no C# que quero ser capaz de chamar a partir do Ruby. Isso é possível, vamos ver como.

Primeiro vou definir a classe que quero chamar do C#. Segue o mesmo molde das classes de antes, ela tem só um método que recebe dois parâmetros, e retorna uma string de acordo com os argumentos recebidos:

public class Teste
{
    public string Chamar(bool flag, string texto)
    {
        return flag ?
            texto + "sufixo" :
            texto;
    }
}

Quero chamar o método “Chamar” desta classe a partir do Ruby. Para poder fazer isso, preciso dizer pra ele referenciar minha dll de alguma forma. No Ruby, a maneira que você usa pra ele acessar outros arquivos Ruby é com a palavra chave “require”. Se você escrever “require MeuArquivo” o Ruby vai tentar encontrar o arquivo “MeuArquivo.rb” nos diretórios especificados na variável $LOAD_PATH, que normalmente inclui o diretório local (.). Pra saber quais são esses diretórios basta inspecionar a variável:

Console Ruby

No IronRuby, além de procurar arquivos .rb, o require vai procurar também dlls. Então você precisa acrescentar uma linha de require com o nome da sua DLL.

O código Ruby então fica assim:

require 'IronRubyNetFX4Test1'
IronRubyNetFX4Test1::Teste.new

Na primeira linha eu referencio meu assembly de testes, que é chamado IronRubyNetFX4Test1.dll. Na linha seguinte eu crio a classe Teste que havia especificado. Notem que os dois pontos duplos :: separaram a especificação do namespace e da classe. Como no Ruby a última linha sempre retorna o resultado, a classe Teste do C# está sendo retornada. O objeto retornado é entendido pelo C# como um objeto dinâmico, e pode ser chamado. Vejam o teste todo:

[TestMethod]
public void ConsigoCriarUmObjetoDotNetEChamarUmMetodoDinamicamenteUsandoONomeCompletoDoTipoEVariavelDinamica()
{
    var source = @"
        require 'IronRubyNetFX4Test1'
        IronRubyNetFX4Test1::Teste.new";

    var scriptSource = _defaultScriptEngine.CreateScriptSourceFromString(source);
    var teste = scriptSource.Execute();
    var resultado = teste.Chamar(true, "ttt");
    Assert.AreEqual("tttsufixo", resultado);
}

Mas eu poderia fazer um cast do retorno, já que o tipo retornado é um tipo .Net, e usá-lo normalmente:

[TestMethod]
public void ConsigoCriarUmObjetoDotNetEChamarUmMetodoDinamicamenteUsandoONomeCompletoDoTipoEVariavelEstatica()
{
    var source = @"
        require 'IronRubyNetFX4Test1'
        IronRubyNetFX4Test1::Teste.new";

    var scriptSource = _defaultScriptEngine.CreateScriptSourceFromString(source);
    var teste = (Teste)scriptSource.Execute();
    var resultado = teste.Chamar(true, "ttt");
    Assert.AreEqual("tttsufixo", resultado);
}

Faz mais sentido, se eu sei que o retorno é um tipo conhecido do C#.

O Ruby tem ainda uma palavra chave que faz a importação do namespace, semelhante ao “using” do C#, é o “include”. E nós podemos usá-la também:

[TestMethod]
public void ConsigoCriarUmObjetoDotNetEChamarUmMetodoDinamicamenteUsandoOInclude()
{
    var source = @"
        require 'IronRubyNetFX4Test1'
        include IronRubyNetFX4Test1
        Teste.new";
    var scriptSource = _defaultScriptEngine.CreateScriptSourceFromString(source);
    var teste = scriptSource.Execute();
    var resultado = teste.Chamar(true, "ttt");
    Assert.AreEqual("tttsufixo", resultado);
}

Com isso, fecho os exemplos do Ruby chamando o C#. Já conseguimos fazer código Ruby chamar C#, e vice-versa. A seguir vou mostrar alguns cenários onde penso que isso pode ser útil. Em breve.

Giovanni Bassi

Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.