mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/syck/emitter.c: new emitter code.
* ext/syck/rubyext.c: Emitter class. * lib/yaml.rb: Load Syck emitter, if available. * lib/yaml/stream.rb: ditto. * lib/yaml/baseemitter.rb: underlying class for all emitters. * lib/yaml/rubytypes.rb: use BaseEmitter abstraction. * lib/yaml/emitter.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4066 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
30399f6c75
commit
a1e257ec48
9 changed files with 359 additions and 271 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
Sat Jul 12 04:43:57 2003 why the lucky stiff <ruby-cvs@whytheluckystiff.net>
|
||||
|
||||
* ext/syck/emitter.c: new emitter code.
|
||||
|
||||
* ext/syck/rubyext.c: Emitter class.
|
||||
|
||||
* lib/yaml.rb: Load Syck emitter, if available.
|
||||
|
||||
* lib/yaml/stream.rb: ditto.
|
||||
|
||||
* lib/yaml/baseemitter.rb: underlying class for all emitters.
|
||||
|
||||
* lib/yaml/rubytypes.rb: use BaseEmitter abstraction.
|
||||
|
||||
* lib/yaml/emitter.rb: ditto.
|
||||
|
||||
Sat Jul 12 01:21:54 2003 Nobuyoshi Nakada <nobu.nokada@softhome.net>
|
||||
|
||||
* eval.c (avalue_to_svalue): typo.
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct RVALUE {
|
|||
static ID s_new, s_utc, s_at, s_to_f, s_read, s_binmode, s_call, s_transfer, s_update, s_dup, s_match;
|
||||
static VALUE sym_model, sym_generic;
|
||||
static VALUE sym_scalar, sym_seq, sym_map;
|
||||
VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, cMergeKey;
|
||||
VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, cMergeKey, cEmitter;
|
||||
VALUE oDefaultLoader;
|
||||
|
||||
/*
|
||||
|
@ -57,6 +57,7 @@ SYMID rb_syck_parse_handler _((SyckParser *, SyckNode *));
|
|||
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));
|
||||
|
||||
struct parser_xtra {
|
||||
VALUE data; /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */
|
||||
|
@ -1015,6 +1016,162 @@ syck_node_transform( self )
|
|||
return rb_funcall( oDefaultLoader, s_transfer, 2, type_id, t );
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle output from the emitter
|
||||
*/
|
||||
void
|
||||
rb_syck_output_handler( emitter, str, len )
|
||||
SyckEmitter *emitter;
|
||||
char *str;
|
||||
long len;
|
||||
{
|
||||
rb_str_cat( (VALUE)emitter->bonus, str, len );
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark emitter values.
|
||||
*/
|
||||
static void
|
||||
syck_mark_emitter(emitter)
|
||||
SyckEmitter *emitter;
|
||||
{
|
||||
rb_gc_mark(emitter->ignore_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.new
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_new(argc, argv, class)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
VALUE class;
|
||||
{
|
||||
VALUE pobj, options, init_argv[1];
|
||||
SyckEmitter *emitter = syck_new_emitter();
|
||||
syck_emitter_ignore_id( emitter, Qnil );
|
||||
syck_emitter_handler( emitter, rb_syck_output_handler );
|
||||
|
||||
emitter->bonus = (void *)rb_str_new2( "" );
|
||||
|
||||
rb_scan_args(argc, argv, "01", &options);
|
||||
pobj = Data_Wrap_Struct( class, syck_mark_emitter, syck_free_emitter, emitter );
|
||||
|
||||
if ( ! rb_obj_is_instance_of( options, rb_cHash ) )
|
||||
{
|
||||
options = rb_hash_new();
|
||||
}
|
||||
init_argv[0] = options;
|
||||
rb_obj_call_init(pobj, 1, init_argv);
|
||||
return pobj;
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.initialize( options )
|
||||
*/
|
||||
static VALUE
|
||||
syck_emitter_initialize( self, options )
|
||||
VALUE self, options;
|
||||
{
|
||||
rb_iv_set(self, "@options", options);
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.level
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_level_m( self )
|
||||
VALUE self;
|
||||
{
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
return LONG2NUM( emitter->level );
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.flush
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_flush_m( self )
|
||||
VALUE self;
|
||||
{
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
syck_emitter_flush( emitter );
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.write( str )
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_write_m( self, str )
|
||||
VALUE str;
|
||||
{
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
syck_emitter_write( emitter, RSTRING(str)->ptr, RSTRING(str)->len );
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.simple( str )
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_simple_write( self, str )
|
||||
VALUE str;
|
||||
{
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
syck_emitter_simple( emitter, RSTRING(str)->ptr, RSTRING(str)->len );
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.start_object( object_id )
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_start_object( self, oid )
|
||||
VALUE self, oid;
|
||||
{
|
||||
char *anchor_name;
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
anchor_name = syck_emitter_start_obj( emitter, oid );
|
||||
|
||||
if ( anchor_name == NULL )
|
||||
{
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
return rb_str_new2( anchor_name );
|
||||
}
|
||||
|
||||
/*
|
||||
* YAML::Syck::Emitter.end_object( object_id )
|
||||
*/
|
||||
VALUE
|
||||
syck_emitter_end_object( self, oid )
|
||||
VALUE self, oid;
|
||||
{
|
||||
SyckEmitter *emitter;
|
||||
|
||||
Data_Get_Struct(self, SyckEmitter, emitter);
|
||||
syck_emitter_end_obj( emitter );
|
||||
|
||||
if ( emitter->level < 0 )
|
||||
{
|
||||
syck_emitter_flush( emitter );
|
||||
}
|
||||
return (VALUE)emitter->bonus;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize Syck extension
|
||||
*/
|
||||
|
@ -1118,5 +1275,19 @@ Init_syck()
|
|||
* Define YAML::Syck::MergeKey class
|
||||
*/
|
||||
cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject );
|
||||
|
||||
/*
|
||||
* Define YAML::Syck::Emitter class
|
||||
*/
|
||||
cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject );
|
||||
rb_define_singleton_method( cEmitter, "new", syck_emitter_new, -1 );
|
||||
rb_define_method( cEmitter, "initialize", syck_emitter_initialize, 1 );
|
||||
rb_define_method( cEmitter, "level", syck_emitter_level_m, 0 );
|
||||
rb_define_method( cEmitter, "write", syck_emitter_write_m, 1 );
|
||||
rb_define_method( cEmitter, "<<", syck_emitter_write_m, 1 );
|
||||
rb_define_method( cEmitter, "simple", syck_emitter_simple_write, 1 );
|
||||
rb_define_method( cEmitter, "flush", syck_emitter_flush_m, 0 );
|
||||
rb_define_method( cEmitter, "start_object", syck_emitter_start_object, 1 );
|
||||
rb_define_method( cEmitter, "end_object", syck_emitter_end_object, 0 );
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
|
||||
#include "syck.h"
|
||||
|
||||
#define SYCK_YAML_MAJOR 1
|
||||
#define SYCK_YAML_MINOR 0
|
||||
#define SYCK_BUFFERSIZE 262144
|
||||
|
||||
void syck_parser_pop_level( SyckParser * );
|
||||
|
||||
/*
|
||||
|
@ -30,6 +26,9 @@ syck_assert( char *file_name, unsigned line_num )
|
|||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocates and copies a string
|
||||
*/
|
||||
char *
|
||||
syck_strndup( char *buf, long len )
|
||||
{
|
||||
|
@ -40,7 +39,7 @@ syck_strndup( char *buf, long len )
|
|||
}
|
||||
|
||||
/*
|
||||
* Default IO functions
|
||||
* Default FILE IO function
|
||||
*/
|
||||
long
|
||||
syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip )
|
||||
|
@ -52,18 +51,15 @@ syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip )
|
|||
|
||||
max_size -= skip;
|
||||
len = fread( buf + skip, max_size, sizeof( char ), file->ptr );
|
||||
#if REDEBUG
|
||||
printf( "LEN: %d\n", len );
|
||||
#endif
|
||||
len += skip;
|
||||
buf[len] = '\0';
|
||||
#if REDEBUG
|
||||
printf( "POS: %d\n", len );
|
||||
printf( "BUFFER: %s\n", buf );
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default string IO function
|
||||
*/
|
||||
long
|
||||
syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
|
||||
{
|
||||
|
@ -95,15 +91,9 @@ syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
|
|||
len = str->ptr - beg;
|
||||
S_MEMCPY( buf + skip, beg, char, len );
|
||||
}
|
||||
#if REDEBUG
|
||||
printf( "LEN: %d\n", len );
|
||||
#endif
|
||||
len += skip;
|
||||
buf[len] = '\0';
|
||||
#if REDEBUG
|
||||
printf( "POS: %d\n", len );
|
||||
printf( "BUFFER: %s\n", buf );
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -150,6 +140,9 @@ syck_parser_reset_cursor( SyckParser *p )
|
|||
p->force_token = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Value to return on a parse error
|
||||
*/
|
||||
void
|
||||
syck_parser_set_root_on_error( SyckParser *p, SYMID roer )
|
||||
{
|
||||
|
@ -212,7 +205,7 @@ syck_st_free( SyckParser *p )
|
|||
{
|
||||
/*
|
||||
* Free the adhoc symbol table
|
||||
*/
|
||||
*/
|
||||
if ( p->syms != NULL )
|
||||
{
|
||||
st_free_table( p->syms );
|
||||
|
@ -410,10 +403,6 @@ syck_move_tokens( SyckParser *p )
|
|||
if ( skip < 1 )
|
||||
return 0;
|
||||
|
||||
#if REDEBUG
|
||||
printf( "DIFF: %d\n", skip );
|
||||
#endif
|
||||
|
||||
if ( ( count = p->token - p->buffer ) )
|
||||
{
|
||||
S_MEMMOVE( p->buffer, p->token, char, skip );
|
||||
|
|
104
ext/syck/syck.h
104
ext/syck/syck.h
|
@ -10,6 +10,9 @@
|
|||
#ifndef SYCK_H
|
||||
#define SYCK_H
|
||||
|
||||
#define SYCK_YAML_MAJOR 1
|
||||
#define SYCK_YAML_MINOR 0
|
||||
|
||||
#define SYCK_VERSION "0.35"
|
||||
#define YAML_DOMAIN "yaml.org,2002"
|
||||
|
||||
|
@ -43,6 +46,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define ALLOC_CT 8
|
||||
#define SYCK_BUFFERSIZE 262144
|
||||
#define S_ALLOC_N(type,n) (type*)malloc(sizeof(type)*(n))
|
||||
#define S_ALLOC(type) (type*)malloc(sizeof(type))
|
||||
#define S_REALLOC_N(var,type,n) (var)=(type*)realloc((char*)(var),sizeof(type)*(n))
|
||||
|
@ -66,11 +70,7 @@ extern "C" {
|
|||
*/
|
||||
#define SYMID unsigned long
|
||||
|
||||
typedef struct _syck_parser SyckParser;
|
||||
typedef struct _syck_file SyckIoFile;
|
||||
typedef struct _syck_str SyckIoStr;
|
||||
typedef struct _syck_node SyckNode;
|
||||
typedef struct _syck_level SyckLevel;
|
||||
|
||||
enum syck_kind_tag {
|
||||
syck_map_kind,
|
||||
|
@ -83,6 +83,9 @@ enum map_part {
|
|||
map_value
|
||||
};
|
||||
|
||||
/*
|
||||
* Node metadata struct
|
||||
*/
|
||||
struct _syck_node {
|
||||
/* Symbol table ID */
|
||||
SYMID id;
|
||||
|
@ -119,6 +122,11 @@ struct _syck_node {
|
|||
/*
|
||||
* Parser definitions
|
||||
*/
|
||||
typedef struct _syck_parser SyckParser;
|
||||
typedef struct _syck_file SyckIoFile;
|
||||
typedef struct _syck_str SyckIoStr;
|
||||
typedef struct _syck_level SyckLevel;
|
||||
|
||||
typedef SYMID (*SyckNodeHandler)(SyckParser *, SyckNode *);
|
||||
typedef void (*SyckErrorHandler)(SyckParser *, char *);
|
||||
typedef SyckNode * (*SyckBadAnchorHandler)(SyckParser *, char *);
|
||||
|
@ -142,6 +150,9 @@ enum syck_level_status {
|
|||
syck_lvl_pause
|
||||
};
|
||||
|
||||
/*
|
||||
* Parser struct
|
||||
*/
|
||||
struct _syck_parser {
|
||||
/* Root node */
|
||||
SYMID root, root_on_error;
|
||||
|
@ -192,6 +203,82 @@ struct _syck_parser {
|
|||
void *bonus;
|
||||
};
|
||||
|
||||
/*
|
||||
* Emitter definitions
|
||||
*/
|
||||
typedef struct _syck_emitter SyckEmitter;
|
||||
typedef struct _syck_emitter_node SyckEmitterNode;
|
||||
|
||||
typedef void (*SyckOutputHandler)(SyckEmitter *, char *, long);
|
||||
|
||||
enum doc_stage {
|
||||
doc_open,
|
||||
doc_need_header,
|
||||
doc_processing
|
||||
};
|
||||
|
||||
enum block_styles {
|
||||
block_arbitrary,
|
||||
block_fold,
|
||||
block_literal
|
||||
};
|
||||
|
||||
/*
|
||||
* Emitter struct
|
||||
*/
|
||||
struct _syck_emitter {
|
||||
/* Headerless doc flag */
|
||||
int headless;
|
||||
/* Sequence map shortcut flag */
|
||||
int seq_map;
|
||||
/* Force header? */
|
||||
int use_header;
|
||||
/* Force version? */
|
||||
int use_version;
|
||||
/* Sort hash keys */
|
||||
int sort_keys;
|
||||
/* Anchor format */
|
||||
char *anchor_format;
|
||||
/* Explicit typing on all collections? */
|
||||
int explicit_typing;
|
||||
/* Best width on folded scalars */
|
||||
int best_width;
|
||||
/* Use literal[1] or folded[2] blocks on all text? */
|
||||
enum block_styles block_style;
|
||||
/* Stage of written document */
|
||||
enum doc_stage stage;
|
||||
/* Level counter */
|
||||
int level;
|
||||
/* Default indentation */
|
||||
int indent;
|
||||
/* Object ignore ID */
|
||||
SYMID ignore_id;
|
||||
/* Symbol table for anchors */
|
||||
st_table *markers, *anchors;
|
||||
/* Custom buffer size */
|
||||
size_t bufsize;
|
||||
/* Buffer */
|
||||
char *buffer, *marker;
|
||||
/* Absolute position of the buffer */
|
||||
long bufpos;
|
||||
/* Handler for output */
|
||||
SyckOutputHandler handler;
|
||||
/* Pointer for extension's use */
|
||||
void *bonus;
|
||||
};
|
||||
|
||||
/*
|
||||
* Emitter node metadata struct
|
||||
*/
|
||||
struct _syck_emitter_node {
|
||||
/* Node buffer position */
|
||||
long pos;
|
||||
/* Current indent */
|
||||
long indent;
|
||||
/* Collection? */
|
||||
int is_shortcut;
|
||||
};
|
||||
|
||||
/*
|
||||
* Handler prototypes
|
||||
*/
|
||||
|
@ -215,6 +302,15 @@ char *syck_match_implicit( char *, size_t );
|
|||
char *syck_strndup( char *, long );
|
||||
long syck_io_file_read( char *, SyckIoFile *, long, long );
|
||||
long syck_io_str_read( char *, SyckIoStr *, long, long );
|
||||
SyckEmitter *syck_new_emitter();
|
||||
void syck_emitter_ignore_id( SyckEmitter *, SYMID );
|
||||
void syck_emitter_handler( SyckEmitter *, SyckOutputHandler );
|
||||
void syck_free_emitter( SyckEmitter * );
|
||||
void syck_emitter_clear( SyckEmitter * );
|
||||
void syck_emitter_write( SyckEmitter *, char *, long );
|
||||
void syck_emitter_flush( SyckEmitter * );
|
||||
char *syck_emitter_start_obj( SyckEmitter *, SYMID );
|
||||
void syck_emitter_end_obj( SyckEmitter * );
|
||||
SyckParser *syck_new_parser();
|
||||
void syck_free_parser( SyckParser * );
|
||||
void syck_parser_set_root_on_error( SyckParser *, SYMID );
|
||||
|
|
37
lib/yaml.rb
37
lib/yaml.rb
|
@ -12,15 +12,26 @@ module YAML
|
|||
require 'yaml/syck'
|
||||
@@parser = YAML::Syck::Parser
|
||||
@@loader = YAML::Syck::DefaultLoader
|
||||
@@emitter = YAML::Syck::Emitter
|
||||
rescue LoadError
|
||||
require 'yaml/parser'
|
||||
@@parser = YAML::Parser
|
||||
@@loader = YAML::DefaultLoader
|
||||
require 'yaml/emitter'
|
||||
@@emitter = YAML::Emitter
|
||||
end
|
||||
require 'yaml/emitter'
|
||||
require 'yaml/loader'
|
||||
require 'yaml/stream'
|
||||
|
||||
#
|
||||
# Load a single document from the current stream
|
||||
#
|
||||
def YAML.dump( obj, io = nil )
|
||||
io ||= ""
|
||||
io << obj.to_yaml
|
||||
io
|
||||
end
|
||||
|
||||
#
|
||||
# Load a single document from the current stream
|
||||
#
|
||||
|
@ -158,6 +169,30 @@ module YAML
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Allocate an Emitter if needed
|
||||
#
|
||||
def YAML.quick_emit( oid, opts = {}, &e )
|
||||
old_opt = nil
|
||||
if opts[:Emitter].is_a? @@emitter
|
||||
out = opts.delete( :Emitter )
|
||||
old_opt = out.options.dup
|
||||
out.options.update( opts )
|
||||
else
|
||||
out = @@emitter.new( opts )
|
||||
end
|
||||
aidx = out.start_object( oid )
|
||||
if aidx
|
||||
out.simple( "*#{ aidx }" )
|
||||
else
|
||||
e.call( out )
|
||||
end
|
||||
if old_opt.is_a? Hash
|
||||
out.options = old_opt
|
||||
end
|
||||
out.end_object
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
require 'yaml/rubytypes'
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
# Output classes and methods
|
||||
#
|
||||
|
||||
require 'yaml/constants'
|
||||
require 'yaml/baseemitter'
|
||||
require 'yaml/encoding'
|
||||
require 'yaml/error'
|
||||
|
||||
module YAML
|
||||
|
||||
|
@ -13,7 +12,11 @@ module YAML
|
|||
#
|
||||
|
||||
class Emitter
|
||||
|
||||
include BaseEmitter
|
||||
|
||||
attr_accessor :options
|
||||
|
||||
def initialize( opts )
|
||||
opts = {} if opts.class != Hash
|
||||
@options = YAML::DEFAULTS.dup.update( opts )
|
||||
|
@ -30,6 +33,10 @@ module YAML
|
|||
@buffer = []
|
||||
end
|
||||
|
||||
def level
|
||||
@level
|
||||
end
|
||||
|
||||
#
|
||||
# Version string
|
||||
#
|
||||
|
@ -48,201 +55,6 @@ module YAML
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Emit binary data
|
||||
#
|
||||
def binary_base64( value )
|
||||
self << "!binary "
|
||||
self.node_text( [value].pack("m"), '|' )
|
||||
end
|
||||
|
||||
#
|
||||
# Emit plain, normal flowing text
|
||||
#
|
||||
def node_text( value, block = '>' )
|
||||
@seq_map = false
|
||||
valx = value.dup
|
||||
if @options[:UseBlock]
|
||||
block = '|'
|
||||
elsif not @options[:UseFold] and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/
|
||||
block = '|'
|
||||
end
|
||||
str = block.dup
|
||||
if valx =~ /\n\Z\n/
|
||||
str << "+"
|
||||
elsif valx =~ /\Z\n/
|
||||
else
|
||||
str << "-"
|
||||
end
|
||||
if valx =~ /#{YAML::ESCAPE_CHAR}/
|
||||
valx = YAML::escape( valx )
|
||||
end
|
||||
if valx =~ /\A[ \t#]/
|
||||
str << @options[:Indent].to_s
|
||||
end
|
||||
if block == '>'
|
||||
valx = fold( valx )
|
||||
end
|
||||
self << str + indent_text( valx ) + "\n"
|
||||
end
|
||||
|
||||
#
|
||||
# Emit a simple, unqouted string
|
||||
#
|
||||
def simple( value )
|
||||
@seq_map = false
|
||||
self << value.to_s
|
||||
end
|
||||
|
||||
#
|
||||
# Emit double-quoted string
|
||||
#
|
||||
def double( value )
|
||||
"\"#{YAML.escape( value )}\""
|
||||
end
|
||||
|
||||
#
|
||||
# Emit single-quoted string
|
||||
#
|
||||
def single( value )
|
||||
"'#{value}'"
|
||||
end
|
||||
|
||||
#
|
||||
# Write a text block with the current indent
|
||||
#
|
||||
def indent_text( text )
|
||||
return "" if text.to_s.empty?
|
||||
spacing = " " * ( @level * @options[:Indent] )
|
||||
return "\n" + text.gsub( /^([^\n])/, "#{spacing}\\1" )
|
||||
end
|
||||
|
||||
#
|
||||
# Write a current indent
|
||||
#
|
||||
def indent
|
||||
#p [ self.id, @level, :INDENT ]
|
||||
return " " * ( @level * @options[:Indent] )
|
||||
end
|
||||
|
||||
#
|
||||
# Add indent to the buffer
|
||||
#
|
||||
def indent!
|
||||
self << indent
|
||||
end
|
||||
|
||||
#
|
||||
# Folding paragraphs within a column
|
||||
#
|
||||
def fold( value )
|
||||
value.gsub!( /\A\n+/, '' )
|
||||
folded = $&.to_s
|
||||
width = (0..@options[:BestWidth])
|
||||
while not value.empty?
|
||||
last = value.index( /(\n+)/ )
|
||||
chop_s = false
|
||||
if width.include?( last )
|
||||
last += $1.length - 1
|
||||
elsif width.include?( value.length )
|
||||
last = value.length
|
||||
else
|
||||
last = value.rindex( /[ \t]/, @options[:BestWidth] )
|
||||
chop_s = true
|
||||
end
|
||||
folded += value.slice!( 0, width.include?( last ) ? last + 1 : @options[:BestWidth] )
|
||||
folded.chop! if chop_s
|
||||
folded += "\n" unless value.empty?
|
||||
end
|
||||
folded
|
||||
end
|
||||
|
||||
#
|
||||
# Quick mapping
|
||||
#
|
||||
def map( type, &e )
|
||||
val = Mapping.new
|
||||
e.call( val )
|
||||
self << "#{type} " if type.length.nonzero?
|
||||
|
||||
#
|
||||
# Empty hashes
|
||||
#
|
||||
if val.length.zero?
|
||||
self << "{}"
|
||||
@seq_map = false
|
||||
else
|
||||
if @buffer.length == 1 and @options[:UseHeader] == false and type.length.zero?
|
||||
@headless = 1
|
||||
end
|
||||
|
||||
defkey = @options.delete( :DefaultKey )
|
||||
if defkey
|
||||
seq_map_shortcut
|
||||
self << "= : "
|
||||
defkey.to_yaml( :Emitter => self )
|
||||
end
|
||||
|
||||
#
|
||||
# Emit the key and value
|
||||
#
|
||||
val.each { |v|
|
||||
seq_map_shortcut
|
||||
if v[0].is_complex_yaml?
|
||||
self << "? "
|
||||
end
|
||||
v[0].to_yaml( :Emitter => self )
|
||||
if v[0].is_complex_yaml?
|
||||
self << "\n"
|
||||
indent!
|
||||
end
|
||||
self << ": "
|
||||
v[1].to_yaml( :Emitter => self )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def seq_map_shortcut
|
||||
if @seq_map
|
||||
@anchor_extras[@buffer.length - 1] = "\n" + indent
|
||||
@seq_map = false
|
||||
else
|
||||
self << "\n"
|
||||
indent!
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Quick sequence
|
||||
#
|
||||
def seq( type, &e )
|
||||
@seq_map = false
|
||||
val = Sequence.new
|
||||
e.call( val )
|
||||
self << "#{type} " if type.length.nonzero?
|
||||
|
||||
#
|
||||
# Empty arrays
|
||||
#
|
||||
if val.length.zero?
|
||||
self << "[]"
|
||||
else
|
||||
if @buffer.length == 1 and @options[:UseHeader] == false and type.length.zero?
|
||||
@headless = 1
|
||||
end
|
||||
#
|
||||
# Emit the key and value
|
||||
#
|
||||
val.each { |v|
|
||||
self << "\n"
|
||||
indent!
|
||||
self << "- "
|
||||
@seq_map = true if v.class == Hash
|
||||
v.to_yaml( :Emitter => self )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Concatenate to the buffer
|
||||
#
|
||||
|
@ -291,44 +103,5 @@ module YAML
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Emitter helper classes
|
||||
#
|
||||
class Mapping < Array
|
||||
def add( k, v )
|
||||
push [k, v]
|
||||
end
|
||||
end
|
||||
|
||||
class Sequence < Array
|
||||
def add( v )
|
||||
push v
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Allocate an Emitter if needed
|
||||
#
|
||||
def YAML.quick_emit( oid, opts = {}, &e )
|
||||
old_opt = nil
|
||||
if opts[:Emitter].is_a? YAML::Emitter
|
||||
out = opts.delete( :Emitter )
|
||||
old_opt = out.options.dup
|
||||
out.options.update( opts )
|
||||
else
|
||||
out = YAML::Emitter.new( opts )
|
||||
end
|
||||
aidx = out.start_object( oid )
|
||||
if aidx
|
||||
out.simple( "*#{out.options[:AnchorFormat]} " % [ aidx ] )
|
||||
else
|
||||
e.call( out )
|
||||
end
|
||||
if old_opt.is_a? Hash
|
||||
out.options = old_opt
|
||||
end
|
||||
out.end_object
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -53,14 +53,14 @@ class Hash
|
|||
opts[:DocType] = self.class if Hash === opts
|
||||
YAML::quick_emit( self.object_id, opts ) { |out|
|
||||
hash_type = to_yaml_type
|
||||
if not out.options[:ExplicitTypes] and hash_type == "!map"
|
||||
if not out.options(:ExplicitTypes) and hash_type == "!map"
|
||||
hash_type = ""
|
||||
end
|
||||
out.map( hash_type ) { |map|
|
||||
#
|
||||
# Sort the hash
|
||||
#
|
||||
if out.options[:SortKeys]
|
||||
if out.options(:SortKeys)
|
||||
map.concat( self.sort )
|
||||
else
|
||||
map.concat( self.to_a )
|
||||
|
@ -213,7 +213,7 @@ class Array
|
|||
opts[:DocType] = self.class if Hash === opts
|
||||
YAML::quick_emit( self.object_id, opts ) { |out|
|
||||
array_type = to_yaml_type
|
||||
if not out.options[:ExplicitTypes] and array_type == "!seq"
|
||||
if not out.options(:ExplicitTypes) and array_type == "!seq"
|
||||
array_type = ""
|
||||
end
|
||||
|
||||
|
@ -302,7 +302,7 @@ class String
|
|||
end
|
||||
end
|
||||
if not complex
|
||||
ostr = if out.options[:KeepValue]
|
||||
ostr = if out.options(:KeepValue)
|
||||
self
|
||||
elsif empty?
|
||||
"''"
|
||||
|
|
|
@ -28,7 +28,7 @@ module YAML
|
|||
opts = @options.dup
|
||||
opts[:UseHeader] = true if @documents.length > 1
|
||||
ct = 0
|
||||
out = Emitter.new( opts )
|
||||
out = YAML::Syck::Emitter.new( opts )
|
||||
@documents.each { |v|
|
||||
if ct > 0
|
||||
out << "\n--- "
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
require 'syck'
|
||||
require 'yaml/basenode'
|
||||
require 'yaml/baseemitter'
|
||||
|
||||
module YAML
|
||||
module Syck
|
||||
|
@ -15,5 +16,12 @@ module YAML
|
|||
include YAML::BaseNode
|
||||
end
|
||||
|
||||
#
|
||||
# Mixin BaseEmitter functionality
|
||||
#
|
||||
class Emitter
|
||||
include YAML::BaseEmitter
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue