typesafe_config 0.0.3 → 0.0.4

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/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
data/README.md CHANGED
@@ -1,2 +1,17 @@
1
1
  ruby-typesafe-config
2
2
  ==========
3
+
4
+ This is a port of the [Typesafe Config](https://github.com/typesafehub/config) library to Ruby.
5
+
6
+ At present, the only features it supports are explicit parsing of config files (.conf/HOCON, .json, .properties) via `ConfigFactory.parse_file`, and rendering a parsed config object back to a String. Testing is minimal and not all data types are supported yet. It also does not yet support `include` or interpolated settings.
7
+
8
+ The implementation is intended to be as close to a line-for-line port as the two languages allow, in hopes of making it fairly easy to port over new changesets from the Java code base over time.
9
+
10
+ Basic Usage
11
+ ===========
12
+
13
+ ```rb
14
+ require 'typesafe/config/config_factory'
15
+
16
+ conf = Typesafe::Config::ConfigFactory.parse_file("myapp.conf")
17
+ conf_map = conf.root.unwrapped
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typesafe_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,50 +11,13 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2014-03-14 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: == A port of the Java {Typesafe Config}[https://github.com/typesafehub/config]
15
- library to Ruby
14
+ description: == This gem has been replaced by the {HOCON}[https://rubygems.org/gems/ruby_hocon]
15
+ gem
16
16
  email: chris@puppetlabs.com
17
17
  executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
- - lib/typesafe/config.rb
22
- - lib/typesafe/config/config_object.rb
23
- - lib/typesafe/config/config_error.rb
24
- - lib/typesafe/config/impl/simple_includer.rb
25
- - lib/typesafe/config/impl/config_number.rb
26
- - lib/typesafe/config/impl/simple_config.rb
27
- - lib/typesafe/config/impl/config_int.rb
28
- - lib/typesafe/config/impl/resolve_status.rb
29
- - lib/typesafe/config/impl/simple_config_origin.rb
30
- - lib/typesafe/config/impl/token.rb
31
- - lib/typesafe/config/impl/config_string.rb
32
- - lib/typesafe/config/impl/config_float.rb
33
- - lib/typesafe/config/impl/full_includer.rb
34
- - lib/typesafe/config/impl/parser.rb
35
- - lib/typesafe/config/impl/tokens.rb
36
- - lib/typesafe/config/impl/tokenizer.rb
37
- - lib/typesafe/config/impl/abstract_config_object.rb
38
- - lib/typesafe/config/impl/simple_include_context.rb
39
- - lib/typesafe/config/impl/token_type.rb
40
- - lib/typesafe/config/impl/path_builder.rb
41
- - lib/typesafe/config/impl/parseable.rb
42
- - lib/typesafe/config/impl/path.rb
43
- - lib/typesafe/config/impl/unmergeable.rb
44
- - lib/typesafe/config/impl/config_impl_util.rb
45
- - lib/typesafe/config/impl/simple_config_object.rb
46
- - lib/typesafe/config/impl/simple_config_list.rb
47
- - lib/typesafe/config/impl/config_impl.rb
48
- - lib/typesafe/config/impl/config_concatenation.rb
49
- - lib/typesafe/config/impl/abstract_config_value.rb
50
- - lib/typesafe/config/impl/origin_type.rb
51
- - lib/typesafe/config/config_factory.rb
52
- - lib/typesafe/config/impl.rb
53
- - lib/typesafe/config/config_parse_options.rb
54
- - lib/typesafe/config/config_render_options.rb
55
- - lib/typesafe/config/config_value_type.rb
56
- - lib/typesafe/config/config_syntax.rb
57
- - lib/typesafe.rb
58
21
  - LICENSE
59
22
  - README.md
60
23
  homepage: https://github.com/cprice404/ruby-typesafe-config
@@ -1,12 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- class Typesafe::Config::ConfigError < StandardError
4
- def initialize(origin, message, cause)
5
- super(message)
6
- @origin = origin
7
- @cause = cause
8
- end
9
-
10
- class ConfigParseError < Typesafe::Config::ConfigError
11
- end
12
- end
@@ -1,9 +0,0 @@
1
- require 'typesafe/config'
2
- require 'typesafe/config/config_parse_options'
3
- require 'typesafe/config/impl/parseable'
4
-
5
- class Typesafe::Config::ConfigFactory
6
- def self.parse_file(file_path, options = Typesafe::Config::ConfigParseOptions.defaults)
7
- Typesafe::Config::Impl::Parseable.new_file(file_path, options).parse.to_config
8
- end
9
- end
@@ -1,4 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- module Typesafe::Config::ConfigObject
4
- end
@@ -1,53 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- class Typesafe::Config::ConfigParseOptions
4
- attr_accessor :syntax, :origin_description, :allow_missing, :includer
5
-
6
- def self.defaults
7
- self.new(nil, nil, true, nil)
8
- end
9
-
10
- def initialize(syntax, origin_description, allow_missing, includer)
11
- @syntax = syntax
12
- @origin_description = origin_description
13
- @allow_missing = allow_missing
14
- @includer = includer
15
- end
16
-
17
- def allow_missing?
18
- @allow_missing
19
- end
20
-
21
- def with_syntax(syntax)
22
- if @syntax == syntax
23
- self
24
- else
25
- Typesafe::Config::ConfigParseOptions.new(syntax,
26
- @origin_description,
27
- @allow_missing,
28
- @includer)
29
- end
30
- end
31
-
32
- def with_includer(includer)
33
- if @includer == includer
34
- self
35
- else
36
- Typesafe::Config::ConfigParseOptions.new(@syntax,
37
- @origin_description,
38
- @allow_missing,
39
- includer)
40
- end
41
- end
42
-
43
- def append_includer(includer)
44
- if @includer == includer
45
- self
46
- elsif @includer
47
- with_includer(@includer.with_fallback(includer))
48
- else
49
- with_includer(includer)
50
- end
51
- end
52
-
53
- end
@@ -1,46 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- class Typesafe::Config::ConfigRenderOptions
4
- def initialize(origin_comments, comments, formatted, json)
5
- @origin_comments = origin_comments
6
- @comments = comments
7
- @formatted = formatted
8
- @json = json
9
- end
10
-
11
- attr_writer :origin_comments, :comments, :formatted, :json
12
-
13
- def origin_comments?
14
- @origin_comments
15
- end
16
- def comments?
17
- @comments
18
- end
19
- def formatted?
20
- @formatted
21
- end
22
- def json?
23
- @json
24
- end
25
-
26
- #
27
- # Returns the default render options which are verbose (commented and
28
- # formatted). See {@link ConfigRenderOptions#concise} for stripped-down
29
- # options. This rendering will not be valid JSON since it has comments.
30
- #
31
- # @return the default render options
32
- #
33
- def self.defaults
34
- Typesafe::Config::ConfigRenderOptions.new(true, true, true, true)
35
- end
36
-
37
- #
38
- # Returns concise render options (no whitespace or comments). For a
39
- # resolved {@link Config}, the concise rendering will be valid JSON.
40
- #
41
- # @return the concise render options
42
- #
43
- def self.concise
44
- Typesafe::Config::ConfigRenderOptions.new(false, false, false, true)
45
- end
46
- end
@@ -1,7 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- module Typesafe::Config::ConfigSyntax
4
- JSON = 0
5
- CONF = 1
6
- PROPERTIES = 2
7
- end
@@ -1,26 +0,0 @@
1
- require 'typesafe/config'
2
-
3
- #
4
- # The type of a configuration value (following the <a
5
- # href="http://json.org">JSON</a> type schema).
6
- #
7
- module Typesafe::Config::ConfigValueType
8
- OBJECT = 0
9
- LIST = 1
10
- NUMBER = 2
11
- BOOLEAN = 3
12
- NULL = 4
13
- STRING = 5
14
-
15
- def self.name(config_value_type)
16
- case config_value_type
17
- when OBJECT then "OBJECT"
18
- when LIST then "LIST"
19
- when NUMBER then "NUMBER"
20
- when BOOLEAN then "BOOLEAN"
21
- when NULL then "NULL"
22
- when STRING then "STRING"
23
- else raise ConfigBugError, "Unrecognized value type '#{config_value_type}'"
24
- end
25
- end
26
- end
@@ -1,64 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/abstract_config_value'
3
- require 'typesafe/config/impl/simple_config'
4
- require 'typesafe/config/config_object'
5
- require 'typesafe/config/config_value_type'
6
- require 'typesafe/config/impl/resolve_status'
7
- require 'typesafe/config/impl/simple_config_origin'
8
-
9
- class Typesafe::Config::Impl::AbstractConfigObject < Typesafe::Config::Impl::AbstractConfigValue
10
- include Typesafe::Config::ConfigObject
11
-
12
- def initialize(origin)
13
- super(origin)
14
- @config = Typesafe::Config::Impl::SimpleConfig.new(self)
15
- end
16
-
17
- def to_config
18
- @config
19
- end
20
-
21
- def to_fallback_value
22
- self
23
- end
24
-
25
- def value_type
26
- Typesafe::Config::ConfigValueType::OBJECT
27
- end
28
-
29
- def new_copy(origin)
30
- new_copy_with_status(resolve_status, origin)
31
- end
32
-
33
- def merge_origins(stack)
34
- if stack.empty?
35
- raise ConfigBugError, "can't merge origins on empty list"
36
- end
37
- origins = []
38
- first_origin = nil
39
- num_merged = 0
40
- stack.each do |v|
41
- if first_origin.nil?
42
- first_origin = v.origin
43
- end
44
-
45
- if (v.is_a?(Typesafe::Config::Impl::AbstractConfigObject)) &&
46
- (v.resolve_status == Typesafe::Config::Impl::ResolveStatus::RESOLVED) &&
47
- v.empty?
48
- # don't include empty files or the .empty()
49
- # config in the description, since they are
50
- # likely to be "implementation details"
51
- else
52
- origins.push(v.origin)
53
- num_merged += 1
54
- end
55
- end
56
-
57
- if num_merged == 0
58
- # the configs were all empty, so just use the first one
59
- origins.push(first_origin)
60
- end
61
-
62
- Typesafe::Config::Impl::SimpleConfigOrigin.merge_origins(origins)
63
- end
64
- end
@@ -1,130 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'stringio'
3
- require 'typesafe/config/config_render_options'
4
- require 'typesafe/config/config_object'
5
- require 'typesafe/config/impl/resolve_status'
6
- require 'typesafe/config/impl/unmergeable'
7
- require 'typesafe/config/impl/abstract_config_object'
8
- require 'typesafe/config/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 Typesafe::Config::Impl::AbstractConfigValue
16
- ConfigImplUtil = Typesafe::Config::Impl::ConfigImplUtil
17
-
18
- def initialize(origin)
19
- @origin = origin
20
- end
21
-
22
- attr_reader :origin
23
-
24
- def resolve_status
25
- Typesafe::Config::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 == Typesafe::Config::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?(Typesafe::Config::Impl::Unmergeable)
59
- merged_with_the_unmergeable(other)
60
- elsif other.is_a?(Typesafe::Config::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, Typesafe::Config::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?(Typesafe::Config::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 = Typesafe::Config::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
@@ -1,136 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/abstract_config_value'
3
- require 'typesafe/config/impl/abstract_config_object'
4
- require 'typesafe/config/impl/simple_config_list'
5
- require 'typesafe/config/config_object'
6
- require 'typesafe/config/impl/unmergeable'
7
- require 'typesafe/config/impl/simple_config_origin'
8
- require 'typesafe/config/impl/config_string'
9
-
10
- class Typesafe::Config::Impl::ConfigConcatenation < Typesafe::Config::Impl::AbstractConfigValue
11
- include Typesafe::Config::Impl::Unmergeable
12
-
13
- SimpleConfigList = Typesafe::Config::Impl::SimpleConfigList
14
- ConfigObject = Typesafe::Config::ConfigObject
15
- Unmergeable = Typesafe::Config::Impl::Unmergeable
16
- SimpleConfigOrigin = Typesafe::Config::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?(Typesafe::Config::Impl::ConfigConcatenation)) ||
42
- (right.is_a?(Typesafe::Config::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 = Typesafe::Config::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?(Typesafe::Config::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
- Typesafe::Config::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?(Typesafe::Config::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
@@ -1,9 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/config_number'
3
-
4
- class Typesafe::Config::Impl::ConfigFloat < Typesafe::Config::Impl::ConfigNumber
5
- def initialize(origin, value, original_text)
6
- super(origin, original_text)
7
- @value = value
8
- end
9
- end
@@ -1,10 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'typesafe/config/impl/simple_includer'
3
-
4
- class Typesafe::Config::Impl::ConfigImpl
5
- @default_includer = Typesafe::Config::Impl::SimpleIncluder.new
6
-
7
- def self.default_includer
8
- @default_includer
9
- end
10
- end
@@ -1,78 +0,0 @@
1
- require 'typesafe/config/impl'
2
- require 'stringio'
3
-
4
- class Typesafe::Config::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