summaryrefslogtreecommitdiff
path: root/ext/syck/rubyext.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/syck/rubyext.c')
-rw-r--r--ext/syck/rubyext.c244
1 files changed, 236 insertions, 8 deletions
diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c
index 66aa7e4fcd..96627f1199 100644
--- a/ext/syck/rubyext.c
+++ b/ext/syck/rubyext.c
@@ -12,10 +12,13 @@
#include <sys/types.h>
#include <time.h>
+#define RUBY_DOMAIN "ruby.yaml.org,2002"
+
static ID s_utc, s_read, s_binmode;
+static VALUE str_taguri, str_xprivate;
static VALUE sym_model, sym_generic;
static VALUE sym_scalar, sym_seq, sym_map;
-VALUE cNode;
+VALUE cParser, cLoader, cNode, oDefaultLoader;
//
// my private collection of numerical oddities.
@@ -84,6 +87,22 @@ syck_parser_assign_io(parser, port)
}
//
+// Get value in hash by key, forcing an empty hash if nil.
+//
+VALUE
+syck_get_hash_aref(hsh, key)
+ VALUE hsh, key;
+{
+ VALUE val = rb_hash_aref( hsh, key );
+ if ( NIL_P( val ) )
+ {
+ val = rb_hash_new();
+ rb_hash_aset(hsh, key, val);
+ }
+ return val;
+}
+
+//
// creating timestamps
//
SYMID
@@ -469,9 +488,199 @@ syck_parser_load_documents(argc, argv, self)
}
//
-// YAML::Syck::Node.initialize
+// YAML::Syck::Loader.initialize
+//
+static VALUE
+syck_loader_initialize( self )
+ VALUE self;
+{
+ VALUE families;
+
+ rb_iv_set(self, "@families", rb_hash_new() );
+ rb_iv_set(self, "@private_types", rb_hash_new() );
+ families = rb_iv_get(self, "@families");
+
+ rb_hash_aset(families, rb_str_new2( YAML_DOMAIN ), rb_hash_new());
+ rb_hash_aset(families, rb_str_new2( RUBY_DOMAIN ), rb_hash_new());
+
+ return self;
+}
+
+//
+// Add type family, used by add_*_type methods.
+//
+VALUE
+syck_loader_add_type_family( self, domain, type_re, proc )
+ VALUE self, domain, type_re, proc;
+{
+ VALUE families, domain_types;
+
+ families = rb_iv_get(self, "@families");
+ domain_types = syck_get_hash_aref(families, domain);
+ rb_hash_aset( domain_types, type_re, proc );
+}
+
+//
+// YAML::Syck::Loader.add_domain_type
+//
+VALUE
+syck_loader_add_domain_type( argc, argv, self )
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE domain, type_re, proc, families, ruby_yaml_org, domain_types;
+
+ rb_scan_args(argc, argv, "2&", &domain, &type_re, &proc);
+ syck_loader_add_type_family( self, domain, type_re, proc );
+}
+
+
+//
+// YAML::Syck::Loader.add_builtin_type
+//
+VALUE
+syck_loader_add_builtin_type( argc, argv, self )
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE type_re, proc, families, ruby_yaml_org, domain_types;
+
+ rb_scan_args(argc, argv, "1&", &type_re, &proc);
+ syck_loader_add_type_family( self, rb_str_new2( YAML_DOMAIN ), type_re, proc );
+}
+
+//
+// YAML::Syck::Loader.add_ruby_type
+//
+VALUE
+syck_loader_add_ruby_type( argc, argv, self )
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE type_re, proc, families, ruby_yaml_org, domain_types;
+
+ rb_scan_args(argc, argv, "1&", &type_re, &proc);
+ syck_loader_add_type_family( self, rb_str_new2( RUBY_DOMAIN ), type_re, proc );
+}
+
+//
+// YAML::Syck::Loader.add_private_type
+//
+VALUE
+syck_loader_add_private_type( argc, argv, self )
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE type_re, proc, priv_types;
+
+ rb_scan_args(argc, argv, "1&", &type_re, &proc);
+
+ priv_types = rb_iv_get(self, "@private_types");
+ rb_hash_aset( priv_types, type_re, proc );
+}
+
+//
+// iterator to search a type hash for a match.
//
static VALUE
+transfer_find_i(entry, col)
+ VALUE entry, col;
+{
+ VALUE key = rb_ary_entry( entry, 0 );
+ VALUE tid = rb_ary_entry( col, 0 );
+ VALUE match = rb_funcall(tid, rb_intern("=~"), 1, key);
+ if ( ! NIL_P( match ) )
+ {
+ rb_ary_push( col, rb_ary_entry( entry, 1 ) );
+ rb_iter_break();
+ }
+ return Qnil;
+}
+
+//
+// YAML::Syck::Loader#transfer
+//
+VALUE
+syck_loader_transfer( self, type, val )
+ VALUE self, type, val;
+{
+ char *taguri = NULL;
+
+ // rb_funcall(rb_mKernel, rb_intern("p"), 2, rb_str_new2( "-- TYPE --" ), type);
+ if (NIL_P(type) || !RSTRING(type)->ptr || RSTRING(type)->len == 0)
+ {
+ //
+ // Empty transfer, detect type
+ //
+ if ( TYPE(val) == T_STRING )
+ {
+ taguri = syck_match_implicit( RSTRING(val)->ptr, RSTRING(val)->len );
+ taguri = syck_taguri( YAML_DOMAIN, taguri, strlen( taguri ) );
+ }
+ }
+ else
+ {
+ taguri = syck_type_id_to_uri( RSTRING(type)->ptr );
+ }
+
+ if ( taguri != NULL )
+ {
+ VALUE scheme, name, type_hash, type_proc;
+ VALUE type_uri = rb_str_new2( taguri );
+ VALUE parts = rb_str_split( type_uri, ":" );
+ // rb_funcall(rb_mKernel, rb_intern("p"), 1, parts);
+
+ scheme = rb_ary_shift( parts );
+
+ if ( rb_str_cmp( scheme, str_xprivate ) == 0 )
+ {
+ name = rb_ary_join( parts, rb_str_new2( ":" ) );
+ type_hash = rb_iv_get(self, "@private_types");
+ }
+ else if ( rb_str_cmp( scheme, str_taguri ) == 0 )
+ {
+ VALUE domain = rb_ary_shift( parts );
+ name = rb_ary_join( parts, rb_str_new2( ":" ) );
+ type_hash = rb_iv_get(self, "@families");
+ type_hash = rb_hash_aref(type_hash, domain);
+ }
+ else
+ {
+ rb_raise(rb_eTypeError, "invalid typing scheme: %s given",
+ scheme);
+ }
+
+ if ( rb_obj_is_instance_of( type_hash, rb_cHash ) )
+ {
+ type_proc = rb_hash_aref( type_hash, name );
+ if ( NIL_P( type_proc ) )
+ {
+ VALUE col = rb_ary_new();
+ rb_ary_push( col, name );
+ rb_iterate(rb_each, type_hash, transfer_find_i, col );
+ name = rb_ary_shift( col );
+ type_proc = rb_ary_shift( col );
+ }
+ // rb_funcall(rb_mKernel, rb_intern("p"), 2, name, type_proc);
+ }
+
+ if ( rb_obj_is_instance_of( type_proc, rb_cProc ) )
+ {
+ val = rb_funcall(type_proc, rb_intern("call"), 2, type_uri, val);
+ }
+ }
+
+ return val;
+}
+
+//
+// YAML::Syck::Node.initialize
+//
+VALUE
syck_node_initialize( self, type_id, val )
VALUE self, type_id, val;
{
@@ -479,7 +688,7 @@ syck_node_initialize( self, type_id, val )
rb_iv_set( self, "@value", val );
}
-static VALUE
+VALUE
syck_node_thash( entry, t )
VALUE entry, t;
{
@@ -489,7 +698,7 @@ syck_node_thash( entry, t )
rb_hash_aset( t, key, val );
}
-static VALUE
+VALUE
syck_node_ahash( entry, t )
VALUE entry, t;
{
@@ -500,11 +709,12 @@ syck_node_ahash( entry, t )
//
// YAML::Syck::Node.transform
//
-static VALUE
+VALUE
syck_node_transform( self )
VALUE self;
{
VALUE t = Qnil;
+ VALUE type_id = rb_iv_get( self, "@type_id" );
VALUE val = rb_iv_get( self, "@value" );
if ( rb_obj_is_instance_of( val, rb_cHash ) )
{
@@ -520,7 +730,7 @@ syck_node_transform( self )
{
t = val;
}
- return t;
+ return rb_funcall( oDefaultLoader, rb_intern( "transfer" ), 2, type_id, t );
}
//
@@ -531,7 +741,6 @@ Init_syck()
{
VALUE rb_yaml = rb_define_module( "YAML" );
VALUE rb_syck = rb_define_module_under( rb_yaml, "Syck" );
- VALUE cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
rb_define_const( rb_syck, "VERSION", rb_str_new2( SYCK_VERSION ) );
//
@@ -540,6 +749,8 @@ Init_syck()
s_utc = rb_intern("utc");
s_read = rb_intern("read");
s_binmode = rb_intern("binmode");
+ str_taguri = rb_str_new2("taguri");
+ str_xprivate = rb_str_new2("x-private");
sym_model = ID2SYM(rb_intern("Model"));
sym_generic = ID2SYM(rb_intern("Generic"));
sym_map = ID2SYM(rb_intern("map"));
@@ -547,10 +758,27 @@ Init_syck()
sym_seq = ID2SYM(rb_intern("seq"));
//
+ // Define YAML::Syck::Loader class
+ //
+ cLoader = rb_define_class_under( rb_syck, "Loader", rb_cObject );
+ rb_define_attr( cLoader, "families", 1, 1 );
+ rb_define_attr( cLoader, "private_types", 1, 1 );
+ rb_define_method( cLoader, "initialize", syck_loader_initialize, 0 );
+ rb_define_method( cLoader, "add_domain_type", syck_loader_add_domain_type, -1 );
+ rb_define_method( cLoader, "add_builtin_type", syck_loader_add_builtin_type, -1 );
+ rb_define_method( cLoader, "add_ruby_type", syck_loader_add_ruby_type, -1 );
+ rb_define_method( cLoader, "add_private_type", syck_loader_add_private_type, -1 );
+ rb_define_method( cLoader, "transfer", syck_loader_transfer, 2 );
+
+ oDefaultLoader = rb_funcall( cLoader, rb_intern( "new" ), 0 );
+ rb_define_const( rb_syck, "DefaultLoader", oDefaultLoader );
+
+ //
// Define YAML::Syck::Parser class
//
+ cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
rb_define_attr( cParser, "options", 1, 1 );
- rb_define_singleton_method(cParser, "new", syck_parser_new, -1);
+ rb_define_singleton_method( cParser, "new", syck_parser_new, -1 );
rb_define_method(cParser, "initialize", syck_parser_initialize, 1);
rb_define_method(cParser, "load", syck_parser_load, -1);
rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1);