travis-yaml 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/.travis.yml +14 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +73 -0
- data/LICENSE +22 -0
- data/README.md +232 -0
- data/Rakefile +3 -0
- data/SPEC.md +1018 -0
- data/bench/parser_bench.rb +54 -0
- data/config.ru +2 -0
- data/lib/travis/yaml.rb +43 -0
- data/lib/travis/yaml/matrix.rb +65 -0
- data/lib/travis/yaml/nodes.rb +40 -0
- data/lib/travis/yaml/nodes/branches.rb +12 -0
- data/lib/travis/yaml/nodes/bundler_args.rb +6 -0
- data/lib/travis/yaml/nodes/cache.rb +29 -0
- data/lib/travis/yaml/nodes/compiler.rb +7 -0
- data/lib/travis/yaml/nodes/compiler_entry.rb +9 -0
- data/lib/travis/yaml/nodes/deploy.rb +7 -0
- data/lib/travis/yaml/nodes/deploy_conditions.rb +12 -0
- data/lib/travis/yaml/nodes/deploy_entry.rb +10 -0
- data/lib/travis/yaml/nodes/env.rb +36 -0
- data/lib/travis/yaml/nodes/fixed_value.rb +60 -0
- data/lib/travis/yaml/nodes/git.rb +9 -0
- data/lib/travis/yaml/nodes/jdk.rb +11 -0
- data/lib/travis/yaml/nodes/language.rb +18 -0
- data/lib/travis/yaml/nodes/language_specific.rb +45 -0
- data/lib/travis/yaml/nodes/mapping.rb +204 -0
- data/lib/travis/yaml/nodes/matrix.rb +36 -0
- data/lib/travis/yaml/nodes/node.rb +102 -0
- data/lib/travis/yaml/nodes/notifications.rb +77 -0
- data/lib/travis/yaml/nodes/open_mapping.rb +18 -0
- data/lib/travis/yaml/nodes/os.rb +21 -0
- data/lib/travis/yaml/nodes/os_entry.rb +19 -0
- data/lib/travis/yaml/nodes/root.rb +44 -0
- data/lib/travis/yaml/nodes/ruby.rb +11 -0
- data/lib/travis/yaml/nodes/scalar.rb +97 -0
- data/lib/travis/yaml/nodes/sequence.rb +84 -0
- data/lib/travis/yaml/nodes/stage.rb +6 -0
- data/lib/travis/yaml/nodes/version.rb +6 -0
- data/lib/travis/yaml/nodes/version_list.rb +7 -0
- data/lib/travis/yaml/nodes/virtual_env.rb +7 -0
- data/lib/travis/yaml/parser.rb +31 -0
- data/lib/travis/yaml/parser/dummy.rb +13 -0
- data/lib/travis/yaml/parser/psych.rb +217 -0
- data/lib/travis/yaml/parser/ruby.rb +77 -0
- data/lib/travis/yaml/secure_string.rb +12 -0
- data/lib/travis/yaml/version.rb +5 -0
- data/play/lint.rb +8 -0
- data/play/spec.rb +183 -0
- data/play/weblint.rb +296 -0
- data/spec/nodes/.rb +0 -0
- data/spec/nodes/branches_spec.rb +45 -0
- data/spec/nodes/bundler_args_spec.rb +9 -0
- data/spec/nodes/cache_spec.rb +55 -0
- data/spec/nodes/compiler_spec.rb +14 -0
- data/spec/nodes/deploy_spec.rb +83 -0
- data/spec/nodes/git_spec.rb +55 -0
- data/spec/nodes/jdk_spec.rb +41 -0
- data/spec/nodes/language_spec.rb +79 -0
- data/spec/nodes/notifications_spec.rb +45 -0
- data/spec/nodes/os_spec.rb +28 -0
- data/spec/nodes/ruby_spec.rb +69 -0
- data/spec/nodes/stage_spec.rb +34 -0
- data/spec/nodes/virtual_env_spec.rb +9 -0
- data/spec/parser/dummy_spec.rb +7 -0
- data/spec/parser/ruby_spec.rb +41 -0
- data/spec/support.rb +3 -0
- data/spec/support/coverage.rb +11 -0
- data/spec/support/environment.rb +1 -0
- data/spec/yaml_spec.rb +26 -0
- data/travis-yaml.gemspec +24 -0
- 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,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,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,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
|