rbplusplus 0.1.1 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
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