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