rbplusplus 0.8 → 0.9

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 (80) hide show
  1. data/Rakefile +13 -13
  2. data/TODO +9 -41
  3. data/lib/rbplusplus/builders/allocation_strategy.rb +57 -0
  4. data/lib/rbplusplus/builders/base.rb +115 -212
  5. data/lib/rbplusplus/builders/class.rb +129 -115
  6. data/lib/rbplusplus/builders/const.rb +30 -0
  7. data/lib/rbplusplus/builders/const_converter.rb +52 -0
  8. data/lib/rbplusplus/builders/constructor.rb +19 -0
  9. data/lib/rbplusplus/builders/director.rb +149 -0
  10. data/lib/rbplusplus/builders/director_method.rb +20 -0
  11. data/lib/rbplusplus/builders/enumeration.rb +19 -26
  12. data/lib/rbplusplus/builders/extension.rb +42 -54
  13. data/lib/rbplusplus/builders/global_function.rb +18 -0
  14. data/lib/rbplusplus/builders/helpers/class.rb +74 -0
  15. data/lib/rbplusplus/builders/helpers/enumeration.rb +28 -0
  16. data/lib/rbplusplus/builders/helpers/module.rb +22 -0
  17. data/lib/rbplusplus/builders/include.rb +32 -0
  18. data/lib/rbplusplus/builders/instance_variable.rb +36 -0
  19. data/lib/rbplusplus/builders/method.rb +14 -0
  20. data/lib/rbplusplus/builders/method_base.rb +136 -0
  21. data/lib/rbplusplus/builders/module.rb +37 -51
  22. data/lib/rbplusplus/builders/module_function.rb +16 -0
  23. data/lib/rbplusplus/builders/static_method.rb +14 -0
  24. data/lib/rbplusplus/extension.rb +140 -28
  25. data/lib/rbplusplus/logger.rb +45 -0
  26. data/lib/rbplusplus/module.rb +55 -1
  27. data/lib/rbplusplus/transformers/class.rb +116 -35
  28. data/lib/rbplusplus/transformers/function.rb +14 -16
  29. data/lib/rbplusplus/transformers/method.rb +26 -1
  30. data/lib/rbplusplus/transformers/namespace.rb +12 -0
  31. data/lib/rbplusplus/transformers/node.rb +47 -54
  32. data/lib/rbplusplus/transformers/node_cache.rb +5 -9
  33. data/lib/rbplusplus/writers/multiple_files_writer.rb +290 -88
  34. data/lib/rbplusplus/writers/single_file_writer.rb +36 -14
  35. data/lib/rbplusplus.rb +44 -18
  36. data/test/allocation_strategies_test.rb +33 -0
  37. data/test/class_methods_encapsulate_test.rb +59 -0
  38. data/test/class_methods_test.rb +2 -35
  39. data/test/classes_test.rb +72 -2
  40. data/test/compiling_test.rb +13 -0
  41. data/test/constructors_test.rb +9 -18
  42. data/test/custom_code_test.rb +53 -0
  43. data/test/default_arguments_test.rb +69 -0
  44. data/test/director_test.rb +173 -0
  45. data/test/enumerations_test.rb +29 -0
  46. data/test/extension_test.rb +7 -2
  47. data/test/file_writers_test.rb +11 -4
  48. data/test/function_pointer_test.rb +56 -0
  49. data/test/function_pointers_classes_test.rb +27 -0
  50. data/test/generated/extconf.rb +2 -2
  51. data/test/headers/Adder.cpp +8 -0
  52. data/test/headers/Adder.h +31 -1
  53. data/test/headers/alloc_strats.h +26 -0
  54. data/test/headers/class_methods.h +30 -0
  55. data/test/headers/code/custom_to_from_ruby.cpp +11 -0
  56. data/test/headers/code/custom_to_from_ruby.hpp +13 -0
  57. data/test/headers/constructors.h +8 -20
  58. data/test/headers/default_arguments.h +49 -0
  59. data/test/headers/director.h +148 -0
  60. data/test/headers/enums.h +33 -0
  61. data/test/headers/function_pointers.h +32 -0
  62. data/test/headers/function_pointers_class.h +26 -0
  63. data/test/headers/needs_code.h +10 -0
  64. data/test/headers/overload.h +0 -3
  65. data/test/headers/subclass.h +10 -0
  66. data/test/headers/to_from_ruby.h +6 -4
  67. data/test/headers/ugly_interface.h +4 -7
  68. data/test/modules_test.rb +11 -6
  69. data/test/overloading_test.rb +6 -2
  70. data/test/subclass_test.rb +20 -10
  71. data/test/test_helper.rb +6 -1
  72. data/test/to_from_ruby_test.rb +0 -2
  73. data/test/wrap_as_test.rb +28 -37
  74. metadata +89 -57
  75. data/lib/rbplusplus/builders/types_manager.rb +0 -93
  76. data/lib/rbplusplus/transformers/constructor.rb +0 -4
  77. data/lib/rbplusplus/transformers/module.rb +0 -71
  78. data/lib/rbplusplus/transformers/node_reference.rb +0 -30
  79. data/test/headers/ugly_helper.h +0 -18
  80. data/test/object_persistence_test.rb +0 -44
@@ -1,137 +1,151 @@
1
1
  module RbPlusPlus
2
2
  module Builders
3
3
 
4
- # This class handles generating source for Class nodes
5
- class ClassBuilder < Base
4
+ # Handles the generation of Rice code to wrap classes
5
+ class ClassNode < Base
6
+ include ClassHelpers
7
+ include EnumerationHelpers
6
8
 
7
- # Different initializer to keep things clean
8
- def initialize(parent, node)
9
- super(node.name, node)
10
- self.parent = parent
9
+ def qualified_name
10
+ @qualified_name || self.code.qualified_name
11
11
  end
12
12
 
13
13
  def build
14
+ add_child IncludeNode.new(self, "rice/Class.hpp", :system)
15
+ add_child IncludeNode.new(self, "rice/Data_Type.hpp", :system)
16
+ add_child IncludeNode.new(self, code.file)
14
17
 
15
- #Handles templated super classes
16
- @typedef_name = node.qualified_name.functionize
17
-
18
- #Handles templated super classes passing in complex members
19
- var_name = node.name
20
- var_name.gsub!("::","_")
21
- var_name.gsub!(/[ ,<>]/, "_")
22
- var_name.gsub!("*", "Ptr")
23
-
24
- self.rice_variable = "rb_c#{var_name}"
25
- self.rice_variable_type = "Rice::Data_Type<#{self.qualified_name} >"
26
-
27
- includes << "#include <rice/Class.hpp>"
28
- includes << "#include <rice/Data_Type.hpp>"
29
- includes << "#include <rice/Constructor.hpp>"
30
-
31
- add_additional_includes
32
- add_includes_for node
33
-
34
- self.declarations.insert(0,"typedef #{node.qualified_name} #{@typedef_name};")
35
-
36
- @body << class_definition
37
-
38
- @body += constructors
39
-
40
- @body += methods
41
-
42
- # Nested Classes
43
- build_classes
44
-
45
- # Enumerations
46
- build_enumerations
18
+ typedef = find_typedef
19
+
20
+ @short_name, @qualified_name = typedef ? [typedef.name, typedef.qualified_name] : [code.name, code.qualified_name]
21
+
22
+ Logger.info "Wrapping class #{@qualified_name}"
23
+
24
+ @class_base_type = @qualified_name
25
+
26
+ supers = self.code.superclasses(:public)
27
+ @superclass = supers[0]
28
+
29
+ if supers.length > 1
30
+ if (@superclass = self.code._get_superclass).nil?
31
+ Logger.warn :mutiple_superclasses, "#{@qualified_name} has multiple public superclasses. " +
32
+ "Will use first superclass, which is #{supers[0].qualified_name} "
33
+ "Please use #use_superclass to specify another superclass as needed."
34
+ end
35
+ end
36
+
37
+ if self.code.needs_director?
38
+ @director = DirectorNode.new(self.code, self, @qualified_name, @superclass)
39
+ add_child @director
40
+
41
+ @qualified_name = @director.qualified_name
42
+ end
43
+
44
+ self.rice_variable = "rb_c#{@short_name.as_variable}"
45
+ self.rice_variable_type = "Rice::Data_Type< #{@qualified_name} >"
46
+
47
+ with_enumerations
48
+ with_classes
49
+ with_constructors
50
+ with_constants
51
+ with_variables
52
+ with_methods
53
+
54
+ unless @director
55
+ check_allocation_strategies
56
+ end
57
+
58
+ # For now, build a const& type converter for all class types until Rice has
59
+ # better management of to_ruby of class types, if it ever happens
60
+ add_global_child ConstConverterNode.new(self.code, self)
47
61
  end
48
62
 
49
- # Build the constructors, and return an array of rice code
50
- def constructors
51
- result = []
52
- # There are no constructors on purely virtual classes.
53
- node.methods.each do |method|
54
- next unless method.is_a? RbGCCXML::Method
55
- return [] if method.purely_virtual?
63
+ def write
64
+ prefix = "#{rice_variable_type} #{rice_variable} = "
65
+ ruby_name = @short_name
66
+ expose_class = @qualified_name
67
+ superclass = @superclass.qualified_name if @superclass && !do_not_wrap?(@superclass)
68
+
69
+ if @director
70
+ @director.write_class_registration
71
+ expose_class = @director.qualified_name
72
+ superclass = @class_base_type
56
73
  end
57
- # Constructors
58
- node.constructors.each do |init|
59
- next if init.ignored?
60
- next unless init.public?
61
- args = [@typedef_name, init.arguments.map {|a| a.cpp_type.to_s(true) }].flatten
62
- result << "\t#{rice_variable}.define_constructor(Rice::Constructor<#{args.join(",")}>());"
74
+
75
+ class_names = [expose_class]
76
+ class_names << superclass if superclass
77
+ class_names = class_names.join(",")
78
+
79
+ if parent.rice_variable
80
+ registrations << "#{prefix} Rice::define_class_under< #{class_names} >" +
81
+ "(#{parent.rice_variable}, \"#{ruby_name}\");"
82
+ else
83
+ registrations << "#{prefix} Rice::define_class< #{class_names} >(\"#{ruby_name}\");"
63
84
  end
64
- result
85
+
86
+ handle_custom_code
65
87
  end
66
-
67
- # Build the methods, and return an array of rice code
68
- def methods
69
- result = []
70
- # Methods are thrown into a hash table so that we can
71
- # determine overloaded methods
72
- methods_hash = {}
73
- node.methods.each do |method|
74
- next unless method.public?
75
-
76
- methods_hash[method.qualified_name] ||= []
77
- methods_hash[method.qualified_name] << method
88
+
89
+ private
90
+
91
+ # Here we take the code manually added to the extension via #add_custom_code
92
+ def handle_custom_code
93
+
94
+ # Any declaration code, usually wrapper function definitions
95
+ self.code._get_custom_declarations.flatten.each do |decl|
96
+ declarations << decl
97
+ end
98
+
99
+ # And the registration code to hook into Rice
100
+ self.code._get_custom_wrappings.flatten.each do |wrap|
101
+ registrations << "#{wrap.gsub(/<class>/, self.rice_variable)}"
78
102
  end
79
-
80
- methods_hash.each do |key, methods|
81
- #Add any method with a const return type to the typemanager
82
- methods.each do |method|
83
- next if method.ignored? || method.moved?
84
- if method.return_type.const? || method.const?
85
- TypesManager.build_const_converter(method.return_type)
86
- end
103
+ end
104
+
105
+ # We need to be sure to inform Rice of classes that may not have public
106
+ # constructors or destructors. This is because when a class is wrapped, code is generated
107
+ # to allocate the class directly. If this code tries to use a non-public
108
+ # constructor, we hit a compiler error.
109
+ def check_allocation_strategies
110
+ # Due to the nature of GCC-XML's handling of templated classes, there are some
111
+ # classes that might not have any gcc-generated constructors or destructors.
112
+ # We check here if we're one of those classes and completely skip this step
113
+ return if [self.code.constructors].flatten.empty?
114
+
115
+ # Find a public default constructor
116
+ found = [self.code.constructors.find(:arguments => [], :access => "public")].flatten
117
+ has_public_constructor = !found.empty?
118
+
119
+ # See if the destructor is public
120
+ has_public_destructor = self.code.destructor && self.code.destructor.public?
121
+
122
+ if !has_public_constructor || !has_public_destructor
123
+ add_global_child AllocationStrategyNode.new(self,
124
+ self.code, has_public_constructor, has_public_destructor)
125
+ end
126
+ end
127
+
128
+ # Wrap up all public methods
129
+ def with_methods
130
+ method_names = @director ? @director.methods_wrapped.map {|m| m.name } : []
131
+ [self.code.methods].flatten.each do |method|
132
+ next if do_not_wrap?(method)
133
+ next if method_names.include?(method.name)
134
+
135
+ # Ignore methods that have non-public arguments anywhere
136
+ if !method.arguments.empty? && !method.arguments.select {|a| !a.cpp_type.base_type.public?}.empty?
137
+ Logger.info "Ignoring method #{method.qualified_name} due to non-public argument type(s)"
138
+ next
87
139
  end
88
- #No overloaded methods
89
- if methods.length == 1
90
- method = methods[0]
91
- next if method.ignored? || method.moved?
92
- m = "define_method"
93
- name = method.qualified_name
94
-
95
- if method.static?
96
- m = "define_singleton_method"
97
- name = build_function_wrapper(method)
98
- end
99
-
100
- result << "\t#{rice_variable}.#{m}(\"#{Inflector.underscore(method.name)}\", &#{name});"
140
+
141
+ if method.static?
142
+ add_child StaticMethodNode.new(method, self)
101
143
  else
102
- #Handle overloaded methods
103
- #currently we just append an index to them if they have not been renamed
104
- #for example getOrigin() and getOrigin(x,y) become
105
- #get_origin_0 and get_origin_1
106
- methods.each_with_index do |method, i|
107
- next if method.ignored? || method.moved?
108
- name = build_method_wrapper(node, method, i)
109
- m = "define_method"
110
- method_name = "#{Inflector.underscore(method.name)}"
111
- method_name += "_#{i}" unless method.renamed?
112
- result << "\t#{rice_variable}.#{m}(\"#{method_name}\", &#{name});"
113
- end
144
+ add_child MethodNode.new(method, self)
114
145
  end
115
146
  end
116
- result
117
- end
118
-
119
- # Return a rice string representing Rice's class definition.
120
- def class_definition
121
- class_defn = "\t#{rice_variable_type} #{rice_variable} = "
122
-
123
- class_name = node.name
124
- supers = node.super_classes.collect { |s| s.qualified_name }
125
- class_names = [@typedef_name, supers].flatten.join(",")
126
-
127
- if !parent.is_a?(ExtensionBuilder)
128
- class_defn += "Rice::define_class_under<#{class_names} >(#{parent.rice_variable}, \"#{class_name}\");"
129
- else
130
- class_defn += "Rice::define_class<#{class_names} >(\"#{class_name}\");"
131
- end
132
- class_defn
133
147
  end
148
+
134
149
  end
135
-
136
150
  end
137
151
  end
@@ -0,0 +1,30 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # Expose a const value
5
+ class ConstNode < Base
6
+
7
+ def build
8
+ add_child IncludeNode.new(self, code.file)
9
+ end
10
+
11
+ def write
12
+ # If this constant is initialized in the header, we need to set the constant to the initialized value
13
+ # If we just use the variable itself, Linux will fail to compile because the linker won't be able to
14
+ # find the constant.
15
+ set_to =
16
+ if init = code.attributes["init"]
17
+ init
18
+ else
19
+ code.qualified_name
20
+ end
21
+
22
+ prefix = parent.rice_variable ? "#{parent.rice_variable}." : "Rice::Module(rb_mKernel)."
23
+ registrations << "#{prefix}const_set(\"#{code.name}\", to_ruby(#{set_to}));"
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+
@@ -0,0 +1,52 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # Handles code generation for to_ruby converters for const& types
5
+ class ConstConverterNode < Base
6
+
7
+ # Used by MultipleFileWriter to only wrap a given type once.
8
+ def qualified_name
9
+ "#{self.code.qualified_name}_ConstConverter"
10
+ end
11
+
12
+ def build
13
+ Logger.debug("Building const converter for #{self.code.qualified_name}")
14
+ end
15
+
16
+ def write
17
+ full_name = self.code.qualified_name
18
+
19
+ # Various reasons we don't want to generate this:
20
+ # Rice already handles it
21
+ if full_name =~ /std::string/
22
+ Logger.debug("Not building const converter for #{full_name}")
23
+ return
24
+ end
25
+
26
+ Logger.debug("Writing out const converter for #{full_name}")
27
+
28
+ includes << "#include <rice/Object.hpp>"
29
+ includes << "#include <rice/Data_Object.hpp>"
30
+ includes << "#include <rice/Data_Type.hpp>"
31
+
32
+ includes << "#include \"#{self.code.file}\""
33
+
34
+ declarations << "template<>"
35
+ declarations << "Rice::Object to_ruby<#{full_name} >(#{full_name} const & a);"
36
+
37
+ build_as = if self.parent.is_a?(EnumerationNode)
38
+ "new #{full_name}(a)"
39
+ else
40
+ "(#{full_name} *)&a"
41
+ end
42
+
43
+ registrations << "template<>"
44
+ registrations << "Rice::Object to_ruby<#{full_name} >(#{full_name} const & a) {"
45
+ registrations << "\treturn Rice::Data_Object<#{full_name} >(#{build_as}, Rice::Data_Type<#{full_name} >::klass(), 0, 0);"
46
+ registrations << "}"
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,19 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # Wrap class constructor(s)
5
+ class ConstructorNode < Base
6
+
7
+ def build
8
+ add_child IncludeNode.new(self, "rice/Constructor.hpp", :system)
9
+ end
10
+
11
+ def write
12
+ args = [code.parent.qualified_name, code.arguments.map {|a| a.cpp_type.to_cpp }].flatten.compact
13
+ registrations << "#{parent.rice_variable}.define_constructor(Rice::Constructor< #{args.join(",")} >());"
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,149 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # This class takes care of the generation of Rice::Director wrapper
5
+ # classes. It's slightly different than other nodes, as it's self.code
6
+ # is the class we're wrapping a director around.
7
+ class DirectorNode < Base
8
+
9
+ attr_reader :methods_wrapped
10
+
11
+ def initialize(code, parent, class_qualified_name, superclass)
12
+ super(code, parent)
13
+
14
+ @class_qualified_name = class_qualified_name
15
+ @methods_wrapped = []
16
+ @superclass = superclass
17
+ @constructors = []
18
+
19
+ @class_base_name = class_qualified_name.split("::")[-1]
20
+ @name = "#{@class_base_name}Director"
21
+ end
22
+
23
+ def qualified_name
24
+ @name
25
+ end
26
+
27
+ def build
28
+ add_child IncludeNode.new(self, "rice/Director.hpp", :global)
29
+ add_child IncludeNode.new(self, "rice/Constructor.hpp", :global)
30
+
31
+ # To ensure proper compilation, this director class needs
32
+ # to implement all pure virtual methods found up the
33
+ # inheritance heirarchy of this class. So here, we traverse
34
+ # this list and build the nest of required methods
35
+ wrapped_names = []
36
+ klass = self.code
37
+ while klass.is_a?(RbGCCXML::Class) || klass.is_a?(RbGCCXML::Struct)
38
+ [klass.methods].flatten.each do |method|
39
+ next if do_not_wrap?(method)
40
+ if method.virtual? && !wrapped_names.include?(method.name)
41
+ @methods_wrapped << method
42
+ wrapped_names << method.name
43
+
44
+ add_child DirectorMethodNode.new(method, self.parent, self)
45
+ end
46
+ end
47
+ klass = klass.superclass
48
+ end
49
+ end
50
+
51
+ def wrap_constructor(constructor)
52
+ @constructors << constructor
53
+ end
54
+
55
+ def write_class_registration
56
+ # Need to tell Rice of the base class, while also making sure that if there's a superclass to this class
57
+ # that we know about it, or attempts to use polymorphism will crash with 'unknown caster for {superclass}
58
+ class_names = [@class_qualified_name]
59
+ class_names << @superclass.qualified_name if @superclass && !do_not_wrap?(@superclass)
60
+ class_names = class_names.join(",")
61
+
62
+ self.parent.registrations << "Rice::define_class< #{class_names} >(\"__#{@class_base_name}__\");"
63
+ end
64
+
65
+ def write_constructor(constructor = nil)
66
+ args = ["Rice::Object self"]
67
+ types = [@name, "Rice::Object"]
68
+ supercall_args = []
69
+
70
+ if constructor
71
+ constructor.arguments.each do |arg|
72
+ type = arg.cpp_type.to_cpp
73
+ name = arg.name
74
+
75
+ args << "#{type} #{name}"
76
+ types << type
77
+ supercall_args << name
78
+ end
79
+ end
80
+
81
+ declarations << "#{@name}(#{args.join(", ")}) : #{@class_qualified_name}(#{supercall_args.join(", ")}), Rice::Director(self) { }"
82
+ registrations << "#{self.parent.rice_variable}.define_constructor(Rice::Constructor< #{types.join(", ")} >());"
83
+ end
84
+
85
+ def write
86
+ declarations << "class #{@name} : public #{@class_qualified_name}, public Rice::Director {"
87
+ declarations << "public:"
88
+
89
+ # Handle constructors
90
+ if @constructors.empty?
91
+ write_constructor
92
+ else
93
+ @constructors.each {|c| write_constructor(c) }
94
+ end
95
+
96
+ # Each virtual method gets wrapped
97
+ @methods_wrapped.each do |method|
98
+
99
+ cpp_name = method.qualified_name.split("::")[-1]
100
+ ruby_name = Inflector.underscore(method.name)
101
+ return_type = method.return_type.to_cpp
102
+ return_call = return_type != "void" ? "return" : ""
103
+
104
+ def_arguments = []
105
+ call_arguments = []
106
+ method.arguments.each do |a|
107
+ def_arg = a.value ? " = #{a.value}" : ""
108
+ def_arguments << "#{a.cpp_type.to_cpp} #{a.name}#{def_arg}"
109
+ call_arguments << a.name
110
+ end
111
+
112
+ def_arguments = def_arguments.length == 0 ? "" : def_arguments.join(", ")
113
+
114
+ reverse = ""
115
+ up_or_raise =
116
+ if method.default_return_value
117
+ reverse = "!"
118
+ "return #{method.default_return_value};"
119
+ else
120
+ if method.purely_virtual?
121
+ "raisePureVirtual()"
122
+ else
123
+ "#{return_call} this->#{method.qualified_name}(#{call_arguments.join(", ")})"
124
+ end
125
+ end
126
+
127
+ call_down = "getSelf().call(\"#{ruby_name}\"#{call_arguments.empty? ? "" : ", "}#{call_arguments.map {|a| "to_ruby(#{a})" }.join(", ")})"
128
+ call_down = "return from_ruby< #{return_type} >( #{call_down} )" if return_type != "void"
129
+
130
+ const = method.const? ? "const" : ""
131
+
132
+ declarations << ""
133
+ declarations << "#{return_type} #{cpp_name}(#{def_arguments}) #{const} {"
134
+ declarations << "if(#{reverse}callIsFromRuby(\"#{ruby_name}\")) {"
135
+ declarations << "#{up_or_raise};"
136
+ declarations << "} else {"
137
+ declarations << "#{call_down};"
138
+ declarations << "}"
139
+ declarations << "}"
140
+ end
141
+
142
+ declarations << "};"
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+ end
149
+
@@ -0,0 +1,20 @@
1
+ module RbPlusPlus
2
+ module Builders
3
+
4
+ # Expose a director method as an instance method
5
+ class DirectorMethodNode < MethodNode
6
+
7
+ def initialize(method, parent, director)
8
+ super(method, parent)
9
+ @director = director
10
+ end
11
+
12
+ def code_path
13
+ cpp_name = self.code.qualified_name.split("::")[-1]
14
+ "#{@director.qualified_name}::#{cpp_name}"
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -1,37 +1,30 @@
1
1
  module RbPlusPlus
2
2
  module Builders
3
3
 
4
- # This class handles generating source for a requested Module
5
- class EnumerationBuilder < Base
6
-
7
- # Different initializer to keep things clean
8
- def initialize(parent, node)
9
- super(node.name, node)
10
- self.parent = parent
11
- end
4
+ # Expose an enumeration.
5
+ class EnumerationNode < Base
12
6
 
13
7
  def build
14
- includes << "#include <rice/Enum.hpp>"
15
- enum_name = node.name
16
- full_name = node.qualified_name
17
- self.rice_variable = "rb_e#{enum_name}"
18
- self.rice_variable_type = "Rice::Enum<#{full_name}>"
19
-
20
- add_additional_includes
21
-
22
- defn = "\t#{rice_variable_type} #{rice_variable} = "
23
-
24
- second_arg = ""
25
- if !parent.is_a?(ExtensionBuilder)
26
- second_arg = ", #{parent.rice_variable}"
27
- end
8
+ add_child IncludeNode.new(self, "rice/Enum.hpp", :system)
9
+ add_child IncludeNode.new(self, code.file)
10
+
11
+ # See ClassNode
12
+ add_global_child ConstConverterNode.new(self.code, self)
13
+
14
+ self.rice_variable_type = "Rice::Enum<#{code.qualified_name}>"
15
+ self.rice_variable = "rb_e#{code.name}"
16
+
17
+ Logger.info "Wrapping enumeration #{code.qualified_name}"
18
+ end
28
19
 
29
- defn += "Rice::define_enum<#{full_name}>(\"#{enum_name}\" #{second_arg});"
20
+ def write
21
+ second = parent.rice_variable ? ", #{parent.rice_variable}" : ""
30
22
 
31
- body << defn
23
+ registrations << "#{rice_variable_type} #{rice_variable} = " \
24
+ "Rice::define_enum<#{code.qualified_name}>(\"#{code.name}\"#{second});"
32
25
 
33
- node.values.each do |v|
34
- body << "\t#{rice_variable}.define_value(\"#{v.name}\", #{v.to_s(true)});"
26
+ code.values.each do |v|
27
+ registrations << "#{rice_variable}.define_value(\"#{v.name}\", #{v.qualified_name});"
35
28
  end
36
29
  end
37
30