hocon 0.0.7 → 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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +4 -2
  3. data/lib/hocon.rb +2 -0
  4. data/lib/hocon/config.rb +1010 -0
  5. data/lib/hocon/config_error.rb +32 -2
  6. data/lib/hocon/config_factory.rb +46 -0
  7. data/lib/hocon/config_include_context.rb +49 -0
  8. data/lib/hocon/config_includer_file.rb +27 -0
  9. data/lib/hocon/config_list.rb +49 -0
  10. data/lib/hocon/config_mergeable.rb +74 -0
  11. data/lib/hocon/config_object.rb +144 -1
  12. data/lib/hocon/config_parse_options.rb +33 -9
  13. data/lib/hocon/config_parseable.rb +51 -0
  14. data/lib/hocon/config_render_options.rb +4 -2
  15. data/lib/hocon/config_resolve_options.rb +31 -0
  16. data/lib/hocon/config_syntax.rb +5 -2
  17. data/lib/hocon/config_util.rb +73 -0
  18. data/lib/hocon/config_value.rb +122 -0
  19. data/lib/hocon/config_value_factory.rb +66 -2
  20. data/lib/hocon/config_value_type.rb +5 -2
  21. data/lib/hocon/impl.rb +2 -0
  22. data/lib/hocon/impl/abstract_config_node.rb +29 -0
  23. data/lib/hocon/impl/abstract_config_node_value.rb +11 -0
  24. data/lib/hocon/impl/abstract_config_object.rb +148 -42
  25. data/lib/hocon/impl/abstract_config_value.rb +251 -11
  26. data/lib/hocon/impl/array_iterator.rb +19 -0
  27. data/lib/hocon/impl/config_boolean.rb +7 -1
  28. data/lib/hocon/impl/config_concatenation.rb +177 -28
  29. data/lib/hocon/impl/config_delayed_merge.rb +329 -0
  30. data/lib/hocon/impl/config_delayed_merge_object.rb +274 -0
  31. data/lib/hocon/impl/config_document_parser.rb +647 -0
  32. data/lib/hocon/impl/config_double.rb +44 -0
  33. data/lib/hocon/impl/config_impl.rb +143 -19
  34. data/lib/hocon/impl/config_impl_util.rb +18 -0
  35. data/lib/hocon/impl/config_include_kind.rb +10 -0
  36. data/lib/hocon/impl/config_int.rb +13 -1
  37. data/lib/hocon/impl/config_node_array.rb +11 -0
  38. data/lib/hocon/impl/config_node_comment.rb +19 -0
  39. data/lib/hocon/impl/config_node_complex_value.rb +54 -0
  40. data/lib/hocon/impl/config_node_concatenation.rb +11 -0
  41. data/lib/hocon/impl/config_node_field.rb +81 -0
  42. data/lib/hocon/impl/config_node_include.rb +33 -0
  43. data/lib/hocon/impl/config_node_object.rb +276 -0
  44. data/lib/hocon/impl/config_node_path.rb +48 -0
  45. data/lib/hocon/impl/config_node_root.rb +60 -0
  46. data/lib/hocon/impl/config_node_simple_value.rb +42 -0
  47. data/lib/hocon/impl/config_node_single_token.rb +17 -0
  48. data/lib/hocon/impl/config_null.rb +15 -7
  49. data/lib/hocon/impl/config_number.rb +43 -4
  50. data/lib/hocon/impl/config_parser.rb +403 -0
  51. data/lib/hocon/impl/config_reference.rb +142 -0
  52. data/lib/hocon/impl/config_string.rb +55 -7
  53. data/lib/hocon/impl/container.rb +29 -0
  54. data/lib/hocon/impl/default_transformer.rb +24 -15
  55. data/lib/hocon/impl/from_map_mode.rb +3 -1
  56. data/lib/hocon/impl/full_includer.rb +2 -0
  57. data/lib/hocon/impl/memo_key.rb +42 -0
  58. data/lib/hocon/impl/mergeable_value.rb +8 -0
  59. data/lib/hocon/impl/origin_type.rb +8 -2
  60. data/lib/hocon/impl/parseable.rb +455 -91
  61. data/lib/hocon/impl/path.rb +181 -59
  62. data/lib/hocon/impl/path_builder.rb +24 -3
  63. data/lib/hocon/impl/path_parser.rb +280 -0
  64. data/lib/hocon/impl/replaceable_merge_stack.rb +22 -0
  65. data/lib/hocon/impl/resolve_context.rb +254 -0
  66. data/lib/hocon/impl/resolve_memos.rb +21 -0
  67. data/lib/hocon/impl/resolve_result.rb +39 -0
  68. data/lib/hocon/impl/resolve_source.rb +354 -0
  69. data/lib/hocon/impl/resolve_status.rb +3 -1
  70. data/lib/hocon/impl/simple_config.rb +264 -10
  71. data/lib/hocon/impl/simple_config_document.rb +48 -0
  72. data/lib/hocon/impl/simple_config_list.rb +282 -8
  73. data/lib/hocon/impl/simple_config_object.rb +424 -88
  74. data/lib/hocon/impl/simple_config_origin.rb +263 -71
  75. data/lib/hocon/impl/simple_include_context.rb +31 -1
  76. data/lib/hocon/impl/simple_includer.rb +196 -1
  77. data/lib/hocon/impl/substitution_expression.rb +38 -0
  78. data/lib/hocon/impl/token.rb +17 -4
  79. data/lib/hocon/impl/token_type.rb +6 -2
  80. data/lib/hocon/impl/tokenizer.rb +339 -109
  81. data/lib/hocon/impl/tokens.rb +330 -79
  82. data/lib/hocon/impl/unmergeable.rb +14 -1
  83. data/lib/hocon/impl/unsupported_operation_error.rb +6 -0
  84. data/lib/hocon/impl/url.rb +37 -0
  85. data/lib/hocon/parser.rb +7 -0
  86. data/lib/hocon/parser/config_document.rb +92 -0
  87. data/lib/hocon/parser/config_document_factory.rb +36 -0
  88. data/lib/hocon/parser/config_node.rb +30 -0
  89. metadata +67 -43
  90. data/lib/hocon/impl/config_float.rb +0 -13
  91. data/lib/hocon/impl/parser.rb +0 -977
  92. data/lib/hocon/impl/properties_parser.rb +0 -83
@@ -1,44 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ require 'stringio'
1
4
  require 'hocon/impl'
2
5
  require 'hocon/impl/token'
3
6
  require 'hocon/impl/token_type'
4
7
  require 'hocon/impl/config_number'
5
8
  require 'hocon/impl/config_string'
9
+ require 'hocon/impl/config_null'
6
10
  require 'hocon/impl/config_boolean'
7
11
  require 'hocon/config_error'
12
+ require 'hocon/impl/resolve_status'
8
13
 
9
14
  # FIXME the way the subclasses of Token are private with static isFoo and accessors is kind of ridiculous.
10
15
  class Hocon::Impl::Tokens
11
16
  Token = Hocon::Impl::Token
12
17
  TokenType = Hocon::Impl::TokenType
13
18
  ConfigNumber = Hocon::Impl::ConfigNumber
19
+ ConfigInt = Hocon::Impl::ConfigInt
20
+ ConfigDouble = Hocon::Impl::ConfigDouble
14
21
  ConfigString = Hocon::Impl::ConfigString
22
+ ConfigNull = Hocon::Impl::ConfigNull
15
23
  ConfigBoolean = Hocon::Impl::ConfigBoolean
24
+ ResolveStatus = Hocon::Impl::ResolveStatus
16
25
 
17
- START = Token.new_without_origin(TokenType::START, "start of file")
18
- EOF = Token.new_without_origin(TokenType::EOF, "end of file")
19
- COMMA = Token.new_without_origin(TokenType::COMMA, "','")
20
- EQUALS = Token.new_without_origin(TokenType::EQUALS, "'='")
21
- COLON = Token.new_without_origin(TokenType::COLON, "':'")
22
- OPEN_CURLY = Token.new_without_origin(TokenType::OPEN_CURLY, "'{'")
23
- CLOSE_CURLY = Token.new_without_origin(TokenType::CLOSE_CURLY, "'}'")
24
- OPEN_SQUARE = Token.new_without_origin(TokenType::OPEN_SQUARE, "'['")
25
- CLOSE_SQUARE = Token.new_without_origin(TokenType::CLOSE_SQUARE, "']'")
26
- PLUS_EQUALS = Token.new_without_origin(TokenType::PLUS_EQUALS, "'+='")
26
+ ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
27
27
 
28
- class Comment < Token
29
- def initialize(origin, text)
30
- super(TokenType::COMMENT, origin)
31
- @text = text
28
+ class Value < Token
29
+ def initialize(value, orig_text = nil)
30
+ super(TokenType::VALUE, value.origin, orig_text)
31
+ @value = value
32
+ end
33
+
34
+ attr_reader :value
35
+
36
+ def to_s
37
+ if value.resolve_status == ResolveStatus::RESOLVED
38
+ "'#{value.unwrapped}' (#{Hocon::ConfigValueType.name(value.value_type)})"
39
+ else
40
+ "'<unresolved value>' (#{@value.value_type.name})"
41
+ end
42
+
43
+ end
44
+
45
+ def can_equal(o)
46
+ o.is_a?(Value)
47
+ end
48
+
49
+ def ==(other)
50
+ super(other) && other.value == @value
51
+ end
52
+
53
+ def hash
54
+ 41 * (41 + super) + value.hash
32
55
  end
33
- attr_reader :text
34
56
  end
35
57
 
36
- # This is not a Value, because it requires special processing
37
- class Substitution < Token
38
- def initialize(origin, optional, expression)
39
- super(TokenType::SUBSTITUTION, origin)
40
- @optional = optional
41
- @value = expression
58
+ class Line < Token
59
+ def initialize(origin)
60
+ super(TokenType::NEWLINE, origin)
61
+ end
62
+
63
+ def can_equal(other)
64
+ o.is_a?(Line)
65
+ end
66
+
67
+ def ==(other)
68
+ super(other) && other.line_number == line_number
69
+ end
70
+
71
+ def hash
72
+ 41 * (41 + super) + line_number
73
+ end
74
+
75
+ def token_text
76
+ "\n"
42
77
  end
43
78
  end
44
79
 
@@ -52,23 +87,49 @@ class Hocon::Impl::Tokens
52
87
  def to_s
53
88
  "'#{value}'"
54
89
  end
90
+
91
+ def can_equal(o)
92
+ o.is_a?(UnquotedText)
93
+ end
94
+
95
+ def ==(other)
96
+ super(other) && other.value == @value
97
+ end
98
+
99
+ def hash
100
+ 41 * (41 + super) + value.hash
101
+ end
102
+
103
+ def token_text
104
+ @value
105
+ end
55
106
  end
56
107
 
57
- class Value < Token
58
- def initialize(value)
59
- super(TokenType::VALUE, value.origin)
60
- @value = value
108
+ class IgnoredWhitespace < Token
109
+ def initialize(origin, s)
110
+ super(TokenType::IGNORED_WHITESPACE, origin)
111
+ @value = s
61
112
  end
62
113
  attr_reader :value
63
114
 
64
115
  def to_s
65
- "'#{value.unwrapped}' (#{Hocon::ConfigValueType.name(value.value_type)})"
116
+ "'#{value}' (WHITESPACE)"
66
117
  end
67
- end
68
118
 
69
- class Line < Token
70
- def initialize(origin)
71
- super(TokenType::NEWLINE, origin)
119
+ def can_equal(o)
120
+ o.is_a?(IgnoredWhitespace)
121
+ end
122
+
123
+ def ==(other)
124
+ super(other) && other.value == value
125
+ end
126
+
127
+ def hash
128
+ 41 * (41 + super) + value.hash
129
+ end
130
+
131
+ def token_text
132
+ @value
72
133
  end
73
134
  end
74
135
 
@@ -96,62 +157,189 @@ class Hocon::Impl::Tokens
96
157
  def cause
97
158
  @cause
98
159
  end
99
- end
100
160
 
101
- def self.get_problem_message(token)
102
- if token.is_a?(Problem)
103
- token.message
104
- else
105
- raise Hocon::ConfigError::ConfigBugOrBrokenError.new("tried to get problem message from #{token}", nil)
161
+ def to_s
162
+ sb = StringIO.new
163
+ sb << "'"
164
+ sb << what
165
+ sb << "'"
166
+ sb << " ("
167
+ sb << message
168
+ sb << ")"
169
+ sb.to_s
170
+ end
171
+
172
+ def can_equal(other)
173
+ other.is_a?(Problem)
174
+ end
175
+
176
+ def ==(other)
177
+ super(other) && other.what == @what &&
178
+ other.message == @message &&
179
+ other.suggest_quotes == @suggest_quotes &&
180
+ Hocon::Impl::ConfigImplUtil.equals_handling_nil?(other.cause, @cause)
181
+ end
182
+
183
+ def hash
184
+ hashcode = 41 * (41 + super)
185
+ hashcode = 41 * (hashcode + @what.hash)
186
+ hashcode = 41 * (hashcode + @message.hash)
187
+ hashcode = 41 * (hashcode + @suggest_quotes.hash)
188
+ unless @cause.nil?
189
+ hashcode = 41 * (hashcode + @cause.hash)
190
+ end
191
+
192
+ hashcode
106
193
  end
107
194
  end
108
195
 
109
- def self.get_problem_suggest_quotes(token)
110
- if token.is_a?(Problem)
111
- token.suggest_quotes
112
- else
113
- raise Hocon::ConfigError::ConfigBugOrBrokenError.new("tried to get problem suggest_quotes from #{token}", nil)
196
+ class Comment < Token
197
+ def initialize(origin, text)
198
+ super(TokenType::COMMENT, origin)
199
+ @text = text
200
+ end
201
+
202
+ class DoubleSlashComment < Comment
203
+ def initialize(origin, text)
204
+ super(origin, text)
205
+ end
206
+
207
+ def token_text
208
+ "//" + @text
209
+ end
210
+ end
211
+
212
+ class HashComment < Comment
213
+ def initialize(origin, text)
214
+ super(origin, text)
215
+ end
216
+
217
+ def token_text
218
+ "#" + @text
219
+ end
220
+ end
221
+
222
+ attr_reader :text
223
+
224
+ def to_s
225
+ sb = StringIO.new
226
+ sb << "'#"
227
+ sb << text
228
+ sb << "' (COMMENT)"
229
+ sb.string
230
+ end
231
+
232
+ def can_equal(other)
233
+ other.is_a?(Comment)
234
+ end
235
+
236
+ def ==(other)
237
+ super(other) && other.text == @text
238
+ end
239
+
240
+ def hash
241
+ hashcode = 41 * (41 + super)
242
+ hashcode = 41 * (hashcode + @text.hash)
243
+
244
+ hashcode
114
245
  end
115
246
  end
116
247
 
117
- def self.get_problem_cause(token)
118
- if token.is_a?(Problem)
119
- token.cause
120
- else
121
- raise Hocon::ConfigError::ConfigBugOrBrokenError.new("tried to get problem cause from #{token}", nil)
248
+ # This is not a Value, because it requires special processing
249
+ class Substitution < Token
250
+ def initialize(origin, optional, expression)
251
+ super(TokenType::SUBSTITUTION, origin)
252
+ @optional = optional
253
+ @value = expression
254
+ end
255
+
256
+ def optional?
257
+ @optional
258
+ end
259
+
260
+ attr_reader :value
261
+
262
+ def token_text
263
+ sub_text = ""
264
+ @value.each { |t| sub_text << t.token_text }
265
+ "${" + (@optional ? "?" : "") + sub_text + "}"
266
+ end
267
+
268
+ def to_s
269
+ sb = StringIO.new
270
+ value.each do |t|
271
+ sb << t.to_s
272
+ end
273
+ "'${#{sb.to_s}}'"
274
+ end
275
+
276
+ def can_equal(other)
277
+ other.is_a?(Substitution)
278
+ end
279
+
280
+ def ==(other)
281
+ super(other) && other.value == @value
282
+ end
283
+
284
+ def hash
285
+ 41 * (41 + super + @value.hash)
122
286
  end
123
287
  end
124
288
 
125
- def self.new_line(origin)
126
- Line.new(origin)
289
+ def self.value?(token)
290
+ token.is_a?(Value)
127
291
  end
128
292
 
129
- def self.new_problem(origin, what, message, suggest_quotes, cause)
130
- Problem.new(origin, what, message, suggest_quotes, cause)
293
+ def self.value(token)
294
+ if token.is_a?(Value)
295
+ token.value
296
+ else
297
+ raise ConfigBugOrBrokenError, "tried to get value of non-value token #{token}"
298
+ end
131
299
  end
132
300
 
133
- def self.new_comment(origin, text)
134
- Comment.new(origin, text)
301
+ def self.value_with_type?(t, value_type)
302
+ value?(t) && (value(t).value_type == value_type)
135
303
  end
136
304
 
137
- def self.new_unquoted_text(origin, s)
138
- UnquotedText.new(origin, s)
305
+ def self.newline?(t)
306
+ t.is_a?(Line)
139
307
  end
140
308
 
141
- def self.new_value(value)
142
- Value.new(value)
309
+ def self.problem?(t)
310
+ t.is_a?(Problem)
143
311
  end
144
312
 
145
- def self.new_string(origin, value)
146
- new_value(ConfigString.new(origin, value))
313
+ def self.get_problem_what(token)
314
+ if token.is_a?(Problem)
315
+ token.what
316
+ else
317
+ raise ConfigBugOrBrokenError, "tried to get problem what from #{token}"
318
+ end
147
319
  end
148
320
 
149
- def self.new_long(origin, value, original_text)
150
- new_value(ConfigNumber.new_number(origin, value, original_text))
321
+ def self.get_problem_message(token)
322
+ if token.is_a?(Problem)
323
+ token.message
324
+ else
325
+ raise ConfigBugOrBrokenError.new("tried to get problem message from #{token}")
326
+ end
151
327
  end
152
328
 
153
- def self.new_boolean(origin, value)
154
- new_value(ConfigBoolean.new(origin, value))
329
+ def self.get_problem_suggest_quotes(token)
330
+ if token.is_a?(Problem)
331
+ token.suggest_quotes
332
+ else
333
+ raise ConfigBugOrBrokenError.new("tried to get problem suggest_quotes from #{token}")
334
+ end
335
+ end
336
+
337
+ def self.get_problem_cause(token)
338
+ if token.is_a?(Problem)
339
+ token.cause
340
+ else
341
+ raise ConfigBugOrBrokenError.new("tried to get problem cause from #{token}")
342
+ end
155
343
  end
156
344
 
157
345
  def self.comment?(t)
@@ -162,14 +350,10 @@ class Hocon::Impl::Tokens
162
350
  if comment?(token)
163
351
  token.text
164
352
  else
165
- raise ConfigBugError, "tried to get comment text from #{token}"
353
+ raise ConfigBugOrBrokenError, "tried to get comment text from #{token}"
166
354
  end
167
355
  end
168
356
 
169
- def self.substitution?(t)
170
- t.is_a?(Substitution)
171
- end
172
-
173
357
  def self.unquoted_text?(token)
174
358
  token.is_a?(UnquotedText)
175
359
  end
@@ -178,31 +362,98 @@ class Hocon::Impl::Tokens
178
362
  if unquoted_text?(token)
179
363
  token.value
180
364
  else
181
- raise ConfigBugError, "tried to get unquoted text from #{token}"
365
+ raise ConfigBugOrBrokenError, "tried to get unquoted text from #{token}"
182
366
  end
183
367
  end
184
368
 
185
- def self.value?(token)
186
- token.is_a?(Value)
369
+ def self.ignored_whitespace?(token)
370
+ token.is_a?(IgnoredWhitespace)
187
371
  end
188
372
 
189
- def self.value(token)
190
- if token.is_a?(Value)
373
+ def self.substitution?(token)
374
+ token.is_a?(Substitution)
375
+ end
376
+
377
+ def self.get_substitution_path_expression(token)
378
+ if token.is_a?(Substitution)
191
379
  token.value
192
380
  else
193
- raise ConfigBugError, "tried to get value of non-value token #{token}"
381
+ raise ConfigBugOrBrokenError, "tried to get substitution from #{token}"
194
382
  end
195
383
  end
196
384
 
197
- def self.value_with_type?(t, value_type)
198
- value?(t) && (value(t).value_type == value_type)
385
+ def self.get_substitution_optional(token)
386
+ if token.is_a?(Substitution)
387
+ token.optional?
388
+ else
389
+ raise ConfigBugOrBrokenError, "tried to get substitution optionality from #{token}"
390
+ end
199
391
  end
200
392
 
201
- def self.newline?(t)
202
- t.is_a?(Line)
393
+ START = Token.new_without_origin(TokenType::START, "start of file", "")
394
+ EOF = Token.new_without_origin(TokenType::EOF, "end of file", "")
395
+ COMMA = Token.new_without_origin(TokenType::COMMA, "','", ",")
396
+ EQUALS = Token.new_without_origin(TokenType::EQUALS, "'='", "=")
397
+ COLON = Token.new_without_origin(TokenType::COLON, "':'", ":")
398
+ OPEN_CURLY = Token.new_without_origin(TokenType::OPEN_CURLY, "'{'", "{")
399
+ CLOSE_CURLY = Token.new_without_origin(TokenType::CLOSE_CURLY, "'}'", "}")
400
+ OPEN_SQUARE = Token.new_without_origin(TokenType::OPEN_SQUARE, "'['", "[")
401
+ CLOSE_SQUARE = Token.new_without_origin(TokenType::CLOSE_SQUARE, "']'", "]")
402
+ PLUS_EQUALS = Token.new_without_origin(TokenType::PLUS_EQUALS, "'+='", "+=")
403
+
404
+ def self.new_line(origin)
405
+ Line.new(origin)
203
406
  end
204
407
 
205
- def self.problem?(t)
206
- t.is_a?(Problem)
408
+ def self.new_problem(origin, what, message, suggest_quotes, cause)
409
+ Problem.new(origin, what, message, suggest_quotes, cause)
410
+ end
411
+
412
+ def self.new_comment_double_slash(origin, text)
413
+ Comment::DoubleSlashComment.new(origin, text)
414
+ end
415
+
416
+ def self.new_comment_hash(origin, text)
417
+ Comment::HashComment.new(origin, text)
418
+ end
419
+
420
+ def self.new_unquoted_text(origin, s)
421
+ UnquotedText.new(origin, s)
422
+ end
423
+
424
+ def self.new_ignored_whitespace(origin, s)
425
+ IgnoredWhitespace.new(origin, s)
426
+ end
427
+
428
+ def self.new_substitution(origin, optional, expression)
429
+ Substitution.new(origin, optional, expression)
430
+ end
431
+
432
+ def self.new_value(value, orig_text = nil)
433
+ Value.new(value, orig_text)
434
+ end
435
+
436
+ def self.new_string(origin, value, orig_text)
437
+ new_value(ConfigString::Quoted.new(origin, value), orig_text)
438
+ end
439
+
440
+ def self.new_int(origin, value, orig_text)
441
+ new_value(ConfigNumber.new_number(origin, value, orig_text), orig_text)
442
+ end
443
+
444
+ def self.new_double(origin, value, orig_text)
445
+ new_value(ConfigNumber.new_number(origin, value, orig_text), orig_text)
446
+ end
447
+
448
+ def self.new_long(origin, value, orig_text)
449
+ new_value(ConfigNumber.new_number(origin, value, orig_text), orig_text)
450
+ end
451
+
452
+ def self.new_null(origin)
453
+ new_value(ConfigNull.new(origin), "null")
454
+ end
455
+
456
+ def self.new_boolean(origin, value)
457
+ new_value(ConfigBoolean.new(origin, value), value.to_s)
207
458
  end
208
459
  end