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
data/lib/rbplusplus.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.expand_path(File.dirname(__FILE__))
2
2
  $:.unshift File.expand_path(File.dirname(__FILE__) + "/rbplusplus")
3
3
 
4
- gem 'rbgccxml'
4
+ require 'rubygems'
5
5
  require 'rbgccxml'
6
6
 
7
7
  require 'inflector'
@@ -15,23 +15,50 @@ module RbPlusPlus
15
15
 
16
16
  RBPP_COMMENT = "// This file generated by rb++"
17
17
 
18
- autoload :Extension, "rbplusplus/extension"
19
- autoload :RbModule, "rbplusplus/module"
18
+ autoload :Extension, "rbplusplus/extension"
19
+ autoload :RbModule, "rbplusplus/module"
20
+ autoload :Logger, "rbplusplus/logger"
20
21
 
21
22
  module Builders
22
- autoload :Base, "rbplusplus/builders/base"
23
- autoload :ClassBuilder, "rbplusplus/builders/class"
24
- autoload :ExtensionBuilder, "rbplusplus/builders/extension"
25
- autoload :ModuleBuilder, "rbplusplus/builders/module"
26
- autoload :EnumerationBuilder, "rbplusplus/builders/enumeration"
27
- autoload :TypesManager, "rbplusplus/builders/types_manager"
23
+
24
+ autoload :Base, "rbplusplus/builders/base"
25
+ autoload :ExtensionNode, "rbplusplus/builders/extension"
26
+
27
+ autoload :ConstNode, "rbplusplus/builders/const"
28
+ autoload :ModuleNode, "rbplusplus/builders/module"
29
+ autoload :IncludeNode, "rbplusplus/builders/include"
30
+ autoload :EnumerationNode, "rbplusplus/builders/enumeration"
31
+
32
+ # Class related nodes
33
+ autoload :ClassNode, "rbplusplus/builders/class"
34
+ autoload :DirectorNode, "rbplusplus/builders/director"
35
+ autoload :ConstructorNode, "rbplusplus/builders/constructor"
36
+ autoload :InstanceVariableNode, "rbplusplus/builders/instance_variable"
37
+
38
+ # Rice type-management nodes
39
+ autoload :ConstConverterNode, "rbplusplus/builders/const_converter"
40
+ autoload :AllocationStrategyNode, "rbplusplus/builders/allocation_strategy"
41
+
42
+ # Method Nodes
43
+ autoload :MethodBase, "rbplusplus/builders/method_base"
44
+ autoload :MethodNode, "rbplusplus/builders/method"
45
+ autoload :StaticMethodNode, "rbplusplus/builders/static_method"
46
+ autoload :DirectorMethodNode, "rbplusplus/builders/director_method"
47
+ autoload :ModuleFunctionNode, "rbplusplus/builders/module_function"
48
+ autoload :GlobalFunctionNode, "rbplusplus/builders/global_function"
49
+
50
+ # Helpers
51
+ autoload :ClassHelpers, "rbplusplus/builders/helpers/class"
52
+ autoload :EnumerationHelpers, "rbplusplus/builders/helpers/enumeration"
53
+ autoload :ModuleHelpers, "rbplusplus/builders/helpers/module"
54
+
28
55
  end
29
56
 
30
57
  module Writers
31
- autoload :Base, "rbplusplus/writers/base"
32
- autoload :ExtensionWriter, "rbplusplus/writers/extension"
33
- autoload :MultipleFilesWriter, "rbplusplus/writers/multiple_files_writer"
34
- autoload :SingleFileWriter, "rbplusplus/writers/single_file_writer"
58
+ autoload :Base, "rbplusplus/writers/base"
59
+ autoload :ExtensionWriter, "rbplusplus/writers/extension"
60
+ autoload :MultipleFilesWriter, "rbplusplus/writers/multiple_files_writer"
61
+ autoload :SingleFileWriter, "rbplusplus/writers/single_file_writer"
35
62
  end
36
63
  end
37
64
 
@@ -39,18 +66,17 @@ class String #:nodoc:
39
66
  # Functionize attempts to rename a string in a cpp function friendly way.
40
67
  #
41
68
  # vector<float>::x => vector_float__x
42
- def functionize
69
+ def as_variable
43
70
  gsub("::","_").gsub(/[ ,<>]/, "_").gsub("*", "Ptr")
44
71
  end
45
72
  end
46
73
 
74
+ # Transformer classes that reopen RbGCCXML classes to add functionality
47
75
  require 'rbplusplus/transformers/rbgccxml'
48
76
  require 'rbplusplus/transformers/node_cache'
49
77
  require 'rbplusplus/transformers/node'
50
- require 'rbplusplus/transformers/node_reference'
51
78
  require 'rbplusplus/transformers/function'
52
- require 'rbplusplus/transformers/method'
53
- require 'rbplusplus/transformers/constructor'
54
79
  require 'rbplusplus/transformers/class'
55
- require 'rbplusplus/transformers/module'
80
+ require 'rbplusplus/transformers/method'
81
+ require 'rbplusplus/transformers/namespace'
56
82
 
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Allocation Strategies" do
4
+
5
+ def setup
6
+ if !defined?(@@alloc_strat_built)
7
+ super
8
+ @@alloc_strat_built = true
9
+ Extension.new "alloc_strats" do |e|
10
+ e.sources full_dir("headers/alloc_strats.h")
11
+ node = e.namespace "alloc_strats"
12
+ end
13
+ end
14
+ end
15
+
16
+ # The test here is simple because if the allocation
17
+ # strategies aren't properly defined, the extension
18
+ # won't even compile. GCC will complain about trying to
19
+ # instantiate an object with a non-public constructor
20
+ # and it all dies.
21
+ specify "properly figures out what allocation to do" do
22
+ assert_nothing_raised LoadError do
23
+ require 'alloc_strats'
24
+ end
25
+
26
+ # Private constructor, public destructor
27
+ assert defined?(NoConstructor)
28
+
29
+ # Private constructor and destructor
30
+ assert defined?(Neither)
31
+ end
32
+
33
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Correct handling of encapsulated methods" do
4
+ def setup
5
+ if !defined?(@@encapsulated)
6
+ super
7
+ @@encapsulated = true
8
+ Extension.new "encapsulation" do |e|
9
+ e.sources full_dir("headers/class_methods.h")
10
+ node = e.namespace "encapsulation"
11
+ end
12
+
13
+ require 'encapsulation'
14
+ end
15
+ end
16
+
17
+ specify "should handle private/protected/public" do
18
+ ext = Extended.new
19
+ ext.public_method.should == 1
20
+ should.raise NoMethodError do
21
+ ext.private_method
22
+ end
23
+ should.raise NoMethodError do
24
+ ext.protected_method
25
+ end
26
+ end
27
+
28
+ specify "should handle virtual methods" do
29
+ ext_factory = ExtendedFactory.new
30
+ ext = ext_factory.new_instance
31
+ ext.fundamental_type_virtual_method.should == 1
32
+ ext.user_defined_type_virtual_method.class.should == Base
33
+ end
34
+
35
+ specify "don't wrap methods that use non-public types in their arguments" do
36
+ arg = ArgumentAccess.new
37
+
38
+ # Single argument methods
39
+ should.raise NoMethodError do
40
+ arg.wrap_me_private
41
+ end
42
+ should.raise NoMethodError do
43
+ arg.wrap_me_protected
44
+ end
45
+
46
+ should.not.raise NoMethodError do
47
+ arg.wrap_me_public ArgumentAccess::PublicStruct.new
48
+ end
49
+
50
+ # Multiple argument methods
51
+ should.raise NoMethodError do
52
+ arg.wrap_me_many_no
53
+ end
54
+ should.not.raise NoMethodError do
55
+ arg.wrap_me_many_yes(1, 2.0, ArgumentAccess::PublicStruct.new)
56
+ end
57
+ end
58
+ end
59
+
@@ -5,12 +5,12 @@ context "Correct handling of static methods" do
5
5
  if !defined?(@@complex_static)
6
6
  super
7
7
  @@complex_static = true
8
- Extension.new "complex" do |e|
8
+ Extension.new "complex_test" do |e|
9
9
  e.sources full_dir("headers/complex_static_methods.h")
10
10
  node = e.namespace "complex"
11
11
  end
12
12
 
13
- require 'complex'
13
+ require 'complex_test'
14
14
  end
15
15
  end
16
16
 
@@ -20,36 +20,3 @@ context "Correct handling of static methods" do
20
20
 
21
21
  end
22
22
 
23
- context "Correct handling of encapsulated methods" do
24
- def setup
25
- if !defined?(@@encapsulated)
26
- super
27
- @@encapsulated = true
28
- Extension.new "encapsulation" do |e|
29
- e.sources full_dir("headers/class_methods.h")
30
- node = e.namespace "encapsulation"
31
- end
32
-
33
- require 'encapsulation'
34
- end
35
- end
36
-
37
- specify "should handle private/protected/public" do
38
- ext = Extended.new
39
- ext.public_method.should == 1
40
- should.raise NoMethodError do
41
- ext.private_method
42
- end
43
- should.raise NoMethodError do
44
- ext.protected_method
45
- end
46
- end
47
-
48
- specify "should handle virtual methods" do
49
- ext_factory = ExtendedFactory.new
50
- ext = ext_factory.new_instance
51
- ext.fundamental_type_virtual_method.should == 1
52
- ext.user_defined_type_virtual_method.class.should == Base
53
- end
54
- end
55
-
data/test/classes_test.rb CHANGED
@@ -7,8 +7,19 @@ context "Extension with wrapped classes" do
7
7
  super
8
8
  @@adder_built = true
9
9
  Extension.new "adder" do |e|
10
- e.sources full_dir("headers/Adder.h")
11
- e.namespace "classes"
10
+ e.sources full_dir("headers/Adder.h"),
11
+ :include_source_files => [
12
+ full_dir("headers/Adder.h"),
13
+ full_dir("headers/Adder.cpp")
14
+ ]
15
+ node = e.namespace "classes"
16
+ adder = node.classes("Adder")
17
+ adder.use_constructor(
18
+ adder.constructors.find(:arguments => [])
19
+ )
20
+
21
+ adder.constants("HideMe").ignore
22
+ adder.disable_typedef_lookup
12
23
  end
13
24
 
14
25
  require 'adder'
@@ -38,5 +49,64 @@ context "Extension with wrapped classes" do
38
49
  Adder.do_adding(1, 2, 3, 4, 5).should == 15
39
50
  end
40
51
 
52
+ specify "should use typedefs when findable" do
53
+ assert defined?(IntAdder), "Did not use the typedef for TemplateAdder"
54
+ end
55
+
56
+ specify "finds and uses multi-nested typedefs" do
57
+ assert defined?(ShouldFindMe), "Didn't find top level typedef for NestedTemplate"
58
+ end
59
+
60
+ specify "can turn off typedef lookup for certain classes" do
61
+ assert !defined?(DontFindMeBro), "Found a typedef we shouldn't have"
62
+ end
63
+
64
+ specify "makes class constants available" do
65
+ Adder::MY_VALUE.should == 10
66
+ end
67
+
68
+ specify "can ignore constants" do
69
+ assert !defined?(Adder::HideMe), "Found HideMe when I shouldn't have"
70
+ end
71
+
72
+ specify "makes public instance variables accessible" do
73
+ a = Adder.new
74
+ a.value1 = 10
75
+ a.value2 = 15.5
76
+ a.value3 = "This is a value!"
77
+ a.should_be_transformed = "TRANSFORM"
78
+
79
+ a.value1.should.equal 10
80
+ a.value2.should.be.close 15.5, 0.01
81
+ a.value3.should.equal "This is a value!"
82
+
83
+ a.should_be_transformed.should.equal "TRANSFORM"
84
+ end
85
+
86
+ specify "const variables are exported as read-only" do
87
+ a = Adder.new
88
+
89
+ should.raise NoMethodError do
90
+ a.const_var = "This is a value!"
91
+ end
92
+
93
+ a.const_var.should.equal 14
94
+ end
95
+
96
+ specify "can subclass a wrapped class and go from there" do
97
+ class MyAdder < Adder
98
+ def add_integers(a, b)
99
+ a * b
100
+ end
101
+
102
+ def add_strings(a, b)
103
+ super(a, b) + "woot"
104
+ end
105
+ end
106
+
107
+ a = MyAdder.new
108
+ a.add_integers(3, 7).should.equal 21
109
+ a.add_strings("piz", "owned").should.equal "pizownedwoot"
110
+ end
41
111
  end
42
112
 
@@ -156,4 +156,17 @@ context "Compiler settings" do
156
156
  # is a symbol lookup failure and death to the Ruby VM
157
157
  needs_to_ruby(3).value.should == 3
158
158
  end
159
+
160
+ specify "can specify a directory containing code to be included into compilation process" do
161
+ Extension.new "code_dir" do |e|
162
+ e.sources full_dir("headers/needs_code.h"),
163
+ :include_source_dir => full_dir("headers/code")
164
+
165
+ e.namespace "needs_code"
166
+ end
167
+
168
+ require 'code_dir'
169
+
170
+ get_number(2).should == 2
171
+ end
159
172
  end
@@ -2,34 +2,25 @@ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  context "Extension with constructors out the whazoo" do
4
4
 
5
- # Test is currently broken due to something Rice is or isn't doing.
6
- xspecify "should make constructors available" do
5
+ specify "should make constructors available" do
7
6
  Extension.new "constructors" do |e|
8
7
  e.sources full_dir("headers/constructors.h")
9
8
  node = e.namespace "constructors"
10
- e.writer_mode :single
11
- end
12
9
 
13
- require 'constructors'
14
10
 
15
- should.not.raise NameError do
16
- # Constructor overloading not yet supported
17
- # s = StringHolder.new
18
- # s.set_name "two"
19
- # s.get_name.should == "two"
20
-
21
- s2 = StringHolder.new "one"
22
- s2.get_name.should == "one"
11
+ node.classes("DoubleStringHolder").use_constructor(
12
+ node.classes("DoubleStringHolder").constructors.find(:arguments => [nil, nil])
13
+ )
23
14
  end
24
15
 
16
+ require 'constructors'
17
+
25
18
  should.not.raise NameError do
26
19
  # Test complex constructors
27
- d = DoubleStringHolder.new(StringHolder.new("one"), StringHolder.new("two"))
20
+ d = DoubleStringHolder.new("one", "two")
28
21
  one = d.get_one
29
- puts "Got one #{one.inspect}"
30
- puts "Name is #{one.get_name}"
31
- # d.get_one.get_name.should == "one"
32
- # d.get_two.get_name.should == "two"
22
+ d.get_one.should == "one"
23
+ d.get_two.should == "two"
33
24
  end
34
25
 
35
26
  should.raise TypeError do
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Extension with wrapped classes" do
4
+
5
+ def setup
6
+ if !defined?(@@adder_built)
7
+ super
8
+ @@adder_built = true
9
+ Extension.new "adder" do |e|
10
+ e.sources full_dir("headers/Adder.h"),
11
+ :include_source_files => [
12
+ full_dir("headers/Adder.h"),
13
+ full_dir("headers/Adder.cpp")
14
+ ]
15
+ node = e.namespace "classes"
16
+ adder = node.classes("Adder")
17
+
18
+ adder.use_constructor( adder.constructors.find(:arguments => []))
19
+ adder.disable_typedef_lookup
20
+
21
+ decl = <<-END
22
+ int subtractIntegers(classes::Adder* self, int a, int b) {
23
+ return a - b;
24
+ }
25
+
26
+ int multiplyIntegers(classes::Adder* self, int a, int b) {
27
+ return a * b;
28
+ }
29
+ END
30
+
31
+ wrapping = <<-END
32
+ <class>.define_method(\"sub_ints\", &subtractIntegers);
33
+ <class>.define_method(\"mult_ints\", &multiplyIntegers);
34
+ END
35
+
36
+ adder.add_custom_code( decl, wrapping )
37
+ end
38
+
39
+ require 'adder'
40
+ end
41
+ end
42
+
43
+ specify "Adder has new custom methods" do
44
+ a = Adder.new
45
+ a.should.respond_to(:sub_ints)
46
+ a.should.respond_to(:mult_ints)
47
+
48
+ a.sub_ints(5, 4).should.equal 1
49
+ a.mult_ints(5, 4).should.equal 20
50
+ end
51
+
52
+ end
53
+
@@ -0,0 +1,69 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Default arguments properly exposed" do
4
+
5
+ def setup
6
+ if !defined?(@@defargs_built)
7
+ super
8
+ @@defargs_built = true
9
+ Extension.new "defargs" do |e|
10
+ e.sources full_dir("headers/default_arguments.h")
11
+ e.writer_mode :single
12
+ node = e.namespace "default_args"
13
+
14
+ e.module "Inner" do |m|
15
+ m.includes node.functions("module_do")
16
+ end
17
+
18
+ node.classes("Directed").director
19
+ end
20
+
21
+ require 'defargs'
22
+ end
23
+ end
24
+
25
+ specify "global functions" do
26
+ global_do(1, 4, 5).should.equal 20
27
+ global_do(1, 4).should.equal 40
28
+ global_do(1).should.equal 30
29
+ end
30
+
31
+ specify "module functions" do
32
+ Inner.module_do(5).should.equal 18
33
+ Inner.module_do(5, 5).should.equal 20
34
+ Inner.module_do(5, 5, 5).should.equal 15
35
+ end
36
+
37
+ specify "class instance methods" do
38
+ tester = Tester.new
39
+ tester.concat("this", "that").should.equal "this-that"
40
+ tester.concat("this", "that", ";").should.equal "this;that"
41
+ end
42
+
43
+ specify "class static methods" do
44
+ Tester.build("base").should.equal "basebasebase"
45
+ Tester.build("woot", 5).should.equal "wootwootwootwootwoot"
46
+ end
47
+
48
+ specify "director methods" do
49
+ d = Directed.new
50
+ d.virtual_do(3).should.equal 30
51
+ d.virtual_do(3, 9).should.equal 27
52
+
53
+ class MyD < Directed
54
+ def virtual_do(x, y = 10)
55
+ super(x * 3, y)
56
+ end
57
+ end
58
+
59
+ myd = MyD.new
60
+ myd.virtual_do(10).should.equal 300
61
+ end
62
+
63
+ specify "throw argument error on bad types" do
64
+ should.raise TypeError do
65
+ global_do(1, "three")
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,173 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ context "Director proxy generation" do
4
+
5
+ def setup
6
+ if !defined?(@@director_built)
7
+ super
8
+ @@director_built = true
9
+ Extension.new "director" do |e|
10
+ e.sources full_dir("headers/director.h")
11
+
12
+ node = e.namespace "director"
13
+
14
+ # As director is pretty complicated to get right
15
+ # automatically for now, we force-specify which
16
+ # classes to have directors set on.
17
+ %w(Worker MultiplyWorker BadNameClass VirtualWithArgs NoConstructor VBase VOne VTwo).each do |k|
18
+ node.classes(k).director
19
+ end
20
+
21
+ node.classes("Worker").methods("doProcessImpl").default_return_value(0)
22
+
23
+ klass = node.classes("BadNameClass")
24
+ klass.wrap_as("BetterNamedClass")
25
+ klass.methods("_is_x_ok_to_run").wrap_as("x_ok?")
26
+ klass.methods("__do_someProcessing").wrap_as("do_processing")
27
+ end
28
+
29
+ require 'director'
30
+ end
31
+ end
32
+
33
+ specify "polymorphic calls extend into Ruby" do
34
+ class MyWorker < Worker
35
+ def process(num)
36
+ num + 10
37
+ end
38
+ end
39
+
40
+ h = Handler.new
41
+ h.add_worker(MyWorker.new)
42
+
43
+ h.process_workers(5).should.equal 15
44
+ end
45
+
46
+ specify "super calls on pure virtual raise exception" do
47
+ class SuperBadWorker < Worker
48
+ def process(num)
49
+ super + 10
50
+ end
51
+ end
52
+
53
+ should.raise NotImplementedError do
54
+ SuperBadWorker.new.process(10)
55
+ end
56
+ end
57
+
58
+ specify "allows super calls to continue back into C++ classes" do
59
+ class SuperGoodWorker < Worker
60
+ def do_something(num)
61
+ super + 10
62
+ end
63
+ end
64
+
65
+ should.not.raise NotImplementedError do
66
+ SuperGoodWorker.new.do_something(10).should.equal 50
67
+ end
68
+ end
69
+
70
+ specify "can specify a default return value in the wrapper" do
71
+ class MyAwesomeWorker < Worker
72
+ def do_process_impl(num)
73
+ num + 7
74
+ end
75
+
76
+ def process(num)
77
+ num + 8
78
+ end
79
+ end
80
+
81
+ w = MyAwesomeWorker.new
82
+ w.do_process(3).should.equal 10
83
+
84
+ h = Handler.new
85
+ h.add_worker(w)
86
+
87
+ h.process_workers(10).should.equal 18
88
+ end
89
+
90
+ specify "properly adds all constructor arguments" do
91
+ v = VirtualWithArgs.new 14, true
92
+ v.process_a("hi").should.equal 16
93
+ v.process_b.should.be true
94
+ end
95
+
96
+ specify "takes into account renamed methods / classes" do
97
+ c = BetterNamedClass.new
98
+ assert !c.x_ok?
99
+
100
+ c.do_processing.should.equal 14
101
+ end
102
+
103
+ specify "handles no constructors" do
104
+ class MyThing < NoConstructor
105
+ end
106
+
107
+ n = MyThing.new
108
+ n.do_something.should.equal 4
109
+ end
110
+
111
+ specify "only builds method wrappers for virtual methods" do
112
+ class NumberWorker < Worker
113
+ def get_number
114
+ super + 15
115
+ end
116
+ end
117
+
118
+ # Super calls still work
119
+ w = NumberWorker.new
120
+ w.get_number.should.equal 27
121
+
122
+ # But polymorphism stops in the C++
123
+ h = Handler.new
124
+ h.add_worker(w)
125
+
126
+ h.add_worker_numbers.should.equal 12
127
+ end
128
+
129
+ specify "Directors implement all pure virtual methods up the inheritance tree" do
130
+ vbase = VBase.new
131
+ v1 = VOne.new
132
+ v2 = VTwo.new
133
+
134
+ v1.method_one.should.equal "methodOne"
135
+
136
+ should.raise NotImplementedError do
137
+ v1.method_two
138
+ end
139
+ should.raise NotImplementedError do
140
+ v1.method_three
141
+ end
142
+
143
+ v2.method_one.should.equal "methodOne"
144
+ v2.method_two.should.equal "methodTwo"
145
+
146
+ should.raise NotImplementedError do
147
+ v2.method_three
148
+ end
149
+ end
150
+
151
+ specify "handles superclasses of the class with virtual methods" do
152
+ class QuadWorker < MultiplyWorker
153
+ def process(num)
154
+ num * 4
155
+ end
156
+ end
157
+
158
+ h = Handler.new
159
+
160
+ h.add_worker(MultiplyWorker.new)
161
+ h.process_workers(5).should.equal 10
162
+
163
+ h.add_worker(QuadWorker.new)
164
+ h.process_workers(5).should.equal 40
165
+ end
166
+
167
+ specify "multiple files writer properly handles directors and nested nodes" do
168
+ assert defined?(Worker::ZeeEnum)
169
+ assert defined?(Worker::ZeeEnum::VALUE)
170
+ Worker::ZeeEnum::VALUE.to_i.should.equal 4
171
+ end
172
+
173
+ end