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
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