rice 4.8.0 → 4.9.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -1
  3. data/CMakePresets.json +77 -50
  4. data/FindRuby.cmake +1 -1
  5. data/bin/rice-doc.rb +2 -0
  6. data/include/rice/api.hpp +14 -1
  7. data/include/rice/rice.hpp +351 -132
  8. data/include/rice/stl.hpp +319 -256
  9. data/lib/rice/doc/config.rb +57 -57
  10. data/lib/rice/doc/cpp_reference.rb +158 -158
  11. data/lib/rice/doc/doxygen.rb +289 -289
  12. data/lib/rice/doc/mkdocs.rb +332 -332
  13. data/lib/rice/doc/rice.rb +48 -47
  14. data/lib/rice/doc/ruby.rb +26 -26
  15. data/lib/rice/native.rb +15 -15
  16. data/lib/rice/native_registry.rb +12 -17
  17. data/lib/rice/parameter.rb +5 -5
  18. data/lib/rice/rbs.rb +72 -72
  19. data/lib/rice/version.rb +1 -1
  20. data/lib/rubygems/builder.rb +9 -9
  21. data/lib/rubygems_plugin.rb +8 -8
  22. data/rice/Data_Type.ipp +12 -7
  23. data/rice/cpp_api/Class.hpp +5 -0
  24. data/rice/cpp_api/Class.ipp +5 -0
  25. data/rice/cpp_api/Object.hpp +6 -0
  26. data/rice/cpp_api/Object.ipp +5 -0
  27. data/rice/detail/Forwards.hpp +18 -0
  28. data/rice/detail/Forwards.ipp +60 -0
  29. data/rice/detail/Native.ipp +2 -4
  30. data/rice/detail/NativeAttributeGet.ipp +1 -1
  31. data/rice/detail/NativeAttributeSet.hpp +5 -3
  32. data/rice/detail/NativeAttributeSet.ipp +41 -33
  33. data/rice/detail/NativeMethod.ipp +25 -22
  34. data/rice/detail/NativeRegistry.hpp +4 -2
  35. data/rice/detail/NativeRegistry.ipp +42 -9
  36. data/rice/detail/Parameter.ipp +3 -4
  37. data/rice/detail/Type.ipp +4 -0
  38. data/rice/detail/Wrapper.hpp +17 -12
  39. data/rice/detail/Wrapper.ipp +95 -36
  40. data/rice/rice.hpp +3 -0
  41. data/rice/rice_api/NativeRegistry.ipp +14 -1
  42. data/rice/stl/exception.ipp +1 -1
  43. data/rice/stl/filesystem.ipp +1 -1
  44. data/rice/stl/map.ipp +13 -11
  45. data/rice/stl/multimap.ipp +13 -11
  46. data/rice/stl/pair.ipp +14 -8
  47. data/rice/stl/set.ipp +16 -16
  48. data/rice/stl/shared_ptr.hpp +16 -0
  49. data/rice/stl/shared_ptr.ipp +74 -37
  50. data/rice/stl/type_index.ipp +1 -1
  51. data/rice/stl/unique_ptr.hpp +9 -3
  52. data/rice/stl/unique_ptr.ipp +80 -124
  53. data/rice/stl/unordered_map.ipp +14 -12
  54. data/rice/stl/vector.ipp +67 -31
  55. data/test/test_Attribute.cpp +72 -0
  56. data/test/test_Callback.cpp +3 -0
  57. data/test/test_Inheritance.cpp +14 -14
  58. data/test/test_Keep_Alive_No_Wrapper.cpp +6 -2
  59. data/test/test_Stl_Map.cpp +46 -0
  60. data/test/test_Stl_Multimap.cpp +46 -0
  61. data/test/test_Stl_Set.cpp +34 -0
  62. data/test/test_Stl_SharedPtr.cpp +160 -45
  63. data/test/test_Stl_UniquePtr.cpp +48 -3
  64. data/test/test_Stl_Unordered_Map.cpp +46 -0
  65. data/test/test_Stl_Variant.cpp +10 -14
  66. data/test/test_Stl_Vector.cpp +140 -13
  67. data/test/test_Tracking.cpp +3 -0
  68. metadata +3 -1
@@ -2,293 +2,293 @@ require 'open-uri'
2
2
  require 'libxml-ruby'
3
3
 
4
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
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
294
  end