travis-yaml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +14 -0
  5. data/Gemfile +9 -0
  6. data/Gemfile.lock +73 -0
  7. data/LICENSE +22 -0
  8. data/README.md +232 -0
  9. data/Rakefile +3 -0
  10. data/SPEC.md +1018 -0
  11. data/bench/parser_bench.rb +54 -0
  12. data/config.ru +2 -0
  13. data/lib/travis/yaml.rb +43 -0
  14. data/lib/travis/yaml/matrix.rb +65 -0
  15. data/lib/travis/yaml/nodes.rb +40 -0
  16. data/lib/travis/yaml/nodes/branches.rb +12 -0
  17. data/lib/travis/yaml/nodes/bundler_args.rb +6 -0
  18. data/lib/travis/yaml/nodes/cache.rb +29 -0
  19. data/lib/travis/yaml/nodes/compiler.rb +7 -0
  20. data/lib/travis/yaml/nodes/compiler_entry.rb +9 -0
  21. data/lib/travis/yaml/nodes/deploy.rb +7 -0
  22. data/lib/travis/yaml/nodes/deploy_conditions.rb +12 -0
  23. data/lib/travis/yaml/nodes/deploy_entry.rb +10 -0
  24. data/lib/travis/yaml/nodes/env.rb +36 -0
  25. data/lib/travis/yaml/nodes/fixed_value.rb +60 -0
  26. data/lib/travis/yaml/nodes/git.rb +9 -0
  27. data/lib/travis/yaml/nodes/jdk.rb +11 -0
  28. data/lib/travis/yaml/nodes/language.rb +18 -0
  29. data/lib/travis/yaml/nodes/language_specific.rb +45 -0
  30. data/lib/travis/yaml/nodes/mapping.rb +204 -0
  31. data/lib/travis/yaml/nodes/matrix.rb +36 -0
  32. data/lib/travis/yaml/nodes/node.rb +102 -0
  33. data/lib/travis/yaml/nodes/notifications.rb +77 -0
  34. data/lib/travis/yaml/nodes/open_mapping.rb +18 -0
  35. data/lib/travis/yaml/nodes/os.rb +21 -0
  36. data/lib/travis/yaml/nodes/os_entry.rb +19 -0
  37. data/lib/travis/yaml/nodes/root.rb +44 -0
  38. data/lib/travis/yaml/nodes/ruby.rb +11 -0
  39. data/lib/travis/yaml/nodes/scalar.rb +97 -0
  40. data/lib/travis/yaml/nodes/sequence.rb +84 -0
  41. data/lib/travis/yaml/nodes/stage.rb +6 -0
  42. data/lib/travis/yaml/nodes/version.rb +6 -0
  43. data/lib/travis/yaml/nodes/version_list.rb +7 -0
  44. data/lib/travis/yaml/nodes/virtual_env.rb +7 -0
  45. data/lib/travis/yaml/parser.rb +31 -0
  46. data/lib/travis/yaml/parser/dummy.rb +13 -0
  47. data/lib/travis/yaml/parser/psych.rb +217 -0
  48. data/lib/travis/yaml/parser/ruby.rb +77 -0
  49. data/lib/travis/yaml/secure_string.rb +12 -0
  50. data/lib/travis/yaml/version.rb +5 -0
  51. data/play/lint.rb +8 -0
  52. data/play/spec.rb +183 -0
  53. data/play/weblint.rb +296 -0
  54. data/spec/nodes/.rb +0 -0
  55. data/spec/nodes/branches_spec.rb +45 -0
  56. data/spec/nodes/bundler_args_spec.rb +9 -0
  57. data/spec/nodes/cache_spec.rb +55 -0
  58. data/spec/nodes/compiler_spec.rb +14 -0
  59. data/spec/nodes/deploy_spec.rb +83 -0
  60. data/spec/nodes/git_spec.rb +55 -0
  61. data/spec/nodes/jdk_spec.rb +41 -0
  62. data/spec/nodes/language_spec.rb +79 -0
  63. data/spec/nodes/notifications_spec.rb +45 -0
  64. data/spec/nodes/os_spec.rb +28 -0
  65. data/spec/nodes/ruby_spec.rb +69 -0
  66. data/spec/nodes/stage_spec.rb +34 -0
  67. data/spec/nodes/virtual_env_spec.rb +9 -0
  68. data/spec/parser/dummy_spec.rb +7 -0
  69. data/spec/parser/ruby_spec.rb +41 -0
  70. data/spec/support.rb +3 -0
  71. data/spec/support/coverage.rb +11 -0
  72. data/spec/support/environment.rb +1 -0
  73. data/spec/yaml_spec.rb +26 -0
  74. data/travis-yaml.gemspec +24 -0
  75. metadata +207 -0
@@ -0,0 +1,18 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class OpenMapping < Mapping
4
+ def self.default_type(identifier = nil)
5
+ @default_type = Nodes[identifier] if identifier
6
+ @default_type ||= superclass.respond_to?(:default_type) ? superclass.default_type : Scalar
7
+ end
8
+
9
+ def self.subnode_for(key)
10
+ super(key) || default_type
11
+ end
12
+
13
+ def accept_key?(key)
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class OS < Sequence
4
+ type OSEntry
5
+
6
+ def verify_language(language)
7
+ children.delete_if do |os|
8
+ next false if os.supports_language? language
9
+ warning "dropping %p, does not support %p", os, language
10
+ true
11
+ end
12
+
13
+ if children.empty?
14
+ default_os = language.respond_to?(:default_os) ? language.default_os : OSEntry.default
15
+ warning "no suitable operating system given for %p, using %p", language, default_os.to_s
16
+ children << OSEntry.new(self) { |os| os.value = default_os }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class OSEntry < FixedValue
4
+ OSX = %w[objective-c ruby c cpp]
5
+
6
+ ignore_case
7
+ default :linux
8
+ value :linux, ubuntu: :linux
9
+ value :osx, mac: :osx, macos: :osx
10
+
11
+ def supports_language?(language)
12
+ case value
13
+ when 'linux' then language != 'objective-c'
14
+ when 'osx' then OSX.include? language
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Root < Mapping
4
+ include LanguageSpecific
5
+
6
+ map :language, required: true
7
+ map :bundler_args, to: BundlerArgs
8
+ map :deploy, :ruby, :os, :compiler, :git, :jdk, :virtualenv, :matrix, :env, :notifications, :branches, :cache
9
+ map :lein, :otp_release, :go, :ghc, :node_js, :xcode_sdk, :xcode_scheme, :perl, :php, :python, :services, :gemfile, to: VersionList
10
+ map :rvm, to: :ruby
11
+ map :otp, to: :otp_release
12
+ map :node, to: :node_js
13
+ map :virtual_env, to: :virtualenv
14
+ map :osx_image, to: Version, experimental: true
15
+ map :gobuild_args, :xcode_project, :xcode_workspace, :xctool_args, :composer_args, :npm_args, to: Scalar[:str]
16
+ map :source_key, to: Scalar[:str, :secure]
17
+ map :sdk_components, to: Sequence
18
+ map :before_install, :install, :before_script, :script, :after_result, :after_script,
19
+ :after_success, :after_failure, :before_deploy, :after_deploy, to: Stage
20
+
21
+ def initialize
22
+ super(nil)
23
+ end
24
+
25
+ def verify
26
+ super
27
+ verify_os
28
+ verify_language(language)
29
+ end
30
+
31
+ def verify_os
32
+ self.os = language.default_os unless include? :os
33
+ end
34
+
35
+ def nested_warnings(*)
36
+ super.uniq
37
+ end
38
+
39
+ def inspect
40
+ "#<Travis::Yaml:#{super}>"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Ruby < VersionList
4
+ def jruby?
5
+ @children.any? do |child|
6
+ child.start_with? 'jruby'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,97 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Scalar < Node
4
+ def self.[](*types)
5
+ Class.new(self) do
6
+ default_type(types.first)
7
+ cast(*types)
8
+ end
9
+ end
10
+
11
+ def self.cast?(type)
12
+ cast.include? type
13
+ end
14
+
15
+ def self.cast(*types)
16
+ @cast ||= superclass.respond_to?(:cast) ? superclass.cast.dup : []
17
+ @cast.concat(types) if types.any?
18
+ @cast
19
+ end
20
+
21
+ def self.default_type(type = nil)
22
+ @default_type = type if type
23
+ @default_type ||= superclass.respond_to?(:default_type) ? superclass.default_type : :str
24
+ end
25
+
26
+ def self.default(value = nil)
27
+ @default = value if value
28
+ @default ||= nil
29
+ end
30
+
31
+ def self.has_default?
32
+ !default.nil?
33
+ end
34
+
35
+ attr_accessor :value
36
+ alias_method :__getobj__, :value
37
+
38
+ def empty?
39
+ value.nil?
40
+ end
41
+
42
+ def prepare
43
+ self.value = self.class.default
44
+ @multiple = false
45
+ super
46
+ end
47
+
48
+ def ==(other)
49
+ other = other.value if other.is_a? self.class
50
+ other == value
51
+ end
52
+
53
+ def default_type
54
+ self.class.default_type
55
+ end
56
+
57
+ def inspect
58
+ value.inspect
59
+ end
60
+
61
+ def visit_scalar(visitor, type, value, implicit = true)
62
+ return self.value = cast(visitor, type, value) if cast? type
63
+ return self.value = cast(visitor, default_type, value) if implicit
64
+ error "%p not supported, dropping %p", type.to_s, cast(visitor, :str, value)
65
+ end
66
+
67
+ def visit_sequence(visitor, value)
68
+ @multiple = false
69
+ visitor.apply_sequence(self, value)
70
+ end
71
+
72
+ def visit_child(visitor, value)
73
+ if @multiple
74
+ value = cast(visitor, :str, value) rescue value
75
+ warning "does not support multiple values, dropping %p", value
76
+ else
77
+ @multiple = true
78
+ visitor.accept(self, value)
79
+ end
80
+ end
81
+
82
+ def cast(visitor, type, value)
83
+ visitor.cast(type, value)
84
+ rescue ArgumentError => error
85
+ error "failed to parse %p - %s", type.to_s, error.message
86
+ end
87
+
88
+ def cast?(type)
89
+ self.class.cast?(type) or type == default_type
90
+ end
91
+
92
+ def !@
93
+ !value
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,84 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Sequence < Node
4
+ attr_reader :children
5
+ alias_method :__getobj__, :children
6
+
7
+ def self.type(identifier = nil)
8
+ @type = Nodes[identifier] if identifier
9
+ @type ||= superclass.respond_to?(:type) ? superclass.type : Scalar
10
+ end
11
+
12
+ def prepare
13
+ @children = []
14
+ end
15
+
16
+ def visit_sequence(visitor, value)
17
+ visitor.apply_sequence(self, value)
18
+ end
19
+
20
+ def visit_scalar(visitor, type, value, implicit = true)
21
+ visit_child(visitor, value) if type != :null
22
+ end
23
+
24
+ def visit_mapping(visitor, value)
25
+ visit_child(visitor, value)
26
+ end
27
+
28
+ def visit_child(visitor, value)
29
+ child = self.class.type.new(self)
30
+ visitor.accept(child, value)
31
+ @children << child
32
+ end
33
+
34
+ def nested_warnings(*prefix)
35
+ @children.inject(super) do |list, value|
36
+ list = value.nested_warnings(*prefix) + list
37
+ end
38
+ end
39
+
40
+ def ==(other)
41
+ other = other.children if other.is_a? Sequence
42
+ if other.respond_to? :to_a and other.to_a.size == children.size
43
+ children.zip(other.to_a).all? { |a, b| a == b }
44
+ else
45
+ identifier == other
46
+ end
47
+ end
48
+
49
+ def empty?
50
+ @children.empty?
51
+ end
52
+
53
+ def inspect
54
+ identifier.inspect
55
+ end
56
+
57
+ def to_s
58
+ identifier.to_s
59
+ end
60
+
61
+ def identifier
62
+ @children.size == 1 ? @children.first : @children
63
+ end
64
+
65
+ def verify
66
+ verify_children
67
+ super
68
+ end
69
+
70
+ def verify_children
71
+ @children.delete_if do |child|
72
+ next unless child.errors?
73
+ child.errors.each { |message| warning(message) }
74
+ true
75
+ end
76
+ end
77
+
78
+ def deep_verify
79
+ @children.each(&:deep_verify)
80
+ super
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,6 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Stage < Sequence
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Version < Scalar
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class VersionList < Sequence
4
+ type Version
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class VirtualEnv < Mapping
4
+ map :system_site_packages, to: Scalar[:bool]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ module Travis::Yaml
2
+ module Parser
3
+ require 'travis/yaml/parser/dummy'
4
+ require 'travis/yaml/parser/psych'
5
+ require 'travis/yaml/parser/ruby'
6
+
7
+ extend self, Enumerable
8
+
9
+ def parses?(value)
10
+ !!parser_for(value)
11
+ end
12
+
13
+ def parse(value)
14
+ raise ArgumentError, "cannot parse %p" % value unless parser = parser_for(value)
15
+ parser.parse(value)
16
+ end
17
+
18
+ def parser_for(value)
19
+ detect { |p| p.parses? value if p.respond_to? :parses? }
20
+ end
21
+
22
+ def each(&block)
23
+ parsers.each(&block)
24
+ end
25
+
26
+ def parsers
27
+ constants.map { |name| const_get(name) }.
28
+ select { |c| c.respond_to? :parse }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ module Travis::Yaml
2
+ module Parser
3
+ module Dummy
4
+ def self.parses?(value)
5
+ value.is_a? Travis::Yaml::Nodes::Node
6
+ end
7
+
8
+ def self.parse(value)
9
+ value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,217 @@
1
+ require 'psych'
2
+ require 'delegate'
3
+
4
+ module Travis::Yaml
5
+ module Parser
6
+ class Psych
7
+ class SetNode < DelegateClass(::Psych::Nodes::Mapping)
8
+ def children
9
+ super.select.with_index { |_,i| i.even? }
10
+ end
11
+ end
12
+
13
+ class ScalarSequence < DelegateClass(::Psych::Nodes::Mapping)
14
+ def children
15
+ [__getobj__]
16
+ end
17
+ end
18
+
19
+ MAP = /\A(?:tag:yaml\.org,2002:|!!?)map\z/
20
+ OMAP = /\A(?:tag:yaml\.org,2002:|!!?)omap\z/
21
+ PAIRS = /\A(?:tag:yaml\.org,2002:|!!?)pairs\z/
22
+ SET = /\A(?:tag:yaml\.org,2002:|!!?)set\z/
23
+ SEQ = /\A(?:tag:yaml\.org,2002:|!!?)seq\z/
24
+ BINARY = /\A(?:tag:yaml\.org,2002:|!!?)binary\z/
25
+ BOOL = /\A(?:tag:yaml\.org,2002:|!!?)bool\z/
26
+ FLOAT = /\A(?:tag:yaml\.org,2002:|!!?)float\z/
27
+ INT = /\A(?:tag:yaml\.org,2002:|!!?)int\z/
28
+ MERGE = /\A(?:tag:yaml\.org,2002:|!!?)merge\z/
29
+ NULL = /\A(?:tag:yaml\.org,2002:|!!?)null\z/
30
+ STR = /\A(?:tag:yaml\.org,2002:|!!?)str\z/
31
+ TIMESTAMP = /\A(?:tag:yaml\.org,2002:|!!?)timestamp\z/
32
+ VALUE = /\A(?:tag:yaml\.org,2002:|!!?)value\z/
33
+ YAML = /\A(?:tag:yaml\.org,2002:|!!?)yaml\z/
34
+ SECURE = /\A!(?:encrypted|secure|decrypted)\z/
35
+ TRUE = /\A(?:y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON)\z/
36
+ FALSE = /\A(?:n|N|no|No|NO|false|False|FALSE|off|Off|OFF)\z/
37
+ REGEXP = /\A!(?:ruby\/)?regexp\z/
38
+ REG_FLAGS = { 'i' => Regexp::IGNORECASE, 'm' => Regexp::MULTILINE, 'x' => Regexp::EXTENDED }
39
+ FORMATS = {
40
+ '!bool' => Regexp.union(TRUE, FALSE),
41
+ '!float' => ::Psych::ScalarScanner::FLOAT,
42
+ '!null' => /\A(:?~|null|Null|NULL|)\z/,
43
+ '!timestamp' => ::Psych::ScalarScanner::TIME,
44
+ '!int' => ::Psych::ScalarScanner::INTEGER,
45
+ '!regexp' => /\A\/(.*)\/([imx]*)\z/
46
+ }
47
+
48
+ if defined? ::Psych::ClassLoader
49
+ CLASS_LOADER = ::Psych::ClassLoader.new
50
+ class ScalarScanner < ::Psych::ScalarScanner
51
+ def initialize
52
+ super(CLASS_LOADER)
53
+ end
54
+ end
55
+ else
56
+ ScalarScanner = ::Psych::ScalarScanner
57
+ end
58
+
59
+ def self.parses?(value)
60
+ return true if value.is_a?(::Psych::Nodes::Node)
61
+ return true if value.is_a?(String) or value.is_a?(IO)
62
+ return true if defined?(StringIO) and value.is_a?(StringIO)
63
+ value.respond_to?(:to_str) or value.respond_to?(:to_io)
64
+ end
65
+
66
+ def self.parse(value)
67
+ new(value).parse
68
+ end
69
+
70
+ def initialize(value)
71
+ value = value.to_str if value.respond_to? :to_str
72
+ value = value.to_io if value.respond_to? :to_io
73
+ @value = value
74
+ @scanner = ScalarScanner.new
75
+ end
76
+
77
+ def parse(root = nil)
78
+ root ||= Travis::Yaml::Nodes::Root.new
79
+ parsed = @value if @value.is_a? ::Psych::Nodes::Node
80
+ parsed ||= ::Psych.parse(@value)
81
+ accept(root, parsed)
82
+ root
83
+ rescue ::Psych::SyntaxError => error
84
+ root.verify
85
+ root.warnings.clear
86
+ root.error("syntax error: %s", error.message)
87
+ root
88
+ end
89
+
90
+ def accept(node, value)
91
+ case value
92
+ when ::Psych::Nodes::Scalar then accept_scalar node, value
93
+ when ::Psych::Nodes::Mapping then accept_mapping node, value
94
+ when ::Psych::Nodes::Sequence then accept_sequence node, value
95
+ when ::Psych::Nodes::Alias then accept_alias node, value
96
+ when ::Psych::Nodes::Document then accept node, value.root
97
+ when ::Psych::Nodes::Stream then accept_sequence node, value
98
+ else node.visit_unexpected(self, value) if value
99
+ end
100
+ node.verify
101
+ end
102
+
103
+ def accept_sequence(node, value)
104
+ case value.tag
105
+ when SET, SEQ
106
+ node.visit_sequence self, value
107
+ when nil
108
+ value = ScalarSequence.new(value) unless value.is_a? ::Psych::Nodes::Sequence
109
+ node.visit_sequence self, value
110
+ else
111
+ node.visit_sequence self, ScalarSequence.new(value)
112
+ end
113
+ end
114
+
115
+ def accept_mapping(node, value)
116
+ case value.tag
117
+ when MAP, OMAP, PAIRS then node.visit_mapping self, value
118
+ when SET then node.visit_sequence self, SetNode.new(value)
119
+ when SEQ then node.visit_sequence self, value
120
+ when nil
121
+ if value.children.size == 2 and value.children.first.value == 'secure'
122
+ node.visit_scalar(self, :secure, value.children.last)
123
+ else
124
+ node.visit_mapping(self, value)
125
+ end
126
+ else
127
+ node.visit_unexpected self, value, "unexpected tag %p for mapping" % value.tag
128
+ end
129
+ end
130
+
131
+ def accept_scalar(node, value)
132
+ case tag = scalar_tag(value)
133
+ when BINARY then node.visit_scalar self, :binary, value, value.tag.nil?
134
+ when BOOL then node.visit_scalar self, :bool, value, value.tag.nil?
135
+ when FLOAT then node.visit_scalar self, :float, value, value.tag.nil?
136
+ when INT then node.visit_scalar self, :int, value, value.tag.nil?
137
+ when NULL then node.visit_scalar self, :null, value, value.tag.nil?
138
+ when STR then node.visit_scalar self, :str, value, value.tag.nil?
139
+ when TIMESTAMP then node.visit_scalar self, :time, value, value.tag.nil?
140
+ when SECURE then node.visit_scalar self, :secure, value, value.tag.nil?
141
+ when NULL then node.visit_scalar self, :null, value, value.tag.nil?
142
+ when REGEXP then node.visit_scalar self, :regexp, value, value.tag.nil?
143
+ else node.visit_unexpected self, value, "unexpected tag %p for scalar %p" % [tag, simple(value)]
144
+ end
145
+ end
146
+
147
+ def simple(value)
148
+ case value
149
+ when ::Psych::Nodes::Scalar then value.value
150
+ when ::Psych::Nodes::Mapping then simple_mapping(value)
151
+ when ::Psych::Nodes::Sequence then value.children.map { |c| simple(c) }
152
+ when ::Psych::Nodes::Document then simple(value.root)
153
+ when ::Psych::Nodes::Stream then value.children.map { |c| simple(c) }
154
+ else value
155
+ end
156
+ end
157
+
158
+ def simple_mapping(value)
159
+ children = {}
160
+ keys, values = value.children.group_by.with_index { |_,i| i.even? }.values_at(true, false)
161
+ keys.zip(values) { |key, value| children[simple(key)] = simple(value) } if keys and values
162
+ children
163
+ end
164
+
165
+ def scalar_tag(value)
166
+ return value.tag if value.tag
167
+ return '!str' if value.quoted
168
+ FORMATS.each do |tag, format|
169
+ return tag if value.value =~ format
170
+ end
171
+ '!str'
172
+ end
173
+
174
+ def regexp(pattern)
175
+ return pattern if pattern.is_a? Regexp
176
+ return Regexp.new(pattern) unless pattern =~ FORMATS['!regexp']
177
+ flag = $2.chars.inject(0) { |f,c| f | REG_FLAGS.fetch(c, 0) }
178
+ Regexp.new($1, flag)
179
+ rescue RegexpError => error
180
+ raise ArgumentError, "broken regular expression - #{error.message}"
181
+ end
182
+
183
+ def cast(type, value)
184
+ case type
185
+ when :str then value.value
186
+ when :binary then value.value.unpack('m').first
187
+ when :bool then value.value !~ FALSE
188
+ when :float then Float @scanner.tokenize(value.value)
189
+ when :int then Integer @scanner.tokenize(value.value)
190
+ when :time then @scanner.parse_time(value.value)
191
+ when :secure then SecureString.new(value.value, value.tag != '!decrypted')
192
+ when :regexp then regexp(value.value)
193
+ when :null then nil
194
+ else raise ArgumentError, 'unknown scalar type %p' % type
195
+ end
196
+ end
197
+
198
+ def apply_mapping(node, value)
199
+ keys, values = value.children.group_by.with_index { |_,i| i.even? }.values_at(true, false)
200
+ keys.zip(values) { |key, value| node.visit_pair(self, key, value) } if keys and values
201
+ end
202
+
203
+ def apply_sequence(node, value)
204
+ value.children.each { |child| node.visit_child(self, child) }
205
+ end
206
+
207
+ def generate_key(node, value)
208
+ unless value.respond_to? :value and (value.tag.nil? || value.tag == STR)
209
+ node.visit_unexpected(self, value, "expected string as key")
210
+ end
211
+
212
+ value = value.value.to_s
213
+ value.start_with?(?:) ? value[1..-1] : value
214
+ end
215
+ end
216
+ end
217
+ end