Re: [Rubydotnet-developer] Getting necessary metadata on Ruby classes for externalization...
Status: Alpha
Brought to you by:
thomas
From: Thomas S. <th...@th...> - 2003-07-22 02:57:25
|
The type declarations would only be necessary if you wanted to define new types in ruby and make them available to other .net classes. With the type annotations you could run a utility, lets call it genWrapperAssembly.rb, that loads your ruby library and generates a .net assembly defining .net wrappers for all your the ruby types. These wrappers would then call into ruby. This would be a useful addition to the interop/bridge at some point, but it is not high on my own priority list. After all, it is possible to do subclassing and interface implementation without doing any of this - it is only if you want to define new types in ruby. Cheers Thomas ---------- Original Message ----------- From: "John R. Pierce" <jo...@pi...> To: rub...@li... Sent: Mon, 21 Jul 2003 08:29:06 -0700 (PDT) Subject: Re: [Rubydotnet-developer] Getting necessary metadata on Ruby classes for externalization... > I'd have to see the .NET calling code to help me see how annotating the > parameter types enables the bridge to work or work better than not annotating > param types. > > I can see how one would need to annotate the return type so that as > the method returns out of Ruby I don't always have to downcast the > return type from object to whatever, but, when it comes to sending > parameters, ruby doesn't care if it gets an object type and, > generally, I don't see the need to enforce a compiler check on > parameter types. That's what unit tests are for. > > Regards, > > John > > On Fri, 18 Jul 2003 23:54:29 -0400, Richard Kilmer wrote: > > > > > All, > > > > I did not quite know where to post this, and I hope this list is ok... > > > > I have been thinking a bit on how to allow a developer to annotate > > their class's methods with parameter types when used externally by > > statically typed languages (Java, C#, SOAP). I want to present a > > syntax, and at the bottom have the code to back it up. > > > > Given the following class: > > > > class Account > > def Account.open(first, last) > > end > > def close > > end > > def add(money) > > end > > def remove(money) > > end > > def transfer(money, account) > > end > > end > > > > And assuming you wanted to make that accessible for statically typed > > systems you would just do this: > > > > require 'extern' > > > > class Account > > extern :Account.open, :return[Account], :first[String], :last[String] > > def Account.open(first, last) > > end > > > > extern :close > > def close > > end > > > > extern :add, :money[Float] > > def add(money) > > end > > > > extern :remove, :money[Float] > > def remove(money) > > end > > > > extern :transfer, :money[Float], :account[Account] > > def transfer(money, account) > > end > > end > > > > So, for each method you want to externalize you just include the > > 'extern' call. > > > > Usage: extern <method symbol>, [ [<:return[Classname]>], > > <:param[Classname]>, ... ] > > > > To reflect on this metadata you do: > > > > Account.each_externalized_method do | method | > > puts method.to_s > > end > > > > Which outputs: > > > > Account Account.open(String first, String last) > > NilClass close() > > NilClass add(Float money) > > NilClass remove(Float money) > > NilClass transfer(Float money, Account account) > > > > You can, of course, inspect the method (ExternalMethodDefinition > > instance) instead of printing it out. So this creates a runtime > > structure to store type information about methods, which again is > > useful is you want to bridge .NET to Ruby at the level of having a CLR > > type subclass a Ruby class, or generate a CLR type that represents a > > Ruby class. > > > > Of course, since Ruby's classes are open, you can define this extern > > metadata on existing classes: > > > > class ThreadGroup > > extern :ThreadGroup.new, :return[ThreadGroup] > > extern :add, :return[ThreadGroup], :thread[Thread] > > extern :list, :return[Array] > > end > > > > So what do folks think about the syntax? > > > > -rich > > > > PS...here is the magic code that makes this syntax work: > > > > ________ BEGIN 'extern.rb' _________ > > > > class ExternalMethodDefinition > > attr_accessor :klass, :name, :return_type > > Parameter = Struct.new(:name, :type) > > @@definitions = Hash.new([]) > > > > def self.[](klass) > > @@definitions[klass] > > end > > > > def initialize(klass, name, *parameters) > > list = @@definitions[klass] > > unless list > > list = [] > > @@defintions[klass] = list > > end > > list << self > > @klass = klass > > @name = name.to_s > > @name.gsub!(/__/, '.') > > @parameters = [] > > parameters.each do |param| > > if param.name=="return" > > @return_type = param.type > > else > > @parameters << param > > end > > end > > @return_type = NilClass unless @return_type > > end > > > > def add_parameter(name, type) > > unless type.kind_of?(Class) > > raise "Parameter #{name}'s type on method '#{@name}' of class > > '#{@klass}' must be a Ruby class" > > end > > if name == :return > > @return_type = type > > else > > @parameters << Parameter.new(name.to_s, type) > > end > > end > > > > def each_parameter > > @parameters.each {|param| yield param} > > end > > > > def to_s > > params = (@parameters.collect {|param| param.type.to_s+' > > '+param.name}).join(', ') > > return "#{@return_type.to_s} #{@name}(#{params})" > > end > > end > > > > class Symbol > > def [](klass=nil) > > if klass > > ExternalMethodDefinition::Parameter.new(self.to_s, klass) > > else > > (self.to_s+"__[]").intern > > end > > end > > > > def method_missing(method, *args, &block) > > if (?A..?Z).member?(self.to_s[0]) > > return (self.to_s+"__"+method.to_s).intern > > end > > super > > end > > end > > > > class Module > > def extern(method, *parameters) > > ExternalMethodDefinition.new(self, method, *parameters) > > end > > > > def each_externalized_method > > ExternalMethodDefinition[self].each { |exdef| yield exdef } > > end > > end > > > > ------ END 'extern.rb' ------ > > > > > > > > ------------------------------------------------------- > > This SF.net email is sponsored by: VM Ware > > With VMware you can run multiple operating systems on a single machine. > > WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines at the > > same time. Free trial click here: http://www.vmware.com/wl/offer/345/0 > > _______________________________________________ > > Rubydotnet-developer mailing list > > Rub...@li... > > https://lists.sourceforge.net/lists/listinfo/rubydotnet-developer > > ------------------------------------------------------- > This SF.net email is sponsored by: VM Ware > With VMware you can run multiple operating systems on a single machine. > WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines at the > same time. Free trial click here: > http://www.vmware.com/wl/offer/345/0 _______________________________________________ > Rubydotnet-developer mailing list > Rub...@li... > https://lists.sourceforge.net/lists/listinfo/rubydotnet-developer ------- End of Original Message ------- |