|
|
b8524a |
From 7ceafcbdf5bd2155704839f97b869e689f66feeb Mon Sep 17 00:00:00 2001
|
|
|
b8524a |
From: tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
|
|
b8524a |
Date: Tue, 14 May 2013 17:26:41 +0000
|
|
|
b8524a |
Subject: [PATCH] * ext/psych/lib/psych.rb: Adding Psych.safe_load for loading
|
|
|
b8524a |
a user defined, restricted subset of Ruby object types. *
|
|
|
b8524a |
ext/psych/lib/psych/class_loader.rb: A class loader for encapsulating the
|
|
|
b8524a |
logic for which objects are allowed to be deserialized. *
|
|
|
b8524a |
ext/psych/lib/psych/deprecated.rb: Changes to use the class loader *
|
|
|
b8524a |
ext/psych/lib/psych/exception.rb: ditto * ext/psych/lib/psych/json/stream.rb:
|
|
|
b8524a |
ditto * ext/psych/lib/psych/nodes/node.rb: ditto *
|
|
|
b8524a |
ext/psych/lib/psych/scalar_scanner.rb: ditto * ext/psych/lib/psych/stream.rb:
|
|
|
b8524a |
ditto * ext/psych/lib/psych/streaming.rb: ditto *
|
|
|
b8524a |
ext/psych/lib/psych/visitors/json_tree.rb: ditto *
|
|
|
b8524a |
ext/psych/lib/psych/visitors/to_ruby.rb: ditto *
|
|
|
b8524a |
ext/psych/lib/psych/visitors/yaml_tree.rb: ditto * ext/psych/psych_to_ruby.c:
|
|
|
b8524a |
ditto * test/psych/helper.rb: ditto * test/psych/test_safe_load.rb: tests for
|
|
|
b8524a |
restricted subset. * test/psych/test_scalar_scanner.rb: ditto *
|
|
|
b8524a |
test/psych/visitors/test_to_ruby.rb: ditto *
|
|
|
b8524a |
test/psych/visitors/test_yaml_tree.rb: ditto
|
|
|
b8524a |
|
|
|
b8524a |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40750 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
b8524a |
---
|
|
|
b8524a |
ChangeLog | 24 +++++++
|
|
|
b8524a |
ext/psych/lib/psych.rb | 57 +++++++++++++++--
|
|
|
b8524a |
ext/psych/lib/psych/class_loader.rb | 101 ++++++++++++++++++++++++++++++
|
|
|
b8524a |
ext/psych/lib/psych/deprecated.rb | 3 +-
|
|
|
b8524a |
ext/psych/lib/psych/exception.rb | 6 ++
|
|
|
b8524a |
ext/psych/lib/psych/json/stream.rb | 1 +
|
|
|
b8524a |
ext/psych/lib/psych/nodes/node.rb | 4 +-
|
|
|
b8524a |
ext/psych/lib/psych/scalar_scanner.rb | 19 +++---
|
|
|
b8524a |
ext/psych/lib/psych/stream.rb | 1 +
|
|
|
b8524a |
ext/psych/lib/psych/streaming.rb | 15 +++--
|
|
|
b8524a |
ext/psych/lib/psych/visitors/json_tree.rb | 7 ++-
|
|
|
b8524a |
ext/psych/lib/psych/visitors/to_ruby.rb | 79 +++++++++++++----------
|
|
|
b8524a |
ext/psych/lib/psych/visitors/yaml_tree.rb | 13 +++-
|
|
|
b8524a |
ext/psych/psych_to_ruby.c | 4 +-
|
|
|
b8524a |
test/psych/helper.rb | 2 +-
|
|
|
b8524a |
test/psych/test_safe_load.rb | 97 ++++++++++++++++++++++++++++
|
|
|
b8524a |
test/psych/test_scalar_scanner.rb | 2 +-
|
|
|
b8524a |
test/psych/visitors/test_to_ruby.rb | 4 +-
|
|
|
b8524a |
test/psych/visitors/test_yaml_tree.rb | 4 +-
|
|
|
b8524a |
19 files changed, 383 insertions(+), 60 deletions(-)
|
|
|
b8524a |
create mode 100644 ext/psych/lib/psych/class_loader.rb
|
|
|
b8524a |
create mode 100644 test/psych/test_safe_load.rb
|
|
|
b8524a |
|
|
|
b8524a |
diff --git a/ChangeLog b/ChangeLog
|
|
|
b8524a |
index be56f61d3a19..e8ad02a53921 100644
|
|
|
b8524a |
--- a/ChangeLog
|
|
|
b8524a |
+++ b/ChangeLog
|
|
|
b8524a |
@@ -3137,6 +3137,30 @@
|
|
|
b8524a |
|
|
|
b8524a |
* include/ruby/intern.h: should include sys/time.h for struct timeval
|
|
|
b8524a |
if it exists. [ruby-list:49363]
|
|
|
b8524a |
+
|
|
|
b8524a |
+Wed May 15 02:22:16 2013 Aaron Patterson <aaron@tenderlovemaking.com>
|
|
|
b8524a |
+
|
|
|
b8524a |
+ * ext/psych/lib/psych.rb: Adding Psych.safe_load for loading a user
|
|
|
b8524a |
+ defined, restricted subset of Ruby object types.
|
|
|
b8524a |
+ * ext/psych/lib/psych/class_loader.rb: A class loader for
|
|
|
b8524a |
+ encapsulating the logic for which objects are allowed to be
|
|
|
b8524a |
+ deserialized.
|
|
|
b8524a |
+ * ext/psych/lib/psych/deprecated.rb: Changes to use the class loader
|
|
|
b8524a |
+ * ext/psych/lib/psych/exception.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/json/stream.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/nodes/node.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/scalar_scanner.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/stream.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/streaming.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/visitors/json_tree.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/visitors/to_ruby.rb: ditto
|
|
|
b8524a |
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
|
|
|
b8524a |
+ * ext/psych/psych_to_ruby.c: ditto
|
|
|
b8524a |
+ * test/psych/helper.rb: ditto
|
|
|
b8524a |
+ * test/psych/test_safe_load.rb: tests for restricted subset.
|
|
|
b8524a |
+ * test/psych/test_scalar_scanner.rb: ditto
|
|
|
b8524a |
+ * test/psych/visitors/test_to_ruby.rb: ditto
|
|
|
b8524a |
+ * test/psych/visitors/test_yaml_tree.rb: ditto
|
|
|
b8524a |
|
|
|
b8524a |
Tue May 14 20:21:41 2013 Eric Hodel <drbrain@segment7.net>
|
|
|
b8524a |
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
|
|
|
b8524a |
index 66a0641f39d8..711b3c1377dc 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych.rb
|
|
|
b8524a |
@@ -124,6 +124,55 @@ def self.load yaml, filename = nil
|
|
|
b8524a |
result ? result.to_ruby : result
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
+ ###
|
|
|
b8524a |
+ # Safely load the yaml string in +yaml+. By default, only the following
|
|
|
b8524a |
+ # classes are allowed to be deserialized:
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # * TrueClass
|
|
|
b8524a |
+ # * FalseClass
|
|
|
b8524a |
+ # * NilClass
|
|
|
b8524a |
+ # * Numeric
|
|
|
b8524a |
+ # * String
|
|
|
b8524a |
+ # * Array
|
|
|
b8524a |
+ # * Hash
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # Recursive data structures are not allowed by default. Arbitrary classes
|
|
|
b8524a |
+ # can be allowed by adding those classes to the +whitelist+. They are
|
|
|
b8524a |
+ # additive. For example, to allow Date deserialization:
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # Psych.safe_load(yaml, [Date])
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # Now the Date class can be loaded in addition to the classes listed above.
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # Aliases can be explicitly allowed by changing the +aliases+ parameter.
|
|
|
b8524a |
+ # For example:
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # x = []
|
|
|
b8524a |
+ # x << x
|
|
|
b8524a |
+ # yaml = Psych.dump x
|
|
|
b8524a |
+ # Psych.safe_load yaml # => raises an exception
|
|
|
b8524a |
+ # Psych.safe_load yaml, [], [], true # => loads the aliases
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # A Psych::DisallowedClass exception will be raised if the yaml contains a
|
|
|
b8524a |
+ # class that isn't in the whitelist.
|
|
|
b8524a |
+ #
|
|
|
b8524a |
+ # A Psych::BadAlias exception will be raised if the yaml contains aliases
|
|
|
b8524a |
+ # but the +aliases+ parameter is set to false.
|
|
|
b8524a |
+ def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil
|
|
|
b8524a |
+ result = parse(yaml, filename)
|
|
|
b8524a |
+ return unless result
|
|
|
b8524a |
+
|
|
|
b8524a |
+ class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s),
|
|
|
b8524a |
+ whitelist_symbols.map(&:to_s))
|
|
|
b8524a |
+ scanner = ScalarScanner.new class_loader
|
|
|
b8524a |
+ if aliases
|
|
|
b8524a |
+ visitor = Visitors::ToRuby.new scanner, class_loader
|
|
|
b8524a |
+ else
|
|
|
b8524a |
+ visitor = Visitors::NoAliasRuby.new scanner, class_loader
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ visitor.accept result
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
###
|
|
|
b8524a |
# Parse a YAML string in +yaml+. Returns the first object of a YAML AST.
|
|
|
b8524a |
# +filename+ is used in the exception message if a Psych::SyntaxError is
|
|
|
b8524a |
@@ -234,7 +283,7 @@ def self.dump o, io = nil, options = {}
|
|
|
b8524a |
io = nil
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
- visitor = Psych::Visitors::YAMLTree.new options
|
|
|
b8524a |
+ visitor = Psych::Visitors::YAMLTree.create options
|
|
|
b8524a |
visitor << o
|
|
|
b8524a |
visitor.tree.yaml io, options
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -246,7 +295,7 @@ def self.dump o, io = nil, options = {}
|
|
|
b8524a |
#
|
|
|
b8524a |
# Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
|
|
|
b8524a |
def self.dump_stream *objects
|
|
|
b8524a |
- visitor = Psych::Visitors::YAMLTree.new {}
|
|
|
b8524a |
+ visitor = Psych::Visitors::YAMLTree.create({})
|
|
|
b8524a |
objects.each do |o|
|
|
|
b8524a |
visitor << o
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -256,7 +305,7 @@ def self.dump_stream *objects
|
|
|
b8524a |
###
|
|
|
b8524a |
# Dump Ruby object +o+ to a JSON string.
|
|
|
b8524a |
def self.to_json o
|
|
|
b8524a |
- visitor = Psych::Visitors::JSONTree.new
|
|
|
b8524a |
+ visitor = Psych::Visitors::JSONTree.create
|
|
|
b8524a |
visitor << o
|
|
|
b8524a |
visitor.tree.yaml
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -314,7 +363,7 @@ def self.remove_type type_tag
|
|
|
b8524a |
@load_tags = {}
|
|
|
b8524a |
@dump_tags = {}
|
|
|
b8524a |
def self.add_tag tag, klass
|
|
|
b8524a |
- @load_tags[tag] = klass
|
|
|
b8524a |
+ @load_tags[tag] = klass.name
|
|
|
b8524a |
@dump_tags[klass] = tag
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
|
|
|
b8524a |
new file mode 100644
|
|
|
b8524a |
index 000000000000..46c6b9362790
|
|
|
b8524a |
--- /dev/null
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/class_loader.rb
|
|
|
b8524a |
@@ -0,0 +1,101 @@
|
|
|
b8524a |
+require 'psych/omap'
|
|
|
b8524a |
+require 'psych/set'
|
|
|
b8524a |
+
|
|
|
b8524a |
+module Psych
|
|
|
b8524a |
+ class ClassLoader # :nodoc:
|
|
|
b8524a |
+ BIG_DECIMAL = 'BigDecimal'
|
|
|
b8524a |
+ COMPLEX = 'Complex'
|
|
|
b8524a |
+ DATE = 'Date'
|
|
|
b8524a |
+ DATE_TIME = 'DateTime'
|
|
|
b8524a |
+ EXCEPTION = 'Exception'
|
|
|
b8524a |
+ OBJECT = 'Object'
|
|
|
b8524a |
+ PSYCH_OMAP = 'Psych::Omap'
|
|
|
b8524a |
+ PSYCH_SET = 'Psych::Set'
|
|
|
b8524a |
+ RANGE = 'Range'
|
|
|
b8524a |
+ RATIONAL = 'Rational'
|
|
|
b8524a |
+ REGEXP = 'Regexp'
|
|
|
b8524a |
+ STRUCT = 'Struct'
|
|
|
b8524a |
+ SYMBOL = 'Symbol'
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def initialize
|
|
|
b8524a |
+ @cache = CACHE.dup
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def load klassname
|
|
|
b8524a |
+ return nil if !klassname || klassname.empty?
|
|
|
b8524a |
+
|
|
|
b8524a |
+ find klassname
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def symbolize sym
|
|
|
b8524a |
+ symbol
|
|
|
b8524a |
+ sym.to_sym
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ constants.each do |const|
|
|
|
b8524a |
+ konst = const_get const
|
|
|
b8524a |
+ define_method(const.to_s.downcase) do
|
|
|
b8524a |
+ load konst
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ private
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def find klassname
|
|
|
b8524a |
+ @cache[klassname] ||= resolve(klassname)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def resolve klassname
|
|
|
b8524a |
+ name = klassname
|
|
|
b8524a |
+ retried = false
|
|
|
b8524a |
+
|
|
|
b8524a |
+ begin
|
|
|
b8524a |
+ path2class(name)
|
|
|
b8524a |
+ rescue ArgumentError, NameError => ex
|
|
|
b8524a |
+ unless retried
|
|
|
b8524a |
+ name = "Struct::#{name}"
|
|
|
b8524a |
+ retried = ex
|
|
|
b8524a |
+ retry
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ raise retried
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ CACHE = Hash[constants.map { |const|
|
|
|
b8524a |
+ val = const_get const
|
|
|
b8524a |
+ begin
|
|
|
b8524a |
+ [val, ::Object.const_get(val)]
|
|
|
b8524a |
+ rescue
|
|
|
b8524a |
+ nil
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ }.compact]
|
|
|
b8524a |
+
|
|
|
b8524a |
+ class Restricted < ClassLoader
|
|
|
b8524a |
+ def initialize classes, symbols
|
|
|
b8524a |
+ @classes = classes
|
|
|
b8524a |
+ @symbols = symbols
|
|
|
b8524a |
+ super()
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def symbolize sym
|
|
|
b8524a |
+ return super if @symbols.empty?
|
|
|
b8524a |
+
|
|
|
b8524a |
+ if @symbols.include? sym
|
|
|
b8524a |
+ super
|
|
|
b8524a |
+ else
|
|
|
b8524a |
+ raise DisallowedClass, 'Symbol'
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ private
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def find klassname
|
|
|
b8524a |
+ if @classes.include? klassname
|
|
|
b8524a |
+ super
|
|
|
b8524a |
+ else
|
|
|
b8524a |
+ raise DisallowedClass, klassname
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+end
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/deprecated.rb b/ext/psych/lib/psych/deprecated.rb
|
|
|
b8524a |
index 1e42859b22fe..8c310b320738 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/deprecated.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/deprecated.rb
|
|
|
b8524a |
@@ -35,7 +35,8 @@ def self.detect_implicit thing
|
|
|
b8524a |
warn "#{caller[0]}: detect_implicit is deprecated" if $VERBOSE
|
|
|
b8524a |
return '' unless String === thing
|
|
|
b8524a |
return 'null' if '' == thing
|
|
|
b8524a |
- ScalarScanner.new.tokenize(thing).class.name.downcase
|
|
|
b8524a |
+ ss = ScalarScanner.new(ClassLoader.new)
|
|
|
b8524a |
+ ss.tokenize(thing).class.name.downcase
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def self.add_ruby_type type_tag, &block
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/exception.rb b/ext/psych/lib/psych/exception.rb
|
|
|
b8524a |
index d96c527cfba7..ce9d2caf3fb2 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/exception.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/exception.rb
|
|
|
b8524a |
@@ -4,4 +4,10 @@ class Exception < RuntimeError
|
|
|
b8524a |
|
|
|
b8524a |
class BadAlias < Exception
|
|
|
b8524a |
end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ class DisallowedClass < Exception
|
|
|
b8524a |
+ def initialize klass_name
|
|
|
b8524a |
+ super "Tried to load unspecified class: #{klass_name}"
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
end
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/json/stream.rb b/ext/psych/lib/psych/json/stream.rb
|
|
|
b8524a |
index be1a0a8a8240..fe2a6e911650 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/json/stream.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/json/stream.rb
|
|
|
b8524a |
@@ -6,6 +6,7 @@ module JSON
|
|
|
b8524a |
class Stream < Psych::Visitors::JSONTree
|
|
|
b8524a |
include Psych::JSON::RubyEvents
|
|
|
b8524a |
include Psych::Streaming
|
|
|
b8524a |
+ extend Psych::Streaming::ClassMethods
|
|
|
b8524a |
|
|
|
b8524a |
class Emitter < Psych::Stream::Emitter # :nodoc:
|
|
|
b8524a |
include Psych::JSON::YAMLEvents
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb
|
|
|
b8524a |
index 0cefe44e446d..83233a61fdd3 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/nodes/node.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/nodes/node.rb
|
|
|
b8524a |
@@ -1,4 +1,6 @@
|
|
|
b8524a |
require 'stringio'
|
|
|
b8524a |
+require 'psych/class_loader'
|
|
|
b8524a |
+require 'psych/scalar_scanner'
|
|
|
b8524a |
|
|
|
b8524a |
module Psych
|
|
|
b8524a |
module Nodes
|
|
|
b8524a |
@@ -32,7 +34,7 @@ def each &block
|
|
|
b8524a |
#
|
|
|
b8524a |
# See also Psych::Visitors::ToRuby
|
|
|
b8524a |
def to_ruby
|
|
|
b8524a |
- Visitors::ToRuby.new.accept self
|
|
|
b8524a |
+ Visitors::ToRuby.create.accept(self)
|
|
|
b8524a |
end
|
|
|
b8524a |
alias :transform :to_ruby
|
|
|
b8524a |
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb
|
|
|
b8524a |
index 8aa594e3337c..5935e26b288a 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/scalar_scanner.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/scalar_scanner.rb
|
|
|
b8524a |
@@ -19,10 +19,13 @@ class ScalarScanner
|
|
|
b8524a |
|[-+]?(?:0|[1-9][0-9_]*) (?# base 10)
|
|
|
b8524a |
|[-+]?0x[0-9a-fA-F_]+ (?# base 16))$/x
|
|
|
b8524a |
|
|
|
b8524a |
+ attr_reader :class_loader
|
|
|
b8524a |
+
|
|
|
b8524a |
# Create a new scanner
|
|
|
b8524a |
- def initialize
|
|
|
b8524a |
+ def initialize class_loader
|
|
|
b8524a |
@string_cache = {}
|
|
|
b8524a |
@symbol_cache = {}
|
|
|
b8524a |
+ @class_loader = class_loader
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
# Tokenize +string+ returning the ruby object
|
|
|
b8524a |
@@ -63,7 +66,7 @@ def tokenize string
|
|
|
b8524a |
when /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/
|
|
|
b8524a |
require 'date'
|
|
|
b8524a |
begin
|
|
|
b8524a |
- Date.strptime(string, '%Y-%m-%d')
|
|
|
b8524a |
+ class_loader.date.strptime(string, '%Y-%m-%d')
|
|
|
b8524a |
rescue ArgumentError
|
|
|
b8524a |
string
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -75,9 +78,9 @@ def tokenize string
|
|
|
b8524a |
Float::NAN
|
|
|
b8524a |
when /^:./
|
|
|
b8524a |
if string =~ /^:(["'])(.*)\1/
|
|
|
b8524a |
- @symbol_cache[string] = $2.sub(/^:/, '').to_sym
|
|
|
b8524a |
+ @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
|
|
|
b8524a |
else
|
|
|
b8524a |
- @symbol_cache[string] = string.sub(/^:/, '').to_sym
|
|
|
b8524a |
+ @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, ''))
|
|
|
b8524a |
end
|
|
|
b8524a |
when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/
|
|
|
b8524a |
i = 0
|
|
|
b8524a |
@@ -117,6 +120,8 @@ def parse_int string
|
|
|
b8524a |
###
|
|
|
b8524a |
# Parse and return a Time from +string+
|
|
|
b8524a |
def parse_time string
|
|
|
b8524a |
+ klass = class_loader.load 'Time'
|
|
|
b8524a |
+
|
|
|
b8524a |
date, time = *(string.split(/[ tT]/, 2))
|
|
|
b8524a |
(yy, m, dd) = date.split('-').map { |x| x.to_i }
|
|
|
b8524a |
md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/)
|
|
|
b8524a |
@@ -124,10 +129,10 @@ def parse_time string
|
|
|
b8524a |
(hh, mm, ss) = md[1].split(':').map { |x| x.to_i }
|
|
|
b8524a |
us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000
|
|
|
b8524a |
|
|
|
b8524a |
- time = Time.utc(yy, m, dd, hh, mm, ss, us)
|
|
|
b8524a |
+ time = klass.utc(yy, m, dd, hh, mm, ss, us)
|
|
|
b8524a |
|
|
|
b8524a |
return time if 'Z' == md[3]
|
|
|
b8524a |
- return Time.at(time.to_i, us) unless md[3]
|
|
|
b8524a |
+ return klass.at(time.to_i, us) unless md[3]
|
|
|
b8524a |
|
|
|
b8524a |
tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) }
|
|
|
b8524a |
offset = tz.first * 3600
|
|
|
b8524a |
@@ -138,7 +143,7 @@ def parse_time string
|
|
|
b8524a |
offset += ((tz[1] || 0) * 60)
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
- Time.at((time - offset).to_i, us)
|
|
|
b8524a |
+ klass.at((time - offset).to_i, us)
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/stream.rb b/ext/psych/lib/psych/stream.rb
|
|
|
b8524a |
index 567c1bb790f9..88c4c4cb4e18 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/stream.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/stream.rb
|
|
|
b8524a |
@@ -32,5 +32,6 @@ def streaming?
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
include Psych::Streaming
|
|
|
b8524a |
+ extend Psych::Streaming::ClassMethods
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/streaming.rb b/ext/psych/lib/psych/streaming.rb
|
|
|
b8524a |
index c6fa109d5a61..9d94eb549f26 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/streaming.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/streaming.rb
|
|
|
b8524a |
@@ -1,10 +1,15 @@
|
|
|
b8524a |
module Psych
|
|
|
b8524a |
module Streaming
|
|
|
b8524a |
- ###
|
|
|
b8524a |
- # Create a new streaming emitter. Emitter will print to +io+. See
|
|
|
b8524a |
- # Psych::Stream for an example.
|
|
|
b8524a |
- def initialize io
|
|
|
b8524a |
- super({}, self.class.const_get(:Emitter).new(io))
|
|
|
b8524a |
+ module ClassMethods
|
|
|
b8524a |
+ ###
|
|
|
b8524a |
+ # Create a new streaming emitter. Emitter will print to +io+. See
|
|
|
b8524a |
+ # Psych::Stream for an example.
|
|
|
b8524a |
+ def new io
|
|
|
b8524a |
+ emitter = const_get(:Emitter).new(io)
|
|
|
b8524a |
+ class_loader = ClassLoader.new
|
|
|
b8524a |
+ ss = ScalarScanner.new class_loader
|
|
|
b8524a |
+ super(emitter, ss, {})
|
|
|
b8524a |
+ end
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
###
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/visitors/json_tree.rb b/ext/psych/lib/psych/visitors/json_tree.rb
|
|
|
b8524a |
index 0350dd1faae0..0127ac8aa8c1 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/visitors/json_tree.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/visitors/json_tree.rb
|
|
|
b8524a |
@@ -5,8 +5,11 @@ module Visitors
|
|
|
b8524a |
class JSONTree < YAMLTree
|
|
|
b8524a |
include Psych::JSON::RubyEvents
|
|
|
b8524a |
|
|
|
b8524a |
- def initialize options = {}, emitter = Psych::JSON::TreeBuilder.new
|
|
|
b8524a |
- super
|
|
|
b8524a |
+ def self.create options = {}
|
|
|
b8524a |
+ emitter = Psych::JSON::TreeBuilder.new
|
|
|
b8524a |
+ class_loader = ClassLoader.new
|
|
|
b8524a |
+ ss = ScalarScanner.new class_loader
|
|
|
b8524a |
+ new(emitter, ss, options)
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def accept target
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
|
|
|
b8524a |
index 75c7bc0c550a..f770bb80aa3a 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
|
|
|
b8524a |
@@ -1,4 +1,5 @@
|
|
|
b8524a |
require 'psych/scalar_scanner'
|
|
|
b8524a |
+require 'psych/class_loader'
|
|
|
b8524a |
require 'psych/exception'
|
|
|
b8524a |
|
|
|
b8524a |
unless defined?(Regexp::NOENCODING)
|
|
|
b8524a |
@@ -10,11 +11,20 @@ module Visitors
|
|
|
b8524a |
###
|
|
|
b8524a |
# This class walks a YAML AST, converting each node to ruby
|
|
|
b8524a |
class ToRuby < Psych::Visitors::Visitor
|
|
|
b8524a |
- def initialize ss = ScalarScanner.new
|
|
|
b8524a |
+ def self.create
|
|
|
b8524a |
+ class_loader = ClassLoader.new
|
|
|
b8524a |
+ scanner = ScalarScanner.new class_loader
|
|
|
b8524a |
+ new(scanner, class_loader)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ attr_reader :class_loader
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def initialize ss, class_loader
|
|
|
b8524a |
super()
|
|
|
b8524a |
@st = {}
|
|
|
b8524a |
@ss = ss
|
|
|
b8524a |
@domain_types = Psych.domain_types
|
|
|
b8524a |
+ @class_loader = class_loader
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def accept target
|
|
|
b8524a |
@@ -33,7 +43,7 @@ def accept target
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def deserialize o
|
|
|
b8524a |
- if klass = Psych.load_tags[o.tag]
|
|
|
b8524a |
+ if klass = resolve_class(Psych.load_tags[o.tag])
|
|
|
b8524a |
instance = klass.allocate
|
|
|
b8524a |
|
|
|
b8524a |
if instance.respond_to?(:init_with)
|
|
|
b8524a |
@@ -60,19 +70,23 @@ def deserialize o
|
|
|
b8524a |
end
|
|
|
b8524a |
when '!ruby/object:BigDecimal'
|
|
|
b8524a |
require 'bigdecimal'
|
|
|
b8524a |
- BigDecimal._load o.value
|
|
|
b8524a |
+ class_loader.big_decimal._load o.value
|
|
|
b8524a |
when "!ruby/object:DateTime"
|
|
|
b8524a |
+ class_loader.date_time
|
|
|
b8524a |
require 'date'
|
|
|
b8524a |
@ss.parse_time(o.value).to_datetime
|
|
|
b8524a |
when "!ruby/object:Complex"
|
|
|
b8524a |
+ class_loader.complex
|
|
|
b8524a |
Complex(o.value)
|
|
|
b8524a |
when "!ruby/object:Rational"
|
|
|
b8524a |
+ class_loader.rational
|
|
|
b8524a |
Rational(o.value)
|
|
|
b8524a |
when "!ruby/class", "!ruby/module"
|
|
|
b8524a |
resolve_class o.value
|
|
|
b8524a |
when "tag:yaml.org,2002:float", "!float"
|
|
|
b8524a |
Float(@ss.tokenize(o.value))
|
|
|
b8524a |
when "!ruby/regexp"
|
|
|
b8524a |
+ klass = class_loader.regexp
|
|
|
b8524a |
o.value =~ /^\/(.*)\/([mixn]*)$/
|
|
|
b8524a |
source = $1
|
|
|
b8524a |
options = 0
|
|
|
b8524a |
@@ -86,15 +100,16 @@ def deserialize o
|
|
|
b8524a |
else lang = option
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
- Regexp.new(*[source, options, lang].compact)
|
|
|
b8524a |
+ klass.new(*[source, options, lang].compact)
|
|
|
b8524a |
when "!ruby/range"
|
|
|
b8524a |
+ klass = class_loader.range
|
|
|
b8524a |
args = o.value.split(/([.]{2,3})/, 2).map { |s|
|
|
|
b8524a |
accept Nodes::Scalar.new(s)
|
|
|
b8524a |
}
|
|
|
b8524a |
args.push(args.delete_at(1) == '...')
|
|
|
b8524a |
- Range.new(*args)
|
|
|
b8524a |
+ klass.new(*args)
|
|
|
b8524a |
when /^!ruby\/sym(bol)?:?(.*)?$/
|
|
|
b8524a |
- o.value.to_sym
|
|
|
b8524a |
+ class_loader.symbolize o.value
|
|
|
b8524a |
else
|
|
|
b8524a |
@ss.tokenize o.value
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -106,7 +121,7 @@ def visit_Psych_Nodes_Scalar o
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def visit_Psych_Nodes_Sequence o
|
|
|
b8524a |
- if klass = Psych.load_tags[o.tag]
|
|
|
b8524a |
+ if klass = resolve_class(Psych.load_tags[o.tag])
|
|
|
b8524a |
instance = klass.allocate
|
|
|
b8524a |
|
|
|
b8524a |
if instance.respond_to?(:init_with)
|
|
|
b8524a |
@@ -138,22 +153,24 @@ def visit_Psych_Nodes_Sequence o
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def visit_Psych_Nodes_Mapping o
|
|
|
b8524a |
- return revive(Psych.load_tags[o.tag], o) if Psych.load_tags[o.tag]
|
|
|
b8524a |
+ if Psych.load_tags[o.tag]
|
|
|
b8524a |
+ return revive(resolve_class(Psych.load_tags[o.tag]), o)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
return revive_hash({}, o) unless o.tag
|
|
|
b8524a |
|
|
|
b8524a |
case o.tag
|
|
|
b8524a |
when /^!ruby\/struct:?(.*)?$/
|
|
|
b8524a |
- klass = resolve_class($1)
|
|
|
b8524a |
+ klass = resolve_class($1) if $1
|
|
|
b8524a |
|
|
|
b8524a |
if klass
|
|
|
b8524a |
s = register(o, klass.allocate)
|
|
|
b8524a |
|
|
|
b8524a |
members = {}
|
|
|
b8524a |
- struct_members = s.members.map { |x| x.to_sym }
|
|
|
b8524a |
+ struct_members = s.members.map { |x| class_loader.symbolize x }
|
|
|
b8524a |
o.children.each_slice(2) do |k,v|
|
|
|
b8524a |
member = accept(k)
|
|
|
b8524a |
value = accept(v)
|
|
|
b8524a |
- if struct_members.include?(member.to_sym)
|
|
|
b8524a |
+ if struct_members.include?(class_loader.symbolize(member))
|
|
|
b8524a |
s.send("#{member}=", value)
|
|
|
b8524a |
else
|
|
|
b8524a |
members[member.to_s.sub(/^@/, '')] = value
|
|
|
b8524a |
@@ -161,22 +178,27 @@ def visit_Psych_Nodes_Mapping o
|
|
|
b8524a |
end
|
|
|
b8524a |
init_with(s, members, o)
|
|
|
b8524a |
else
|
|
|
b8524a |
+ klass = class_loader.struct
|
|
|
b8524a |
members = o.children.map { |c| accept c }
|
|
|
b8524a |
h = Hash[*members]
|
|
|
b8524a |
- Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v })
|
|
|
b8524a |
+ klass.new(*h.map { |k,v|
|
|
|
b8524a |
+ class_loader.symbolize k
|
|
|
b8524a |
+ }).new(*h.map { |k,v| v })
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
when /^!ruby\/object:?(.*)?$/
|
|
|
b8524a |
name = $1 || 'Object'
|
|
|
b8524a |
|
|
|
b8524a |
if name == 'Complex'
|
|
|
b8524a |
+ class_loader.complex
|
|
|
b8524a |
h = Hash[*o.children.map { |c| accept c }]
|
|
|
b8524a |
register o, Complex(h['real'], h['image'])
|
|
|
b8524a |
elsif name == 'Rational'
|
|
|
b8524a |
+ class_loader.rational
|
|
|
b8524a |
h = Hash[*o.children.map { |c| accept c }]
|
|
|
b8524a |
register o, Rational(h['numerator'], h['denominator'])
|
|
|
b8524a |
else
|
|
|
b8524a |
- obj = revive((resolve_class(name) || Object), o)
|
|
|
b8524a |
+ obj = revive((resolve_class(name) || class_loader.object), o)
|
|
|
b8524a |
obj
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
@@ -204,18 +226,19 @@ def visit_Psych_Nodes_Mapping o
|
|
|
b8524a |
list
|
|
|
b8524a |
|
|
|
b8524a |
when '!ruby/range'
|
|
|
b8524a |
+ klass = class_loader.range
|
|
|
b8524a |
h = Hash[*o.children.map { |c| accept c }]
|
|
|
b8524a |
- register o, Range.new(h['begin'], h['end'], h['excl'])
|
|
|
b8524a |
+ register o, klass.new(h['begin'], h['end'], h['excl'])
|
|
|
b8524a |
|
|
|
b8524a |
when /^!ruby\/exception:?(.*)?$/
|
|
|
b8524a |
h = Hash[*o.children.map { |c| accept c }]
|
|
|
b8524a |
|
|
|
b8524a |
- e = build_exception((resolve_class($1) || Exception),
|
|
|
b8524a |
+ e = build_exception((resolve_class($1) || class_loader.exception),
|
|
|
b8524a |
h.delete('message'))
|
|
|
b8524a |
init_with(e, h, o)
|
|
|
b8524a |
|
|
|
b8524a |
when '!set', 'tag:yaml.org,2002:set'
|
|
|
b8524a |
- set = Psych::Set.new
|
|
|
b8524a |
+ set = class_loader.psych_set.new
|
|
|
b8524a |
@st[o.anchor] = set if o.anchor
|
|
|
b8524a |
o.children.each_slice(2) do |k,v|
|
|
|
b8524a |
set[accept(k)] = accept(v)
|
|
|
b8524a |
@@ -226,7 +249,7 @@ def visit_Psych_Nodes_Mapping o
|
|
|
b8524a |
revive_hash resolve_class($1).new, o
|
|
|
b8524a |
|
|
|
b8524a |
when '!omap', 'tag:yaml.org,2002:omap'
|
|
|
b8524a |
- map = register(o, Psych::Omap.new)
|
|
|
b8524a |
+ map = register(o, class_loader.psych_omap.new)
|
|
|
b8524a |
o.children.each_slice(2) do |l,r|
|
|
|
b8524a |
map[accept(l)] = accept r
|
|
|
b8524a |
end
|
|
|
b8524a |
@@ -326,21 +349,13 @@ def init_with o, h, node
|
|
|
b8524a |
|
|
|
b8524a |
# Convert +klassname+ to a Class
|
|
|
b8524a |
def resolve_class klassname
|
|
|
b8524a |
- return nil unless klassname and not klassname.empty?
|
|
|
b8524a |
-
|
|
|
b8524a |
- name = klassname
|
|
|
b8524a |
- retried = false
|
|
|
b8524a |
-
|
|
|
b8524a |
- begin
|
|
|
b8524a |
- path2class(name)
|
|
|
b8524a |
- rescue ArgumentError, NameError => ex
|
|
|
b8524a |
- unless retried
|
|
|
b8524a |
- name = "Struct::#{name}"
|
|
|
b8524a |
- retried = ex
|
|
|
b8524a |
- retry
|
|
|
b8524a |
- end
|
|
|
b8524a |
- raise retried
|
|
|
b8524a |
- end
|
|
|
b8524a |
+ class_loader.load klassname
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ class NoAliasRuby < ToRuby
|
|
|
b8524a |
+ def visit_Psych_Nodes_Alias o
|
|
|
b8524a |
+ raise BadAlias, "Unknown alias: #{o.anchor}"
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
end
|
|
|
b8524a |
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
|
|
|
b8524a |
index 96640e026719..ddd745b34a9c 100644
|
|
|
b8524a |
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
|
|
|
b8524a |
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
|
|
|
b8524a |
@@ -1,3 +1,7 @@
|
|
|
b8524a |
+require 'psych/tree_builder'
|
|
|
b8524a |
+require 'psych/scalar_scanner'
|
|
|
b8524a |
+require 'psych/class_loader'
|
|
|
b8524a |
+
|
|
|
b8524a |
module Psych
|
|
|
b8524a |
module Visitors
|
|
|
b8524a |
###
|
|
|
b8524a |
@@ -36,7 +40,14 @@ def node_for target
|
|
|
b8524a |
alias :finished? :finished
|
|
|
b8524a |
alias :started? :started
|
|
|
b8524a |
|
|
|
b8524a |
- def initialize options = {}, emitter = TreeBuilder.new, ss = ScalarScanner.new
|
|
|
b8524a |
+ def self.create options = {}, emitter = nil
|
|
|
b8524a |
+ emitter ||= TreeBuilder.new
|
|
|
b8524a |
+ class_loader = ClassLoader.new
|
|
|
b8524a |
+ ss = ScalarScanner.new class_loader
|
|
|
b8524a |
+ new(emitter, ss, options)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def initialize emitter, ss, options
|
|
|
b8524a |
super()
|
|
|
b8524a |
@started = false
|
|
|
b8524a |
@finished = false
|
|
|
b8524a |
diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c
|
|
|
b8524a |
index ed5245e12e7a..3cc87a965ec1 100644
|
|
|
b8524a |
--- a/ext/psych/psych_to_ruby.c
|
|
|
b8524a |
+++ b/ext/psych/psych_to_ruby.c
|
|
|
b8524a |
@@ -31,11 +31,13 @@ static VALUE path2class(VALUE self, VALUE path)
|
|
|
b8524a |
void Init_psych_to_ruby(void)
|
|
|
b8524a |
{
|
|
|
b8524a |
VALUE psych = rb_define_module("Psych");
|
|
|
b8524a |
+ VALUE class_loader = rb_define_class_under(psych, "ClassLoader", rb_cObject);
|
|
|
b8524a |
+
|
|
|
b8524a |
VALUE visitors = rb_define_module_under(psych, "Visitors");
|
|
|
b8524a |
VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
|
|
|
b8524a |
cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
|
|
|
b8524a |
|
|
|
b8524a |
rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
|
|
|
b8524a |
- rb_define_private_method(cPsychVisitorsToRuby, "path2class", path2class, 1);
|
|
|
b8524a |
+ rb_define_private_method(class_loader, "path2class", path2class, 1);
|
|
|
b8524a |
}
|
|
|
b8524a |
/* vim: set noet sws=4 sw=4: */
|
|
|
b8524a |
diff --git a/test/psych/helper.rb b/test/psych/helper.rb
|
|
|
b8524a |
index 77ab0bb9d71c..f9b73cf5b588 100644
|
|
|
b8524a |
--- a/test/psych/helper.rb
|
|
|
b8524a |
+++ b/test/psych/helper.rb
|
|
|
b8524a |
@@ -31,7 +31,7 @@ def assert_parse_only( obj, yaml )
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def assert_cycle( obj )
|
|
|
b8524a |
- v = Visitors::YAMLTree.new
|
|
|
b8524a |
+ v = Visitors::YAMLTree.create
|
|
|
b8524a |
v << obj
|
|
|
b8524a |
assert_equal(obj, Psych.load(v.tree.yaml))
|
|
|
b8524a |
assert_equal( obj, Psych::load(Psych.dump(obj)))
|
|
|
b8524a |
diff --git a/test/psych/test_safe_load.rb b/test/psych/test_safe_load.rb
|
|
|
b8524a |
new file mode 100644
|
|
|
b8524a |
index 000000000000..dd299c0ebf40
|
|
|
b8524a |
--- /dev/null
|
|
|
b8524a |
+++ b/test/psych/test_safe_load.rb
|
|
|
b8524a |
@@ -0,0 +1,97 @@
|
|
|
b8524a |
+require 'psych/helper'
|
|
|
b8524a |
+
|
|
|
b8524a |
+module Psych
|
|
|
b8524a |
+ class TestSafeLoad < TestCase
|
|
|
b8524a |
+ class Foo; end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ [1, 2.2, {}, [], "foo"].each do |obj|
|
|
|
b8524a |
+ define_method(:"test_basic_#{obj.class}") do
|
|
|
b8524a |
+ assert_safe_cycle obj
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_no_recursion
|
|
|
b8524a |
+ x = []
|
|
|
b8524a |
+ x << x
|
|
|
b8524a |
+ assert_raises(Psych::BadAlias) do
|
|
|
b8524a |
+ Psych.safe_load Psych.dump(x)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_explicit_recursion
|
|
|
b8524a |
+ x = []
|
|
|
b8524a |
+ x << x
|
|
|
b8524a |
+ assert_equal(x, Psych.safe_load(Psych.dump(x), [], [], true))
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_symbol_whitelist
|
|
|
b8524a |
+ yml = Psych.dump :foo
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ Psych.safe_load yml
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ assert_equal(:foo, Psych.safe_load(yml, [Symbol], [:foo]))
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_symbol
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ assert_safe_cycle :foo
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ Psych.safe_load '--- !ruby/symbol foo', []
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ assert_safe_cycle :foo, [Symbol]
|
|
|
b8524a |
+ assert_safe_cycle :foo, %w{ Symbol }
|
|
|
b8524a |
+ assert_equal :foo, Psych.safe_load('--- !ruby/symbol foo', [Symbol])
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_foo
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ Psych.safe_load '--- !ruby/object:Foo {}', [Foo]
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ assert_safe_cycle Foo.new
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ assert_kind_of(Foo, Psych.safe_load(Psych.dump(Foo.new), [Foo]))
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ X = Struct.new(:x)
|
|
|
b8524a |
+ def test_struct_depends_on_sym
|
|
|
b8524a |
+ assert_safe_cycle(X.new, [X, Symbol])
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ cycle X.new, [X]
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def test_anon_struct
|
|
|
b8524a |
+ assert Psych.safe_load(<<-eoyml, [Struct, Symbol])
|
|
|
b8524a |
+--- !ruby/struct
|
|
|
b8524a |
+ foo: bar
|
|
|
b8524a |
+ eoyml
|
|
|
b8524a |
+
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ Psych.safe_load(<<-eoyml, [Struct])
|
|
|
b8524a |
+--- !ruby/struct
|
|
|
b8524a |
+ foo: bar
|
|
|
b8524a |
+ eoyml
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ assert_raises(Psych::DisallowedClass) do
|
|
|
b8524a |
+ Psych.safe_load(<<-eoyml, [Symbol])
|
|
|
b8524a |
+--- !ruby/struct
|
|
|
b8524a |
+ foo: bar
|
|
|
b8524a |
+ eoyml
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ private
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def cycle object, whitelist = []
|
|
|
b8524a |
+ Psych.safe_load(Psych.dump(object), whitelist)
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+
|
|
|
b8524a |
+ def assert_safe_cycle object, whitelist = []
|
|
|
b8524a |
+ other = cycle object, whitelist
|
|
|
b8524a |
+ assert_equal object, other
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+ end
|
|
|
b8524a |
+end
|
|
|
b8524a |
diff --git a/test/psych/test_scalar_scanner.rb b/test/psych/test_scalar_scanner.rb
|
|
|
b8524a |
index a7bf17c912b6..e8e423cb053d 100644
|
|
|
b8524a |
--- a/test/psych/test_scalar_scanner.rb
|
|
|
b8524a |
+++ b/test/psych/test_scalar_scanner.rb
|
|
|
b8524a |
@@ -7,7 +7,7 @@ class TestScalarScanner < TestCase
|
|
|
b8524a |
|
|
|
b8524a |
def setup
|
|
|
b8524a |
super
|
|
|
b8524a |
- @ss = Psych::ScalarScanner.new
|
|
|
b8524a |
+ @ss = Psych::ScalarScanner.new ClassLoader.new
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def test_scan_time
|
|
|
b8524a |
diff --git a/test/psych/visitors/test_to_ruby.rb b/test/psych/visitors/test_to_ruby.rb
|
|
|
b8524a |
index 022cc2d2d4ea..c13d980468d4 100644
|
|
|
b8524a |
--- a/test/psych/visitors/test_to_ruby.rb
|
|
|
b8524a |
+++ b/test/psych/visitors/test_to_ruby.rb
|
|
|
b8524a |
@@ -6,7 +6,7 @@ module Visitors
|
|
|
b8524a |
class TestToRuby < TestCase
|
|
|
b8524a |
def setup
|
|
|
b8524a |
super
|
|
|
b8524a |
- @visitor = ToRuby.new
|
|
|
b8524a |
+ @visitor = ToRuby.create
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def test_object
|
|
|
b8524a |
@@ -88,7 +88,7 @@ def test_anon_struct
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def test_exception
|
|
|
b8524a |
- exc = Exception.new 'hello'
|
|
|
b8524a |
+ exc = ::Exception.new 'hello'
|
|
|
b8524a |
|
|
|
b8524a |
mapping = Nodes::Mapping.new nil, '!ruby/exception'
|
|
|
b8524a |
mapping.children << Nodes::Scalar.new('message')
|
|
|
b8524a |
diff --git a/test/psych/visitors/test_yaml_tree.rb b/test/psych/visitors/test_yaml_tree.rb
|
|
|
b8524a |
index 496cdd05cc34..40702bce796f 100644
|
|
|
b8524a |
--- a/test/psych/visitors/test_yaml_tree.rb
|
|
|
b8524a |
+++ b/test/psych/visitors/test_yaml_tree.rb
|
|
|
b8524a |
@@ -5,7 +5,7 @@ module Visitors
|
|
|
b8524a |
class TestYAMLTree < TestCase
|
|
|
b8524a |
def setup
|
|
|
b8524a |
super
|
|
|
b8524a |
- @v = Visitors::YAMLTree.new
|
|
|
b8524a |
+ @v = Visitors::YAMLTree.create
|
|
|
b8524a |
end
|
|
|
b8524a |
|
|
|
b8524a |
def test_tree_can_be_called_twice
|
|
|
b8524a |
@@ -18,7 +18,7 @@ def test_tree_can_be_called_twice
|
|
|
b8524a |
def test_yaml_tree_can_take_an_emitter
|
|
|
b8524a |
io = StringIO.new
|
|
|
b8524a |
e = Psych::Emitter.new io
|
|
|
b8524a |
- v = Visitors::YAMLTree.new({}, e)
|
|
|
b8524a |
+ v = Visitors::YAMLTree.create({}, e)
|
|
|
b8524a |
v.start
|
|
|
b8524a |
v << "hello world"
|
|
|
b8524a |
v.finish
|