travis-yaml 0.1.0

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.
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