typesafe_config 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.md +15 -0
  2. metadata +3 -40
  3. data/lib/typesafe/config/config_error.rb +0 -12
  4. data/lib/typesafe/config/config_factory.rb +0 -9
  5. data/lib/typesafe/config/config_object.rb +0 -4
  6. data/lib/typesafe/config/config_parse_options.rb +0 -53
  7. data/lib/typesafe/config/config_render_options.rb +0 -46
  8. data/lib/typesafe/config/config_syntax.rb +0 -7
  9. data/lib/typesafe/config/config_value_type.rb +0 -26
  10. data/lib/typesafe/config/impl/abstract_config_object.rb +0 -64
  11. data/lib/typesafe/config/impl/abstract_config_value.rb +0 -130
  12. data/lib/typesafe/config/impl/config_concatenation.rb +0 -136
  13. data/lib/typesafe/config/impl/config_float.rb +0 -9
  14. data/lib/typesafe/config/impl/config_impl.rb +0 -10
  15. data/lib/typesafe/config/impl/config_impl_util.rb +0 -78
  16. data/lib/typesafe/config/impl/config_int.rb +0 -31
  17. data/lib/typesafe/config/impl/config_number.rb +0 -27
  18. data/lib/typesafe/config/impl/config_string.rb +0 -37
  19. data/lib/typesafe/config/impl/full_includer.rb +0 -4
  20. data/lib/typesafe/config/impl/origin_type.rb +0 -9
  21. data/lib/typesafe/config/impl/parseable.rb +0 -151
  22. data/lib/typesafe/config/impl/parser.rb +0 -882
  23. data/lib/typesafe/config/impl/path.rb +0 -59
  24. data/lib/typesafe/config/impl/path_builder.rb +0 -36
  25. data/lib/typesafe/config/impl/resolve_status.rb +0 -18
  26. data/lib/typesafe/config/impl/simple_config.rb +0 -11
  27. data/lib/typesafe/config/impl/simple_config_list.rb +0 -70
  28. data/lib/typesafe/config/impl/simple_config_object.rb +0 -178
  29. data/lib/typesafe/config/impl/simple_config_origin.rb +0 -174
  30. data/lib/typesafe/config/impl/simple_include_context.rb +0 -7
  31. data/lib/typesafe/config/impl/simple_includer.rb +0 -19
  32. data/lib/typesafe/config/impl/token.rb +0 -32
  33. data/lib/typesafe/config/impl/token_type.rb +0 -42
  34. data/lib/typesafe/config/impl/tokenizer.rb +0 -370
  35. data/lib/typesafe/config/impl/tokens.rb +0 -157
  36. data/lib/typesafe/config/impl/unmergeable.rb +0 -4
  37. data/lib/typesafe/config/impl.rb +0 -5
  38. data/lib/typesafe/config.rb +0 -4
  39. data/lib/typesafe.rb +0 -2
@@ -1,370 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/config_impl_util'
3
- require 'typesafe/config/impl/tokens'
4
- require 'stringio'
5
-
6
- class Typesafe::Config::Impl::Tokenizer
7
- Tokens = Typesafe::Config::Impl::Tokens
8
-
9
- class TokenizerProblemError < StandardError
10
- end
11
-
12
- class TokenIterator
13
- class WhitespaceSaver
14
- def initialize
15
- @whitespace = StringIO.new
16
- @last_token_was_simple_value = false
17
- end
18
-
19
- def add(c)
20
- if @last_token_was_simple_value
21
- @whitespace << c
22
- end
23
- end
24
-
25
- def check(t, base_origin, line_number)
26
- if Typesafe::Config::Impl::Tokenizer::TokenIterator.simple_value?(t)
27
- next_is_a_simple_value(base_origin, line_number)
28
- else
29
- next_is_not_a_simple_value
30
- nil
31
- end
32
- end
33
-
34
- private
35
- # called if the next token is not a simple value;
36
- # discards any whitespace we were saving between
37
- # simple values.
38
- def next_is_not_a_simple_value
39
- @last_token_was_simple_value = false
40
- @whitespace.reopen("")
41
- end
42
-
43
- # called if the next token IS a simple value,
44
- # so creates a whitespace token if the previous
45
- # token also was.
46
- def next_is_a_simple_value(base_origin, line_number)
47
- if @last_token_was_simple_value
48
- # need to save whitespace between the two so
49
- # the parser has the option to concatenate it.
50
- if @whitespace.length > 0
51
- Tokens.new_unquoted_text(
52
- line_origin(base_origin, line_number),
53
- @whitespace.string = ""
54
- )
55
- end
56
- end
57
- end
58
-
59
- end
60
-
61
- # chars JSON allows a number to start with
62
- FIRST_NUMBER_CHARS = "0123456789-"
63
- # chars JSON allows to be part of a number
64
- NUMBER_CHARS = "0123456789eE+-."
65
- # chars that stop an unquoted string
66
- NOT_IN_UNQUOTED_TEXT = "$\"{}[]:=,+#`^?!@*&\\"
67
-
68
- def self.simple_value?(t)
69
- Tokens.substitution?(t) ||
70
- Tokens.unquoted_text?(t) ||
71
- Tokens.value?(t)
72
- end
73
-
74
- def self.whitespace?(c)
75
- Typesafe::Config::Impl::ConfigImplUtil.whitespace?(c)
76
- end
77
-
78
- def self.whitespace_not_newline?(c)
79
- (c != "\n") and (Typesafe::Config::Impl::ConfigImplUtil.whitespace?(c))
80
- end
81
-
82
- def initialize(origin, input, allow_comments)
83
- @origin = origin
84
- @input = input
85
- @allow_comments = allow_comments
86
- @buffer = []
87
- @line_number = 1
88
- @line_origin = @origin.set_line_number(@line_number)
89
- @tokens = []
90
- @tokens << Tokens::START
91
- @whitespace_saver = WhitespaceSaver.new
92
- end
93
-
94
- def start_of_comment?(c)
95
- if c == -1
96
- false
97
- else
98
- if @allow_comments
99
- if c == '#'
100
- true
101
- elsif c == '/'
102
- maybe_second_slash = next_char_raw
103
- # we want to predictably NOT consume any chars
104
- put_back(maybe_second_slash)
105
- if maybe_second_slash == '/'
106
- true
107
- else
108
- false
109
- end
110
- end
111
- else
112
- false
113
- end
114
- end
115
- end
116
-
117
- def put_back(c)
118
- if @buffer.length > 2
119
- raise ConfigBugError, "bug: putBack() three times, undesirable look-ahead"
120
- end
121
- @buffer.push(c)
122
- end
123
-
124
- def next_char_raw
125
- if @buffer.empty?
126
- begin
127
- @input.readchar
128
- rescue EOFError
129
- -1
130
- end
131
- else
132
- @buffer.pop
133
- end
134
- end
135
-
136
- def next_char_after_whitespace(saver)
137
- while true
138
- c = next_char_raw
139
- if c == -1
140
- return -1
141
- else
142
- if self.class.whitespace_not_newline?(c)
143
- saver.add(c)
144
- else
145
- return c
146
- end
147
- end
148
- end
149
- end
150
-
151
- # The rules here are intended to maximize convenience while
152
- # avoiding confusion with real valid JSON. Basically anything
153
- # that parses as JSON is treated the JSON way and otherwise
154
- # we assume it's a string and let the parser sort it out.
155
- def pull_unquoted_text
156
- origin = @line_origin
157
- io = StringIO.new
158
- c = next_char_raw
159
- while true
160
- if (c == -1) or
161
- (NOT_IN_UNQUOTED_TEXT.index(c)) or
162
- (self.class.whitespace?(c)) or
163
- (start_of_comment?(c))
164
- break
165
- else
166
- io << c
167
- end
168
-
169
- # we parse true/false/null tokens as such no matter
170
- # what is after them, as long as they are at the
171
- # start of the unquoted token.
172
- if io.length == 4
173
- if io.string == "true"
174
- return Tokens.new_boolean(origin, true)
175
- elsif io.string == "null"
176
- return Tokens.new_null(origin)
177
- end
178
- elsif io.length == 5
179
- if io.string == "false"
180
- return Tokens.new_boolean(origin, false)
181
- end
182
- end
183
-
184
- c = next_char_raw
185
- end
186
-
187
- # put back the char that ended the unquoted text
188
- put_back(c)
189
-
190
- Tokens.new_unquoted_text(origin, io.string)
191
- end
192
-
193
-
194
- def pull_comment(first_char)
195
- if first_char == '/'
196
- discard = next_char_raw
197
- if discard != '/'
198
- raise ConfigBugError, "called pullComment but // not seen"
199
- end
200
- end
201
-
202
- io = StringIO.new
203
- while true
204
- c = next_char_raw
205
- if (c == -1) || (c == "\n")
206
- put_back(c)
207
- return Tokens.new_comment(@line_origin, io.string)
208
- else
209
- io << c
210
- end
211
- end
212
- end
213
-
214
- def pull_number(first_char)
215
- sb = StringIO.new
216
- sb << first_char
217
- contained_decimal_or_e = false
218
- c = next_char_raw
219
- while (c != -1) && (NUMBER_CHARS.index(c))
220
- if (c == '.') ||
221
- (c == 'e') ||
222
- (c == 'E')
223
- contained_decimal_or_e = true
224
- end
225
- sb << c
226
- c = next_char_raw
227
- end
228
- # the last character we looked at wasn't part of the number, put it
229
- # back
230
- put_back(c)
231
- s = sb.string
232
- begin
233
- if contained_decimal_or_e
234
- # force floating point representation
235
- Tokens.new_double(@line_origin, s.to_f, s)
236
- else
237
- Tokens.new_long(@line_origin, s.to_i, s)
238
- end
239
- rescue ArgumentError => e
240
- if e.message =~ /^invalid value for (Float|Integer)\(\)/
241
- # not a number after all, see if it's an unquoted string.
242
- s.each do |u|
243
- if NOT_IN_UNQUOTED_TEXT.index
244
- raise problem(u, "Reserved character '#{u}'" +
245
- "is not allowed outside quotes", true)
246
- end
247
- end
248
- # no evil chars so we just decide this was a string and
249
- # not a number.
250
- Tokens.new_unquoted_text(@line_origin, s)
251
- else
252
- raise e
253
- end
254
- end
255
- end
256
-
257
- def pull_quoted_string
258
- # the open quote has already been consumed
259
- sb = StringIO.new
260
- c = ""
261
- while c != '"'
262
- c = next_char_raw
263
- if c == -1
264
- raise problem("End of input but string quote was still open")
265
- end
266
-
267
- if c == "\\"
268
- pull_escape_sequence(sb)
269
- elsif c == '"'
270
- # done!
271
- elsif c =~ /[[:cntrl:]]/
272
- raise problem(c, "JSON does not allow unescaped #{c}" +
273
- " in quoted strings, use a backslash escape")
274
- else
275
- sb << c
276
- end
277
- end
278
-
279
- # maybe switch to triple-quoted string, sort of hacky...
280
- if sb.length == 0
281
- third = next_char_raw
282
- if third == '"'
283
- append_triple_quoted_string(sb)
284
- else
285
- put_back(third)
286
- end
287
- end
288
-
289
- Tokens.new_string(@line_origin, sb.string)
290
- end
291
-
292
- def pull_next_token(saver)
293
- c = next_char_after_whitespace(saver)
294
- if c == -1
295
- Tokens::EOF
296
- elsif c == "\n"
297
- # newline tokens have the just-ended line number
298
- line = Tokens.new_line(@line_origin)
299
- @line_number += 1
300
- @line_origin = @origin.set_line_number(@line_number)
301
- line
302
- else
303
- t = nil
304
- if start_of_comment?(c)
305
- t = pull_comment(c)
306
- else
307
- t = case c
308
- when '"' then pull_quoted_string
309
- when '$' then pull_substitution
310
- when ':' then Tokens::COLON
311
- when ',' then Tokens::COMMA
312
- when '=' then Tokens::EQUALS
313
- when '{' then Tokens::OPEN_CURLY
314
- when '}' then Tokens::CLOSE_CURLY
315
- when '[' then Tokens::OPEN_SQUARE
316
- when ']' then Tokens::CLOSE_SQUARE
317
- when '+' then pull_plus_equals
318
- else nil
319
- end
320
-
321
- if t.nil?
322
- if FIRST_NUMBER_CHARS.index(c)
323
- t = pull_number(c)
324
- elsif NOT_IN_UNQUOTED_TEXT.index(c)
325
- raise problem(c, "Reserved character '#{c}' is not allowed outside quotes", true)
326
- else
327
- put_back(c)
328
- t = pull_unquoted_text
329
- end
330
- end
331
- end
332
-
333
- if t.nil?
334
- raise ConfigBugError, "bug: failed to generate next token"
335
- end
336
-
337
- t
338
- end
339
- end
340
-
341
- def queue_next_token
342
- t = pull_next_token(@whitespace_saver)
343
- whitespace = @whitespace_saver.check(t, @origin, @line_number)
344
- if whitespace
345
- @tokens.push(whitespace)
346
- end
347
- @tokens.push(t)
348
- end
349
-
350
- def next
351
- t = @tokens.shift
352
- if (@tokens.empty?) and (t != Tokens::EOF)
353
- begin
354
- queue_next_token
355
- rescue TokenizerProblemError => e
356
- @tokens.push(e.problem)
357
- end
358
- if @tokens.empty?
359
- raise ConfigBugError, "bug: tokens queue should not be empty here"
360
- end
361
- end
362
- t
363
- end
364
- end
365
-
366
-
367
- def self.tokenize(origin, input, syntax)
368
- TokenIterator.new(origin, input, syntax != Typesafe::Config::ConfigSyntax::JSON)
369
- end
370
- end
@@ -1,157 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/token'
3
- require 'typesafe/config/impl/token_type'
4
- require 'typesafe/config/impl/config_number'
5
- require 'typesafe/config/impl/config_string'
6
-
7
- # FIXME the way the subclasses of Token are private with static isFoo and accessors is kind of ridiculous.
8
- class Typesafe::Config::Impl::Tokens
9
- Token = Typesafe::Config::Impl::Token
10
- TokenType = Typesafe::Config::Impl::TokenType
11
- ConfigNumber = Typesafe::Config::Impl::ConfigNumber
12
- ConfigString = Typesafe::Config::Impl::ConfigString
13
-
14
- START = Token.new_without_origin(TokenType::START, "start of file")
15
- EOF = Token.new_without_origin(TokenType::EOF, "end of file")
16
- COMMA = Token.new_without_origin(TokenType::COMMA, "','")
17
- EQUALS = Token.new_without_origin(TokenType::EQUALS, "'='")
18
- COLON = Token.new_without_origin(TokenType::COLON, "':'")
19
- OPEN_CURLY = Token.new_without_origin(TokenType::OPEN_CURLY, "'{'")
20
- CLOSE_CURLY = Token.new_without_origin(TokenType::CLOSE_CURLY, "'}'")
21
- OPEN_SQUARE = Token.new_without_origin(TokenType::OPEN_SQUARE, "'['")
22
- CLOSE_SQUARE = Token.new_without_origin(TokenType::CLOSE_SQUARE, "']'")
23
- PLUS_EQUALS = Token.new_without_origin(TokenType::PLUS_EQUALS, "'+='")
24
-
25
- class Comment < Token
26
- def initialize(origin, text)
27
- super(TokenType::COMMENT, origin)
28
- @text = text
29
- end
30
- attr_reader :text
31
- end
32
-
33
- # This is not a Value, because it requires special processing
34
- class Substitution < Token
35
- def initialize(origin, optional, expression)
36
- super(TokenType::SUBSTITUTION, origin)
37
- @optional = optional
38
- @value = expression
39
- end
40
- end
41
-
42
- class UnquotedText < Token
43
- def initialize(origin, s)
44
- super(TokenType::UNQUOTED_TEXT, origin)
45
- @value = s
46
- end
47
- attr_reader :value
48
-
49
- def to_s
50
- "'#{value}'"
51
- end
52
- end
53
-
54
- class Value < Token
55
- def initialize(value)
56
- super(TokenType::VALUE, value.origin)
57
- @value = value
58
- end
59
- attr_reader :value
60
-
61
- def to_s
62
- "'#{value.unwrapped}' (#{Typesafe::Config::ConfigValueType.name(value.value_type)})"
63
- end
64
- end
65
-
66
- class Line < Token
67
- def initialize(origin)
68
- super(TokenType::NEWLINE, origin)
69
- end
70
- end
71
-
72
- class Problem < Token
73
- def initialize(origin, what, message, suggest_quotes, cause)
74
- super(TokenType::PROBLEM, origin)
75
- @what = what
76
- @message = message
77
- @suggest_quotes = suggest_quotes
78
- @cause = cause
79
- end
80
- end
81
-
82
- def self.new_line(origin)
83
- Line.new(origin)
84
- end
85
-
86
- def self.new_comment(origin, text)
87
- Comment.new(origin, text)
88
- end
89
-
90
- def self.new_unquoted_text(origin, s)
91
- UnquotedText.new(origin, s)
92
- end
93
-
94
- def self.new_value(value)
95
- Value.new(value)
96
- end
97
-
98
- def self.new_string(origin, value)
99
- new_value(ConfigString.new(origin, value))
100
- end
101
-
102
- def self.new_long(origin, value, original_text)
103
- new_value(ConfigNumber.new_number(origin, value, original_text))
104
- end
105
-
106
- def self.comment?(t)
107
- t.is_a?(Comment)
108
- end
109
-
110
- def self.comment_text(token)
111
- if comment?(token)
112
- token.text
113
- else
114
- raise ConfigBugError, "tried to get comment text from #{token}"
115
- end
116
- end
117
-
118
- def self.substitution?(t)
119
- t.is_a?(Substitution)
120
- end
121
-
122
- def self.unquoted_text?(token)
123
- token.is_a?(UnquotedText)
124
- end
125
-
126
- def self.unquoted_text(token)
127
- if unquoted_text?(token)
128
- token.value
129
- else
130
- raise ConfigBugError, "tried to get unquoted text from #{token}"
131
- end
132
- end
133
-
134
- def self.value?(token)
135
- token.is_a?(Value)
136
- end
137
-
138
- def self.value(token)
139
- if token.is_a?(Value)
140
- token.value
141
- else
142
- raise ConfigBugError, "tried to get value of non-value token #{token}"
143
- end
144
- end
145
-
146
- def self.value_with_type?(t, value_type)
147
- value?(t) && (value(t).value_type == value_type)
148
- end
149
-
150
- def self.newline?(t)
151
- t.is_a?(Line)
152
- end
153
-
154
- def self.problem?(t)
155
- t.is_a?(Problem)
156
- end
157
- end
@@ -1,4 +0,0 @@
1
- require 'typesafe/config/impl'
2
-
3
- module Typesafe::Config::Impl::Unmergeable
4
- end
@@ -1,5 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- module Typesafe::Config::Impl
4
-
5
- end
@@ -1,4 +0,0 @@
1
- require 'typesafe'
2
-
3
- module Typesafe::Config
4
- end
data/lib/typesafe.rb DELETED
@@ -1,2 +0,0 @@
1
- module Typesafe
2
- end