rubytree 2.2.2 → 2.2.3
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 +4 -4
- data/Gemfile.lock +59 -24
- data/History.md +6 -0
- data/README.md +5 -5
- data/Rakefile +45 -2
- data/examples/example_basic.rb +1 -1
- data/lib/tree/utils/json_converter.rb +102 -11
- data/lib/tree/version.rb +1 -1
- data/test/test_binarytree.rb +13 -0
- data/test/test_subclassed_node.rb +16 -0
- data/test/test_tree.rb +40 -12
- metadata +42 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 26db44620b76570b7b952dddc9eb36d2b1f0e885ba324953c9c8a9563eb47be6
|
|
4
|
+
data.tar.gz: c43b65542c8a14fe5f8230e00c041127451526dcabbe009485ea8e6f11489619
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2dff529a36b6bbae3ce9be8c05af13d68914860455ab40d4f9eeedb2b3031cc31f716637d19c38407bfdca2538ea06f6c5c17ab439ea07ff91c60ec99bf2722
|
|
7
|
+
data.tar.gz: 17657bdcbc22cc6bf7e48dfe621192c2d2137b2435e32fd013ecc8eaf7b5956dcf73b4cf99bf5942ac775dbb63d5fd4595cc72ea7f5477d3922848b022c608d4
|
data/Gemfile.lock
CHANGED
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rubytree (2.2.
|
|
5
|
-
json (
|
|
4
|
+
rubytree (2.2.3)
|
|
5
|
+
json (>= 2.21.2, < 4)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
-
ast (2.4.
|
|
10
|
+
ast (2.4.3)
|
|
11
|
+
awesome_bot (1.20.0)
|
|
12
|
+
parallel (= 1.20.1)
|
|
13
|
+
bundler-audit (0.9.3)
|
|
14
|
+
bundler (>= 1.2.0)
|
|
15
|
+
thor (~> 1.0)
|
|
16
|
+
chef-utils (19.3.15)
|
|
17
|
+
concurrent-ruby
|
|
18
|
+
concurrent-ruby (1.3.8)
|
|
11
19
|
date (3.4.1)
|
|
12
20
|
diff-lcs (1.5.1)
|
|
13
21
|
docile (1.4.1)
|
|
14
|
-
json (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
parser (
|
|
22
|
+
json (3.0.2)
|
|
23
|
+
kramdown (2.5.2)
|
|
24
|
+
rexml (>= 3.4.4)
|
|
25
|
+
kramdown-parser-gfm (1.1.0)
|
|
26
|
+
kramdown (~> 2.0)
|
|
27
|
+
language_server-protocol (3.17.0.6)
|
|
28
|
+
lint_roller (1.1.0)
|
|
29
|
+
mdl (0.14.0)
|
|
30
|
+
kramdown (~> 2.3)
|
|
31
|
+
kramdown-parser-gfm (~> 1.1)
|
|
32
|
+
mixlib-cli (~> 2.1, >= 2.1.1)
|
|
33
|
+
mixlib-config (>= 2.2.1, < 4)
|
|
34
|
+
mixlib-shellout
|
|
35
|
+
mixlib-cli (2.1.8)
|
|
36
|
+
mixlib-config (3.0.27)
|
|
37
|
+
tomlrb
|
|
38
|
+
mixlib-shellout (3.3.8)
|
|
39
|
+
chef-utils
|
|
40
|
+
parallel (1.20.1)
|
|
41
|
+
parser (3.3.12.0)
|
|
18
42
|
ast (~> 2.4.1)
|
|
19
43
|
racc
|
|
20
44
|
power_assert (2.0.4)
|
|
45
|
+
prism (1.9.0)
|
|
21
46
|
psych (5.2.2)
|
|
22
47
|
date
|
|
23
48
|
stringio
|
|
@@ -26,7 +51,8 @@ GEM
|
|
|
26
51
|
rake (13.2.1)
|
|
27
52
|
rdoc (6.10.0)
|
|
28
53
|
psych (>= 4.0.0)
|
|
29
|
-
regexp_parser (2.
|
|
54
|
+
regexp_parser (2.13.1)
|
|
55
|
+
rexml (3.4.4)
|
|
30
56
|
rspec (3.13.0)
|
|
31
57
|
rspec-core (~> 3.13.0)
|
|
32
58
|
rspec-expectations (~> 3.13.0)
|
|
@@ -43,22 +69,27 @@ GEM
|
|
|
43
69
|
rtags (0.97)
|
|
44
70
|
rtagstask (0.0.4)
|
|
45
71
|
rtags (> 0.0.0)
|
|
46
|
-
rubocop (1.
|
|
47
|
-
json (
|
|
48
|
-
language_server-protocol (
|
|
49
|
-
|
|
72
|
+
rubocop (1.91.0)
|
|
73
|
+
json (>= 2.3)
|
|
74
|
+
language_server-protocol (~> 3.17.0.2)
|
|
75
|
+
lint_roller (~> 1.1.0)
|
|
76
|
+
parallel (>= 1.10)
|
|
50
77
|
parser (>= 3.3.0.2)
|
|
51
78
|
rainbow (>= 2.2.2, < 4.0)
|
|
52
79
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
53
|
-
rubocop-ast (>= 1.
|
|
80
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
54
81
|
ruby-progressbar (~> 1.7)
|
|
55
82
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
56
|
-
rubocop-ast (1.
|
|
57
|
-
parser (>= 3.3.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
rubocop (
|
|
83
|
+
rubocop-ast (1.50.0)
|
|
84
|
+
parser (>= 3.3.7.2)
|
|
85
|
+
prism (~> 1.7)
|
|
86
|
+
rubocop-rake (0.7.1)
|
|
87
|
+
lint_roller (~> 1.1)
|
|
88
|
+
rubocop (>= 1.72.1)
|
|
89
|
+
rubocop-rspec (3.10.2)
|
|
90
|
+
lint_roller (~> 1.1)
|
|
91
|
+
regexp_parser (>= 2.0)
|
|
92
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
62
93
|
ruby-progressbar (1.13.0)
|
|
63
94
|
simplecov (0.22.0)
|
|
64
95
|
docile (~> 1.1)
|
|
@@ -70,21 +101,25 @@ GEM
|
|
|
70
101
|
stringio (3.1.2)
|
|
71
102
|
test-unit (3.6.7)
|
|
72
103
|
power_assert
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
unicode-
|
|
104
|
+
thor (1.5.0)
|
|
105
|
+
tomlrb (2.0.4)
|
|
106
|
+
unicode-display_width (3.3.0)
|
|
107
|
+
unicode-emoji (~> 4.3)
|
|
108
|
+
unicode-emoji (4.3.0)
|
|
76
109
|
yard (0.9.44)
|
|
77
110
|
|
|
78
111
|
PLATFORMS
|
|
79
112
|
ruby
|
|
80
113
|
|
|
81
114
|
DEPENDENCIES
|
|
82
|
-
|
|
115
|
+
awesome_bot (~> 1.20)
|
|
116
|
+
bundler-audit (~> 0.9)
|
|
117
|
+
mdl (~> 0.14)
|
|
83
118
|
rake (~> 13.2)
|
|
84
119
|
rdoc (~> 6.10)
|
|
85
120
|
rspec (~> 3.0, >= 3.13)
|
|
86
121
|
rtagstask (~> 0.0.4)
|
|
87
|
-
rubocop (~> 1.
|
|
122
|
+
rubocop (~> 1.90)
|
|
88
123
|
rubocop-rake (~> 0.6)
|
|
89
124
|
rubocop-rspec (~> 3.3)
|
|
90
125
|
rubytree!
|
data/History.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# History of Changes
|
|
2
2
|
|
|
3
|
+
### 2.2.3 / 2026-10-07
|
|
4
|
+
|
|
5
|
+
* Add support for the `json` gem 3.x while preserving compatibility with 2.x.
|
|
6
|
+
|
|
7
|
+
* Add `Tree::TreeNode.from_json` to rebuild trees from JSON documents.
|
|
8
|
+
|
|
3
9
|
### 2.2.2 / 2026-08-09
|
|
4
10
|
|
|
5
11
|
* Bump the `json` runtime dependency to 2.21.2+, fixing a use-after-free in
|
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# **RubyTree** #
|
|
2
2
|
|
|
3
3
|
[](http://badge.fury.io/rb/rubytree)
|
|
4
|
+
[](https://rubygems.org/gems/rubytree)
|
|
4
5
|

|
|
5
|
-
[](https://codeclimate.com/github/evolve75/RubyTree)
|
|
6
6
|
[](https://coveralls.io/r/evolve75/RubyTree)
|
|
7
7
|
|
|
8
8
|
__ _ _
|
|
@@ -55,7 +55,7 @@ See the [API][rt_doc] documentation for more details.
|
|
|
55
55
|
#
|
|
56
56
|
# example_basic.rb:: Basic usage of the tree library.
|
|
57
57
|
#
|
|
58
|
-
# Copyright (C) 2013-
|
|
58
|
+
# Copyright (C) 2013-2026 Anupam Sengupta <anupamsg@gmail.com>
|
|
59
59
|
#
|
|
60
60
|
# The following example implements this tree structure:
|
|
61
61
|
#
|
|
@@ -123,7 +123,7 @@ This example can also be found at
|
|
|
123
123
|
|
|
124
124
|
* Run-time Dependencies:
|
|
125
125
|
|
|
126
|
-
* [JSON][] for converting to/from the JSON format
|
|
126
|
+
* [JSON][] (2.x or 3.x) for converting to/from the JSON format
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
* Development dependencies (not required for installing the gem):
|
|
@@ -155,7 +155,7 @@ command at the terminal to view the text mode ri documentation:
|
|
|
155
155
|
|
|
156
156
|
Documentation for the latest released version is available at:
|
|
157
157
|
|
|
158
|
-
[rubytree.anupamsg.me/
|
|
158
|
+
[rubytree.anupamsg.me/doc][rt_doc]
|
|
159
159
|
|
|
160
160
|
Documentation for the latest git HEAD is available at:
|
|
161
161
|
|
|
@@ -259,7 +259,7 @@ A big thanks to the following contributors for helping improve **RubyTree**:
|
|
|
259
259
|
[pre-order]: http://en.wikipedia.org/wiki/Tree_traversal#Pre-order "Pre-ordered Traversal"
|
|
260
260
|
[rt@github]: http://github.com/evolve75/RubyTree "RubyTree Project Page on Github"
|
|
261
261
|
[rt_doc@head]: http://rdoc.info/projects/evolve75/RubyTree "RubyTree Documentation for VCS Head"
|
|
262
|
-
[rt_doc]:
|
|
262
|
+
[rt_doc]: https://rubytree.anupamsg.me/doc/ "RubyTree Documentation"
|
|
263
263
|
[rt_gem]: http://rubygems.org/gems/rubytree "RubyTree Gem"
|
|
264
264
|
[rt_site]: http://rubytree.anupamsg.me "RubyTree Site"
|
|
265
265
|
[tree_data_structure]: http://en.wikipedia.org/wiki/Tree_data_structure "Tree Data Structure"
|
data/Rakefile
CHANGED
|
@@ -42,6 +42,9 @@ GEM_SPEC = Bundler.load_gemspec(File.join(__dir__, 'rubytree.gemspec'))
|
|
|
42
42
|
PKG_NAME = GEM_SPEC.name
|
|
43
43
|
PKG_VER = GEM_SPEC.version
|
|
44
44
|
GEM_NAME = "#{PKG_NAME}-#{PKG_VER}.gem"
|
|
45
|
+
MARKDOWN_FILES = Dir['**/*.md'].reject do |path|
|
|
46
|
+
path.start_with?('vendor/', 'pkg/')
|
|
47
|
+
end.sort
|
|
45
48
|
|
|
46
49
|
desc 'Default Task (Run the tests)'
|
|
47
50
|
task :default do
|
|
@@ -98,6 +101,19 @@ namespace :doc do # ................................ Documentation
|
|
|
98
101
|
task :clobber_yard do
|
|
99
102
|
rm_rf 'doc'
|
|
100
103
|
end
|
|
104
|
+
|
|
105
|
+
desc 'Run markdown lint checks'
|
|
106
|
+
task :lint do
|
|
107
|
+
sh('mdl', '--config', '.mdlrc', *MARKDOWN_FILES)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
desc 'Validate http(s) links in markdown files'
|
|
111
|
+
task :links do
|
|
112
|
+
sh('awesome_bot', *MARKDOWN_FILES, '--allow-redirect', '--allow-dupe')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
desc 'Run markdown lint and link checks'
|
|
116
|
+
task check: %i[lint links]
|
|
101
117
|
end
|
|
102
118
|
|
|
103
119
|
desc 'Run the unit tests'
|
|
@@ -178,6 +194,33 @@ require 'rubocop/rake_task'
|
|
|
178
194
|
|
|
179
195
|
RuboCop::RakeTask.new(:rubocop) do |t|
|
|
180
196
|
t.options = ['--display-cop-names']
|
|
181
|
-
|
|
182
|
-
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# ................................ Gem metadata
|
|
200
|
+
desc 'Validate gemspec metadata and required fields'
|
|
201
|
+
task :gemspec do
|
|
202
|
+
GEM_SPEC.validate
|
|
203
|
+
puts 'Gemspec is valid.'
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# ................................ Linting
|
|
207
|
+
desc 'Run lint checks'
|
|
208
|
+
task lint: %i[gemspec rubocop]
|
|
209
|
+
|
|
210
|
+
# ................................ Security checks
|
|
211
|
+
desc 'Run security checks (bundler-audit, semgrep)'
|
|
212
|
+
task :security do
|
|
213
|
+
sh('bundle', 'exec', 'bundler-audit', 'check', '--update')
|
|
214
|
+
|
|
215
|
+
semgrep_available = system('command -v semgrep >/dev/null 2>&1')
|
|
216
|
+
unless semgrep_available
|
|
217
|
+
warn 'WARN: semgrep not found; skipping semgrep security scan.'
|
|
218
|
+
return
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
env = {}
|
|
222
|
+
default_cert = '/etc/ssl/cert.pem'
|
|
223
|
+
env['SSL_CERT_FILE'] = default_cert if ENV['SSL_CERT_FILE'].nil? && File.exist?(default_cert)
|
|
224
|
+
|
|
225
|
+
sh(env, 'semgrep', '--config', 'p/r2c-security-audit', '--config', 'p/ruby', 'lib')
|
|
183
226
|
end
|
data/examples/example_basic.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Author: Anupam Sengupta
|
|
6
6
|
# Time-stamp: <2022-06-19 22:52:29 anupam>
|
|
7
|
-
# Copyright (C) 2013
|
|
7
|
+
# Copyright (C) 2013-2026 Anupam Sengupta <anupamsg@gmail.com>
|
|
8
8
|
#
|
|
9
9
|
# The following example implements this tree structure:
|
|
10
10
|
#
|
|
@@ -43,7 +43,21 @@ module Tree
|
|
|
43
43
|
module Utils
|
|
44
44
|
# Provides utility methods to convert a {Tree::TreeNode} to and from
|
|
45
45
|
# JSON[http://flori.github.com/json/].
|
|
46
|
+
#
|
|
47
|
+
# Every serialized node carries its Ruby class name under the +json_class+
|
|
48
|
+
# key. With the json gem 2.x this is the key the gem inspects itself when
|
|
49
|
+
# parsing with +create_additions: true+. The json gem 3.x removed that
|
|
50
|
+
# option together with the +JSON.create_id+ accessor, so RubyTree emits the
|
|
51
|
+
# key on its own and rebuilds the nodes through {ClassMethods#from_json},
|
|
52
|
+
# which relies on the +on_load+ parser callback available in both the json
|
|
53
|
+
# gem 2.x and 3.x.
|
|
46
54
|
module JSONConverter
|
|
55
|
+
# The hash key which carries the Ruby class name of a serialized node.
|
|
56
|
+
# Equals the default +JSON.create_id+ of the json gem 2.x, so documents
|
|
57
|
+
# written by earlier RubyTree versions stay readable.
|
|
58
|
+
JSON_CLASS_KEY = 'json_class'
|
|
59
|
+
|
|
60
|
+
# Extend the base class with the converter class methods.
|
|
47
61
|
def self.included(base)
|
|
48
62
|
base.extend(ClassMethods)
|
|
49
63
|
end
|
|
@@ -69,7 +83,7 @@ module Tree
|
|
|
69
83
|
json_hash = {
|
|
70
84
|
name: name,
|
|
71
85
|
content: content,
|
|
72
|
-
|
|
86
|
+
JSON_CLASS_KEY => self.class.name
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
json_hash['children'] = children if children?
|
|
@@ -86,7 +100,7 @@ module Tree
|
|
|
86
100
|
#
|
|
87
101
|
# @return The JSON representation of this subtree.
|
|
88
102
|
#
|
|
89
|
-
# @see ClassMethods#
|
|
103
|
+
# @see ClassMethods#from_json
|
|
90
104
|
# @see #as_json
|
|
91
105
|
# @see http://flori.github.com/json
|
|
92
106
|
def to_json(*args)
|
|
@@ -96,17 +110,93 @@ module Tree
|
|
|
96
110
|
# ClassMethods for the {JSONConverter} module. Will become class methods in
|
|
97
111
|
# the +include+ target.
|
|
98
112
|
module ClassMethods
|
|
113
|
+
# Parses a JSON document and returns the tree it describes.
|
|
114
|
+
#
|
|
115
|
+
# tree = Tree::TreeNode.from_json(json_string)
|
|
116
|
+
#
|
|
117
|
+
# The nodes are rebuilt from the hashes tagged with the +json_class+
|
|
118
|
+
# key, see {#json_on_load} for the rules. The document root must
|
|
119
|
+
# describe a node of this class, or of one of its subclasses.
|
|
120
|
+
#
|
|
121
|
+
# This works with both the json gem 2.x and 3.x. With the json gem 2.x
|
|
122
|
+
# the legacy +JSON.parse(json_string, create_additions: true)+ keeps
|
|
123
|
+
# working as well, but the json gem 3.x removed that option.
|
|
124
|
+
#
|
|
125
|
+
# @param [String] source The JSON document to parse.
|
|
126
|
+
#
|
|
127
|
+
# @return [Tree::TreeNode] The root node of the parsed tree.
|
|
128
|
+
#
|
|
129
|
+
# @raise [ArgumentError] This exception is raised if the document does
|
|
130
|
+
# not describe a node of this class.
|
|
131
|
+
#
|
|
132
|
+
# @raise [JSON::ParserError] This exception is raised if the document
|
|
133
|
+
# is not valid JSON.
|
|
134
|
+
#
|
|
135
|
+
# @see #json_on_load
|
|
136
|
+
# @see JSONConverter#to_json
|
|
137
|
+
def from_json(source)
|
|
138
|
+
tree = JSON.parse(source, on_load: method(:json_on_load).to_proc)
|
|
139
|
+
return tree if tree.is_a?(self)
|
|
140
|
+
|
|
141
|
+
raise ArgumentError, "JSON document does not describe a #{self} tree"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Rebuilds a node from its parsed JSON hash. This is the +on_load+
|
|
145
|
+
# callback for the parser of the json gem, used by {#from_json} and
|
|
146
|
+
# available for custom parser setups (the parser expects a +Proc+):
|
|
147
|
+
#
|
|
148
|
+
# on_load = Tree::TreeNode.method(:json_on_load).to_proc
|
|
149
|
+
# tree = JSON::Coder.new(on_load: on_load).load(json_string)
|
|
150
|
+
#
|
|
151
|
+
# The parser invokes the callback for every parsed value, innermost
|
|
152
|
+
# first, so the +children+ of a node hash are already nodes by the
|
|
153
|
+
# time the hash of their parent arrives here. Only hashes whose
|
|
154
|
+
# +json_class+ names this class or one of its subclasses are turned
|
|
155
|
+
# into nodes, any other value is returned untouched. This keeps the
|
|
156
|
+
# deserialization scoped to tree nodes, unlike the global
|
|
157
|
+
# +create_additions+ mechanism of the json gem 2.x which instantiated
|
|
158
|
+
# any class named in a document.
|
|
159
|
+
#
|
|
160
|
+
# @param [Object] object A value produced by the JSON parser.
|
|
161
|
+
#
|
|
162
|
+
# @return [Tree::TreeNode, Object] The node for a tagged hash, or the
|
|
163
|
+
# unchanged value otherwise.
|
|
164
|
+
#
|
|
165
|
+
# @see #from_json
|
|
166
|
+
# @see #json_create
|
|
167
|
+
def json_on_load(object)
|
|
168
|
+
return object unless object.is_a?(Hash)
|
|
169
|
+
|
|
170
|
+
node_class = json_node_class(object[JSON_CLASS_KEY])
|
|
171
|
+
node_class ? node_class.json_create(object) : object
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Resolves the class named by a +json_class+ tag, limited to this
|
|
175
|
+
# class and its subclasses.
|
|
176
|
+
#
|
|
177
|
+
# @param [String, nil] class_name The class name found in the tag.
|
|
178
|
+
#
|
|
179
|
+
# @return [Class, nil] The node class, or +nil+ when the tag is
|
|
180
|
+
# missing, unknown or names a foreign class.
|
|
181
|
+
def json_node_class(class_name)
|
|
182
|
+
return nil unless class_name.is_a?(String)
|
|
183
|
+
|
|
184
|
+
node_class = Object.const_get(class_name)
|
|
185
|
+
node_class if node_class.is_a?(Class) && node_class <= self
|
|
186
|
+
rescue NameError
|
|
187
|
+
nil
|
|
188
|
+
end
|
|
189
|
+
|
|
99
190
|
# Helper method to create a Tree::TreeNode instance from the JSON hash
|
|
100
191
|
# representation. Note that this method should *NOT* be called directly.
|
|
101
|
-
# Instead, to convert
|
|
102
|
-
#
|
|
103
|
-
# tree = JSON.parse(the_json_hash, create_additions: true)
|
|
192
|
+
# Instead, to convert a JSON document back to a tree, do:
|
|
104
193
|
#
|
|
105
|
-
#
|
|
106
|
-
# be available, or else the operation fails with a warning message.
|
|
194
|
+
# tree = Tree::TreeNode.from_json(the_json_string)
|
|
107
195
|
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
196
|
+
# With the json gem 2.x this method also serves as the hook of the
|
|
197
|
+
# +create_additions+ mechanism, so the legacy
|
|
198
|
+
# +JSON.parse(the_json_string, create_additions: true)+ keeps working
|
|
199
|
+
# there. The json gem 3.x removed that mechanism.
|
|
110
200
|
#
|
|
111
201
|
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
|
112
202
|
# @since 0.7.0
|
|
@@ -115,8 +205,9 @@ module Tree
|
|
|
115
205
|
#
|
|
116
206
|
# @return [Tree::TreeNode] The created tree.
|
|
117
207
|
#
|
|
118
|
-
# @see #
|
|
119
|
-
# @see
|
|
208
|
+
# @see #from_json
|
|
209
|
+
# @see #json_on_load
|
|
210
|
+
# @see JSONConverter#to_json
|
|
120
211
|
def json_create(json_hash)
|
|
121
212
|
node = new(json_hash['name'], json_hash['content'])
|
|
122
213
|
|
data/lib/tree/version.rb
CHANGED
data/test/test_binarytree.rb
CHANGED
|
@@ -196,6 +196,19 @@ module TestTree
|
|
|
196
196
|
assert_equal(Enumerable::Enumerator, f.inordered_each.class) if defined?(Enumerable::Enumerator.class)
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
+
# Test the JSON round trip, which has to rebuild binary tree nodes.
|
|
200
|
+
def test_json_round_trip
|
|
201
|
+
@root << @left_child1 << Tree::BinaryTreeNode.new('C', 'Grand child')
|
|
202
|
+
@root << @right_child1
|
|
203
|
+
|
|
204
|
+
tree = Tree::BinaryTreeNode.from_json(@root.to_json)
|
|
205
|
+
|
|
206
|
+
assert_equal(Tree::BinaryTreeNode, tree.class)
|
|
207
|
+
assert_equal(@left_child1.name, tree.left_child.name)
|
|
208
|
+
assert_equal(@right_child1.name, tree.right_child.name)
|
|
209
|
+
assert_equal('C', tree.left_child.left_child.name)
|
|
210
|
+
end
|
|
211
|
+
|
|
199
212
|
# Test the left_child method.
|
|
200
213
|
def test_left_child
|
|
201
214
|
@root << @left_child1
|
|
@@ -48,6 +48,22 @@ module TestTree
|
|
|
48
48
|
root = MyNode.new('Root')
|
|
49
49
|
assert_equal(MyNode, root.detached_copy.class)
|
|
50
50
|
end
|
|
51
|
+
|
|
52
|
+
def test_from_json_same_clz
|
|
53
|
+
root = MyNode.new('Root')
|
|
54
|
+
root << MyNode.new('Child')
|
|
55
|
+
|
|
56
|
+
tree = MyNode.from_json(root.to_json)
|
|
57
|
+
|
|
58
|
+
assert_equal(MyNode, tree.class)
|
|
59
|
+
assert_equal(MyNode, tree['Child'].class)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_from_json_via_base_class
|
|
63
|
+
tree = Tree::TreeNode.from_json(MyNode.new('Root').to_json)
|
|
64
|
+
|
|
65
|
+
assert_equal(MyNode, tree.class)
|
|
66
|
+
end
|
|
51
67
|
end
|
|
52
68
|
end
|
|
53
69
|
|
data/test/test_tree.rb
CHANGED
|
@@ -1345,16 +1345,16 @@ module TestTree
|
|
|
1345
1345
|
expected_json = {
|
|
1346
1346
|
'name' => 'ROOT',
|
|
1347
1347
|
'content' => 'Root Node',
|
|
1348
|
-
|
|
1348
|
+
'json_class' => 'Tree::TreeNode',
|
|
1349
1349
|
'children' => [
|
|
1350
|
-
{ 'name' => 'Child1', 'content' => 'Child Node 1',
|
|
1351
|
-
{ 'name' => 'Child2', 'content' => 'Child Node 2',
|
|
1350
|
+
{ 'name' => 'Child1', 'content' => 'Child Node 1', 'json_class' => 'Tree::TreeNode' },
|
|
1351
|
+
{ 'name' => 'Child2', 'content' => 'Child Node 2', 'json_class' => 'Tree::TreeNode' },
|
|
1352
1352
|
{
|
|
1353
1353
|
'name' => 'Child3',
|
|
1354
1354
|
'content' => 'Child Node 3',
|
|
1355
|
-
|
|
1355
|
+
'json_class' => 'Tree::TreeNode',
|
|
1356
1356
|
'children' => [
|
|
1357
|
-
{ 'name' => 'Child4', 'content' => 'Grand Child 1',
|
|
1357
|
+
{ 'name' => 'Child4', 'content' => 'Grand Child 1', 'json_class' => 'Tree::TreeNode' }
|
|
1358
1358
|
]
|
|
1359
1359
|
}
|
|
1360
1360
|
]
|
|
@@ -1367,22 +1367,22 @@ module TestTree
|
|
|
1367
1367
|
tree_as_json = {
|
|
1368
1368
|
'name' => 'ROOT',
|
|
1369
1369
|
'content' => 'Root Node',
|
|
1370
|
-
|
|
1370
|
+
'json_class' => 'Tree::TreeNode',
|
|
1371
1371
|
'children' => [
|
|
1372
|
-
{ 'name' => 'Child1', 'content' => 'Child Node 1',
|
|
1373
|
-
{ 'name' => 'Child2', 'content' => 'Child Node 2',
|
|
1372
|
+
{ 'name' => 'Child1', 'content' => 'Child Node 1', 'json_class' => 'Tree::TreeNode' },
|
|
1373
|
+
{ 'name' => 'Child2', 'content' => 'Child Node 2', 'json_class' => 'Tree::TreeNode' },
|
|
1374
1374
|
{
|
|
1375
1375
|
'name' => 'Child3',
|
|
1376
1376
|
'content' => 'Child Node 3',
|
|
1377
|
-
|
|
1377
|
+
'json_class' => 'Tree::TreeNode',
|
|
1378
1378
|
'children' => [
|
|
1379
|
-
{ 'name' => 'Child4', 'content' => 'Grand Child 1',
|
|
1379
|
+
{ 'name' => 'Child4', 'content' => 'Grand Child 1', 'json_class' => 'Tree::TreeNode' }
|
|
1380
1380
|
]
|
|
1381
1381
|
}
|
|
1382
1382
|
]
|
|
1383
1383
|
}.to_json
|
|
1384
1384
|
|
|
1385
|
-
tree =
|
|
1385
|
+
tree = Tree::TreeNode.from_json(tree_as_json)
|
|
1386
1386
|
|
|
1387
1387
|
assert_equal(@root.name, tree.root.name, 'Root should be returned')
|
|
1388
1388
|
assert_equal(@child1.name, tree[0].name, 'Child 1 should be returned')
|
|
@@ -1399,7 +1399,7 @@ module TestTree
|
|
|
1399
1399
|
|
|
1400
1400
|
j = root_node.to_json
|
|
1401
1401
|
|
|
1402
|
-
k =
|
|
1402
|
+
k = Tree::TreeNode.from_json(j)
|
|
1403
1403
|
|
|
1404
1404
|
assert_equal(k.name, root_node.name, 'Root should be returned')
|
|
1405
1405
|
assert_equal(k[0].name, root_node[0].name, 'Child 1 should be returned')
|
|
@@ -1407,6 +1407,34 @@ module TestTree
|
|
|
1407
1407
|
assert_equal(k[1].name, root_node[1].name, 'Child 2 should be returned')
|
|
1408
1408
|
end
|
|
1409
1409
|
|
|
1410
|
+
# The json gem 2.x can still rebuild the tree on its own through its
|
|
1411
|
+
# +create_additions+ mechanism, which the json gem 3.x removed.
|
|
1412
|
+
def test_json_create_additions_on_json2
|
|
1413
|
+
omit_unless(JSON.respond_to?(:create_id),
|
|
1414
|
+
'create_additions was removed by the json gem 3.x')
|
|
1415
|
+
setup_test_tree
|
|
1416
|
+
|
|
1417
|
+
tree = JSON.parse(@root.to_json, create_additions: true)
|
|
1418
|
+
|
|
1419
|
+
assert_equal(@root.name, tree.name, 'Root should be returned')
|
|
1420
|
+
assert_equal(@child4.name, tree[2][0].name,
|
|
1421
|
+
'Grand Child 1 should be returned')
|
|
1422
|
+
end
|
|
1423
|
+
|
|
1424
|
+
def test_from_json_rejects_foreign_class
|
|
1425
|
+
document = { 'json_class' => 'String', 'raw' => [112, 119, 110] }.to_json
|
|
1426
|
+
|
|
1427
|
+
assert_raise(ArgumentError) { Tree::TreeNode.from_json(document) }
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
def test_from_json_keeps_untagged_content
|
|
1431
|
+
root_node = Tree::TreeNode.new('ROOT', { 'key' => 'value' })
|
|
1432
|
+
|
|
1433
|
+
tree = Tree::TreeNode.from_json(root_node.to_json)
|
|
1434
|
+
|
|
1435
|
+
assert_equal({ 'key' => 'value' }, tree.content)
|
|
1436
|
+
end
|
|
1437
|
+
|
|
1410
1438
|
# Test usage of integers as node names
|
|
1411
1439
|
def test_integer_node_names
|
|
1412
1440
|
@n_root = Tree::TreeNode.new(0, 'Root Node')
|
metadata
CHANGED
|
@@ -1,49 +1,77 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubytree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.2.
|
|
4
|
+
version: 2.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anupam Sengupta
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "~>"
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.0'
|
|
20
17
|
- - ">="
|
|
21
18
|
- !ruby/object:Gem::Version
|
|
22
19
|
version: 2.21.2
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '4'
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
|
-
- - "~>"
|
|
28
|
-
- !ruby/object:Gem::Version
|
|
29
|
-
version: '2.0'
|
|
30
27
|
- - ">="
|
|
31
28
|
- !ruby/object:Gem::Version
|
|
32
29
|
version: 2.21.2
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '4'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: awesome_bot
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.20'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.20'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: bundler-audit
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.9'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.9'
|
|
33
61
|
- !ruby/object:Gem::Dependency
|
|
34
|
-
name:
|
|
62
|
+
name: mdl
|
|
35
63
|
requirement: !ruby/object:Gem::Requirement
|
|
36
64
|
requirements:
|
|
37
65
|
- - "~>"
|
|
38
66
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
67
|
+
version: '0.14'
|
|
40
68
|
type: :development
|
|
41
69
|
prerelease: false
|
|
42
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
71
|
requirements:
|
|
44
72
|
- - "~>"
|
|
45
73
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
74
|
+
version: '0.14'
|
|
47
75
|
- !ruby/object:Gem::Dependency
|
|
48
76
|
name: rake
|
|
49
77
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -112,14 +140,14 @@ dependencies:
|
|
|
112
140
|
requirements:
|
|
113
141
|
- - "~>"
|
|
114
142
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: '1.
|
|
143
|
+
version: '1.90'
|
|
116
144
|
type: :development
|
|
117
145
|
prerelease: false
|
|
118
146
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
147
|
requirements:
|
|
120
148
|
- - "~>"
|
|
121
149
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: '1.
|
|
150
|
+
version: '1.90'
|
|
123
151
|
- !ruby/object:Gem::Dependency
|
|
124
152
|
name: rubocop-rake
|
|
125
153
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -304,7 +332,7 @@ post_install_message: |2
|
|
|
304
332
|
========================================================================
|
|
305
333
|
rdoc_options:
|
|
306
334
|
- "--title"
|
|
307
|
-
- 'Rubytree Documentation: rubytree-2.2.
|
|
335
|
+
- 'Rubytree Documentation: rubytree-2.2.3'
|
|
308
336
|
- "--main"
|
|
309
337
|
- README.md
|
|
310
338
|
- "--quiet"
|