nestedtext 3.2.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -5
- data/README.md +16 -13
- data/lib/nestedtext/constants.rb +6 -3
- data/lib/nestedtext/core_ext.rb +7 -12
- data/lib/nestedtext/core_ext_internal.rb +3 -1
- data/lib/nestedtext/decode.rb +11 -9
- data/lib/nestedtext/dumper.rb +74 -69
- data/lib/nestedtext/encode.rb +7 -6
- data/lib/nestedtext/encode_helpers.rb +4 -3
- data/lib/nestedtext/error.rb +2 -0
- data/lib/nestedtext/errors_internal.rb +82 -58
- data/lib/nestedtext/inline_parser.rb +134 -0
- data/lib/nestedtext/parser.rb +144 -185
- data/lib/nestedtext/scanners.rb +21 -15
- data/lib/nestedtext/version.rb +1 -1
- data/lib/nestedtext.rb +6 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 195cf273687c9cf4af35eaea661eef6086bdb8b1f47578092e7473a4cb56a418
|
4
|
+
data.tar.gz: 32ca43c2433eea7065cd56e2809c85accd1165a3bf734e5ba0525fe3a256f56a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8869b326141ccf9e56653bade9795f5a110f45d628df8eb1c372763a7cf5bfe7cb8a1077ff0fb36e5b0ec466f5f9f286fe877e1aaf1a4af3271c4ce5f8f718ed
|
7
|
+
data.tar.gz: ac63098b99b0d5d4f2060ecae53d8f325ca64af240e7250e07f3757088d7aee9ef81f495f8b4969b7a139f373b2c77d8c0711d947421ef41075f6671b2d9c453
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [4.0.0] - 2022-01-28
|
10
|
+
### Changed
|
11
|
+
- **Breaking change**: Renamed `NTEncodeMixin` to `ToNTMixin`.
|
12
|
+
- All code linted with RuboCop
|
13
|
+
|
9
14
|
## [3.2.1] - 2022-01-27
|
10
15
|
### Fixed
|
11
16
|
- Fix logo at rubydoc.info
|
@@ -26,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
26
31
|
- Removed leaked `NT_MIXIN` constant in core extensions.
|
27
32
|
|
28
33
|
### Changed
|
29
|
-
- **Breaking change**: `#to_nt` on `String`, `Array` and `Hash` is no longer strict by default for consistency an unexpected surprises e.g. when having an array of
|
34
|
+
- **Breaking change**: `#to_nt` on `String`, `Array` and `Hash` is no longer strict by default for consistency an unexpected surprises e.g. when having an array of Custom Objects and calling the method on the array.
|
30
35
|
- Internal clean-up and simplifications on helper classes and methods.
|
31
36
|
|
32
37
|
## [2.1.0] - 2022-01-27
|
@@ -49,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
49
54
|
|
50
55
|
## [1.1.1] - 2022-01-25
|
51
56
|
### Fixed
|
52
|
-
- Renamed `
|
57
|
+
- Renamed `ToNTMixing` to `ToNTMixin` .
|
53
58
|
|
54
59
|
## [1.1.0] - 2022-01-25
|
55
60
|
### Added
|
@@ -70,13 +75,13 @@ The library is now useful for users!
|
|
70
75
|
- Publish Gem to GitHub Packages
|
71
76
|
|
72
77
|
## [0.4.0] - 2022-01-24
|
73
|
-
- Iteration on CD GitHub
|
78
|
+
- Iteration on CD GitHub Actions workflow.
|
74
79
|
|
75
80
|
## [0.3.0] - 2022-01-24
|
76
|
-
- Iteration on CD GitHub
|
81
|
+
- Iteration on CD GitHub Actions workflow.
|
77
82
|
|
78
83
|
## [0.2.0] - 2022-01-24
|
79
|
-
- Iteration on CD GitHub
|
84
|
+
- Iteration on CD GitHub Actions workflow.
|
80
85
|
|
81
86
|
## [0.1.0] - 2022-01-24
|
82
87
|
### Added
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# NestedText Ruby Library [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=NestedText,%20the%20human%20friendly%20data%20format,%20has%20a%20now%20a%20ruby%20library%20for%20easy%20encoding%20and%20decoding&url=https://github.com/erikw/nestedtext-ruby&via=erik_westrup&hashtags=nestedtext,ruby,gem)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/nestedtext.svg)](https://badge.fury.io/rb/nestedtext)
|
3
3
|
[![Gem Downloads](https://ruby-gem-downloads-badge.herokuapp.com/nestedtext?color=brightgreen&type=total&label=gem%20downloads)](https://rubygems.org/gems/nestedtext)
|
4
|
-
[![Documentation](https://img.shields.io/badge/docs-API-informational?logo=readthedocs&logoColor=violet)](https://www.rubydoc.info/gems/nestedtext/)
|
4
|
+
[![Documentation](https://img.shields.io/badge/docs-API-informational?logo=readthedocs&logoColor=violet)](https://www.rubydoc.info/gems/nestedtext/NestedText)
|
5
5
|
[![Data Format Version Supported](https://img.shields.io/badge/%F0%9F%84%BD%F0%9F%85%83%20Version%20Supported-3.2.1-blueviolet)](https://nestedtext.org/en/v3.2/)
|
6
6
|
[![Official Tests](https://img.shields.io/badge/Official%20Tests-Passing-success?logo=cachet)](https://github.com/KenKundert/nestedtext_tests/tree/585e95a73d94ac1f48e71a154e2db0ab67cf30fa)
|
7
7
|
[![GitHub Actions: Continuous Integration](https://github.com/erikw/nestedtext-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/erikw/nestedtext-ruby/actions/workflows/ci.yml)
|
@@ -16,8 +16,8 @@
|
|
16
16
|
|
17
17
|
A ruby library for the human friendly data format [NestedText](https://nestedtext.org/).
|
18
18
|
|
19
|
-
<!-- Use URL to
|
20
|
-
<a href="#" ><img src="https://raw.githubusercontent.com/erikw/nestedtext-ruby/main/img/logo.webp" align="right" width="420px" alt="
|
19
|
+
<!-- Use URL to hosted image, so that it shows up at rubydocs.info as well. Using relative image and yardoc option "--asset img:img" did not work. -->
|
20
|
+
<a href="#" ><img src="https://raw.githubusercontent.com/erikw/nestedtext-ruby/main/img/logo.webp" align="right" width="420px" alt="nestedtext-ruby logo" /></a>
|
21
21
|
|
22
22
|
Provided is support for decoding a NestedText file or string to Ruby data structures, as well as encoding Ruby objects to a NestedText file or string. Furthermore there is support for serialization and deserialization of custom classes. The supported language version of the data format can be see in the badge above. This implementation pass all the [official tests](https://github.com/KenKundert/nestedtext_tests).
|
23
23
|
|
@@ -57,7 +57,7 @@ vice president:
|
|
57
57
|
See the [language introduction](https://nestedtext.org/en/latest/basic_syntax.html) for more details.
|
58
58
|
|
59
59
|
# Usage
|
60
|
-
The full API documentation can be found at [
|
60
|
+
The **full API documentation** can be found at [rubydocs.info](https://www.rubydoc.info/gems/nestedtext/NestedText). A minimal & fully working example of a project using this library can be found at [erikw/nestedtext-ruby-test](https://github.com/erikw/nestedtext-ruby-test).
|
61
61
|
|
62
62
|
## Decoding (reading NT)
|
63
63
|
This is how you can decode NestedText from a string or directly from a file (`*.nt`) to Ruby object instances:
|
@@ -172,7 +172,7 @@ Other Class | String | `#to_s` will be called if there is no `#encode_nt_with`
|
|
172
172
|
## Custom Classes Serialization
|
173
173
|
This library has support for serialization/deserialization of custom classes as well. This is done by letting the objects tell NestedText what data should be used to represent the object instance with the `#encode_nt_with` method (inspired by `YAML`'s `#encode_with` method). All objects being recursively referenced from a root object being serialized must either implement this method or be one of the core supported NestedText data types from the table above.
|
174
174
|
|
175
|
-
A class implementing `#encode_nt_with` is
|
175
|
+
A class implementing `#encode_nt_with` is referred to as `Custom Class` in this document.
|
176
176
|
|
177
177
|
```ruby
|
178
178
|
class Apple
|
@@ -221,10 +221,10 @@ data:
|
|
221
221
|
- 12
|
222
222
|
```
|
223
223
|
|
224
|
-
If you want to add some more super powers to your custom class, you can add the `#to_nt` shortcut by including the `
|
224
|
+
If you want to add some more super powers to your custom class, you can add the `#to_nt` shortcut by including the `ToNTMixin`:
|
225
225
|
```ruby
|
226
226
|
class Apple
|
227
|
-
include NestedText::
|
227
|
+
include NestedText::ToNTMixin
|
228
228
|
...
|
229
229
|
end
|
230
230
|
|
@@ -278,12 +278,15 @@ See [encode_custom_classes_test.rb](test/nestedtext/encode_custom_classes_test.r
|
|
278
278
|
1. For local testing, install the gem on local machine with: `$ bundle exec rake install`.
|
279
279
|
* or manually with `$ gem build *.gemscpec && gem install *.gem`
|
280
280
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
irb>
|
286
|
-
|
281
|
+
|
282
|
+
Extra:
|
283
|
+
* Make sure that only intended constants and methods are exposed publicly from the module `NestedText`. Check with
|
284
|
+
```
|
285
|
+
irb> require 'nestedtext'
|
286
|
+
irb> NestedText.constants
|
287
|
+
irb> NestedText.methods(false)
|
288
|
+
```
|
289
|
+
* To see undocumented methods with [YARD](https://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md): `$ yard stats --list-undoc`
|
287
290
|
|
288
291
|
# Releasing
|
289
292
|
Instructions for releasing on rubygems.org below. Optionally make a GitHub [release](https://github.com/erikw/nestedtext-ruby/releases) after this for the pushed git tag.
|
data/lib/nestedtext/constants.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
2
5
|
module NestedText
|
3
|
-
TOP_LEVEL_TYPES = [Object, Hash, Array, String]
|
4
|
-
CUSTOM_CLASS_KEY =
|
6
|
+
TOP_LEVEL_TYPES = [Object, Hash, Array, String].freeze
|
7
|
+
CUSTOM_CLASS_KEY = '__nestedtext_class__'
|
5
8
|
|
6
9
|
private_constant :TOP_LEVEL_TYPES, :CUSTOM_CLASS_KEY
|
7
10
|
end
|
data/lib/nestedtext/core_ext.rb
CHANGED
@@ -1,28 +1,23 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
# TODO: add encoding of more Ruby native classes like Integer, Float etc plus commons like Set,....? Not covered in NestedText language.
|
6
|
-
# Or leave this to a schema validator 3rd party plugin maybe? And replace my custom class decoding (and also encoding?)?
|
7
|
-
# Or both: add encoding/decoding of more native classes, and allow decoding + applying a schema with 3rd party.
|
8
|
-
# Or encourage using Marshal from core?
|
3
|
+
require 'nestedtext/encode_helpers'
|
9
4
|
|
10
5
|
# Extended with the `#to_nt` method.
|
11
|
-
class String include NestedText::
|
6
|
+
class String include NestedText::ToNTMixin; end
|
12
7
|
|
13
8
|
# Extended with the `#to_nt` method.
|
14
|
-
class Array include NestedText::
|
9
|
+
class Array include NestedText::ToNTMixin; end
|
15
10
|
|
16
11
|
# Extended with the `#to_nt` method.
|
17
|
-
class Hash include NestedText::
|
12
|
+
class Hash include NestedText::ToNTMixin; end
|
18
13
|
|
19
14
|
# Extended with NestedText support.
|
20
15
|
class NilClass
|
21
|
-
include NestedText::
|
16
|
+
include NestedText::ToNTMixin
|
22
17
|
|
23
18
|
# Adds support for encoding and decoding nil.
|
24
19
|
def self.nt_create(_data) = nil
|
25
20
|
|
26
21
|
# Adds support for encoding and decoding nil.
|
27
|
-
def encode_nt_with() =
|
22
|
+
def encode_nt_with() = ''
|
28
23
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NestedText
|
2
4
|
# Hiding extensions for Kernel here away from users.
|
3
5
|
# Reference: https://ruby-doc.org/core-3.1.0/doc/syntax/refinements_rdoc.html
|
4
6
|
module CoreExtInternal
|
5
7
|
refine String do
|
6
8
|
def normalize_line_endings
|
7
|
-
#
|
9
|
+
# Windows/Mac -> Unix
|
8
10
|
gsub(/\r\n?/, "\n")
|
9
11
|
end
|
10
12
|
end
|
data/lib/nestedtext/decode.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'nestedtext/parser'
|
4
|
+
require 'nestedtext/errors_internal'
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require 'logger'
|
7
|
+
require 'stringio'
|
8
8
|
|
9
9
|
module NestedText
|
10
10
|
# Decode a NestedText string to Ruby objects.
|
11
11
|
#
|
12
12
|
# @param ntstring [String] The string containing NestedText to be decoded.
|
13
|
-
# @param top_class [String] Force the top level returned object to be of this type.
|
13
|
+
# @param top_class [String] Force the top level returned object to be of this type.
|
14
|
+
# Supported values are `Object`, `Array`, `Hash` and `String`.
|
14
15
|
# @param strict [Boolean] If strict mode should be used.
|
15
16
|
#
|
16
17
|
# @return [Object, nil] The parsed object.
|
@@ -19,13 +20,14 @@ module NestedText
|
|
19
20
|
def self.load(ntstring, top_class: Object, strict: false)
|
20
21
|
raise Errors::WrongInputTypeError.new([String], ntstring) unless ntstring.nil? || ntstring.is_a?(String)
|
21
22
|
|
22
|
-
Parser.new(StringIO.new(ntstring), top_class, strict:
|
23
|
+
Parser.new(StringIO.new(ntstring), top_class, strict:).parse
|
23
24
|
end
|
24
25
|
|
25
26
|
# Decode a NestedText stored in a given file.
|
26
27
|
#
|
27
28
|
# @param filename [String] The file path to read NestedText to decode from.
|
28
|
-
# @param top_class [String] Force the top level returned object to be of this type.
|
29
|
+
# @param top_class [String] Force the top level returned object to be of this type.
|
30
|
+
# Supported values are `Object`, `Array`, `Hash` and `String`.
|
29
31
|
# @param strict [Boolean] If strict mode should be used.
|
30
32
|
#
|
31
33
|
# @return [Object, nil] The parsed object.
|
@@ -36,8 +38,8 @@ module NestedText
|
|
36
38
|
raise Errors::WrongInputTypeError.new([String], filename) unless !filename.nil? && filename.is_a?(String)
|
37
39
|
|
38
40
|
# Open explicitly in text mode to detect \r as line ending.
|
39
|
-
File.open(filename,
|
40
|
-
Parser.new(file, top_class, strict:
|
41
|
+
File.open(filename, 'rt') do |file|
|
42
|
+
Parser.new(file, top_class, strict:).parse
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
data/lib/nestedtext/dumper.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nestedtext/core_ext_internal'
|
2
4
|
|
3
5
|
module NestedText
|
4
6
|
using NestedText.const_get(:CoreExtInternal)
|
5
7
|
|
6
8
|
# Dumping with recursive DFS traversal of the object references.
|
7
|
-
class Dumper
|
9
|
+
class Dumper # rubocop:disable Metrics/ClassLength
|
8
10
|
def initialize(indentation, strict)
|
9
11
|
@indentation = indentation
|
10
12
|
@strict = strict
|
@@ -18,31 +20,31 @@ module NestedText
|
|
18
20
|
dump_any obj
|
19
21
|
end
|
20
22
|
|
21
|
-
private
|
22
|
-
|
23
23
|
def self.add_prefix(prefix, target)
|
24
24
|
if target.empty? || target[0] == "\n"
|
25
|
-
target
|
25
|
+
"#{prefix}#{target}"
|
26
26
|
else
|
27
|
-
|
27
|
+
"#{prefix} #{target}"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.multiline_key?(key)
|
32
|
-
syntax1 =
|
33
|
-
syntax2 =
|
32
|
+
syntax1 = '{[#'
|
33
|
+
syntax2 = ':->'
|
34
34
|
|
35
35
|
key.empty? ||
|
36
36
|
key != key.strip ||
|
37
37
|
key.include?("\n") ||
|
38
|
-
key.include?(
|
38
|
+
key.include?(': ') ||
|
39
39
|
syntax1.include?(key.lstrip[0]) ||
|
40
|
-
syntax2.include?(key.lstrip[0]) && key.lstrip[1] ==
|
40
|
+
(syntax2.include?(key.lstrip[0]) && key.lstrip[1] == ' ')
|
41
41
|
end
|
42
42
|
|
43
|
+
private
|
44
|
+
|
43
45
|
def convert_key(key)
|
44
46
|
if key.nil?
|
45
|
-
|
47
|
+
''
|
46
48
|
elsif key.is_a? String
|
47
49
|
key.normalize_line_endings
|
48
50
|
elsif !@strict
|
@@ -52,10 +54,11 @@ module NestedText
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
def indent(target)
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
def indent(target, depth)
|
58
|
+
return target unless depth.positive?
|
59
|
+
|
60
|
+
indentstr = ' ' * @indentation
|
61
|
+
"\n#{target.lines.map { |line| indentstr + line }.join}"
|
59
62
|
end
|
60
63
|
|
61
64
|
def trace_cycles(obj)
|
@@ -81,77 +84,79 @@ module NestedText
|
|
81
84
|
def dump_any(obj, depth: 0, **kwargs)
|
82
85
|
trace_cycles(obj) do
|
83
86
|
case obj
|
84
|
-
when Hash then dump_hash(obj, depth
|
85
|
-
when Array then dump_array(obj, depth
|
86
|
-
when String then dump_string(obj, depth
|
87
|
+
when Hash then dump_hash(obj, depth:, **kwargs)
|
88
|
+
when Array then dump_array(obj, depth:, **kwargs)
|
89
|
+
when String then dump_string(obj, depth:, **kwargs)
|
87
90
|
when nil
|
88
|
-
@strict ?
|
91
|
+
@strict ? '' : dump_custom_class(nil, depth:, **kwargs)
|
89
92
|
else
|
90
|
-
dump_custom_class(obj, depth
|
93
|
+
dump_custom_class(obj, depth:, **kwargs)
|
91
94
|
end
|
92
95
|
end
|
93
96
|
end
|
94
97
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
key = convert_key(key)
|
102
|
-
|
103
|
-
if Dumper.multiline_key?(key)
|
104
|
-
key_lines = key.empty? ? [""] : key.lines
|
105
|
-
key_lines << "" if key_lines[-1][-1] =~ /\n|\r/
|
106
|
-
rep_key = key_lines.map { |line| Dumper.add_prefix(":", line) }.join
|
107
|
-
force_multiline = value.is_a? String
|
108
|
-
rep_value = dump_any(value, depth: depth + 1, force_multiline: force_multiline, **kwargs)
|
109
|
-
else
|
110
|
-
rep_key = "#{key}:"
|
111
|
-
rep_value = dump_any(value, depth: depth + 1, **kwargs)
|
112
|
-
rep_key += " " unless rep_value.empty? || rep_value.include?("\n")
|
113
|
-
end
|
114
|
-
"#{rep_key}#{rep_value}"
|
115
|
-
end
|
116
|
-
end.join("\n")
|
117
|
-
end
|
118
|
-
indent(rep) if depth > 0
|
119
|
-
rep
|
98
|
+
def dump_hash_key_multiline(key, value, depth, **kwargs)
|
99
|
+
key_lines = key.empty? ? [''] : key.lines
|
100
|
+
key_lines << '' if key_lines[-1][-1] =~ /\n|\r/
|
101
|
+
rep_key = key_lines.map { |line| Dumper.add_prefix(':', line) }.join
|
102
|
+
rep_value = dump_any(value, depth: depth + 1, force_multiline: value.is_a?(String), **kwargs)
|
103
|
+
[rep_key, rep_value].join
|
120
104
|
end
|
121
105
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
125
|
-
|
106
|
+
def dump_hash_key(key, value, depth, **kwargs)
|
107
|
+
rep_key = "#{key}:"
|
108
|
+
rep_value = dump_any(value, depth: depth + 1, **kwargs)
|
109
|
+
rep_key += ' ' unless rep_value.empty? || rep_value.include?("\n")
|
110
|
+
[rep_key, rep_value].join
|
111
|
+
end
|
112
|
+
|
113
|
+
def dump_hash_items(hash, depth, **kwargs)
|
114
|
+
hash.map do |key, value|
|
115
|
+
trace_keys(key) do
|
116
|
+
key = convert_key(key)
|
117
|
+
if Dumper.multiline_key?(key)
|
118
|
+
dump_hash_key_multiline(key, value, depth, **kwargs)
|
119
|
+
else
|
120
|
+
dump_hash_key(key, value, depth, **kwargs)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end.join("\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
def dump_hash(hash, depth: 0, **kwargs)
|
127
|
+
rep = hash.empty? ? '{}' : dump_hash_items(hash, depth, **kwargs)
|
128
|
+
indent(rep, depth)
|
129
|
+
end
|
130
|
+
|
131
|
+
def dump_array(array, depth: 0, **kwargs)
|
132
|
+
rep = if array.empty?
|
133
|
+
'[]'
|
126
134
|
else
|
127
|
-
|
135
|
+
array.each_with_index.map do |e, i|
|
128
136
|
trace_keys(i) do
|
129
|
-
|
130
|
-
Dumper.add_prefix("-", e_rep)
|
137
|
+
Dumper.add_prefix('-', dump_any(e, depth: depth + 1, **kwargs))
|
131
138
|
end
|
132
139
|
end.join("\n")
|
133
140
|
end
|
134
141
|
|
135
|
-
indent(rep
|
136
|
-
rep
|
142
|
+
indent(rep, depth)
|
137
143
|
end
|
138
144
|
|
139
|
-
def
|
140
|
-
|
141
|
-
lines
|
142
|
-
lines
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
145
|
+
def prefix_lines(lines, depth, multiline)
|
146
|
+
lines = lines.map { |line| Dumper.add_prefix('>', line) } if multiline || depth.zero?
|
147
|
+
lines << '>' if lines.empty? && (depth.zero? || multiline)
|
148
|
+
lines
|
149
|
+
end
|
150
|
+
|
151
|
+
def dump_string(string, depth: 0, force_multiline: false)
|
152
|
+
lines = string.normalize_line_endings.lines
|
153
|
+
lines << '' if !lines.empty? && lines.last[-1] == "\n"
|
154
|
+
multiline = lines.length > 1 || force_multiline
|
148
155
|
|
149
|
-
|
150
|
-
lines << ">" if lines.empty? && (depth == 0 || force_multiline)
|
156
|
+
lines = prefix_lines(lines, depth, multiline)
|
151
157
|
|
152
158
|
rep = lines.join.chomp
|
153
|
-
indent(rep
|
154
|
-
rep
|
159
|
+
multiline ? indent(rep, depth) : rep
|
155
160
|
end
|
156
161
|
|
157
162
|
def dump_custom_class(obj, **kwargs)
|
@@ -160,8 +165,8 @@ module NestedText
|
|
160
165
|
if obj.is_a? Symbol
|
161
166
|
dump_string(obj.id2name, **kwargs)
|
162
167
|
elsif obj.respond_to? :encode_nt_with
|
163
|
-
class_name = obj.nil? ?
|
164
|
-
enc = { CUSTOM_CLASS_KEY => class_name,
|
168
|
+
class_name = obj.nil? ? 'nil' : obj.class.name
|
169
|
+
enc = { CUSTOM_CLASS_KEY => class_name, 'data' => obj.encode_nt_with }
|
165
170
|
dump_any(enc, **kwargs)
|
166
171
|
else
|
167
172
|
dump_string(obj.to_s, **kwargs)
|
data/lib/nestedtext/encode.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'nestedtext/dumper'
|
4
|
+
require 'nestedtext/errors_internal'
|
5
5
|
|
6
6
|
module NestedText
|
7
7
|
# Encode a Ruby object to a NestedText string.
|
8
8
|
#
|
9
9
|
# @param obj [Object] The object to encode to NestedText.
|
10
|
-
# @param io [IO] Additionally write the output to this IO object.
|
10
|
+
# @param io [IO] Additionally write the output to this IO object.
|
11
|
+
# The caller is responsible for that the IO is closed after the call to this method.
|
11
12
|
# @param indentation [Integer] The indentation of nested levels to use.
|
12
13
|
# @param strict [Boolean] If strict mode should be used.
|
13
14
|
#
|
14
|
-
# @return A String containing NestedText data.
|
15
|
+
# @return [String, nil] A String containing NestedText data, or nil when obj is represented as empty.
|
15
16
|
# @raise [NestedText::Error] if anything went wrong.
|
16
17
|
# @raise Whatever the `io` can raise, if supplied.
|
17
18
|
def self.dump(obj, io: nil, indentation: 4, strict: false)
|
18
|
-
raise Errors::DumpBadIOError, io unless io.nil? || io.respond_to?(:write) && io.respond_to?(:fsync)
|
19
|
+
raise Errors::DumpBadIOError, io unless io.nil? || (io.respond_to?(:write) && io.respond_to?(:fsync))
|
19
20
|
|
20
21
|
dumper = Dumper.new(indentation, strict)
|
21
22
|
result = dumper.dump obj
|
@@ -41,7 +42,7 @@ module NestedText
|
|
41
42
|
def self.dump_file(obj, filename, **kwargs)
|
42
43
|
raise Errors::DumpFileBadPathError, filename unless filename.is_a? String
|
43
44
|
|
44
|
-
File.open(filename,
|
45
|
+
File.open(filename, 'wt') do |file|
|
45
46
|
dump(obj, io: file, **kwargs)
|
46
47
|
end
|
47
48
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nestedtext/dumper'
|
2
4
|
|
3
5
|
module NestedText
|
4
6
|
# A mixin for Custom Classes to get the to_nt shortcut.
|
5
|
-
|
6
|
-
module NTEncodeMixin
|
7
|
+
module ToNTMixin
|
7
8
|
# Encode this object to a NestedText string.
|
8
9
|
#
|
9
10
|
# This method takes the same named arguments as {NestedText.dump}.
|