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