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.c2367
1 files changed, 0 insertions, 2367 deletions
diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c
deleted file mode 100644
index e2de4bbfd0..0000000000
--- a/ext/syck/rubyext.c
+++ /dev/null
@@ -1,2367 +0,0 @@
-/* -*- indent-tabs-mode: nil -*- */
-/*
- * rubyext.c
- *
- * $Author: ocean $
- * $Date: 2006/01/30 15:11:57 $
- *
- * Copyright (C) 2003-2005 why the lucky stiff
- */
-
-#include "ruby.h"
-#include "syck.h"
-#include <sys/types.h>
-#include <time.h>
-
-typedef struct RVALUE {
- union {
-#if 0
- struct {
- unsigned long flags; /* always 0 for freed obj */
- struct RVALUE *next;
- } free;
-#endif
- struct RBasic basic;
- struct RObject object;
- struct RClass klass;
- /*struct RFloat flonum;*/
- /*struct RString string;*/
- struct RArray array;
- /*struct RRegexp regexp;*/
- struct RHash hash;
- /*struct RData data;*/
- struct RStruct rstruct;
- /*struct RBignum bignum;*/
- /*struct RFile file;*/
- } as;
-} RVALUE;
-
-typedef struct {
- long hash;
- char *buffer;
- long length;
- long remaining;
- int printed;
-} bytestring_t;
-
-#define RUBY_DOMAIN "ruby.yaml.org,2002"
-
-/*
- * symbols and constants
- */
-static ID s_new, s_utc, s_at, s_to_f, s_to_i, s_read, s_binmode, s_call, s_cmp, s_transfer, s_update, s_dup, s_haskey, s_match, s_keys, s_unpack, s_tr_bang, s_default_set, s_tag_read_class, s_tag_subclasses, s_resolver, s_push, s_emitter, s_level, s_detect_implicit, s_node_import, s_out, s_input, s_intern, s_transform, s_yaml_new, s_yaml_initialize, s_node_export, s_to_yaml, s_write, s_set_resolver;
-static ID s_tags, s_domain, s_kind, s_name, s_options, s_type_id, s_type_id_set, s_style, s_style_set, s_value, s_value_set;
-static VALUE sym_model, sym_generic, sym_input, sym_bytecode;
-static VALUE sym_scalar, sym_seq, sym_map;
-static VALUE sym_1quote, sym_2quote, sym_fold, sym_literal, sym_plain, sym_inline;
-static VALUE cDate, cNode, cMap, cSeq, cScalar, cOut, cParser, cResolver, cPrivateType, cDomainType, cYObject, cBadAlias, cDefaultKey, cMergeKey, cEmitter;
-static VALUE oDefaultResolver, oGenericResolver;
-
-/*
- * my private collection of numerical oddities.
- */
-static double S_zero() { return 0.0; }
-static double S_one() { return 1.0; }
-static double S_inf() { return S_one() / S_zero(); }
-static double S_nan() { return S_zero() / S_zero(); }
-
-static VALUE syck_node_transform( VALUE );
-
-/*
- * handler prototypes
- */
-SYMID rb_syck_load_handler _((SyckParser *, SyckNode *));
-void rb_syck_err_handler _((SyckParser *, char *));
-SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *));
-void rb_syck_output_handler _((SyckEmitter *, char *, long));
-void rb_syck_emitter_handler _((SyckEmitter *, st_data_t));
-int syck_parser_assign_io _((SyckParser *, VALUE *));
-VALUE syck_scalar_alloc _((VALUE class));
-VALUE syck_seq_alloc _((VALUE class));
-VALUE syck_map_alloc _((VALUE class));
-
-struct parser_xtra {
- VALUE data; /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */
- VALUE proc;
- VALUE resolver;
- int taint;
-};
-
-struct emitter_xtra {
- VALUE oid;
- VALUE data;
- VALUE port;
-};
-
-/*
- * Convert YAML to bytecode
- */
-VALUE
-rb_syck_compile(self, port)
- VALUE self, port;
-{
- SYMID oid;
- int taint;
- char *ret;
- VALUE bc;
- bytestring_t *sav;
-
- SyckParser *parser = syck_new_parser();
- taint = syck_parser_assign_io(parser, &port);
- syck_parser_handler( parser, syck_yaml2byte_handler );
- syck_parser_error_handler( parser, NULL );
- syck_parser_implicit_typing( parser, 0 );
- syck_parser_taguri_expansion( parser, 0 );
- oid = syck_parse( parser );
- syck_lookup_sym( parser, oid, (char **)&sav );
-
- ret = S_ALLOCA_N( char, strlen( sav->buffer ) + 3 );
- ret[0] = '\0';
- strcat( ret, "D\n" );
- strcat( ret, sav->buffer );
-
- syck_free_parser( parser );
-
- bc = rb_str_new2( ret );
- if ( taint ) OBJ_TAINT( bc );
- return bc;
-}
-
-/*
- * read from io.
- */
-long
-rb_syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
-{
- long len = 0;
-
- ASSERT( str != NULL );
- max_size -= skip;
-
- if ( max_size <= 0 ) max_size = 0;
- else
- {
- /*
- * call io#read.
- */
- VALUE src = (VALUE)str->ptr;
- VALUE n = LONG2NUM(max_size);
- VALUE str2 = rb_funcall2(src, s_read, 1, &n);
- if (!NIL_P(str2))
- {
- StringValue(str2);
- len = RSTRING(str2)->len;
- memcpy( buf + skip, RSTRING(str2)->ptr, len );
- }
- }
- len += skip;
- buf[len] = '\0';
- return len;
-}
-
-/*
- * determine: are we reading from a string or io?
- * (returns tainted? boolean)
- */
-int
-syck_parser_assign_io(parser, pport)
- SyckParser *parser;
- VALUE *pport;
-{
- int taint = Qtrue;
- VALUE tmp, port = *pport;
- if (!NIL_P(tmp = rb_check_string_type(port))) {
- taint = OBJ_TAINTED(port); /* original taintedness */
- port = tmp;
- syck_parser_str( parser, RSTRING(port)->ptr, RSTRING(port)->len, NULL );
- }
- else if (rb_respond_to(port, s_read)) {
- if (rb_respond_to(port, s_binmode)) {
- rb_funcall2(port, s_binmode, 0, 0);
- }
- syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read );
- }
- else {
- rb_raise(rb_eTypeError, "instance of IO needed");
- }
- *pport = port;
- return taint;
-}
-
-/*
- * 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
-rb_syck_mktime(str, len)
- char *str;
- long len;
-{
- VALUE time;
- char *ptr = str;
- VALUE year = INT2FIX(0);
- VALUE mon = INT2FIX(0);
- VALUE day = INT2FIX(0);
- VALUE hour = INT2FIX(0);
- VALUE min = INT2FIX(0);
- VALUE sec = INT2FIX(0);
- long usec;
-
- /* Year*/
- if ( ptr[0] != '\0' && len > 0 ) {
- year = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Month*/
- ptr += 4;
- if ( ptr[0] != '\0' && len > ptr - str ) {
- while ( !ISDIGIT( *ptr ) ) ptr++;
- mon = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Day*/
- ptr += 2;
- if ( ptr[0] != '\0' && len > ptr - str ) {
- while ( !ISDIGIT( *ptr ) ) ptr++;
- day = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Hour*/
- ptr += 2;
- if ( ptr[0] != '\0' && len > ptr - str ) {
- while ( !ISDIGIT( *ptr ) ) ptr++;
- hour = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Minute */
- ptr += 2;
- if ( ptr[0] != '\0' && len > ptr - str ) {
- while ( !ISDIGIT( *ptr ) ) ptr++;
- min = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Second */
- ptr += 2;
- if ( ptr[0] != '\0' && len > ptr - str ) {
- while ( !ISDIGIT( *ptr ) ) ptr++;
- sec = INT2FIX(strtol(ptr, NULL, 10));
- }
-
- /* Millisecond */
- ptr += 2;
- if ( len > ptr - str && *ptr == '.' )
- {
- char padded[] = "000000";
- char *end = ptr + 1;
- while ( isdigit( *end ) ) end++;
- MEMCPY(padded, ptr + 1, char, end - (ptr + 1));
- usec = strtol(padded, NULL, 10);
- }
- else
- {
- usec = 0;
- }
-
- /* Time Zone*/
- while ( len > ptr - str && *ptr != 'Z' && *ptr != '+' && *ptr != '-' && *ptr != '\0' ) ptr++;
- if ( len > ptr - str && ( *ptr == '-' || *ptr == '+' ) )
- {
- time_t tz_offset = strtol(ptr, NULL, 10) * 3600;
- time_t tmp;
-
- while ( *ptr != ':' && *ptr != '\0' ) ptr++;
- if ( *ptr == ':' )
- {
- ptr += 1;
- if ( tz_offset < 0 )
- {
- tz_offset -= strtol(ptr, NULL, 10) * 60;
- }
- else
- {
- tz_offset += strtol(ptr, NULL, 10) * 60;
- }
- }
-
- /* Make TZ time*/
- time = rb_funcall(rb_cTime, s_utc, 6, year, mon, day, hour, min, sec);
- tmp = NUM2LONG(rb_funcall(time, s_to_i, 0)) - tz_offset;
- return rb_funcall(rb_cTime, s_at, 2, LONG2NUM(tmp), LONG2NUM(usec));
- }
- else
- {
- /* Make UTC time*/
- return rb_funcall(rb_cTime, s_utc, 7, year, mon, day, hour, min, sec, LONG2NUM(usec));
- }
-}
-
-/*
- * handles merging of an array of hashes
- * (see http://www.yaml.org/type/merge/)
- */
-VALUE
-syck_merge_i( entry, hsh )
- VALUE entry, hsh;
-{
- VALUE tmp;
- if ( !NIL_P(tmp = rb_check_convert_type(entry, T_HASH, "Hash", "to_hash")) )
- {
- entry = tmp;
- rb_funcall( hsh, s_update, 1, entry );
- }
- return Qnil;
-}
-
-/*
- * default handler for ruby.yaml.org types
- */
-int
-yaml_org_handler( n, ref )
- SyckNode *n;
- VALUE *ref;
-{
- char *type_id = n->type_id;
- int transferred = 0;
- long i = 0;
- VALUE obj = Qnil;
-
- if ( type_id != NULL && strncmp( type_id, "tag:yaml.org,2002:", 18 ) == 0 )
- {
- type_id += 18;
- }
-
- switch (n->kind)
- {
- case syck_str_kind:
- transferred = 1;
- if ( type_id == NULL )
- {
- obj = rb_str_new( n->data.str->ptr, n->data.str->len );
- }
- else if ( strcmp( type_id, "null" ) == 0 )
- {
- obj = Qnil;
- }
- else if ( strcmp( type_id, "binary" ) == 0 )
- {
- VALUE arr;
- obj = rb_str_new( n->data.str->ptr, n->data.str->len );
- rb_funcall( obj, s_tr_bang, 2, rb_str_new2( "\n\t " ), rb_str_new2( "" ) );
- arr = rb_funcall( obj, s_unpack, 1, rb_str_new2( "m" ) );
- obj = rb_ary_shift( arr );
- }
- else if ( strcmp( type_id, "bool#yes" ) == 0 )
- {
- obj = Qtrue;
- }
- else if ( strcmp( type_id, "bool#no" ) == 0 )
- {
- obj = Qfalse;
- }
- else if ( strcmp( type_id, "int#hex" ) == 0 )
- {
- syck_str_blow_away_commas( n );
- obj = rb_cstr2inum( n->data.str->ptr, 16 );
- }
- else if ( strcmp( type_id, "int#oct" ) == 0 )
- {
- syck_str_blow_away_commas( n );
- obj = rb_cstr2inum( n->data.str->ptr, 8 );
- }
- else if ( strcmp( type_id, "int#base60" ) == 0 )
- {
- char *ptr, *end;
- long sixty = 1;
- long total = 0;
- syck_str_blow_away_commas( n );
- ptr = n->data.str->ptr;
- end = n->data.str->ptr + n->data.str->len;
- while ( end > ptr )
- {
- long bnum = 0;
- char *colon = end - 1;
- while ( colon >= ptr && *colon != ':' )
- {
- colon--;
- }
- if ( colon >= ptr && *colon == ':' ) *colon = '\0';
-
- bnum = strtol( colon + 1, NULL, 10 );
- total += bnum * sixty;
- sixty *= 60;
- end = colon;
- }
- obj = INT2FIX(total);
- }
- else if ( strncmp( type_id, "int", 3 ) == 0 )
- {
- syck_str_blow_away_commas( n );
- obj = rb_cstr2inum( n->data.str->ptr, 10 );
- }
- else if ( strcmp( type_id, "float#base60" ) == 0 )
- {
- char *ptr, *end;
- long sixty = 1;
- double total = 0.0;
- syck_str_blow_away_commas( n );
- ptr = n->data.str->ptr;
- end = n->data.str->ptr + n->data.str->len;
- while ( end > ptr )
- {
- double bnum = 0;
- char *colon = end - 1;
- while ( colon >= ptr && *colon != ':' )
- {
- colon--;
- }
- if ( colon >= ptr && *colon == ':' ) *colon = '\0';
-
- bnum = strtod( colon + 1, NULL );
- total += bnum * sixty;
- sixty *= 60;
- end = colon;
- }
- obj = rb_float_new( total );
- }
- else if ( strcmp( type_id, "float#nan" ) == 0 )
- {
- obj = rb_float_new( S_nan() );
- }
- else if ( strcmp( type_id, "float#inf" ) == 0 )
- {
- obj = rb_float_new( S_inf() );
- }
- else if ( strcmp( type_id, "float#neginf" ) == 0 )
- {
- obj = rb_float_new( -S_inf() );
- }
- else if ( strncmp( type_id, "float", 5 ) == 0 )
- {
- double f;
- syck_str_blow_away_commas( n );
- f = strtod( n->data.str->ptr, NULL );
- obj = rb_float_new( f );
- }
- else if ( strcmp( type_id, "timestamp#iso8601" ) == 0 )
- {
- obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
- }
- else if ( strcmp( type_id, "timestamp#spaced" ) == 0 )
- {
- obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
- }
- else if ( strcmp( type_id, "timestamp#ymd" ) == 0 )
- {
- char *ptr = n->data.str->ptr;
- VALUE year, mon, day;
-
- /* Year*/
- ptr[4] = '\0';
- year = INT2FIX(strtol(ptr, NULL, 10));
-
- /* Month*/
- ptr += 4;
- while ( !ISDIGIT( *ptr ) ) ptr++;
- mon = INT2FIX(strtol(ptr, NULL, 10));
-
- /* Day*/
- ptr += 2;
- while ( !ISDIGIT( *ptr ) ) ptr++;
- day = INT2FIX(strtol(ptr, NULL, 10));
-
- if ( !cDate ) {
- /*
- * Load Date module
- */
- rb_require( "date" );
- cDate = rb_const_get( rb_cObject, rb_intern("Date") );
- }
-
- obj = rb_funcall( cDate, s_new, 3, year, mon, day );
- }
- else if ( strncmp( type_id, "timestamp", 9 ) == 0 )
- {
- obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
- }
- else if ( strncmp( type_id, "merge", 5 ) == 0 )
- {
- obj = rb_funcall( cMergeKey, s_new, 0 );
- }
- else if ( strncmp( type_id, "default", 7 ) == 0 )
- {
- obj = rb_funcall( cDefaultKey, s_new, 0 );
- }
- else if ( n->data.str->style == scalar_plain &&
- n->data.str->len > 1 &&
- strncmp( n->data.str->ptr, ":", 1 ) == 0 )
- {
- obj = rb_funcall( oDefaultResolver, s_transfer, 2,
- rb_str_new2( "tag:ruby.yaml.org,2002:sym" ),
- rb_str_new( n->data.str->ptr + 1, n->data.str->len - 1 ) );
- }
- else if ( strcmp( type_id, "str" ) == 0 )
- {
- obj = rb_str_new( n->data.str->ptr, n->data.str->len );
- }
- else
- {
- transferred = 0;
- obj = rb_str_new( n->data.str->ptr, n->data.str->len );
- }
- break;
-
- case syck_seq_kind:
- if ( type_id == NULL || strcmp( type_id, "seq" ) == 0 )
- {
- transferred = 1;
- }
- 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:
- if ( type_id == NULL || strcmp( type_id, "map" ) == 0 )
- {
- transferred = 1;
- }
- 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 ) )
- {
- VALUE tmp;
- if ( !NIL_P(tmp = rb_check_convert_type(v, T_HASH, "Hash", "to_hash")) )
- {
- VALUE dup = rb_funcall( tmp, s_dup, 0 );
- rb_funcall( dup, s_update, 1, obj );
- obj = dup;
- skip_aset = 1;
- }
- else if ( !NIL_P(tmp = rb_check_array_type(v)) )
- {
- VALUE end = rb_ary_pop( tmp );
- VALUE tmph = rb_check_convert_type(end, T_HASH, "Hash", "to_hash");
- if ( !NIL_P(tmph) )
- {
- VALUE dup = rb_funcall( tmph, s_dup, 0 );
- tmp = rb_ary_reverse( tmp );
- rb_ary_push( tmp, obj );
- rb_iterate( rb_each, tmp, 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;
- }
-
- *ref = obj;
- return transferred;
-}
-
-static void syck_node_mark( SyckNode *n );
-
-/*
- * {native mode} node handler
- * - Converts data into native Ruby types
- */
-SYMID
-rb_syck_load_handler(p, n)
- SyckParser *p;
- SyckNode *n;
-{
- VALUE obj = Qnil;
- struct parser_xtra *bonus = (struct parser_xtra *)p->bonus;
- VALUE resolver = bonus->resolver;
- if ( NIL_P( resolver ) )
- {
- resolver = oDefaultResolver;
- }
-
- /*
- * Create node,
- */
- obj = rb_funcall( resolver, s_node_import, 1, Data_Wrap_Struct( cNode, NULL, NULL, n ) );
-
- /*
- * ID already set, let's alter the symbol table to accept the new object
- */
- if (n->id > 0 && !NIL_P(obj))
- {
- MEMCPY((void *)n->id, (void *)obj, RVALUE, 1);
- MEMZERO((void *)obj, RVALUE, 1);
- obj = n->id;
- }
-
- if ( bonus->taint) OBJ_TAINT( obj );
- if ( bonus->proc != 0 ) rb_funcall(bonus->proc, s_call, 1, obj);
-
- rb_hash_aset(bonus->data, INT2FIX(RHASH(bonus->data)->tbl->num_entries), obj);
- return obj;
-}
-
-/*
- * friendly errors.
- */
-void
-rb_syck_err_handler(p, msg)
- SyckParser *p;
- char *msg;
-{
- char *endl = p->cursor;
-
- while ( *endl != '\0' && *endl != '\n' )
- endl++;
-
- endl[0] = '\0';
- rb_raise(rb_eArgError, "%s on line %d, col %d: `%s'",
- msg,
- p->linect,
- p->cursor - p->lineptr,
- p->lineptr);
-}
-
-/*
- * provide bad anchor object to the parser.
- */
-SyckNode *
-rb_syck_bad_anchor_handler(p, a)
- SyckParser *p;
- char *a;
-{
- VALUE anchor_name = rb_str_new2( a );
- SyckNode *badanc = syck_new_map( rb_str_new2( "name" ), anchor_name );
- badanc->type_id = syck_strndup( "tag:ruby.yaml.org,2002:object:YAML::Syck::BadAlias", 53 );
- return badanc;
-}
-
-/*
- * data loaded based on the model requested.
- */
-void
-syck_set_model( p, input, model )
- VALUE p, input, model;
-{
- SyckParser *parser;
- Data_Get_Struct(p, SyckParser, parser);
- syck_parser_handler( parser, rb_syck_load_handler );
- /* WARN: gonna be obsoleted soon!! */
- if ( model == sym_generic )
- {
- rb_funcall( p, s_set_resolver, 1, oGenericResolver );
- }
- syck_parser_implicit_typing( parser, 1 );
- syck_parser_taguri_expansion( parser, 1 );
-
- if ( NIL_P( input ) )
- {
- input = rb_ivar_get( p, s_input );
- }
- if ( input == sym_bytecode )
- {
- syck_parser_set_input_type( parser, syck_bytecode_utf8 );
- }
- else
- {
- syck_parser_set_input_type( parser, syck_yaml_utf8 );
- }
- syck_parser_error_handler( parser, rb_syck_err_handler );
- syck_parser_bad_anchor_handler( parser, rb_syck_bad_anchor_handler );
-}
-
-static int
-syck_st_mark_nodes( char *key, SyckNode *n, char *arg )
-{
- if ( n != (void *)1 ) syck_node_mark( n );
- return ST_CONTINUE;
-}
-
-/*
- * mark parser nodes
- */
-static void
-syck_mark_parser(parser)
- SyckParser *parser;
-{
- struct parser_xtra *bonus = (struct parser_xtra *)parser->bonus;
- rb_gc_mark_maybe(parser->root);
- rb_gc_mark_maybe(parser->root_on_error);
- rb_gc_mark( bonus->data );
- rb_gc_mark( bonus->proc );
- rb_gc_mark( bonus->resolver );
-
- if ( parser->anchors != NULL )
- {
- st_foreach( parser->anchors, syck_st_mark_nodes, 0 );
- }
- if ( parser->bad_anchors != NULL )
- {
- st_foreach( parser->bad_anchors, syck_st_mark_nodes, 0 );
- }
-}
-
-/*
- * Free the parser and any bonus attachment.
- */
-void
-rb_syck_free_parser(p)
- SyckParser *p;
-{
- S_FREE( p->bonus );
- syck_free_parser(p);
-}
-
-/*
- * YAML::Syck::Parser.allocate
- */
-VALUE syck_parser_s_alloc _((VALUE));
-VALUE
-syck_parser_s_alloc(class)
- VALUE class;
-{
- VALUE pobj;
- SyckParser *parser = syck_new_parser();
-
- parser->bonus = S_ALLOC( struct parser_xtra );
- S_MEMZERO( parser->bonus, struct parser_xtra, 1 );
-
- pobj = Data_Wrap_Struct( class, syck_mark_parser, rb_syck_free_parser, parser );
-
- syck_parser_set_root_on_error( parser, Qnil );
-
- return pobj;
-}
-
-/*
- * YAML::Syck::Parser.initialize( resolver, options )
- */
-static VALUE
-syck_parser_initialize(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE options;
- if (rb_scan_args(argc, argv, "01", &options) == 0)
- {
- options = rb_hash_new();
- }
- else
- {
- Check_Type(options, T_HASH);
- }
- rb_ivar_set(self, s_options, options);
- rb_ivar_set(self, s_input, Qnil);
- return self;
-}
-
-/*
- * YAML::Syck::Parser.bufsize = Integer
- */
-static VALUE
-syck_parser_bufsize_set( self, size )
- VALUE self, size;
-{
- SyckParser *parser;
-
- if ( rb_respond_to( size, s_to_i ) ) {
- int n = NUM2INT(rb_funcall(size, s_to_i, 0));
- Data_Get_Struct(self, SyckParser, parser);
- parser->bufsize = n;
- }
- return self;
-}
-
-/*
- * YAML::Syck::Parser.bufsize => Integer
- */
-static VALUE
-syck_parser_bufsize_get( self )
- VALUE self;
-{
- SyckParser *parser;
-
- Data_Get_Struct(self, SyckParser, parser);
- return INT2FIX( parser->bufsize );
-}
-
-/*
- * YAML::Syck::Parser.load( IO or String )
- */
-VALUE
-syck_parser_load(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE port, proc, model, input;
- SyckParser *parser;
- struct parser_xtra *bonus;
-
- rb_scan_args(argc, argv, "11", &port, &proc);
-
- input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
- model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
- Data_Get_Struct(self, SyckParser, parser);
- syck_set_model( self, input, model );
-
- bonus = (struct parser_xtra *)parser->bonus;
- bonus->taint = syck_parser_assign_io(parser, &port);
- bonus->data = rb_hash_new();
- bonus->resolver = rb_attr_get( self, s_resolver );
- if ( NIL_P( proc ) ) bonus->proc = 0;
- else bonus->proc = proc;
-
- return syck_parse( parser );
-}
-
-/*
- * YAML::Syck::Parser.load_documents( IO or String ) { |doc| }
- */
-VALUE
-syck_parser_load_documents(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE port, proc, v, input, model;
- SyckParser *parser;
- struct parser_xtra *bonus;
-
- rb_scan_args(argc, argv, "1&", &port, &proc);
-
- input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
- model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
- Data_Get_Struct(self, SyckParser, parser);
- syck_set_model( self, input, model );
-
- bonus = (struct parser_xtra *)parser->bonus;
- bonus->taint = syck_parser_assign_io(parser, &port);
- bonus->resolver = rb_attr_get( self, s_resolver );
- bonus->proc = 0;
-
- while ( 1 )
- {
- /* Reset hash for tracking nodes */
- bonus->data = rb_hash_new();
-
- /* Parse a document */
- v = syck_parse( parser );
- if ( parser->eof == 1 )
- {
- break;
- }
-
- /* Pass document to block */
- rb_funcall( proc, s_call, 1, v );
- }
-
- return Qnil;
-}
-
-/*
- * YAML::Syck::Parser#set_resolver
- */
-VALUE
-syck_parser_set_resolver( self, resolver )
- VALUE self, resolver;
-{
- rb_ivar_set( self, s_resolver, resolver );
- return self;
-}
-
-/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
- * YAML::Syck::Resolver#detect_implicit
- */
-VALUE
-syck_resolver_detect_implicit( self, val )
- VALUE self, val;
-{
- char *type_id;
- return rb_str_new2( "" );
-}
-
-/*
- * 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;
-}
-
-/*
- * Set instance variables
- */
-VALUE
-syck_set_ivars( vars, obj )
- VALUE vars, obj;
-{
- VALUE ivname = rb_ary_entry( vars, 0 );
- char *ivn;
- StringValue( ivname );
- ivn = S_ALLOCA_N( char, RSTRING(ivname)->len + 2 );
- ivn[0] = '@';
- ivn[1] = '\0';
- strncat( ivn, RSTRING(ivname)->ptr, RSTRING(ivname)->len );
- rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) );
- return Qnil;
-}
-
-/*
- * YAML::Syck::Resolver#const_find
- */
-VALUE
-syck_const_find( const_name )
- VALUE const_name;
-{
- VALUE tclass = rb_cObject;
- VALUE tparts = rb_str_split( const_name, "::" );
- int i = 0;
- for ( i = 0; i < RARRAY(tparts)->len; i++ ) {
- VALUE tpart = rb_to_id( rb_ary_entry( tparts, i ) );
- if ( !rb_const_defined( tclass, tpart ) ) return Qnil;
- tclass = rb_const_get( tclass, tpart );
- }
- return tclass;
-}
-
-/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
- * YAML::Syck::DefaultResolver#detect_implicit
- */
-VALUE
-syck_defaultresolver_detect_implicit( self, val )
- VALUE self, val;
-{
- char *type_id;
- VALUE tmp = rb_check_string_type(val);
-
- if ( !NIL_P(tmp) )
- {
- val = tmp;
- type_id = syck_match_implicit( RSTRING(val)->ptr, RSTRING(val)->len );
- return rb_str_new2( type_id );
- }
-
- return rb_str_new2( "" );
-}
-
-/*
- * YAML::Syck::DefaultResolver#node_import
- */
-VALUE
-syck_defaultresolver_node_import( self, node )
- VALUE self, node;
-{
- SyckNode *n;
- VALUE obj;
- Data_Get_Struct( node, SyckNode, n );
- if ( !yaml_org_handler( n, &obj ) )
- {
- obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
- }
- return obj;
-}
-
-/*
- * YAML::Syck::GenericResolver#node_import
- */
-VALUE
-syck_genericresolver_node_import( self, node )
- VALUE self, node;
-{
- SyckNode *n;
- int i = 0;
- VALUE t = Qnil, obj = Qnil, v = Qnil, style = Qnil;
- Data_Get_Struct(node, SyckNode, n);
-
- if ( n->type_id != NULL )
- {
- t = rb_str_new2(n->type_id);
- }
-
- switch (n->kind)
- {
- case syck_str_kind:
- {
- v = rb_str_new( n->data.str->ptr, n->data.str->len );
- if ( n->data.str->style == scalar_1quote )
- {
- style = sym_1quote;
- }
- else if ( n->data.str->style == scalar_2quote )
- {
- style = sym_2quote;
- }
- else if ( n->data.str->style == scalar_fold )
- {
- style = sym_fold;
- }
- else if ( n->data.str->style == scalar_literal )
- {
- style = sym_literal;
- }
- else if ( n->data.str->style == scalar_plain )
- {
- style = sym_plain;
- }
- obj = rb_funcall( cScalar, s_new, 3, t, v, style );
- }
- break;
-
- case syck_seq_kind:
- rb_iv_set(obj, "@kind", sym_seq);
- v = rb_ary_new2( syck_seq_count( n ) );
- for ( i = 0; i < syck_seq_count( n ); i++ )
- {
- rb_ary_store( v, i, syck_seq_read( n, i ) );
- }
- if ( n->data.list->style == seq_inline )
- {
- style = sym_inline;
- }
- obj = rb_funcall( cSeq, s_new, 3, t, v, style );
- break;
-
- case syck_map_kind:
- rb_iv_set(obj, "@kind", sym_map);
- v = rb_hash_new();
- for ( i = 0; i < syck_map_count( n ); i++ )
- {
- rb_hash_aset( v, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) );
- }
- if ( n->data.pairs->style == map_inline )
- {
- style = sym_inline;
- }
- obj = rb_funcall( cMap, s_new, 3, t, v, style );
- break;
- }
-
- return obj;
-}
-
-/*
- * YAML::Syck::BadAlias.initialize
- */
-VALUE
-syck_badalias_initialize( self, val )
- VALUE self, val;
-{
- rb_iv_set( self, "@name", val );
- return self;
-}
-
-/*
- * YAML::Syck::BadAlias.<=>
- */
-VALUE
-syck_badalias_cmp( alias1, alias2 )
- VALUE alias1, alias2;
-{
- VALUE str1 = rb_ivar_get( alias1, s_name );
- VALUE str2 = rb_ivar_get( alias2, s_name );
- VALUE val = rb_funcall( str1, s_cmp, 1, str2 );
- return val;
-}
-
-/*
- * YAML::DomainType.initialize
- */
-VALUE
-syck_domaintype_initialize( self, domain, type_id, val )
- VALUE self, domain, type_id, val;
-{
- rb_iv_set( self, "@domain", domain );
- rb_iv_set( self, "@type_id", type_id );
- rb_iv_set( self, "@value", val );
- return self;
-}
-
-/*
- * YAML::Object.initialize
- */
-VALUE
-syck_yobject_initialize( self, klass, ivars )
- VALUE self, klass, ivars;
-{
- rb_iv_set( self, "@class", klass );
- rb_iv_set( self, "@ivars", ivars );
- return self;
-}
-
-/*
- * YAML::PrivateType.initialize
- */
-VALUE
-syck_privatetype_initialize( self, type_id, val )
- VALUE self, type_id, val;
-{
- rb_iv_set( self, "@type_id", type_id );
- rb_iv_set( self, "@value", val );
- return self;
-}
-
-/*
- * Mark node contents.
- */
-static void
-syck_node_mark( n )
- SyckNode *n;
-{
- int i;
- rb_gc_mark_maybe( n->id );
- switch ( n->kind )
- {
- case syck_seq_kind:
- for ( i = 0; i < n->data.list->idx; i++ )
- {
- rb_gc_mark( syck_seq_read( n, i ) );
- }
- break;
-
- case syck_map_kind:
- for ( i = 0; i < n->data.pairs->idx; i++ )
- {
- rb_gc_mark( syck_map_read( n, map_key, i ) );
- rb_gc_mark( syck_map_read( n, map_value, i ) );
- }
- break;
- }
-#if 0 /* maybe needed */
- if ( n->shortcut ) syck_node_mark( n->shortcut ); /* caution: maybe cyclic */
-#endif
-}
-
-/*
- * YAML::Syck::Scalar.allocate
- */
-VALUE
-syck_scalar_alloc( class )
- VALUE class;
-{
- SyckNode *node = syck_alloc_str();
- VALUE obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
- node->id = obj;
- return obj;
-}
-
-/*
- * YAML::Syck::Scalar.initialize
- */
-VALUE
-syck_scalar_initialize( self, type_id, val, style )
- VALUE self, type_id, val, style;
-{
- rb_iv_set( self, "@kind", sym_scalar );
- rb_funcall( self, s_type_id_set, 1, type_id );
- rb_funcall( self, s_value_set, 1, val );
- rb_funcall( self, s_style_set, 1, style );
- return self;
-}
-
-/*
- * YAML::Syck::Scalar.style=
- */
-VALUE
-syck_scalar_style_set( self, style )
- VALUE self, style;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- if ( NIL_P( style ) )
- {
- node->data.str->style = scalar_none;
- }
- else if ( style == sym_1quote )
- {
- node->data.str->style = scalar_1quote;
- }
- else if ( style == sym_2quote )
- {
- node->data.str->style = scalar_2quote;
- }
- else if ( style == sym_fold )
- {
- node->data.str->style = scalar_fold;
- }
- else if ( style == sym_literal )
- {
- node->data.str->style = scalar_literal;
- }
- else if ( style == sym_plain )
- {
- node->data.str->style = scalar_plain;
- }
-
- rb_iv_set( self, "@style", style );
- return self;
-}
-
-/*
- * YAML::Syck::Scalar.value=
- */
-VALUE
-syck_scalar_value_set( self, val )
- VALUE self, val;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- StringValue( val );
- node->data.str->ptr = syck_strndup( RSTRING(val)->ptr, RSTRING(val)->len );
- node->data.str->len = RSTRING(val)->len;
- node->data.str->style = scalar_none;
-
- rb_iv_set( self, "@value", val );
- return val;
-}
-
-/*
- * YAML::Syck::Seq.allocate
- */
-VALUE
-syck_seq_alloc( class )
- VALUE class;
-{
- SyckNode *node;
- VALUE obj;
- node = syck_alloc_seq();
- obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
- node->id = obj;
- return obj;
-}
-
-/*
- * YAML::Syck::Seq.initialize
- */
-VALUE
-syck_seq_initialize( self, type_id, val, style )
- VALUE self, type_id, val, style;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- rb_iv_set( self, "@kind", sym_seq );
- rb_funcall( self, s_type_id_set, 1, type_id );
- rb_funcall( self, s_value_set, 1, val );
- rb_funcall( self, s_style_set, 1, style );
- return self;
-}
-
-/*
- * YAML::Syck::Seq.value=
- */
-VALUE
-syck_seq_value_set( self, val )
- VALUE self, val;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- val = rb_check_array_type( val );
- if ( !NIL_P( val ) ) {
- int i;
- syck_seq_empty( node );
- for ( i = 0; i < RARRAY( val )->len; i++ )
- {
- syck_seq_add( node, rb_ary_entry(val, i) );
- }
- }
-
- rb_iv_set( self, "@value", val );
- return val;
-}
-
-/*
- * YAML::Syck::Seq.add
- */
-VALUE
-syck_seq_add_m( self, val )
- VALUE self, val;
-{
- SyckNode *node;
- VALUE emitter = rb_ivar_get( self, s_emitter );
- Data_Get_Struct( self, SyckNode, node );
-
- if ( rb_respond_to( emitter, s_node_export ) ) {
- val = rb_funcall( emitter, s_node_export, 1, val );
- }
- syck_seq_add( node, val );
- rb_ary_push( rb_ivar_get( self, s_value ), val );
-
- return self;
-}
-
-/*
- * YAML::Syck::Seq.style=
- */
-VALUE
-syck_seq_style_set( self, style )
- VALUE self, style;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- if ( style == sym_inline )
- {
- node->data.list->style = seq_inline;
- }
- else
- {
- node->data.list->style = seq_none;
- }
-
- rb_iv_set( self, "@style", style );
- return self;
-}
-
-/*
- * YAML::Syck::Map.allocate
- */
-VALUE
-syck_map_alloc( class )
- VALUE class;
-{
- SyckNode *node;
- VALUE obj;
- node = syck_alloc_map();
- obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
- node->id = obj;
- return obj;
-}
-
-/*
- * YAML::Syck::Map.initialize
- */
-VALUE
-syck_map_initialize( self, type_id, val, style )
- VALUE self, type_id, val, style;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- if ( !NIL_P( val ) )
- {
- VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
- VALUE keys;
- int i;
- if ( NIL_P(hsh) )
- {
- rb_raise( rb_eTypeError, "wrong argument type" );
- }
-
- keys = rb_funcall( hsh, s_keys, 0 );
- for ( i = 0; i < RARRAY(keys)->len; i++ )
- {
- VALUE key = rb_ary_entry(keys, i);
- syck_map_add( node, key, rb_hash_aref(hsh, key) );
- }
- }
-
- rb_iv_set( self, "@kind", sym_seq );
- rb_funcall( self, s_type_id_set, 1, type_id );
- rb_funcall( self, s_value_set, 1, val );
- rb_funcall( self, s_style_set, 1, style );
- return self;
-}
-
-/*
- * YAML::Syck::Map.value=
- */
-VALUE
-syck_map_value_set( self, val )
- VALUE self, val;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- if ( !NIL_P( val ) )
- {
- VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
- VALUE keys;
- int i;
- if ( NIL_P(hsh) )
- {
- rb_raise( rb_eTypeError, "wrong argument type" );
- }
-
- syck_map_empty( node );
- keys = rb_funcall( hsh, s_keys, 0 );
- for ( i = 0; i < RARRAY(keys)->len; i++ )
- {
- VALUE key = rb_ary_entry(keys, i);
- syck_map_add( node, key, rb_hash_aref(hsh, key) );
- }
- }
-
- rb_iv_set( self, "@value", val );
- return val;
-}
-
-/*
- * YAML::Syck::Map.add
- */
-VALUE
-syck_map_add_m( self, key, val )
- VALUE self, key, val;
-{
- SyckNode *node;
- VALUE emitter = rb_ivar_get( self, s_emitter );
- Data_Get_Struct( self, SyckNode, node );
-
- if ( rb_respond_to( emitter, s_node_export ) ) {
- key = rb_funcall( emitter, s_node_export, 1, key );
- val = rb_funcall( emitter, s_node_export, 1, val );
- }
- syck_map_add( node, key, val );
- rb_hash_aset( rb_ivar_get( self, s_value ), key, val );
-
- return self;
-}
-
-/*
- * YAML::Syck::Map.style=
- */
-VALUE
-syck_map_style_set( self, style )
- VALUE self, style;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- if ( style == sym_inline )
- {
- node->data.pairs->style = map_inline;
- }
- else
- {
- node->data.pairs->style = map_none;
- }
-
- rb_iv_set( self, "@style", style );
- return self;
-}
-
-/*
- * Cloning method for all node types
- */
-VALUE
-syck_node_init_copy( copy, orig )
- VALUE copy, orig;
-{
- SyckNode *copy_n;
- SyckNode *orig_n;
-
- if ( copy == orig )
- return copy;
-
- if ( TYPE( orig ) != T_DATA )
- {
- rb_raise( rb_eTypeError, "wrong argument type" );
- }
-
- Data_Get_Struct( orig, SyckNode, orig_n );
- Data_Get_Struct( copy, SyckNode, copy_n );
- MEMCPY( copy_n, orig_n, SyckNode, 1 );
- return copy;
-}
-
-/*
- * YAML::Syck::Node#type_id=
- */
-VALUE
-syck_node_type_id_set( self, type_id )
- VALUE self, type_id;
-{
- SyckNode *node;
- Data_Get_Struct( self, SyckNode, node );
-
- S_FREE( node->type_id );
-
- if ( !NIL_P( type_id ) ) {
- StringValue( type_id );
- node->type_id = syck_strndup( RSTRING(type_id)->ptr, RSTRING(type_id)->len );
- }
-
- rb_iv_set( self, "@type_id", type_id );
- return type_id;
-}
-
-/*
- * YAML::Syck::Node.transform
- */
-VALUE
-syck_node_transform( self )
- VALUE self;
-{
- VALUE t;
- SyckNode *n;
- SyckNode *orig_n;
- Data_Get_Struct(self, SyckNode, orig_n);
- t = Data_Wrap_Struct( cNode, syck_node_mark, syck_free_node, 0 );
-
- switch (orig_n->kind)
- {
- case syck_map_kind:
- {
- int i;
- DATA_PTR(t) = n = syck_alloc_map();
- for ( i = 0; i < orig_n->data.pairs->idx; i++ )
- {
- syck_map_add( n, rb_funcall( syck_map_read( orig_n, map_key, i ), s_transform, 0 ),
- rb_funcall( syck_map_read( orig_n, map_value, i ), s_transform, 0 ) );
- }
- }
- break;
-
- case syck_seq_kind:
- {
- int i;
- DATA_PTR(t) = n = syck_alloc_seq();
- for ( i = 0; i < orig_n->data.list->idx; i++ )
- {
- syck_seq_add( n, rb_funcall( syck_seq_read( orig_n, i ), s_transform, 0 ) );
- }
- }
- break;
-
- case syck_str_kind:
- DATA_PTR(t) = n = syck_new_str2( orig_n->data.str->ptr, orig_n->data.str->len, orig_n->data.str->style );
- break;
- }
-
- if ( orig_n->type_id != NULL )
- {
- n->type_id = syck_strndup( orig_n->type_id, strlen( orig_n->type_id ) );
- }
- if ( orig_n->anchor != NULL )
- {
- n->anchor = syck_strndup( orig_n->anchor, strlen( orig_n->anchor ) );
- }
- n->id = t;
- return rb_funcall( oDefaultResolver, s_node_import, 1, t );
-}
-
-/*
- * Emitter callback: assembles YAML document events from
- * Ruby symbols. This is a brilliant way to do it.
- * No one could possibly object.
- */
-void
-rb_syck_emitter_handler(e, data)
- SyckEmitter *e;
- st_data_t data;
-{
- SyckNode *n;
- Data_Get_Struct((VALUE)data, SyckNode, n);
-
- switch (n->kind)
- {
- case syck_map_kind:
- {
- int i;
- syck_emit_map( e, n->type_id, n->data.pairs->style );
- for ( i = 0; i < n->data.pairs->idx; i++ )
- {
- syck_emit_item( e, syck_map_read( n, map_key, i ) );
- syck_emit_item( e, syck_map_read( n, map_value, i ) );
- }
- syck_emit_end( e );
- }
- break;
-
- case syck_seq_kind:
- {
- int i;
- syck_emit_seq( e, n->type_id, n->data.list->style );
- for ( i = 0; i < n->data.list->idx; i++ )
- {
- syck_emit_item( e, syck_seq_read( n, i ) );
- }
- syck_emit_end( e );
- }
- break;
-
- case syck_str_kind:
- {
- syck_emit_scalar( e, n->type_id, n->data.str->style, 0, 0, 0, n->data.str->ptr, n->data.str->len );
- }
- break;
- }
-}
-
-/*
- * Handle output from the emitter
- */
-void
-rb_syck_output_handler( emitter, str, len )
- SyckEmitter *emitter;
- char *str;
- long len;
-{
- struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
- VALUE dest = bonus->port;
- if (TYPE(dest) == T_STRING) {
- rb_str_cat( dest, str, len );
- } else {
- rb_io_write( dest, rb_str_new( str, len ) );
- }
-}
-
-/*
- * Helper function for marking nodes in the anchor
- * symbol table.
- */
-void
-syck_out_mark( emitter, node )
- VALUE emitter, node;
-{
- SyckEmitter *emitterPtr;
- struct emitter_xtra *bonus;
- Data_Get_Struct(emitter, SyckEmitter, emitterPtr);
- bonus = (struct emitter_xtra *)emitterPtr->bonus;
- rb_ivar_set( node, s_emitter, emitter );
- /* syck_emitter_mark_node( emitterPtr, (st_data_t)node ); */
- if ( !NIL_P( bonus->oid ) ) {
- rb_hash_aset( bonus->data, bonus->oid, node );
- }
-}
-
-/*
- * Mark emitter values.
- */
-static void
-syck_mark_emitter(emitter)
- SyckEmitter *emitter;
-{
- struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
- rb_gc_mark( bonus->oid );
- rb_gc_mark( bonus->data );
- rb_gc_mark( bonus->port );
-}
-
-/*
- * Free the emitter and any bonus attachment.
- */
-void
-rb_syck_free_emitter(e)
- SyckEmitter *e;
-{
- S_FREE( e->bonus );
- syck_free_emitter(e);
-}
-
-/*
- * YAML::Syck::Emitter.allocate
- */
-VALUE syck_emitter_s_alloc _((VALUE));
-VALUE
-syck_emitter_s_alloc(class)
- VALUE class;
-{
- VALUE pobj;
- SyckEmitter *emitter = syck_new_emitter();
-
- emitter->bonus = S_ALLOC( struct emitter_xtra );
- S_MEMZERO( emitter->bonus, struct emitter_xtra, 1 );
-
- pobj = Data_Wrap_Struct( class, syck_mark_emitter, rb_syck_free_emitter, emitter );
- syck_emitter_handler( emitter, rb_syck_emitter_handler );
- syck_output_handler( emitter, rb_syck_output_handler );
-
- rb_ivar_set( pobj, s_out, rb_funcall( cOut, s_new, 1, pobj ) );
- return pobj;
-}
-
-/*
- * YAML::Syck::Emitter.reset( options )
- */
-VALUE
-syck_emitter_reset( argc, argv, self )
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE options, tmp;
- SyckEmitter *emitter;
- struct emitter_xtra *bonus;
-
- Data_Get_Struct(self, SyckEmitter, emitter);
- bonus = (struct emitter_xtra *)emitter->bonus;
-
- bonus->oid = Qnil;
- bonus->port = rb_str_new2( "" );
- bonus->data = rb_hash_new();
-
- if (rb_scan_args(argc, argv, "01", &options) == 0)
- {
- options = rb_hash_new();
- rb_ivar_set(self, s_options, options);
- }
- else if ( !NIL_P(tmp = rb_check_string_type(options)) )
- {
- bonus->port = tmp;
- }
- else if ( rb_respond_to( options, s_write ) )
- {
- bonus->port = options;
- }
- else
- {
- Check_Type(options, T_HASH);
- rb_ivar_set(self, s_options, options);
- }
-
- emitter->headless = 0;
- rb_ivar_set(self, s_level, INT2FIX(0));
- rb_ivar_set(self, s_resolver, Qnil);
- return self;
-}
-
-/*
- * YAML::Syck::Emitter.emit( object_id ) { |out| ... }
- */
-VALUE
-syck_emitter_emit( argc, argv, self )
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE oid, proc;
- char *anchor_name;
- SyckEmitter *emitter;
- struct emitter_xtra *bonus;
- SYMID symple;
- int level = FIX2INT(rb_ivar_get(self, s_level)) + 1;
- rb_ivar_set(self, s_level, INT2FIX(level));
-
- rb_scan_args(argc, argv, "1&", &oid, &proc);
- Data_Get_Struct(self, SyckEmitter, emitter);
- bonus = (struct emitter_xtra *)emitter->bonus;
-
- /* Calculate anchors, normalize nodes, build a simpler symbol table */
- bonus->oid = oid;
- if ( !NIL_P( oid ) && RTEST( rb_funcall( bonus->data, s_haskey, 1, oid ) ) ) {
- symple = rb_hash_aref( bonus->data, oid );
- } else {
- symple = rb_funcall( proc, s_call, 1, rb_ivar_get( self, s_out ) );
- }
- syck_emitter_mark_node( emitter, (st_data_t)symple );
-
- /* Second pass, build emitted string */
- level -= 1;
- rb_ivar_set(self, s_level, INT2FIX(level));
- if ( level == 0 )
- {
- syck_emit(emitter, (st_data_t)symple);
- syck_emitter_flush(emitter, 0);
-
- return bonus->port;
- }
-
- return symple;
-}
-
-/*
- * YAML::Syck::Emitter#node_export
- */
-VALUE
-syck_emitter_node_export( self, node )
- VALUE self, node;
-{
- return rb_funcall( node, s_to_yaml, 1, self );
-}
-
-/*
- * YAML::Syck::Emitter#set_resolver
- */
-VALUE
-syck_emitter_set_resolver( self, resolver )
- VALUE self, resolver;
-{
- rb_ivar_set( self, s_resolver, resolver );
- return self;
-}
-
-/*
- * YAML::Syck::Out::initialize
- */
-VALUE
-syck_out_initialize( self, emitter )
- VALUE self, emitter;
-{
- rb_ivar_set( self, s_emitter, emitter );
- return self;
-}
-
-/*
- * YAML::Syck::Out::map
- */
-VALUE
-syck_out_map( argc, argv, self )
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE type_id, style, map;
- if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
- style = Qnil;
- }
- map = rb_funcall( cMap, s_new, 3, type_id, rb_hash_new(), style );
- syck_out_mark( rb_ivar_get( self, s_emitter ), map );
- rb_yield( map );
- return map;
-}
-
-/*
- * YAML::Syck::Out::seq
- */
-VALUE
-syck_out_seq( argc, argv, self )
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE type_id, style, seq;
- if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
- style = Qnil;
- }
- seq = rb_funcall( cSeq, s_new, 3, type_id, rb_ary_new(), style );
- syck_out_mark( rb_ivar_get( self, s_emitter ), seq );
- rb_yield( seq );
- return seq;
-}
-
-/*
- * YAML::Syck::Out::scalar
-syck_out_scalar( self, type_id, str, style )
- VALUE self, type_id, str, style;
- */
-VALUE
-syck_out_scalar( argc, argv, self )
- int argc;
- VALUE *argv;
- VALUE self;
-{
- VALUE type_id, str, style, scalar;
- if (rb_scan_args(argc, argv, "21", &type_id, &str, &style) == 2) {
- style = Qnil;
- }
- scalar = rb_funcall( cScalar, s_new, 3, type_id, str, style );
- syck_out_mark( rb_ivar_get( self, s_emitter ), scalar );
- return scalar;
-}
-
-/*
- * Initialize Syck extension
- */
-void
-Init_syck()
-{
- VALUE rb_yaml = rb_define_module( "YAML" );
- VALUE rb_syck = rb_define_module_under( rb_yaml, "Syck" );
- rb_define_const( rb_syck, "VERSION", rb_str_new2( SYCK_VERSION ) );
- rb_define_module_function( rb_syck, "compile", rb_syck_compile, 1 );
-
- /*
- * Global symbols
- */
- s_new = rb_intern("new");
- s_utc = rb_intern("utc");
- s_at = rb_intern("at");
- s_to_f = rb_intern("to_f");
- s_to_i = rb_intern("to_i");
- s_read = rb_intern("read");
- s_binmode = rb_intern("binmode");
- s_transfer = rb_intern("transfer");
- s_call = rb_intern("call");
- s_cmp = rb_intern("<=>");
- s_intern = rb_intern("intern");
- s_update = rb_intern("update");
- s_detect_implicit = rb_intern("detect_implicit");
- s_dup = rb_intern("dup");
- s_default_set = rb_intern("default=");
- s_match = rb_intern("match");
- s_push = rb_intern("push");
- s_haskey = rb_intern("has_key?");
- s_keys = rb_intern("keys");
- s_node_import = rb_intern("node_import");
- s_tr_bang = rb_intern("tr!");
- s_unpack = rb_intern("unpack");
- s_write = rb_intern("write");
- s_tag_read_class = rb_intern( "yaml_tag_read_class" );
- s_tag_subclasses = rb_intern( "yaml_tag_subclasses?" );
- s_emitter = rb_intern( "emitter" );
- s_set_resolver = rb_intern( "set_resolver" );
- s_node_export = rb_intern( "node_export" );
- s_to_yaml = rb_intern( "to_yaml" );
- s_transform = rb_intern( "transform" );
- s_yaml_new = rb_intern("yaml_new");
- s_yaml_initialize = rb_intern("yaml_initialize");
-
- s_tags = rb_intern("@tags");
- s_name = rb_intern("@name");
- s_options = rb_intern("@options");
- s_kind = rb_intern("@kind");
- s_type_id = rb_intern("@type_id");
- s_type_id_set = rb_intern("type_id=");
- s_resolver = rb_intern("@resolver");
- s_level = rb_intern( "@level" );
- s_style = rb_intern("@style");
- s_style_set = rb_intern("style=");
- s_value = rb_intern("@value");
- s_value_set = rb_intern("value=");
- s_out = rb_intern("@out");
- s_input = rb_intern("@input");
-
- sym_model = ID2SYM(rb_intern("Model"));
- sym_generic = ID2SYM(rb_intern("Generic"));
- sym_bytecode = ID2SYM(rb_intern("bytecode"));
- sym_map = ID2SYM(rb_intern("map"));
- sym_scalar = ID2SYM(rb_intern("scalar"));
- sym_seq = ID2SYM(rb_intern("seq"));
- sym_1quote = ID2SYM(rb_intern("quote1"));
- sym_2quote = ID2SYM(rb_intern("quote2"));
- sym_fold = ID2SYM(rb_intern("fold"));
- sym_literal = ID2SYM(rb_intern("literal"));
- sym_plain = ID2SYM(rb_intern("plain"));
- sym_inline = ID2SYM(rb_intern("inline"));
-
- /*
- * Define YAML::Syck::Resolver class
- */
- cResolver = rb_define_class_under( rb_syck, "Resolver", rb_cObject );
- rb_define_attr( cResolver, "tags", 1, 1 );
- rb_define_method( cResolver, "initialize", syck_resolver_initialize, 0 );
- rb_define_method( cResolver, "add_type", syck_resolver_add_type, 2 );
- rb_define_method( cResolver, "use_types_at", syck_resolver_use_types_at, 1 );
- rb_define_method( cResolver, "detect_implicit", syck_resolver_detect_implicit, 1 );
- rb_define_method( cResolver, "transfer", syck_resolver_transfer, 2 );
- rb_define_method( cResolver, "node_import", syck_resolver_node_import, 1 );
- rb_define_method( cResolver, "tagurize", syck_resolver_tagurize, 1 );
-
- rb_global_variable( &oDefaultResolver );
- oDefaultResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
- rb_define_singleton_method( oDefaultResolver, "node_import", syck_defaultresolver_node_import, 1 );
- rb_define_singleton_method( oDefaultResolver, "detect_implicit", syck_defaultresolver_detect_implicit, 1 );
- rb_define_const( rb_syck, "DefaultResolver", oDefaultResolver );
- rb_global_variable( &oGenericResolver );
- oGenericResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
- rb_define_singleton_method( oGenericResolver, "node_import", syck_genericresolver_node_import, 1 );
- rb_define_const( rb_syck, "GenericResolver", oGenericResolver );
-
- /*
- * Define YAML::Syck::Parser class
- */
- cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
- rb_define_attr( cParser, "options", 1, 1 );
- rb_define_attr( cParser, "resolver", 1, 1 );
- rb_define_attr( cParser, "input", 1, 1 );
- rb_define_alloc_func( cParser, syck_parser_s_alloc );
- rb_define_method(cParser, "initialize", syck_parser_initialize, -1 );
- rb_define_method(cParser, "bufsize=", syck_parser_bufsize_set, 1 );
- rb_define_method(cParser, "bufsize", syck_parser_bufsize_get, 0 );
- rb_define_method(cParser, "load", syck_parser_load, -1);
- rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1);
- rb_define_method(cParser, "set_resolver", syck_parser_set_resolver, 1);
-
- /*
- * Define YAML::Syck::Node class
- */
- cNode = rb_define_class_under( rb_syck, "Node", rb_cObject );
- rb_define_method( cNode, "initialize_copy", syck_node_init_copy, 1 );
- rb_define_attr( cNode, "emitter", 1, 1 );
- rb_define_attr( cNode, "resolver", 1, 1 );
- rb_define_attr( cNode, "kind", 1, 0 );
- rb_define_attr( cNode, "type_id", 1, 0 );
- rb_define_attr( cNode, "value", 1, 0 );
- rb_define_method( cNode, "type_id=", syck_node_type_id_set, 1 );
- rb_define_method( cNode, "transform", syck_node_transform, 0);
-
- /*
- * Define YAML::Syck::Scalar, YAML::Syck::Seq, YAML::Syck::Map --
- * all are the publicly usable variants of YAML::Syck::Node
- */
- cScalar = rb_define_class_under( rb_syck, "Scalar", cNode );
- rb_define_alloc_func( cScalar, syck_scalar_alloc );
- rb_define_attr( cNode, "value", 1, 0 );
- rb_define_method( cScalar, "initialize", syck_scalar_initialize, 3 );
- rb_define_method( cScalar, "value=", syck_scalar_value_set, 1 );
- rb_define_method( cScalar, "style=", syck_scalar_style_set, 1 );
- cSeq = rb_define_class_under( rb_syck, "Seq", cNode );
- rb_define_alloc_func( cSeq, syck_seq_alloc );
- rb_define_method( cSeq, "initialize", syck_seq_initialize, 3 );
- rb_define_method( cSeq, "value=", syck_seq_value_set, 1 );
- rb_define_method( cSeq, "add", syck_seq_add_m, 1 );
- rb_define_method( cSeq, "style=", syck_seq_style_set, 1 );
- cMap = rb_define_class_under( rb_syck, "Map", cNode );
- rb_define_alloc_func( cMap, syck_map_alloc );
- rb_define_method( cMap, "initialize", syck_map_initialize, 3 );
- rb_define_method( cMap, "value=", syck_map_value_set, 1 );
- rb_define_method( cMap, "add", syck_map_add_m, 2 );
- rb_define_method( cMap, "style=", syck_map_style_set, 1 );
-
- /*
- * Define YAML::PrivateType class
- */
- cPrivateType = rb_define_class_under( rb_yaml, "PrivateType", rb_cObject );
- rb_define_attr( cPrivateType, "type_id", 1, 1 );
- rb_define_attr( cPrivateType, "value", 1, 1 );
- rb_define_method( cPrivateType, "initialize", syck_privatetype_initialize, 2);
-
- /*
- * Define YAML::DomainType class
- */
- cDomainType = rb_define_class_under( rb_yaml, "DomainType", rb_cObject );
- rb_define_attr( cDomainType, "domain", 1, 1 );
- rb_define_attr( cDomainType, "type_id", 1, 1 );
- rb_define_attr( cDomainType, "value", 1, 1 );
- rb_define_method( cDomainType, "initialize", syck_domaintype_initialize, 3);
-
- /*
- * Define YAML::Object class
- */
- cYObject = rb_define_class_under( rb_yaml, "Object", rb_cObject );
- rb_define_attr( cYObject, "class", 1, 1 );
- rb_define_attr( cYObject, "ivars", 1, 1 );
- rb_define_method( cYObject, "initialize", syck_yobject_initialize, 2);
- rb_define_method( cYObject, "yaml_initialize", syck_yobject_initialize, 2);
-
- /*
- * Define YAML::Syck::BadAlias class
- */
- cBadAlias = rb_define_class_under( rb_syck, "BadAlias", rb_cObject );
- rb_define_attr( cBadAlias, "name", 1, 1 );
- rb_define_method( cBadAlias, "initialize", syck_badalias_initialize, 1);
- rb_define_method( cBadAlias, "<=>", syck_badalias_cmp, 1);
- rb_include_module( cBadAlias, rb_const_get( rb_cObject, rb_intern("Comparable") ) );
-
- /*
- * Define YAML::Syck::MergeKey class
- */
- cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject );
-
- /*
- * Define YAML::Syck::DefaultKey class
- */
- cDefaultKey = rb_define_class_under( rb_syck, "DefaultKey", rb_cObject );
-
- /*
- * Define YAML::Syck::Out classes
- */
- cOut = rb_define_class_under( rb_syck, "Out", rb_cObject );
- rb_define_attr( cOut, "emitter", 1, 1 );
- rb_define_method( cOut, "initialize", syck_out_initialize, 1 );
- rb_define_method( cOut, "map", syck_out_map, -1 );
- rb_define_method( cOut, "seq", syck_out_seq, -1 );
- rb_define_method( cOut, "scalar", syck_out_scalar, -1 );
-
- /*
- * Define YAML::Syck::Emitter class
- */
- cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject );
- rb_define_attr( cEmitter, "level", 1, 1 );
- rb_define_alloc_func( cEmitter, syck_emitter_s_alloc );
- rb_define_method( cEmitter, "initialize", syck_emitter_reset, -1 );
- rb_define_method( cEmitter, "reset", syck_emitter_reset, -1 );
- rb_define_method( cEmitter, "emit", syck_emitter_emit, -1 );
- rb_define_method( cEmitter, "set_resolver", syck_emitter_set_resolver, 1);
- rb_define_method( cEmitter, "node_export", syck_emitter_node_export, 1);
-}
-
or)
+ io = StringIO.new(+"test", "r")
+ -> { io.print("test") }.should.raise(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
- -> { io.print("test") }.should raise_error(IOError)
+ -> { io.print("test") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb
index 9dd1a3b410..ae7e0af729 100644
--- a/spec/ruby/library/stringio/printf_spec.rb
+++ b/spec/ruby/library/stringio/printf_spec.rb
@@ -4,17 +4,17 @@ require_relative '../../core/kernel/shared/sprintf'
describe "StringIO#printf" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new()
end
it "returns nil" do
- @io.printf("%d %04x", 123, 123).should be_nil
+ @io.printf("%d %04x", 123, 123).should == nil
end
it "pads self with \\000 when the current position is after the end" do
- @io.pos = 10
+ @io.pos = 3
@io.printf("%d", 123)
- @io.string.should == "example\000\000\000123"
+ @io.string.should == "\000\000\000123"
end
it "performs format conversion" do
@@ -24,10 +24,10 @@ describe "StringIO#printf" do
it "updates the current position" do
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(8)
+ @io.pos.should.eql?(8)
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
describe "formatting" do
@@ -39,9 +39,30 @@ describe "StringIO#printf" do
end
end
+describe "StringIO#printf when in read-write mode" do
+ before :each do
+ @io = StringIO.new(+"example", "r+")
+ end
+
+ it "starts from the beginning" do
+ @io.printf("%s", "abcdefghijk")
+ @io.string.should == "abcdefghijk"
+ end
+
+ it "does not truncate existing string" do
+ @io.printf("%s", "abc")
+ @io.string.should == "abcmple"
+ end
+
+ it "correctly updates self's position" do
+ @io.printf("%s", "abc")
+ @io.pos.should.eql?(3)
+ end
+end
+
describe "StringIO#printf when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
@@ -54,17 +75,17 @@ describe "StringIO#printf when in append mode" do
it "correctly updates self's position" do
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(15)
+ @io.pos.should.eql?(15)
end
end
describe "StringIO#printf when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
- -> { io.printf("test") }.should raise_error(IOError)
+ io = StringIO.new(+"test", "r")
+ -> { io.printf("test") }.should.raise(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
- -> { io.printf("test") }.should raise_error(IOError)
+ -> { io.printf("test") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb
index 223b3523e5..742f8623eb 100644
--- a/spec/ruby/library/stringio/putc_spec.rb
+++ b/spec/ruby/library/stringio/putc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#putc when passed [String]" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new(+'example')
end
it "overwrites the character at the current position" do
@@ -22,7 +22,7 @@ describe "StringIO#putc when passed [String]" do
it "returns the passed String" do
str = "test"
- @io.putc(str).should equal(str)
+ @io.putc(str).should.equal?(str)
end
it "correctly updates the current position" do
@@ -35,11 +35,26 @@ describe "StringIO#putc when passed [String]" do
@io.putc("t")
@io.pos.should == 3
end
+
+ it "handles concurrent writes correctly" do
+ @io = StringIO.new
+ n = 8
+ go = false
+ threads = n.times.map { |i|
+ Thread.new {
+ Thread.pass until go
+ @io.putc i.to_s
+ }
+ }
+ go = true
+ threads.each(&:join)
+ @io.string.size.should == n
+ end
end
describe "StringIO#putc when passed [Object]" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new(+'example')
end
it "it writes the passed Integer % 256 to self" do
@@ -64,13 +79,13 @@ describe "StringIO#putc when passed [Object]" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { @io.putc(Object.new) }.should raise_error(TypeError)
+ -> { @io.putc(Object.new) }.should.raise(TypeError)
end
end
describe "StringIO#putc when in append mode" do
it "appends to the end of self" do
- io = StringIO.new("test", "a")
+ io = StringIO.new(+"test", "a")
io.putc(?t)
io.string.should == "testt"
end
@@ -78,11 +93,11 @@ end
describe "StringIO#putc when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
- -> { io.putc(?a) }.should raise_error(IOError)
+ io = StringIO.new(+"test", "r")
+ -> { io.putc(?a) }.should.raise(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
- -> { io.putc("t") }.should raise_error(IOError)
+ -> { io.putc("t") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb
index a9f289a5a5..ebe74d4a45 100644
--- a/spec/ruby/library/stringio/puts_spec.rb
+++ b/spec/ruby/library/stringio/puts_spec.rb
@@ -101,6 +101,20 @@ describe "StringIO#puts when passed 1 or more objects" do
@io.puts ''
@io.string.should == "\n"
end
+
+ it "handles concurrent writes correctly" do
+ n = 8
+ go = false
+ threads = n.times.map { |i|
+ Thread.new {
+ Thread.pass until go
+ @io.puts i
+ }
+ }
+ go = true
+ threads.each(&:join)
+ @io.string.size.should == n.times.map { |i| "#{i}\n" }.join.size
+ end
end
describe "StringIO#puts when passed no arguments" do
@@ -109,7 +123,7 @@ describe "StringIO#puts when passed no arguments" do
end
it "returns nil" do
- @io.puts.should be_nil
+ @io.puts.should == nil
end
it "prints a newline" do
@@ -131,7 +145,7 @@ end
describe "StringIO#puts when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
@@ -144,24 +158,24 @@ describe "StringIO#puts when in append mode" do
it "correctly updates self's position" do
@io.puts(", testing")
- @io.pos.should eql(17)
+ @io.pos.should.eql?(17)
end
end
describe "StringIO#puts when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
- -> { io.puts }.should raise_error(IOError)
+ io = StringIO.new(+"test", "r")
+ -> { io.puts }.should.raise(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
- -> { io.puts }.should raise_error(IOError)
+ -> { io.puts }.should.raise(IOError)
end
end
describe "StringIO#puts when passed an encoded string" do
it "stores the bytes unmodified" do
- io = StringIO.new("")
+ io = StringIO.new(+"")
io.puts "\x00\x01\x02"
io.puts "æåø"
diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb
index 2a8f926bd0..38ae7541ca 100644
--- a/spec/ruby/library/stringio/read_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/read_nonblock_spec.rb
@@ -5,10 +5,21 @@ require_relative 'shared/sysread'
describe "StringIO#read_nonblock when passed length, buffer" do
it_behaves_like :stringio_read, :read_nonblock
+
+ it "accepts :exception option" do
+ io = StringIO.new("example")
+ io.read_nonblock(3, buffer = +"", exception: true)
+ buffer.should == "exa"
+ end
end
describe "StringIO#read_nonblock when passed length" do
it_behaves_like :stringio_read_length, :read_nonblock
+
+ it "accepts :exception option" do
+ io = StringIO.new("example")
+ io.read_nonblock(3, exception: true).should == "exa"
+ end
end
describe "StringIO#read_nonblock when passed nil" do
@@ -29,12 +40,12 @@ describe "StringIO#read_nonblock" do
context "when exception option is set to false" do
context "when the end is reached" do
it "returns nil" do
- stringio = StringIO.new('')
+ stringio = StringIO.new(+'')
stringio << "hello"
stringio.rewind
stringio.read_nonblock(5).should == "hello"
- stringio.read_nonblock(5, exception: false).should be_nil
+ stringio.read_nonblock(5, exception: false).should == nil
end
end
end
diff --git a/spec/ruby/library/stringio/read_spec.rb b/spec/ruby/library/stringio/read_spec.rb
index 52ab3dcf47..9a2086a682 100644
--- a/spec/ruby/library/stringio/read_spec.rb
+++ b/spec/ruby/library/stringio/read_spec.rb
@@ -39,7 +39,7 @@ describe "StringIO#read when passed [length]" do
it "returns nil when self's position is at the end" do
@io.pos = 7
- @io.read(10).should be_nil
+ @io.read(10).should == nil
end
it "returns an empty String when length is 0" do
@@ -53,10 +53,10 @@ describe "StringIO#read when passed length and a buffer" do
end
it "reads [length] characters into the buffer" do
- buf = "foo"
+ buf = +"foo"
result = @io.read(10, buf)
buf.should == "abcdefghij"
- result.should equal(buf)
+ result.should.equal?(buf)
end
end
diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb
index 94b67bc92d..3f026080e2 100644
--- a/spec/ruby/library/stringio/readline_spec.rb
+++ b/spec/ruby/library/stringio/readline_spec.rb
@@ -1,130 +1,58 @@
require_relative '../../spec_helper'
+require "stringio"
require_relative 'fixtures/classes'
+require_relative "shared/gets"
+describe "StringIO#readline" do
+ describe "when passed [separator]" do
+ it_behaves_like :stringio_gets_separator, :readline
-describe "StringIO#readline when passed [separator]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
-
- it "returns the data read till the next occurrence of the passed separator" do
- @io.readline(">").should == "this>"
- @io.readline(">").should == "is>"
- @io.readline(">").should == "an>"
- @io.readline(">").should == "example"
- end
-
- it "sets $_ to the read content" do
- @io.readline(">")
- $_.should == "this>"
- @io.readline(">")
- $_.should == "is>"
- @io.readline(">")
- $_.should == "an>"
- @io.readline(">")
- $_.should == "example"
- end
-
- it "updates self's lineno by one" do
- @io.readline(">")
- @io.lineno.should eql(1)
-
- @io.readline(">")
- @io.lineno.should eql(2)
-
- @io.readline(">")
- @io.lineno.should eql(3)
- end
-
- it "returns the next paragraph when the passed separator is an empty String" do
- io = StringIO.new("this is\n\nan example")
- io.readline("").should == "this is\n\n"
- io.readline("").should == "an example"
- end
-
- it "returns the remaining content starting at the current position when passed nil" do
- io = StringIO.new("this is\n\nan example")
- io.pos = 5
- io.readline(nil).should == "is\n\nan example"
- end
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- it "tries to convert the passed separator to a String using #to_str" do
- obj = mock('to_str')
- obj.should_receive(:to_str).and_return(">")
- @io.readline(obj).should == "this>"
+ @io.pos = 36
+ -> { @io.readline(">") }.should.raise(IOError)
+ end
end
-end
-describe "StringIO#readline when passed no argument" do
- before :each do
- @io = StringIO.new("this is\nan example\nfor StringIO#readline")
- end
+ describe "when passed [limit]" do
+ it_behaves_like :stringio_gets_limit, :readline
- it "returns the data read till the next occurrence of $/ or till eof" do
- @io.readline.should == "this is\n"
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- begin
- old_sep = $/
- suppress_warning {$/ = " "}
- @io.readline.should == "an "
- @io.readline.should == "example\nfor "
- @io.readline.should == "StringIO#readline"
- ensure
- suppress_warning {$/ = old_sep}
+ @io.pos = 36
+ -> { @io.readline(3) }.should.raise(IOError)
end
end
- it "sets $_ to the read content" do
- @io.readline
- $_.should == "this is\n"
- @io.readline
- $_.should == "an example\n"
- @io.readline
- $_.should == "for StringIO#readline"
- end
-
- it "updates self's position" do
- @io.readline
- @io.pos.should eql(8)
+ describe "when passed [separator] and [limit]" do
+ it_behaves_like :stringio_gets_separator_and_limit, :readline
- @io.readline
- @io.pos.should eql(19)
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- @io.readline
- @io.pos.should eql(40)
+ @io.pos = 36
+ -> { @io.readline(">", 3) }.should.raise(IOError)
+ end
end
- it "updates self's lineno" do
- @io.readline
- @io.lineno.should eql(1)
+ describe "when passed no argument" do
+ it_behaves_like :stringio_gets_no_argument, :readline
- @io.readline
- @io.lineno.should eql(2)
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- @io.readline
- @io.lineno.should eql(3)
- end
-
- it "raises an IOError if self is at the end" do
- @io.pos = 40
- -> { @io.readline }.should raise_error(IOError)
+ @io.pos = 36
+ -> { @io.readline }.should.raise(IOError)
+ end
end
-end
-
-describe "StringIO#readline when in write-only mode" do
- it "raises an IOError" do
- io = StringIO.new("xyz", "w")
- -> { io.readline }.should raise_error(IOError)
- io = StringIO.new("xyz")
- io.close_read
- -> { io.readline }.should raise_error(IOError)
+ describe "when passed [chomp]" do
+ it_behaves_like :stringio_gets_chomp, :readline
end
-end
-describe "StringIO#readline when passed [chomp]" do
- it "returns the data read without a trailing newline character" do
- io = StringIO.new("this>is>an>example\n")
- io.readline(chomp: true).should == "this>is>an>example"
+ describe "when in write-only mode" do
+ it_behaves_like :stringio_gets_write_only, :readline
end
end
diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb
index 4b007787e2..821a8169e7 100644
--- a/spec/ruby/library/stringio/readlines_spec.rb
+++ b/spec/ruby/library/stringio/readlines_spec.rb
@@ -12,12 +12,12 @@ describe "StringIO#readlines when passed [separator]" do
it "updates self's position based on the number of read bytes" do
@io.readlines(">")
- @io.pos.should eql(18)
+ @io.pos.should.eql?(18)
end
it "updates self's lineno based on the number of read lines" do
@io.readlines(">")
- @io.lineno.should eql(4)
+ @io.lineno.should.eql?(4)
end
it "does not change $_" do
@@ -61,12 +61,12 @@ describe "StringIO#readlines when passed no argument" do
it "updates self's position based on the number of read bytes" do
@io.readlines
- @io.pos.should eql(41)
+ @io.pos.should.eql?(41)
end
it "updates self's lineno based on the number of read lines" do
@io.readlines
- @io.lineno.should eql(3)
+ @io.lineno.should.eql?(3)
end
it "does not change $_" do
@@ -83,12 +83,12 @@ end
describe "StringIO#readlines when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
- -> { io.readlines }.should raise_error(IOError)
+ io = StringIO.new(+"xyz", "w")
+ -> { io.readlines }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.readlines }.should raise_error(IOError)
+ -> { io.readlines }.should.raise(IOError)
end
end
@@ -98,3 +98,21 @@ describe "StringIO#readlines when passed [chomp]" do
io.readlines(chomp: true).should == ["this>is", "an>example"]
end
end
+
+describe "StringIO#readlines when passed [limit]" do
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "returns the data read until the limit is met" do
+ @io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
+ end
+
+ it "raises ArgumentError when limit is 0" do
+ -> { @io.readlines(0) }.should.raise(ArgumentError)
+ end
+
+ it "ignores it when the limit is negative" do
+ @io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"]
+ end
+end
diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb
index 2601fe8c42..e05d9bded4 100644
--- a/spec/ruby/library/stringio/readpartial_spec.rb
+++ b/spec/ruby/library/stringio/readpartial_spec.rb
@@ -3,20 +3,14 @@ require_relative 'fixtures/classes'
describe "StringIO#readpartial" do
before :each do
- @string = StringIO.new('Stop, look, listen')
+ @string = StringIO.new(+'Stop, look, listen')
end
after :each do
@string.close unless @string.closed?
end
- it "raises IOError on closed stream" do
- @string.close
- -> { @string.readpartial(10) }.should raise_error(IOError)
- end
-
it "reads at most the specified number of bytes" do
-
# buffered read
@string.read(1).should == 'S'
# return only specified number, not the whole buffer
@@ -30,6 +24,14 @@ describe "StringIO#readpartial" do
@string.readpartial(3).should == ", l"
end
+ it "reads after ungetc with multibyte characters in the buffer" do
+ @string = StringIO.new(+"∂φ/∂x = gaîté")
+ c = @string.getc
+ @string.ungetc(c)
+ @string.readpartial(3).should == "\xE2\x88\x82".b
+ @string.readpartial(3).should == "\xCF\x86/".b
+ end
+
it "reads after ungetc without data in the buffer" do
@string = StringIO.new
@string.write("f").should == 1
@@ -48,33 +50,53 @@ describe "StringIO#readpartial" do
end
it "discards the existing buffer content upon successful read" do
- buffer = "existing"
+ buffer = +"existing"
@string.readpartial(11, buffer)
buffer.should == "Stop, look,"
end
it "raises EOFError on EOF" do
@string.readpartial(18).should == 'Stop, look, listen'
- -> { @string.readpartial(10) }.should raise_error(EOFError)
+ -> { @string.readpartial(10) }.should.raise(EOFError)
end
it "discards the existing buffer content upon error" do
- buffer = 'hello'
+ buffer = +'hello'
@string.readpartial(100)
- -> { @string.readpartial(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @string.readpartial(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError if the stream is closed" do
@string.close
- -> { @string.readpartial(1) }.should raise_error(IOError)
+ -> { @string.readpartial(1) }.should.raise(IOError, "not opened for reading")
end
it "raises ArgumentError if the negative argument is provided" do
- -> { @string.readpartial(-1) }.should raise_error(ArgumentError)
+ -> { @string.readpartial(-1) }.should.raise(ArgumentError, "negative length -1 given")
end
it "immediately returns an empty string if the length argument is 0" do
@string.readpartial(0).should == ""
end
+
+ it "raises IOError if the stream is closed and the length argument is 0" do
+ @string.close
+ -> { @string.readpartial(0) }.should.raise(IOError, "not opened for reading")
+ end
+
+ it "clears and returns the given buffer if the length argument is 0" do
+ buffer = +"existing content"
+ @string.readpartial(0, buffer).should == buffer
+ buffer.should == ""
+ end
+
+ version_is StringIO::VERSION, "3.1.2" do # ruby_version_is "3.4"
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @string.readpartial(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+ end
end
diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb
index 6752cf9970..3d4ae3a698 100644
--- a/spec/ruby/library/stringio/reopen_spec.rb
+++ b/spec/ruby/library/stringio/reopen_spec.rb
@@ -8,50 +8,39 @@ describe "StringIO#reopen when passed [Object, Integer]" do
it "reopens self with the passed Object in the passed mode" do
@io.reopen("reopened", IO::RDONLY)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
- @io.reopen("reopened, twice", IO::WRONLY)
- @io.closed_read?.should be_true
- @io.closed_write?.should be_false
+ @io.reopen(+"reopened, twice", IO::WRONLY)
+ @io.closed_read?.should == true
+ @io.closed_write?.should == false
@io.string.should == "reopened, twice"
- @io.reopen("reopened, another time", IO::RDWR)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.reopen(+"reopened, another time", IO::RDWR)
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, another time"
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint, IO::RDONLY)
- @io.tainted?.should be_false
-
- @io.reopen("reopened".taint, IO::WRONLY)
- @io.tainted?.should be_false
- end
- end
-
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
- obj.should_receive(:to_str).and_return("to_str")
+ obj.should_receive(:to_str).and_return(+"to_str")
@io.reopen(obj, IO::RDWR)
@io.string.should == "to_str"
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { @io.reopen(Object.new, IO::RDWR) }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new, IO::RDWR) }.should.raise(TypeError)
end
it "raises an Errno::EACCES when trying to reopen self with a frozen String in write-mode" do
- -> { @io.reopen("burn".freeze, IO::WRONLY) }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should raise_error(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, IO::WRONLY) }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should.raise(Errno::EACCES)
end
it "raises a FrozenError when trying to reopen self with a frozen String in truncate-mode" do
- -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should raise_error(FrozenError)
+ -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should.raise(FrozenError)
end
it "does not raise IOError when passed a frozen String in read-mode" do
@@ -67,42 +56,31 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "reopens self with the passed Object in the passed mode" do
@io.reopen("reopened", "r")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
- @io.reopen("reopened, twice", "r+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.reopen(+"reopened, twice", "r+")
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, twice"
- @io.reopen("reopened, another", "w+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.reopen(+"reopened, another", "w+")
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == ""
- @io.reopen("reopened, another time", "r+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.reopen(+"reopened, another time", "r+")
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, another time"
end
it "truncates the passed String when opened in truncate mode" do
- @io.reopen(str = "reopened", "w")
+ @io.reopen(str = +"reopened", "w")
str.should == ""
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint, "r")
- @io.tainted?.should be_false
-
- @io.reopen("reopened".taint, "w")
- @io.tainted?.should be_false
- end
- end
-
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("to_str")
@@ -111,35 +89,35 @@ describe "StringIO#reopen when passed [Object, Object]" do
end
it "raises a TypeError when the passed Object can't be converted to a String using #to_str" do
- -> { @io.reopen(Object.new, "r") }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new, "r") }.should.raise(TypeError)
end
it "resets self's position to 0" do
@io.read(5)
- @io.reopen("reopened")
- @io.pos.should eql(0)
+ @io.reopen(+"reopened")
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen("reopened")
- @io.lineno.should eql(0)
+ @io.reopen(+"reopened")
+ @io.lineno.should.eql?(0)
end
it "tries to convert the passed mode Object to an Integer using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("r")
@io.reopen("reopened", obj)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
end
it "raises an Errno::EACCES error when trying to reopen self with a frozen String in write-mode" do
- -> { @io.reopen("burn".freeze, 'w') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, 'w+') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, 'a') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, "r+") }.should raise_error(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'w') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'w+') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'a') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, "r+") }.should.raise(Errno::EACCES)
end
it "does not raise IOError if a frozen string is passed in read mode" do
@@ -156,32 +134,24 @@ describe "StringIO#reopen when passed [String]" do
it "reopens self with the passed String in read-write mode" do
@io.close
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
- @io.closed_write?.should be_false
- @io.closed_read?.should be_false
+ @io.closed_write?.should == false
+ @io.closed_read?.should == false
@io.string.should == "reopened"
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint)
- @io.tainted?.should be_false
- end
- end
-
it "resets self's position to 0" do
@io.read(5)
- @io.reopen("reopened")
- @io.pos.should eql(0)
+ @io.reopen(+"reopened")
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen("reopened")
- @io.lineno.should eql(0)
+ @io.reopen(+"reopened")
+ @io.lineno.should.eql?(0)
end
end
@@ -191,29 +161,21 @@ describe "StringIO#reopen when passed [Object]" do
end
it "raises a TypeError when passed an Object that can't be converted to a StringIO" do
- -> { @io.reopen(Object.new) }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new) }.should.raise(TypeError)
end
it "does not try to convert the passed Object to a String using #to_str" do
obj = mock("not to_str")
obj.should_not_receive(:to_str)
- -> { @io.reopen(obj) }.should raise_error(TypeError)
+ -> { @io.reopen(obj) }.should.raise(TypeError)
end
it "tries to convert the passed Object to a StringIO using #to_strio" do
obj = mock("to_strio")
- obj.should_receive(:to_strio).and_return(StringIO.new("to_strio"))
+ obj.should_receive(:to_strio).and_return(StringIO.new(+"to_strio"))
@io.reopen(obj)
@io.string.should == "to_strio"
end
-
- # NOTE: WEIRD!
- ruby_version_is ""..."2.7" do
- it "taints self when the passed Object was tainted" do
- @io.reopen(StringIO.new("reopened").taint)
- @io.tainted?.should be_true
- end
- end
end
describe "StringIO#reopen when passed no arguments" do
@@ -224,20 +186,20 @@ describe "StringIO#reopen when passed no arguments" do
it "resets self's mode to read-write" do
@io.close
@io.reopen
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
end
it "resets self's position to 0" do
@io.read(5)
@io.reopen
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
@io.reopen
- @io.lineno.should eql(0)
+ @io.lineno.should.eql?(0)
end
end
@@ -246,49 +208,40 @@ end
# for details.
describe "StringIO#reopen" do
before :each do
- @io = StringIO.new('hello','a')
+ @io = StringIO.new(+'hello', 'a')
end
# TODO: find out if this is really a bug
it "reopens a stream when given a String argument" do
- @io.reopen('goodbye').should == @io
+ @io.reopen(+'goodbye').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'xoodbye'
end
it "reopens a stream in append mode when flagged as such" do
- @io.reopen('goodbye', 'a').should == @io
+ @io.reopen(+'goodbye', 'a').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'goodbyex'
end
it "reopens and truncate when reopened in write mode" do
- @io.reopen('goodbye', 'wb').should == @io
+ @io.reopen(+'goodbye', 'wb').should == @io
@io.string.should == ''
@io << 'x'
@io.string.should == 'x'
end
it "truncates the given string, not a copy" do
- str = 'goodbye'
+ str = +'goodbye'
@io.reopen(str, 'w')
@io.string.should == ''
str.should == ''
end
- ruby_version_is ""..."2.7" do
- it "taints self if the provided StringIO argument is tainted" do
- new_io = StringIO.new("tainted")
- new_io.taint
- @io.reopen(new_io)
- @io.should.tainted?
- end
- end
-
it "does not truncate the content even when the StringIO argument is in the truncate mode" do
- orig_io = StringIO.new("Original StringIO", IO::RDWR|IO::TRUNC)
+ orig_io = StringIO.new(+"Original StringIO", IO::RDWR|IO::TRUNC)
orig_io.write("BLAH") # make sure the content is not empty
@io.reopen(orig_io)
diff --git a/spec/ruby/library/stringio/rewind_spec.rb b/spec/ruby/library/stringio/rewind_spec.rb
index 5f885ecf81..8c48709d89 100644
--- a/spec/ruby/library/stringio/rewind_spec.rb
+++ b/spec/ruby/library/stringio/rewind_spec.rb
@@ -9,7 +9,7 @@ describe "StringIO#rewind" do
end
it "returns 0" do
- @io.rewind.should eql(0)
+ @io.rewind.should.eql?(0)
end
it "resets the position" do
diff --git a/spec/ruby/library/stringio/seek_spec.rb b/spec/ruby/library/stringio/seek_spec.rb
index 253b5027a9..9043e0338f 100644
--- a/spec/ruby/library/stringio/seek_spec.rb
+++ b/spec/ruby/library/stringio/seek_spec.rb
@@ -9,18 +9,18 @@ describe "StringIO#seek" do
it "seeks from the current position when whence is IO::SEEK_CUR" do
@io.pos = 1
@io.seek(1, IO::SEEK_CUR)
- @io.pos.should eql(2)
+ @io.pos.should.eql?(2)
@io.seek(-1, IO::SEEK_CUR)
- @io.pos.should eql(1)
+ @io.pos.should.eql?(1)
end
it "seeks from the end of self when whence is IO::SEEK_END" do
@io.seek(3, IO::SEEK_END)
- @io.pos.should eql(11) # Outside of the StringIO's content
+ @io.pos.should.eql?(11) # Outside of the StringIO's content
@io.seek(-2, IO::SEEK_END)
- @io.pos.should eql(6)
+ @io.pos.should.eql?(6)
end
it "seeks to an absolute position when whence is IO::SEEK_SET" do
@@ -33,25 +33,25 @@ describe "StringIO#seek" do
end
it "raises an Errno::EINVAL error on negative amounts when whence is IO::SEEK_SET" do
- -> { @io.seek(-5, IO::SEEK_SET) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(-5, IO::SEEK_SET) }.should.raise(Errno::EINVAL)
end
it "raises an Errno::EINVAL error on incorrect whence argument" do
- -> { @io.seek(0, 3) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, -1) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, 2**16) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, -2**16) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(0, 3) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, -1) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, 2**16) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, -2**16) }.should.raise(Errno::EINVAL)
end
it "tries to convert the passed Object to a String using #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(2)
@io.seek(obj)
- @io.pos.should eql(2)
+ @io.pos.should.eql?(2)
end
it "raises a TypeError when the passed Object can't be converted to an Integer" do
- -> { @io.seek(Object.new) }.should raise_error(TypeError)
+ -> { @io.seek(Object.new) }.should.raise(TypeError)
end
end
@@ -62,6 +62,6 @@ describe "StringIO#seek when self is closed" do
end
it "raises an IOError" do
- -> { @io.seek(5) }.should raise_error(IOError)
+ -> { @io.seek(5) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb
new file mode 100644
index 0000000000..b4583a7ad7
--- /dev/null
+++ b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb
@@ -0,0 +1,237 @@
+require 'stringio'
+require_relative '../../spec_helper'
+
+# Should be synced with specs for IO#set_encoding_by_bom
+describe "StringIO#set_encoding_by_bom" do
+ it "returns nil if not readable" do
+ io = StringIO.new("".b, "wb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "returns the result encoding if found BOM UTF-8 sequence" do
+ io = StringIO.new("\u{FEFF}".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_8
+ io.external_encoding.should == Encoding::UTF_8
+ io.read.b.should == "".b
+
+ io = StringIO.new("\u{FEFF}abc".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_8
+ io.external_encoding.should == Encoding::UTF_8
+ io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_16LE sequence" do
+ io = StringIO.new("\xFF\xFE".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ io.external_encoding.should == Encoding::UTF_16LE
+ io.read.b.should == "".b
+
+ io = StringIO.new("\xFF\xFEabc".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ io.external_encoding.should == Encoding::UTF_16LE
+ io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_16BE sequence" do
+ io = StringIO.new("\xFE\xFF".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16BE
+ io.external_encoding.should == Encoding::UTF_16BE
+ io.read.b.should == "".b
+
+ io = StringIO.new("\xFE\xFFabc".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16BE
+ io.external_encoding.should == Encoding::UTF_16BE
+ io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_32LE sequence" do
+ io = StringIO.new("\xFF\xFE\x00\x00".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_32LE
+ io.external_encoding.should == Encoding::UTF_32LE
+ io.read.b.should == "".b
+
+ io = StringIO.new("\xFF\xFE\x00\x00abc".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_32LE
+ io.external_encoding.should == Encoding::UTF_32LE
+ io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_32BE sequence" do
+ io = StringIO.new("\x00\x00\xFE\xFF".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_32BE
+ io.external_encoding.should == Encoding::UTF_32BE
+ io.read.b.should == "".b
+
+ io = StringIO.new("\x00\x00\xFE\xFFabc".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_32BE
+ io.external_encoding.should == Encoding::UTF_32BE
+ io.read.b.should == "abc".b
+ end
+
+ it "returns nil if io is empty" do
+ io = StringIO.new("".b, "rb")
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "returns nil if UTF-8 BOM sequence is incomplete" do
+ io = StringIO.new("\xEF".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xEF".b
+
+ io = StringIO.new("\xEFa".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xEFa".b
+
+ io = StringIO.new("\xEF\xBB".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xEF\xBB".b
+
+ io = StringIO.new("\xEF\xBBa".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xEF\xBBa".b
+ end
+
+ it "returns nil if UTF-16BE BOM sequence is incomplete" do
+ io = StringIO.new("\xFE".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xFE".b
+
+ io = StringIO.new("\xFEa".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xFEa".b
+ end
+
+ it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do
+ io = StringIO.new("\xFF".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xFF".b
+
+ io = StringIO.new("\xFFa".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\xFFa".b
+ end
+
+ it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do
+ io = StringIO.new("\xFF\xFE".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ io.external_encoding.should == Encoding::UTF_16LE
+ io.read.b.should == "".b
+
+ io = StringIO.new("\xFF\xFE\x00".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ io.external_encoding.should == Encoding::UTF_16LE
+ io.read.b.should == "\x00".b
+
+ io = StringIO.new("\xFF\xFE\x00a".b, "rb")
+
+ io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ io.external_encoding.should == Encoding::UTF_16LE
+ io.read.b.should == "\x00a".b
+ end
+
+ it "returns nil if UTF-32BE BOM sequence is incomplete" do
+ io = StringIO.new("\x00".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00".b
+
+ io = StringIO.new("\x00a".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00a".b
+
+ io = StringIO.new("\x00\x00".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00\x00".b
+
+ io = StringIO.new("\x00\x00a".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00\x00a".b
+
+ io = StringIO.new("\x00\x00\xFE".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00\x00\xFE".b
+
+ io = StringIO.new("\x00\x00\xFEa".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read.b.should == "\x00\x00\xFEa".b
+ end
+
+ it "returns nil if found BOM sequence not provided" do
+ io = StringIO.new("abc".b, "rb")
+
+ io.set_encoding_by_bom.should == nil
+ io.external_encoding.should == Encoding::ASCII_8BIT
+ io.read(3).should == "abc".b
+ end
+
+ it "does not raise exception if io not in binary mode" do
+ io = StringIO.new("", 'r')
+ io.set_encoding_by_bom.should == nil
+ end
+
+ it "does not raise exception if encoding already set" do
+ io = StringIO.new("".b, "rb")
+ io.set_encoding("utf-8")
+ io.set_encoding_by_bom.should == nil
+ end
+
+ it "does not raise exception if encoding conversion is already set" do
+ io = StringIO.new("".b, "rb")
+ io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE)
+
+ io.set_encoding_by_bom.should == nil
+ end
+
+ it "raises FrozenError when io is frozen" do
+ io = StringIO.new()
+ io.freeze
+ -> { io.set_encoding_by_bom }.should.raise(FrozenError)
+ end
+
+ it "does not raise FrozenError when initial string is frozen" do
+ io = StringIO.new("".freeze)
+ io.set_encoding_by_bom.should == nil
+ end
+end
diff --git a/spec/ruby/library/stringio/set_encoding_spec.rb b/spec/ruby/library/stringio/set_encoding_spec.rb
index 21d45750f3..19ca0875bf 100644
--- a/spec/ruby/library/stringio/set_encoding_spec.rb
+++ b/spec/ruby/library/stringio/set_encoding_spec.rb
@@ -17,4 +17,12 @@ describe "StringIO#set_encoding" do
io.set_encoding Encoding::UTF_8
io.string.encoding.should == Encoding::US_ASCII
end
+
+ it "accepts a String" do
+ str = "".encode(Encoding::US_ASCII)
+ io = StringIO.new(str)
+ io.set_encoding("ASCII-8BIT")
+ io.external_encoding.should == Encoding::BINARY
+ str.encoding.should == Encoding::BINARY
+ end
end
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb
index 9d84aa4919..e35a02ccb4 100644
--- a/spec/ruby/library/stringio/shared/codepoints.rb
+++ b/spec/ruby/library/stringio/shared/codepoints.rb
@@ -6,7 +6,7 @@ describe :stringio_codepoints, shared: true do
end
it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
+ @enum.should.instance_of?(Enumerator)
end
it "yields each codepoint code in turn" do
@@ -20,15 +20,15 @@ describe :stringio_codepoints, shared: true do
it "raises an error if reading invalid sequence" do
@io.pos = 1 # inside of a multibyte sequence
- -> { @enum.first }.should raise_error(ArgumentError)
+ -> { @enum.first }.should.raise(ArgumentError)
end
it "raises an IOError if not readable" do
@io.close_read
- -> { @enum.to_a }.should raise_error(IOError)
+ -> { @enum.to_a }.should.raise(IOError)
- io = StringIO.new("xyz", "w")
- -> { io.send(@method).to_a }.should raise_error(IOError)
+ io = StringIO.new(+"xyz", "w")
+ -> { io.send(@method).to_a }.should.raise(IOError)
end
@@ -39,7 +39,7 @@ describe :stringio_codepoints, shared: true do
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
end
diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb
index 14b0a013b3..04e40b6b2a 100644
--- a/spec/ruby/library/stringio/shared/each.rb
+++ b/spec/ruby/library/stringio/shared/each.rb
@@ -16,7 +16,7 @@ describe :stringio_each_separator, shared: true do
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
it "tries to convert the passed separator to a String using #to_str" do
@@ -36,11 +36,11 @@ describe :stringio_each_separator, shared: true do
seen.should == ["2 1 2 1 2"]
end
- it "yields each paragraph when passed an empty String as separator" do
+ it "yields each paragraph with all separation characters when passed an empty String as separator" do
seen = []
io = StringIO.new("para1\n\npara2\n\n\npara3")
io.send(@method, "") {|s| seen << s}
- seen.should == ["para1\n\n", "para2\n\n", "para3"]
+ seen.should == ["para1\n\n", "para2\n\n\n", "para3"]
end
end
@@ -74,19 +74,19 @@ describe :stringio_each_no_arguments, shared: true do
old_rs = $/
suppress_warning {$/ = " "}
@io.send(@method) {|s| seen << s }
- seen.should eql(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"])
+ seen.should.eql?(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"])
ensure
suppress_warning {$/ = old_rs}
end
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |b| seen << b }
@@ -96,12 +96,12 @@ end
describe :stringio_each_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("a b c d e", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ io = StringIO.new(+"a b c d e", "w")
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("a b c d e")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
@@ -112,4 +112,98 @@ describe :stringio_each_chomp, shared: true do
io.send(@method, chomp: true) {|s| seen << s }
seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
end
+
+ it "returns each line with removed newline characters when called without block" do
+ seen = []
+ io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end")
+ enum = io.send(@method, chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
+ end
+end
+
+describe :stringio_each_separator_and_chomp, shared: true do
+ it "yields each line with removed separator to the passed block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ io.send(@method, "|", chomp: true) {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
+
+ it "returns each line with removed separator when called without block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ enum = io.send(@method, "|", chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
+end
+
+describe :stringio_each_limit, shared: true do
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "returns the data read until the limit is met" do
+ seen = []
+ @io.send(@method, 4) { |s| seen << s }
+ seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
+ end
+end
+
+describe :stringio_each_separator_and_limit, shared: true do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is consumed or the separator is met" do
+ @io.send(@method, '>', 8) { |s| break s }.should == "this>"
+ @io.send(@method, '>', 2) { |s| break s }.should == "is"
+ @io.send(@method, '>', 10) { |s| break s }.should == ">"
+ @io.send(@method, '>', 6) { |s| break s }.should == "an>"
+ @io.send(@method, '>', 5) { |s| break s }.should == "examp"
+ end
+
+ it "truncates the multi-character separator at the end to meet the limit" do
+ @io.send(@method, "is>an", 7) { |s| break s }.should == "this>is"
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.send(@method, '>', 8) { |s| s }
+ $_.should == "test"
+ end
+
+ it "updates self's lineno by one" do
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(3)
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do # TODO
+ obj = mock('to_str')
+ obj.should_receive(:to_str).and_return('>')
+
+ seen = []
+ @io.send(@method, obj, 5) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
+
+ it "does not raise TypeError if passed separator is nil" do
+ @io.send(@method, nil, 5) { |s| break s }.should == "this>"
+ end
+
+ it "tries to convert the passed limit to an Integer using #to_int" do # TODO
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(5)
+
+ seen = []
+ @io.send(@method, '>', obj) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
end
diff --git a/spec/ruby/library/stringio/shared/each_byte.rb b/spec/ruby/library/stringio/shared/each_byte.rb
index 56734ff99d..b3939c26de 100644
--- a/spec/ruby/library/stringio/shared/each_byte.rb
+++ b/spec/ruby/library/stringio/shared/each_byte.rb
@@ -19,16 +19,16 @@ describe :stringio_each_byte, shared: true do
@io.pos = 1000
seen = nil
@io.send(@method) { |b| seen = b }
- seen.should be_nil
+ seen.should == nil
end
it "returns self" do
- @io.send(@method) {}.should equal(@io)
+ @io.send(@method) {}.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |b| seen << b }
@@ -38,11 +38,11 @@ end
describe :stringio_each_byte_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ io = StringIO.new(+"xyz", "w")
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb
index bcdac53282..4215a9952b 100644
--- a/spec/ruby/library/stringio/shared/each_char.rb
+++ b/spec/ruby/library/stringio/shared/each_char.rb
@@ -11,12 +11,12 @@ describe :stringio_each_char, shared: true do
end
it "returns self" do
- @io.send(@method) {}.should equal(@io)
+ @io.send(@method) {}.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |c| seen << c }
@@ -26,11 +26,11 @@ end
describe :stringio_each_char_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ io = StringIO.new(+"xyz", "w")
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/eof.rb b/spec/ruby/library/stringio/shared/eof.rb
index e0368a2892..a9489581fc 100644
--- a/spec/ruby/library/stringio/shared/eof.rb
+++ b/spec/ruby/library/stringio/shared/eof.rb
@@ -5,20 +5,20 @@ describe :stringio_eof, shared: true do
it "returns true when self's position is greater than or equal to self's size" do
@io.pos = 3
- @io.send(@method).should be_true
+ @io.send(@method).should == true
@io.pos = 6
- @io.send(@method).should be_true
+ @io.send(@method).should == true
end
it "returns false when self's position is less than self's size" do
@io.pos = 0
- @io.send(@method).should be_false
+ @io.send(@method).should == false
@io.pos = 1
- @io.send(@method).should be_false
+ @io.send(@method).should == false
@io.pos = 2
- @io.send(@method).should be_false
+ @io.send(@method).should == false
end
end
diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb