safe_yaml 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ dist/
data/lib/safe_yaml.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "yaml"
2
- require "handler"
1
+ require "safe_yaml/handler"
2
+ require "safe_yaml/version"
3
3
 
4
4
  module YAML
5
5
  def self.safe_load(yaml)
@@ -2,7 +2,20 @@ require "yaml"
2
2
 
3
3
  module SafeYAML
4
4
  class Handler < Psych::Handler
5
+ PREDEFINED_VALUES = {
6
+ "" => nil,
7
+ "~" => nil,
8
+ "null" => nil,
9
+ "yes" => true,
10
+ "on" => true,
11
+ "true" => true,
12
+ "no" => false,
13
+ "off" => false,
14
+ "false" => false
15
+ }.freeze
16
+
5
17
  def initialize
18
+ @anchors = {}
6
19
  @stack = []
7
20
  end
8
21
 
@@ -10,7 +23,11 @@ module SafeYAML
10
23
  @result
11
24
  end
12
25
 
13
- def add_to_current_structure(value)
26
+ def add_to_current_structure(value, anchor=nil)
27
+ value = transform_value(value)
28
+
29
+ @anchors[anchor] = value if anchor
30
+
14
31
  if @result.nil?
15
32
  @result = value
16
33
  @current_structure = @result
@@ -19,13 +36,19 @@ module SafeYAML
19
36
 
20
37
  case @current_structure
21
38
  when Array
22
- @current_structure.push(transform_value(value))
39
+ @current_structure.push(value)
23
40
 
24
41
  when Hash
25
42
  if @current_key.nil?
26
- @current_key = transform_value(value)
43
+ @current_key = value
44
+
27
45
  else
28
- @current_structure[@current_key] = transform_value(value)
46
+ if @current_key == "<<"
47
+ @current_structure.merge!(value)
48
+ else
49
+ @current_structure[@current_key] = value
50
+ end
51
+
29
52
  @current_key = nil
30
53
  end
31
54
 
@@ -36,7 +59,10 @@ module SafeYAML
36
59
 
37
60
  def transform_value(value)
38
61
  if value.is_a?(String)
39
- if value.match(/^:\w+$/)
62
+ if PREDEFINED_VALUES.include?(value.downcase)
63
+ return PREDEFINED_VALUES[value.downcase]
64
+
65
+ elsif value.match(/^:\w+$/)
40
66
  return value[1..-1].to_sym
41
67
 
42
68
  elsif value.match(/^\d+$/)
@@ -50,37 +76,44 @@ module SafeYAML
50
76
  value
51
77
  end
52
78
 
79
+ def end_current_structure
80
+ @stack.pop
81
+ @current_structure = @stack.last
82
+ end
83
+
53
84
  def streaming?
54
85
  false
55
86
  end
56
87
 
57
88
  # event handlers
89
+ def alias(anchor)
90
+ add_to_current_structure(@anchors[anchor])
91
+ end
92
+
58
93
  def scalar(value, anchor, tag, plain, quoted, style)
59
- add_to_current_structure(value)
94
+ add_to_current_structure(value, anchor)
60
95
  end
61
96
 
62
- def start_mapping(*args) # anchor, tag, implicit, style
97
+ def start_mapping(anchor, tag, implicit, style)
63
98
  map = {}
64
- self.add_to_current_structure(map)
99
+ self.add_to_current_structure(map, anchor)
65
100
  @current_structure = map
66
101
  @stack.push(map)
67
102
  end
68
103
 
69
104
  def end_mapping
70
- @stack.pop
71
- @current_structure = @stack.last
105
+ self.end_current_structure()
72
106
  end
73
107
 
74
- def start_sequence(*args) # anchor, tag, implicit, style
108
+ def start_sequence(anchor, tag, implicit, style)
75
109
  seq = []
76
- self.add_to_current_structure(seq)
110
+ self.add_to_current_structure(seq, anchor)
77
111
  @current_structure = seq
78
112
  @stack.push(seq)
79
113
  end
80
114
 
81
115
  def end_sequence
82
- @stack.pop
83
- @current_structure = @stack.last
116
+ self.end_current_structure()
84
117
  end
85
118
  end
86
119
  end
@@ -1,3 +1,3 @@
1
1
  module SafeYAML
2
- VERSION = "0.1"
2
+ VERSION = "0.2"
3
3
  end
data/safe_yaml.gemspec CHANGED
@@ -1,10 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path("../lib/version", __FILE__)
2
+ require File.join(File.dirname(__FILE__), "lib", "safe_yaml", "version")
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = "safe_yaml"
6
- gem.authors = ["Dan Tao"]
7
- gem.email = ["daniel.tao@gmail.com"]
6
+ gem.version = SafeYAML::VERSION
7
+ gem.authors = "Dan Tao"
8
+ gem.email = "daniel.tao@gmail.com"
8
9
  gem.description = %q{Parse (simple) YAML safely, without that pesky arbitrary code execution vulnerability.}
9
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).}
10
11
  gem.homepage = "http://dtao.github.com/safe_yaml/"
@@ -12,5 +13,6 @@ Gem::Specification.new do |gem|
12
13
  gem.files = `git ls-files`.split($\)
13
14
  gem.test_files = gem.files.grep(%r{^spec/})
14
15
  gem.require_paths = ["lib"]
15
- gem.version = SafeYAML::VERSION
16
+
17
+ gem.add_dependency("psych")
16
18
  end
data/spec/handler_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
- require "handler"
3
+ require "safe_yaml/handler"
4
4
 
5
5
  describe SafeYAML::Handler do
6
6
  let(:handler) { SafeYAML::Handler.new }
@@ -31,6 +31,27 @@ describe SafeYAML::Handler do
31
31
  result.should == { "float" => 3.14 }
32
32
  end
33
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
+
34
55
  it "applies the same transformations to values as to keys" do
35
56
  parse <<-YAML
36
57
  string: value
@@ -105,4 +126,47 @@ describe SafeYAML::Handler do
105
126
 
106
127
  result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
107
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
108
172
  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.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,21 +10,37 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
  date: 2013-01-17 00:00:00.000000000 Z
13
- dependencies: []
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: psych
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Parse (simple) YAML safely, without that pesky arbitrary code execution
15
31
  vulnerability.
16
- email:
17
- - daniel.tao@gmail.com
32
+ email: daniel.tao@gmail.com
18
33
  executables: []
19
34
  extensions: []
20
35
  extra_rdoc_files: []
21
36
  files:
37
+ - .gitignore
22
38
  - Gemfile
23
39
  - Gemfile.lock
24
40
  - Rakefile
25
- - lib/handler.rb
26
41
  - lib/safe_yaml.rb
27
- - lib/version.rb
42
+ - lib/safe_yaml/handler.rb
43
+ - lib/safe_yaml/version.rb
28
44
  - safe_yaml.gemspec
29
45
  - spec/handler_spec.rb
30
46
  - spec/safe_yaml_spec.rb