rbplusplus 0.1.1 → 0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/Rakefile +31 -15
  2. data/TODO +20 -0
  3. data/lib/rbplusplus/builders/base.rb +148 -8
  4. data/lib/rbplusplus/builders/class.rb +106 -31
  5. data/lib/rbplusplus/builders/enumeration.rb +40 -0
  6. data/lib/rbplusplus/builders/extension.rb +31 -6
  7. data/lib/rbplusplus/builders/module.rb +12 -6
  8. data/lib/rbplusplus/builders/types_manager.rb +93 -0
  9. data/lib/rbplusplus/extension.rb +69 -41
  10. data/lib/rbplusplus/module.rb +3 -1
  11. data/lib/rbplusplus/transformers/class.rb +67 -0
  12. data/lib/rbplusplus/transformers/constructor.rb +4 -0
  13. data/lib/rbplusplus/transformers/function.rb +27 -0
  14. data/lib/rbplusplus/transformers/method.rb +4 -0
  15. data/lib/rbplusplus/transformers/module.rb +71 -0
  16. data/lib/rbplusplus/transformers/node.rb +77 -0
  17. data/lib/rbplusplus/transformers/node_cache.rb +19 -0
  18. data/lib/rbplusplus/transformers/node_reference.rb +30 -0
  19. data/lib/rbplusplus/transformers/rbgccxml.rb +6 -0
  20. data/lib/rbplusplus/writers/extension.rb +33 -25
  21. data/lib/rbplusplus/writers/multiple_files_writer.rb +42 -2
  22. data/lib/rbplusplus/writers/single_file_writer.rb +5 -0
  23. data/lib/rbplusplus.rb +24 -0
  24. data/test/class_methods_test.rb +55 -0
  25. data/test/classes_test.rb +0 -25
  26. data/test/compiling_test.rb +30 -0
  27. data/test/constructors_test.rb +40 -0
  28. data/test/enumerations_test.rb +63 -0
  29. data/test/file_writers_test.rb +56 -4
  30. data/test/generated/extconf.rb +25 -5
  31. data/test/headers/class_methods.h +41 -0
  32. data/test/headers/complex_static_methods.h +25 -0
  33. data/test/headers/constructors.h +47 -0
  34. data/test/headers/enums.h +77 -0
  35. data/test/headers/external_mapping.h +16 -0
  36. data/test/headers/external_mapping_rice.h +20 -0
  37. data/test/headers/include/helper.h +1 -0
  38. data/test/headers/nested_struct.h +20 -0
  39. data/test/headers/overload.h +28 -0
  40. data/test/headers/subclass.h +42 -0
  41. data/test/headers/to_from_ruby.h +78 -0
  42. data/test/headers/to_from_ruby_source.cpp +22 -0
  43. data/test/headers/ugly_helper.h +18 -0
  44. data/test/headers/ugly_interface.h +115 -0
  45. data/test/headers/ugly_interface_ns.h +8 -0
  46. data/test/nested_test.rb +26 -0
  47. data/test/object_persistence_test.rb +44 -0
  48. data/test/overloading_test.rb +36 -0
  49. data/test/struct_test.rb +22 -0
  50. data/test/subclass_test.rb +31 -0
  51. data/test/test_helper.rb +5 -0
  52. data/test/to_from_ruby_test.rb +24 -0
  53. data/test/wrap_as_test.rb +114 -0
  54. metadata +43 -6
@@ -0,0 +1,93 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # This is a singleton class that takes care of handling any to_ruby and from_ruby
5
+ # definitions this wrapper might need. This is pulled out seperate from other builders
6
+ # because of C++ coding and compiling restrictions. Mainly,
7
+ #
8
+ # 1. All cpp/hpp files where Rice needs to know about a given type needs to know about any to_/from_ruby definitions of that type
9
+ # 2. The actual definition of these methods can only be in one place or we get compiler redefinition errors.
10
+ class TypesManager
11
+ include Singleton
12
+
13
+ # Forward off all calls to the singleton instance of this method.
14
+ # This allows one to use this class as if it's a bunch of class methods. E.g.:
15
+ #
16
+ # TypesManager.build_const_converter(type)
17
+ #
18
+ def self.method_missing(method, *args)
19
+ if TypesManager.instance.respond_to?(method)
20
+ TypesManager.instance.send(method, *args)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ attr_accessor :body, :prototypes, :includes
27
+
28
+ def initialize
29
+ @consts_wrapped = []
30
+ @body = []
31
+ @prototypes = []
32
+ @includes = []
33
+ end
34
+
35
+ # Some libraries have really bad namespace declarations
36
+ # so we allow for 2 methods of including files
37
+ # 1. trace the class definition to the parent file
38
+ # 2. explicitly declare which files to include in every generated source
39
+ #
40
+ def add_include_for(type)
41
+ file = type.file_name(false)
42
+ if Base.sources.include? file
43
+ @includes << "#include \"#{file}\""
44
+ else
45
+ Base.sources.each do |header|
46
+ @includes << "#include \"#{header}\""
47
+ end
48
+ end
49
+ end
50
+
51
+ # Rice doesn't automatically handle all to_ / from_ruby conversions for a given type.
52
+ # A common construct is the +const Type&+ variable, which we need to manually handle.
53
+ def build_const_converter(type)
54
+ type = type.is_a?(RbGCCXML::Type) ? type.base_type : type
55
+
56
+ # Don't need to deal with fundamental types
57
+ return if type.is_a?(RbGCCXML::FundamentalType)
58
+
59
+ full_name = type.qualified_name
60
+
61
+ # Only wrap once
62
+ # TODO cleaner way of doing this
63
+ return if @consts_wrapped.include?(full_name)
64
+
65
+ # Some types are already handled by Rice, ignore such types
66
+ return if full_name =~ /std::string/
67
+
68
+ @consts_wrapped << full_name
69
+
70
+ # Enumerations are handled slightly differently
71
+ class_type = if type.is_a?(RbGCCXML::Enumeration)
72
+ "new #{full_name}(a)"
73
+ else
74
+ "(#{full_name} *)&a"
75
+ end
76
+
77
+ @includes << "#include <rice/Object.hpp>"
78
+ @includes << "#include <rice/Data_Object.hpp>"
79
+ @includes << "#include <rice/Data_Type.hpp>"
80
+ add_include_for type
81
+
82
+ @body << "template<>"
83
+ @body << "Rice::Object to_ruby<#{full_name} >(#{full_name} const & a) {"
84
+ @body << "\treturn Rice::Data_Object<#{full_name} >(#{class_type}, Rice::Data_Type<#{full_name} >::klass(), 0, 0);"
85
+ @body << "}"
86
+
87
+ @prototypes << "template<>"
88
+ @prototypes << "Rice::Object to_ruby<#{full_name} >(#{full_name} const & a);"
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -45,20 +45,11 @@ module RbPlusPlus
45
45
  # The list of modules to create
46
46
  attr_accessor :modules
47
47
 
48
- # List of extra include directives
49
- attr_accessor :includes
50
-
51
- # List of directories for library searching
52
- attr_accessor :lib_paths
53
-
54
- # List of libraries to link
55
- attr_accessor :libraries
56
-
57
- # List of extra CXXFLAGS that might need to be added to compile lines
58
- attr_accessor :cxxflags
59
-
60
- # List of extra LDFLAGS that might need to be added to compile lines
61
- attr_accessor :ldflags
48
+ # Various options given by the user to help with
49
+ # parsing, linking, compiling, etc.
50
+ #
51
+ # See #sources for a list of the possible options
52
+ attr_accessor :options
62
53
 
63
54
  # Create a new Ruby extension with a given name. This name will be
64
55
  # the module built into the extension.
@@ -67,11 +58,18 @@ module RbPlusPlus
67
58
  @name = name
68
59
  @modules = []
69
60
  @writer_mode = :multiple
70
- @includes = []
71
- @lib_paths = []
72
- @libraries = []
73
- @cxxflags = []
74
- @ldflags = []
61
+
62
+ @options = {
63
+ :include_paths => [],
64
+ :library_paths => [],
65
+ :libraries => [],
66
+ :cxxflags => [],
67
+ :ldflags => [],
68
+ :include_source_files => [],
69
+ :includes => []
70
+ }
71
+
72
+ @node = nil
75
73
 
76
74
  if block
77
75
  build_working_dir(&block)
@@ -84,40 +82,56 @@ module RbPlusPlus
84
82
 
85
83
  # Define where we can find the header files to parse
86
84
  # Can give an array of directories, a glob, or just a string.
87
- # All file names should be full paths, not partial.
85
+ # All file names should be full paths, not relative.
88
86
  #
89
- # Options can be the following:
87
+ # Options can be any or all of the following:
90
88
  #
91
- # * <tt>:include_paths</tt> - An array or string of full paths to be added as -I flags
92
- # * <tt>:library_paths</tt> - An array or string of full paths to be added as -L flags
93
- # * <tt>:libraries</tt> - An array or string of full paths to be added as -l flags
94
- # * <tt>:cxxflags</tt> - An array or string of flags to be added to command line for parsing / compiling
95
- # * <tt>:ldflags</tt> - An array or string of flags to be added to command line for linking
89
+ # * <tt>:include_paths</tt> - Path(s) to be added as -I flags
90
+ # * <tt>:library_paths</tt> - Path(s) to be added as -L flags
91
+ # * <tt>:libraries</tt> - Path(s) to be added as -l flags
92
+ # * <tt>:cxxflags</tt> - Flag(s) to be added to command line for parsing / compiling
93
+ # * <tt>:ldflags</tt> - Flag(s) to be added to command line for linking
94
+ # * <tt>:includes</tt> - Header file(s) to include at the beginning of each .rb.cpp file generated.
95
+ # * <tt>:include_source_files</tt> - C++ source files that need to be compiled into the extension but not wrapped.
96
96
  def sources(dirs, options = {})
97
97
  parser_options = {}
98
98
 
99
99
  if (paths = options.delete(:include_paths))
100
- @includes << paths
101
- parser_options[:includes] = @includes
100
+ @options[:include_paths] << paths
101
+ parser_options[:includes] = paths
102
102
  end
103
103
 
104
104
  if (lib_paths = options.delete(:library_paths))
105
- @lib_paths << lib_paths
105
+ @options[:library_paths] << lib_paths
106
106
  end
107
107
 
108
108
  if (libs = options.delete(:libraries))
109
- @libraries << libs
109
+ @options[:libraries] << libs
110
110
  end
111
111
 
112
112
  if (flags = options.delete(:cxxflags))
113
- @cxxflags << flags
114
- parser_options[:cxxflags] = @cxxflags
113
+ @options[:cxxflags] << flags
114
+ parser_options[:cxxflags] = flags
115
115
  end
116
116
 
117
117
  if (flags = options.delete(:ldflags))
118
- @ldflags << flags
118
+ @options[:ldflags] << flags
119
+ end
120
+
121
+ if (files = options.delete(:include_source_files))
122
+ @options[:include_source_files] << files
123
+ end
124
+
125
+ if (flags = options.delete(:includes))
126
+ includes = Dir.glob(flags)
127
+ if(includes.length == 0)
128
+ puts "Warning: There were no matches for includes #{flags.inspect}"
129
+ else
130
+ @options[:includes] += [*includes]
131
+ end
119
132
  end
120
133
 
134
+ @sources = Dir.glob dirs
121
135
  @parser = RbGCCXML.parse(dirs, parser_options)
122
136
  end
123
137
 
@@ -125,12 +139,18 @@ module RbPlusPlus
125
139
  # Specifing a namespace on the Extension itself will mark functions,
126
140
  # class, enums, etc to be globally available to Ruby (aka not in it's own
127
141
  # module)
142
+ #
143
+ # For now, to get access to the underlying RbGCCXML query system, save the
144
+ # return value of this method:
145
+ #
146
+ # node = namespace "lib::to_wrap"
147
+ #
128
148
  def namespace(name)
129
149
  @node = @parser.namespaces(name)
130
150
  end
131
151
 
132
152
  # Mark that this extension needs to create a Ruby module of
133
- # a give name. Like Extension, this can be used with or without
153
+ # a give name. Like Extension.new, this can be used with or without
134
154
  # a block.
135
155
  def module(name, &block)
136
156
  m = RbModule.new(name, @parser, &block)
@@ -145,13 +165,15 @@ module RbPlusPlus
145
165
  raise "Unknown writer mode #{mode}" unless [:multiple, :single].include?(mode)
146
166
  @writer_mode = mode
147
167
  end
148
-
168
+
149
169
  # Start the code generation process.
150
170
  def build
151
171
  raise ConfigurationError.new("Must specify working directory") unless @working_dir
152
172
  raise ConfigurationError.new("Must specify which sources to wrap") unless @parser
153
173
 
154
174
  @builder = Builders::ExtensionBuilder.new(@name, @node || @parser)
175
+ Builders::Base.additional_includes = @options[:includes]
176
+ Builders::Base.sources = @sources
155
177
  @builder.modules = @modules
156
178
  @builder.build
157
179
  end
@@ -160,6 +182,7 @@ module RbPlusPlus
160
182
  # #build must be called before this step or nothing will be written out
161
183
  def write
162
184
  prepare_working_dir
185
+ process_other_source_files
163
186
 
164
187
  # Create the code
165
188
  writer_class = @writer_mode == :multiple ? Writers::MultipleFilesWriter : Writers::SingleFileWriter
@@ -167,11 +190,7 @@ module RbPlusPlus
167
190
 
168
191
  # Create the extconf.rb
169
192
  extconf = Writers::ExtensionWriter.new(@builder, @working_dir)
170
- extconf.includes = @includes
171
- extconf.library_paths = @lib_paths
172
- extconf.libraries = @libraries
173
- extconf.cxxflags = @cxxflags
174
- extconf.ldflags = @ldflags
193
+ extconf.options = @options
175
194
  extconf.write
176
195
  end
177
196
 
@@ -192,7 +211,16 @@ module RbPlusPlus
192
211
  # and if it does exist, clean it out
193
212
  def prepare_working_dir
194
213
  FileUtils.mkdir_p @working_dir unless File.directory?(@working_dir)
195
- FileUtils.rm_rf "#{@working_dir}/*"
214
+ FileUtils.rm_rf Dir["#{@working_dir}/*"]
215
+ end
216
+
217
+ # Make sure that any files or globs of files in :include_source_files are copied into the working
218
+ # directory before compilation
219
+ def process_other_source_files
220
+ files = @options[:include_source_files].flatten
221
+ files.each do |f|
222
+ FileUtils.cp Dir[f], @working_dir
223
+ end
196
224
  end
197
225
 
198
226
  # Cool little eval / binding hack, from need.rb
@@ -42,8 +42,10 @@ module RbPlusPlus
42
42
 
43
43
  # Specify a C++ namespace from which the contained code will
44
44
  # be wrapped and exposed to Ruby under this Module.
45
+ #
46
+ # Also see Extension#namespace
45
47
  def namespace(name)
46
- @node = @parser.namespaces(name)
48
+ @node = @parser.namespaces.find(:all, :name => name)
47
49
  end
48
50
 
49
51
  # Register another module to be defined inside of
@@ -0,0 +1,67 @@
1
+ module RbGCCXML
2
+ class Class
3
+ # Class can include nested classes and nested structs.
4
+ #
5
+ # Class can also include external methods/functions as class level methods
6
+ # also supports instance level methods
7
+ #
8
+ # ex.
9
+ #
10
+ # math_class.includes node.namespaces("Math").functions("mod")
11
+ #
12
+ # or for a instance method:
13
+ #
14
+ # math_class.includes node.namespaces("Math").functions("mod").as_method
15
+ #
16
+ # or for nesting a class/struct:
17
+ #
18
+ # math_class.includes node.namespaces("Math").classes("Degree")
19
+ #
20
+ def includes(val)
21
+ if (val.is_a?(RbGCCXML::Struct) || val.is_a?(RbGCCXML::Class))
22
+ @classes ||= []
23
+ @classes << RbPlusPlus::NodeReference.new(val)
24
+ else
25
+ @methods ||= []
26
+ @methods << RbPlusPlus::NodeReference.new(val)
27
+ end
28
+ val.moved=true
29
+ end
30
+
31
+ alias_method :node_methods, :methods
32
+ def methods(*args) #:nodoc:
33
+ nodes = node_methods(*args)
34
+ methods = @methods || QueryResult.new
35
+ methods << cache(nodes)
36
+ methods.flatten!
37
+ return methods if args.empty?
38
+ return (methods.size == 1 ? methods[0] : methods)
39
+ end
40
+
41
+ alias_method :node_classes, :classes
42
+ def classes(*args) #:nodoc:
43
+ [@classes || [], node_classes].flatten
44
+ end
45
+
46
+ # returns a list of superclasses of this node, including the node's class
47
+ def super_classes
48
+ retv = []
49
+ unless node.attributes['bases'].nil? || node.attributes['bases'] == ""
50
+ node.attributes['bases'].split.each do |cls_id|
51
+ c = XMLParsing.find(:type => "Class", :id => cls_id)
52
+ c = XMLParsing.find(:type => "Struct", :id => cls_id) if c.nil?
53
+ if c.nil?
54
+ puts "#{self.qualified_name} cannot find super class for id #{cls_id} "
55
+ next
56
+ end
57
+ c = RbPlusPlus::NodeCache.instance.get(c)
58
+ retv << c unless c.ignored?
59
+ end
60
+ end
61
+
62
+ return retv
63
+ end
64
+
65
+ end
66
+ end
67
+
@@ -0,0 +1,4 @@
1
+ module RbGCCXML
2
+ class Constructor #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ module RbGCCXML
2
+ class Function
3
+ attr_reader :special_qualified_name
4
+
5
+ # always true for functions, false for methods
6
+ def static?
7
+ !(@as_method || false)
8
+ end
9
+
10
+ # Sets this function to be an instance method.
11
+ # Useful for custom function declaration.
12
+ def as_instance_method
13
+ @as_method = true
14
+ return self
15
+ end
16
+
17
+ def calls(method_name)
18
+ @special_qualified_name = method_name
19
+ self
20
+ end
21
+
22
+ alias_method :method_qualified_name, :qualified_name
23
+ def qualified_name #:nodoc:
24
+ @special_qualified_name || method_qualified_name
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module RbGCCXML
2
+ class Method #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,71 @@
1
+ module RbPlusPlus
2
+ class RbModule
3
+ # Helper function for moving pieces of an API into other Ruby locations, eg from a Class to a Module,
4
+ # from global functions to a Class, or from Module to Module.
5
+ #
6
+ # Module may include Functions
7
+ # e.module "System" do |m|
8
+ # m.includes node.functions("print").wrap_as("puts") # Moves the ::print function into the System module
9
+ #
10
+ # m.include node.classes("Vector3") # Explicitly put Vector3 class in the System module
11
+ # end
12
+ #
13
+ def includes(val)
14
+ if is_a?(val, RbGCCXML::Function)
15
+ reference_function(val)
16
+ elsif is_a?(val, RbGCCXML::Class)
17
+ reference_class(val)
18
+ elsif is_a?(val, RbGCCXML::Struct)
19
+ reference_struct(val)
20
+ else
21
+ raise "Cannot use #{self.class}#includes for type '#{val.class}'"
22
+ end
23
+ end
24
+
25
+ def functions #:nodoc:
26
+ functions = @functions || []
27
+ functions << @node.functions if @node
28
+ functions.flatten
29
+ end
30
+
31
+ def classes #:nodoc:
32
+ classes = @classes || []
33
+ classes << @node.classes if @node
34
+ classes.flatten
35
+ end
36
+
37
+ def structs #:nodoc:
38
+ structs = @structs || []
39
+ structs << @node.structs if @node
40
+ structs.flatten
41
+ end
42
+
43
+ private
44
+
45
+ # Map a function from a different namespace
46
+ def reference_function(val) #:nodoc:
47
+ @functions ||= []
48
+ @functions << NodeReference.new(val)
49
+ val.moved=true
50
+ end
51
+
52
+ # Map a class from a different namespace
53
+ def reference_class(val) #:nodoc:
54
+ @classes ||= []
55
+ @classes << NodeReference.new(val)
56
+ val.moved=true
57
+ end
58
+
59
+ def reference_struct(val) #:nodoc:
60
+ @structs ||= []
61
+ @structs << NodeReference.new(val)
62
+ val.moved=true
63
+ end
64
+
65
+ def is_a?(val, klass) #:nodoc:
66
+ return true if val.is_a?(klass)
67
+ return true if val.is_a?(NodeReference) && val.references?(klass)
68
+ return false
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,77 @@
1
+ module RbGCCXML
2
+ class Node
3
+ # Specifies to not export this node
4
+ def ignore
5
+ @ignored = true
6
+ end
7
+
8
+ # Returns true if this node is ignored in exporting
9
+ def ignored?
10
+ @ignored || false
11
+ end
12
+
13
+ # Specifies that this node has been included somewhere else
14
+ def moved=(val)
15
+ @moved = val
16
+ end
17
+
18
+ # Change what the name of this node will be when wrapped into Ruby
19
+ def wrap_as(name)
20
+ @renamed = name
21
+ self
22
+ end
23
+
24
+ # Returns true if the node has been moved
25
+ def moved?
26
+ @moved || false
27
+ end
28
+
29
+ # Has this node been renamed
30
+ def renamed?
31
+ (@renamed.nil? ? false : true)
32
+ end
33
+
34
+ alias_method :rbgccxml_namespaces, :namespaces
35
+ def namespaces(*args) #:nodoc:
36
+ nodes = rbgccxml_namespaces(*args)
37
+ return cache(nodes)
38
+ end
39
+
40
+ alias_method :rbgccxml_classes, :classes
41
+ def classes(*args) #:nodoc:
42
+ nodes = rbgccxml_classes(*args)
43
+ return cache(nodes)
44
+ end
45
+
46
+ alias_method :rbgccxml_functions, :functions
47
+ def functions(*args) #:nodoc:
48
+ nodes = rbgccxml_functions(*args)
49
+ return cache(nodes)
50
+ end
51
+
52
+ alias_method :rbgccxml_methods, :functions
53
+ def methods(*args) #:nodoc:
54
+ nodes = rbgccxml_methods(*args)
55
+ return cache(nodes)
56
+ end
57
+
58
+ alias_method :rbgccxml_name, :name
59
+ def name #:nodoc:
60
+ @renamed || rbgccxml_name
61
+ end
62
+
63
+ private
64
+ # Looks up the objects in the node cache.
65
+ def cache(nodes)
66
+ if nodes.is_a?(QueryResult)
67
+ retv = QueryResult.new
68
+ nodes.each do |node|
69
+ retv << RbPlusPlus::NodeCache.instance.get(node)
70
+ end
71
+ return retv
72
+ else
73
+ return RbPlusPlus::NodeCache.instance.get(nodes)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,19 @@
1
+ module RbPlusPlus
2
+ class NodeCache #:nodoc:
3
+ include Singleton
4
+ # Retrieves a node from the cache based on the node's qualified name
5
+ def get(node)
6
+ demangled = node.attributes['demangled']
7
+ @@nodes ||= {}
8
+ if @@nodes[demangled].nil?
9
+ @@nodes[demangled] = node
10
+ end
11
+ return @@nodes[demangled]
12
+ end
13
+
14
+ # Clears out the cache
15
+ def clear
16
+ @@nodes = {}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ module RbPlusPlus
2
+ class NodeReference #:nodoc:
3
+ # Takes the delegate object as input
4
+ def initialize(from)
5
+ @delegate = from
6
+ end
7
+
8
+ # Delegate
9
+ def method_missing(name, *args)
10
+ @delegate.send name, *args
11
+ end
12
+
13
+ # Always false
14
+ def moved?
15
+ false
16
+ end
17
+
18
+ # Delegate
19
+ def methods(*args)
20
+ @delegate.methods *args
21
+ end
22
+
23
+ # Returns true if the class references the specified class
24
+ def references?(klass)
25
+ return true if @delegate.is_a?(klass)
26
+ return true if @delegate.is_a?(NodeReference) && @delegate.references?(klass)
27
+ return false
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ # In order to facilitate a very clean wrapping and code management API,
2
+ # Rb++ adds a few helper methods to various RbGCCXML node classes. What
3
+ # is documented here are added on top of the normal RbGCCXML methods
4
+ # documented elsewhere.
5
+ module RbGCCXML
6
+ end