lib/rbplusplus/transformers/class.rb in rbplusplus-0.8 vs lib/rbplusplus/transformers/class.rb in rbplusplus-0.9

- old
+ new

@@ -1,7 +1,7 @@ module RbGCCXML - class Class + class Class < Node # Class can include nested classes and nested structs. # # Class can also include external methods/functions as class level methods # also supports instance level methods # @@ -9,59 +9,140 @@ # # math_class.includes node.namespaces("Math").functions("mod") # # or for a instance method: # - # math_class.includes node.namespaces("Math").functions("mod").as_method + # math_class.includes node.namespaces("Math").functions("mod").as_instance_method # # or for nesting a class/struct: # # math_class.includes node.namespaces("Math").classes("Degree") # def includes(val) if (val.is_a?(RbGCCXML::Struct) || val.is_a?(RbGCCXML::Class)) - @classes ||= [] - @classes << RbPlusPlus::NodeReference.new(val) + cache[:classes] ||= [] + cache[:classes] << val else - @methods ||= [] - @methods << RbPlusPlus::NodeReference.new(val) + cache[:methods] ||= [] + cache[:methods] << val end - val.moved=true + val.moved_to = self end + alias_method :node_classes, :classes + def classes(*args) #:nodoc: + find_with_cache(:classes, node_classes(*args)) + end + alias_method :node_methods, :methods def methods(*args) #:nodoc: - nodes = node_methods(*args) - methods = @methods || QueryResult.new - methods << cache(nodes) - methods.flatten! - return methods if args.empty? - return (methods.size == 1 ? methods[0] : methods) + find_with_cache(:methods, node_methods(*args)) end - alias_method :node_classes, :classes - def classes(*args) #:nodoc: - [@classes || [], node_classes].flatten + # Specify which superclass to use. + # Because Rice doesn't support multiple inheritance right now, + # we need to know which superclass Rice should use for this class. + # An error message will show on classes with mutiple superclasses + # where this method hasn't been used yet. + # + # klass should be the node for the class you want to wrap + def use_superclass(node) + cache[:use_superclass] = node end - - # returns a list of superclasses of this node, including the node's class - def super_classes - retv = [] - unless node.attributes['bases'].nil? || node.attributes['bases'] == "" - node.attributes['bases'].split.each do |cls_id| - c = XMLParsing.find(:type => "Class", :id => cls_id) - c = XMLParsing.find(:type => "Struct", :id => cls_id) if c.nil? - if c.nil? - puts "#{self.qualified_name} cannot find super class for id #{cls_id} " - next - end - c = RbPlusPlus::NodeCache.instance.get(c) - retv << c unless c.ignored? - end - end - - return retv + + def _get_superclass #:nodoc: + cache[:use_superclass] end - + + # Like #use_superclass, this method allows the user to specify + # which constructor Rice should expose to Ruby. + # Rice currently, because of the lack of method overloading, + # only supports one constructor definition. Having multiple + # in the code will work, but only the last defined will actually + # work. + def use_constructor(node) + cache[:use_constructor] = node + end + + def _get_constructor #:nodoc: + cache[:use_constructor] + end + + # Sometimes, type manipulation, moving nodes around, or flat + # ignoring nodes just doesn't do the trick and you need to write + # your own custom wrapper code. This method is for that. There are + # two parts to custom code: the declaration and the wrapping. + # + # The Declaration: + # This is the actual custom code you write. It may need to take + # a pointer to the class type as the first parameter + # and follow with that any parameters you want. + # + # The Wrapping + # The wrapping is the custom (usually one-line) bit of Rice code that + # hooks up your declaration with the class in question. To ensure that + # you doesn't need to know the variable of the ruby class object, + # use <class> and rb++ will replace it as needed. + # + # Example (taken from Ogre.rb's wrapping of Ogre) + # + # decl = <<-END + # int RenderTarget_getCustomAttributeInt(Ogre::RenderTarget* self, const std::string& name) { + # int value(0); + # self->getCustomAttribute(name, &value); + # return value; + # } + # END + # wrapping = "<class>.define_method(\"get_custom_attribute_int\", &RenderTarget_getCustomAttributeInt);" + # + # ogre.classes("RenderTarget").add_custom_code(decl, wrapping) + # + # This method works as an aggregator, so feel free to use it any number + # of times for a class, it won't clobber any previous uses. + # + def add_custom_code(declaration, wrapping) + cache[:declarations] ||= [] + cache[:declarations] << declaration + + cache[:wrappings] ||= [] + cache[:wrappings] << wrapping + end + + def _get_custom_declarations #:nodoc: + cache[:declarations] || [] + end + + def _get_custom_wrappings #:nodoc: + cache[:wrappings] || [] + end + + # Does this class have virtual methods (especially pure virtual?) + # If so, then rb++ will generate a proxy class to handle + # the message routing as needed. + def needs_director? #:nodoc: + !!cache[:build_director] #[methods].flatten.select {|m| m.virtual? }.length > 0 + end + + # Until all the kinks of the director code generation can be + # worked out, rb++ must be told which classes to build + # directors for. Simply call this method on the class to do so + def director + cache[:build_director] = true + end + + private + + # Take the cache key, and the normal results, adds to the results + # those that are in the cache and returns them properly. + def find_with_cache(type, results) + in_cache = cache[type] + + ret = QueryResult.new + ret << results if results + ret << in_cache if in_cache + ret.flatten! + + ret.size == 1 ? ret[0] : ret + end end end