safe_yaml 0.2.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ gemspec
4
4
 
5
5
  group :development do
6
6
  gem "heredoc_unindent"
7
+ gem "pry"
7
8
  gem "rake"
8
9
  gem "rspec"
9
10
  end
data/Gemfile.lock CHANGED
@@ -1,13 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- safe_yaml (0.1)
4
+ safe_yaml (0.2.2)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
+ coderay (1.0.8)
9
10
  diff-lcs (1.1.3)
10
11
  heredoc_unindent (1.1.2)
12
+ method_source (0.8.1)
13
+ pry (0.9.11.2)
14
+ coderay (~> 1.0.5)
15
+ method_source (~> 0.8)
16
+ slop (~> 3.4)
11
17
  rake (10.0.3)
12
18
  rspec (2.12.0)
13
19
  rspec-core (~> 2.12.0)
@@ -17,12 +23,14 @@ GEM
17
23
  rspec-expectations (2.12.1)
18
24
  diff-lcs (~> 1.1.3)
19
25
  rspec-mocks (2.12.1)
26
+ slop (3.4.3)
20
27
 
21
28
  PLATFORMS
22
29
  ruby
23
30
 
24
31
  DEPENDENCIES
25
32
  heredoc_unindent
33
+ pry
26
34
  rake
27
35
  rspec
28
36
  safe_yaml!
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  SafeYAML
2
2
  ========
3
3
 
4
- *Parse (simple) YAML safely, without that pesky arbitrary code execution vulnerability.*
4
+ *Parse YAML safely, without that pesky arbitrary code execution vulnerability.*
5
5
 
6
6
  ***
7
7
 
@@ -38,4 +38,4 @@ With `YAML.safe_load`, that attacker would be thwarted:
38
38
  > YAML.safe_load(yaml)
39
39
  => {"foo; end; puts %(I'm in yr system!); def bar"=>"baz"}
40
40
 
41
- SafeYAML requires Ruby 1.9.2 or newer. Maybe I'll get around to writing a Syck handler eventually, at which point it could support older versions as well.
41
+ SafeYAML requires Ruby 1.8.7 or newer and works with both [Syck](http://www.ruby-doc.org/stdlib-1.8.7/libdoc/yaml/rdoc/YAML.html) and [Psych](http://github.com/tenderlove/psych).
@@ -1,20 +1,7 @@
1
1
  require "psych"
2
- require "yaml"
3
2
 
4
3
  module SafeYAML
5
- class Handler < Psych::Handler
6
- PREDEFINED_VALUES = {
7
- "" => nil,
8
- "~" => nil,
9
- "null" => nil,
10
- "yes" => true,
11
- "on" => true,
12
- "true" => true,
13
- "no" => false,
14
- "off" => false,
15
- "false" => false
16
- }.freeze
17
-
4
+ class PsychHandler < Psych::Handler
18
5
  def initialize
19
6
  @anchors = {}
20
7
  @stack = []
@@ -25,7 +12,7 @@ module SafeYAML
25
12
  end
26
13
 
27
14
  def add_to_current_structure(value, anchor=nil)
28
- value = transform_value(value)
15
+ value = Transform.to_proper_type(value)
29
16
 
30
17
  @anchors[anchor] = value if anchor
31
18
 
@@ -58,25 +45,6 @@ module SafeYAML
58
45
  end
59
46
  end
60
47
 
61
- def transform_value(value)
62
- if value.is_a?(String)
63
- if PREDEFINED_VALUES.include?(value.downcase)
64
- return PREDEFINED_VALUES[value.downcase]
65
-
66
- elsif value.match(/^:\w+$/)
67
- return value[1..-1].to_sym
68
-
69
- elsif value.match(/^\d+$/)
70
- return value.to_i
71
-
72
- elsif value.match(/^\d+(?:\.\d*)?$/) || value.match(/^\.\d+$/)
73
- return value.to_f
74
- end
75
- end
76
-
77
- value
78
- end
79
-
80
48
  def end_current_structure
81
49
  @stack.pop
82
50
  @current_structure = @stack.last
@@ -0,0 +1,49 @@
1
+ module SafeYAML
2
+ class SyckResolver
3
+ def initialize
4
+ @anchors = {}
5
+ end
6
+
7
+ def resolve_tree(tree)
8
+ case tree.kind
9
+ when :map
10
+ return resolve_map(tree.value)
11
+ when :seq
12
+ return resolve_seq(tree.value)
13
+ else
14
+ raise "Don't know how to resolve a #{tree.kind} tree!"
15
+ end
16
+ end
17
+
18
+ def resolve_node(node)
19
+ case node.kind
20
+ when :map
21
+ return resolve_map(node.value)
22
+ when :seq
23
+ return resolve_seq(node.value)
24
+ when :scalar
25
+ return resolve_scalar(node.value)
26
+ end
27
+ end
28
+
29
+ def resolve_map(map)
30
+ hash = {}
31
+ map.each do |key_node, value_node|
32
+ if resolve_node(key_node) == "<<"
33
+ hash.merge!(resolve_node(value_node))
34
+ else
35
+ hash[resolve_node(key_node)] = resolve_node(value_node)
36
+ end
37
+ end
38
+ return hash
39
+ end
40
+
41
+ def resolve_seq(seq)
42
+ seq.map { |node| resolve_node(node) }
43
+ end
44
+
45
+ def resolve_scalar(scalar)
46
+ Transform.to_proper_type(scalar)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ module SafeYAML
2
+ class Transform
3
+ PREDEFINED_VALUES = {
4
+ "" => nil,
5
+ "~" => nil,
6
+ "null" => nil,
7
+ "yes" => true,
8
+ "on" => true,
9
+ "true" => true,
10
+ "no" => false,
11
+ "off" => false,
12
+ "false" => false
13
+ }.freeze
14
+
15
+ def self.to_proper_type(value)
16
+ if value.is_a?(String)
17
+ if PREDEFINED_VALUES.include?(value.downcase)
18
+ return PREDEFINED_VALUES[value.downcase]
19
+
20
+ elsif value.match(/^:\w+$/)
21
+ return value[1..-1].to_sym
22
+
23
+ elsif value.match(/^\d+$/)
24
+ return value.to_i
25
+
26
+ elsif value.match(/^\d+(?:\.\d*)?$/) || value.match(/^\.\d+$/)
27
+ return value.to_f
28
+ end
29
+ end
30
+
31
+ value
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module SafeYAML
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3"
3
3
  end
data/lib/safe_yaml.rb CHANGED
@@ -1,10 +1,22 @@
1
- require "safe_yaml/handler"
1
+ require "yaml"
2
+ require "safe_yaml/transform"
2
3
  require "safe_yaml/version"
3
4
 
4
5
  module YAML
5
- def self.safe_load(yaml)
6
- safe_handler = SafeYAML::Handler.new
7
- Psych::Parser.new(safe_handler).parse(yaml)
8
- return safe_handler.result
6
+ if RUBY_VERSION >= "1.9.2"
7
+ require "safe_yaml/psych_handler"
8
+ def self.safe_load(yaml)
9
+ safe_handler = SafeYAML::PsychHandler.new
10
+ Psych::Parser.new(safe_handler).parse(yaml)
11
+ return safe_handler.result
12
+ end
13
+
14
+ else
15
+ require "safe_yaml/syck_resolver"
16
+ def self.safe_load(yaml)
17
+ safe_resolver = SafeYAML::SyckResolver.new
18
+ tree = YAML.parse(yaml)
19
+ return safe_resolver.resolve_tree(tree)
20
+ end
9
21
  end
10
22
  end
data/safe_yaml.gemspec CHANGED
@@ -6,13 +6,13 @@ Gem::Specification.new do |gem|
6
6
  gem.version = SafeYAML::VERSION
7
7
  gem.authors = "Dan Tao"
8
8
  gem.email = "daniel.tao@gmail.com"
9
- gem.description = %q{Parse (simple) YAML safely, without that pesky arbitrary code execution vulnerability.}
9
+ gem.description = %q{Parse YAML safely, without that pesky arbitrary code execution vulnerability.}
10
10
  gem.summary = %q{SameYAML adds a ::safe_load method to Ruby's built-in YAML module to parse YAML data for only basic types (strings, symbols, numbers, arrays, and hashes).}
11
- gem.homepage = "http://dtao.github.com/safe_yaml/"
11
+ gem.homepage = "http://github.com/dtao/safe_yaml"
12
12
 
13
13
  gem.files = `git ls-files`.split($\)
14
14
  gem.test_files = gem.files.grep(%r{^spec/})
15
15
  gem.require_paths = ["lib"]
16
16
 
17
- gem.required_ruby_version = ">= 1.9.2"
17
+ gem.required_ruby_version = ">= 1.8.7"
18
18
  end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ if RUBY_VERSION >= "1.9.2"
4
+ require "safe_yaml/psych_handler"
5
+
6
+ describe SafeYAML::PsychHandler do
7
+ let(:handler) { SafeYAML::PsychHandler.new }
8
+ let(:parser) { Psych::Parser.new(handler) }
9
+ let(:result) { handler.result }
10
+
11
+ def parse(yaml)
12
+ parser.parse(yaml.unindent)
13
+ end
14
+
15
+ include SharedSpecs
16
+ end
17
+ end
@@ -4,33 +4,36 @@ require "safe_yaml"
4
4
  require "exploitable_back_door"
5
5
 
6
6
  describe YAML do
7
- before :each do
8
- ExploitableBackDoor.reset
9
- end
10
-
11
7
  describe "load" do
12
8
  if RUBY_VERSION >= "1.9.3"
13
- it "allows exploits through objects defined in YAML w/ !ruby/hash" do
14
- YAML.load "--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n"
15
- ExploitableBackDoor.should be_exploited
9
+ it "allows exploits through objects defined in YAML w/ !ruby/hash through custom :[]= methods" do
10
+ backdoor = YAML.load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
11
+ backdoor.should be_exploited_through_setter
12
+ end
13
+ end
14
+
15
+ if RUBY_VERSION >= "1.9.2"
16
+ it "allows exploits through objects defined in YAML w/ !ruby/object through" do
17
+ backdoor = YAML.load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
18
+ backdoor.should be_exploited_through_init_with
16
19
  end
17
20
  end
18
21
 
19
- it "allows exploits through objects defined in YAML w/ !ruby/object" do
20
- YAML.load "--- !ruby/object:ExploitableBackDoor\nfoo: bar\n"
21
- ExploitableBackDoor.should be_exploited
22
+ it "allows exploits through objects w/ sensitive instance variables defined in YAML w/ !ruby/object" do
23
+ backdoor = YAML.load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
24
+ backdoor.should be_exploited_through_ivars
22
25
  end
23
26
  end
24
27
 
25
28
  describe "safe_load" do
26
- it "does NOT allow exploits through objects defined in YAML w/ !ruby/object" do
27
- YAML.safe_load "--- !ruby/object:ExploitableBackDoor\nfoo: bar\n"
28
- ExploitableBackDoor.should_not be_exploited
29
+ it "does NOT allow exploits through objects defined in YAML w/ !ruby/hash" do
30
+ object = YAML.safe_load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
31
+ object.should_not be_a(ExploitableBackDoor)
29
32
  end
30
33
 
31
- it "does NOT allow exploits through objects defined in YAML w/ !ruby/hash" do
32
- YAML.safe_load "--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n"
33
- ExploitableBackDoor.should_not be_exploited
34
+ it "does NOT allow exploits through objects defined in YAML w/ !ruby/object" do
35
+ object = YAML.safe_load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
36
+ object.should_not be_a(ExploitableBackDoor)
34
37
  end
35
38
 
36
39
  it "loads a plain ol' YAML document just fine" do
@@ -53,5 +56,48 @@ describe YAML do
53
56
  }
54
57
  }
55
58
  end
59
+
60
+ it "works for YAML documents with anchors and aliases" do
61
+ result = YAML.safe_load <<-YAML
62
+ - &id001 {}
63
+ - *id001
64
+ - *id001
65
+ YAML
66
+
67
+ result.should == [{}, {}, {}]
68
+ end
69
+
70
+ it "works for YAML documents with sections" do
71
+ result = YAML.safe_load <<-YAML
72
+ mysql: &foo
73
+ adapter: mysql
74
+ pool: 30
75
+ login: &login
76
+ username: dan
77
+ password: gobbledygook
78
+ local: &local
79
+ <<: *foo
80
+ <<: *login
81
+ host: localhost
82
+ YAML
83
+
84
+ result.should == {
85
+ "mysql" => {
86
+ "adapter" => "mysql",
87
+ "pool" => 30
88
+ },
89
+ "login" => {
90
+ "username" => "dan",
91
+ "password" => "gobbledygook"
92
+ },
93
+ "local" => {
94
+ "adapter" => "mysql",
95
+ "pool" => 30,
96
+ "username" => "dan",
97
+ "password" => "gobbledygook",
98
+ "host" => "localhost"
99
+ }
100
+ }
101
+ end
56
102
  end
57
103
  end
@@ -0,0 +1,125 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ require "safe_yaml/transform"
4
+
5
+ module SharedSpecs
6
+ def self.included(base)
7
+ base.instance_eval do
8
+ it "translates most values to strings" do
9
+ parse "key: value"
10
+ result.should == { "key" => "value" }
11
+ end
12
+
13
+ it "translates values starting with ':' to symbols" do
14
+ parse ":key: value"
15
+ result.should == { :key => "value" }
16
+ end
17
+
18
+ it "translates valid integral numbers to integers" do
19
+ parse "integer: 1"
20
+ result.should == { "integer" => 1 }
21
+ end
22
+
23
+ it "translates valid decimal numbers to floats" do
24
+ parse "float: 3.14"
25
+ result.should == { "float" => 3.14 }
26
+ end
27
+
28
+ it "translates valid true/false values to booleans" do
29
+ parse <<-YAML
30
+ - yes
31
+ - true
32
+ - no
33
+ - false
34
+ YAML
35
+
36
+ result.should == [true, true, false, false]
37
+ end
38
+
39
+ it "translates valid nulls to nil" do
40
+ parse <<-YAML
41
+ -
42
+ - ~
43
+ - null
44
+ YAML
45
+
46
+ result.should == [nil] * 3
47
+ end
48
+
49
+ it "applies the same transformations to values as to keys" do
50
+ parse <<-YAML
51
+ string: value
52
+ symbol: :value
53
+ integer: 1
54
+ float: 3.14
55
+ YAML
56
+
57
+ result.should == {
58
+ "string" => "value",
59
+ "symbol" => :value,
60
+ "integer" => 1,
61
+ "float" => 3.14
62
+ }
63
+ end
64
+
65
+ it "translates sequences to arrays" do
66
+ parse <<-YAML
67
+ - foo
68
+ - bar
69
+ - baz
70
+ YAML
71
+
72
+ result.should == ["foo", "bar", "baz"]
73
+ end
74
+
75
+ it "applies the same transformations to elements in sequences as to all values" do
76
+ parse <<-YAML
77
+ - string
78
+ - :symbol
79
+ - 1
80
+ - 3.14
81
+ YAML
82
+
83
+ result.should == ["string", :symbol, 1, 3.14]
84
+ end
85
+
86
+ it "translates maps to hashes" do
87
+ parse <<-YAML
88
+ foo: blah
89
+ bar: glah
90
+ baz: flah
91
+ YAML
92
+
93
+ result.should == {
94
+ "foo" => "blah",
95
+ "bar" => "glah",
96
+ "baz" => "flah"
97
+ }
98
+ end
99
+
100
+ it "applies the same transformations to values in hashes as to all values" do
101
+ parse <<-YAML
102
+ foo: :symbol
103
+ bar: 1
104
+ baz: 3.14
105
+ YAML
106
+
107
+ result.should == {
108
+ "foo" => :symbol,
109
+ "bar" => 1,
110
+ "baz" => 3.14
111
+ }
112
+ end
113
+
114
+ it "deals just fine with nested maps" do
115
+ parse <<-YAML
116
+ foo:
117
+ bar:
118
+ marco: polo
119
+ YAML
120
+
121
+ result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
122
+ end
123
+ end
124
+ end
125
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,3 +5,6 @@ $LOAD_PATH << File.join(ROOT, "lib")
5
5
  $LOAD_PATH << File.join(HERE, "support")
6
6
 
7
7
  require "heredoc_unindent"
8
+ require "pry"
9
+
10
+ require File.join(HERE, "shared_specs")
@@ -1,23 +1,29 @@
1
1
  class ExploitableBackDoor
2
- @@exploited = false
2
+ def exploited?
3
+ @exploited_through_setter || @exploited_through_init_with || @exploited_through_ivars
4
+ end
5
+
6
+ def exploited_through_setter?
7
+ @exploited_through_setter
8
+ end
3
9
 
4
- def self.exploited?
5
- @@exploited
10
+ def exploited_through_init_with?
11
+ @exploited_through_init_with
6
12
  end
7
13
 
8
- def self.reset
9
- @@exploited = false
14
+ def exploited_through_ivars?
15
+ self.instance_variables.any?
10
16
  end
11
17
 
12
18
  def init_with(command)
13
19
  # Note: this is how bad this COULD be.
14
20
  # system("#{command}")
15
- @@exploited = true
21
+ @exploited_through_init_with = true
16
22
  end
17
23
 
18
24
  def []=(command, arguments)
19
25
  # Note: this is how bad this COULD be.
20
26
  # system("#{command} #{arguments}")
21
- @@exploited = true
27
+ @exploited_through_setter = true
22
28
  end
23
29
  end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ if RUBY_VERSION < "1.9.2"
4
+ require "safe_yaml/syck_resolver"
5
+
6
+ describe SafeYAML::SyckResolver do
7
+ let(:resolver) { SafeYAML::SyckResolver.new }
8
+ let(:result) { @result }
9
+
10
+ def parse(yaml)
11
+ tree = YAML.parse(yaml.unindent)
12
+ @result = resolver.resolve_tree(tree)
13
+ end
14
+
15
+ include SharedSpecs
16
+ end
17
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safe_yaml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: '0.3'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,9 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-17 00:00:00.000000000 Z
12
+ date: 2013-01-18 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: Parse (simple) YAML safely, without that pesky arbitrary code execution
15
- vulnerability.
14
+ description: Parse YAML safely, without that pesky arbitrary code execution vulnerability.
16
15
  email: daniel.tao@gmail.com
17
16
  executables: []
18
17
  extensions: []
@@ -24,14 +23,18 @@ files:
24
23
  - README.md
25
24
  - Rakefile
26
25
  - lib/safe_yaml.rb
27
- - lib/safe_yaml/handler.rb
26
+ - lib/safe_yaml/psych_handler.rb
27
+ - lib/safe_yaml/syck_resolver.rb
28
+ - lib/safe_yaml/transform.rb
28
29
  - lib/safe_yaml/version.rb
29
30
  - safe_yaml.gemspec
30
- - spec/handler_spec.rb
31
+ - spec/psych_handler_spec.rb
31
32
  - spec/safe_yaml_spec.rb
33
+ - spec/shared_specs.rb
32
34
  - spec/spec_helper.rb
33
35
  - spec/support/exploitable_back_door.rb
34
- homepage: http://dtao.github.com/safe_yaml/
36
+ - spec/syck_resolver_spec.rb
37
+ homepage: http://github.com/dtao/safe_yaml
35
38
  licenses: []
36
39
  post_install_message:
37
40
  rdoc_options: []
@@ -42,7 +45,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
45
  requirements:
43
46
  - - ! '>='
44
47
  - !ruby/object:Gem::Version
45
- version: 1.9.2
48
+ version: 1.8.7
46
49
  required_rubygems_version: !ruby/object:Gem::Requirement
47
50
  none: false
48
51
  requirements:
@@ -57,7 +60,9 @@ specification_version: 3
57
60
  summary: SameYAML adds a ::safe_load method to Ruby's built-in YAML module to parse
58
61
  YAML data for only basic types (strings, symbols, numbers, arrays, and hashes).
59
62
  test_files:
60
- - spec/handler_spec.rb
63
+ - spec/psych_handler_spec.rb
61
64
  - spec/safe_yaml_spec.rb
65
+ - spec/shared_specs.rb
62
66
  - spec/spec_helper.rb
63
67
  - spec/support/exploitable_back_door.rb
68
+ - spec/syck_resolver_spec.rb
data/spec/handler_spec.rb DELETED
@@ -1,172 +0,0 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
2
-
3
- require "safe_yaml/handler"
4
-
5
- describe SafeYAML::Handler do
6
- let(:handler) { SafeYAML::Handler.new }
7
- let(:parser) { Psych::Parser.new(handler) }
8
- let(:result) { handler.result }
9
-
10
- def parse(yaml)
11
- parser.parse(yaml.unindent)
12
- end
13
-
14
- it "translates most values to strings" do
15
- parser.parse "key: value"
16
- result.should == { "key" => "value" }
17
- end
18
-
19
- it "translates values starting with ':' to symbols" do
20
- parser.parse ":key: value"
21
- result.should == { :key => "value" }
22
- end
23
-
24
- it "translates valid integral numbers to integers" do
25
- parser.parse "integer: 1"
26
- result.should == { "integer" => 1 }
27
- end
28
-
29
- it "translates valid decimal numbers to floats" do
30
- parser.parse "float: 3.14"
31
- result.should == { "float" => 3.14 }
32
- end
33
-
34
- it "translates valid true/false values to booleans" do
35
- parser.parse <<-YAML
36
- - yes
37
- - true
38
- - no
39
- - false
40
- YAML
41
-
42
- result.should == [true, true, false, false]
43
- end
44
-
45
- it "translates valid nulls to nil" do
46
- parser.parse <<-YAML
47
- -
48
- - ~
49
- - null
50
- YAML
51
-
52
- result.should == [nil] * 3
53
- end
54
-
55
- it "applies the same transformations to values as to keys" do
56
- parse <<-YAML
57
- string: value
58
- symbol: :value
59
- integer: 1
60
- float: 3.14
61
- YAML
62
-
63
- result.should == {
64
- "string" => "value",
65
- "symbol" => :value,
66
- "integer" => 1,
67
- "float" => 3.14
68
- }
69
- end
70
-
71
- it "translates sequences to arrays" do
72
- parse <<-YAML
73
- - foo
74
- - bar
75
- - baz
76
- YAML
77
-
78
- result.should == ["foo", "bar", "baz"]
79
- end
80
-
81
- it "applies the same transformations to elements in sequences as to all values" do
82
- parse <<-YAML
83
- - string
84
- - :symbol
85
- - 1
86
- - 3.14
87
- YAML
88
-
89
- result.should == ["string", :symbol, 1, 3.14]
90
- end
91
-
92
- it "translates maps to hashes" do
93
- parse <<-YAML
94
- foo: blah
95
- bar: glah
96
- baz: flah
97
- YAML
98
-
99
- result.should == {
100
- "foo" => "blah",
101
- "bar" => "glah",
102
- "baz" => "flah"
103
- }
104
- end
105
-
106
- it "applies the same transformations to values in hashes as to all values" do
107
- parse <<-YAML
108
- foo: :symbol
109
- bar: 1
110
- baz: 3.14
111
- YAML
112
-
113
- result.should == {
114
- "foo" => :symbol,
115
- "bar" => 1,
116
- "baz" => 3.14
117
- }
118
- end
119
-
120
- it "deals just fine with nested maps" do
121
- parse <<-YAML
122
- foo:
123
- bar:
124
- marco: polo
125
- YAML
126
-
127
- result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
128
- end
129
-
130
- it "deals just fine with aliases and anchors" do
131
- parse <<-YAML
132
- - &id001 {}
133
- - *id001
134
- - *id001
135
- YAML
136
-
137
- result.should == [{}, {}, {}]
138
- end
139
-
140
- it "deals just fine with sections" do
141
- parse <<-YAML
142
- mysql: &mysql
143
- adapter: mysql
144
- pool: 30
145
- login: &login
146
- username: dan
147
- password: gobbledygook
148
- local: &local
149
- <<: *mysql
150
- <<: *login
151
- host: localhost
152
- YAML
153
-
154
- result.should == {
155
- "mysql" => {
156
- "adapter" => "mysql",
157
- "pool" => 30
158
- },
159
- "login" => {
160
- "username" => "dan",
161
- "password" => "gobbledygook"
162
- },
163
- "local" => {
164
- "adapter" => "mysql",
165
- "pool" => 30,
166
- "username" => "dan",
167
- "password" => "gobbledygook",
168
- "host" => "localhost"
169
- }
170
- }
171
- end
172
- end