yerba 0.9.2-aarch64-linux-gnu → 0.10.0-aarch64-linux-gnu
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/README.md +34 -17
- data/exe/aarch64-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +56 -34
- data/ext/yerba/yerba.c +268 -186
- data/lib/yerba/3.2/yerba.so +0 -0
- data/lib/yerba/3.3/yerba.so +0 -0
- data/lib/yerba/3.4/yerba.so +0 -0
- data/lib/yerba/4.0/yerba.so +0 -0
- data/lib/yerba/collection.rb +4 -4
- data/lib/yerba/document.rb +134 -0
- data/lib/yerba/formatting.rb +1 -0
- data/lib/yerba/location.rb +8 -1
- data/lib/yerba/map.rb +16 -6
- data/lib/yerba/node.rb +41 -0
- data/lib/yerba/query_result.rb +33 -10
- data/lib/yerba/scalar.rb +29 -0
- data/lib/yerba/selector.rb +3 -1
- data/lib/yerba/sequence.rb +38 -33
- data/lib/yerba/version.rb +1 -1
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/commands/get.rs +12 -12
- data/rust/src/commands/init.rs +8 -8
- data/rust/src/commands/insert.rs +4 -18
- data/rust/src/commands/location.rs +2 -0
- data/rust/src/commands/mod.rs +34 -6
- data/rust/src/commands/move_item.rs +1 -1
- data/rust/src/commands/move_key.rs +8 -8
- data/rust/src/commands/rename.rs +1 -1
- data/rust/src/commands/selectors.rs +1 -1
- data/rust/src/commands/set.rs +14 -6
- data/rust/src/document/condition.rs +25 -25
- data/rust/src/document/delete.rs +57 -43
- data/rust/src/document/get.rs +91 -82
- data/rust/src/document/insert.rs +77 -77
- data/rust/src/document/mod.rs +138 -64
- data/rust/src/document/nodes.rs +162 -0
- data/rust/src/document/schema.rs +8 -8
- data/rust/src/document/set.rs +49 -26
- data/rust/src/document/sort.rs +54 -54
- data/rust/src/document/style.rs +50 -49
- data/rust/src/document/unique.rs +5 -5
- data/rust/src/error.rs +8 -4
- data/rust/src/ffi.rs +218 -106
- data/rust/src/json.rs +62 -2
- data/rust/src/lib.rs +2 -1
- data/rust/src/main.rs +2 -1
- data/rust/src/selector.rs +48 -7
- data/rust/src/syntax.rs +449 -56
- data/rust/src/validation.rs +5 -3
- data/rust/src/yerbafile.rs +124 -76
- metadata +3 -2
data/lib/yerba/3.2/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.3/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.4/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/4.0/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/collection.rb
CHANGED
|
@@ -12,12 +12,12 @@ module Yerba
|
|
|
12
12
|
Dir.glob(@glob).each { |path| yield Document.new(path) }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def get(
|
|
16
|
-
self.class.get(@glob,
|
|
15
|
+
def get(selector)
|
|
16
|
+
self.class.get(@glob, selector)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def find(
|
|
20
|
-
self.class.find(@glob,
|
|
19
|
+
def find(selector, condition: nil, select: nil)
|
|
20
|
+
self.class.find(@glob, selector, condition: condition, select: select)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def find_by(...)
|
data/lib/yerba/document.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Yerba
|
|
4
4
|
class Document
|
|
5
|
+
include NodeTree
|
|
6
|
+
|
|
5
7
|
ROOT_SELECTOR = ""
|
|
6
8
|
|
|
7
9
|
def self.cache
|
|
@@ -76,6 +78,48 @@ module Yerba
|
|
|
76
78
|
File.mtime(@path) != @loaded_mtime
|
|
77
79
|
end
|
|
78
80
|
|
|
81
|
+
def [](selector)
|
|
82
|
+
return native_node_at(selector) unless selector.is_a?(String)
|
|
83
|
+
|
|
84
|
+
parsed = Selector.parse(selector)
|
|
85
|
+
matches = find_nodes(parsed)
|
|
86
|
+
return native_node_at(selector) if matches.nil?
|
|
87
|
+
|
|
88
|
+
matches = matches.map { |match| match&.dup }
|
|
89
|
+
parsed.wildcard? ? matches.compact : matches.first
|
|
90
|
+
end
|
|
91
|
+
alias node_at []
|
|
92
|
+
|
|
93
|
+
def value_at(selector)
|
|
94
|
+
return native_value_at(selector) unless selector.is_a?(String) || selector.is_a?(Selector)
|
|
95
|
+
|
|
96
|
+
parsed = Selector.parse(selector)
|
|
97
|
+
matches = find_nodes(parsed) unless parsed.wildcard?
|
|
98
|
+
return native_value_at(selector) if matches.nil?
|
|
99
|
+
|
|
100
|
+
node = matches.first
|
|
101
|
+
return nil if node.nil?
|
|
102
|
+
|
|
103
|
+
node.is_a?(Scalar) && node.tree_node? ? node.value : native_value_at(selector)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def nodes
|
|
107
|
+
generation = native_generation
|
|
108
|
+
return @nodes if @nodes_generation == generation
|
|
109
|
+
|
|
110
|
+
@nodes_generation = generation
|
|
111
|
+
@nodes = build_nodes(native_node_records)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def length_at(selector)
|
|
115
|
+
parsed = Selector.parse(selector)
|
|
116
|
+
matches = find_nodes(parsed) unless parsed.wildcard?
|
|
117
|
+
return Array(value_at(selector)).length if matches.nil?
|
|
118
|
+
|
|
119
|
+
children = matches.first&.tree_children
|
|
120
|
+
children.is_a?(Array) ? children.length : 0
|
|
121
|
+
end
|
|
122
|
+
|
|
79
123
|
def dig(*keys)
|
|
80
124
|
keys.reduce(self) { |node, key| node.nil? ? nil : node[key] }
|
|
81
125
|
end
|
|
@@ -177,6 +221,96 @@ module Yerba
|
|
|
177
221
|
|
|
178
222
|
private
|
|
179
223
|
|
|
224
|
+
def build_nodes(records)
|
|
225
|
+
built = []
|
|
226
|
+
|
|
227
|
+
records.each do |parent, type, selector, key_name, value, has_value, location, key_location|
|
|
228
|
+
key = Scalar.from_document(nil, nil, key_location, nil, value: key_name) if key_name
|
|
229
|
+
node = build_node(type, selector, location, key, value)
|
|
230
|
+
|
|
231
|
+
node.attach_tree(built.first || node, tree_container(type), !has_value) if type
|
|
232
|
+
add_child(built[parent], key_name, node) unless parent.negative?
|
|
233
|
+
|
|
234
|
+
built << node
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
built.each { |node| node&.tree_children&.freeze }
|
|
238
|
+
built.first
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def build_node(type, selector, location, key, value)
|
|
242
|
+
case type
|
|
243
|
+
when :scalar
|
|
244
|
+
Scalar.from_document(self, selector, location, key, value: value)
|
|
245
|
+
when :map
|
|
246
|
+
Map.from_document(self, selector, location, key)
|
|
247
|
+
when :sequence
|
|
248
|
+
Sequence.from_document(self, selector, location, key)
|
|
249
|
+
else
|
|
250
|
+
native_node_at(selector)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def tree_container(type)
|
|
255
|
+
case type
|
|
256
|
+
when :map
|
|
257
|
+
{}
|
|
258
|
+
when :sequence
|
|
259
|
+
[]
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def add_child(parent, key_name, node)
|
|
264
|
+
children = parent.tree_children
|
|
265
|
+
|
|
266
|
+
if children.is_a?(Hash)
|
|
267
|
+
children[key_name] = node
|
|
268
|
+
else
|
|
269
|
+
children << node
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def find_nodes(selector)
|
|
274
|
+
return nil if selector.relative? || malformed?(selector.to_s) || nodes.nil?
|
|
275
|
+
|
|
276
|
+
wildcard = selector.wildcard?
|
|
277
|
+
|
|
278
|
+
selector.segments.reduce([nodes]) do |current, segment|
|
|
279
|
+
current.flat_map do |node|
|
|
280
|
+
children = node&.tree_node? ? node.tree_children : nil
|
|
281
|
+
matches = children && child_matches(children, segment)
|
|
282
|
+
return nil if matches.nil?
|
|
283
|
+
|
|
284
|
+
wildcard && children.is_a?(Hash) ? matches.reject { |match| valueless_entry?(match) } : matches
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def valueless_entry?(node)
|
|
290
|
+
node.valueless?
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def malformed?(selector)
|
|
294
|
+
selector.end_with?(".") || selector.include?("..") || (selector.include?("[") && !selector.include?("]"))
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def child_matches(children, segment)
|
|
298
|
+
case segment
|
|
299
|
+
when Selector::ALL_ITEMS
|
|
300
|
+
children if children.is_a?(Array)
|
|
301
|
+
when Selector::ALL_KEYS
|
|
302
|
+
children.values if children.is_a?(Hash)
|
|
303
|
+
when Integer
|
|
304
|
+
return nil unless children.is_a?(Array)
|
|
305
|
+
|
|
306
|
+
segment < children.length ? [children[segment]] : []
|
|
307
|
+
else
|
|
308
|
+
return nil unless children.is_a?(Hash)
|
|
309
|
+
|
|
310
|
+
children.key?(segment) ? [children[segment]] : []
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
180
314
|
def empty_root?
|
|
181
315
|
root.is_a?(Scalar) && root.value.nil?
|
|
182
316
|
end
|
data/lib/yerba/formatting.rb
CHANGED
data/lib/yerba/location.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Yerba
|
|
4
|
-
Location = Data.define(
|
|
4
|
+
Location = Data.define(
|
|
5
|
+
:start_line, :start_column, :end_line, :end_column, :start_offset, :end_offset,
|
|
6
|
+
:start_character_column, :end_character_column
|
|
7
|
+
) do
|
|
8
|
+
def initialize(start_column:, end_column:, start_character_column: start_column, end_character_column: end_column, **)
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
end
|
|
5
12
|
end
|
data/lib/yerba/map.rb
CHANGED
|
@@ -40,13 +40,14 @@ module Yerba
|
|
|
40
40
|
all_keys = keys
|
|
41
41
|
key_index = all_keys.index(key.to_s)
|
|
42
42
|
after_key = key_index&.positive? ? all_keys[key_index - 1] : nil
|
|
43
|
+
before_key = key_index&.zero? ? all_keys[1] : nil
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
document.insert(new_path, coerced, after: after_key, plain: true)
|
|
45
|
+
if after_key || before_key
|
|
46
|
+
document.delete(new_path)
|
|
47
|
+
document.insert(new_path, coerced, after: after_key, before: before_key, plain: true)
|
|
48
48
|
else
|
|
49
|
-
document.
|
|
49
|
+
document.set(new_path, coerce_value(value, style: :flow), plain: true)
|
|
50
|
+
document[new_path].collection_style = :block unless value.empty?
|
|
50
51
|
end
|
|
51
52
|
elsif document.exists?(new_path)
|
|
52
53
|
document.set(new_path, coerced, plain: is_collection)
|
|
@@ -93,6 +94,12 @@ module Yerba
|
|
|
93
94
|
return self
|
|
94
95
|
end
|
|
95
96
|
|
|
97
|
+
if (tree = current_children)
|
|
98
|
+
tree.each_key { |name| yield name, tree[name]&.dup }
|
|
99
|
+
|
|
100
|
+
return self
|
|
101
|
+
end
|
|
102
|
+
|
|
96
103
|
names = keys
|
|
97
104
|
values = document.get_all(@selector.empty? ? "*" : "#{@selector}.*")
|
|
98
105
|
|
|
@@ -124,6 +131,9 @@ module Yerba
|
|
|
124
131
|
|
|
125
132
|
def value_at(key)
|
|
126
133
|
if connected?
|
|
134
|
+
child = current_children&.[](key.to_s)
|
|
135
|
+
return child.value if child.is_a?(Scalar)
|
|
136
|
+
|
|
127
137
|
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
128
138
|
document.value_at(new_path)
|
|
129
139
|
else
|
|
@@ -135,7 +145,7 @@ module Yerba
|
|
|
135
145
|
#
|
|
136
146
|
# When +key+ is given and the map is connected to a document, deletes that key
|
|
137
147
|
# from the map in the YAML document. When no +key+ is given and the map is
|
|
138
|
-
# connected, removes the entire map node at its selector
|
|
148
|
+
# connected, removes the entire map node at its selector. When not connected
|
|
139
149
|
# to a document, delegates to the underlying Hash.
|
|
140
150
|
#
|
|
141
151
|
# Returns +self+.
|
data/lib/yerba/node.rb
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Yerba
|
|
4
|
+
module NodeTree
|
|
5
|
+
protected
|
|
6
|
+
|
|
7
|
+
def tree_node?
|
|
8
|
+
!@tree.nil? && @tree.equal?(document.nodes)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def tree_children
|
|
12
|
+
@children
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def valueless?
|
|
16
|
+
@valueless == true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def attach_tree(tree, children, valueless)
|
|
20
|
+
@tree = tree
|
|
21
|
+
@children = children
|
|
22
|
+
@valueless = valueless
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
4
26
|
module Node
|
|
27
|
+
include NodeTree
|
|
28
|
+
|
|
5
29
|
attr_reader :selector, :location, :key
|
|
6
30
|
|
|
7
31
|
def file_path
|
|
@@ -26,6 +50,17 @@ module Yerba
|
|
|
26
50
|
document.source(@selector)
|
|
27
51
|
end
|
|
28
52
|
|
|
53
|
+
def children
|
|
54
|
+
tree = current_children
|
|
55
|
+
|
|
56
|
+
case tree
|
|
57
|
+
when Hash
|
|
58
|
+
tree.transform_values { |child| child&.dup }
|
|
59
|
+
when Array
|
|
60
|
+
tree.map { |child| child&.dup }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
29
64
|
module ClassMethods
|
|
30
65
|
def from_document(document, selector, location = nil, key = nil, **attributes)
|
|
31
66
|
instance = allocate
|
|
@@ -58,6 +93,12 @@ module Yerba
|
|
|
58
93
|
|
|
59
94
|
private
|
|
60
95
|
|
|
96
|
+
def current_children
|
|
97
|
+
node = tree_node? ? self : document&.[](@selector)
|
|
98
|
+
|
|
99
|
+
node.tree_children if node.is_a?(Node) && node.tree_node?
|
|
100
|
+
end
|
|
101
|
+
|
|
61
102
|
def init_node(document, selector, location, key, file_path, line)
|
|
62
103
|
@document = document
|
|
63
104
|
@selector = selector
|
data/lib/yerba/query_result.rb
CHANGED
|
@@ -4,47 +4,70 @@ module Yerba
|
|
|
4
4
|
class QueryResult
|
|
5
5
|
include Enumerable
|
|
6
6
|
|
|
7
|
-
def initialize(sequence, indices)
|
|
7
|
+
def initialize(sequence, indices, &query)
|
|
8
8
|
@sequence = sequence
|
|
9
9
|
@indices = indices
|
|
10
|
+
@query = query
|
|
11
|
+
@tree = current_tree
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def each
|
|
13
15
|
return enum_for(:each) unless block_given?
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
current_indices.each { |index| yield @sequence[index] }
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def [](position)
|
|
19
|
-
index =
|
|
21
|
+
index = current_indices[position]
|
|
20
22
|
|
|
21
23
|
@sequence[index] if index
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
def first
|
|
25
|
-
self[0]
|
|
26
|
+
def first(count = nil)
|
|
27
|
+
return self[0] if count.nil?
|
|
28
|
+
|
|
29
|
+
current_indices.first(count).map { |index| @sequence[index] }
|
|
26
30
|
end
|
|
27
31
|
|
|
28
|
-
def last
|
|
29
|
-
self[-1]
|
|
32
|
+
def last(count = nil)
|
|
33
|
+
return self[-1] if count.nil?
|
|
34
|
+
|
|
35
|
+
current_indices.last(count).map { |index| @sequence[index] }
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
def length
|
|
33
|
-
|
|
39
|
+
current_indices.length
|
|
34
40
|
end
|
|
35
41
|
alias size length
|
|
36
42
|
alias count length
|
|
37
43
|
|
|
38
44
|
def empty?
|
|
39
|
-
|
|
45
|
+
current_indices.empty?
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
def indices
|
|
43
|
-
|
|
49
|
+
current_indices.dup
|
|
44
50
|
end
|
|
45
51
|
|
|
46
52
|
def inspect
|
|
47
53
|
"#<Yerba::QueryResult length=#{length}>"
|
|
48
54
|
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def current_indices
|
|
59
|
+
tree = current_tree
|
|
60
|
+
|
|
61
|
+
if @query && !tree.equal?(@tree)
|
|
62
|
+
@indices = @query.call
|
|
63
|
+
@tree = tree
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@indices
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def current_tree
|
|
70
|
+
@sequence&.document&.nodes
|
|
71
|
+
end
|
|
49
72
|
end
|
|
50
73
|
end
|
data/lib/yerba/scalar.rb
CHANGED
|
@@ -12,6 +12,11 @@ module Yerba
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def value
|
|
15
|
+
live = live_document if @selector
|
|
16
|
+
adopt_current_node(live) if live && !tree_node?
|
|
17
|
+
|
|
18
|
+
return @value.is_a?(String) ? @value.dup : @value if tree_node?
|
|
19
|
+
|
|
15
20
|
@value ||= document&.value_at(@selector)
|
|
16
21
|
end
|
|
17
22
|
|
|
@@ -72,8 +77,32 @@ module Yerba
|
|
|
72
77
|
end
|
|
73
78
|
end
|
|
74
79
|
|
|
80
|
+
protected
|
|
81
|
+
|
|
82
|
+
def stored_value
|
|
83
|
+
@value
|
|
84
|
+
end
|
|
85
|
+
|
|
75
86
|
private
|
|
76
87
|
|
|
88
|
+
def live_document
|
|
89
|
+
return @document if @document
|
|
90
|
+
|
|
91
|
+
document if @file_path && Document.cache.key?(@file_path)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def adopt_current_node(live)
|
|
95
|
+
node = live[@selector]
|
|
96
|
+
|
|
97
|
+
if node.is_a?(Scalar) && node.tree_node?
|
|
98
|
+
@value = node.stored_value
|
|
99
|
+
attach_tree(live.nodes, nil, node.valueless?)
|
|
100
|
+
else
|
|
101
|
+
@value = nil
|
|
102
|
+
@tree = nil
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
77
106
|
def init_from(value: nil, quote_style: nil, **)
|
|
78
107
|
@value = value
|
|
79
108
|
@quote_style = quote_style
|
data/lib/yerba/selector.rb
CHANGED
|
@@ -10,11 +10,12 @@ module Yerba
|
|
|
10
10
|
# Yerba::Selector.parse("database.*").segments # => ["database", :all_keys]
|
|
11
11
|
# Yerba::Selector.parse(".title").relative? # => true
|
|
12
12
|
#
|
|
13
|
-
# Keys are Strings, indexes Integers, `[]` is `:all_items` and `*` is `:all_keys`.
|
|
13
|
+
# Keys are Strings, indexes Integers (negative from the end), `[]` is `:all_items` and `*` is `:all_keys`.
|
|
14
14
|
#
|
|
15
15
|
class Selector
|
|
16
16
|
ALL_KEYS = :all_keys
|
|
17
17
|
ALL_ITEMS = :all_items
|
|
18
|
+
CACHE_LIMIT = 10_000
|
|
18
19
|
|
|
19
20
|
attr_reader :segments
|
|
20
21
|
|
|
@@ -24,6 +25,7 @@ module Yerba
|
|
|
24
25
|
string = selector.to_s
|
|
25
26
|
|
|
26
27
|
cache[string] ||= begin
|
|
28
|
+
cache.clear if cache.size >= CACHE_LIMIT
|
|
27
29
|
parsed = native_parse(string)
|
|
28
30
|
|
|
29
31
|
new(parsed["segments"].map { |segment| decode(segment) }, relative: parsed["relative"], source: string)
|
data/lib/yerba/sequence.rb
CHANGED
|
@@ -45,6 +45,9 @@ module Yerba
|
|
|
45
45
|
|
|
46
46
|
def value_at(index)
|
|
47
47
|
if connected?
|
|
48
|
+
child = current_children&.[](index) if index.is_a?(Integer) && !index.negative?
|
|
49
|
+
return child.value if child.is_a?(Scalar)
|
|
50
|
+
|
|
48
51
|
new_path = "#{@selector}[#{index}]"
|
|
49
52
|
document.value_at(new_path)
|
|
50
53
|
else
|
|
@@ -73,15 +76,15 @@ module Yerba
|
|
|
73
76
|
|
|
74
77
|
def concat(items)
|
|
75
78
|
if connected?
|
|
76
|
-
|
|
79
|
+
values = items.map do |item|
|
|
77
80
|
case item
|
|
78
81
|
when Map then item.to_hash
|
|
79
|
-
when
|
|
80
|
-
else
|
|
82
|
+
when Scalar then item.value
|
|
83
|
+
else item
|
|
81
84
|
end
|
|
82
85
|
end
|
|
83
86
|
|
|
84
|
-
document.insert_objects(@selector,
|
|
87
|
+
document.insert_objects(@selector, values)
|
|
85
88
|
else
|
|
86
89
|
@data.concat(items)
|
|
87
90
|
end
|
|
@@ -92,6 +95,12 @@ module Yerba
|
|
|
92
95
|
def each(&)
|
|
93
96
|
return enum_for(:each) unless block_given?
|
|
94
97
|
|
|
98
|
+
if connected? && (tree = current_children)
|
|
99
|
+
tree.each { |child| yield child&.dup }
|
|
100
|
+
|
|
101
|
+
return self
|
|
102
|
+
end
|
|
103
|
+
|
|
95
104
|
if connected?
|
|
96
105
|
items = document.get_all("#{@selector}[]")
|
|
97
106
|
|
|
@@ -114,7 +123,7 @@ module Yerba
|
|
|
114
123
|
end
|
|
115
124
|
|
|
116
125
|
def where(selector = nil, value = nil, **criteria)
|
|
117
|
-
QueryResult.new(self, indices_of(selector, value, **criteria))
|
|
126
|
+
QueryResult.new(self, indices_of(selector, value, **criteria)) { indices_of(selector, value, **criteria) }
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
def pluck(*fields)
|
|
@@ -211,28 +220,24 @@ module Yerba
|
|
|
211
220
|
end
|
|
212
221
|
|
|
213
222
|
def length
|
|
214
|
-
|
|
215
|
-
scalar_items = document.value_at("#{@selector}[]")
|
|
223
|
+
return @data.length unless connected?
|
|
216
224
|
|
|
217
|
-
|
|
218
|
-
scalar_items.length
|
|
219
|
-
else
|
|
220
|
-
data = document.value_at(@selector)
|
|
221
|
-
|
|
222
|
-
data.is_a?(Array) ? data.length : 0
|
|
223
|
-
end
|
|
224
|
-
else
|
|
225
|
-
@data.length
|
|
226
|
-
end
|
|
225
|
+
current_children&.size || document.length_at(@selector)
|
|
227
226
|
end
|
|
228
227
|
alias size length
|
|
229
228
|
|
|
230
|
-
def first
|
|
231
|
-
self[0]
|
|
229
|
+
def first(count = nil)
|
|
230
|
+
return self[0] if count.nil?
|
|
231
|
+
|
|
232
|
+
super
|
|
232
233
|
end
|
|
233
234
|
|
|
234
|
-
def last
|
|
235
|
-
|
|
235
|
+
def last(count = nil)
|
|
236
|
+
size = length
|
|
237
|
+
return self[size - 1] if count.nil?
|
|
238
|
+
raise ArgumentError, "negative array size" if count.negative?
|
|
239
|
+
|
|
240
|
+
([size - count, 0].max...size).map { |index| self[index] }
|
|
236
241
|
end
|
|
237
242
|
|
|
238
243
|
def remove(value)
|
|
@@ -263,15 +268,15 @@ module Yerba
|
|
|
263
268
|
self
|
|
264
269
|
end
|
|
265
270
|
|
|
266
|
-
def sort(by: nil, case_sensitive: false)
|
|
267
|
-
document&.sort(@selector, by: by, case_sensitive: case_sensitive)
|
|
271
|
+
def sort(by: nil, order: nil, case_sensitive: false)
|
|
272
|
+
document&.sort(@selector, by: by, order: order, case_sensitive: case_sensitive)
|
|
268
273
|
|
|
269
274
|
self
|
|
270
275
|
end
|
|
271
276
|
|
|
272
277
|
# Deletes the entire sequence node from the YAML document.
|
|
273
278
|
#
|
|
274
|
-
# Removes the sequence at its selector
|
|
279
|
+
# Removes the sequence at its selector from the parent document.
|
|
275
280
|
# Has no effect if the sequence is not connected to a document.
|
|
276
281
|
#
|
|
277
282
|
# Returns the document, or +nil+ if the sequence is not connected to a document.
|
|
@@ -345,8 +350,8 @@ module Yerba
|
|
|
345
350
|
|
|
346
351
|
private
|
|
347
352
|
|
|
348
|
-
def dig_into(hash,
|
|
349
|
-
keys =
|
|
353
|
+
def dig_into(hash, selector)
|
|
354
|
+
keys = selector.split(".")
|
|
350
355
|
|
|
351
356
|
keys.reduce(hash) { |current, key| current.is_a?(Hash) ? current[key] : nil }
|
|
352
357
|
end
|
|
@@ -356,8 +361,8 @@ module Yerba
|
|
|
356
361
|
|
|
357
362
|
criteria.each do |field, value|
|
|
358
363
|
if value.is_a?(Hash)
|
|
359
|
-
flatten_hash("#{field}[]", value).each do |
|
|
360
|
-
expanded << [
|
|
364
|
+
flatten_hash("#{field}[]", value).each do |selector, leaf_value|
|
|
365
|
+
expanded << [selector, leaf_value]
|
|
361
366
|
end
|
|
362
367
|
elsif value.is_a?(Array)
|
|
363
368
|
value.each do |item|
|
|
@@ -375,12 +380,12 @@ module Yerba
|
|
|
375
380
|
result = {}
|
|
376
381
|
|
|
377
382
|
hash.each do |key, value|
|
|
378
|
-
|
|
383
|
+
selector = "#{prefix}.#{key}"
|
|
379
384
|
|
|
380
385
|
if value.is_a?(Hash)
|
|
381
|
-
flatten_hash("#{
|
|
386
|
+
flatten_hash("#{selector}[]", value).each { |nested_selector, leaf| result[nested_selector] = leaf }
|
|
382
387
|
else
|
|
383
|
-
result[
|
|
388
|
+
result[selector] = value
|
|
384
389
|
end
|
|
385
390
|
end
|
|
386
391
|
|
|
@@ -399,8 +404,8 @@ module Yerba
|
|
|
399
404
|
end
|
|
400
405
|
end
|
|
401
406
|
|
|
402
|
-
def dig_values(hash,
|
|
403
|
-
parts =
|
|
407
|
+
def dig_values(hash, selector)
|
|
408
|
+
parts = selector.split(".")
|
|
404
409
|
current = [hash]
|
|
405
410
|
|
|
406
411
|
parts.each do |part|
|
data/lib/yerba/version.rb
CHANGED
data/rust/Cargo.lock
CHANGED