summaryrefslogtreecommitdiff
path: root/lib/yaml
diff options
context:
space:
mode:
authorwhy <why@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-05-06 06:39:45 +0000
committerwhy <why@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-05-06 06:39:45 +0000
commit605014cb5544518d26e1039fa7d2de912151fb46 (patch)
tree77ab105fb4d3d964ac9b3f06b971d0c2d1a6b76f /lib/yaml
parent5363ed4c81916bda16b7dad0c6fe5a738bffa726 (diff)
* lib/yaml/rubytypes.rb (to_yaml): added instance variable handling
for Ranges, Strings, Structs, Regexps. * lib/yaml/rubytypes.rb (to_yaml_fold): new method for setting a String's flow style. * lib/yaml.rb (YAML::object_maker): now uses Object.allocate. * ext/syck/gram.c: fixed transfer methods on structs, broke it last commit. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@6253 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/yaml')
-rw-r--r--lib/yaml/baseemitter.rb46
-rw-r--r--lib/yaml/rubytypes.rb212
2 files changed, 190 insertions, 68 deletions
diff --git a/lib/yaml/baseemitter.rb b/lib/yaml/baseemitter.rb
index 007ee7be5e..1072f75533 100644
--- a/lib/yaml/baseemitter.rb
+++ b/lib/yaml/baseemitter.rb
@@ -36,28 +36,36 @@ module YAML
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
+ unless block
+ block =
+ if options(:UseBlock)
+ '|'
+ elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/
+ '|'
+ else
+ '>'
+ end
+ block +=
+ if valx =~ /\n\Z\n/
+ "+"
+ elsif valx =~ /\Z\n/
+ ""
+ else
+ "-"
+ end
+ if valx =~ /\A[ \t#]/
+ block += options(:Indent).to_s
+ end
+ end
if valx =~ /#{YAML::ESCAPE_CHAR}/
valx = YAML::escape( valx )
end
- if valx =~ /\A[ \t#]/
- str << options(:Indent).to_s
- end
- if block == '>'
+ if block[0] == ?>
valx = fold( valx )
end
- self << str + indent_text( valx ) + "\n"
+ indt = nil
+ indt = $&.to_i if block =~ /\d+/
+ self << block + indent_text( valx, indt ) + "\n"
end
#
@@ -85,9 +93,9 @@ module YAML
#
# Write a text block with the current indent
#
- def indent_text( text )
+ def indent_text( text, indt = nil )
return "" if text.to_s.empty?
- spacing = " " * ( level * options(:Indent) )
+ spacing = " " * ( level * ( indt || options(:Indent) ) )
return "\n" + text.gsub( /^([^\n])/, "#{spacing}\\1" )
end
diff --git a/lib/yaml/rubytypes.rb b/lib/yaml/rubytypes.rb
index 7d36b468d6..adebf9439e 100644
--- a/lib/yaml/rubytypes.rb
+++ b/lib/yaml/rubytypes.rb
@@ -6,7 +6,7 @@ require 'date'
class Class
def to_yaml( opts = {} )
- raise ArgumentError, "can't dump anonymous class %s" % self.class
+ raise TypeError, "can't dump anonymous class %s" % self.class
end
end
@@ -161,6 +161,9 @@ class Struct
self.members.each { |m|
map.add( m, self[m] )
}
+ self.to_yaml_properties.each { |m|
+ map.add( m, instance_variable_get( m ) )
+ }
}
}
end
@@ -173,6 +176,8 @@ YAML.add_ruby_type( /^struct/ ) { |type, val|
#
# Use existing Struct if it exists
#
+ props = {}
+ val.delete_if { |k,v| props[k] = v if k =~ /^@/ }
begin
struct_name, struct_type = YAML.read_type_class( type, Struct )
rescue NameError
@@ -185,10 +190,13 @@ YAML.add_ruby_type( /^struct/ ) { |type, val|
#
# Set the Struct properties
#
- st = struct_type.new
+ st = YAML::object_maker( struct_type, {} )
st.members.each { |m|
st.send( "#{m}=", val[m] )
}
+ props.each { |k,v|
+ st.instance_variable_set(k, v)
+ }
st
else
raise YAML::Error, "Invalid Ruby Struct: " + val.inspect
@@ -276,11 +284,17 @@ YAML.add_ruby_type( /^exception/ ) { |type, val|
#
class String
def is_complex_yaml?
- ( self =~ /\n.+/ ? true : false )
+ to_yaml_fold or not to_yaml_properties.empty? or self =~ /\n.+/
end
def is_binary_data?
( self.count( "^ -~", "^\r\n" ) / self.size > 0.3 || self.count( "\x00" ) > 0 )
end
+ def to_yaml_type
+ "!ruby/string#{ if self.class != ::String; ":#{ self.class }"; end }"
+ end
+ def to_yaml_fold
+ nil
+ end
def to_yaml( opts = {} )
complex = false
if self.is_complex_yaml?
@@ -292,12 +306,19 @@ class String
end
YAML::quick_emit( complex ? self.object_id : nil, opts ) { |out|
if complex
- if self.is_binary_data?
+ if not to_yaml_properties.empty?
+ out.map( self.to_yaml_type ) { |map|
+ map.add( 'str', "#{self}" )
+ to_yaml_properties.each { |m|
+ map.add( m, instance_variable_get( m ) )
+ }
+ }
+ elsif self.is_binary_data?
out.binary_base64( self )
elsif self =~ /^ |#{YAML::ESCAPE_CHAR}| $/
complex = false
else
- out.node_text( self )
+ out.node_text( self, to_yaml_fold )
end
end
if not complex
@@ -318,6 +339,21 @@ class String
end
end
+YAML.add_ruby_type( /^string/ ) { |type, val|
+ type, obj_class = YAML.read_type_class( type, ::String )
+ if Hash === val
+ s = YAML::object_maker( obj_class, {} )
+ # Thank you, NaHi
+ String.instance_method(:initialize).
+ bind(s).
+ call( val.delete( 'str' ) )
+ val.each { |k,v| s.instance_variable_set( k, v ) }
+ s
+ else
+ raise YAML::Error, "Invalid String: " + val.inspect
+ end
+}
+
#
# Symbol#to_yaml
#
@@ -335,6 +371,7 @@ end
symbol_proc = Proc.new { |type, val|
if String === val
+ val = YAML::load( "--- #{val}") if val =~ /^["'].*["']$/
val.intern
else
raise YAML::Error, "Invalid Symbol: " + val.inspect
@@ -348,102 +385,179 @@ YAML.add_ruby_type( 'sym', &symbol_proc )
#
class Range
def is_complex_yaml?
- false
+ true
+ end
+ def to_yaml_type
+ "!ruby/range#{ if self.class != ::Range; ":#{ self.class }"; end }"
end
def to_yaml( opts = {} )
- YAML::quick_emit( nil, opts ) { |out|
- out << "!ruby/range '"
- self.begin.to_yaml(:Emitter => out)
- out << ( self.exclude_end? ? "..." : ".." )
- self.end.to_yaml(:Emitter => out)
- out << "'"
+ YAML::quick_emit( self.object_id, opts ) { |out|
+ if self.begin.is_complex_yaml? or self.end.is_complex_yaml? or not to_yaml_properties.empty?
+ out.map( to_yaml_type ) { |map|
+ map.add( 'begin', self.begin )
+ map.add( 'end', self.end )
+ map.add( 'excl', self.exclude_end? )
+ to_yaml_properties.each { |m|
+ map.add( m, instance_variable_get( m ) )
+ }
+ }
+ else
+ out << "#{ to_yaml_type } '"
+ self.begin.to_yaml(:Emitter => out)
+ out << ( self.exclude_end? ? "..." : ".." )
+ self.end.to_yaml(:Emitter => out)
+ out << "'"
+ end
}
end
end
-YAML.add_ruby_type( 'range' ) { |type, val|
+YAML.add_ruby_type( /^range/ ) { |type, val|
+ type, obj_class = YAML.read_type_class( type, ::Range )
inr = '(\w+|[+-]*\d+(?:\.\d+)?|"(?:[^\\"]|\\.)*")'
+ opts = {}
if String === val and val =~ /^#{inr}(\.{2,3})#{inr}$/
r1, rdots, r2 = $1, $2, $3
- Range.new( YAML.load( "--- #{r1}" ), YAML.load( "--- #{r2}" ), rdots.length == 3 )
- elsif Hash === val
- Range.new( val['begin'], val['end'], val['exclude_end?'] )
+ opts = {
+ 'begin' => YAML.load( "--- #{r1}" ),
+ 'end' => YAML.load( "--- #{r2}" ),
+ 'excl' => rdots.length == 3
+ }
+ val = {}
+ elsif Hash === val
+ opts['begin'] = val.delete('begin')
+ opts['end'] = val.delete('end')
+ opts['excl'] = val.delete('excl')
+ end
+ if Hash === opts
+ r = YAML::object_maker( obj_class, {} )
+ # Thank you, NaHi
+ Range.instance_method(:initialize).
+ bind(r).
+ call( opts['begin'], opts['end'], opts['excl'] )
+ val.each { |k,v| r.instance_variable_set( k, v ) }
+ r
else
raise YAML::Error, "Invalid Range: " + val.inspect
end
}
#
-# Make an RegExp
+# Make an Regexp
#
class Regexp
def is_complex_yaml?
- false
+ self.class != Regexp or not to_yaml_properties.empty?
+ end
+ def to_yaml_type
+ "!ruby/regexp#{ if self.class != ::Regexp; ":#{ self.class }"; end }"
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
- out << "!ruby/regexp "
- self.inspect.to_yaml( :Emitter => out )
+ if self.is_complex_yaml?
+ out.map( self.to_yaml_type ) { |map|
+ src = self.inspect
+ if src =~ /\A\/(.*)\/([a-z]*)\Z/
+ map.add( 'regexp', $1 )
+ map.add( 'mods', $2 )
+ else
+ raise YAML::Error, "Invalid Regular expression: " + src
+ end
+ to_yaml_properties.each { |m|
+ map.add( m, instance_variable_get( m ) )
+ }
+ }
+ else
+ out << "#{ to_yaml_type } "
+ self.inspect.to_yaml( :Emitter => out )
+ end
}
end
end
regexp_proc = Proc.new { |type, val|
+ type, obj_class = YAML.read_type_class( type, ::Regexp )
if String === val and val =~ /^\/(.*)\/([mix]*)$/
- val = { 'REGEXP' => $1, 'MODIFIERS' => $2 }
+ val = { 'regexp' => $1, 'mods' => $2 }
end
if Hash === val
mods = nil
- unless val['MODIFIERS'].to_s.empty?
+ unless val['mods'].to_s.empty?
mods = 0x00
- if val['MODIFIERS'].include?( 'x' )
- mods |= Regexp::EXTENDED
- elsif val['MODIFIERS'].include?( 'i' )
- mods |= Regexp::IGNORECASE
- elsif val['MODIFIERS'].include?( 'm' )
- mods |= Regexp::POSIXLINE
- end
+ mods |= Regexp::EXTENDED if val['mods'].include?( 'x' )
+ mods |= Regexp::IGNORECASE if val['mods'].include?( 'i' )
+ mods |= Regexp::MULTILINE if val['mods'].include?( 'm' )
end
- Regexp::compile( val['REGEXP'], mods )
+ val.delete( 'mods' )
+ r = YAML::object_maker( obj_class, {} )
+ Regexp.instance_method(:initialize).
+ bind(r).
+ call( val.delete( 'regexp' ), mods )
+ val.each { |k,v| r.instance_variable_set( k, v ) }
+ r
else
raise YAML::Error, "Invalid Regular expression: " + val.inspect
end
}
YAML.add_domain_type( "perl.yaml.org,2002", /^regexp/, &regexp_proc )
-YAML.add_ruby_type( 'regexp', &regexp_proc )
+YAML.add_ruby_type( /^regexp/, &regexp_proc )
#
# Emit a Time object as an ISO 8601 timestamp
#
class Time
def is_complex_yaml?
- false
+ self.class != Time or not to_yaml_properties.empty?
+ end
+ def to_yaml_type
+ "!ruby/time#{ if self.class != ::Time; ":#{ self.class }"; end }"
end
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
- tz = "Z"
- # from the tidy Tobias Peters <t-peters@gmx.de> Thanks!
- unless self.utc?
- utc_same_instant = self.dup.utc
- utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec)
- difference_to_utc = utc_same_writing - utc_same_instant
- if (difference_to_utc < 0)
- difference_sign = '-'
- absolute_difference = -difference_to_utc
- else
- difference_sign = '+'
- absolute_difference = difference_to_utc
+ if self.is_complex_yaml?
+ out.map( self.to_yaml_type ) { |map|
+ map.add( 'at', ::Time.at( self ) )
+ to_yaml_properties.each { |m|
+ map.add( m, instance_variable_get( m ) )
+ }
+ }
+ else
+ tz = "Z"
+ # from the tidy Tobias Peters <t-peters@gmx.de> Thanks!
+ unless self.utc?
+ utc_same_instant = self.dup.utc
+ utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec)
+ difference_to_utc = utc_same_writing - utc_same_instant
+ if (difference_to_utc < 0)
+ difference_sign = '-'
+ absolute_difference = -difference_to_utc
+ else
+ difference_sign = '+'
+ absolute_difference = difference_to_utc
+ end
+ difference_minutes = (absolute_difference/60).round
+ tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60]
end
- difference_minutes = (absolute_difference/60).round
- tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60]
+ standard = self.strftime( "%Y-%m-%d %H:%M:%S" )
+ standard += ".%06d" % [usec] if usec.nonzero?
+ standard += " %s" % [tz]
+ standard.to_yaml( :Emitter => out, :KeepValue => true )
end
- ( self.strftime( "%Y-%m-%d %H:%M:%S." ) +
- "%06d %s" % [usec, tz] ).
- to_yaml( :Emitter => out, :KeepValue => true )
}
end
end
+YAML.add_ruby_type( /^time/ ) { |type, val|
+ type, obj_class = YAML.read_type_class( type, ::Time )
+ if Hash === val
+ t = obj_class.at( val.delete( 'at' ) )
+ val.each { |k,v| t.instance_variable_set( k, v ) }
+ t
+ else
+ raise YAML::Error, "Invalid Time: " + val.inspect
+ end
+}
+
#
# Emit a Date object as a simple implicit
#