Module: Tree::Utils::JSONConverter::ClassMethods

Defined in:
lib/tree/utils/json_converter.rb

Overview

ClassMethods for the Tree::Utils::JSONConverter module. Will become class methods in the include target.

Converting to/from JSON collapse

Instance Method Details

#from_json(source) ⇒ Tree::TreeNode

Parses a JSON document and returns the tree it describes.

tree = Tree::TreeNode.from_json(json_string)

The nodes are rebuilt from the hashes tagged with the json_class key, see #json_on_load for the rules. The document root must describe a node of this class, or of one of its subclasses.

This works with both the json gem 2.x and 3.x. With the json gem 2.x the legacy JSON.parse(json_string, create_additions: true) keeps working as well, but the json gem 3.x removed that option.

Parameters:

  • source (String) —

    The JSON document to parse.

Returns:

Raises:

  • (ArgumentError) —

    This exception is raised if the document does not describe a node of this class.

  • (JSON::ParserError) —

    This exception is raised if the document is not valid JSON.

See Also:



137
138
139
140
141
142
# File 'lib/tree/utils/json_converter.rb', line 137

def from_json(source)
  tree = JSON.parse(source, on_load: method(:json_on_load).to_proc)
  return tree if tree.is_a?(self)

  raise ArgumentError, "JSON document does not describe a #{self} tree"
end

#json_create(json_hash) ⇒ Tree::TreeNode

Helper method to create a Tree::TreeNode instance from the JSON hash representation. Note that this method should NOT be called directly. Instead, to convert a JSON document back to a tree, do:

tree = Tree::TreeNode.from_json(the_json_string)

With the json gem 2.x this method also serves as the hook of the create_additions mechanism, so the legacy JSON.parse(the_json_string, create_additions: true) keeps working there. The json gem 3.x removed that mechanism.

Parameters:

  • json_hash (Hash) —

    The JSON hash to convert from.

Returns:

See Also:

Author:

Since:

  • 0.7.0



211
212
213
214
215
216
217
218
219
# File 'lib/tree/utils/json_converter.rb', line 211

def json_create(json_hash)
  node = new(json_hash['name'], json_hash['content'])

  json_hash['children']&.each do |child|
    node << child
  end

  node
end

#json_node_class(class_name) ⇒ Class?

Resolves the class named by a json_class tag, limited to this class and its subclasses.

Parameters:

  • class_name (String, nil) —

    The class name found in the tag.

Returns:

  • (Class, nil) —

    The node class, or nil when the tag is missing, unknown or names a foreign class.



181
182
183
184
185
186
187
188
# File 'lib/tree/utils/json_converter.rb', line 181

def json_node_class(class_name)
  return nil unless class_name.is_a?(String)

  node_class = Object.const_get(class_name)
  node_class if node_class.is_a?(Class) && node_class <= self
rescue NameError
  nil
end

#json_on_load(object) ⇒ Tree::TreeNode, Object

Rebuilds a node from its parsed JSON hash. This is the on_load callback for the parser of the json gem, used by #from_json and available for custom parser setups (the parser expects a Proc):

on_load = Tree::TreeNode.method(:json_on_load).to_proc
tree = JSON::Coder.new(on_load: on_load).load(json_string)

The parser invokes the callback for every parsed value, innermost first, so the children of a node hash are already nodes by the time the hash of their parent arrives here. Only hashes whose json_class names this class or one of its subclasses are turned into nodes, any other value is returned untouched. This keeps the deserialization scoped to tree nodes, unlike the global create_additions mechanism of the json gem 2.x which instantiated any class named in a document.

Parameters:

  • object (Object) —

    A value produced by the JSON parser.

Returns:

  • (Tree::TreeNode, Object) —

    The node for a tagged hash, or the unchanged value otherwise.

See Also:



167
168
169
170
171
172
# File 'lib/tree/utils/json_converter.rb', line 167

def json_on_load(object)
  return object unless object.is_a?(Hash)

  node_class = json_node_class(object[JSON_CLASS_KEY])
  node_class ? node_class.json_create(object) : object
end