tags:

views:

102

answers:

1

Hi,

I am trying to create a Dsl which will have instances that live in individual Dsl .rb files and then run them from the CLR.

I want to create and set the values of the Clr object in IronRuby and then somehow have access to the CLR object after the .rb Dsl instance file has run.

Here is my Clr object which is very simple at the moment:

namespace Horn.Core.Dsl
{
    public class BuildMetaData : IBuildMetaData
    {
        public string Description { get; set; }
    }
}

I have the following module which I am using to specify my Dsl and which will create an instance of the BuildMetaData specified above:

module MetaBuilder
  module Dsl
    module Main
      attr_accessor :metadata
      def install(name, &block)
        @metadata = Horn::Core::Dsl::BuildMetaData.new
        yield self if block_given?
      end

      def description(desc)
         @metadata.Description = desc
      end

      def get_metadata
          @metadata
      end

    end
  end
end

include MetaBuilder::Dsl::Main

I somehow want to be able to get the @metadata property from the Clr code after an instance of the Dsl has ran.

An instance of the Dsl looks like this currently:

install :horn do
  description "A .NET build and dependency manager"
end

My C# code looks like this currently:

var engine = Ruby.CreateEngine();
engine.Runtime.LoadAssembly(typeof(BuildMetaData).Assembly);
engine.ExecuteFile(buildFile);
var klass = engine.Runtime.Globals.GetVariable("get_metadata");

Is there anyway I can get at the @metadata property without having to pollute the Dsl instance?

Thanks in advance

Paul

+1  A: 

Hi,

For anyone who is interested, I managed to solve this by creating a singleton to house an instance of the BuildMetaData class.

My Ruby code ended up looking like this:

module MetaBuilder
  module Dsl
    module Main

      def install(name, &block)
        yield self if block_given?
      end

      def get_from(name, url)
        puts name
        puts url
      end

      def description(desc)
         meta.metadata.Description = desc
      end

      class MetaDataAccessor
        attr_accessor :metadata

        private
        def initialize
          @metadata = Horn::Core::Dsl::BuildMetaData.new
        end

        public
        def self.instance
          @@instance ||= new
        end

        def self.get_metadata
            @metadata
        end
      end
    end
  end
end

def meta
  MetaBuilder::Dsl::Main::MetaDataAccessor.instance
end

class ClrAccessor
  def get_build_metadata
    meta.metadata
  end
end

include MetaBuilder::Dsl::Main

I created the MetaDataAccessor to keep a singleton BuildMetaData instance.

I could not work out the C# code to access a fully qualified class that is nested in between modules so I created the ClrAccessor class to provide access from the Clr.

My C# code ended up looking like this:

var engine = Ruby.CreateEngine();
engine.Runtime.LoadAssembly(typeof(BuildMetaData).Assembly);
engine.ExecuteFile(buildFile);
var klass = engine.Runtime.Globals.GetVariable("ClrAccessor");
var instance = engine.Operations.CreateInstance(klass);
buildMetaData = (BuildMetaData)engine.Operations.InvokeMember(instance, 
"get_build_metadata");

I am fairly sure there is an easier way but for me it is progress.

Any input into this "round the houses" approach would be appreciated.

Cheers

Paul

dagda1