ruby_hocon 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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