nestedtext 2.1.0 → 3.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 +12 -1
- data/README.md +49 -22
- data/lib/nestedtext/core_ext.rb +6 -5
- data/lib/nestedtext/decode.rb +21 -1
- data/lib/nestedtext/dumper.rb +0 -1
- data/lib/nestedtext/encode.rb +20 -7
- data/lib/nestedtext/encode_helpers.rb +6 -8
- data/lib/nestedtext/error.rb +8 -0
- data/lib/nestedtext/{errors.rb → errors_internal.rb} +1 -5
- data/lib/nestedtext/parser.rb +1 -2
- data/lib/nestedtext/scanners.rb +1 -1
- data/lib/nestedtext/version.rb +2 -1
- data/lib/nestedtext.rb +9 -2
- 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: bfafdf3e9638459777da2f7209954955473758103c72533b58a66cc23f4020e3
|
4
|
+
data.tar.gz: 400fd879811f4d09c193da219ffa0ff61853ee0e51baac386c58b7016dfbe354
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 708025814b4038b1b5c6eea70378762e1155ae73e933cc902a17d26d4ce3efbb2a5b52f7d535c385818e34484fe12278f981c253469d80a875e97aa8f25b20c1
|
7
|
+
data.tar.gz: fe87505719301bf79a71cdef1c9d89d71f9058318f5f59f1305ac79b0b69007b79976d6e288a4846824c6cc89323021b4b29df56b8f14f534cd59906d55b0843
|
data/CHANGELOG.md
CHANGED
@@ -6,7 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
-
## [
|
9
|
+
## [3.0.0] - 2022-01-27
|
10
|
+
### Added
|
11
|
+
- API documentation generated with rdoc.
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- Removed leaked `NT_MIXIN` constant in core extensions.
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
- **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 CustomObjects and calling the method on the array.
|
18
|
+
- Internal clean-up and simplifications on helper classes and methods.
|
19
|
+
|
20
|
+
## [2.1.0] - 2022-01-27
|
10
21
|
### Changed
|
11
22
|
- Slim down Gem by using include instead of block list.
|
12
23
|
|
data/README.md
CHANGED
@@ -3,13 +3,13 @@
|
|
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
4
|
[![Documentation](https://img.shields.io/badge/docs-API-informational?logo=readthedocs&logoColor=violet)](https://www.rubydoc.info/gems/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
|
-
[![Official Tests](https://img.shields.io/badge
|
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)
|
8
8
|
[![GitHub Actions: Continuous Deployment](https://github.com/erikw/nestedtext-ruby/actions/workflows/cd.yml/badge.svg)](https://github.com/erikw/nestedtext-ruby/actions/workflows/cd.yml)
|
9
9
|
[![GitHub Actions: CodeQL Analysis](https://github.com/erikw/nestedtext-ruby/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/erikw/nestedtext-ruby/actions/workflows/codeql-analysis.yml)
|
10
10
|
[![Code Climate Maintainability](https://api.codeclimate.com/v1/badges/8409b6cdc3dc62a33f6f/maintainability)](https://codeclimate.com/github/erikw/nestedtext-ruby/maintainability)
|
11
11
|
[![Code Climate Test Coverage](https://api.codeclimate.com/v1/badges/8409b6cdc3dc62a33f6f/test_coverage)](https://codeclimate.com/github/erikw/nestedtext-ruby/test_coverage)
|
12
|
-
[![SLOC](https://img.shields.io/tokei/lines/github/erikw/nestedtext-ruby)](#)
|
12
|
+
[![SLOC](https://img.shields.io/tokei/lines/github/erikw/nestedtext-ruby?logo=codefactor&logoColor=lightgrey)](#)
|
13
13
|
[![License](https://img.shields.io/github/license/erikw/nestedtext-ruby?color=informational)](LICENSE.txt)
|
14
14
|
[![OSS Lifecycle](https://img.shields.io/osslifecycle/erikw/nestedtext-ruby)](https://github.com/Netflix/osstracker)
|
15
15
|
|
@@ -56,7 +56,7 @@ vice president:
|
|
56
56
|
See the [language introduction](https://nestedtext.org/en/latest/basic_syntax.html) for more details.
|
57
57
|
|
58
58
|
# Usage
|
59
|
-
The full documentation can be found at [
|
59
|
+
The full API documentation can be found at [**rubydocs.info**](https://www.rubydoc.info/gems/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).
|
60
60
|
|
61
61
|
## Decoding (reading NT)
|
62
62
|
This is how you can decode NestedText from a string or directly from a file (`*.nt`) to Ruby object instances:
|
@@ -78,17 +78,6 @@ key1: value1
|
|
78
78
|
key2: value2
|
79
79
|
```
|
80
80
|
|
81
|
-
The NestedText types maps like this to Ruby:
|
82
|
-
|
83
|
-
[NestedText](https://nestedtext.org/en/latest/basic_syntax.html) | Ruby | Comment
|
84
|
-
---|---|---
|
85
|
-
`String` | `String` |
|
86
|
-
`List` | `Array` |
|
87
|
-
`Dictionary`| `Hash` |
|
88
|
-
`String` | `Symbol` | when `strict: true`, otherwise Ruby Symbols are encoded as Custom Class (see below).
|
89
|
-
*empty* | `nil` | when `strict: true`, otherwise as Custom Class. How empty strings and nil are handled depends on where it is used. This library follows how the official implementation does it.
|
90
|
-
|
91
|
-
|
92
81
|
Thus you must know what you're parsing, or test what you decoded.
|
93
82
|
|
94
83
|
### Explicit Top Level Type
|
@@ -119,7 +108,6 @@ ntstr = NestedText::dump(data)
|
|
119
108
|
NestedText::dump_file(data, "path/to/data.nt")
|
120
109
|
```
|
121
110
|
|
122
|
-
|
123
111
|
### `#to_nt` Convenience
|
124
112
|
To make it more convenient, the Ruby Core is extended with a `#to_nt` method on the supported types that will dump a String of the data structure. Here's an IRB session showing how it works:
|
125
113
|
|
@@ -142,9 +130,46 @@ k3:
|
|
142
130
|
- list
|
143
131
|
```
|
144
132
|
|
133
|
+
## Types
|
134
|
+
Ruby classes maps like this to NestedText types:
|
135
|
+
Ruby | [NestedText](https://nestedtext.org/en/latest/basic_syntax.html)
|
136
|
+
---|---
|
137
|
+
`String` |`String`
|
138
|
+
`Array` |`List`
|
139
|
+
`Hash` |`Dictionary`
|
140
|
+
|
141
|
+
|
142
|
+
### Strict Mode
|
143
|
+
The strict mode determines how classes other than the basic types `String`, `Array` and `Hash` are handled during encoding and decoding. By **default** strict mode is turned **off**.
|
144
|
+
|
145
|
+
With `strict: true`
|
146
|
+
Ruby | NestedText | Comment
|
147
|
+
---|---|---
|
148
|
+
`nil` |*empty* | (1.)
|
149
|
+
`Symbol` |`String` | Raises `NestedText::Error`
|
150
|
+
Other Class | -- | Raises `NestedText::Error`
|
151
|
+
|
152
|
+
|
153
|
+
With `strict: false`
|
154
|
+
Ruby | NestedText | Comment
|
155
|
+
---|---|---
|
156
|
+
`nil` | *Custom Class Encoding* | (1.)
|
157
|
+
`Symbol` | `String` |
|
158
|
+
Custom Class | *Custom Class Encoding* | If the [Custom Class](#custom-classes-serialization) implements `#encode_nt_with` (2.)
|
159
|
+
Other Class | String | `#to_s` will be called if there is no `#encode_nt_with`
|
160
|
+
|
161
|
+
|
162
|
+
* (1.) How empty strings and nil are handled depends on where it is used. This library follows how the official implementation does it.
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
|
145
168
|
## Custom Classes Serialization
|
146
169
|
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.
|
147
170
|
|
171
|
+
A class implementing `#encode_nt_with` is refered to as `Custom Class` in this document.
|
172
|
+
|
148
173
|
```ruby
|
149
174
|
class Apple
|
150
175
|
def initialize(type, weight)
|
@@ -191,7 +216,6 @@ data:
|
|
191
216
|
- granny smith
|
192
217
|
- 12
|
193
218
|
```
|
194
|
-
Note that the special key to denote the class name is subject to change in future versions and you **must not** rely on it.
|
195
219
|
|
196
220
|
If you want to add some more super powers to your custom class, you can add the `#to_nt` shortcut by including the `NTEncodeMixin`:
|
197
221
|
```ruby
|
@@ -204,13 +228,16 @@ Apple.new("granny smith", 12).to_nt
|
|
204
228
|
```
|
205
229
|
|
206
230
|
|
207
|
-
**
|
208
|
-
|
209
|
-
|
210
|
-
|
231
|
+
**Important notes**:
|
232
|
+
* The special key to denote the class name is subject to change in future versions and you **must not** rely on it.
|
233
|
+
* Custom Classes **can not be a key** in a Hash. Trying to do this will raise an Error.
|
234
|
+
* When deserializing a custom class, this custom class must be available when calling the `#dump*` methods e.g.
|
235
|
+
```ruby
|
236
|
+
require 'nestedtext'
|
237
|
+
require_relative 'apple' # This is needed if Apple is defined in apple.rb and not in this scope already.
|
211
238
|
|
212
|
-
NestedText::load_file('path/to/apple_dump.nt')
|
213
|
-
```
|
239
|
+
NestedText::load_file('path/to/apple_dump.nt')
|
240
|
+
```
|
214
241
|
|
215
242
|
See [encode_custom_classes_test.rb](test/nestedtext/encode_custom_classes_test.rb) for more real working examples.
|
216
243
|
|
data/lib/nestedtext/core_ext.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
require "nestedtext/encode_helpers"
|
2
2
|
|
3
|
+
# Extension of Ruby core types with the NestedText::NTEncodeMixin.
|
4
|
+
#
|
3
5
|
# TODO: add encoding of more Ruby native classes like Integer, Float etc plus commons like Set,....? Not covered in NestedText language.
|
4
6
|
# Or leave this to a schema validator 3rd party plugin maybe? And replace my custom class decoding (and also encoding?)?
|
5
7
|
# Or both: add encoding/decoding of more native classes, and allow decoding + applying a schema with 3rd party.
|
6
8
|
# Or encourage using Marshal from core?
|
7
9
|
|
8
|
-
|
9
|
-
class
|
10
|
-
class
|
11
|
-
class Hash include NT_MIXIN end
|
10
|
+
class String include NestedText::NTEncodeMixin; end
|
11
|
+
class Array include NestedText::NTEncodeMixin; end
|
12
|
+
class Hash include NestedText::NTEncodeMixin; end
|
12
13
|
|
13
14
|
class NilClass
|
14
|
-
include
|
15
|
+
include NestedText::NTEncodeMixin
|
15
16
|
|
16
17
|
def self.nt_create(_data) = nil
|
17
18
|
|
data/lib/nestedtext/decode.rb
CHANGED
@@ -1,18 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "nestedtext/parser"
|
4
|
-
require "nestedtext/
|
4
|
+
require "nestedtext/errors_internal"
|
5
5
|
|
6
6
|
require "logger"
|
7
7
|
require "stringio"
|
8
8
|
|
9
9
|
module NestedText
|
10
|
+
# Decode a NestedText string to Ruby objects.
|
11
|
+
#
|
12
|
+
# [ntstring] The string containing NestedText to be decoded.
|
13
|
+
# [top_class] Force the top level returned object to be of this type. Supported values are +Object+, +Array+, +Hash+ and +String+. Default is +Object+.
|
14
|
+
# [strict] If strict mode should be used. +true+ or +false+. Default is +false+
|
15
|
+
#
|
16
|
+
# Returns the parsed object.
|
17
|
+
#
|
18
|
+
# Raises NestedText::Error if anything went wrong.
|
10
19
|
def self.load(ntstring, top_class: Object, strict: false)
|
11
20
|
raise Errors::WrongInputTypeError.new([String], ntstring) unless ntstring.nil? || ntstring.is_a?(String)
|
12
21
|
|
13
22
|
Parser.new(StringIO.new(ntstring), top_class, strict: strict).parse
|
14
23
|
end
|
15
24
|
|
25
|
+
# Decode a NestedText stored in a given file.
|
26
|
+
|
27
|
+
# [filename] The file path to read NestedText to decode from.
|
28
|
+
# [top_class] Force the top level returned object to be of this type. Supported values are +Object+, +Array+, +Hash+ and +String+. Default is +Object+.
|
29
|
+
# [strict] If strict mode should be used. +true+ or +false+. Default is +false+
|
30
|
+
#
|
31
|
+
# Returns the parsed object.
|
32
|
+
#
|
33
|
+
# Raises NestedText::Error if anything went wrong.
|
34
|
+
#
|
35
|
+
# Raises +IOError+ on issue opening +filename+ for reading in text mode.
|
16
36
|
def self.load_file(filename, top_class: Object, strict: false)
|
17
37
|
raise Errors::WrongInputTypeError.new([String], filename) unless !filename.nil? && filename.is_a?(String)
|
18
38
|
|
data/lib/nestedtext/dumper.rb
CHANGED
data/lib/nestedtext/encode.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "nestedtext/errors"
|
4
3
|
require "nestedtext/dumper"
|
5
|
-
|
6
|
-
# Model after JSON
|
7
|
-
# NestedText.dump(obj, io=nil) => dumps to string, or to IO if given
|
8
|
-
# NestedText.dump_file(obj, filename)
|
4
|
+
require "nestedtext/errors_internal"
|
9
5
|
|
10
6
|
module NestedText
|
7
|
+
# Encode a Ruby object to a NestedText string.
|
8
|
+
#
|
9
|
+
# [obj] The object to encode to NestedText.
|
10
|
+
# [io] Additionally write the output to this IO object. The caller is responsible for that the IO is closed after the call to this method.
|
11
|
+
# [indentation] The indentation of nested levels to use.
|
12
|
+
# [strict] If strict mode should be used. +true+ or +false+. Default is +false+
|
13
|
+
#
|
14
|
+
# Returns a String containing NestedText data.
|
15
|
+
#
|
16
|
+
# Raises NestedText::Error if anything went wrong.
|
17
|
+
#
|
18
|
+
# Raises whatever the passed +io+ can raise.
|
11
19
|
def self.dump(obj, io: nil, indentation: 4, strict: false)
|
12
|
-
# io - additionaly write the out result to IO and still return result.
|
13
|
-
|
14
20
|
raise Errors::DumpBadIOError, io unless io.nil? || io.respond_to?(:write) && io.respond_to?(:fsync)
|
15
21
|
|
16
22
|
dumper = Dumper.new(indentation, strict)
|
@@ -22,6 +28,13 @@ module NestedText
|
|
22
28
|
dumper.dump obj
|
23
29
|
end
|
24
30
|
|
31
|
+
# Encode a Ruby object to a NestedText file.
|
32
|
+
#
|
33
|
+
# [filename] The file path to write the NestedText result to. The conventional file extension is +.nt+.
|
34
|
+
#
|
35
|
+
# Raises +IOError+ on issues opening the +filename+ for writing in text mode.
|
36
|
+
#
|
37
|
+
# Apart from +filename+, this method behaves exactly like dump (taking same arguments, returning and raising the same values).
|
25
38
|
def self.dump_file(obj, filename, **kwargs)
|
26
39
|
raise Errors::DumpFileBadPathError, filename unless filename.is_a? String
|
27
40
|
|
@@ -1,16 +1,14 @@
|
|
1
1
|
require "nestedtext/dumper"
|
2
2
|
|
3
3
|
module NestedText
|
4
|
-
|
5
|
-
|
6
|
-
NestedText.dump(self, strict: true, **kwargs)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
private_constant :NTEncodeStrictMixin
|
10
|
-
|
4
|
+
# A mixin for Custom Classes to get the to_nt shortcut.
|
5
|
+
# TODO rename to: ToNTMixin
|
11
6
|
module NTEncodeMixin
|
7
|
+
# Encode this object to a NestedText string.
|
8
|
+
#
|
9
|
+
# This method takes the same arguments as NestedText::dump.
|
12
10
|
def to_nt(**kwargs)
|
13
|
-
NestedText.dump(self, **kwargs)
|
11
|
+
NestedText.dump(self, strict: false, **kwargs)
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -4,13 +4,9 @@ require "word_wrap"
|
|
4
4
|
require "word_wrap/core_ext"
|
5
5
|
|
6
6
|
require "nestedtext/constants"
|
7
|
+
require "nestedtext/error"
|
7
8
|
|
8
9
|
module NestedText
|
9
|
-
# Top level error for users to rescue on.
|
10
|
-
class Error < StandardError
|
11
|
-
private_class_method :new
|
12
|
-
end
|
13
|
-
|
14
10
|
module Errors
|
15
11
|
class InternalError < Error
|
16
12
|
public_class_method :new # Prevent users from instansiating.
|
data/lib/nestedtext/parser.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "stringio"
|
4
4
|
|
5
|
-
require "nestedtext/
|
5
|
+
require "nestedtext/errors_internal"
|
6
6
|
require "nestedtext/scanners"
|
7
7
|
require "nestedtext/constants"
|
8
8
|
|
@@ -15,7 +15,6 @@ module NestedText
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# TODO: document that caller is responsible for closing IO after done with Parser.
|
19
18
|
def initialize(io, top_class, strict: false)
|
20
19
|
assert_valid_input_type io
|
21
20
|
Parser.assert_valid_top_level_type(top_class)
|
data/lib/nestedtext/scanners.rb
CHANGED
data/lib/nestedtext/version.rb
CHANGED
data/lib/nestedtext.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "nestedtext/encode"
|
4
|
-
require_relative "nestedtext/decode"
|
5
3
|
require_relative "nestedtext/core_ext"
|
4
|
+
require_relative "nestedtext/decode"
|
5
|
+
require_relative "nestedtext/encode"
|
6
|
+
require_relative "nestedtext/encode_helpers"
|
7
|
+
require_relative "nestedtext/error"
|
6
8
|
require_relative "nestedtext/version"
|
7
9
|
|
10
|
+
##
|
11
|
+
# = NestedText
|
12
|
+
# The main module in this library to use.
|
13
|
+
#
|
14
|
+
# See README.md for documentation on Types, Strict Mode and Custom Classes.
|
8
15
|
module NestedText
|
9
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nestedtext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Westrup
|
@@ -62,7 +62,8 @@ files:
|
|
62
62
|
- lib/nestedtext/dumper.rb
|
63
63
|
- lib/nestedtext/encode.rb
|
64
64
|
- lib/nestedtext/encode_helpers.rb
|
65
|
-
- lib/nestedtext/
|
65
|
+
- lib/nestedtext/error.rb
|
66
|
+
- lib/nestedtext/errors_internal.rb
|
66
67
|
- lib/nestedtext/parser.rb
|
67
68
|
- lib/nestedtext/scanners.rb
|
68
69
|
- lib/nestedtext/version.rb
|