diff --git a/.classpath b/.classpath index 7fca1fe2fe3..41f95a585c7 100644 --- a/.classpath +++ b/.classpath @@ -6,5 +6,6 @@ + diff --git a/docs/jvyaml/CREDITS b/docs/jvyaml/CREDITS new file mode 100644 index 00000000000..f9e8f87a4a2 --- /dev/null +++ b/docs/jvyaml/CREDITS @@ -0,0 +1,4 @@ +Credits +------- + +Kirill Simonov - for writing the original Python code. diff --git a/docs/jvyaml/LICENSE b/docs/jvyaml/LICENSE new file mode 100644 index 00000000000..0a588b5f6a5 --- /dev/null +++ b/docs/jvyaml/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006 Ola Bini + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/jvyaml/README b/docs/jvyaml/README new file mode 100644 index 00000000000..90a96100a91 --- /dev/null +++ b/docs/jvyaml/README @@ -0,0 +1,31 @@ += RbYAML - A pure Ruby YAML 1.1 loader and dumper + +Project Contact: Ola Bini + +The code is based mostly on the Python code written by Kirill Simonov for PyYAML3000. + +RbYAML is a project originating in the JRuby project (http://jruby.sourceforge.net), to create a pure Ruby +YAML parser for use in JRuby and SYCK cannot be used in this case. +Since the effort of writing a new one from scratch seemed like a major undertaking it seemed easier to +port an existing one. + +The current functionality is more or less 1.1-compliant. What's missing is the Unicode-support. The idea +is to have the interface resemble SYCK as much as possible, but this is still work in progress, since some +of the major architectural choices are quite different. + +== Use + +Just require 'rbyaml' and use it as you would use YAML, but in module RbYAML instead: + + require 'rbyaml' + + RbYAML.load("--- \n- A\n- b\n- c\n") ----> ["A","b","c"] + "foo".to_yaml ----> "foo\n" + +== More information + +Visit http://rbyaml.rubyforge.org for more information and updated versions + +== License + +RbYAML is distributed with a MIT license, which can be found in the file LICENSE. diff --git a/docs/rbyaml/LICENSE b/docs/rbyaml/LICENSE new file mode 100644 index 00000000000..0a588b5f6a5 --- /dev/null +++ b/docs/rbyaml/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006 Ola Bini + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/rbyaml/README b/docs/rbyaml/README new file mode 100644 index 00000000000..90a96100a91 --- /dev/null +++ b/docs/rbyaml/README @@ -0,0 +1,31 @@ += RbYAML - A pure Ruby YAML 1.1 loader and dumper + +Project Contact: Ola Bini + +The code is based mostly on the Python code written by Kirill Simonov for PyYAML3000. + +RbYAML is a project originating in the JRuby project (http://jruby.sourceforge.net), to create a pure Ruby +YAML parser for use in JRuby and SYCK cannot be used in this case. +Since the effort of writing a new one from scratch seemed like a major undertaking it seemed easier to +port an existing one. + +The current functionality is more or less 1.1-compliant. What's missing is the Unicode-support. The idea +is to have the interface resemble SYCK as much as possible, but this is still work in progress, since some +of the major architectural choices are quite different. + +== Use + +Just require 'rbyaml' and use it as you would use YAML, but in module RbYAML instead: + + require 'rbyaml' + + RbYAML.load("--- \n- A\n- b\n- c\n") ----> ["A","b","c"] + "foo".to_yaml ----> "foo\n" + +== More information + +Visit http://rbyaml.rubyforge.org for more information and updated versions + +== License + +RbYAML is distributed with a MIT license, which can be found in the file LICENSE. diff --git a/lib/jvyaml.jar b/lib/jvyaml.jar new file mode 100644 index 00000000000..1cade989414 Binary files /dev/null and b/lib/jvyaml.jar differ diff --git a/src/builtin/yaml.rb b/src/builtin/yaml.rb index 94332cebf06..ee929c17a65 100644 --- a/src/builtin/yaml.rb +++ b/src/builtin/yaml.rb @@ -1,3563 +1,36 @@ -# -# DO NOT MODIFY!!!! -# This file is automatically generated by racc 1.4.3 -# from racc grammer file "src/yaml.y.rb". -# -# -# src/yaml.rb: generated by racc (runtime embedded) -# -###### racc/parser.rb +require 'rbyaml' +require 'java' -unless $".index 'racc/parser.rb' -$".push 'racc/parser.rb' - -self.class.module_eval <<'..end /usr/local/lib/ruby/site_ruby/1.8/racc/parser.rb modeval..id4449eb2054', '/usr/local/lib/ruby/site_ruby/1.8/racc/parser.rb', 1 -# -# parser.rb -# -# Copyright (c) 1999-2002 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the same terms of ruby. -# -# As a special exception, when this code is copied by Racc -# into a Racc output file, you may use that output file -# without restriction. -# -# - -unless defined? NotImplementedError - NotImplementedError = NotImplementError -end - - -module Racc - class ParseError < StandardError; end -end -unless defined? ::ParseError - ParseError = Racc::ParseError -end - - -module Racc - - unless defined? Racc_No_Extentions - Racc_No_Extentions = false - end - - class Parser - - # revisions have been hardcoded to avoid branch/merge issues - Racc_Runtime_Version = '1.4.3' - Racc_Runtime_Revision = '1.1'.split(/\s+/)[1] - - Racc_Runtime_Core_Version_R = '1.4.3' - Racc_Runtime_Core_Revision_R = '1.1'.split(/\s+/)[1] - begin - require 'racc/cparse' - # Racc_Runtime_Core_Version_C = (defined in extention) - Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split(/\s+/)[2] - unless new.respond_to?(:_racc_do_parse_c, true) - raise LoadError, 'old cparse.so' - end - if Racc_No_Extentions - raise LoadError, 'selecting ruby version of racc runtime core' - end - - Racc_Main_Parsing_Routine = :_racc_do_parse_c - Racc_YY_Parse_Method = :_racc_yyparse_c - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C - Racc_Runtime_Type = 'c' - rescue LoadError - Racc_Main_Parsing_Routine = :_racc_do_parse_rb - Racc_YY_Parse_Method = :_racc_yyparse_rb - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R - Racc_Runtime_Type = 'ruby' - end - - def self.racc_runtime_type - Racc_Runtime_Type - end - - private - - def _racc_setup - @yydebug = false unless self.class::Racc_debug_parser - @yydebug = false unless defined? @yydebug - if @yydebug - @racc_debug_out = $stderr unless defined? @racc_debug_out - @racc_debug_out ||= $stderr - end - arg = self.class::Racc_arg - arg[13] = true if arg.size < 14 - arg - end - - def _racc_init_sysvars - @racc_state = [0] - @racc_tstack = [] - @racc_vstack = [] - - @racc_t = nil - @racc_val = nil - - @racc_read_next = true - - @racc_user_yyerror = false - @racc_error_status = 0 - end - - - ### - ### do_parse - ### - - def do_parse - __send__ Racc_Main_Parsing_Routine, _racc_setup(), false - end - - def next_token - raise NotImplementedError, "#{self.class}\#next_token is not defined" - end - - def _racc_do_parse_rb( arg, in_debug ) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars() - tok = act = i = nil - nerr = 0 - - catch(:racc_end_parse) { - while true - if i = action_pointer[@racc_state[-1]] - if @racc_read_next - if @racc_t != 0 # not EOF - tok, @racc_val = next_token() - unless tok # EOF - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - racc_read_token(@racc_t, tok, @racc_val) if @yydebug - @racc_read_next = false - end - end - i += @racc_t - if i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - ; - else - act = action_default[@racc_state[-1]] - end - else - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - end - end - } - end - - - ### - ### yyparse - ### - - def yyparse( recv, mid ) - __send__ Racc_YY_Parse_Method, recv, mid, _racc_setup(), true - end - - def _racc_yyparse_rb( recv, mid, arg, c_debug ) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars - tok = nil - act = nil - i = nil - nerr = 0 - - - catch(:racc_end_parse) { - until i = action_pointer[@racc_state[-1]] - while act = _racc_evalact(action_default[@racc_state[-1]], arg) - end - end - - recv.__send__(mid) do |tok, val| -# $stderr.puts "rd: tok=#{tok}, val=#{val}" - unless tok - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - @racc_val = val - @racc_read_next = false - - i += @racc_t - if i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - ; -# $stderr.puts "01: act=#{act}" - else - act = action_default[@racc_state[-1]] -# $stderr.puts "02: act=#{act}" -# $stderr.puts "curstate=#{@racc_state[-1]}" - end - - while act = _racc_evalact(act, arg) - end - - while not (i = action_pointer[@racc_state[-1]]) or - not @racc_read_next or - @racc_t == 0 # $ - if i and i += @racc_t and - i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - ; -# $stderr.puts "03: act=#{act}" - else -# $stderr.puts "04: act=#{act}" - act = action_default[@racc_state[-1]] - end - - while act = _racc_evalact(act, arg) - end - end - end - } - end - - - ### - ### common - ### - - def _racc_evalact( act, arg ) -# $stderr.puts "ea: act=#{act}" - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg -nerr = 0 # tmp - - if act > 0 and act < shift_n - # - # shift - # - - if @racc_error_status > 0 - @racc_error_status -= 1 unless @racc_t == 1 # error token - end - - @racc_vstack.push @racc_val - @racc_state.push act - @racc_read_next = true - - if @yydebug - @racc_tstack.push @racc_t - racc_shift @racc_t, @racc_tstack, @racc_vstack - end - - elsif act < 0 and act > -reduce_n - # - # reduce - # - - code = catch(:racc_jump) { - @racc_state.push _racc_do_reduce(arg, act) - false - } - if code - case code - when 1 # yyerror - @racc_user_yyerror = true # user_yyerror - return -reduce_n - when 2 # yyaccept - return shift_n - else - raise RuntimeError, '[Racc Bug] unknown jump code' - end - end - - elsif act == shift_n - # - # accept - # - - racc_accept if @yydebug - throw :racc_end_parse, @racc_vstack[0] - - elsif act == -reduce_n - # - # error - # - - case @racc_error_status - when 0 - unless arg[21] # user_yyerror - nerr += 1 - on_error @racc_t, @racc_val, @racc_vstack - end - when 3 - if @racc_t == 0 # is $ - throw :racc_end_parse, nil - end - @racc_read_next = true - end - @racc_user_yyerror = false - @racc_error_status = 3 - - while true - if i = action_pointer[@racc_state[-1]] - i += 1 # error token - if i >= 0 and - (act = action_table[i]) and - action_check[i] == @racc_state[-1] - break - end - end - - throw :racc_end_parse, nil if @racc_state.size < 2 - @racc_state.pop - @racc_vstack.pop - if @yydebug - @racc_tstack.pop - racc_e_pop @racc_state, @racc_tstack, @racc_vstack - end - end - - return act - - else - raise RuntimeError, "[Racc Bug] unknown action #{act.inspect}" - end - - racc_next_state(@racc_state[-1], @racc_state) if @yydebug - - nil - end - - def _racc_do_reduce( arg, act ) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - state = @racc_state - vstack = @racc_vstack - tstack = @racc_tstack - - i = act * -3 - len = reduce_table[i] - reduce_to = reduce_table[i+1] - method_id = reduce_table[i+2] - void_array = [] - - tmp_t = tstack[-len, len] if @yydebug - tmp_v = vstack[-len, len] - tstack[-len, len] = void_array if @yydebug - vstack[-len, len] = void_array - state[-len, len] = void_array - - # tstack must be updated AFTER method call - if use_result - vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) - else - vstack.push __send__(method_id, tmp_v, vstack) - end - tstack.push reduce_to - - racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug - - k1 = reduce_to - nt_base - if i = goto_pointer[k1] - i += state[-1] - if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 - return curstate - end - end - goto_default[k1] - end - - def on_error( t, val, vstack ) - raise ParseError, sprintf("\nparse error on value %s (%s)", - val.inspect, token_to_str(t) || '?') - end - - def yyerror - throw :racc_jump, 1 - end - - def yyaccept - throw :racc_jump, 2 - end - - def yyerrok - @racc_error_status = 0 - end - - - # for debugging output - - def racc_read_token( t, tok, val ) - @racc_debug_out.print 'read ' - @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' - @racc_debug_out.puts val.inspect - @racc_debug_out.puts - end - - def racc_shift( tok, tstack, vstack ) - @racc_debug_out.puts "shift #{racc_token2str tok}" - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_reduce( toks, sim, tstack, vstack ) - out = @racc_debug_out - out.print 'reduce ' - if toks.empty? - out.print ' ' - else - toks.each {|t| out.print ' ', racc_token2str(t) } - end - out.puts " --> #{racc_token2str(sim)}" - - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_accept - @racc_debug_out.puts 'accept' - @racc_debug_out.puts - end - - def racc_e_pop( state, tstack, vstack ) - @racc_debug_out.puts 'error recovering mode: pop token' - racc_print_states state - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_next_state( curstate, state ) - @racc_debug_out.puts "goto #{curstate}" - racc_print_states state - @racc_debug_out.puts - end - - def racc_print_stacks( t, v ) - out = @racc_debug_out - out.print ' [' - t.each_index do |i| - out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' - end - out.puts ' ]' - end - - def racc_print_states( s ) - out = @racc_debug_out - out.print ' [' - s.each {|st| out.print ' ', st } - out.puts ' ]' - end - - def racc_token2str( tok ) - self.class::Racc_token_to_s_table[tok] or - raise RuntimeError, "[Racc Bug] can't convert token #{tok} to string" - end - - def token_to_str( t ) - self.class::Racc_token_to_s_table[t] - end - - end - -end -..end /usr/local/lib/ruby/site_ruby/1.8/racc/parser.rb modeval..id4449eb2054 -end # end of racc/parser.rb - - -self.class.module_eval <<'..end src/emitter.rb modeval..iddd2784be19', 'src/emitter.rb', 1 -# vim:sw=4:ts=4 -# -# YAML for Ruby: -# - Thanks to Brian Ingerson for YAML.pm -# -# Docs in YAML (see /doc/) -# -require 'pstore' -require 'parsedate' -require 'date' - -begin -require 'stringio' -rescue LoadError - # StringIO based on code by MoonWolf - class StringIO - def initialize(string="") - @string=string - @pos=0 - @eof=(string.size==0) - end - def pos - @pos - end - def eof - @eof - end - alias eof? eof - def readline(rs=$/) - if @eof - raise EOFError - else - if p = @string[@pos..-1]=~rs - line = @string[@pos,p+1] - else - line = @string[@pos..-1] - end - @pos+=line.size - @eof =true if @pos==@string.size - $_ = line - end - end - def rewind - seek(0,0) - end - def seek(offset,whence) - case whence - when 0 - @pos=offset - when 1 - @pos+=offset - when 2 - @pos=@string.size+offset - end - @eof=(@pos>=@string.size) - 0 - end - end - -end - - -module YAML - - # - # Constants - # - VERSION = '0.49' - SUPPORTED_YAML_VERSIONS = ['1.0'] - - # - # Parser tokens - # - WORD_CHAR = 'A-Za-z0-9' - PRINTABLE_CHAR = '-_A-Za-z0-9!?/()$\'". ' - NOT_PLAIN_CHAR = '\x7f\x0-\x1f\x80-\x9f' - ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]' - INDICATOR_CHAR = '*&!|\\\\^@%{}[]=' - SPACE_INDICATORS = '-#:,?' - RESTRICTED_INDICATORS = '#:,}]' - DNS_COMP_RE = "\\w(?:[-\\w]*\\w)?" - DNS_NAME_RE = "(?:(?:#{DNS_COMP_RE}\\.)+#{DNS_COMP_RE}|#{DNS_COMP_RE})" - ESCAPES = %w{\z \x01 \x02 \x03 \x04 \x05 \x06 \a - \x08 \t \n \v \f \r \x0e \x0f - \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 - \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f - } - UNESCAPES = { - 'z' => "\x00", 'a' => "\x07", 'b' => "\x08", 't' => "\x09", - 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", - 'r' => "\x0d", 'e' => "\x1b", '\\' => '\\', - } - - # - # Encodings ( $-K to ICONV ) - # - CHARSETS = { - 'NONE' => 'LATIN1', - 'ASCII' => 'US-ASCII', - 'UTF-8' => 'UTF-8', - 'EUC' => 'EUC-JP', - 'SJIS' => 'SHIFT-JIS' - } - - # - # Error messages - # - ERROR_NO_HEADER_NODE = "With UseHeader=false, the node Array or Hash must have elements" - ERROR_NEED_HEADER = "With UseHeader=false, the node must be an Array or Hash" - ERROR_BAD_EXPLICIT = "Unsupported explicit transfer: '%s'" - ERROR_MANY_EXPLICIT = "More than one explicit transfer" - ERROR_MANY_IMPLICIT = "More than one implicit request" - ERROR_NO_ANCHOR = "No anchor for alias '%s'" - ERROR_BAD_ANCHOR = "Invalid anchor: %s" - ERROR_MANY_ANCHOR = "More than one anchor" - ERROR_ANCHOR_ALIAS = "Can't define both an anchor and an alias" - ERROR_BAD_ALIAS = "Invalid alias: %s" - ERROR_MANY_ALIAS = "More than one alias" - ERROR_ZERO_INDENT = "Can't use zero as an indentation width" - ERROR_UNSUPPORTED_VERSION = "This release of YAML.rb does not support YAML version %s" - ERROR_UNSUPPORTED_ENCODING = "Attempt to use unsupported encoding: %s" - - # - # Default settings - # - DEFAULTS = { - :Indent => 2, :UseHeader => false, :UseVersion => false, :Version => '1.0', - :SortKeys => false, :AnchorFormat => 'id%03d', :ExplicitTypes => false, - :WidthType => 'absolute', :BestWidth => 80, - :UseBlock => false, :UseFold => false, :Encoding => :None - } - TRANSFER_DOMAINS = { - 'yaml.org,2002' => {}, - 'ruby.yaml.org,2002' => {} - } - PRIVATE_TYPES = {} - IMPLICIT_TYPES = [ 'null', 'bool', 'time', 'int', 'float' ] - - def YAML.object_maker( obj_class, val ) - if Hash === val - o = obj_class.new_without_initialize - val.each_pair { |k,v| - o.instance_eval "@#{k} = v" - } - o - else - raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect - end - end - - # - # YAML documents can be in UTF-8, UTF-16 or UTF-32 - # So let's read and write in Unicode - # - @@unicode = false - begin - require 'iconv' - DEFAULTS[:Encoding] = :Utf8 - rescue LoadError - end - - def YAML.unicode; @@unicode; end - def YAML.unicode=( bool ); @@unicode = bool; end - - # - # YAML Error class - # - class Error < StandardError; end - class ParseError < Error; end - - # - # YAML Generic Model container - # - class YamlNode - attr_accessor :kind, :type_id, :value, :anchor - def initialize( t, v ) - @type_id = t - if Hash === v - @kind = 'map' - @value = {} - v.each { |k,v| - @value[ k.transform ] = [ k, v ] - } - elsif Array === v - @kind = 'seq' - @value = v - elsif String === v - @kind = 'scalar' - @value = v - end - end - - # - # Search for YPath entry and return - # qualified nodes. - # - def select( ypath_str ) - matches = match_path( ypath_str ) - - # - # Create a new generic view of the elements selected - # - if matches - result = [] - matches.each { |m| - result.push m.last - } - YamlNode.new( 'seq', result ) - end - end - - # - # Search for YPath entry and return a list of - # qualified paths. - # - def search( ypath_str ) - matches = match_path( ypath_str ) - - if matches - matches.collect { |m| - path = [] - m.each_index { |i| - path.push m[i] if ( i % 2 ).zero? - } - "/" + path.compact.join( "/" ) - } - end - end - - def at( seg ) - if Hash === @value and @value.has_key?( seg ) - @value[seg][1] - elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i] - @value[seg.to_i] - end - end - - # - # YPath search returning a complete depth array - # - def match_path( ypath_str ) - depth = 0 - matches = [] - YPath.each_path( ypath_str ) do |ypath| - seg = match_segment( ypath, 0 ) - matches += seg if seg - end - matches.uniq - end - - # - # Search a node for a single YPath segment - # - def match_segment( ypath, depth ) - deep_nodes = [] - seg = ypath.segments[ depth ] - if seg == "/" - unless String === @value - idx = -1 - @value.collect { |v| - idx += 1 - if Hash === @value - match_init = [v[0], v[1][1]] - match_deep = v[1][1].match_segment( ypath, depth ) - else - match_init = [idx, v] - match_deep = v.match_segment( ypath, depth ) - end - if match_deep - match_deep.each { |m| - deep_nodes.push( match_init + m ) - } - end - } - end - depth += 1 - seg = ypath.segments[ depth ] - end - match_nodes = - case seg - when "." - [[nil, self]] - when ".." - [["..", nil]] - when "*" - unless String === @value - idx = -1 - @value.collect { |h| - idx += 1 - if Hash === @value - [h[0], h[1][1]] - else - [idx, h] - end - } - end - else - if seg =~ /^"(.*)"$/ - seg = $1 - elsif seg =~ /^'(.*)'$/ - seg = $1 - end - if ( v = at( seg ) ) - [[ seg, v ]] - end - end - return deep_nodes unless match_nodes - pred = ypath.predicates[ depth ] - if pred - case pred - when /^\.=/ - pred = $' - match_nodes.reject! { |n| - n.last.value != pred - } - else - match_nodes.reject! { |n| - n.last.at( pred ).nil? - } - end - end - return match_nodes + deep_nodes unless ypath.segments.length > depth + 1 - - #puts "DEPTH: #{depth + 1}" - deep_nodes = [] - match_nodes.each { |n| - if n[1].is_a? YamlNode - match_deep = n[1].match_segment( ypath, depth + 1 ) - if match_deep - match_deep.each { |m| - deep_nodes.push( n + m ) - } - end - else - deep_nodes = [] - end - } - deep_nodes = nil if deep_nodes.length == 0 - deep_nodes - end - - # - # Transform this node fully into a native type - # - def transform - t = nil - if @value.is_a? Hash - t = {} - @value.each { |k,v| - t[ k ] = v[1].transform - } - elsif @value.is_a? Array - t = [] - @value.each { |v| - t.push v.transform - } - else - t = @value - end - YAML.transfer_method( @type_id, t ) - end - - # - # We want the node to act like as Hash - # if it is. - # - def []( *k ) - if Hash === @value - v = @value.[]( *k ) - v[1] if v - elsif Array === @value - @value.[]( *k ) - end - end - - def children - if Hash === @value - @value.values.collect { |c| c[1] } - elsif Array === @value - @value - end - end - - def children_with_index - if Hash === @value - @value.keys.collect { |i| [self[i], i] } - elsif Array === @value - i = -1; @value.collect { |v| i += 1; [v, i] } - end - end - - def emit - transform.to_yaml - end - end - - class YPath - attr_accessor :segments, :predicates, :flags - def initialize( str ) - @segments = [] - @predicates = [] - @flags = nil - while str =~ /^\/?(\/|[^\/[]+)(?:\[([^\]]+)\])?/ - @segments.push $1 - @predicates.push $2 - str = $' - end - unless str.to_s.empty? - @segments += str.split( "/" ) - end - if @segments.length == 0 - @segments.push "." - end - end - def YPath.each_path( str ) - # - # Find choices - # - paths = [] - str = "(#{ str })" - while str.sub!( /\(([^()]+)\)/, "\n#{ paths.length }\n" ) - paths.push $1.split( '|' ) - end - - # - # Construct all possible paths - # - all = [ str ] - ( paths.length - 1 ).downto( 0 ) do |i| - all = all.collect do |a| - paths[i].collect do |p| - a.gsub( /\n#{ i }\n/, p ) - end - end.flatten.uniq - end - all.collect do |path| - yield YPath.new( path ) - end - end - end - - # - # Class method for creating streams - # - def YAML.make_stream( io ) - if String === io - io = StringIO.new( io ) - #elsif not IO === io - # raise YAML::Error, "YAML stream must be an IO or String object." - # cnutter: This test was removed because GzipFile does not < IO in Ruby 1.8 - end - if YAML::unicode - def io.readline - YAML.utf_to_internal( readline( @ln_sep ), @utf_encoding ) - end - def io.check_unicode - @utf_encoding = YAML.sniff_encoding( read( 4 ) ) - @ln_sep = YAML.enc_separator( @utf_encoding ) - seek( -4, IO::SEEK_CUR ) - end - def io.utf_encoding - @utf_encoding - end - io.check_unicode - else - def io.utf_encoding - :None - end - end - io - end - - # - # Unicode conversion - # - def YAML.utf_to_internal( str, from_enc ) - return unless str - to_enc = CHARSETS[$-K] - case from_enc - when :Utf32 - Iconv.iconv( to_enc, 'UTF-32', str )[0] - when :Utf16 - Iconv.iconv( to_enc, 'UTF-16', str )[0] - when :Utf8 - Iconv.iconv( to_enc, 'UTF-8', str )[0] - when :None - str - else - raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % from_enc.inspect - end - end - - def YAML.internal_to_utf( str, to_enc ) - return unless str - from_enc = CHARSETS[$-K] - case to_enc - when :Utf32 - Iconv.iconv( 'UTF-32', from_enc, str )[0] - when :Utf16 - Iconv.iconv( 'UTF-16', from_enc, str )[0] - when :Utf8 - Iconv.iconv( 'UTF-8', from_enc, str )[0] - when :None - str - else - raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % to_enc.inspect - end - end - - def YAML.sniff_encoding( str ) - unless YAML::unicode - :None - else - case str - when /^\x00\x00\xFE\xFF/ # UTF-32 - :Utf32 - when /^\xFE\xFF/ # UTF-32BE - :Utf16 - else - :Utf8 - end - end - end - - def YAML.enc_separator( enc ) - case enc - when :Utf32 - "\000\000\000\n" - when :Utf16 - "\000\n" - when :Utf8 - "\n" - when :None - "\n" - else - raise YAML::Error, ERROR_UNSUPPORTED_ENCODING % enc.inspect - end - end - - # - # Output methods - # - - # - # Emit a set of values - # - class Emitter - attr_accessor :options - def initialize( opts ) - opts = {} if opts.class != Hash - @options = YAML::DEFAULTS.dup.update( opts ) - @headless = 0 - @seq_map = false - @anchors = {} - @anchor_extras = {} - @active_anchors = [] - @level = -1 - self.clear - end - - def clear - @buffer = [] - end - - # - # Version string - # - def version_s - " %YAML:#{@options[:Version]}" if @options[:UseVersion] - end - - # - # Header - # - def header - if @headless.nonzero? - "" - else - "---#{version_s} " - 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 = '>' ) - 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 ) - 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 << "{}" - 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 ) - 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 - # - def <<( str ) - #p [ self.id, @level, str ] - @buffer.last << str - end - - # - # Monitor objects and allow references - # - def start_object( oid ) - @level += 1 - @buffer.push( "" ) - #p [ self.id, @level, :OPEN ] - idx = nil - if oid - if @anchors.has_key?( oid ) - idx = @active_anchors.index( oid ) - unless idx - idx = @active_anchors.length - af_str = "&#{@options[:AnchorFormat]} " % [ idx + 1 ] - af_str += @anchor_extras[ @anchors[ oid ] ].to_s - @buffer[ @anchors[ oid ] ][0,0] = af_str - @headless = 0 if @anchors[ oid ].zero? - end - idx += 1 - @active_anchors.push( oid ) - else - @anchors[ oid ] = @buffer.length - 1 - end - end - return idx - end - - # - # Output method - # - def end_object - @level -= 1 - @buffer.push( "" ) - #p [ self.id, @level, :END ] - if @level < 0 - YAML.internal_to_utf( header + @buffer.to_s[@headless..-1], @options[:Encoding] ) - end - 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 - - # - # Input methods - # - - # - # Load a single document from the current stream - # - def YAML.load( io ) - yp = YAML::Parser.new.parse( io ) - end - - # - # Parse a single document from the current stream - # - def YAML.parse( io ) - yp = YAML::Parser.new( :Model => :Generic ).parse( io ) - end - - # - # Load all documents from the current stream - # - def YAML.each_document( io, &doc_proc ) - yp = YAML::Parser.new.parse_documents( io, &doc_proc ) - end - - # - # Identical to each_document - # - def YAML.load_documents( io, &doc_proc ) - YAML.each_document( io, &doc_proc ) - end - - # - # Parse all documents from the current stream - # - def YAML.each_node( io, &doc_proc ) - yp = YAML::Parser.new( :Model => :Generic ).parse_documents( io, &doc_proc ) - end - - # - # Parse all documents from the current stream - # - def YAML.parse_documents( io, &doc_proc ) - YAML.each_node( io, &doc_proc ) - end - - # - # Load all documents from the current stream - # - def YAML.load_stream( io ) - yp = YAML::Parser.new - d = nil - yp.parse_documents( io ) { |doc| - d = YAML::Stream.new( yp.options ) if not d - d.add( doc ) - } - return d - end - - # - # Racc parser will go here - # - # class Parser; def initialize; raise YAML::Error, "No parser available"; end; end - - # - # Add a transfer method to a domain - # - def YAML.add_domain_type( domain, type_re, &transfer_proc ) - type_re = /^#{Regexp::quote( type_re )}$/ if type_re.class == String - if not YAML::TRANSFER_DOMAINS.has_key?( domain ) - YAML::TRANSFER_DOMAINS[ domain ] = {} - end - YAML::TRANSFER_DOMAINS[ domain ][ type_re ] = transfer_proc - end - - # - # Add a transfer method for a builtin type - # - def YAML.add_builtin_type( type_re, &transfer_proc ) - type_re = /^#{Regexp::quote( type_re )}$/ if type_re.class == String - YAML::TRANSFER_DOMAINS[ 'yaml.org,2002' ][ type_re ] = transfer_proc - end - - # - # Add a transfer method for a builtin type - # - def YAML.add_ruby_type( type, &transfer_proc ) - type_re = /^#{Regexp::quote( type.to_s )}(?::.+)?$/i - YAML::TRANSFER_DOMAINS[ 'ruby.yaml.org,2002' ][ type_re ] = transfer_proc - end - - # - # Add a private document type - # - def YAML.add_private_type( type_re, &transfer_proc ) - type_re = /^#{Regexp::quote( type_re )}$/ if type_re.class == String - YAML::PRIVATE_TYPES[ type_re ] = transfer_proc - end - - # - # Method to extract colon-seperated type and class, returning - # the type and the constant of the class - # - def YAML.read_type_class( type, obj_class ) - type =~ /^([^:]+):(.+)/i - if $2 - type = $1 - $2.split( "::" ).each { |c| - obj_class = obj_class.const_get( c ) - } - end - return [ type, obj_class ] - end - - # - # Default private type - # - class PrivateType - attr_accessor :type_id, :value - def initialize( type, val ) - @type_id = type; @value = val - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out << " !!#{@type_id}" - value.to_yaml( :Emitter => out ) - } - end - end - - # - # Default domain type - # - class DomainType - attr_accessor :domain, :type_id, :value - def initialize( domain, type, val ) - @domain = domain; @type_id = type; @value = val - end - def to_yaml_type - dom = @domain.dup - if dom =~ /\.yaml\.org,2002$/ - dom = $` - end - "#{dom}/#{@type_id}" - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out << " !#{to_yaml_type} " - value.to_yaml( :Emitter => out ) - } - end - end - - # - # Utility functions - # - - # - # Handle all transfer methods - # http://www.yaml.org/spec/#syntax-trans - # - def YAML.transfer_method( type, val ) - domain = "yaml.org,2002" - - # - # Figure out the domain - # - if type =~ /^(\w+)\/(.+)$/ - domain = "#{$1}.yaml.org,2002"; type = $2 - elsif type =~ /^(#{DNS_NAME_RE},\d{4}(?:-\d{2}){0,2})\/(.+)$/ - domain = $1; type = $2 - end - - # - # Route the data, transfer it - # - begin - r = nil - if type == "" - YAML.try_implicit( val ) - elsif type =~ /^!(.*)/ - type = $1 - if YAML::PRIVATE_TYPES.keys.detect { |r| type =~ r } - YAML::PRIVATE_TYPES[r].call( type, val ) - else - YAML::PrivateType.new( type, val ) - end - else - type = YAML.escape( type ) - if YAML::TRANSFER_DOMAINS.has_key?( domain ) and - YAML::TRANSFER_DOMAINS[domain].keys.detect { |r| type =~ r } - YAML::TRANSFER_DOMAINS[domain][r].call( type, val ) - else - YAML::DomainType.new( domain, type, val ) - end - end - end - end - - # - # Try a string against all implicit YAML types - # http://www.yaml.org/spec/#trans - # - def YAML.detect_implicit( str ) - r = nil - YAML::IMPLICIT_TYPES.each { |type| - if YAML::TRANSFER_DOMAINS['yaml.org,2002'].keys.detect { |r| type =~ r } - val = YAML::TRANSFER_DOMAINS['yaml.org,2002'][r].call( :Implicit, str ) - return type unless Symbol === val and val == :InvalidType - end - } - return 'str' - end - - # - # Uses the implicit if found - # - def YAML.try_implicit( str ) - type = YAML.detect_implicit( str ) - YAML.transfer_method( type, str ) - end - - # - # Make a time with the time zone - # - def YAML.mktime( year, mon, day, hour, min, sec, usec, zone = "Z" ) - usec = usec.to_s.to_f * 1000000 - val = Time::utc( year.to_i, mon.to_i, day.to_i, hour.to_i, min.to_i, sec.to_i, usec ) - if zone != "Z" - hour = zone[0,3].to_i * 3600 - min = zone[3,2].to_i * 60 - ofs = (hour + min) - val = Time.at( val.to_f - ofs ) - end - return val - end - - # - # Retrieve plain scalar regexp - # - def YAML.plain_re( allow = '' ) - space_set = '' - restrict_set = RESTRICTED_INDICATORS.delete( allow ) - restrict_set.split( // ).each { |ind| - if ind == "#" - space_set << "[^#\\s]#+|#+[^#\\s]|" - elsif SPACE_INDICATORS.include?( ind ) - ind = Regexp::quote( ind ) - space_set << "#{ind}+[^#{ind}\\s]|" - end - } - /\A([^#{NOT_PLAIN_CHAR}#{Regexp::quote(INDICATOR_CHAR)}](?:#{space_set}[^#{NOT_PLAIN_CHAR}#{Regexp::quote(restrict_set)}])*)/ - end - - # - # Escape the string, condensing common escapes - # - def YAML.escape( value ) - value.gsub( /\\/, "\\\\\\" ).gsub( /"/, "\\\"" ).gsub( /([\x00-\x1f])/ ) { |x| ESCAPES[ x.unpack("C")[0] ] } - end - - # - # Unescape the condenses escapes - # - def YAML.unescape( value ) - value.gsub( /\\(?:([nevbr\\fartz])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { |x| - if $3 - ["#$3".hex ].pack('U*') - elsif $2 - [$2].pack( "H2" ) - else - UNESCAPES[$1] - end - } - end - - # - # YAML::Stream -- for emitting many documents - # - class Stream - - attr_accessor :documents, :options - - def initialize( opts = {} ) - @options = opts - @documents = [] - end - - def []( i ) - @documents[ i ] - end - - def add( doc ) - @documents << doc - end - - def edit( doc_num, doc ) - @documents[ doc_num ] = doc - end - - def emit - opts = @options.dup - opts[:UseHeader] = true if @documents.length > 1 - ct = 0 - out = Emitter.new( opts ) - @documents.each { |v| - if ct > 0 - out << "\n--- " - end - v.to_yaml( :Emitter => out ) - ct += 1 - } - out.end_object - 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 - - # - # YAML::Store -- Pstore replacement - # - class Store < PStore - # - # Constructor - # - def initialize( *o ) - @opt = YAML::DEFAULTS.dup - if String === o.first - super(o.pop) - end - if o.last.is_a? Hash - @opt.update(o.pop) - end - end - - # - # Override Pstore#transaction - # - def transaction - raise YAML::Error, "nested transaction" if @transaction - raise YAML::Error, "no filename for transaction" unless @filename - begin - @transaction = true - value = nil - backup = @filename+"~" - if File::exist?(@filename) - file = File::open(@filename, "rb+") - orig = true - else - @table = {} - file = File::open(@filename, "wb+") - file.write( @table.to_yaml( @opt ) ) - end - file.flock(File::LOCK_EX) - if orig - File::copy @filename, backup - @table = YAML::load( file ) - end - begin - catch(:pstore_abort_transaction) do - value = yield(self) - end - rescue Exception - @abort = true - raise - ensure - unless @abort - begin - file.rewind - file.write( @table.to_yaml( @opt ) ) - file.truncate(file.pos) - rescue - File::rename backup, @filename if File::exist?(backup) - raise - end - end - @abort = false - end - ensure - @table = nil - @transaction = false - file.close if file - end - value - end - end - - # - # YAML Hash class to support comments and defaults - # - class SpecialHash < Hash - attr_accessor :default - def inspect - self.default.to_s - end - def to_s - self.default.to_s - end - def update( h ) - if YAML::SpecialHash === h - @default = h.default if h.default - end - super( h ) - end - def to_yaml( opts = {} ) - opts[:DefaultKey] = self.default - super( opts ) - end - end - - # - # Builtin collection: !omap - # - class Omap < Array - def self.[]( *vals ) - o = Omap.new - 0.step( vals.length - 1, 2 ) { |i| - o[vals[i]] = vals[i+1] - } - o - end - def []( k ) - self.assoc( k ).to_a[1] - end - def []=( k, *rest ) - val, set = rest.reverse - if ( tmp = self.assoc( k ) ) and not set - tmp[1] = val - else - self << [ k, val ] - end - val - end - def has_key?( k ) - self.assoc( k ) ? true : false - end - def is_complex_yaml? - true - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out.seq( "!omap" ) { |seq| - self.each { |v| - seq.add( Hash[ *v ] ) - } - } - } - end - end - - YAML.add_builtin_type( "omap" ) { |type, val| - if Array === val - p = Omap.new - val.each { |v| - if Hash === v - p.concat( v.to_a ) # Convert the map to a sequence - else - raise YAML::Error, "Invalid !omap entry: " + val.inspect - end - } - else - raise YAML::Error, "Invalid !omap: " + val.inspect - end - p - } - - # - # Builtin collection: !pairs - # - class Pairs < Array - def self.[]( *vals ) - p = Pairs.new - 0.step( vals.length - 1, 2 ) { |i| - p[vals[i]] = vals[i+1] - } - p - end - def []( k ) - self.assoc( k ).to_a - end - def []=( k, val ) - self << [ k, val ] - val - end - def has_key?( k ) - self.assoc( k ) ? true : false - end - def is_complex_yaml? - true - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out.seq( "!pairs" ) { |seq| - self.each { |v| - seq.add( Hash[ *v ] ) - } - } - } - end - end - - YAML.add_builtin_type( "pairs" ) { |type, val| - if Array === val - p = Pairs.new - val.each { |v| - if Hash === v - p.concat( v.to_a ) # Convert the map to a sequence - else - raise YAML::Error, "Invalid !pairs entry: " + val.inspect - end - } - else - raise YAML::Error, "Invalid !pairs: " + val.inspect - end - p - } - - # - # Builtin collection: !set - # - class Set < Hash - def to_yaml_type - "!set" - end - end - - YAML.add_builtin_type( 'set' ) { |type, val| - if Array === val - val = Set[ *val ] - elsif Hash === val - Set[ val ] - else - raise YAML::Error, "Invalid map explicitly tagged !map: " + val.inspect - end - val - } - - # - # Ruby-specific collection: !ruby/flexhash - # - class FlexHash < Array - def []( k ) - self.assoc( k ).to_a[1] - end - def []=( k, *rest ) - val, set = rest.reverse - if ( tmp = self.assoc( k ) ) and not set - tmp[1] = val - else - self << [ k, val ] - end - val - end - def has_key?( k ) - self.assoc( k ) ? true : false - end - def is_complex_yaml? - true - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out.seq( "!ruby/flexhash" ) { |seq| - self.each { |v| - if v[1] - seq.add( Hash.[]( *v ) ) - else - seq.add( v[0] ) - end - } - } - } - end - end - - YAML.add_ruby_type( :flexhash ) { |type, val| - if Array === val - p = FlexHash.new - val.each { |v| - if Hash === v - p.concat( v.to_a ) # Convert the map to a sequence - else - p << [ v, nil ] - end - } - p - else - raise YAML::Error, "Invalid !ruby/flexhash: " + val.inspect - end - } - -end - -# -# Type conversions -# -class Object - def is_complex_yaml? - true - end - def to_yaml_type - "!ruby/object:#{self.class}" - end - def to_yaml_properties - instance_variables.sort - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - out.map( self.to_yaml_type ) { |map| - to_yaml_properties.each { |m| - map.add( m[1..-1], instance_eval( m ) ) - } - } - } - end -end - -class Class - def new_without_initialize( *args ) - self.class_eval %{ - alias :old_initialize_with_args :initialize - def initialize( *args ); end - } - begin - result = self.new( *args ) - ensure - self.class_eval %{ - alias :initialize :old_initialize_with_args - } - end - result - end -end - -YAML.add_ruby_type( Object ) { |type, val| - type, obj_class = YAML.read_type_class( type, Object ) - YAML.object_maker( obj_class, val ) -} - -# -# Maps: Hash#to_yaml -# -class Hash - def is_complex_yaml? - true - end - def to_yaml_type - if self.class == Hash or self.class == YAML::SpecialHash - "!map" - else - "!ruby/hash:#{self.class}" - end - end - def to_yaml( opts = {} ) - opts[:DocType] = self.class if Hash === opts - YAML::quick_emit( self.id, opts ) { |out| - hash_type = to_yaml_type - if not out.options[:ExplicitTypes] and hash_type == "!map" - hash_type = "" - end - out.map( hash_type ) { |map| - # - # Sort the hash - # - if out.options[:SortKeys] - map.concat( self.sort ) - else - map.concat( self.to_a ) - end - } - } - end -end - -hash_proc = Proc.new { |type, val| - if Array === val - val = Hash.[]( *val ) # Convert the map to a sequence - elsif Hash === val - type, obj_class = YAML.read_type_class( type, Hash ) - if obj_class != Hash - o = obj_class.new - o.update( val ) - val = o - end - else - raise YAML::Error, "Invalid map explicitly tagged !map: " + val.inspect - end - val -} -YAML.add_builtin_type( /^map/, &hash_proc ) -YAML.add_ruby_type( Hash, &hash_proc ) - -# -# Structs: export as a !map -# -class Struct - def is_complex_yaml? - true - end - def to_yaml( opts = {} ) - YAML::quick_emit( self.id, opts ) { |out| - # - # Basic struct is passed as a YAML map - # - struct_name = self.class.name.gsub( "Struct:", "" ) - out.map( "!ruby/struct#{struct_name}" ) { |map| - self.members.each { |m| - map.add( m, self[m] ) - } - } - } - end -end - -YAML.add_ruby_type( Struct ) { |type, val| - type =~ /^struct:(\w+)/ - if Hash === val - type = $1 - struct_type = nil - struct_def = [] - struct_name = "" - if $1.to_s.length > 1 - struct_name = $1[0..$1.length] - struct_def << struct_name - end - - # - # Use existing Struct if it exists - # - begin - struct_type = Struct.const_get( struct_name ) - rescue NameError - end - if not struct_type - struct_type = Struct.new( *struct_def.concat( val.keys.collect { |k| k.intern } ) ) - end - - # - # Set the Struct properties - # - st = struct_type.new - st.members.each { |m| - st.send( "#{m}=", val[m] ) - } - st - else - raise YAML::Error, "Invalid Ruby Struct: " + val.inspect - end -} - -# -# Sequences: Array#to_yaml -# -class Array - def is_complex_yaml? - true - end - def to_yaml_type - if self.class == Array - "!seq" - else - "!ruby/array:#{self.class}" - end - end - def to_yaml( opts = {} ) - opts[:DocType] = self.class if Hash === opts - YAML::quick_emit( self.id, opts ) { |out| - array_type = to_yaml_type - if not out.options[:ExplicitTypes] and array_type == "!seq" - array_type = "" - end - - out.seq( array_type ) { |seq| - seq.concat( self ) - } - } - end -end - -array_proc = Proc.new { |type, val| - if Array === val - type, obj_class = YAML.read_type_class( type, Array ) - if obj_class != Array - o = obj_class.new - o.concat( val ) - val = o - end - val - else - val.to_a - end -} -YAML.add_builtin_type( /^seq/, &array_proc ) -YAML.add_ruby_type( Array, &array_proc ) - -# -# String#to_yaml -# -class String - def is_complex_yaml? - ( self =~ /\n.+/ ? true : false ) - end - def is_binary_data? - ( self.count( "^ -~", "^\r\n" ) / self.size > 0.3 || self.count( "\x00" ) > 0 ) - end - def to_yaml( opts = {} ) - complex = false - if self.is_complex_yaml? - complex = true - elsif opts[:BestWidth].to_i > 0 - if self.length > opts[:BestWidth] and opts[:UseFold] - complex = true - end - end - YAML::quick_emit( complex ? self.id : nil, opts ) { |out| - if complex - if self.is_binary_data? - out.binary_base64( self ) - else - out.node_text( self ) - end - else - ostr = if out.options[:KeepValue] - self - elsif empty? - "''" - elsif YAML.detect_implicit( self ) != 'str' - "\"#{YAML.escape( self )}\"" - elsif self =~ /#{YAML::ESCAPE_CHAR}|[#{YAML::SPACE_INDICATORS}] |\n|\'/ - "\"#{YAML.escape( self )}\"" - elsif self =~ /^[^#{YAML::WORD_CHAR}]/ - "\"#{YAML.escape( self )}\"" - else - self - end - out.simple( ostr ) - end - } - end -end - -YAML.add_builtin_type( 'str' ) { |type,val| val.to_s } -YAML.add_builtin_type( 'binary' ) { |type,val| - enctype = "m" - if String === val - val.gsub( /\s+/, '' ).unpack( enctype )[0] - else - raise YAML::Error, "Binary data must be represented by a string: " + val.inspect - end -} - -# -# Symbol#to_yaml -# -class Symbol - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - YAML::quick_emit( nil, opts ) { |out| - out << "!ruby/sym " - self.id2name.to_yaml( :Emitter => out ) - } - end -end - -symbol_proc = Proc.new { |type, val| - if String === val - val.intern - else - raise YAML::Error, "Invalid Symbol: " + val.inspect - end -} -YAML.add_ruby_type( Symbol, &symbol_proc ) -YAML.add_ruby_type( :sym, &symbol_proc ) - -# -# Range#to_yaml -# -class Range - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - YAML::quick_emit( nil, opts ) { |out| - out << "!ruby/range " - self.inspect.to_yaml( :Emitter => out ) - } - end -end - -YAML.add_ruby_type( Range ) { |type, val| - if String === val and val =~ /^(.*[^.])(\.{2,3})([^.].*)$/ - r1, rdots, r2 = $1, $2, $3 - Range.new( YAML.try_implicit( r1 ), YAML.try_implicit( r2 ), rdots.length == 3 ) - elsif Hash === val - Range.new( val['begin'], val['end'], val['exclude_end?'] ) - else - raise YAML::Error, "Invalid Range: " + val.inspect - end -} - -# -# Make an RegExp -# -class Regexp - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - YAML::quick_emit( nil, opts ) { |out| - out << "!ruby/regexp " - self.inspect.to_yaml( :Emitter => out ) - } - end -end - -regexp_proc = Proc.new { |type, val| - if String === val and val =~ /^\/(.*)\/([mix]*)$/ - val = { 'REGEXP' => $1, 'MODIFIERS' => $2 } - end - if Hash === val - mods = nil - unless val['MODIFIERS'].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 - end - Regexp::compile( val['REGEXP'], mods ) - else - raise YAML::Error, "Invalid Regular expression: " + val.inspect - end -} -YAML.add_domain_type( "perl.yaml.org,2002", /^regexp/, ®exp_proc ) -YAML.add_ruby_type( Regexp, ®exp_proc ) - -# -# Emit a Time object as an ISO 8601 timestamp -# -class Time - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - YAML::quick_emit( nil, opts ) { |out| - tz = "Z" - # from the tidy Tobias Peters 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 - ( self.strftime( "%Y-%m-%d %H:%M:%S." ) + - "%06d %s" % [usec, tz] ). - to_yaml( :Emitter => out, :KeepValue => true ) - } - end -end - -YAML.add_builtin_type( 'time' ) { |type, val| - if val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[Tt](\d{2})\:(\d{2})\:(\d{2})(\.\d{1,2})?(Z|[-+][0-9][0-9](?:\:[0-9][0-9])?)\Z/ - YAML.mktime( *$~.to_a[1,8] ) - elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[ \t]+(\d{2})\:(\d{2})\:(\d{2})(\.\d+)?[ \t]+(Z|[-+][0-9][0-9](?:\:[0-9][0-9])?)\Z/ - YAML.mktime( *$~.to_a[1,8] ) - elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})[ \t]+(\d{2})\:(\d{2})\:(\d{2})(\.\d{1,2})?\Z/ - YAML.mktime( *$~.to_a[1,7] ) - elsif val =~ /\A(\d{4})\-(\d{1,2})\-(\d{1,2})\Z/ - Date.new($1.to_i, $2.to_i, $3.to_i) - elsif type == :Implicit - :InvalidType - else - raise YAML::TypeError, "Invalid !time string: " + val.inspect - end -} - -# -# Emit a Date object as a simple implicit -# -class Date - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - opts[:KeepValue] = true - self.to_s.to_yaml( opts ) - end -end - -# -# Send Integer, Booleans, NilClass to String -# -class Numeric - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - str = self.to_s - if str == "Infinity" - str = ".Inf" - elsif str == "-Infinity" - str = "-.Inf" - elsif str == "NaN" - str = ".NaN" - end - opts[:KeepValue] = true - str.to_yaml( opts ) - end -end - -YAML.add_builtin_type( 'float' ) { |type, val| - if val =~ /\A[-+]?[\d][\d,]*\.[\d,]*[eE][-+][0-9]+\Z/ # Float (exponential) - $&.tr( ',', '' ).to_f - elsif val =~ /\A[-+]?[\d][\d,]*\.[\d,]*\Z/ # Float (fixed) - $&.tr( ',', '' ).to_f - elsif val =~ /\A([-+]?)\.(inf|Inf|INF)\Z/ # Float (english) - ( $1 == "-" ? -1.0/0.0 : 1.0/0.0 ) - elsif val =~ /\A\.(nan|NaN|NAN)\Z/ - 0.0/0.0 - elsif type == :Implicit - :InvalidType - else - val.to_f - end -} - -YAML.add_builtin_type( 'int' ) { |type, val| - if val =~ /\A[-+]?0[0-7,]+\Z/ # Integer (octal) - $&.oct - elsif val =~ /\A[-+]?0x[0-9a-fA-F,]+\Z/ # Integer (hex) - $&.hex - elsif val =~ /\A[-+]?\d[\d,]*\Z/ # Integer (canonical) - $&.tr( ',', '' ).to_i - elsif val =~ /\A([-+]?)(\d[\d,]*(?::[0-5]?[0-9])+)\Z/ - sign = ( $1 == '-' ? -1 : 1 ) - digits = $2.split( /:/ ).collect { |x| x.to_i } - val = 0; digits.each { |x| val = ( val * 60 ) + x }; val *= sign - elsif type == :Implicit - :InvalidType - else - val.to_i - end -} - -class TrueClass - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - opts[:KeepValue] = true - "true".to_yaml( opts ) - end -end - -class FalseClass - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - opts[:KeepValue] = true - "false".to_yaml( opts ) - end -end - -YAML.add_builtin_type( 'bool' ) { |type, val| - if val =~ /\A(\+|true|True|TRUE|yes|Yes|YES|on|On|ON)\Z/ - true - elsif val =~ /\A(\-|false|False|FALSE|no|No|NO|off|Off|OFF)\Z/ - false - elsif type == :Implicit - :InvalidType - else - raise YAML::TypeError, "Invalid !bool string: " + val.inspect - end -} - -class NilClass - def is_complex_yaml? - false - end - def to_yaml( opts = {} ) - opts[:KeepValue] = true - "".to_yaml( opts ) - end -end - -YAML.add_builtin_type( 'null' ) { |type, val| - if val =~ /\A(\~|null|Null|NULL)\Z/ - nil - elsif val.empty? - nil - elsif type == :Implicit - :InvalidType - else - raise YAML::TypeError, "Invalid !null string: " + val.inspect - end -} - -# -# ryan: You know how Kernel.p is a really convenient way to dump ruby -# structures? The only downside is that it's not as legible as -# YAML. -# -# _why: (listening) -# -# ryan: I know you don't want to urinate all over your users' namespaces. -# But, on the other hand, convenience of dumping for debugging is, -# IMO, a big YAML use case. -# -# _why: Go nuts! Have a pony parade! -# -# ryan: Either way, I certainly will have a pony parade. -# -module Kernel - def y( x ) - puts x.to_yaml - end -end - -# -# Example of using YAML to replace PStore -# -if __FILE__ == $0 - y = YAML::Store.new( "/tmp/yaml.store.1", :Indent => 2, - :UseHeader => true, :UseVersion => true ) - y.transaction do - y['names'] = ['Steve', 'Jonathan', 'Tom'] - y['hello'] = {'hi' => 'hello', 'yes' => 'YES!!' } - end -end - -# -# Example of using YAML::Stream -# -# a = "File ID" -# y = YAML::Stream.new( :Indent => 2, :UseVersion => 0 ) -# y.add( {'hi2' => 'hello', 'map' => {'good' => 'two'}, 'time' => Time.now, 'try' => /^po(.*)$/, 'bye' => 'goodbye' } ) -# y.add( {'po' => nil, 'oper' => 90 } ) -# y.add( {'hi' => 'wow!', 'bye' => 'wow!'} ) -# y.add( {['Red Socks','Boston'] => ['One', 'Two', 'Three']} ) -# y.add( [true, false, false] ) # This should use aliases -# puts y.emit - -# -# Example of loading a YAML document -# -# obj = YAML::load( "/tmp/yaml.store.1" ) - -# -# Examples of using #to_yaml -# -# puts [1, 2, 3, nil, 'hello', "Glow all!", 'hi', Time.now, /^po(.*)/im ].to_yaml( :UseBlock => true ) -# puts Hash['hi', 'hello', 'time', Time.now, 'try', /^po(.*)$/, 'bye', 'goodbye' ].to_yaml -# puts [ -# {'hi' => 'hello', 'time' => Time.now, 'try' => /^po(.*)$/, 'bye' => 'goodbye' }, -# {'po' => nil, 'oper' => 90 }, -# {'hi' => 'wow!', 'bye' => 'wow!'} ].to_yaml - - -..end src/emitter.rb modeval..iddd2784be19 +include_class "org.jruby.yaml.JRubyConstructor" +include_class "org.jruby.util.IOReader" +include_class "org.jvyaml.ComposerImpl" +include_class "org.jvyaml.ParserImpl" +include_class "org.jvyaml.ScannerImpl" +include_class "org.jvyaml.ResolverImpl" module YAML - - class Parser < Racc::Parser - -module_eval <<'..end src/yaml.y.rb modeval..idae682a68eb', 'src/yaml.y.rb', 140 - -attr_accessor :finished, :directives, :options - -# -# Reset the directives, EOF flag -# -def initialize( opts = {} ) - @directives = { 'YAML' => '1.0', 'TAB' => 'NONE' } - @options = YAML::DEFAULTS.dup.update( opts ) - @finished = false - @plain_sets = { - :AllowInline => YAML.plain_re( ',}]' ), - :AllowMapping => YAML.plain_re( ':' ), - :AllowNone => YAML.plain_re - } -end - -# -# Iterator for parsing many documents -# -def parse_documents( io, &doc_proc ) - @stream = YAML.make_stream( io ) - @lineno = 0 - @charno = 0 - @leftovers = nil - @options[:Encoding] = @stream.utf_encoding - while true - o = _parse - doc_proc.call( o ) - break if @finished - end -end - -# -# Basic single document parsing -# -def parse( io ) - @stream = YAML.make_stream( io ) - @lineno = 0 - @charno = 0 - @leftovers = nil - @options[:Encoding] = @stream.utf_encoding - _parse -end - -# -# Common tokenizer and parser -# -def _parse - - # - # Parser instance variables - # - @anchor = {} - @lvl = [ Level.new( -1, :Implicit, "" ) ] - @separator = nil - @last_tokens = [] - @plain_set = @plain_sets[ :AllowInline ] - - reset_indent - reset_tokens - - # Tokenizer - do_tokenize - - @finished = true if eof? and @leftovers.nil? - return nil if @q.length.zero? - - add_end_indent -1 - close_tokens - - # @q.each { |tok| - # p [ tok.sym, tok.data ] - # } - - # Parser - begin - do_parse - rescue Racc::ParseError => rpe - token = @last_tokens.last - raise YAML::ParseError, "Parse error at line #{token.lineno}, char #{token.charno}: [#{token.sym}, #{token.data}]" - end -end - -def do_tokenize - until eof? and @leftovers.nil? do - if @leftovers - yline = @leftovers - @leftovers = nil - else -# ENEBO: readline returns nil instead of "". I wonder if this is a ruby behavioral change thing - yline = readline - yline.chomp! if yline - end - handle_indent( yline ) - until !yline || yline.empty? do - handle_content( yline ) - if [ :End, :Pause ].include?( @lvl.last.status ) - @leftovers = yline - return - end - end - end -end - -def handle_indent( yline ) - if ( indt_match = @lvl.last.indent_re.match( yline ) ) - @indent_raw << "\n" + indt_match[0] - case indt_match[2] - when /^#/ - yline.replace "" - when /^-/ - @indent << "\n" + yline.slice!( 0, indt_match[1].length ) + " " - @charno += indt_match[1].length - else - @indent << "\n" + yline.slice!( 0, indt_match[0].length ) - @charno += indt_match[0].length - end - end -end - -def handle_content( yline ) - if @charno == 1 - case yline - when /\A---( |$)/ - if @q.length.zero? - reset_indent - @lvl.last.status = :Header - @charno += $&.length - yline.replace $' - else - @lvl.last.status = :End - end - return - when /\A\.\.\.( |$)/ - @lvl.last.status = :Pause - @charno += $&.length - yline.replace $' - return - end - elsif @lvl.last.status == :Header - if yline =~ /\A%(\w+):(\S+)/ - @directives[$1] = $2 - case $1 - when "YAML" - @options[:Version] = $2 - @options[:UseVersion] = true - end - len = $&.length - yline.slice!( 0, len ) - @charno += len - return - else - @lvl.last.status = :Implicit - end - end - if @lvl.last.status != :Block or @q.last.sym == :FSTART - case yline - when /\A#/ - # Throwaway comments - yline.replace "" - return - when /\A +/ - # Throwaway space - len = $&.length - yline.slice!( 0, len ) - @charno += len - return - end - end - apply_indent - if @lvl.last.status == :Block - add_token :FOLD, yline - yline.replace "" - return - end - len = 0 - case yline - when /\A[#{ Regexp::quote( SPACE_INDICATORS ) }]( |$)/ - # Space indicators - len = $&.length - c = yline[ 0, 1 ] - if @lvl.last.status == :Inline - if c == ':' - @plain_set = @plain_sets[ :AllowMapping ] - elsif c == ',' - @plain_set = @plain_sets[ :AllowNone ] - end - else - if c == ':' - @plain_set = @plain_sets[ :AllowInline ] - elsif c == '-' - handle_seq_shortcuts - if @q[-1] and [ :INDENT, :IOPEN, :IEND ].include?( @q[-1] ) - @lvl.last.spaces = @charno + 1 - @q.last.data = @charno + 1 - end - end - end - add_token c, c - when /\A([>|])([-+\d]*)/ - len = $&.length - fold = $& - fold_type = $1 - @lvl.push Level.new( @lvl.last.spaces + 1, :Block, fold_type == "|" ? :Literal : :Folded ) - @q.push Token.new( :IOPEN, @lvl.last.spaces, @lineno, 1 ) - add_token :FSTART, fold - when /\A([{\[])/ - len = $&.length - tok = $& - @lvl.push Level.new( @lvl.last.spaces + 2, :Inline, @lvl.last.domain ) - @plain_set = @plain_sets[ :AllowNone ] - add_token tok, tok - when /\A([}\]])/ - len = $&.length - tok = $& - @lvl.pop - @plain_set = @plain_sets[ :AllowInline ] - add_token tok, tok - when /\A&(\w+)/ - len = $&.length - add_token :ANCHOR, $1 - when /\A\*(\w+)/ - len = $&.length - add_token :ALIAS, $1 - when /\A!(\S*)/ - len = $&.length - ttype = $1 - if ttype =~ /(.*)\^(.+)/ - if $1.length > 0 - @lvl.last.domain = $1 - ttype = $1 + $2 - else - ttype = @lvl.last.domain + $2 - end - end - add_token :TRANSFER, ttype - when /\A"((?:\\\"|[^\n"])*)/ - handle_seq_shortcuts - len = $&.length - yline.slice!( 0, len ) - @charno += len - qstr = $1.to_s - qstr_indt = "+" - while yline[0,1] != '"' - if qstr[-1,1] == "\\" - qstr = qstr.chop! - else - qstr << " " - end - yline = readline - yline =~ /\A(\s#{qstr_indt})((?:\\\"|[^\n"])*)/ - len = $&.to_s.length - yline.slice!( 0, len ) - @charno += len - qstr << $2.to_s - end - len = 1 - add_token :WORD, YAML.unescape(qstr.gsub( /\\"/, '"' )) - when /\A'((?:''|[^\n'])*)/ - handle_seq_shortcuts - len = $&.length - yline.slice!( 0, len ) - @charno += len - qstr = $1.to_s - qstr_indt = "+" - nl_mode = false - while yline[0,1] != "'" - qstr << " " if qstr[-1,1] != "\n" - yline = readline - yline =~ /\A(\s#{qstr_indt})((?:''|[^\n'])*)/ - qstr_indt = "{0,#{$1.length}}" if qstr_indt == "+" - inner_str = $2.to_s.strip - if inner_str == "" - qstr = ( nl_mode ? qstr : qstr[0..-2] ) + "\n" - nl_mode = true - else - qstr << $2 - nl_mode = false - end - len = $&.to_s.length - yline.slice!( 0, len ) - @charno += len - end - len = 1 - add_token :WORD, qstr.gsub( "''", "'" ) - when @plain_set - handle_seq_shortcuts - len = $&.length - match = $&.strip - if @q.last and @q.last.sym == :PLAIN - @q.last.data += " " if @q.last.data !~ /\Z\n/ - @q.last.data += match - else - add_token :PLAIN, match - end - else - handle_seq_shortcuts - len = 1 - c = yline[ 0, 1 ] - add_token c, c - end - yline.slice!( 0, len ) - @charno += len -end - -def handle_seq_shortcuts - if @q[-1] and @q[-1].sym == '-' and @q[-2] and [:IOPEN, :INDENT, :IEND].include?( @q[-2].sym ) - # Check the current level and indent to match the dash - @lvl.last.spaces = @q[-1].charno - @q[-2].data = @q[-1].charno - # Add open indent after the dash - @lvl.push Level.new( @charno - 1, @lvl.last.status, @lvl.last.domain ) - @q.push Token.new( :IOPEN, @charno - 1, @lineno, @charno ) - end -end - -# -# Level descent class added 2002 Dec 31 -# The levels of indentation are tracked using this class. -# Each level has an indentation space count, a status field -# indicating what sort of data is contained at this depth, -# and the domain anchored at this depth. -# -class Level - attr_accessor :spaces, :status, :domain - def initialize( ct, s, d ) - @spaces, @status, @domain = ct, s, d - end - def indent_re - if @status == :Block - if @spaces > 0 - /\A( {0,#{ @spaces - 1 }})(#[^\n]+|-( +(?!:)|$)| *)?/ - else - /\A( *)(#[^\n]+)?/ - end - else - /\A( *)(#[^\n]+|-( +(?!:)|$))?/ - end - end -end - -# -# Token class added 2002 Dec 26. -# Thanks to this class, we can now track line numbers -# and store accessory data to our tokens. This should -# eventually assist our emitter in reforming a document -# in its original form. -# -class Token - attr_accessor :sym, :data, :lineno, :charno - def initialize( s, d, ln, cn ) - @sym, @data, @lineno, @charno = s, d, ln, cn - end -end - -# -# Token stack ops -# -def reset_indent - @indent, @indent_raw = "", "" -end - -def reset_tokens - @q = [] -end - -def add_token( sym, data ) - if sym == :FOLD - if @q.last.sym != :FOLD - raise YAML::Error, "Improper fold!!" - end - if @q.last.data =~ / \Z/ - @lvl.last.domain = :FoldIndt if @lvl.last.domain == :Folded - elsif @lvl.last.domain == :Folded - @q.last.data.gsub!( /\n\Z\n/, "\n" ) unless @q.last.data.gsub!( /(.)\Z\n/, '\1 ' ) - elsif @lvl.last.domain == :FoldIndt - @lvl.last.domain = :Folded - end - @q.last.data += data + def self.load( io ) + if String === io + ctor = JRubyConstructor.new(self,ComposerImpl.new(ParserImpl.new(ScannerImpl.new(io)),ResolverImpl.new)) else - @q.push Token.new( sym, data, @lineno, @charno ) + ctor = JRubyConstructor.new(self,ComposerImpl.new(ParserImpl.new(ScannerImpl.new(IOReader.new(io))),ResolverImpl.new)) end -end - -def apply_indent - # Turn indent into a token - unless @indent.empty? - indt_len = /^ *\Z/.match( @indent )[0].length - if @lvl.last.status == :Block and @q.last.sym == :FOLD - add_fold_indent - end - if @lvl.last.spaces > indt_len - add_end_indent indt_len - end - if @lvl.last.status == :Block - fold_txt = "" - if @q.last.sym == :FSTART - if @q.last.data =~ /(\d+)/ - if @lvl.last.spaces > 0 - @lvl.last.spaces -= 1 - end - indt_len = $1.to_i + @lvl.last.spaces - end - @lvl.last.spaces = indt_len - @q.push Token.new( :FOLD, fold_txt, @lineno, 1 ) - @indent.slice!( 0, 1 ) - add_fold_indent - end - else - indt_type = :INDENT - if @lvl.last.spaces < indt_len - indt_type = :IOPEN - end - if @q.last and @q.last.sym == :PLAIN and ( indt_type == :IOPEN or - ( @lvl.last.spaces == indt_len and @q[-2] and @q[-2].sym == :IOPEN ) ) - unless @q.last.data.empty? - @q.last.data += @indent_raw.gsub( /^ +/, '' ).gsub( /\n(\n*)/, '\1' ) - end - elsif @lvl.last.status != :Inline - @plain_set = @plain_sets[ :AllowInline ] - if indt_type == :IOPEN - @lvl.push Level.new( indt_len, @lvl.last.status, @lvl.last.domain ) - end - @q.push Token.new( indt_type, indt_len, @lineno, 1 ) - end - end - reset_indent - end -end - -def close_tokens - @q.push Token.new( false, '$', @lineno, @charno ) -end - -def pop_token - @q.pop -end - -def push_token( tok ) - @q.push tok -end - -# -# Used by Racc -# The @last_token stored for error_reporting -# -def next_token - @last_tokens.push @q.first - if @last_tokens.length > 5 - @last_tokens.shift - end - tok = @q.shift - [ tok.sym, tok.data ] -end - -def add_end_indent( indt_len ) - while @lvl.last.spaces > indt_len - @q.push Token.new( :IEND, @lvl.pop.spaces, @lineno, 1 ) - end -end - -# -# Keep line number count -# -def readline - @lineno += 1 - @charno = 1 - begin - @stream.readline - rescue IOError - end -end - -def eof?; @stream.eof?; end - -# -# Handle Hash special keys -# -def hash_update( h, item ) - if item.class == Array - # if h.class != YAML::SpecialHash - # h = YAML::SpecialHash.new.update( h ) - # end - if item[0] == :MERGE - if Hash === item[1] - h.update( item[1] ) - elsif Array === item[1] - item[1].flatten.reverse.each { |hmerge| - h.update( hmerge ) - } - end - elsif item[0] == :DEFAULT - h.default = item[1] - # elsif item[0] == :COMMENT - # h.comment = item[1] - end - elsif item.class == YAML::SpecialHash - h = item.update( h ) - elsif item.is_a? Hash - h.update( item ) - else - raise YAML::Error, "Invalid update to Hash with item: " + item.inspect - end - return h -end - -def attach_transfer( meth, val ) - meth = YAML.unescape( meth ) - if @options[:Model] == :Generic - val.type_id = meth - val - else - YAML.transfer_method( meth, val ) - end -end - -# -# Add a new node -# -def new_node( type_id, val ) - if @options[:Model] == :Generic - val = YamlNode.new( type_id, val ) - end - val -end - -# -# Take block text and format based on the block def characters -# -def process_block( fold_type, fold_text ) - fold_text.chomp! if fold_type.include?( '|' ) - if fold_type.include?( '+' ) - fold_text << "\n" - else - fold_text.chomp!( '' ) - if fold_type.include?( '-' ) - fold_text.chomp! - else - fold_text << "\n" - end - end - return fold_text -end - -def add_fold_indent - if @lvl.last.spaces > 0 - @indent.gsub!( /^ {0,#{ @lvl.last.spaces }}/, '' ) - end - @q.last.data += @indent -end - -def process_plain( p ) - if @options[:Model] == :Generic - new_node( YAML.detect_implicit( p ), p ) - else - YAML.try_implicit( p ) - end -end -..end src/yaml.y.rb modeval..idae682a68eb - -##### racc 1.4.3 generates ### - -racc_reduce_table = [ - 0, 0, :racc_error, - 1, 22, :_reduce_none, - 1, 22, :_reduce_none, - 2, 22, :_reduce_3, - 1, 22, :_reduce_4, - 1, 25, :_reduce_none, - 0, 25, :_reduce_6, - 2, 23, :_reduce_7, - 1, 23, :_reduce_8, - 1, 23, :_reduce_9, - 3, 23, :_reduce_10, - 2, 24, :_reduce_11, - 1, 24, :_reduce_none, - 1, 24, :_reduce_none, - 1, 24, :_reduce_none, - 3, 24, :_reduce_15, - 1, 24, :_reduce_none, - 1, 24, :_reduce_none, - 3, 24, :_reduce_18, - 4, 26, :_reduce_19, - 3, 26, :_reduce_20, - 3, 27, :_reduce_21, - 2, 32, :_reduce_22, - 1, 31, :_reduce_23, - 3, 31, :_reduce_24, - 3, 28, :_reduce_25, - 2, 28, :_reduce_26, - 1, 33, :_reduce_27, - 2, 33, :_reduce_28, - 3, 33, :_reduce_29, - 3, 29, :_reduce_30, - 3, 35, :_reduce_31, - 3, 35, :_reduce_32, - 1, 36, :_reduce_none, - 5, 36, :_reduce_34, - 1, 34, :_reduce_35, - 3, 34, :_reduce_36, - 3, 30, :_reduce_37, - 2, 30, :_reduce_38, - 1, 37, :_reduce_39, - 3, 37, :_reduce_40 ] - -racc_reduce_n = 41 - -racc_shift_n = 74 - -racc_action_table = [ - 4, 6, 8, 10, 12, 14, 59, 60, 52, 61, - 58, 3, 30, 10, 12, 34, 51, 15, 4, 6, - 8, 10, 12, 14, 68, 31, 44, 45, 42, 3, - 30, 10, 12, 34, 43, 15, 4, 6, 8, 10, - 12, 14, 50, 31, 33, 62, 49, 3, 20, 21, - 63, 54, 17, 15, 4, 6, 8, 10, 12, 14, - 30, 10, 12, 34, 57, 3, 30, 10, 12, 34, - 52, 15, 4, 6, 8, 10, 12, 14, 25, 31, - 70, 53, 72, 3, 30, 10, 12, 34, 51, 15, - 4, 6, 8, 10, 12, 14, nil, nil, nil, nil, - nil, 3, nil, nil, nil, nil, nil, 15, 4, 6, - 8, 10, 12, 14, nil, nil, nil, nil, nil, 3, - nil, nil, nil, nil, nil, 15, 4, 6, 8, 10, - 12, 14, nil, nil, nil, nil, nil, 3, nil, nil, - nil, nil, nil, 15, 4, 6, 8, 10, 12, 14, - nil, nil, nil, nil, nil, 3, nil, nil, nil, nil, - nil, 15, 4, 6, 8, 10, 12, 14, 8, 10, - 12, 14, nil, 3, nil, nil, nil, 3, nil, 15, - nil, nil, nil, 15, 30, 10, 12, 34, nil, 37, - nil, 25, nil, 3, nil, nil, nil, 31, 33, 15 ] - -racc_action_check = [ - 0, 0, 0, 0, 0, 0, 36, 37, 27, 37, - 36, 0, 15, 15, 15, 15, 27, 0, 53, 53, - 53, 53, 53, 53, 55, 15, 19, 19, 15, 53, - 49, 49, 49, 49, 17, 53, 3, 3, 3, 3, - 3, 3, 26, 49, 49, 41, 26, 3, 3, 3, - 41, 32, 1, 3, 4, 4, 4, 4, 4, 4, - 30, 30, 30, 30, 35, 4, 62, 62, 62, 62, - 56, 4, 51, 51, 51, 51, 51, 51, 58, 62, - 61, 31, 68, 51, 34, 34, 34, 34, 39, 51, - 45, 45, 45, 45, 45, 45, nil, nil, nil, nil, - nil, 45, nil, nil, nil, nil, nil, 45, 21, 21, - 21, 21, 21, 21, nil, nil, nil, nil, nil, 21, - nil, nil, nil, nil, nil, 21, 33, 33, 33, 33, - 33, 33, nil, nil, nil, nil, nil, 33, nil, nil, - nil, nil, nil, 33, 25, 25, 25, 25, 25, 25, - nil, nil, nil, nil, nil, 25, nil, nil, nil, nil, - nil, 25, 72, 72, 72, 72, 72, 72, 8, 8, - 8, 8, nil, 72, nil, nil, nil, 8, nil, 72, - nil, nil, nil, 8, 14, 14, 14, 14, nil, 14, - nil, 14, nil, 14, nil, nil, nil, 14, 14, 14 ] - -racc_action_pointer = [ - -2, 52, nil, 34, 52, nil, nil, nil, 164, nil, - nil, nil, nil, nil, 180, 8, nil, 34, nil, 12, - nil, 106, nil, nil, nil, 142, 34, 0, nil, nil, - 56, 65, 43, 124, 80, 56, -2, -1, nil, 72, - nil, 30, nil, nil, nil, 88, nil, nil, nil, 26, - nil, 70, nil, 16, nil, 12, 62, nil, 67, nil, - nil, 72, 62, nil, nil, nil, nil, nil, 66, nil, - nil, nil, 160, nil ] - -racc_action_default = [ - -41, -41, -1, -41, -41, -2, -4, -12, -41, -13, - -8, -14, -9, -16, -41, -41, -17, -41, -27, -41, - -26, -6, -3, -7, -11, -6, -41, -41, -33, -35, - -41, -41, -41, -41, -41, -41, -41, -41, -23, -41, - -39, -41, -38, 74, -25, -6, -5, -28, -22, -41, - -30, -6, -10, -6, -15, -41, -41, -18, -41, -21, - -20, -41, -41, -37, -29, -36, -31, -32, -41, -24, - -19, -40, -6, -34 ] - -racc_goto_table = [ - 23, 47, 40, 38, 29, 48, 27, 39, 36, 1, - 35, 19, 18, 22, 26, 32, 24, 41, nil, nil, - nil, nil, 23, nil, nil, 64, 56, nil, nil, nil, - nil, 66, nil, 67, nil, nil, nil, nil, nil, 65, - nil, 39, 55, nil, nil, nil, nil, 69, nil, 71, - nil, nil, 73, nil, 39 ] - -racc_goto_check = [ - 2, 4, 14, 11, 15, 4, 2, 2, 10, 1, - 9, 12, 1, 1, 13, 7, 3, 16, nil, nil, - nil, nil, 2, nil, nil, 4, 2, nil, nil, nil, - nil, 4, nil, 4, nil, nil, nil, nil, nil, 15, - nil, 2, 1, nil, nil, nil, nil, 11, nil, 14, - nil, nil, 4, nil, 2 ] - -racc_goto_pointer = [ - nil, 9, -8, 8, -20, nil, nil, 1, nil, -4, - -6, -11, 8, 0, -13, -10, 2 ] - -racc_goto_default = [ - nil, 46, 2, 5, nil, 7, 9, 11, 13, 16, - nil, nil, nil, nil, 28, nil, nil ] - -racc_token_table = { - false => 0, - Object.new => 1, - :ANCHOR => 2, - :ALIAS => 3, - :TRANSFER => 4, - :WORD => 5, - :PLAIN => 6, - :IOPEN => 7, - :IEND => 8, - :FSTART => 9, - :FOLD => 10, - "-" => 11, - :INDENT => 12, - "[" => 13, - "]" => 14, - "," => 15, - ":" => 16, - "=" => 17, - "?" => 18, - "{" => 19, - "}" => 20 } - -racc_use_result_var = true - -racc_nt_base = 21 - -Racc_arg = [ - racc_action_table, - racc_action_check, - racc_action_default, - racc_action_pointer, - racc_goto_table, - racc_goto_check, - racc_goto_default, - racc_goto_pointer, - racc_nt_base, - racc_reduce_table, - racc_token_table, - racc_shift_n, - racc_reduce_n, - racc_use_result_var ] - -Racc_token_to_s_table = [ -'$end', -'error', -'ANCHOR', -'ALIAS', -'TRANSFER', -'WORD', -'PLAIN', -'IOPEN', -'IEND', -'FSTART', -'FOLD', -'"-"', -'INDENT', -'"["', -'"]"', -'","', -'":"', -'"="', -'"?"', -'"{"', -'"}"', -'$start', -'atom', -'word_rep', -'struct_rep', -'atom_or_empty', -'scalar_block', -'implicit_seq', -'inline_seq', -'implicit_map', -'inline_map', -'in_implicit_seq', -'basic_seq', -'in_inline_seq', -'in_implicit_map', -'basic_mapping', -'complex_mapping', -'in_inline_map'] - -Racc_debug_parser = false - -##### racc system variables end ##### - - # reduce 0 omitted - - # reduce 1 omitted - - # reduce 2 omitted - -module_eval <<'.,.,', 'src/yaml.y.rb', 17 - def _reduce_3( val, _values, result ) - if @options[:Model] == :Generic - val[1].anchor = val[0] - end - result = @anchor[ val[0] ] = val[1] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 22 - def _reduce_4( val, _values, result ) - result = @anchor[ val[0] ] - result - end -.,., - - # reduce 5 omitted - -module_eval <<'.,.,', 'src/yaml.y.rb', 25 - def _reduce_6( val, _values, result ) - result = new_node( 'null', nil ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 32 - def _reduce_7( val, _values, result ) - result = attach_transfer( val[0], val[1] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 33 - def _reduce_8( val, _values, result ) - result = new_node( 'str', val[0] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 34 - def _reduce_9( val, _values, result ) - result = process_plain( val[0] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 35 - def _reduce_10( val, _values, result ) - result = val[1] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 41 - def _reduce_11( val, _values, result ) - result = attach_transfer( val[0], val[1] ) - result - end -.,., - - # reduce 12 omitted - - # reduce 13 omitted - - # reduce 14 omitted - -module_eval <<'.,.,', 'src/yaml.y.rb', 45 - def _reduce_15( val, _values, result ) - result = val[1] - result - end -.,., - - # reduce 16 omitted - - # reduce 17 omitted - -module_eval <<'.,.,', 'src/yaml.y.rb', 48 - def _reduce_18( val, _values, result ) - result = val[1] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 56 - def _reduce_19( val, _values, result ) - result = new_node( 'str', process_block( val[1], val[2] ) ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 60 - def _reduce_20( val, _values, result ) - result = new_node( 'str', '' ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 66 - def _reduce_21( val, _values, result ) - result = new_node( 'seq', val[1] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 68 - def _reduce_22( val, _values, result ) - result = val[1] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 70 - def _reduce_23( val, _values, result ) - result = val - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 73 - def _reduce_24( val, _values, result ) - result.push val[2] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 79 - def _reduce_25( val, _values, result ) - result = new_node( 'seq', val[1] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 80 - def _reduce_26( val, _values, result ) - result = new_node( 'seq', [] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 82 - def _reduce_27( val, _values, result ) - result = val - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 83 - def _reduce_28( val, _values, result ) - result = [ result = new_node( 'null', nil ), val[1] ] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 84 - def _reduce_29( val, _values, result ) - result.push val[2] - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 89 - def _reduce_30( val, _values, result ) - result = new_node( 'map', val[1] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 93 - def _reduce_31( val, _values, result ) - if val[0] == '<<' - result = [ :MERGE, val[2] ] - else - result = { val[0] => val[2] } - end - result + ctor.getData if ctor.checkData end -.,., -module_eval <<'.,.,', 'src/yaml.y.rb', 101 - def _reduce_32( val, _values, result ) - result = [ :DEFAULT, val[2] ] - result - end -.,., - - # reduce 33 omitted - -module_eval <<'.,.,', 'src/yaml.y.rb', 107 - def _reduce_34( val, _values, result ) - result = { val[1] => val[4] } - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 112 - def _reduce_35( val, _values, result ) - result = hash_update( {}, val[0] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 116 - def _reduce_36( val, _values, result ) - result = hash_update( val[0], val[2] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 122 - def _reduce_37( val, _values, result ) - result = new_node( 'map', val[1] ) - result - end -.,., - -module_eval <<'.,.,', 'src/yaml.y.rb', 123 - def _reduce_38( val, _values, result ) - result = new_node( 'map', Hash.new ) - result + def self.load_file( filepath ) + File.open( filepath ) do |f| + load( f ) + end end -.,., -module_eval <<'.,.,', 'src/yaml.y.rb', 127 - def _reduce_39( val, _values, result ) - result = hash_update( {}, val[0] ) - result + # Make YAML module to act exactly as RbYAML + def self.method_missing(name,*args) + RbYAML.send(name,*args) end -.,., -module_eval <<'.,.,', 'src/yaml.y.rb', 131 - def _reduce_40( val, _values, result ) - result = hash_update( val[0], val[2] ) - result + def self.const_missing(name) + RbYAML.const_get(name) end -.,., - - def _reduce_none( val, _values, result ) - result - end - - end # class Parser - -end # module YAML +end diff --git a/src/org/jruby/util/IOReader.java b/src/org/jruby/util/IOReader.java new file mode 100644 index 00000000000..f751d8c8e3f --- /dev/null +++ b/src/org/jruby/util/IOReader.java @@ -0,0 +1,71 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Common Public + * License Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2006 Ola Bini + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id$ + */ +package org.jruby.util; + +import java.io.IOException; +import java.io.Reader; + +import org.jruby.RubyString; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * @author Ola Bini + * @version $Revision$ + */ +public class IOReader extends Reader { + private IRubyObject io; + + public IOReader(final IRubyObject io) { + if(!io.respondsTo("read")) { + throw new IllegalArgumentException("Object: " + io + " is not a legal argument to this wrapper, cause it doesn't respond to \"read\"."); + } + this.io = io; + } + + public void close() throws IOException { + if(io.respondsTo("close")) { + io.callMethod("close"); + } + } + + public int read(final char[] arr, final int off, final int len) { + final IRubyObject read = io.callMethod("read",io.getRuntime().newFixnum(len)); + if(read.isNil() || ((RubyString)read).getValue().length() == 0) { + return -1; + } else { + final RubyString str = (RubyString)read; + final CharSequence val = str.getValue(); + System.arraycopy(val.toString().toCharArray(),0,arr,off,val.length()); + return val.length(); + } + } +}// IOReader + diff --git a/src/org/jruby/yaml/JRubyConstructor.java b/src/org/jruby/yaml/JRubyConstructor.java new file mode 100644 index 00000000000..79e98b19436 --- /dev/null +++ b/src/org/jruby/yaml/JRubyConstructor.java @@ -0,0 +1,258 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Common Public + * License Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2006 Ola Bini + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id$ + */ +package org.jruby.yaml; + +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import java.util.regex.Pattern; + +import org.jvyaml.Composer; +import org.jvyaml.Constructor; +import org.jvyaml.ConstructorException; +import org.jvyaml.ConstructorImpl; +import org.jvyaml.SafeConstructorImpl; + +import org.jvyaml.nodes.Node; + +import org.jruby.IRuby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyHash; +import org.jruby.RubyTime; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * @author Ola Bini + * @version $Revision$ + */ +public class JRubyConstructor extends ConstructorImpl { + private final static Map yamlConstructors = new HashMap(); + private final static Map yamlMultiConstructors = new HashMap(); + private final static Map yamlMultiRegexps = new HashMap(); + public YamlConstructor getYamlConstructor(final Object key) { + return (YamlConstructor)yamlConstructors.get(key); + } + + public YamlMultiConstructor getYamlMultiConstructor(final Object key) { + return (YamlMultiConstructor)yamlMultiConstructors.get(key); + } + + public Pattern getYamlMultiRegexp(final Object key) { + return (Pattern)yamlMultiRegexps.get(key); + } + + public Set getYamlMultiRegexps() { + return yamlMultiRegexps.keySet(); + } + + public static void addConstructor(final String tag, final YamlConstructor ctor) { + yamlConstructors.put(tag,ctor); + } + + public static void addMultiConstructor(final String tagPrefix, final YamlMultiConstructor ctor) { + yamlMultiConstructors.put(tagPrefix,ctor); + yamlMultiRegexps.put(tagPrefix,Pattern.compile("^"+tagPrefix)); + } + + private final IRuby runtime; + + public JRubyConstructor(final IRubyObject receiver, final Composer composer) { + super(composer); + this.runtime = receiver.getRuntime(); + } + + public Object constructRubyScalar(final Node node) { + return runtime.newString((String)super.constructScalar(node)); + } + + public Object constructRubySequence(final Node node) { + return runtime.newArray((List)super.constructSequence(node)); + } + + public Object constructRubyMapping(final Node node) { + return RubyHash.newHash(runtime,(Map)super.constructMapping(node),runtime.getNil()); + } + + public Object constructRubyPairs(final Node node) { + return runtime.newArray((List)super.constructPairs(node)); + } + + public static Object constructYamlNull(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).runtime.getNil(); + } + + public static Object constructYamlBool(final Constructor ctor, final Node node) { + return SafeConstructorImpl.constructYamlBool(ctor,node) == Boolean.TRUE ? ((JRubyConstructor)ctor).runtime.getTrue() : ((JRubyConstructor)ctor).runtime.getFalse(); + } + + public static Object constructYamlOmap(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).constructRubyPairs(node); + } + + public static Object constructYamlPairs(final Constructor ctor, final Node node) { + return constructYamlOmap(ctor,node); + } + + public static Object constructYamlSet(final Constructor ctor, final Node node) { + return SafeConstructorImpl.constructYamlSet(ctor,node); + } + + public static Object constructYamlStr(final Constructor ctor, final Node node) { + final org.jruby.RubyString str = (org.jruby.RubyString)((JRubyConstructor)ctor).constructRubyScalar(node); + return str.getValue().length() == 0 ? str.getRuntime().getNil() : str; + } + + public static Object constructYamlSeq(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).constructRubySequence(node); + } + + public static Object constructYamlMap(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).constructRubyMapping(node); + } + + public static Object constructUndefined(final Constructor ctor, final Node node) { + throw new ConstructorException(null,"could not determine a constructor for the tag " + node.getTag(),null); + } + + public static Object constructYamlTimestamp(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).runtime.newTime(((Date)SafeConstructorImpl.constructYamlTimestamp(ctor,node)).getTime()); + } + + public static Object constructYamlInt(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).runtime.newFixnum(((Long)SafeConstructorImpl.constructYamlInt(ctor,node)).longValue()); + } + public static Object constructYamlFloat(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).runtime.newFloat(((Double)SafeConstructorImpl.constructYamlFloat(ctor,node)).doubleValue()); + } + public static Object constructYamlBinary(final Constructor ctor, final Node node) { + return ((JRubyConstructor)ctor).runtime.newString(((String)SafeConstructorImpl.constructYamlBinary(ctor,node))); + } + public static Object constructRuby(final Constructor ctor, final String tag, final Node node) { + final IRuby runtime = ((JRubyConstructor)ctor).runtime; + RubyModule objClass = runtime.getModule("Object"); + if(tag != null) { + final String[] nms = tag.split("::"); + for(int i=0,j=nms.length;i