# frozen_string_literal: truerequire'strscan'modulePsych#### Scan scalars for built in typesclassScalarScanner# Taken from http://yaml.org/type/timestamp.htmlTIME=/^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/# Taken from http://yaml.org/type/float.html# Base 60, [-+]inf and NaN are handled separatelyFLOAT=/^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10))$/x# Taken from http://yaml.org/type/int.htmlINTEGER=/^(?:[-+]?0b[0-1_,]+ (?# base 2)
|[-+]?0[0-7_,]+ (?# base 8)
|[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10)
|[-+]?0x[0-9a-fA-F_,]+ (?# base 16))$/xattr_reader:class_loader# Create a new scannerdefinitializeclass_loader@symbol_cache={}@class_loader=class_loaderend# Tokenize +string+ returning the Ruby objectdeftokenizestringreturnnilifstring.empty?return@symbol_cache[string]if@symbol_cache.key?(string)# Check for a String type, being careful not to get caught by hash keys, hex values, and# special floats (e.g., -.inf).ifstring.match?(%r{^[^\d.:-]?[[:alpha:]_\s!@#$%\^&*(){}<>|/\\~;=]+})||string.match?(/\n/)returnstringifstring.length>5ifstring.match?(/^[^ytonf~]/i)stringelsifstring=='~'||string.match?(/^null$/i)nilelsifstring.match?(/^(yes|true|on)$/i)trueelsifstring.match?(/^(no|false|off)$/i)falseelsestringendelsifstring.match?(TIME)beginparse_timestringrescueArgumentErrorstringendelsifstring.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/)require'date'beginclass_loader.date.strptime(string,'%Y-%m-%d')rescueArgumentErrorstringendelsifstring.match?(/^\+?\.inf$/i)Float::INFINITYelsifstring.match?(/^-\.inf$/i)-Float::INFINITYelsifstring.match?(/^\.nan$/i)Float::NANelsifstring.match?(/^:./)ifstring=~/^:(["'])(.*)\1/@symbol_cache[string]=class_loader.symbolize($2.sub(/^:/,''))else@symbol_cache[string]=class_loader.symbolize(string.sub(/^:/,''))endelsifstring.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/)i=0string.split(':').each_with_indexdo|n,e|i+=(n.to_i*60**(e-2).abs)endielsifstring.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/)i=0string.split(':').each_with_indexdo|n,e|i+=(n.to_f*60**(e-2).abs)endielsifstring.match?(FLOAT)ifstring.match?(/\A[-+]?\.\Z/)stringelseFloat(string.gsub(/[,_]|\.([Ee]|$)/,'\1'))endelsifstring.match?(INTEGER)parse_intstringelsestringendend#### Parse and return an int from +string+defparse_intstringInteger(string.gsub(/[,_]/,''))end#### Parse and return a Time from +string+defparse_timestringklass=class_loader.load'Time'date,time=*(string.split(/[ tT]/,2))(yy,m,dd)=date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map{|x|x.to_i}md=time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/)(hh,mm,ss)=md[1].split(':').map{|x|x.to_i}us=(md[2]?Rational("0.#{md[2]}"):0)*1000000time=klass.utc(yy,m,dd,hh,mm,ss,us)returntimeif'Z'==md[3]returnklass.at(time.to_i,us)unlessmd[3]tz=md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map{|digit|Integer(digit,10)}offset=tz.first*3600ifoffset<0offset-=((tz[1]||0)*60)elseoffset+=((tz[1]||0)*60)endklass.new(yy,m,dd,hh,mm,ss+us/(1_000_000r),offset)endendend