Class: YAML::Syck::Resolver

Inherits:
Object
  • Object
show all
Defined in:
rubyext.c

Instance Method Summary collapse

Constructor Details

#initializeObject

YAML::Syck::Resolver.initialize



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver.initialize
 */
static VALUE
syck_resolver_initialize( self )
    VALUE self;
{
    VALUE tags = rb_hash_new();
    rb_ivar_set(self, s_tags, rb_hash_new());
    return self;
}

Instance Method Details

#add_typeObject

YAML::Syck::Resolver#add_type



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#add_type
 */
VALUE
syck_resolver_add_type( self, taguri, cls )
    VALUE self, taguri, cls;
{
    VALUE tags = rb_attr_get(self, s_tags);
    rb_hash_aset( tags, taguri, cls );
    return Qnil;
}

#detect_implicitObject

YAML::Syck::Resolver#detect_implicit



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#detect_implicit 
 */
VALUE
syck_resolver_detect_implicit( self, val )
    VALUE self, val;
{
    char *type_id;
    return rb_str_new2( "" );
}

#node_importObject

YAML::Syck::Resolver#node_import



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#node_import
 */
VALUE
syck_resolver_node_import( self, node )
    VALUE self, node;
{
    SyckNode *n;
    VALUE obj;
    int i = 0;
    Data_Get_Struct(node, SyckNode, n);

    switch (n->kind)
    {
        case syck_str_kind:
            obj = rb_str_new( n->data.str->ptr, n->data.str->len );
        break;

        case syck_seq_kind:
            obj = rb_ary_new2( n->data.list->idx );
            for ( i = 0; i < n->data.list->idx; i++ )
            {
                rb_ary_store( obj, i, syck_seq_read( n, i ) );
            }
        break;

        case syck_map_kind:
            obj = rb_hash_new();
            for ( i = 0; i < n->data.pairs->idx; i++ )
            {
                VALUE k = syck_map_read( n, map_key, i );
                VALUE v = syck_map_read( n, map_value, i );
                int skip_aset = 0;

                /*
                 * Handle merge keys
                 */
                if ( rb_obj_is_kind_of( k, cMergeKey ) )
                {
                    if ( rb_obj_is_kind_of( v, rb_cHash ) )
                    {
                        VALUE dup = rb_funcall( v, s_dup, 0 );
                        rb_funcall( dup, s_update, 1, obj );
                        obj = dup;
                        skip_aset = 1;
                    }
                    else if ( rb_obj_is_kind_of( v, rb_cArray ) )
                    {
                        VALUE end = rb_ary_pop( v );
                        if ( rb_obj_is_kind_of( end, rb_cHash ) )
                        {
                            VALUE dup = rb_funcall( end, s_dup, 0 );
                            v = rb_ary_reverse( v );
                            rb_ary_push( v, obj );
                            rb_iterate( rb_each, v, syck_merge_i, dup );
                            obj = dup;
                            skip_aset = 1;
                        }
                    }
                }
                else if ( rb_obj_is_kind_of( k, cDefaultKey ) )
                {
                    rb_funcall( obj, s_default_set, 1, v );
                    skip_aset = 1;
                }

                if ( ! skip_aset )
                {
                    rb_hash_aset( obj, k, v );
                }
            }
        break;
    }

    if ( n->type_id != NULL )
    {
        obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
    }
    return obj;
}

#tagurizeObject

YAML::Syck::Resolver#tagurize



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#tagurize
 */
VALUE
syck_resolver_tagurize( self, val )
    VALUE self, val;
{
    VALUE tmp = rb_check_string_type(val);

    if ( !NIL_P(tmp) )
    {
        char *taguri = syck_type_id_to_uri( RSTRING(tmp)->ptr );
        val = rb_str_new2( taguri );
        S_FREE( taguri );
    }

    return val;
}

#transferObject

YAML::Syck::Resolver#transfer



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#transfer
 */
VALUE
syck_resolver_transfer( self, type, val )
    VALUE self, type, val;
{
    if (NIL_P(type) || RSTRING(StringValue(type))->len == 0) 
    {
        type = rb_funcall( self, s_detect_implicit, 1, val );
    }

    if ( ! (NIL_P(type) || RSTRING(StringValue(type))->len == 0) )
    {
        VALUE str_xprivate = rb_str_new2( "x-private" );
        VALUE colon = rb_str_new2( ":" );
        VALUE tags = rb_attr_get(self, s_tags);
        VALUE target_class = rb_hash_aref( tags, type );
        VALUE subclass = target_class;
        VALUE obj = Qnil;

        /*
         * Should no tag match exactly, check for subclass format
         */
        if ( NIL_P( target_class ) )
        {
            VALUE subclass_parts = rb_ary_new();
            VALUE parts = rb_str_split( type, ":" );

            while ( RARRAY(parts)->len > 1 )
            {
                VALUE partial;
                rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) );
                partial = rb_ary_join( parts, colon );
                target_class = rb_hash_aref( tags, partial );
                if ( NIL_P( target_class ) )
                {
                    rb_str_append( partial, colon );
                    target_class = rb_hash_aref( tags, partial );
                }

                /*
                 * Possible subclass found, see if it supports subclassing
                 */
                if ( ! NIL_P( target_class ) )
                {
                    subclass = target_class;
                    if ( RARRAY(subclass_parts)->len > 0 && rb_respond_to( target_class, s_tag_subclasses ) &&
                         RTEST( rb_funcall( target_class, s_tag_subclasses, 0 ) ) )
                    {
                        VALUE subclass_v;
                        subclass = rb_ary_join( subclass_parts, colon );
                        subclass = rb_funcall( target_class, s_tag_read_class, 1, subclass );
                        subclass_v = syck_const_find( subclass );

                        if ( subclass_v != Qnil ) 
                        {
                            subclass = subclass_v;
                        }
                        else if ( rb_cObject == target_class && subclass_v == Qnil )
                        {
                            target_class = cYObject;
                            type = subclass;
                            subclass = cYObject;
                        }
                        else /* workaround for SEGV. real fix please */
                        {
                            rb_raise( rb_eTypeError, "invalid subclass" );
                        }
                    }
                    break;
                }
            }
        }

        /* rb_raise(rb_eTypeError, "invalid typing scheme: %s given",
         *         scheme);
         */

        if ( rb_respond_to( target_class, s_call ) )
        {
            obj = rb_funcall( target_class, s_call, 2, type, val );
        }
        else
        {
            if ( rb_respond_to( target_class, s_yaml_new ) )
            {
                obj = rb_funcall( target_class, s_yaml_new, 3, subclass, type, val );
            }
            else if ( !NIL_P( target_class ) )
            {
                if ( subclass == rb_cBignum )
                {
                    obj = rb_str2inum( val, 10 ); /* for yaml dumped by 1.8.3 [ruby-core:6159] */
                }
                else
                {
                    obj = rb_obj_alloc( subclass );
                }

                if ( rb_respond_to( obj, s_yaml_initialize ) )
                {
                    rb_funcall( obj, s_yaml_initialize, 2, type, val );
                }
                else if ( !NIL_P( obj ) && rb_obj_is_instance_of( val, rb_cHash ) )
                {
                    rb_iterate( rb_each, val, syck_set_ivars, obj );
                }
            }
            else 
            {
                VALUE parts = rb_str_split( type, ":" );
                VALUE scheme = rb_ary_shift( parts );
                if ( rb_str_cmp( scheme, str_xprivate ) == 0 )
                {
                    VALUE name = rb_ary_join( parts, colon );
                    obj = rb_funcall( cPrivateType, s_new, 2, name, val );
                }
                else
                {
                    VALUE domain = rb_ary_shift( parts );
                    VALUE name = rb_ary_join( parts, colon );
                    obj = rb_funcall( cDomainType, s_new, 3, domain, name, val );
                }
            }
        }
        val = obj;
    }

    return val;
}

#use_types_atObject

YAML::Syck::Resolver#use_types_at



# File 'rubyext.c'

/*
 * YAML::Syck::Resolver#use_types_at
 */
VALUE
syck_resolver_use_types_at( self, hsh )
    VALUE self, hsh;
{
    rb_ivar_set( self, s_tags, hsh );
    return Qnil;
}