Class: JSI::JSON::Node
- Inherits:
-
Object
- Object
- JSI::JSON::Node
- Includes:
- Enumerable, PathedNode, Util::FingerprintHash
- Defined in:
- lib/jsi/json/node.rb
Overview
JSI::JSON::Node is an abstraction of a node within a JSON document. it aims to act like the underlying data type of the node's content (generally Hash or Array-like) in most cases.
the main advantage offered by using a Node over the underlying data is in dereferencing. if a Node consists of a hash with a $ref property pointing within the same document, then the Node will transparently follow the ref and return the referenced data.
in most other respects, a Node aims to act like a Hash when the content is Hash-like, an Array when the content is Array-like. methods of Hash and Array are defined and delegated to the node's content.
however, destructive methods are for the most part not implemented. at the moment only #[]= is implemented. since Node thinly wraps the underlying data, you can change the data and it will be reflected in the node. implementations of destructive methods are planned.
methods that return a modified copy such as #merge are defined, and return a copy of the document with the content of the node modified. the original node's document and content are untouched.
Instance Attribute Summary collapse
-
#node_document ⇒ Object
readonly
the document containing this Node at our pointer.
-
#node_ptr ⇒ Object
readonly
JSI::JSON::Pointer pointing to this node within its document.
Class Method Summary collapse
-
.new_by_type(node_document, node_ptr) ⇒ Object
if the content of the document at the given pointer is Hash-like, returns a HashNode; if Array-like, returns ArrayNode.
- .new_doc(node_document) ⇒ Object
Instance Method Summary collapse
-
#[](subscript) ⇒ Object
returns content at the given subscript - call this the subcontent.
-
#[]=(subscript, value) ⇒ Object
assigns the given subscript of the content to the given value.
-
#as_json(*opt) ⇒ Object
returns a jsonifiable representation of this node's content.
-
#deref {|Node| ... } ⇒ JSI::JSON::Node
returns a Node, dereferencing a $ref attribute if possible.
-
#document_root_node ⇒ Object
a Node at the root of the document.
- #dup ⇒ Object
-
#initialize(node_document, node_ptr) ⇒ Node
constructor
a Node represents the content of a document at a given pointer.
-
#inspect ⇒ Object
a string representing this node.
-
#jsi_fingerprint ⇒ Object
fingerprint for equality (see FingerprintHash).
-
#modified_copy(&block) ⇒ Object
takes a block.
-
#object_group_text ⇒ Array<String>
meta-information about the object, outside the content.
-
#parent_node ⇒ Object
the parent of this node.
-
#pretty_print(q) ⇒ Object
pretty-prints a representation this node to the given printer.
Methods included from Util::FingerprintHash
Methods included from PathedNode
#node_content, #node_ptr_deref
Constructor Details
#initialize(node_document, node_ptr) ⇒ Node
a Node represents the content of a document at a given pointer.
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/jsi/json/node.rb', line 50 def initialize(node_document, node_ptr) unless node_ptr.is_a?(JSI::JSON::Pointer) raise(TypeError, "node_ptr must be a JSI::JSON::Pointer. got: #{node_ptr.pretty_inspect.chomp} (#{node_ptr.class})") end if node_document.is_a?(JSI::JSON::Node) raise(TypeError, "node_document of a Node should not be another JSI::JSON::Node: #{node_document.inspect}") end @node_document = node_document @node_ptr = node_ptr end |
Instance Attribute Details
#node_document ⇒ Object (readonly)
the document containing this Node at our pointer
62 63 64 |
# File 'lib/jsi/json/node.rb', line 62 def node_document @node_document end |
#node_ptr ⇒ Object (readonly)
JSI::JSON::Pointer pointing to this node within its document
65 66 67 |
# File 'lib/jsi/json/node.rb', line 65 def node_ptr @node_ptr end |
Class Method Details
.new_by_type(node_document, node_ptr) ⇒ Object
if the content of the document at the given pointer is Hash-like, returns a HashNode; if Array-like, returns ArrayNode. otherwise returns a regular Node, although Nodes are for the most part instantiated from Hash or Array-like content.
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/jsi/json/node.rb', line 38 def self.new_by_type(node_document, node_ptr) content = node_ptr.evaluate(node_document) if content.respond_to?(:to_hash) HashNode.new(node_document, node_ptr) elsif content.respond_to?(:to_ary) ArrayNode.new(node_document, node_ptr) else Node.new(node_document, node_ptr) end end |
Instance Method Details
#[](subscript) ⇒ Object
returns content at the given subscript - call this the subcontent.
if the content cannot be subscripted, raises TypeError.
if the subcontent is Hash-like, it is wrapped as a JSI::JSON::HashNode before being returned. if the subcontent is Array-like, it is wrapped as a JSI::JSON::ArrayNode before being returned.
if this node's content is a $ref - that is, a hash with a $ref attribute - and the subscript is not a key of the hash, then the $ref is followed before returning the subcontent.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/jsi/json/node.rb', line 76 def [](subscript) ptr = self.node_ptr content = self.node_content unless content.respond_to?(:[]) if content.respond_to?(:to_hash) content = content.to_hash elsif content.respond_to?(:to_ary) content = content.to_ary else raise(NoMethodError, "undefined method `[]`\nsubscripting with #{subscript.pretty_inspect.chomp} (#{subscript.class}) from #{content.class.inspect}. content is: #{content.pretty_inspect.chomp}") end end begin subcontent = content[subscript] rescue TypeError => e raise(e.class, e. + "\nsubscripting with #{subscript.pretty_inspect.chomp} (#{subscript.class}) from #{content.class.inspect}. content is: #{content.pretty_inspect.chomp}", e.backtrace) end if subcontent.respond_to?(:to_hash) HashNode.new(node_document, ptr[subscript]) elsif subcontent.respond_to?(:to_ary) ArrayNode.new(node_document, ptr[subscript]) else subcontent end end |
#[]=(subscript, value) ⇒ Object
assigns the given subscript of the content to the given value. the document is modified in place.
103 104 105 106 107 108 109 |
# File 'lib/jsi/json/node.rb', line 103 def []=(subscript, value) if value.is_a?(Node) node_content[subscript] = value.node_content else node_content[subscript] = value end end |
#as_json(*opt) ⇒ Object
returns a jsonifiable representation of this node's content
139 140 141 |
# File 'lib/jsi/json/node.rb', line 139 def as_json(*opt) Typelike.as_json(node_content, *opt) end |
#deref {|Node| ... } ⇒ JSI::JSON::Node
returns a Node, dereferencing a $ref attribute if possible. if this node is not hash-like, does not have a $ref, or if what its $ref cannot be found, this node is returned.
currently only $refs pointing within the same document are followed.
120 121 122 123 124 125 |
# File 'lib/jsi/json/node.rb', line 120 def deref(&block) node_ptr_deref do |deref_ptr| return Node.new_by_type(node_document, deref_ptr).tap(&(block || Util::NOOP)) end return self end |
#document_root_node ⇒ Object
a Node at the root of the document
128 129 130 |
# File 'lib/jsi/json/node.rb', line 128 def document_root_node Node.new_doc(node_document) end |
#dup ⇒ Object
149 150 151 |
# File 'lib/jsi/json/node.rb', line 149 def dup modified_copy(&:dup) end |
#inspect ⇒ Object
a string representing this node
163 164 165 |
# File 'lib/jsi/json/node.rb', line 163 def inspect "\#<#{object_group_text.join(' ')} #{node_content.inspect}>" end |
#jsi_fingerprint ⇒ Object
fingerprint for equality (see FingerprintHash). two nodes are equal if they are both nodes (regardless of type, e.g. one may be a Node and the other may be a HashNode) within equal documents at equal pointers. note that this means two nodes with the same content may not be considered equal.
185 186 187 |
# File 'lib/jsi/json/node.rb', line 185 def jsi_fingerprint {class: JSI::JSON::Node, node_document: node_document, node_ptr: node_ptr} end |
#modified_copy(&block) ⇒ Object
takes a block. the block is yielded the content of this node. the block MUST return a modified copy of that content (and NOT modify the object it is given).
145 146 147 |
# File 'lib/jsi/json/node.rb', line 145 def modified_copy(&block) Node.new_by_type(node_ptr.modified_document_copy(node_document, &block), node_ptr) end |
#object_group_text ⇒ Array<String>
meta-information about the object, outside the content. used by #inspect / #pretty_print
155 156 157 158 159 160 |
# File 'lib/jsi/json/node.rb', line 155 def object_group_text [ self.class.inspect, node_ptr.uri.to_s, ] + (node_content.respond_to?(:object_group_text) ? node_content.object_group_text : []) end |
#parent_node ⇒ Object
the parent of this node. if this node is the document root, raises JSI::JSON::Pointer::ReferenceError.
134 135 136 |
# File 'lib/jsi/json/node.rb', line 134 def parent_node Node.new_by_type(node_document, node_ptr.parent) end |
#pretty_print(q) ⇒ Object
pretty-prints a representation this node to the given printer
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/jsi/json/node.rb', line 168 def pretty_print(q) q.text '#<' q.text object_group_text.join(' ') q.group_sub { q.nest(2) { q.breakable ' ' q.pp node_content } } q.breakable '' q.text '>' end |