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