$search
00001 #include "typelib.hh" 00002 00003 #include <typelib/pluginmanager.hh> 00004 #include <typelib/importer.hh> 00005 #include <typelib/exporter.hh> 00006 #include <typelib/registryiterator.hh> 00007 #include <lang/csupport/standard_types.hh> 00008 #include <utilmm/configfile/configset.hh> 00009 #include <set> 00010 00011 using namespace Typelib; 00012 using utilmm::config_set; 00013 using namespace std; 00014 using namespace typelib_ruby; 00015 using cxx2rb::RbRegistry; 00016 00017 00018 namespace typelib_ruby { 00019 VALUE cRegistry = Qnil; 00020 VALUE eNotFound = Qnil; 00021 } 00022 00023 /*********************************************************************************** 00024 * 00025 * Wrapping of the Registry class 00026 * 00027 */ 00028 00029 00030 static 00031 void registry_free(void* ptr) 00032 { 00033 using cxx2rb::WrapperMap; 00034 RbRegistry* rbregistry = reinterpret_cast<RbRegistry*>(ptr); 00035 WrapperMap& wrappers = rbregistry->wrappers; 00036 for (WrapperMap::iterator it = wrappers.begin(); it != wrappers.end(); ++it) 00037 { 00038 if (it->second.first) 00039 delete it->first; 00040 } 00041 00042 delete rbregistry; 00043 } 00044 00045 static 00046 void registry_mark(void* ptr) 00047 { 00048 using cxx2rb::WrapperMap; 00049 WrapperMap const& wrappers = reinterpret_cast<RbRegistry const*>(ptr)->wrappers; 00050 for (WrapperMap::const_iterator it = wrappers.begin(); it != wrappers.end(); ++it) 00051 rb_gc_mark(it->second.second); 00052 } 00053 00054 static 00055 VALUE registry_wrap(VALUE klass, Registry* registry) 00056 { 00057 return Data_Wrap_Struct(klass, registry_mark, registry_free, new RbRegistry(registry)); 00058 } 00059 00060 static 00061 VALUE registry_alloc(VALUE klass) 00062 { 00063 Registry* registry = new Registry; 00064 return registry_wrap(klass, registry); 00065 } 00066 00067 00068 static 00069 VALUE registry_includes_p(VALUE self, VALUE name) 00070 { 00071 Registry& registry = rb2cxx::object<Registry>(self); 00072 Type const* type = registry.get( StringValuePtr(name) ); 00073 return type ? Qtrue : Qfalse; 00074 } 00075 00076 /* call-seq: 00077 * registry.remove(type) => removed_types 00078 * 00079 * Removes +type+ from the registry, along with all the types that depends on 00080 * +type+. 00081 * 00082 * Returns the set of removed types 00083 */ 00084 static 00085 VALUE registry_remove(VALUE self, VALUE rbtype) 00086 { 00087 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self); 00088 Registry& registry = *(rbregistry.registry); 00089 Type const& type(rb2cxx::object<Type>(rbtype)); 00090 std::set<Type*> deleted = registry.remove(type); 00091 00092 VALUE result = rb_ary_new(); 00093 std::set<Type*>::iterator it, end; 00094 for (it = deleted.begin(); it != deleted.end(); ++it) 00095 { 00096 rb_ary_push(result, cxx2rb::type_wrap(**it, self)); 00097 cxx2rb::WrapperMap::iterator wrapper_it = rbregistry.wrappers.find(*it); 00098 wrapper_it->second.first = true; 00099 } 00100 00101 return result; 00102 } 00103 00104 /* call-seq: 00105 * registry.source_id_of(type) => source_or_nil 00106 * 00107 * Returns the source ID for the given type, if one is set 00108 */ 00109 static 00110 VALUE registry_source_id_of(VALUE self, VALUE rbtype) 00111 { 00112 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self); 00113 Registry& registry = *(rbregistry.registry); 00114 Type const& type(rb2cxx::object<Type>(rbtype)); 00115 00116 RegistryIterator it = registry.find(type.getName()); 00117 if (it == registry.end()) 00118 rb_raise(rb_eArgError, "this registry has no type called %s", type.getName().c_str()); 00119 00120 std::string source = it.getSource(); 00121 if (source.empty()) return Qnil; 00122 return rb_str_new(it.getSource().c_str(), it.getSource().length()); 00123 } 00124 00125 /* call-seq: 00126 * registry.reverse_depends(type) => types 00127 * 00128 * Returns the array of types that depend on +type+, including +type+ itself 00129 */ 00130 static 00131 VALUE registry_reverse_depends(VALUE self, VALUE rbtype) 00132 { 00133 Registry const& registry = rb2cxx::object<Registry>(self); 00134 Type const& type(rb2cxx::object<Type>(rbtype)); 00135 std::set<Type const*> rdeps = registry.reverseDepends(type); 00136 00137 VALUE result = rb_ary_new(); 00138 std::set<Type const*>::iterator it, end; 00139 for (it = rdeps.begin(); it != rdeps.end(); ++it) 00140 rb_ary_push(result, cxx2rb::type_wrap(**it, self)); 00141 00142 return result; 00143 } 00144 00145 static 00146 VALUE registry_do_get(VALUE self, VALUE name) 00147 { 00148 Registry& registry = rb2cxx::object<Registry>(self); 00149 Type const* type = registry.get( StringValuePtr(name) ); 00150 00151 if (! type) 00152 rb_raise(eNotFound, "there is no type in this registry with the name '%s'", StringValuePtr(name)); 00153 return cxx2rb::type_wrap(*type, self); 00154 } 00155 00156 static 00157 VALUE registry_do_build(VALUE self, VALUE name) 00158 { 00159 Registry& registry = rb2cxx::object<Registry>(self); 00160 try { 00161 Type const* type = registry.build( StringValuePtr(name) ); 00162 if (! type) 00163 rb_raise(eNotFound, "cannot find %s in registry", StringValuePtr(name)); 00164 return cxx2rb::type_wrap(*type, self); 00165 } 00166 catch(std::exception const& e) { rb_raise(rb_eRuntimeError, "%s", e.what()); } 00167 } 00168 00169 00170 /* call-seq: 00171 * alias(new_name, name) => self 00172 * 00173 * Make +new_name+ refer to the type named +name+ 00174 */ 00175 static 00176 VALUE registry_alias(VALUE self, VALUE name, VALUE aliased) 00177 { 00178 Registry& registry = rb2cxx::object<Registry>(self); 00179 00180 try { 00181 registry.alias(StringValuePtr(aliased), StringValuePtr(name)); 00182 return self; 00183 } catch(BadName) { 00184 rb_raise(rb_eArgError, "invalid type name %s", StringValuePtr(name)); 00185 } catch(Undefined) { 00186 rb_raise(eNotFound, "there is not type in this registry with the name '%s'", StringValuePtr(aliased)); 00187 } 00188 } 00189 00190 static 00191 void setup_configset_from_option_array(config_set& config, VALUE options) 00192 { 00193 int options_length = RARRAY_LEN(options); 00194 for (int i = 0; i < options_length; ++i) 00195 { 00196 VALUE entry = RARRAY_PTR(options)[i]; 00197 VALUE k = RARRAY_PTR(entry)[0]; 00198 VALUE v = RARRAY_PTR(entry)[1]; 00199 00200 if ( rb_obj_is_kind_of(v, rb_cArray) ) 00201 { 00202 VALUE first_el = rb_ary_entry(v, 0); 00203 if (rb_obj_is_kind_of(first_el, rb_cArray)) 00204 { 00205 // We are building recursive config sets 00206 for (int j = 0; j < RARRAY_LEN(v); ++j) 00207 { 00208 config_set* child = new config_set; 00209 setup_configset_from_option_array(*child, rb_ary_entry(v, j)); 00210 config.insert(StringValuePtr(k), child); 00211 } 00212 } 00213 else 00214 { 00215 for (int j = 0; j < RARRAY_LEN(v); ++j) 00216 { 00217 VALUE value = rb_ary_entry(v, j); 00218 config.insert(StringValuePtr(k), StringValuePtr(value)); 00219 } 00220 } 00221 } 00222 else if (TYPE(v) == T_TRUE || TYPE(v) == T_FALSE) 00223 config.set(StringValuePtr(k), RTEST(v) ? "true" : "false"); 00224 else 00225 config.set(StringValuePtr(k), StringValuePtr(v)); 00226 } 00227 } 00228 00229 /* Private method to import a given file in the registry 00230 * We expect Registry#import to format the arguments before calling 00231 * do_import 00232 */ 00233 static 00234 VALUE registry_import(VALUE self, VALUE file, VALUE kind, VALUE merge, VALUE options) 00235 { 00236 Registry& registry = rb2cxx::object<Registry>(self); 00237 00238 config_set config; 00239 setup_configset_from_option_array(config, options); 00240 00241 std::string error_string; 00242 try { 00243 if (RTEST(merge)) 00244 { 00245 Registry temp; 00246 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, temp); 00247 registry.merge(temp); 00248 } 00249 else 00250 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, registry); 00251 return Qnil; 00252 } 00253 catch(boost::bad_lexical_cast e) { error_string = e.what(); } 00254 catch(std::exception const& e) { error_string = e.what(); } 00255 00256 rb_raise(rb_eRuntimeError, "%s", error_string.c_str()); 00257 } 00258 00259 /* Private method called by Registry#export. This latter method is supposed 00260 * to format the +options+ argument from a Ruby hash into an array suitable 00261 * for setup_configset_from_option_array 00262 */ 00263 static 00264 VALUE registry_export(VALUE self, VALUE kind, VALUE options) 00265 { 00266 Registry& registry = rb2cxx::object<Registry>(self); 00267 00268 config_set config; 00269 setup_configset_from_option_array(config, options); 00270 00271 string error_message; 00272 try { 00273 std::string exported = PluginManager::save(StringValuePtr(kind), config, registry); 00274 return rb_str_new(exported.c_str(), exported.length()); 00275 } 00276 catch (std::exception const& e) { error_message = e.what(); } 00277 rb_raise(rb_eRuntimeError, "%s", error_message.c_str()); 00278 } 00279 00280 00281 /* 00282 * call-seq: 00283 * merge(other_registry) => self 00284 * 00285 * Move all types found in +other_registry+ into +self+ 00286 */ 00287 static 00288 VALUE registry_merge(VALUE self, VALUE rb_merged) 00289 { 00290 std::string error_string; 00291 00292 Registry& registry = rb2cxx::object<Registry>(self); 00293 Registry& merged = rb2cxx::object<Registry>(rb_merged); 00294 try { 00295 registry.merge(merged); 00296 return self; 00297 } 00298 catch(std::exception const& e) { error_string = e.what(); } 00299 rb_raise(rb_eRuntimeError, "%s", error_string.c_str()); 00300 } 00301 00302 00303 /* 00304 * call-seq: 00305 * resize(new_sizes) => nil 00306 * 00307 * Changes the size of some types, while modifying the types that depend on 00308 * them to keep the registry consistent. 00309 */ 00310 static 00311 VALUE registry_resize(VALUE self, VALUE new_sizes) 00312 { 00313 Registry& registry = rb2cxx::object<Registry>(self); 00314 00315 std::map<std::string, size_t> sizes; 00316 size_t map_size = RARRAY_LEN(new_sizes); 00317 VALUE* map_values = RARRAY_PTR(new_sizes); 00318 for (size_t i = 0; i < map_size; ++i) 00319 { 00320 VALUE* pair = RARRAY_PTR(map_values[i]); 00321 sizes.insert(std::make_pair( 00322 StringValuePtr(pair[0]), 00323 NUM2INT(pair[1]))); 00324 } 00325 try { 00326 registry.resize(sizes); 00327 return Qnil; 00328 } 00329 catch(std::exception const& e) { 00330 rb_raise(rb_eRuntimeError, "%s", e.what()); 00331 } 00332 } 00333 00334 /* call-seq: 00335 * minimal(auto_types) => registry 00336 * 00337 * Returns the minimal registry needed to define all types that are in +self+ 00338 * but not in +auto_types+ 00339 */ 00340 static 00341 VALUE registry_minimal(VALUE self, VALUE rb_auto, VALUE with_aliases) 00342 { 00343 std::string error_string; 00344 Registry& registry = rb2cxx::object<Registry>(self); 00345 00346 if (rb_obj_is_kind_of(rb_auto, rb_cString)) 00347 { 00348 try { 00349 Registry* result = registry.minimal(StringValuePtr(rb_auto), RTEST(with_aliases)); 00350 return registry_wrap(cRegistry, result); 00351 } 00352 catch(std::exception const& e) 00353 { rb_raise(rb_eRuntimeError, "%s", e.what()); } 00354 } 00355 else 00356 { 00357 Registry& auto_types = rb2cxx::object<Registry>(rb_auto); 00358 try { 00359 Registry* result = registry.minimal(auto_types); 00360 return registry_wrap(cRegistry, result); 00361 } 00362 catch(std::exception const& e) 00363 { rb_raise(rb_eRuntimeError, "%s", e.what()); } 00364 } 00365 } 00366 00367 00368 static void yield_types(VALUE self, bool with_aliases, RegistryIterator it, RegistryIterator end) 00369 { 00370 if (with_aliases) 00371 { 00372 for (; it != end; ++it) 00373 { 00374 std::string const& type_name = it.getName(); 00375 VALUE rb_type_name = rb_str_new(type_name.c_str(), type_name.length()); 00376 rb_yield_values(2, rb_type_name, cxx2rb::type_wrap(*it, self)); 00377 } 00378 } 00379 else 00380 { 00381 for (; it != end; ++it) 00382 { 00383 if (!it.isAlias()) 00384 rb_yield(cxx2rb::type_wrap(*it, self)); 00385 } 00386 } 00387 } 00388 00389 /* 00390 * each_type(filter, false) { |type| ... } 00391 * each_type(filter, true) { |name, type| ... } 00392 * 00393 * Iterates on the types found in this registry. If include_alias is true, also 00394 * yield the aliased types. If +filter+ is not nil, only the types whose names 00395 * start with +filter+ will be yield 00396 */ 00397 static 00398 VALUE registry_each_type(VALUE self, VALUE filter_, VALUE with_aliases_) 00399 { 00400 Registry& registry = rb2cxx::object<Registry>(self); 00401 bool with_aliases = RTEST(with_aliases_); 00402 std::string filter; 00403 if (RTEST(filter_)) 00404 filter = StringValuePtr(filter_); 00405 00406 try 00407 { 00408 if (filter.empty()) 00409 yield_types(self, with_aliases, registry.begin(), registry.end()); 00410 else 00411 yield_types(self, with_aliases, registry.begin(filter), registry.end(filter)); 00412 00413 return self; 00414 } 00415 catch(std::exception const& e) 00416 { 00417 rb_raise(rb_eRuntimeError, "%s", e.what()); 00418 } 00419 } 00420 00421 /* call-seq: 00422 * registry.merge_xml(xml) => registry 00423 * 00424 * Build a registry from a string, which is formatted as Typelib's own XML 00425 * format. See also #export, #import and #to_xml 00426 */ 00427 static 00428 VALUE registry_merge_xml(VALUE rb_registry, VALUE xml) 00429 { 00430 Registry& registry = rb2cxx::object<Registry>(rb_registry); 00431 00432 std::istringstream istream(StringValuePtr(xml)); 00433 config_set config; 00434 try { PluginManager::load("tlb", istream, config, registry); } 00435 catch(boost::bad_lexical_cast e) 00436 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); } 00437 catch(std::exception const& e) 00438 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); } 00439 00440 return rb_registry; 00441 } 00442 00443 /* 00444 * call-seq: 00445 * Registry.aliases_of(type) => list_of_names 00446 * 00447 * Lists all the known aliases for the given type 00448 */ 00449 static VALUE registry_aliases_of(VALUE self, VALUE type_) 00450 { 00451 Registry& registry = rb2cxx::object<Registry>(self); 00452 Type const& type(rb2cxx::object<Type>(type_)); 00453 std::set<std::string> aliases = 00454 registry.getAliasesOf(type); 00455 00456 VALUE result = rb_ary_new(); 00457 for (set<string>::const_iterator it = aliases.begin(); it != aliases.end(); ++it) 00458 rb_ary_push(result, rb_str_new(it->c_str(), it->length())); 00459 return result; 00460 } 00461 00462 /* 00463 * call-seq: 00464 * registry.clear_aliases 00465 * 00466 * Removes all aliases defined on this registry 00467 */ 00468 static VALUE registry_clear_aliases(VALUE self) 00469 { 00470 Registry& registry = rb2cxx::object<Registry>(self); 00471 registry.clearAliases(); 00472 return Qnil; 00473 } 00474 00475 /* 00476 * call-seq: 00477 * registry.size => size 00478 * 00479 * Returns the number of types registered in +self+ 00480 */ 00481 static VALUE registry_size(VALUE self) 00482 { 00483 Registry& registry = rb2cxx::object<Registry>(self); 00484 return INT2NUM(registry.size()); 00485 } 00486 00487 /* 00488 * call-seq: 00489 * Registry.available_containers => container_names 00490 * 00491 * Returns the set of known container names 00492 */ 00493 static VALUE registry_available_container(VALUE registry_module) 00494 { 00495 Typelib::Container::AvailableContainers containers = 00496 Typelib::Container::availableContainers(); 00497 00498 VALUE result = rb_ary_new(); 00499 Typelib::Container::AvailableContainers::const_iterator 00500 it = containers.begin(), 00501 end = containers.end(); 00502 00503 while (it != end) 00504 { 00505 std::string name = it->first; 00506 rb_ary_push(result, rb_str_new(name.c_str(), name.length())); 00507 ++it; 00508 } 00509 return result; 00510 } 00511 00512 /* 00513 * call-seq: 00514 * registry.define_container(kind, element_type) => new_type 00515 * 00516 * Defines a new container instance with the given container kind and element 00517 * type. +element_type+ is a type object, i.e. a subclass of Type, that has to 00518 * be part of +registry+ (obtained through registry.get or registry.build). If 00519 * +element_type+ comes from another registry object, the method raises 00520 * ArgumentError. 00521 * 00522 * Moreover, the method raises NotFound if +kind+ is not a known container name. 00523 */ 00524 static VALUE registry_define_container(VALUE registry, VALUE kind, VALUE element) 00525 { 00526 Registry& reg = rb2cxx::object<Registry>(registry); 00527 Type const& element_type(rb2cxx::object<Type>(element)); 00528 // Check that +reg+ contains +element_type+ 00529 if (!reg.isIncluded(element_type)) 00530 rb_raise(rb_eArgError, "the given type object comes from a different type registry"); 00531 00532 try { 00533 Container const& new_type = Container::createContainer(reg, StringValuePtr(kind), element_type); 00534 return cxx2rb::type_wrap(new_type, registry); 00535 } catch(Typelib::UnknownContainer) { 00536 rb_raise(eNotFound, "%s is not a known container type", StringValuePtr(kind)); 00537 } 00538 } 00539 00540 /* 00541 * call-seq: 00542 * Registry.add_standard_cxx_types(registry) => registry 00543 * 00544 * Adds to +registry+ some standard C/C++ types that Typelib can represent 00545 */ 00546 static VALUE registry_add_standard_cxx_types(VALUE klass, VALUE registry) 00547 { 00548 Registry& reg = rb2cxx::object<Registry>(registry); 00549 Typelib::CXX::addStandardTypes(reg); 00550 return registry; 00551 } 00552 00553 /* 00554 * call-seq: 00555 * registry.create_compound(name, field_defs) 00556 * 00557 * Creates a new compound type in which the fields are provided by +field_defs+ 00558 */ 00559 static VALUE registry_create_compound(VALUE registry, VALUE name, VALUE field_defs) 00560 { 00561 Registry& reg = rb2cxx::object<Registry>(registry); 00562 00563 std::auto_ptr<Typelib::Compound> new_t(new Typelib::Compound(StringValuePtr(name))); 00564 00565 int size = RARRAY_LEN(field_defs); 00566 for (int i = 0; i < size; ++i) 00567 { 00568 VALUE field = rb_ary_entry(field_defs, i); 00569 00570 VALUE rb_name = rb_ary_entry(field, 0); 00571 std::string field_name(StringValuePtr(rb_name)); 00572 Typelib::Type& field_type(rb2cxx::object<Type>(rb_ary_entry(field, 1))); 00573 int offset(NUM2INT(rb_ary_entry(field, 2))); 00574 new_t->addField(field_name, field_type, offset); 00575 } 00576 00577 Typelib::Compound* type = new_t.release(); 00578 try { reg.add(type, true, ""); } 00579 catch(std::runtime_error e) 00580 { rb_raise(rb_eArgError, "%s", e.what()); } 00581 return cxx2rb::type_wrap(*type, registry); 00582 } 00583 00584 /* 00585 * call-seq: 00586 * registry.create_enum(name, symbol_defs) 00587 * 00588 * Creates a new compound type in which the fields are provided by +field_defs+ 00589 */ 00590 static VALUE registry_create_enum(VALUE registry, VALUE name, VALUE symbol_defs) 00591 { 00592 Registry& reg = rb2cxx::object<Registry>(registry); 00593 00594 std::auto_ptr<Typelib::Enum> new_t(new Typelib::Enum(StringValuePtr(name))); 00595 00596 int size = RARRAY_LEN(symbol_defs); 00597 for (int i = 0; i < size; ++i) 00598 { 00599 VALUE sym = rb_ary_entry(symbol_defs, i); 00600 00601 VALUE rb_name = rb_ary_entry(sym, 0); 00602 std::string sym_name(StringValuePtr(rb_name)); 00603 int sym_value(NUM2INT(rb_ary_entry(sym, 1))); 00604 new_t->add(sym_name, sym_value); 00605 } 00606 00607 Typelib::Enum* type = new_t.release(); 00608 try { reg.add(type, true, ""); } 00609 catch(std::runtime_error e) 00610 { rb_raise(rb_eArgError, "%s", e.what()); } 00611 return cxx2rb::type_wrap(*type, registry); 00612 } 00613 00614 void typelib_ruby::Typelib_init_registry() 00615 { 00616 VALUE mTypelib = rb_define_module("Typelib"); 00617 cRegistry = rb_define_class_under(mTypelib, "Registry", rb_cObject); 00618 eNotFound = rb_define_class_under(mTypelib, "NotFound", rb_eRuntimeError); 00619 rb_define_alloc_func(cRegistry, registry_alloc); 00620 rb_define_method(cRegistry, "size", RUBY_METHOD_FUNC(registry_size), 0); 00621 rb_define_method(cRegistry, "get", RUBY_METHOD_FUNC(registry_do_get), 1); 00622 rb_define_method(cRegistry, "build", RUBY_METHOD_FUNC(registry_do_build), 1); 00623 rb_define_method(cRegistry, "each_type", RUBY_METHOD_FUNC(registry_each_type), 2); 00624 // do_import is called by the Ruby-defined import, which formats the 00625 // option hash (if there is one), and can detect the import type by extension 00626 rb_define_method(cRegistry, "do_import", RUBY_METHOD_FUNC(registry_import), 4); 00627 rb_define_method(cRegistry, "do_export", RUBY_METHOD_FUNC(registry_export), 2); 00628 rb_define_method(cRegistry, "merge_xml", RUBY_METHOD_FUNC(registry_merge_xml), 1); 00629 rb_define_method(cRegistry, "alias", RUBY_METHOD_FUNC(registry_alias), 2); 00630 rb_define_method(cRegistry, "clear_aliases", RUBY_METHOD_FUNC(registry_clear_aliases), 0); 00631 rb_define_method(cRegistry, "aliases_of", RUBY_METHOD_FUNC(registry_aliases_of), 1); 00632 rb_define_method(cRegistry, "merge", RUBY_METHOD_FUNC(registry_merge), 1); 00633 rb_define_method(cRegistry, "do_minimal", RUBY_METHOD_FUNC(registry_minimal), 2); 00634 rb_define_method(cRegistry, "includes?", RUBY_METHOD_FUNC(registry_includes_p), 1); 00635 rb_define_method(cRegistry, "do_resize", RUBY_METHOD_FUNC(registry_resize), 1); 00636 rb_define_method(cRegistry, "reverse_depends", RUBY_METHOD_FUNC(registry_reverse_depends), 1); 00637 rb_define_method(cRegistry, "remove", RUBY_METHOD_FUNC(registry_remove), 1); 00638 rb_define_method(cRegistry, "source_id_of", RUBY_METHOD_FUNC(registry_source_id_of), 1); 00639 rb_define_method(cRegistry, "do_create_compound", RUBY_METHOD_FUNC(registry_create_compound), 2); 00640 rb_define_method(cRegistry, "do_create_enum", RUBY_METHOD_FUNC(registry_create_enum), 2); 00641 00642 rb_define_singleton_method(cRegistry, "add_standard_cxx_types", RUBY_METHOD_FUNC(registry_add_standard_cxx_types), 1); 00643 00644 rb_define_singleton_method(cRegistry, "available_containers", RUBY_METHOD_FUNC(registry_available_container), 0); 00645 rb_define_method(cRegistry, "define_container", RUBY_METHOD_FUNC(registry_define_container), 2); 00646 } 00647