yerba 0.2.0-arm-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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +528 -0
- data/exe/yerba +6 -0
- data/ext/yerba/extconf.rb +111 -0
- data/ext/yerba/yerba.c +752 -0
- 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 +31 -0
- data/lib/yerba/document.rb +59 -0
- data/lib/yerba/formatting.rb +18 -0
- data/lib/yerba/location.rb +5 -0
- data/lib/yerba/map.rb +166 -0
- data/lib/yerba/scalar.rb +85 -0
- data/lib/yerba/sequence.rb +182 -0
- data/lib/yerba/version.rb +5 -0
- data/lib/yerba.rb +131 -0
- data/rust/Cargo.lock +805 -0
- data/rust/Cargo.toml +36 -0
- data/rust/build.rs +11 -0
- data/rust/cbindgen.toml +27 -0
- data/rust/rustfmt.toml +2 -0
- data/rust/src/commands/apply.rs +5 -0
- data/rust/src/commands/blank_lines.rs +58 -0
- data/rust/src/commands/check.rs +5 -0
- data/rust/src/commands/delete.rs +35 -0
- data/rust/src/commands/get.rs +194 -0
- data/rust/src/commands/init.rs +89 -0
- data/rust/src/commands/insert.rs +106 -0
- data/rust/src/commands/mate.rs +55 -0
- data/rust/src/commands/mod.rs +349 -0
- data/rust/src/commands/move_item.rs +54 -0
- data/rust/src/commands/move_key.rs +87 -0
- data/rust/src/commands/quote_style.rs +62 -0
- data/rust/src/commands/remove.rs +35 -0
- data/rust/src/commands/rename.rs +37 -0
- data/rust/src/commands/set.rs +59 -0
- data/rust/src/commands/sort.rs +52 -0
- data/rust/src/commands/sort_keys.rs +62 -0
- data/rust/src/commands/version.rs +8 -0
- data/rust/src/document.rs +2237 -0
- data/rust/src/error.rs +45 -0
- data/rust/src/ffi.rs +991 -0
- data/rust/src/json.rs +128 -0
- data/rust/src/lib.rs +29 -0
- data/rust/src/main.rs +72 -0
- data/rust/src/quote_style.rs +42 -0
- data/rust/src/selector.rs +241 -0
- data/rust/src/syntax.rs +262 -0
- data/rust/src/yaml_writer.rs +89 -0
- data/rust/src/yerbafile.rs +475 -0
- data/sig/yerba.rbs +3 -0
- data/yerba.gemspec +52 -0
- metadata +108 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Collection
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
def initialize(glob)
|
|
8
|
+
@glob = glob
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def each
|
|
12
|
+
Dir.glob(@glob).each { |path| yield Document.new(path) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def get(path)
|
|
16
|
+
self.class.get(@glob, path)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def find(path, condition: nil, select: nil)
|
|
20
|
+
self.class.find(@glob, path, condition: condition, select: select)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def apply!
|
|
24
|
+
each do |document|
|
|
25
|
+
yield document
|
|
26
|
+
|
|
27
|
+
document.save!
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Document
|
|
5
|
+
def root
|
|
6
|
+
self[""]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def map?
|
|
10
|
+
root.is_a?(Map)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sequence?
|
|
14
|
+
root.is_a?(Sequence)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_h
|
|
18
|
+
get_value("")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_a
|
|
22
|
+
get_value("")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_yaml
|
|
26
|
+
to_s
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def dig(*keys)
|
|
30
|
+
result = keys.reduce(self) { |node, key| node.nil? ? nil : node[key] }
|
|
31
|
+
|
|
32
|
+
result&.value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def at_path(path)
|
|
36
|
+
if path.include?("[]")
|
|
37
|
+
values = get(path)
|
|
38
|
+
return [] unless values.is_a?(Array)
|
|
39
|
+
|
|
40
|
+
path.sub("[]", "")
|
|
41
|
+
|
|
42
|
+
values.each_with_index.map do |_value, index|
|
|
43
|
+
resolved_path = path.sub("[]", "[#{index}]")
|
|
44
|
+
self[resolved_path]
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
self[path]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def inspect
|
|
52
|
+
if path
|
|
53
|
+
"#<Yerba::Document path=#{path.inspect}>"
|
|
54
|
+
else
|
|
55
|
+
"#<Yerba::Document (parsed)>"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
module Formatting
|
|
5
|
+
def self.quote(value, style)
|
|
6
|
+
case style
|
|
7
|
+
when :double
|
|
8
|
+
escaped = value.to_s.gsub("\\", "\\\\").gsub('"', '\\"')
|
|
9
|
+
"\"#{escaped}\""
|
|
10
|
+
when :single
|
|
11
|
+
escaped = value.to_s.gsub("'", "''")
|
|
12
|
+
"'#{escaped}'"
|
|
13
|
+
else
|
|
14
|
+
value.to_s
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/yerba/map.rb
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Map
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
attr_reader :selector, :location, :key
|
|
8
|
+
|
|
9
|
+
def initialize(document_or_hash = nil, selector = nil, location = nil, key = nil)
|
|
10
|
+
if document_or_hash.is_a?(Document)
|
|
11
|
+
@document = document_or_hash
|
|
12
|
+
@selector = selector
|
|
13
|
+
@location = location
|
|
14
|
+
@key = key
|
|
15
|
+
@data = nil
|
|
16
|
+
elsif document_or_hash.is_a?(Hash)
|
|
17
|
+
@document = nil
|
|
18
|
+
@selector = nil
|
|
19
|
+
@location = nil
|
|
20
|
+
@data = document_or_hash
|
|
21
|
+
else
|
|
22
|
+
@document = nil
|
|
23
|
+
@selector = nil
|
|
24
|
+
@location = nil
|
|
25
|
+
@data = {}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def [](key)
|
|
30
|
+
if @document
|
|
31
|
+
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
32
|
+
@document[new_path]
|
|
33
|
+
else
|
|
34
|
+
@data[key]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def []=(key, value)
|
|
39
|
+
if @document
|
|
40
|
+
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
41
|
+
@document.set(new_path, value)
|
|
42
|
+
else
|
|
43
|
+
@data[key] = value
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def insert(key, value, before: nil, after: nil)
|
|
48
|
+
if @document
|
|
49
|
+
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
50
|
+
@document.insert(new_path, value.to_s, before: before, after: after)
|
|
51
|
+
else
|
|
52
|
+
@data[key] = value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def sort_keys(order)
|
|
59
|
+
@document&.sort_keys(@selector, order)
|
|
60
|
+
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def keys
|
|
65
|
+
if @document
|
|
66
|
+
results = @document.find(@selector)
|
|
67
|
+
return [] unless results.is_a?(Array) && results.first.is_a?(Hash)
|
|
68
|
+
|
|
69
|
+
results.first.keys
|
|
70
|
+
else
|
|
71
|
+
@data.keys
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def each(&)
|
|
76
|
+
return enum_for(:each) unless block_given?
|
|
77
|
+
|
|
78
|
+
if @document
|
|
79
|
+
keys.each { |key| yield key, self[key] }
|
|
80
|
+
else
|
|
81
|
+
@data.each(&)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def dig(*keys)
|
|
86
|
+
if @document
|
|
87
|
+
result = keys.reduce(self) { |node, key| node.nil? ? nil : node[key] }
|
|
88
|
+
result&.value
|
|
89
|
+
else
|
|
90
|
+
@data.dig(*keys)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def delete(key = nil)
|
|
95
|
+
if key && @document
|
|
96
|
+
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
97
|
+
@document.delete(new_path)
|
|
98
|
+
elsif @document
|
|
99
|
+
@document.delete(@selector)
|
|
100
|
+
else
|
|
101
|
+
@data.delete(key)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def key?(key)
|
|
108
|
+
if @document
|
|
109
|
+
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
110
|
+
@document.exists?(new_path)
|
|
111
|
+
else
|
|
112
|
+
@data.key?(key)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
alias has_key? key?
|
|
116
|
+
alias include? key?
|
|
117
|
+
|
|
118
|
+
def value
|
|
119
|
+
@data || nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def to_h
|
|
123
|
+
if @document
|
|
124
|
+
results = @document.find(@selector)
|
|
125
|
+
results&.first || {}
|
|
126
|
+
else
|
|
127
|
+
@data
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
alias to_hash to_h
|
|
131
|
+
|
|
132
|
+
def to_yaml
|
|
133
|
+
to_hash.map do |key, val|
|
|
134
|
+
formatted = format_value(val)
|
|
135
|
+
"#{key}: #{formatted}"
|
|
136
|
+
end.join("\n")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def inspect
|
|
140
|
+
if @document
|
|
141
|
+
results = @document.find(@selector)
|
|
142
|
+
|
|
143
|
+
if results.is_a?(Array) && !results.empty? && results.first.is_a?(Hash)
|
|
144
|
+
map_keys = results.first.keys.first(5)
|
|
145
|
+
preview = map_keys.map { |key| "#{key}: #{results.first[key].inspect}" }.join(", ")
|
|
146
|
+
|
|
147
|
+
"#<Yerba::Map selector=#{@selector.inspect} {#{preview}}>"
|
|
148
|
+
else
|
|
149
|
+
"#<Yerba::Map selector=#{@selector.inspect}>"
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
"#<Yerba::Map {#{@data.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")}}>"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def format_value(value)
|
|
159
|
+
case value
|
|
160
|
+
when Scalar then value.to_yaml
|
|
161
|
+
when nil then "null"
|
|
162
|
+
else value.to_s
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
data/lib/yerba/scalar.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Scalar
|
|
5
|
+
attr_reader :selector, :location, :key
|
|
6
|
+
|
|
7
|
+
def initialize(document_or_value, selector_or_opts = nil, value = nil, location = nil, key = nil, quote_style: nil)
|
|
8
|
+
if document_or_value.is_a?(Document) || document_or_value.nil?
|
|
9
|
+
@document = document_or_value
|
|
10
|
+
@selector = selector_or_opts
|
|
11
|
+
@value = value
|
|
12
|
+
@location = location
|
|
13
|
+
@key = key
|
|
14
|
+
@quote_style = quote_style
|
|
15
|
+
else
|
|
16
|
+
@document = nil
|
|
17
|
+
@selector = nil
|
|
18
|
+
@value = document_or_value
|
|
19
|
+
@location = nil
|
|
20
|
+
@key = nil
|
|
21
|
+
@quote_style = selector_or_opts.is_a?(Hash) ? selector_or_opts[:quote_style] : quote_style
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def value
|
|
26
|
+
@value ||= @document&.get(@selector)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def quote_style
|
|
30
|
+
@quote_style || @document&.get_quote_style(@selector)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def quote_style=(style)
|
|
34
|
+
@document&.set_quote_style(@selector, style)
|
|
35
|
+
|
|
36
|
+
@quote_style = style
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def value=(new_value)
|
|
40
|
+
@document&.set(@selector, new_value)
|
|
41
|
+
@value = new_value
|
|
42
|
+
end
|
|
43
|
+
alias set value=
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
value.to_s
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_str
|
|
50
|
+
to_s
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_i
|
|
54
|
+
value.to_i
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_f
|
|
58
|
+
value.to_f
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def ==(other)
|
|
62
|
+
value == other
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_yaml
|
|
66
|
+
case value
|
|
67
|
+
when nil then "null"
|
|
68
|
+
when String then Formatting.quote(value, quote_style)
|
|
69
|
+
else value.to_s
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def delete
|
|
74
|
+
@document&.delete(@selector)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def inspect
|
|
78
|
+
if @selector
|
|
79
|
+
"#<Yerba::Scalar selector=#{@selector.inspect} value=#{value.inspect}>"
|
|
80
|
+
else
|
|
81
|
+
"#<Yerba::Scalar value=#{value.inspect} quote_style=#{quote_style.inspect}>"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yerba
|
|
4
|
+
class Sequence
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
attr_reader :selector, :location, :key
|
|
8
|
+
|
|
9
|
+
def initialize(document_or_array = nil, selector = nil, location = nil, key = nil)
|
|
10
|
+
if document_or_array.is_a?(Document)
|
|
11
|
+
@document = document_or_array
|
|
12
|
+
@selector = selector
|
|
13
|
+
@location = location
|
|
14
|
+
@key = key
|
|
15
|
+
@data = nil
|
|
16
|
+
elsif document_or_array.is_a?(Array)
|
|
17
|
+
@document = nil
|
|
18
|
+
@selector = nil
|
|
19
|
+
@location = nil
|
|
20
|
+
@data = document_or_array
|
|
21
|
+
else
|
|
22
|
+
@document = nil
|
|
23
|
+
@selector = nil
|
|
24
|
+
@location = nil
|
|
25
|
+
@data = []
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def [](index)
|
|
30
|
+
if @document
|
|
31
|
+
new_path = "#{@selector}[#{index}]"
|
|
32
|
+
@document[new_path]
|
|
33
|
+
else
|
|
34
|
+
@data[index]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def <<(item)
|
|
39
|
+
if @document
|
|
40
|
+
case item
|
|
41
|
+
when Map
|
|
42
|
+
@document.insert_object(@selector, item.to_hash)
|
|
43
|
+
when Hash
|
|
44
|
+
@document.insert_object(@selector, item)
|
|
45
|
+
when Scalar
|
|
46
|
+
@document.insert(@selector, item.to_yaml)
|
|
47
|
+
else
|
|
48
|
+
formatted = format_for_insert(item.to_s)
|
|
49
|
+
@document.insert(@selector, formatted)
|
|
50
|
+
end
|
|
51
|
+
else
|
|
52
|
+
@data << item
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def each
|
|
59
|
+
return enum_for(:each) unless block_given?
|
|
60
|
+
|
|
61
|
+
length.times { |i| yield self[i] }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def length
|
|
65
|
+
if @document
|
|
66
|
+
scalar_items = @document.get("#{@selector}[]")
|
|
67
|
+
|
|
68
|
+
if scalar_items.is_a?(Array) && !scalar_items.empty?
|
|
69
|
+
scalar_items.length
|
|
70
|
+
else
|
|
71
|
+
data = @document.get_value(@selector)
|
|
72
|
+
data.is_a?(Array) ? data.length : 0
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
@data.length
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
alias size length
|
|
79
|
+
|
|
80
|
+
def first
|
|
81
|
+
self[0]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def last
|
|
85
|
+
self[length - 1] # rubocop:disable Style/NegativeArrayIndex
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def remove(value)
|
|
89
|
+
@document&.remove(@selector, value.to_s)
|
|
90
|
+
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def delete_at(index)
|
|
95
|
+
@document&.remove_at(@selector, index)
|
|
96
|
+
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def delete_if
|
|
101
|
+
return enum_for(:delete_if) unless block_given?
|
|
102
|
+
|
|
103
|
+
indices_to_remove = []
|
|
104
|
+
|
|
105
|
+
length.times do |index|
|
|
106
|
+
indices_to_remove << index if yield self[index]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
indices_to_remove.reverse_each do |index|
|
|
110
|
+
@document&.remove_at(@selector, index)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def sort(by: nil, case_sensitive: false)
|
|
117
|
+
@document&.sort(@selector, by: by, case_sensitive: case_sensitive)
|
|
118
|
+
|
|
119
|
+
self
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def delete
|
|
123
|
+
@document&.delete(@selector)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def value
|
|
127
|
+
items
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def to_a
|
|
131
|
+
@data || items
|
|
132
|
+
end
|
|
133
|
+
alias to_ary to_a
|
|
134
|
+
|
|
135
|
+
def to_yaml
|
|
136
|
+
items.map do |item|
|
|
137
|
+
case item
|
|
138
|
+
when Scalar then "- #{item.to_yaml}"
|
|
139
|
+
when Map then "- #{item.to_yaml.gsub("\n", "\n ")}"
|
|
140
|
+
else "- #{item}"
|
|
141
|
+
end
|
|
142
|
+
end.join("\n")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def inspect
|
|
146
|
+
list = items
|
|
147
|
+
preview = list.first(5).map(&:inspect).join(", ")
|
|
148
|
+
suffix = list.length > 5 ? ", ... (#{list.length} items)" : ""
|
|
149
|
+
|
|
150
|
+
if @selector
|
|
151
|
+
"#<Yerba::Sequence selector=#{@selector.inspect} [#{preview}#{suffix}]>"
|
|
152
|
+
else
|
|
153
|
+
"#<Yerba::Sequence [#{preview}#{suffix}]>"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
def format_for_insert(value)
|
|
160
|
+
Formatting.quote(value, detect_quote_style)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def detect_quote_style
|
|
164
|
+
@document.get_quote_style("#{@selector}[0]")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def items
|
|
168
|
+
if @document
|
|
169
|
+
result = @document.get("#{@selector}[]")
|
|
170
|
+
|
|
171
|
+
if result.is_a?(Array) && !result.empty?
|
|
172
|
+
result
|
|
173
|
+
else
|
|
174
|
+
data = @document.get_value(@selector)
|
|
175
|
+
data.is_a?(Array) ? data : []
|
|
176
|
+
end
|
|
177
|
+
else
|
|
178
|
+
@data
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
data/lib/yerba.rb
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "yerba/version"
|
|
4
|
+
require_relative "yerba/location"
|
|
5
|
+
require_relative "yerba/formatting"
|
|
6
|
+
require_relative "yerba/scalar"
|
|
7
|
+
require_relative "yerba/map"
|
|
8
|
+
require_relative "yerba/sequence"
|
|
9
|
+
require_relative "yerba/document"
|
|
10
|
+
require_relative "yerba/collection"
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
require "yerba/yerba"
|
|
14
|
+
rescue LoadError
|
|
15
|
+
# C extension not available, fall back to CLI mode
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module Yerba
|
|
19
|
+
class UnsupportedPlatformError < StandardError; end
|
|
20
|
+
class ExecutableNotFoundError < StandardError; end
|
|
21
|
+
class CompilationError < StandardError; end
|
|
22
|
+
|
|
23
|
+
GEM_NAME = "yerba"
|
|
24
|
+
EXECUTABLE_NAME = "yerba"
|
|
25
|
+
|
|
26
|
+
NATIVE_PLATFORMS = {
|
|
27
|
+
"arm64-darwin" => "arm64-darwin",
|
|
28
|
+
"x86_64-darwin" => "x86_64-darwin",
|
|
29
|
+
"aarch64-linux" => "aarch64-linux",
|
|
30
|
+
"arm64-linux" => "aarch64-linux",
|
|
31
|
+
"x86_64-linux" => "x86_64-linux",
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
def self.executable(exe_path: nil)
|
|
35
|
+
if exe_path
|
|
36
|
+
return exe_path if File.executable?(exe_path)
|
|
37
|
+
|
|
38
|
+
raise ExecutableNotFoundError, "yerba executable not found at #{exe_path}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if ENV["YERBA_INSTALL_DIR"]
|
|
42
|
+
install_dir_exe = File.join(ENV["YERBA_INSTALL_DIR"], EXECUTABLE_NAME)
|
|
43
|
+
|
|
44
|
+
if File.executable?(install_dir_exe)
|
|
45
|
+
return install_dir_exe
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
raise ExecutableNotFoundError, "yerba executable not found at #{install_dir_exe} (set by YERBA_INSTALL_DIR)"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
platform = Gem::Platform.local
|
|
52
|
+
platform_key = "#{platform.cpu}-#{platform.os}"
|
|
53
|
+
|
|
54
|
+
exe_directory = NATIVE_PLATFORMS[platform_key]
|
|
55
|
+
|
|
56
|
+
if exe_directory
|
|
57
|
+
exe_file = File.expand_path(
|
|
58
|
+
File.join("..", "exe", exe_directory, EXECUTABLE_NAME),
|
|
59
|
+
__dir__
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return exe_file if File.executable?(exe_file)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
compiled = compile_from_source
|
|
66
|
+
|
|
67
|
+
return compiled if compiled
|
|
68
|
+
|
|
69
|
+
if exe_directory
|
|
70
|
+
raise ExecutableNotFoundError,
|
|
71
|
+
"yerba executable not found at exe/#{exe_directory}/yerba. " \
|
|
72
|
+
"Try reinstalling the gem: gem install yerba"
|
|
73
|
+
else
|
|
74
|
+
raise UnsupportedPlatformError,
|
|
75
|
+
"yerba does not have a precompiled binary for #{platform_key}. " \
|
|
76
|
+
"Install Rust (https://rustup.rs) and reinstall the gem to compile from source, " \
|
|
77
|
+
"or set YERBA_INSTALL_DIR to use a custom binary."
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.compile_from_source
|
|
82
|
+
rust_dir = File.expand_path(File.join("..", "rust"), __dir__)
|
|
83
|
+
|
|
84
|
+
return nil unless File.exist?(File.join(rust_dir, "Cargo.toml"))
|
|
85
|
+
return nil unless system("cargo --version > /dev/null 2>&1")
|
|
86
|
+
|
|
87
|
+
platform = Gem::Platform.local
|
|
88
|
+
platform_key = "#{platform.cpu}-#{platform.os}"
|
|
89
|
+
exe_directory = File.join(File.expand_path(File.join("..", "exe", platform_key), __dir__))
|
|
90
|
+
exe_file = File.join(exe_directory, EXECUTABLE_NAME)
|
|
91
|
+
|
|
92
|
+
return exe_file if File.executable?(exe_file)
|
|
93
|
+
|
|
94
|
+
warn "yerba: No precompiled binary found. Compiling from source..."
|
|
95
|
+
|
|
96
|
+
FileUtils.mkdir_p(exe_directory)
|
|
97
|
+
|
|
98
|
+
unless system("cd #{rust_dir} && cargo build --release")
|
|
99
|
+
raise CompilationError, "Failed to compile yerba from source. Is Rust installed?"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
source_binary = File.join(rust_dir, "target", "release", EXECUTABLE_NAME)
|
|
103
|
+
|
|
104
|
+
unless File.exist?(source_binary)
|
|
105
|
+
raise CompilationError, "Compilation succeeded but binary not found at #{source_binary}"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
FileUtils.cp(source_binary, exe_file)
|
|
109
|
+
FileUtils.chmod(0o755, exe_file)
|
|
110
|
+
|
|
111
|
+
exe_file
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private_class_method :compile_from_source
|
|
115
|
+
|
|
116
|
+
def self.parse(content)
|
|
117
|
+
Document.parse(content)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.parse_file(path)
|
|
121
|
+
Document.new(path)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.document(path)
|
|
125
|
+
Document.new(path)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.files(glob)
|
|
129
|
+
Collection.new(glob)
|
|
130
|
+
end
|
|
131
|
+
end
|