rice 4.6.1 → 4.7.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/CMakeLists.txt +0 -4
  4. data/Rakefile +2 -8
  5. data/bin/rice-doc.rb +212 -0
  6. data/bin/rice-rbs.rb +93 -0
  7. data/include/rice/rice.hpp +4972 -4015
  8. data/include/rice/stl.hpp +822 -294
  9. data/lib/rice/doc/cpp_reference.rb +166 -0
  10. data/lib/rice/doc/doxygen.rb +294 -0
  11. data/lib/rice/doc/mkdocs.rb +298 -0
  12. data/lib/rice/doc/rice.rb +29 -0
  13. data/lib/rice/doc/ruby.rb +37 -0
  14. data/lib/rice/doc.rb +5 -0
  15. data/lib/{make_rice_headers.rb → rice/make_rice_headers.rb} +3 -0
  16. data/lib/rice/native.rb +18 -0
  17. data/lib/rice/native_registry.rb +21 -0
  18. data/lib/rice/parameter.rb +7 -0
  19. data/lib/rice/rbs.rb +104 -0
  20. data/lib/rice/version.rb +1 -1
  21. data/lib/rice.rb +4 -0
  22. data/lib/rubygems/cmake_builder.rb +24 -27
  23. data/rice/Arg.hpp +4 -4
  24. data/rice/Arg.ipp +4 -4
  25. data/rice/Buffer.hpp +32 -28
  26. data/rice/Buffer.ipp +306 -178
  27. data/rice/Data_Object.ipp +101 -82
  28. data/rice/Data_Type.hpp +5 -7
  29. data/rice/Data_Type.ipp +48 -29
  30. data/rice/Enum.ipp +15 -21
  31. data/rice/Function.hpp +17 -0
  32. data/rice/Function.ipp +13 -0
  33. data/rice/Pointer.hpp +15 -0
  34. data/rice/Pointer.ipp +49 -0
  35. data/rice/Return.hpp +1 -1
  36. data/rice/Return.ipp +2 -2
  37. data/rice/api.hpp +30 -0
  38. data/rice/cpp_api/Array.hpp +2 -2
  39. data/rice/cpp_api/Array.ipp +50 -5
  40. data/rice/cpp_api/Class.hpp +0 -5
  41. data/rice/cpp_api/Class.ipp +19 -0
  42. data/rice/cpp_api/Hash.ipp +20 -0
  43. data/rice/cpp_api/Module.hpp +6 -3
  44. data/rice/cpp_api/Module.ipp +49 -11
  45. data/rice/cpp_api/Object.ipp +31 -2
  46. data/rice/cpp_api/String.hpp +1 -2
  47. data/rice/cpp_api/String.ipp +21 -1
  48. data/rice/cpp_api/Struct.ipp +5 -0
  49. data/rice/cpp_api/Symbol.ipp +34 -0
  50. data/rice/cpp_api/shared_methods.hpp +12 -12
  51. data/rice/detail/MethodInfo.hpp +4 -2
  52. data/rice/detail/MethodInfo.ipp +19 -3
  53. data/rice/detail/ModuleRegistry.hpp +18 -0
  54. data/rice/detail/ModuleRegistry.ipp +25 -0
  55. data/rice/detail/Native.hpp +45 -2
  56. data/rice/detail/Native.ipp +196 -2
  57. data/rice/detail/NativeAttributeGet.hpp +9 -4
  58. data/rice/detail/NativeAttributeGet.ipp +65 -11
  59. data/rice/detail/NativeAttributeSet.hpp +4 -0
  60. data/rice/detail/NativeAttributeSet.ipp +30 -2
  61. data/rice/detail/NativeCallbackFFI.ipp +2 -2
  62. data/rice/detail/NativeCallbackSimple.ipp +1 -1
  63. data/rice/detail/NativeFunction.hpp +11 -49
  64. data/rice/detail/NativeFunction.ipp +82 -379
  65. data/rice/detail/NativeInvoker.hpp +74 -0
  66. data/rice/detail/NativeInvoker.ipp +197 -0
  67. data/rice/detail/NativeIterator.hpp +4 -0
  68. data/rice/detail/NativeIterator.ipp +19 -0
  69. data/rice/detail/NativeMethod.hpp +97 -0
  70. data/rice/detail/NativeMethod.ipp +332 -0
  71. data/rice/detail/NativeProc.hpp +51 -0
  72. data/rice/detail/NativeProc.ipp +133 -0
  73. data/rice/detail/NativeRegistry.hpp +8 -0
  74. data/rice/detail/NativeRegistry.ipp +27 -0
  75. data/rice/detail/Parameter.hpp +47 -0
  76. data/rice/detail/Parameter.ipp +105 -0
  77. data/rice/detail/Proc.ipp +14 -13
  78. data/rice/detail/Registries.hpp +1 -0
  79. data/rice/detail/RubyType.hpp +0 -2
  80. data/rice/detail/RubyType.ipp +15 -33
  81. data/rice/detail/Type.hpp +44 -8
  82. data/rice/detail/Type.ipp +151 -49
  83. data/rice/detail/TypeRegistry.hpp +3 -0
  84. data/rice/detail/TypeRegistry.ipp +17 -27
  85. data/rice/detail/Types.ipp +430 -0
  86. data/rice/detail/Wrapper.hpp +12 -0
  87. data/rice/detail/Wrapper.ipp +45 -2
  88. data/rice/detail/from_ruby.ipp +567 -1073
  89. data/rice/detail/ruby.hpp +1 -0
  90. data/rice/detail/to_ruby.ipp +4 -635
  91. data/rice/libc/file.ipp +3 -6
  92. data/rice/rice.hpp +22 -12
  93. data/rice/rice_api/Arg.hpp +7 -0
  94. data/rice/rice_api/Arg.ipp +9 -0
  95. data/rice/rice_api/ModuleRegistry.hpp +7 -0
  96. data/rice/rice_api/ModuleRegistry.ipp +10 -0
  97. data/rice/rice_api/Native.hpp +7 -0
  98. data/rice/rice_api/Native.ipp +52 -0
  99. data/rice/rice_api/NativeRegistry.hpp +7 -0
  100. data/rice/rice_api/NativeRegistry.ipp +21 -0
  101. data/rice/rice_api/Parameter.hpp +7 -0
  102. data/rice/rice_api/Parameter.ipp +11 -0
  103. data/rice/rice_api/Registries.hpp +6 -0
  104. data/rice/rice_api/Registries.ipp +12 -0
  105. data/rice/rice_api/TypeRegistry.hpp +7 -0
  106. data/rice/rice_api/TypeRegistry.ipp +10 -0
  107. data/rice/stl/complex.ipp +35 -0
  108. data/rice/stl/exception.ipp +20 -7
  109. data/rice/stl/filesystem.hpp +6 -0
  110. data/rice/stl/filesystem.ipp +34 -0
  111. data/rice/stl/map.ipp +13 -21
  112. data/rice/stl/monostate.ipp +37 -1
  113. data/rice/stl/multimap.ipp +17 -24
  114. data/rice/stl/optional.ipp +47 -2
  115. data/rice/stl/pair.ipp +23 -58
  116. data/rice/stl/reference_wrapper.ipp +22 -1
  117. data/rice/stl/set.ipp +17 -9
  118. data/rice/stl/shared_ptr.ipp +44 -17
  119. data/rice/stl/string.ipp +175 -7
  120. data/rice/stl/string_view.ipp +5 -0
  121. data/rice/stl/tuple.ipp +38 -9
  122. data/rice/stl/unique_ptr.ipp +46 -2
  123. data/rice/stl/unordered_map.ipp +13 -21
  124. data/rice/stl/variant.ipp +47 -11
  125. data/rice/stl/vector.ipp +183 -104
  126. data/rice/stl.hpp +1 -0
  127. data/rice/traits/function_traits.hpp +2 -2
  128. data/rice/traits/method_traits.hpp +5 -16
  129. data/rice/traits/rice_traits.hpp +24 -4
  130. data/rice.gemspec +11 -22
  131. data/test/embed_ruby.cpp +0 -3
  132. data/test/test_Array.cpp +38 -38
  133. data/test/test_Attribute.cpp +187 -2
  134. data/test/test_Buffer.cpp +302 -26
  135. data/test/test_Callback.cpp +2 -3
  136. data/test/test_Class.cpp +5 -5
  137. data/test/test_Data_Object.cpp +0 -55
  138. data/test/test_Data_Type.cpp +19 -30
  139. data/test/test_Enum.cpp +4 -46
  140. data/test/test_From_Ruby.cpp +88 -81
  141. data/test/test_GVL.cpp +109 -0
  142. data/test/test_Iterator.cpp +1 -1
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -3
  144. data/test/test_Module.cpp +8 -9
  145. data/test/test_Object.cpp +1 -1
  146. data/test/test_Overloads.cpp +3 -3
  147. data/test/test_Stl_Map.cpp +8 -8
  148. data/test/test_Stl_Multimap.cpp +4 -4
  149. data/test/test_Stl_Pair.cpp +5 -3
  150. data/test/test_Stl_SharedPtr.cpp +24 -12
  151. data/test/test_Stl_Tuple.cpp +1 -1
  152. data/test/test_Stl_UniquePtr.cpp +8 -0
  153. data/test/test_Stl_Unordered_Map.cpp +9 -9
  154. data/test/test_Stl_Variant.cpp +9 -3
  155. data/test/test_Stl_Vector.cpp +118 -13
  156. data/test/test_To_Ruby.cpp +35 -28
  157. data/test/test_Type.cpp +256 -53
  158. data/test/unittest.hpp +35 -0
  159. metadata +66 -34
  160. data/rice/Init.hpp +0 -8
  161. data/rice/Init.ipp +0 -8
  162. data/rice/detail/RubyFunction.hpp +0 -31
  163. data/rice/detail/RubyFunction.ipp +0 -77
  164. data/sample/callbacks/extconf.rb +0 -5
  165. data/sample/callbacks/sample_callbacks.cpp +0 -35
  166. data/sample/callbacks/test.rb +0 -28
  167. data/sample/enum/extconf.rb +0 -5
  168. data/sample/enum/sample_enum.cpp +0 -40
  169. data/sample/enum/test.rb +0 -8
  170. data/sample/inheritance/animals.cpp +0 -82
  171. data/sample/inheritance/extconf.rb +0 -5
  172. data/sample/inheritance/test.rb +0 -7
  173. data/sample/map/extconf.rb +0 -5
  174. data/sample/map/map.cpp +0 -73
  175. data/sample/map/test.rb +0 -7
  176. data/test/ext/t1/Foo.hpp +0 -10
  177. data/test/ext/t1/extconf.rb +0 -4
  178. data/test/ext/t1/t1.cpp +0 -13
  179. data/test/ext/t2/extconf.rb +0 -4
  180. data/test/ext/t2/t2.cpp +0 -11
  181. data/test/ruby/test_callbacks_sample.rb +0 -28
  182. data/test/ruby/test_multiple_extensions.rb +0 -18
  183. data/test/ruby/test_multiple_extensions_same_class.rb +0 -14
  184. data/test/ruby/test_multiple_extensions_with_inheritance.rb +0 -20
  185. /data/test/{test_Stl_Type.cpp → test_Stl_Type_Info.cpp} +0 -0
@@ -0,0 +1,166 @@
1
+ require 'open-uri'
2
+ require 'libxml-ruby'
3
+
4
+ module Rice
5
+ module Doc
6
+ class CppReference
7
+ ROOT = "https://en.cppreference.com/w"
8
+ INDEX = "https://raw.githubusercontent.com/p12tic/cppreference-doc/refs/heads/master/index-functions-cpp.xml"
9
+ #INDEX = "c:/Users/cfis/Downloads/index-functions-cpp.xml"
10
+
11
+ OPERATORS = {"assign" => "operator=",
12
+ "assign_plus" => "operator+=",
13
+ "assign_minus" => "operator-=",
14
+ "assign_multiply" => "operator*=",
15
+ "assign_divide" => "operator/=",
16
+ "call" => "operator()",
17
+ "decrement" => "operator--",
18
+ "dereference" => "operator*",
19
+ "increment" => "operator++",
20
+ "==" => "operator==",
21
+ "!=" => "operator!=",
22
+ "+" => "operator+",
23
+ "-" => "operator-",
24
+ "*" => "operator*",
25
+ "/" => "operator/",
26
+ "&" => "operator&",
27
+ "|" => "operator|",
28
+ "<" => "operator<",
29
+ ">" => "operator>",
30
+ "<=" => "operator<=",
31
+ "<<" => "operator<<",
32
+ "[]" => "operator[]",
33
+ "[]=" => "operator[]"}
34
+
35
+ def initialize
36
+ @type_mappings = {/^enum\s*/i => '',
37
+ /^union\s*/i => '',
38
+ /<.*>/ => ''}
39
+
40
+ @method_mappings = {'std::exception' => {'message' => 'what'},
41
+ 'std::map' => {'delete' => 'erase',
42
+ 'include?' => 'find'},
43
+ 'std::multimap' => {'delete' => 'erase',
44
+ 'include?' => 'find'},
45
+ 'std::runtime_error' => {'message' => 'what'},
46
+ 'std::unorderedmap' => {'delete' => 'erase',
47
+ 'include?' => 'find'},
48
+ 'std::vector' => {'delete_at' => 'erase',
49
+ 'first' => 'front',
50
+ 'last' => 'back',
51
+ 'pop' => 'pop_back',
52
+ 'push' => 'push_back'}}
53
+
54
+ @cache = Hash.new
55
+ data = URI.open(INDEX).read
56
+ parser = LibXML::XML::Parser.string(data)
57
+ @doc = parser.parse
58
+ end
59
+
60
+ def camelize(content, capitalize = true)
61
+ result = content.gsub(/(?:_)(.)/) do |matched|
62
+ $1.capitalize
63
+ end
64
+
65
+ result[0] = capitalize ? result[0].upcase : result[0].downcase
66
+ result
67
+ end
68
+
69
+ def cpp_name(klass)
70
+ result = klass.cpp_class
71
+ @type_mappings.each do |key, value|
72
+ result = result.gsub(key, value)
73
+ end
74
+ result
75
+ end
76
+
77
+ def get_node(klass, xpath)
78
+ node = @cache[klass]
79
+ if node.nil? && !@cache.has_key?(klass)
80
+ node = @cache[klass] = @doc.find_first(xpath)
81
+ end
82
+ node
83
+ end
84
+
85
+ def class_node(klass)
86
+ xpath = "//class[@name='#{cpp_name(klass)}']"
87
+ get_node(klass, xpath)
88
+ end
89
+
90
+ def class_base(klass)
91
+ node = class_node(klass)
92
+ if node
93
+ path = node.attributes["link"]
94
+ name = cpp_name(klass)
95
+ parts = name.split("::")
96
+ "#{ROOT}/#{path}"
97
+ end
98
+ end
99
+
100
+ def class_url(klass)
101
+ node = class_node(klass)
102
+ if node
103
+ "#{class_base(klass)}.html"
104
+ end
105
+ end
106
+
107
+ def module_url(klass)
108
+ a = 1
109
+ end
110
+
111
+ def method_url(klass, native)
112
+ node = class_node(klass)
113
+ if node
114
+ ruby_name = native.name
115
+ method_names = Array.new
116
+ if ruby_name == "initialize" || ruby_name == "initialize_copy"
117
+ return "#{class_base(klass)}.html"
118
+ elsif native_name = OPERATORS[ruby_name]
119
+ method_names << native_name
120
+ elsif native_name = @method_mappings.dig(cpp_name(klass), ruby_name)
121
+ method_names << native_name
122
+ elsif ruby_name.match(/\?$/)
123
+ native_name = ruby_name.gsub(/\?$/, "")
124
+ method_names << camelize(native_name, false)
125
+ method_names << camelize(native_name, true)
126
+ method_names << "is#{camelize(native_name, true)}"
127
+ else
128
+ method_names << ruby_name
129
+ method_names << camelize(ruby_name, false)
130
+ method_names << camelize(ruby_name, true)
131
+ end
132
+
133
+ pattern = method_names.map do |method_name|
134
+ "@name='#{method_name}'"
135
+ end.join(" or ")
136
+
137
+ xpath = "function[#{pattern}]"
138
+ member_node = node&.find_first(xpath)
139
+ if member_node && member_node.attributes["link"]
140
+ "#{class_base(klass)}/#{member_node.attributes['link']}.html"
141
+ elsif member_node
142
+ "#{class_base(klass)}/#{member_node.attributes['name']}.html"
143
+ end
144
+ end
145
+ end
146
+
147
+ def attribute_url(klass, native)
148
+ node = class_node(klass)
149
+
150
+ # Find the member node
151
+ attribute_name = camelize(native.name, false)
152
+
153
+ xpath = "variable[@name='#{attribute_name}']"
154
+ member_node = node&.find_first(xpath)
155
+ link = member_node.attributes["link"]
156
+ if member_node && link && link != "."
157
+ "#{class_base(klass)}/#{member_node.attributes['link']}.html"
158
+ elsif member_node && link && link == "."
159
+ "#{class_base(klass)}.html"
160
+ elsif member_node
161
+ "#{class_base(klass)}/#{member_node.attributes['name']}.html"
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,294 @@
1
+ require 'open-uri'
2
+ require 'libxml-ruby'
3
+
4
+ module Rice
5
+ module Doc
6
+ class Doxygen
7
+ OPERATORS = {"assign" => "operator=",
8
+ "assign_plus" => "operator+=",
9
+ "assign_minus" => "operator-=",
10
+ "assign_multiply" => "operator*=",
11
+ "assign_divide" => "operator/=",
12
+ "call" => "operator()",
13
+ "decrement" => "operator--",
14
+ "dereference" => "operator*",
15
+ "increment" => "operator++",
16
+ "==" => "operator==",
17
+ "!=" => "operator!=",
18
+ "+" => "operator+",
19
+ "-" => "operator-",
20
+ "*" => "operator*",
21
+ "/" => "operator/",
22
+ "&" => "operator&",
23
+ "|" => "operator|",
24
+ "<" => "operator<",
25
+ ">" => "operator>",
26
+ "<=" => "operator<=",
27
+ "<<" => "operator<<",
28
+ "[]" => "operator[]",
29
+ "[]=" => "operator[]"}
30
+
31
+ def initialize(root, index, type_mappings = Hash.new, method_mappings = Hash.new)
32
+ @root = root
33
+ @type_mappings = type_mappings
34
+ @method_mappings = method_mappings
35
+ @cache = Hash.new
36
+ @typedefs = Hash.new(Hash.new)
37
+
38
+ data = URI.open(index).read
39
+ parser = LibXML::XML::Parser.string(data)
40
+ @doc = parser.parse
41
+ end
42
+
43
+ def camelize(content, capitalize = true)
44
+ result = content.gsub(/(?:_)(.)/) do |matched|
45
+ $1.capitalize
46
+ end
47
+
48
+ result[0] = capitalize ? result[0].upcase : result[0].downcase
49
+ result
50
+ end
51
+
52
+ def url(member_node)
53
+ # Build url
54
+ anchor_file = member_node.find_first('anchorfile').content
55
+ anchor = member_node.find_first('anchor').content
56
+ "#{@root}/#{anchor_file}##{anchor}"
57
+ end
58
+
59
+ def cpp_name(klass)
60
+ result = klass.cpp_class
61
+ @type_mappings.each do |key, value|
62
+ result = result.gsub(key, value)
63
+ end
64
+ result
65
+ end
66
+
67
+ def get_node(klass, xpath)
68
+ node = @cache[klass]
69
+ if node.nil? && !@cache.has_key?(klass)
70
+ node = @cache[klass] = @doc.find_first(xpath)
71
+ end
72
+ node
73
+ end
74
+
75
+ def module_node(a_module)
76
+ xpath = "//tagfile/compound[@kind='namespace'][name='#{a_module.name.downcase}']"
77
+ result = get_node(a_module, xpath)
78
+ if result
79
+ read_typedefs(a_module, result)
80
+ end
81
+ result
82
+ end
83
+
84
+ def class_node(klass)
85
+ native_name = cpp_name(klass)
86
+ typedef_parts = native_name.split("::")
87
+ typedef_name = typedef_parts.pop
88
+
89
+ typedefs = @typedefs[klass.name.split("::").first]
90
+
91
+ if typedef_type = typedefs[typedef_name]
92
+ typedef_parts.push(typedef_type)
93
+ native_name = typedef_parts.join("::")
94
+ end
95
+
96
+ xpath = "//tagfile/compound[@kind='class' or @kind='struct' or @kind='union'][name='#{native_name}']"
97
+ get_node(klass, xpath)
98
+ end
99
+
100
+ def enum_node(klass)
101
+ cpp_name = klass.cpp_class.gsub(/^enum /, '')
102
+ cpp_parts = cpp_name.split("::")
103
+
104
+ kind = enum_kind(klass)
105
+ xpath = if kind == "group"
106
+ "//tagfile/compound[@kind='#{enum_kind(klass)}']/member[@kind='enumeration'][name='#{cpp_parts.last}']"
107
+ else
108
+ parent_name = cpp_name.split("::")[0..-2].join("::")
109
+ "//tagfile/compound[@kind='#{enum_kind(klass)}'][name='#{parent_name}']/member[@kind='enumeration'][name='#{cpp_parts.last}']"
110
+ end
111
+ get_node(klass, xpath)
112
+ end
113
+
114
+ def read_typedefs(klass, node)
115
+ typedefs = @typedefs[klass.name.split("::").first]
116
+ node.find("member[@kind='typedef']").each do |typedef|
117
+ name = typedef.find_first("name").content
118
+ type = typedef.find_first("type").content
119
+ type.gsub!(/(const|volatile|&|\*| )/, "")
120
+ typedefs[name] = type
121
+ end
122
+ end
123
+
124
+ def class_url(klass)
125
+ node = class_node(klass)
126
+ if node
127
+ file = node.find_first('filename').content
128
+ "#{@root}/#{file}"
129
+ end
130
+ end
131
+
132
+ def module_url(klass)
133
+ end
134
+
135
+ def figure_parent(klass)
136
+ # Split namespace
137
+ names = klass.name.split('::')
138
+ # Remove the class
139
+ names.pop
140
+
141
+ current_module = Object
142
+
143
+ names.each do |name|
144
+ current_module = current_module.const_get(name)
145
+ end
146
+
147
+ current_module
148
+ end
149
+
150
+ def enum_kind(klass)
151
+ parent = figure_parent(klass)
152
+ if parent == Object
153
+ "group"
154
+ elsif parent.is_a?(Class)
155
+ "class"
156
+ elsif parent.is_a?(Module)
157
+ "namespace"
158
+ else
159
+ raise("Unknown parent type: #{parent}")
160
+ end
161
+ end
162
+
163
+ def enum_url(klass)
164
+ cpp_name = klass.cpp_class.gsub(/^enum /, '')
165
+ cpp_parts = cpp_name.split("::")
166
+
167
+ kind = enum_kind(klass)
168
+ xpath = if kind == "group"
169
+ "//tagfile/compound[@kind='#{enum_kind(klass)}']/member[@kind='enumeration'][name='#{cpp_parts.last}']"
170
+ else
171
+ parent_name = cpp_name.split("::")[0..-2].join("::")
172
+ "//tagfile/compound[@kind='#{enum_kind(klass)}'][name='#{parent_name}']/member[@kind='enumeration'][name='#{cpp_parts.last}']"
173
+ end
174
+
175
+ member_node = @doc.find_first(xpath)
176
+ if member_node
177
+ url(member_node)
178
+ else
179
+ nil
180
+ end
181
+ end
182
+
183
+ def enum_value_url(klass, value)
184
+ node = enum_node(klass)
185
+ xpath = "../member[@kind='enumvalue'][name='#{value}']"
186
+ member_node = node&.find_first(xpath)
187
+ if member_node
188
+ url(member_node)
189
+ else
190
+ nil
191
+ end
192
+ end
193
+
194
+ def union_url(union)
195
+ node = class_node(union)
196
+ url_node = node.find_first('filename')
197
+ "#{OPENCV_ROOT}/#{url_node.content}"
198
+ end
199
+
200
+ def attribute_url(klass, native)
201
+ node = class_node(klass)
202
+
203
+ # Find the member node
204
+ attribute_name = camelize(native.name, false)
205
+
206
+ xpath = "member[@kind='variable'][name='#{attribute_name}']"
207
+ member_node = node&.find_first(xpath)
208
+ if member_node
209
+ url(member_node)
210
+ else
211
+ nil
212
+ end
213
+ end
214
+
215
+ def figure_member_node(native, xpath)
216
+ # First get all matching functions - remember C++ supports method overloads
217
+ member_nodes = @doc.find(xpath)
218
+ case member_nodes.size
219
+ when 0
220
+ return nil
221
+ when 1
222
+ return member_nodes.first
223
+ end
224
+
225
+ # Next filter members that have the same number of parameters
226
+ filtered = member_nodes.find_all do |member_node|
227
+ arglist_content = member_node.find_first('arglist').content
228
+ match = arglist_content.match(/\((.*)\)/)
229
+ tag_args = match[1].split(',')
230
+ tag_args.size == native.parameters.size
231
+ end
232
+
233
+ if filtered.size == 1
234
+ return filtered.first
235
+ end
236
+
237
+ # Next filter on type
238
+ filtered.first
239
+ end
240
+
241
+ def singleton_method_url(klass, native)
242
+ node = class_node(klass)
243
+ member_name = native.name.gsub(/\?$/, "")
244
+ member_name = camelize(member_name, false)
245
+ xpath = "member[@kind='function' and @static='yes'][name='#{member_name}' or name='#{member_name.capitalize}']"
246
+ member_node = node&.find_first(xpath)
247
+ if member_node
248
+ url(member_node)
249
+ end
250
+ end
251
+
252
+ def method_url(klass, native)
253
+ node = if klass.instance_of?(Module)
254
+ module_node(klass)
255
+ else
256
+ class_node(klass)
257
+ end
258
+
259
+ ruby_name = native.name
260
+ method_names = Array.new
261
+ if ruby_name == "initialize" || ruby_name == "initialize_copy"
262
+ method_names << cpp_name(klass).split('::').last
263
+ elsif native_name = OPERATORS[ruby_name]
264
+ method_names << native_name
265
+ elsif native_name = @method_mappings.dig(klass.name, ruby_name)
266
+ method_names << native_name
267
+ elsif ruby_name.match(/\?$/)
268
+ native_name = ruby_name.gsub(/\?$/, "")
269
+ method_names << camelize(native_name, false)
270
+ method_names << camelize(native_name, true)
271
+ method_names << "is#{camelize(native_name, true)}"
272
+ else
273
+ method_names << ruby_name
274
+ method_names << camelize(ruby_name, false)
275
+ method_names << camelize(ruby_name, true)
276
+ end
277
+
278
+ pattern = method_names.map do |method_name|
279
+ "name='#{method_name}'"
280
+ end.join(" or ")
281
+
282
+ xpath = "member[@kind='function'][#{pattern}]"
283
+ member_node = node&.find_first(xpath)
284
+ if member_node
285
+ url(member_node)
286
+ elsif native.name == "initialize"
287
+ class_url(klass)
288
+ #else
289
+ #STDERR << "'#{native.name}' => '#{camelize(native.name, false)}'," << "\n"
290
+ end
291
+ end
292
+ end
293
+ end
294
+ end