hocon 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.
Files changed (39) hide show
  1. data/LICENSE +202 -0
  2. data/README.md +19 -0
  3. data/lib/hocon.rb +2 -0
  4. data/lib/hocon/config_error.rb +12 -0
  5. data/lib/hocon/config_factory.rb +9 -0
  6. data/lib/hocon/config_object.rb +4 -0
  7. data/lib/hocon/config_parse_options.rb +53 -0
  8. data/lib/hocon/config_render_options.rb +46 -0
  9. data/lib/hocon/config_syntax.rb +7 -0
  10. data/lib/hocon/config_value_type.rb +26 -0
  11. data/lib/hocon/impl.rb +5 -0
  12. data/lib/hocon/impl/abstract_config_object.rb +64 -0
  13. data/lib/hocon/impl/abstract_config_value.rb +130 -0
  14. data/lib/hocon/impl/config_concatenation.rb +136 -0
  15. data/lib/hocon/impl/config_float.rb +9 -0
  16. data/lib/hocon/impl/config_impl.rb +10 -0
  17. data/lib/hocon/impl/config_impl_util.rb +78 -0
  18. data/lib/hocon/impl/config_int.rb +31 -0
  19. data/lib/hocon/impl/config_number.rb +27 -0
  20. data/lib/hocon/impl/config_string.rb +37 -0
  21. data/lib/hocon/impl/full_includer.rb +4 -0
  22. data/lib/hocon/impl/origin_type.rb +9 -0
  23. data/lib/hocon/impl/parseable.rb +151 -0
  24. data/lib/hocon/impl/parser.rb +882 -0
  25. data/lib/hocon/impl/path.rb +59 -0
  26. data/lib/hocon/impl/path_builder.rb +36 -0
  27. data/lib/hocon/impl/resolve_status.rb +18 -0
  28. data/lib/hocon/impl/simple_config.rb +11 -0
  29. data/lib/hocon/impl/simple_config_list.rb +70 -0
  30. data/lib/hocon/impl/simple_config_object.rb +178 -0
  31. data/lib/hocon/impl/simple_config_origin.rb +174 -0
  32. data/lib/hocon/impl/simple_include_context.rb +7 -0
  33. data/lib/hocon/impl/simple_includer.rb +19 -0
  34. data/lib/hocon/impl/token.rb +32 -0
  35. data/lib/hocon/impl/token_type.rb +42 -0
  36. data/lib/hocon/impl/tokenizer.rb +370 -0
  37. data/lib/hocon/impl/tokens.rb +157 -0
  38. data/lib/hocon/impl/unmergeable.rb +4 -0
  39. metadata +84 -0
@@ -0,0 +1,130 @@
1
+ require 'hocon/impl'
2
+ require 'stringio'
3
+ require 'hocon/config_render_options'
4
+ require 'hocon/config_object'
5
+ require 'hocon/impl/resolve_status'
6
+ require 'hocon/impl/unmergeable'
7
+ require 'hocon/impl/abstract_config_object'
8
+ require 'hocon/impl/config_impl_util'
9
+
10
+ ##
11
+ ## Trying very hard to avoid a parent reference in config values; when you have
12
+ ## a tree like this, the availability of parent() tends to result in a lot of
13
+ ## improperly-factored and non-modular code. Please don't add parent().
14
+ ##
15
+ class Hocon::Impl::AbstractConfigValue
16
+ ConfigImplUtil = Hocon::Impl::ConfigImplUtil
17
+
18
+ def initialize(origin)
19
+ @origin = origin
20
+ end
21
+
22
+ attr_reader :origin
23
+
24
+ def resolve_status
25
+ Hocon::Impl::ResolveStatus::RESOLVED
26
+ end
27
+
28
+ # this is virtualized rather than a field because only some subclasses
29
+ # really need to store the boolean, and they may be able to pack it
30
+ # with another boolean to save space.
31
+ def ignores_fallbacks?
32
+ # if we are not resolved, then somewhere in this value there's
33
+ # a substitution that may need to look at the fallbacks.
34
+ resolve_status == Hocon::Impl::ResolveStatus::RESOLVED
35
+ end
36
+
37
+ # the withFallback() implementation is supposed to avoid calling
38
+ # mergedWith* if we're ignoring fallbacks.
39
+ def require_not_ignoring_fallbacks
40
+ if ignores_fallbacks?
41
+ raise ConfigBugError, "method should not have been called with ignoresFallbacks=true #{self.class.name}"
42
+ end
43
+ end
44
+
45
+ def with_origin(origin)
46
+ if @origin == origin
47
+ self
48
+ else
49
+ new_copy(origin)
50
+ end
51
+ end
52
+
53
+ def with_fallback(mergeable)
54
+ if ignores_fallbacks?
55
+ self
56
+ else
57
+ other = mergeable.to_fallback_value
58
+ if other.is_a?(Hocon::Impl::Unmergeable)
59
+ merged_with_the_unmergeable(other)
60
+ elsif other.is_a?(Hocon::Impl::AbstractConfigObject)
61
+ merged_with_object(other)
62
+ else
63
+ merged_with_non_object(other)
64
+ end
65
+ end
66
+ end
67
+
68
+ def to_s
69
+ sb = StringIO.new
70
+ render_to_sb(sb, 0, true, nil, Hocon::ConfigRenderOptions.concise)
71
+ "#{self.class.name}(#{sb.string})"
72
+ end
73
+
74
+ def indent(sb, indent_size, options)
75
+ if options.formatted?
76
+ remaining = indent_size
77
+ while remaining > 0
78
+ sb << " "
79
+ remaining -= 1
80
+ end
81
+ end
82
+ end
83
+
84
+ def render_to_sb(sb, indent, at_root, at_key, options)
85
+ if !at_key.nil?
86
+ rendered_key =
87
+ if options.json?
88
+ ConfigImplUtil.render_json_string(at_key)
89
+ else
90
+ ConfigImplUtil.render_string_unquoted_if_possible(at_key)
91
+ end
92
+
93
+ sb << rendered_key
94
+
95
+ if options.json?
96
+ if options.formatted?
97
+ sb << " : "
98
+ else
99
+ sb << ":"
100
+ end
101
+ else
102
+ # in non-JSON we can omit the colon or equals before an object
103
+ if self.is_a?(Hocon::ConfigObject)
104
+ if options.formatted?
105
+ sb << ' '
106
+ end
107
+ else
108
+ sb << "="
109
+ end
110
+ end
111
+ end
112
+ render_value_to_sb(sb, indent, at_root, options)
113
+ end
114
+
115
+ # to be overridden by subclasses
116
+ def render_value_to_sb(sb, indent, at_root, options)
117
+ u = unwrapped
118
+ sb << u.to_s
119
+ end
120
+
121
+ def render(options = Hocon::ConfigRenderOptions.defaults)
122
+ sb = StringIO.new
123
+ render_to_sb(sb, 0, true, nil, options)
124
+ # We take a substring that ends at sb.pos, because we've been decrementing
125
+ # sb.pos at various points in the code as a means to remove characters from
126
+ # the end of the StringIO
127
+ sb.string[0, sb.pos]
128
+ end
129
+
130
+ end
@@ -0,0 +1,136 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/abstract_config_value'
3
+ require 'hocon/impl/abstract_config_object'
4
+ require 'hocon/impl/simple_config_list'
5
+ require 'hocon/config_object'
6
+ require 'hocon/impl/unmergeable'
7
+ require 'hocon/impl/simple_config_origin'
8
+ require 'hocon/impl/config_string'
9
+
10
+ class Hocon::Impl::ConfigConcatenation < Hocon::Impl::AbstractConfigValue
11
+ include Hocon::Impl::Unmergeable
12
+
13
+ SimpleConfigList = Hocon::Impl::SimpleConfigList
14
+ ConfigObject = Hocon::ConfigObject
15
+ Unmergeable = Hocon::Impl::Unmergeable
16
+ SimpleConfigOrigin = Hocon::Impl::SimpleConfigOrigin
17
+
18
+ #
19
+ # Add left and right, or their merger, to builder
20
+ #
21
+ def self.join(builder, orig_right)
22
+ left = builder[builder.size - 1]
23
+ right = orig_right
24
+
25
+ # check for an object which can be converted to a list
26
+ # (this will be an object with numeric keys, like foo.0, foo.1)
27
+ if (left.is_a?(ConfigObject)) && (right.is_a?(SimpleConfigList))
28
+ left = DefaultTransformer.transform(left, ConfigValueType::LIST)
29
+ elsif (left.is_a?(SimpleConfigList)) && (right.is_a?(ConfigObject))
30
+ right = DefaultTransformer.transform(right, ConfigValueType::LIST)
31
+ end
32
+
33
+ # Since this depends on the type of two instances, I couldn't think
34
+ # of much alternative to an instanceof chain. Visitors are sometimes
35
+ # used for multiple dispatch but seems like overkill.
36
+ joined = nil
37
+ if (left.is_a?(ConfigObject)) && (right.is_a?(ConfigObject))
38
+ joined = right.with_fallback(left)
39
+ elsif (left.is_a?(SimpleConfigList)) && (right.is_a?(SimpleConfigList))
40
+ joined = left.concatenate(right)
41
+ elsif (left.is_a?(Hocon::Impl::ConfigConcatenation)) ||
42
+ (right.is_a?(Hocon::Impl::ConfigConcatenation))
43
+ raise ConfigBugError, "unflattened ConfigConcatenation"
44
+ elsif (left.is_a?(Unmergeable)) || (right.is_a?(Unmergeable))
45
+ # leave joined=null, cannot join
46
+ else
47
+ # handle primitive type or primitive type mixed with object or list
48
+ s1 = left.transform_to_string
49
+ s2 = right.transform_to_string
50
+ if s1.nil? || s2.nil?
51
+ raise ConfigWrongTypeError.new(left.origin,
52
+ "Cannot concatenate object or list with a non-object-or-list, #{left} " +
53
+ "and #{right} are not compatible")
54
+ else
55
+ joined_origin = SimpleConfigOrigin.merge_origins([left.origin, right.origin])
56
+ joined = Hocon::Impl::ConfigString.new(joined_origin, s1 + s2)
57
+ end
58
+ end
59
+
60
+ if joined.nil?
61
+ builder.push(right)
62
+ else
63
+ builder.pop
64
+ builder.push(joined)
65
+ end
66
+ end
67
+
68
+ def self.consolidate(pieces)
69
+ if pieces.length < 2
70
+ pieces
71
+ else
72
+ flattened = []
73
+ pieces.each do |v|
74
+ if v.is_a?(Hocon::Impl::ConfigConcatenation)
75
+ flattened.concat(v.pieces)
76
+ else
77
+ flattened.push(v)
78
+ end
79
+ end
80
+
81
+ consolidated = []
82
+ flattened.each do |v|
83
+ if consolidated.empty?
84
+ consolidated.push(v)
85
+ else
86
+ join(consolidated, v)
87
+ end
88
+ end
89
+
90
+ consolidated
91
+ end
92
+ end
93
+
94
+ def self.concatenate(pieces)
95
+ consolidated = consolidate(pieces)
96
+ if consolidated.empty?
97
+ nil
98
+ elsif consolidated.length == 1
99
+ consolidated[0]
100
+ else
101
+ merged_origin = SimpleConfigOrigin.merge_origins(consolidated)
102
+ Hocon::Impl::ConfigConcatenation.new(merged_origin, consolidated)
103
+ end
104
+ end
105
+
106
+
107
+ def initialize(origin, pieces)
108
+ super(origin)
109
+ @pieces = pieces
110
+
111
+ if pieces.size < 2
112
+ raise ConfigBugError, "Created concatenation with less than 2 items: #{self}"
113
+ end
114
+
115
+ had_unmergeable = false
116
+ pieces.each do |p|
117
+ if p.is_a?(Hocon::Impl::ConfigConcatenation)
118
+ raise ConfigBugError, "ConfigConcatenation should never be nested: #{self}"
119
+ end
120
+ if p.is_a?(Unmergeable)
121
+ had_unmergeable = true
122
+ end
123
+ end
124
+
125
+ unless had_unmergeable
126
+ raise ConfigBugError, "Created concatenation without an unmergeable in it: #{self}"
127
+ end
128
+ end
129
+
130
+ def ignores_fallbacks?
131
+ # we can never ignore fallbacks because if a child ConfigReference
132
+ # is self-referential we have to look lower in the merge stack
133
+ # for its value.
134
+ false
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/config_number'
3
+
4
+ class Hocon::Impl::ConfigFloat < Hocon::Impl::ConfigNumber
5
+ def initialize(origin, value, original_text)
6
+ super(origin, original_text)
7
+ @value = value
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/simple_includer'
3
+
4
+ class Hocon::Impl::ConfigImpl
5
+ @default_includer = Hocon::Impl::SimpleIncluder.new
6
+
7
+ def self.default_includer
8
+ @default_includer
9
+ end
10
+ end
@@ -0,0 +1,78 @@
1
+ require 'hocon/impl'
2
+ require 'stringio'
3
+
4
+ class Hocon::Impl::ConfigImplUtil
5
+ def self.equals_handling_nil?(a, b)
6
+ # This method probably doesn't make any sense in ruby... not sure
7
+ if a.nil? && !b.nil?
8
+ false
9
+ elsif !a.nil? && b.nil?
10
+ false
11
+ # in ruby, the == and .equal? are the opposite of what they are in Java
12
+ elsif a.equal?(b)
13
+ true
14
+ else
15
+ a == b
16
+ end
17
+ end
18
+
19
+ #
20
+ # This is public ONLY for use by the "config" package, DO NOT USE this ABI
21
+ # may change.
22
+ #
23
+ def self.render_json_string(s)
24
+ sb = StringIO.new
25
+ sb << '"'
26
+ s.chars.each do |c|
27
+ case c
28
+ when '"' then sb << "\\\""
29
+ when "\\" then sb << "\\\\"
30
+ when "\n" then sb << "\\n"
31
+ when "\b" then sb << "\\b"
32
+ when "\f" then sb << "\\f"
33
+ when "\r" then sb << "\\r"
34
+ when "\t" then sb << "\\t"
35
+ else
36
+ if c =~ /[[:cntrl:]]/
37
+ sb << ("\\u%04x" % c)
38
+ else
39
+ sb << c
40
+ end
41
+ end
42
+ end
43
+ sb << '"'
44
+ sb.string
45
+ end
46
+
47
+ def self.render_string_unquoted_if_possible(s)
48
+ # this can quote unnecessarily as long as it never fails to quote when
49
+ # necessary
50
+ if s.length == 0
51
+ return render_json_string(s)
52
+ end
53
+
54
+ # if it starts with a hyphen or number, we have to quote
55
+ # to ensure we end up with a string and not a number
56
+ first = s.chars.first
57
+ if (first =~ /[[:digit:]]/) || (first == '-')
58
+ return render_json_string(s)
59
+ end
60
+
61
+ # only unquote if it's pure alphanumeric
62
+ s.chars.each do |c|
63
+ unless (c =~ /[[:alnum:]]/) || (c == '-')
64
+ return render_json_string(s)
65
+ end
66
+ end
67
+
68
+ s
69
+ end
70
+
71
+ def self.whitespace?(c)
72
+ # this implementation is *not* a port of the java code, because it relied on
73
+ # the method java.lang.Character#isWhitespace. This is probably
74
+ # insanely slow (running a regex against every single character in the
75
+ # file).
76
+ c =~ /[[:space:]]/
77
+ end
78
+ end
@@ -0,0 +1,31 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/config_number'
3
+ require 'hocon/config_value_type'
4
+
5
+ class Hocon::Impl::ConfigInt < Hocon::Impl::ConfigNumber
6
+ def initialize(origin, value, original_text)
7
+ super(origin, original_text)
8
+ @value = value
9
+ end
10
+
11
+ def value_type
12
+ Hocon::ConfigValueType::NUMBER
13
+ end
14
+
15
+ def unwrapped
16
+ @value
17
+ end
18
+
19
+ def transform_to_string
20
+ s = super
21
+ if s.nil?
22
+ self.to_s
23
+ else
24
+ s
25
+ end
26
+ end
27
+
28
+ def new_copy(origin)
29
+ Hocon::Impl::ConfigInt.new(origin, @value, @original_text)
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/abstract_config_value'
3
+
4
+ class Hocon::Impl::ConfigNumber < Hocon::Impl::AbstractConfigValue
5
+ ## sigh... requiring these subclasses before this class
6
+ ## is declared would cause an error. Thanks, ruby.
7
+ require 'hocon/impl/config_int'
8
+ require 'hocon/impl/config_float'
9
+
10
+ def self.new_number(origin, number, original_text)
11
+ as_int = number.to_i
12
+ if as_int == number
13
+ Hocon::Impl::ConfigInt.new(origin, as_int, original_text)
14
+ else
15
+ Hocon::Impl::ConfigFloat.new(origin, number, original_text)
16
+ end
17
+ end
18
+
19
+ def initialize(origin, original_text)
20
+ super(origin)
21
+ @original_text = original_text
22
+ end
23
+
24
+ def transform_to_string
25
+ @original_text
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'hocon/impl'
2
+ require 'hocon/impl/abstract_config_value'
3
+ require 'hocon/config_value_type'
4
+ require 'hocon/impl/config_impl_util'
5
+
6
+ class Hocon::Impl::ConfigString < Hocon::Impl::AbstractConfigValue
7
+ ConfigImplUtil = Hocon::Impl::ConfigImplUtil
8
+
9
+ def initialize(origin, value)
10
+ super(origin)
11
+ @value = value
12
+ end
13
+
14
+ def value_type
15
+ Hocon::ConfigValueType::STRING
16
+ end
17
+
18
+ def unwrapped
19
+ @value
20
+ end
21
+
22
+ def transform_to_string
23
+ @value
24
+ end
25
+
26
+ def render_value_to_sb(sb, indent_size, at_root, options)
27
+ if options.json?
28
+ sb << ConfigImplUtil.render_json_string(@value)
29
+ else
30
+ sb << ConfigImplUtil.render_string_unquoted_if_possible(@value)
31
+ end
32
+ end
33
+
34
+ def new_copy(origin)
35
+ Hocon::Impl::ConfigString.new(origin, @value)
36
+ end
37
+ end