typesafe_config 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +202 -0
- data/README.md +2 -0
- data/lib/typesafe/config/config_error.rb +12 -0
- data/lib/typesafe/config/config_factory.rb +9 -0
- data/lib/typesafe/config/config_object.rb +4 -0
- data/lib/typesafe/config/config_parse_options.rb +53 -0
- data/lib/typesafe/config/config_render_options.rb +46 -0
- data/lib/typesafe/config/config_syntax.rb +7 -0
- data/lib/typesafe/config/config_value_type.rb +26 -0
- data/lib/typesafe/config/impl/abstract_config_object.rb +64 -0
- data/lib/typesafe/config/impl/abstract_config_value.rb +130 -0
- data/lib/typesafe/config/impl/config_concatenation.rb +136 -0
- data/lib/typesafe/config/impl/config_float.rb +9 -0
- data/lib/typesafe/config/impl/config_impl.rb +10 -0
- data/lib/typesafe/config/impl/config_impl_util.rb +78 -0
- data/lib/typesafe/config/impl/config_int.rb +31 -0
- data/lib/typesafe/config/impl/config_number.rb +27 -0
- data/lib/typesafe/config/impl/config_string.rb +37 -0
- data/lib/typesafe/config/impl/full_includer.rb +4 -0
- data/lib/typesafe/config/impl/origin_type.rb +9 -0
- data/lib/typesafe/config/impl/parseable.rb +151 -0
- data/lib/typesafe/config/impl/parser.rb +882 -0
- data/lib/typesafe/config/impl/path.rb +59 -0
- data/lib/typesafe/config/impl/path_builder.rb +36 -0
- data/lib/typesafe/config/impl/resolve_status.rb +18 -0
- data/lib/typesafe/config/impl/simple_config.rb +11 -0
- data/lib/typesafe/config/impl/simple_config_list.rb +70 -0
- data/lib/typesafe/config/impl/simple_config_object.rb +178 -0
- data/lib/typesafe/config/impl/simple_config_origin.rb +174 -0
- data/lib/typesafe/config/impl/simple_include_context.rb +7 -0
- data/lib/typesafe/config/impl/simple_includer.rb +19 -0
- data/lib/typesafe/config/impl/token.rb +32 -0
- data/lib/typesafe/config/impl/token_type.rb +42 -0
- data/lib/typesafe/config/impl/tokenizer.rb +370 -0
- data/lib/typesafe/config/impl/tokens.rb +157 -0
- data/lib/typesafe/config/impl/unmergeable.rb +4 -0
- data/lib/typesafe/config/impl.rb +5 -0
- data/lib/typesafe/config.rb +4 -0
- data/lib/typesafe.rb +2 -0
- metadata +85 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class Typesafe::Config::Impl::Path
|
5
|
+
# this doesn't have a very precise meaning, just to reduce
|
6
|
+
# noise from quotes in the rendered path for average cases
|
7
|
+
def self.has_funky_chars?(s)
|
8
|
+
length = s.length
|
9
|
+
if length == 0
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
|
13
|
+
# if the path starts with something that could be a number,
|
14
|
+
# we need to quote it because the number could be invalid,
|
15
|
+
# for example it could be a hyphen with no digit afterward
|
16
|
+
# or the exponent "e" notation could be mangled.
|
17
|
+
first = s[0]
|
18
|
+
unless first =~ /[[:alpha:]]/
|
19
|
+
return true
|
20
|
+
end
|
21
|
+
|
22
|
+
s.chars.each do |c|
|
23
|
+
unless (c =~ /[[:alnum:]]/) || (c == '-') || (c == '_')
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(first, remainder)
|
32
|
+
@first = first
|
33
|
+
@remainder = remainder
|
34
|
+
end
|
35
|
+
attr_reader :first, :remainder
|
36
|
+
|
37
|
+
#
|
38
|
+
# toString() is a debugging-oriented version while this is an
|
39
|
+
# error-message-oriented human-readable one.
|
40
|
+
#
|
41
|
+
def render
|
42
|
+
sb = StringIO.new
|
43
|
+
append_to_string_builder(sb)
|
44
|
+
sb.string
|
45
|
+
end
|
46
|
+
|
47
|
+
def append_to_string_builder(sb)
|
48
|
+
if self.class.has_funky_chars?(@first) || @first.empty?
|
49
|
+
sb << ConfigImplUtil.render_json_string(@first)
|
50
|
+
else
|
51
|
+
sb << @first
|
52
|
+
end
|
53
|
+
|
54
|
+
unless @remainder.nil?
|
55
|
+
sb << "."
|
56
|
+
@remainder.append_to_string_builder(sb)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'typesafe/config/impl/path'
|
3
|
+
|
4
|
+
class Typesafe::Config::Impl::PathBuilder
|
5
|
+
Path = Typesafe::Config::Impl::Path
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@keys = []
|
9
|
+
@result = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_can_append
|
13
|
+
if @result
|
14
|
+
raise ConfigBugError, "Adding to PathBuilder after getting result"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def append_key(key)
|
19
|
+
check_can_append
|
20
|
+
@keys.push(key)
|
21
|
+
end
|
22
|
+
|
23
|
+
def result
|
24
|
+
# note: if keys is empty, we want to return null, which is a valid
|
25
|
+
# empty path
|
26
|
+
if @result.nil?
|
27
|
+
remainder = nil
|
28
|
+
while !@keys.empty?
|
29
|
+
key = @keys.pop
|
30
|
+
remainder = Path.new(key, remainder)
|
31
|
+
end
|
32
|
+
@result = remainder
|
33
|
+
end
|
34
|
+
@result
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
|
3
|
+
class Typesafe::Config::Impl::ResolveStatus
|
4
|
+
UNRESOLVED = 0
|
5
|
+
RESOLVED = 1
|
6
|
+
|
7
|
+
def self.from_values(values)
|
8
|
+
if values.any? { |v| v.resolve_status == UNRESOLVED }
|
9
|
+
UNRESOLVED
|
10
|
+
else
|
11
|
+
RESOLVED
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_boolean(resolved)
|
16
|
+
resolved ? RESOLVED : UNRESOLVED
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'typesafe/config/impl/resolve_status'
|
3
|
+
require 'typesafe/config/config_value_type'
|
4
|
+
|
5
|
+
class Typesafe::Config::Impl::SimpleConfigList < Typesafe::Config::Impl::AbstractConfigValue
|
6
|
+
ResolveStatus = Typesafe::Config::Impl::ResolveStatus
|
7
|
+
|
8
|
+
def initialize(origin, value, status = ResolveStatus.from_values(value))
|
9
|
+
super(origin)
|
10
|
+
@value = value
|
11
|
+
@resolved = (status == ResolveStatus::RESOLVED)
|
12
|
+
|
13
|
+
# kind of an expensive debug check (makes this constructor pointless)
|
14
|
+
if status != ResolveStatus.from_values(value)
|
15
|
+
raise ConfigBugError, "SimpleConfigList created with wrong resolve status: #{self}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def value_type
|
20
|
+
Typesafe::Config::ConfigValueType::LIST
|
21
|
+
end
|
22
|
+
|
23
|
+
def unwrapped
|
24
|
+
@value.map { |v| v.unwrapped }
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_value_to_sb(sb, indent_size, at_root, options)
|
28
|
+
if @value.empty?
|
29
|
+
sb << "[]"
|
30
|
+
else
|
31
|
+
sb << "["
|
32
|
+
if options.formatted?
|
33
|
+
sb << "\n"
|
34
|
+
end
|
35
|
+
@value.each do |v|
|
36
|
+
if options.origin_comments?
|
37
|
+
indent(sb, indent_size + 1, options)
|
38
|
+
sb << "# "
|
39
|
+
sb << v.origin.description
|
40
|
+
sb << "\n"
|
41
|
+
end
|
42
|
+
if options.comments?
|
43
|
+
v.origin.comments.each do |comment|
|
44
|
+
sb << "# "
|
45
|
+
sb << comment
|
46
|
+
sb << "\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
indent(sb, indent_size + 1, options)
|
50
|
+
|
51
|
+
v.render_value_to_sb(sb, indent_size + 1, at_root, options)
|
52
|
+
sb << ","
|
53
|
+
if options.formatted?
|
54
|
+
sb << "\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# couldn't figure out a better way to chop characters off of the end of
|
59
|
+
# the StringIO. This relies on making sure that, prior to returning the
|
60
|
+
# final string, we take a substring that ends at sb.pos.
|
61
|
+
sb.pos = sb.pos - 1 # chop or newline
|
62
|
+
if options.formatted?
|
63
|
+
sb.pos = sb.pos - 1 # also chop comma
|
64
|
+
sb << "\n"
|
65
|
+
indent(sb, indent_size, options)
|
66
|
+
end
|
67
|
+
sb << "]"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'typesafe/config/impl/simple_config_origin'
|
3
|
+
require 'typesafe/config/impl/abstract_config_object'
|
4
|
+
require 'typesafe/config/impl/resolve_status'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
class Typesafe::Config::Impl::SimpleConfigObject < Typesafe::Config::Impl::AbstractConfigObject
|
8
|
+
def self.empty_missing(base_origin)
|
9
|
+
self.new(
|
10
|
+
Typesafe::Config::Impl::SimpleConfigOrigin.new_simple("#{base_origin.description} (not found)"),
|
11
|
+
{})
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(origin, value,
|
15
|
+
status = Typesafe::Config::Impl::ResolveStatus.from_values(value.values),
|
16
|
+
ignores_fallbacks = false)
|
17
|
+
super(origin)
|
18
|
+
if value.nil?
|
19
|
+
raise ConfigBugError, "creating config object with null map"
|
20
|
+
end
|
21
|
+
@value = value
|
22
|
+
@resolved = (status == Typesafe::Config::Impl::ResolveStatus::RESOLVED)
|
23
|
+
@ignores_fallbacks = ignores_fallbacks
|
24
|
+
|
25
|
+
# Kind of an expensive debug check. Comment out?
|
26
|
+
if status != Typesafe::Config::Impl::ResolveStatus.from_values(value.values)
|
27
|
+
raise ConfigBugError, "Wrong resolved status on #{self}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :value
|
32
|
+
|
33
|
+
def new_copy_with_status(new_status, new_origin, new_ignores_fallbacks = nil)
|
34
|
+
Typesafe::Config::Impl::SimpleConfigObject.new(new_origin,
|
35
|
+
@value, new_status, new_ignores_fallbacks)
|
36
|
+
end
|
37
|
+
|
38
|
+
def ignores_fallbacks?
|
39
|
+
@ignores_fallbacks
|
40
|
+
end
|
41
|
+
|
42
|
+
def unwrapped
|
43
|
+
@value.merge(@value) { |k,v| v.unwrapped }
|
44
|
+
end
|
45
|
+
|
46
|
+
def merged_with_object(abstract_fallback)
|
47
|
+
require_not_ignoring_fallbacks
|
48
|
+
|
49
|
+
unless abstract_fallback.is_a?(Typesafe::Config::Impl::SimpleConfigObject)
|
50
|
+
raise ConfigBugError, "should not be reached (merging non-SimpleConfigObject)"
|
51
|
+
end
|
52
|
+
|
53
|
+
fallback = abstract_fallback
|
54
|
+
changed = false
|
55
|
+
all_resolved = true
|
56
|
+
merged = {}
|
57
|
+
all_keys = key_set.union(fallback.key_set)
|
58
|
+
all_keys.each do |key|
|
59
|
+
first = @value[key]
|
60
|
+
second = fallback.value[key]
|
61
|
+
kept =
|
62
|
+
if first.nil?
|
63
|
+
second
|
64
|
+
elsif second.nil?
|
65
|
+
first
|
66
|
+
else
|
67
|
+
first.with_fallback(second)
|
68
|
+
end
|
69
|
+
merged[key] = kept
|
70
|
+
|
71
|
+
if first != kept
|
72
|
+
changed = true
|
73
|
+
end
|
74
|
+
|
75
|
+
if kept.resolve_status == Typesafe::Config::Impl::ResolveStatus::UNRESOLVED
|
76
|
+
all_resolved = false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
new_resolve_status = Typesafe::Config::Impl::ResolveStatus.from_boolean(all_resolved)
|
81
|
+
new_ignores_fallbacks = fallback.ignores_fallbacks?
|
82
|
+
|
83
|
+
if changed
|
84
|
+
Typesafe::Config::Impl::SimpleConfigObject.new(merge_origins([self, fallback]),
|
85
|
+
merged, new_resolve_status,
|
86
|
+
new_ignores_fallbacks)
|
87
|
+
elsif (new_resolve_status != resolve_status) || (new_ignores_fallbacks != ignores_fallbacks?)
|
88
|
+
newCopy(new_resolve_status, origin, new_ignores_fallbacks)
|
89
|
+
else
|
90
|
+
self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def render_value_to_sb(sb, indent_size, at_root, options)
|
95
|
+
if empty?
|
96
|
+
sb << "{}"
|
97
|
+
else
|
98
|
+
outer_braces = options.json? || !at_root
|
99
|
+
|
100
|
+
inner_indent =
|
101
|
+
if outer_braces
|
102
|
+
sb << "{"
|
103
|
+
if options.formatted?
|
104
|
+
sb << "\n"
|
105
|
+
end
|
106
|
+
indent_size + 1
|
107
|
+
else
|
108
|
+
indent_size
|
109
|
+
end
|
110
|
+
|
111
|
+
separator_count = 0
|
112
|
+
key_set.each do |k|
|
113
|
+
v = @value[k]
|
114
|
+
|
115
|
+
if options.origin_comments?
|
116
|
+
indent(sb, inner_indent, options)
|
117
|
+
sb << "# "
|
118
|
+
sb << v.origin.description
|
119
|
+
sb << "\n"
|
120
|
+
end
|
121
|
+
if options.comments?
|
122
|
+
v.origin.comments.each do |comment|
|
123
|
+
indent(sb, inner_indent, options)
|
124
|
+
sb << "#"
|
125
|
+
if !comment.start_with?(" ")
|
126
|
+
sb << " "
|
127
|
+
end
|
128
|
+
sb << comment
|
129
|
+
sb << "\n"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
indent(sb, inner_indent, options)
|
133
|
+
v.render_to_sb(sb, inner_indent, false, k.to_s, options)
|
134
|
+
|
135
|
+
if options.formatted?
|
136
|
+
if options.json?
|
137
|
+
sb << ","
|
138
|
+
separator_count = 2
|
139
|
+
else
|
140
|
+
separator_count = 1
|
141
|
+
end
|
142
|
+
sb << "\n"
|
143
|
+
else
|
144
|
+
sb << ","
|
145
|
+
separator_count = 1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
# chop last commas/newlines
|
149
|
+
# couldn't figure out a better way to chop characters off of the end of
|
150
|
+
# the StringIO. This relies on making sure that, prior to returning the
|
151
|
+
# final string, we take a substring that ends at sb.pos.
|
152
|
+
sb.pos = sb.pos - separator_count
|
153
|
+
|
154
|
+
if outer_braces
|
155
|
+
if options.formatted?
|
156
|
+
sb << "\n" # put a newline back
|
157
|
+
if outer_braces
|
158
|
+
indent(sb, indent_size, options)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
sb << "}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
if at_root && options.formatted?
|
165
|
+
sb << "\n"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
def key_set
|
171
|
+
Set.new(@value.keys)
|
172
|
+
end
|
173
|
+
|
174
|
+
def empty?
|
175
|
+
@value.empty?
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'typesafe/config/impl'
|
3
|
+
require 'typesafe/config/impl/origin_type'
|
4
|
+
|
5
|
+
class Typesafe::Config::Impl::SimpleConfigOrigin
|
6
|
+
|
7
|
+
MERGE_OF_PREFIX = "merge of "
|
8
|
+
|
9
|
+
def self.new_file(file_path)
|
10
|
+
url = URI.join('file:///', file_path)
|
11
|
+
self.new(file_path, -1, -1,
|
12
|
+
Typesafe::Config::Impl::OriginType::FILE,
|
13
|
+
url, nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.new_simple(description)
|
17
|
+
self.new(description, -1, -1,
|
18
|
+
Typesafe::Config::Impl::OriginType::GENERIC,
|
19
|
+
nil, nil)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.remove_merge_of_prefix(desc)
|
23
|
+
if desc.start_with?(MERGE_OF_PREFIX)
|
24
|
+
desc = desc[MERGE_OF_PREFIX.length, desc.length - 1]
|
25
|
+
end
|
26
|
+
desc
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.merge_two(a, b)
|
30
|
+
merged_desc = nil
|
31
|
+
merged_start_line = nil
|
32
|
+
merged_end_line = nil
|
33
|
+
merged_comments = nil
|
34
|
+
|
35
|
+
merged_type =
|
36
|
+
if a.origin_type == b.origin_type
|
37
|
+
a.origin_type
|
38
|
+
else
|
39
|
+
Typesafe::Config::Impl::OriginType.GENERIC
|
40
|
+
end
|
41
|
+
|
42
|
+
# first use the "description" field which has no line numbers
|
43
|
+
# cluttering it.
|
44
|
+
a_desc = remove_merge_of_prefix(a.description)
|
45
|
+
b_desc = remove_merge_of_prefix(b.description)
|
46
|
+
|
47
|
+
if a_desc == b_desc
|
48
|
+
merged_desc = a_desc
|
49
|
+
if a.line_number < 0
|
50
|
+
merged_start_line = b.line_number
|
51
|
+
elsif b.line_number < 0
|
52
|
+
merged_start_line = a.line_number
|
53
|
+
else
|
54
|
+
merged_start_line = [a.line_number, b.line_number].min
|
55
|
+
end
|
56
|
+
|
57
|
+
merged_end_line = [a.end_line_number, b.end_line_number].max
|
58
|
+
else
|
59
|
+
# this whole merge song-and-dance was intended to avoid this case
|
60
|
+
# whenever possible, but we've lost. Now we have to lose some
|
61
|
+
# structured information and cram into a string.
|
62
|
+
#
|
63
|
+
# description() method includes line numbers, so use it instead
|
64
|
+
# of description field.
|
65
|
+
a_full = remove_merge_of_prefix(a.description)
|
66
|
+
b_full = remove_merge_of_prefix(b.description)
|
67
|
+
|
68
|
+
merged_desc = "#{MERGE_OF_PREFIX}#{a_full},#{b_full}"
|
69
|
+
merged_start_line = -1
|
70
|
+
merged_end_line = -1
|
71
|
+
end
|
72
|
+
|
73
|
+
merged_url =
|
74
|
+
if Typesafe::Config::Impl::ConfigImplUtil.equals_handling_nil?(a.url_or_nil, b.url_or_nil)
|
75
|
+
a.url_or_nil
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
if Typesafe::Config::Impl::ConfigImplUtil.equals_handling_nil?(a.comments_or_nil, b.comments_or_nil)
|
81
|
+
merged_comments = a.comments_or_nil
|
82
|
+
else
|
83
|
+
merged_comments = []
|
84
|
+
if a.comments_or_nil
|
85
|
+
merged_comments.concat(a.comments_or_nil)
|
86
|
+
end
|
87
|
+
if b.comments_or_nil
|
88
|
+
merged_comments.concat(b.comments_or_nil)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Typesafe::Config::Impl::SimpleConfigOrigin.new(
|
93
|
+
merged_desc, merged_start_line, merged_end_line,
|
94
|
+
merged_type, merged_url, merged_comments)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.merge_origins(stack)
|
98
|
+
if stack.empty?
|
99
|
+
raise ConfigBugError, "can't merge empty list of origins"
|
100
|
+
elsif stack.length == 1
|
101
|
+
stack[0]
|
102
|
+
elsif stack.length == 2
|
103
|
+
merge_two(stack[0], stack[1])
|
104
|
+
else
|
105
|
+
remaining = stack.clone
|
106
|
+
while remaining.length > 2
|
107
|
+
merged = merge_three(remaining[0], remaining[1], remaining[2])
|
108
|
+
remaining.pop
|
109
|
+
remaining.pop
|
110
|
+
remaining.pop
|
111
|
+
end
|
112
|
+
|
113
|
+
# should be down to either 1 or 2
|
114
|
+
merge_origins(remaining)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def initialize(description, line_number, end_line_number,
|
120
|
+
origin_type, url, comments)
|
121
|
+
if !description
|
122
|
+
raise ArgumentError, "description may not be nil"
|
123
|
+
end
|
124
|
+
|
125
|
+
@description = description
|
126
|
+
@line_number = line_number
|
127
|
+
@end_line_number = end_line_number
|
128
|
+
@origin_type = origin_type
|
129
|
+
@url_or_nil = url
|
130
|
+
@comments_or_nil = comments
|
131
|
+
end
|
132
|
+
|
133
|
+
attr_reader :description, :line_number, :end_line_number, :origin_type,
|
134
|
+
:url_or_nil, :comments_or_nil
|
135
|
+
|
136
|
+
def set_line_number(line_number)
|
137
|
+
if (line_number == @line_number) and
|
138
|
+
(line_number == @end_line_number)
|
139
|
+
self
|
140
|
+
else
|
141
|
+
Typesafe::Config::Impl::SimpleConfigOrigin.new(
|
142
|
+
@description, line_number, line_number,
|
143
|
+
@origin_type, @url_or_nil, @comments_or_nil)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def set_comments(comments)
|
148
|
+
if Typesafe::Config::Impl::ConfigImplUtil.equals_handling_nil?(comments, @comments_or_nil)
|
149
|
+
self
|
150
|
+
else
|
151
|
+
Typesafe::Config::Impl::SimpleConfigOrigin.new(
|
152
|
+
@description, @line_number, @end_line_number,
|
153
|
+
@origin_type, @url_or_nil, comments)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def prepend_comments(comments)
|
158
|
+
if Typesafe::Config::Impl::ConfigImplUtil.equals_handling_nil?(comments, @comments_or_nil)
|
159
|
+
self
|
160
|
+
elsif @comments_or_nil.nil?
|
161
|
+
set_comments(comments)
|
162
|
+
else
|
163
|
+
merged = []
|
164
|
+
merged.concat(comments)
|
165
|
+
merged.concat(@comments_or_nil)
|
166
|
+
set_comments(merged)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def comments
|
171
|
+
@comments_or_nil || []
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'typesafe/config/impl/full_includer'
|
3
|
+
|
4
|
+
class Typesafe::Config::Impl::SimpleIncluder < Typesafe::Config::Impl::FullIncluder
|
5
|
+
class Proxy < Typesafe::Config::Impl::FullIncluder
|
6
|
+
def initialize(delegate)
|
7
|
+
@delegate = delegate
|
8
|
+
end
|
9
|
+
## TODO: port remaining implementation when needed
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.make_full(includer)
|
13
|
+
if includer.is_a?(Typesafe::Config::Impl::FullIncluder)
|
14
|
+
includer
|
15
|
+
else
|
16
|
+
Proxy.new(includer)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
require 'typesafe/config/impl/token_type'
|
3
|
+
|
4
|
+
class Typesafe::Config::Impl::Token
|
5
|
+
def self.new_without_origin(token_type, debug_string)
|
6
|
+
Typesafe::Config::Impl::Token.new(token_type, nil, debug_string)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(token_type, origin, debug_string = nil)
|
10
|
+
@token_type = token_type
|
11
|
+
@origin = origin
|
12
|
+
@debug_string = debug_string
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :origin
|
16
|
+
|
17
|
+
def line_number
|
18
|
+
if @origin
|
19
|
+
@origin.line_number
|
20
|
+
else
|
21
|
+
-1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
if !@debug_string.nil?
|
27
|
+
@debug_string
|
28
|
+
else
|
29
|
+
Typesafe::Config::Impl::TokenType.name(@token_type)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'typesafe/config/impl'
|
2
|
+
|
3
|
+
class Typesafe::Config::Impl::TokenType
|
4
|
+
START = 0
|
5
|
+
EOF = 1
|
6
|
+
COMMA = 2
|
7
|
+
EQUALS = 3
|
8
|
+
COLON = 4
|
9
|
+
OPEN_CURLY = 5
|
10
|
+
CLOSE_CURLY = 6
|
11
|
+
OPEN_SQUARE = 7
|
12
|
+
CLOSE_SQUARE = 8
|
13
|
+
VALUE = 9
|
14
|
+
NEWLINE = 10
|
15
|
+
UNQUOTED_TEXT = 11
|
16
|
+
SUBSTITUTION = 12
|
17
|
+
PROBLEM = 13
|
18
|
+
COMMENT = 14
|
19
|
+
PLUS_EQUALS = 15
|
20
|
+
|
21
|
+
def self.name(token_type)
|
22
|
+
case token_type
|
23
|
+
when START then "START"
|
24
|
+
when EOF then "EOF"
|
25
|
+
when COMMA then "COMMA"
|
26
|
+
when EQUALS then "EQUALS"
|
27
|
+
when COLON then "COLON"
|
28
|
+
when OPEN_CURLY then "OPEN_CURLY"
|
29
|
+
when CLOSE_CURLY then "CLOSE_CURLY"
|
30
|
+
when OPEN_SQUARE then "OPEN_SQUARE"
|
31
|
+
when CLOSE_SQUARE then "CLOSE_SQUARE"
|
32
|
+
when VALUE then "VALUE"
|
33
|
+
when NEWLINE then "NEWLINE"
|
34
|
+
when UNQUOTED_TEXT then "UNQUOTED_TEXT"
|
35
|
+
when SUBSTITUTION then "SUBSTITUTION"
|
36
|
+
when PROBLEM then "PROBLEM"
|
37
|
+
when COMMENT then "COMMENT"
|
38
|
+
when PLUS_EQUALS then "PLUS_EQUALS"
|
39
|
+
else raise ConfigBugError, "Unrecognized token type #{token_type}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|