nestedtext 2.1.0 → 3.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 830cd05483344cec4a5d4132a7b6a373c81e6e48494dbf22dd29ff5ff5985599
4
- data.tar.gz: 8ff4109630f482c63ddc9aac99de1a34f3dc3977c12af5a94eae266ad8a8a7d0
3
+ metadata.gz: bfafdf3e9638459777da2f7209954955473758103c72533b58a66cc23f4020e3
4
+ data.tar.gz: 400fd879811f4d09c193da219ffa0ff61853ee0e51baac386c58b7016dfbe354
5
5
  SHA512:
6
- metadata.gz: 2e10ec7ae7e7d48c5a708be79803e8048322e474301d3e499c4bdee33199e7e99c4b1d3c8de2fd9ad6055d12332745c93c108d178ff829bdf1ddee1fad243d2a
7
- data.tar.gz: 247bd8a03e0c4433f10811523b1e7da9b2ac747f98c1d735a1a7efdeef23b6b8b38be360a88c82acdedba66c90f177102a04ecd85777c77cac9f9a092a3f86e2
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
- ## [2.1.0] - date
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/%F0%9F%8F%81%20Official%20Tests-Passing-success)](https://github.com/KenKundert/nestedtext_tests/tree/585e95a73d94ac1f48e71a154e2db0ab67cf30fa)
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 [TODO](TODO). 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).
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
- **NOTE** that when deserializing a custom class, this custom class must be available when calling the `#dump*` methods e.g.
208
- ```ruby
209
- require 'nestedtext'
210
- require_relative 'apple' # This is needed if Apple is defined in apple.rb and not in this scope already.
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
 
@@ -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
- NT_MIXIN = NestedText.const_get(:NTEncodeStrictMixin)
9
- class String include NT_MIXIN end
10
- class Array include NT_MIXIN end
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 NT_MIXIN
15
+ include NestedText::NTEncodeMixin
15
16
 
16
17
  def self.nt_create(_data) = nil
17
18
 
@@ -1,18 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "nestedtext/parser"
4
- require "nestedtext/errors"
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
 
@@ -92,7 +92,6 @@ module NestedText
92
92
  end
93
93
  end
94
94
 
95
- # TODO: document that @strict==false allows to_s on key object
96
95
  def dump_hash(obj, depth: 0, **kwargs)
97
96
  rep = if obj.empty?
98
97
  "{}"
@@ -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
- module NTEncodeStrictMixin
5
- def to_nt(**kwargs)
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
@@ -0,0 +1,8 @@
1
+ module NestedText
2
+ # Top level error to rescue on.
3
+ #
4
+ # +Error+ is a subclass of +StandardError+ and behaves as expected e.g. +#message+.
5
+ class Error < StandardError
6
+ private_class_method :new
7
+ end
8
+ 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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "stringio"
4
4
 
5
- require "nestedtext/errors"
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)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "nestedtext/errors"
3
+ require "nestedtext/errors_internal"
4
4
 
5
5
  module NestedText
6
6
  class LineScanner
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NestedText
4
- VERSION = "2.1.0"
4
+ # The version of this library.
5
+ VERSION = "3.0.0"
5
6
  end
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: 2.1.0
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/errors.rb
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