rbplusplus 0.8 → 0.9

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