subhash 0.1.2 → 0.1.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/.rubocop.yml +3 -0
- data/build/build_with_proxy.sh +1 -1
- data/lib/iarray.rb +86 -28
- data/lib/ihash.rb +137 -13
- data/lib/rh.rb +80 -0
- data/lib/subhash/version.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f0a051059b11209331fa863d593e6e7d2b0714c
|
4
|
+
data.tar.gz: 989f14524b03c77768a03e8d30588548d477980a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db164809d9c9bdd2e6f0c68e6e74c995d4ceb845c03ca2eaeef5e3f26ca00fed1123f39c1dd098e1e1cb63f58a4bc664121c084845039993e8d754d0892e9b21
|
7
|
+
data.tar.gz: cdcbc82160fa22fb53d1beca45df9cc2e0c43fa899151d87b3d6ae5fa6b9b62a279ed74ef65a4332acad9b297c75a9b3fc37f93c66f2a768923062620e4a7544
|
data/.rubocop.yml
CHANGED
data/build/build_with_proxy.sh
CHANGED
data/lib/iarray.rb
CHANGED
@@ -26,9 +26,12 @@ class Array
|
|
26
26
|
key = p[0]
|
27
27
|
sp = p.drop(1)
|
28
28
|
|
29
|
-
|
29
|
+
re, _, opts = _regexp(key)
|
30
|
+
return _keys_match_lexist(re, [], sp, opts) unless re.nil?
|
30
31
|
|
31
|
-
|
32
|
+
return _lexist_array(sp, key) if [Fixnum, Range].include?(key.class)
|
33
|
+
|
34
|
+
_loop_lexist_array(p, key)
|
32
35
|
end
|
33
36
|
|
34
37
|
# Recursive Hash deep level existence
|
@@ -54,9 +57,9 @@ class Array
|
|
54
57
|
re, res, opts = _regexp(key)
|
55
58
|
return _keys_match(re, res, sp, opts) unless re.nil?
|
56
59
|
|
57
|
-
return _get_array(sp, key) if
|
60
|
+
return _get_array(sp, key) if [Fixnum, Range].include?(key.class)
|
58
61
|
|
59
|
-
_loop_get_array(
|
62
|
+
_loop_get_array(key, p)
|
60
63
|
end
|
61
64
|
|
62
65
|
# return an exact clone of the recursive Array and Hash contents.
|
@@ -189,49 +192,78 @@ class Array
|
|
189
192
|
private
|
190
193
|
|
191
194
|
# Loop in array
|
192
|
-
def _loop_get_array(
|
195
|
+
def _loop_get_array(key, p)
|
196
|
+
if key =~ /=\[[0-9]+\.\.[0-9]+\]/
|
197
|
+
found = /=\[([0-9]+)\.\.([0-9]+)\]/.match(key)
|
198
|
+
extract = Range.new(found[1].to_i, found[2].to_i)
|
199
|
+
sp = p.drop(1)
|
200
|
+
elsif key =~ /=\[[0-9]+\]/
|
201
|
+
extract = /=\[([0-9]+)\]/.match(key)[1].to_i
|
202
|
+
sp = p.drop(1)
|
203
|
+
else
|
204
|
+
sp = p.clone
|
205
|
+
end
|
206
|
+
|
207
|
+
ret = _loop_array(sp)
|
208
|
+
|
209
|
+
return ret[extract] unless extract.nil?
|
210
|
+
return ret if ret.length > 0
|
211
|
+
nil
|
212
|
+
end
|
213
|
+
|
214
|
+
def _loop_array(sp)
|
193
215
|
ret = []
|
194
216
|
each do |e|
|
195
|
-
next unless e.is_a?(Hash)
|
196
|
-
next unless e.key?(key)
|
197
|
-
|
198
217
|
if sp.length == 0
|
199
|
-
ret << e
|
200
|
-
|
201
|
-
ret << e[key].rh_get(sp) if [Array, Hash].include?(e[key].class)
|
218
|
+
ret << e
|
219
|
+
next
|
202
220
|
end
|
221
|
+
|
222
|
+
next unless e.structured?
|
223
|
+
found = e.rh_get(*sp)
|
224
|
+
ret << found unless found.nil?
|
203
225
|
end
|
204
|
-
|
205
|
-
nil
|
226
|
+
ret
|
206
227
|
end
|
207
|
-
|
208
228
|
# Index provided. return the value of the index.
|
209
229
|
def _get_array(sp, key)
|
210
230
|
return self[key] if sp.length == 0
|
211
231
|
|
212
|
-
|
232
|
+
if key.is_a?(Range)
|
233
|
+
res = []
|
234
|
+
self[key].each do |k|
|
235
|
+
next unless k.structured?
|
236
|
+
res << k.rh_get(sp) if k.rh_exist?(sp)
|
237
|
+
end
|
238
|
+
res
|
239
|
+
else
|
240
|
+
self[key].rh_get(sp) if self[key].structured?
|
241
|
+
end
|
213
242
|
end
|
214
243
|
|
244
|
+
# Check in existing Array, Fixnum and Range data.
|
215
245
|
def _lexist_array(sp, key)
|
216
|
-
return 0
|
246
|
+
return 0 if _key_out_of_array(key)
|
247
|
+
|
217
248
|
return 1 if sp.length == 0
|
218
249
|
|
219
|
-
1 + self[key].rh_lexist?(sp) if
|
250
|
+
1 + self[key].rh_lexist?(sp) if self[key].structured?
|
251
|
+
end
|
252
|
+
|
253
|
+
def _key_out_of_array(key)
|
254
|
+
return !(key >= 0 && key < length) if key.is_a?(Fixnum)
|
255
|
+
|
256
|
+
test = 0..(length - 1)
|
257
|
+
!(test.include?(key.first) && test.include?(key.last))
|
220
258
|
end
|
221
259
|
|
222
|
-
|
260
|
+
# Check under each array element to get result.
|
261
|
+
def _loop_lexist_array(p, _key)
|
223
262
|
ret = []
|
224
263
|
each do |e|
|
225
|
-
next unless e.
|
226
|
-
next unless e.key?(key)
|
264
|
+
next unless e.structured?
|
227
265
|
|
228
|
-
|
229
|
-
ret << 1
|
230
|
-
else
|
231
|
-
res = 1
|
232
|
-
res += e[key].rh_lexist?(sp) if [Array, Hash].include?(e[key].class)
|
233
|
-
ret << res
|
234
|
-
end
|
266
|
+
ret << e.rh_lexist?(*p)
|
235
267
|
end
|
236
268
|
ret.length > 0 ? ret.max : 0
|
237
269
|
end
|
@@ -249,6 +281,27 @@ class Array
|
|
249
281
|
nil
|
250
282
|
end
|
251
283
|
|
284
|
+
def _keys_match_lexist(re, res, sp, _opts)
|
285
|
+
each do |e|
|
286
|
+
next unless e.is_a?(Hash)
|
287
|
+
|
288
|
+
_keys_match_lexist_hash(re, res, sp, e)
|
289
|
+
end
|
290
|
+
return res.max if res.length > 0
|
291
|
+
0
|
292
|
+
end
|
293
|
+
|
294
|
+
def _keys_match_lexist_hash(re, res, sp, e)
|
295
|
+
e.keys.sort.each do |k|
|
296
|
+
k_re = _key_to_s(k)
|
297
|
+
next unless re.match(k_re)
|
298
|
+
|
299
|
+
v = 1
|
300
|
+
v += e[k].rh_lexist?(sp) if sp.length > 0 && e[k].structured?
|
301
|
+
res << v
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
252
305
|
def _keys_match_hash(re, res, sp, e)
|
253
306
|
e.keys.sort.each do |k|
|
254
307
|
k_re = _key_to_s(k)
|
@@ -257,13 +310,18 @@ class Array
|
|
257
310
|
if sp.length == 0
|
258
311
|
_update_res(res, k, e[k])
|
259
312
|
else
|
260
|
-
v = e[k].rh_get(sp) if
|
313
|
+
v = e[k].rh_get(sp) if e[k].structured?
|
261
314
|
|
262
315
|
_update_res(res, k, v) unless v.nil?
|
263
316
|
end
|
264
317
|
end
|
265
318
|
res
|
266
319
|
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Internal function for merge.
|
323
|
+
class Array
|
324
|
+
private
|
267
325
|
|
268
326
|
def _rh_merge(result, data)
|
269
327
|
data = data.clone
|
data/lib/ihash.rb
CHANGED
@@ -64,21 +64,31 @@ class Hash
|
|
64
64
|
#
|
65
65
|
# # it is like searching for nothing...
|
66
66
|
# yVal.rh_lexist? => 0
|
67
|
-
|
67
|
+
#
|
68
|
+
# New features 0.1.3
|
69
|
+
#
|
68
70
|
def rh_lexist?(*p)
|
69
71
|
p = p.flatten
|
70
72
|
|
71
73
|
return 0 if p.length == 0
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
return 0 unless
|
75
|
+
key = p[0]
|
76
|
+
sp = p.drop(1)
|
77
|
+
|
78
|
+
selected, key = _erb_select(key)
|
79
|
+
return 0 unless selected
|
80
|
+
|
81
|
+
key = _erb_extract(key)
|
82
|
+
|
83
|
+
re, _, opts = _regexp(key)
|
84
|
+
return _keys_match_lexist(re, [], sp, opts) unless re.nil?
|
85
|
+
|
86
|
+
return 0 unless self.key?(key)
|
87
|
+
|
88
|
+
return 1 if p.length == 1
|
89
|
+
|
78
90
|
ret = 0
|
79
|
-
|
80
|
-
ret = self[p[0]].rh_lexist?(p.drop(1))
|
81
|
-
end
|
91
|
+
ret = self[key].rh_lexist?(*sp) if self[key].structured?
|
82
92
|
1 + ret
|
83
93
|
end
|
84
94
|
|
@@ -148,8 +158,8 @@ class Hash
|
|
148
158
|
# In the subhash structure, each hierachie tree level is a Hash or an
|
149
159
|
# Array.
|
150
160
|
#
|
151
|
-
# At a given level the top key will be interpreted as follow
|
152
|
-
# is:
|
161
|
+
# At a given level the top key will be interpreted as follow and used as
|
162
|
+
# data selection if the object is:
|
153
163
|
# - Hash:
|
154
164
|
# You can define key matching with Regexp or with a structured string:
|
155
165
|
# - Regexp or '/<Regexp>/' or '[<Regexp>]' :
|
@@ -200,7 +210,7 @@ class Hash
|
|
200
210
|
# data.rh_get => { :test => {:test2 => 'value1', :test3 => 'value2'},
|
201
211
|
# :test4 => 'value3'}
|
202
212
|
#
|
203
|
-
# New features:
|
213
|
+
# New features: 0.1.2
|
204
214
|
# data.rh_get(:test, /^test/) # => []
|
205
215
|
# data.rh_get(:test, /^:test/) # => ['value1', 'value2']
|
206
216
|
# data.rh_get(:test, /^:test.*/) # => ['value1', 'value2']
|
@@ -230,6 +240,95 @@ class Hash
|
|
230
240
|
# data.rh_get(:arr2, 1, :test7) # => 'value7'
|
231
241
|
# data.rh_get(:arr2, 0, :test7) # => nil
|
232
242
|
#
|
243
|
+
# New features: 0.1.3
|
244
|
+
#
|
245
|
+
# Introduce ERB context rh_get/exist?/lexist? functions:
|
246
|
+
# ERB can be used to select a subhash or extract a key.
|
247
|
+
#
|
248
|
+
# - ERB Selection
|
249
|
+
# The ERB selection is detected by a string containing
|
250
|
+
# '<%= ... %>|something'
|
251
|
+
# The ERB code must return a boolean or 'true' to consider the current
|
252
|
+
# data context as queriable with a key.
|
253
|
+
# 'something' can be any key (string, symbol or even an ERB extraction)
|
254
|
+
# - ERB Extraction
|
255
|
+
# The ERB selection is detected by a string containing simply
|
256
|
+
# '<%= ... %>'
|
257
|
+
# The result of that ERB call should return a string which will become a
|
258
|
+
# key to extract data from the current data context.
|
259
|
+
#
|
260
|
+
# NOTE! ERB convert any symbol using to_s. If you need to get a key as a
|
261
|
+
# symbol, you will to add : in front of the context string:
|
262
|
+
#
|
263
|
+
# Ex:
|
264
|
+
# RhContext.context = :test
|
265
|
+
# data.rh_get('<%= context =>') # is equivalent to data.rh_get('test')
|
266
|
+
#
|
267
|
+
# RhContext.context = ':test'
|
268
|
+
# data.rh_get('<%= context =>') # is equivalent to data.rh_get(:test)
|
269
|
+
#
|
270
|
+
# The ERB context by default contains:
|
271
|
+
# - at least a 'data' attribute. It contains the current Hash/Array
|
272
|
+
# level data in the data structure hierarchy.
|
273
|
+
# - optionally a 'context' attribute. Contains any kind of data.
|
274
|
+
# This is typically set before any call to rh_* functions.
|
275
|
+
#
|
276
|
+
# you can introduce more data in the context, by creating a derived class
|
277
|
+
# from RhContext.ERBConfig. This will ensure attribute data/context exist
|
278
|
+
# in the context.
|
279
|
+
# Ex:
|
280
|
+
#
|
281
|
+
# class MyContext < RhContext::ERBConfig
|
282
|
+
# attr_accessor :config # Added config in context
|
283
|
+
# end
|
284
|
+
#
|
285
|
+
# RhContext.erb = MyContext.new
|
286
|
+
# RhContext.erb.config = my_config
|
287
|
+
# data.rh_get(...)
|
288
|
+
#
|
289
|
+
# data = YAML.parse("---
|
290
|
+
# :test:
|
291
|
+
# :test2: value1
|
292
|
+
# :test3: value2
|
293
|
+
# :test4: value3
|
294
|
+
# :arr1: [ 4, value4]
|
295
|
+
# :arr2:
|
296
|
+
# - :test5: value5
|
297
|
+
# :test6: value6
|
298
|
+
# - :test7: value7
|
299
|
+
# :test8
|
300
|
+
# :test5: value8
|
301
|
+
# - :test5: value9")
|
302
|
+
#
|
303
|
+
# # Default context:
|
304
|
+
# RhContext.erb = nil
|
305
|
+
# # Filtering using |
|
306
|
+
# data.rh_get(:arr2, '<%= data.key?(:test8) %>|:test5')
|
307
|
+
# # => ['value8']
|
308
|
+
# RhContext.context = :test6
|
309
|
+
# data.rh_get(:arr2, '<%= context %>')
|
310
|
+
# # => ['value6']
|
311
|
+
#
|
312
|
+
# Introduce Array extraction (Fixnum and Range)
|
313
|
+
# When a data at a current level is an Array, get/exist?/lexist? interpret
|
314
|
+
# - the string '=[<Fixnum|Range>]' where
|
315
|
+
# - Fixnum : From found result, return the content of result[<Fixnum>]
|
316
|
+
# => subhash data found. It can return nil
|
317
|
+
# - Range : From found result, return the Range context of result[<Range>]
|
318
|
+
# => Array of (subhash data found)
|
319
|
+
# - the Range. complete the Array index selection.
|
320
|
+
# ex: [:test1, {:test2 => :value1}].rh_get(0..1, :test2)
|
321
|
+
#
|
322
|
+
# # data extraction. By default:
|
323
|
+
# # data.rh_get(:arr2, :test5) return ['value5', 'value8', 'value9']
|
324
|
+
# # then
|
325
|
+
# data.rh_get(:arr2, '=[0]', :test5) # => 'value5'
|
326
|
+
# data.rh_get(:arr2, '=[0..1]', :test5) # => ['value5', 'value8']
|
327
|
+
# data.rh_get(:arr2, '=[0..3]', :test5) # => ['value5', 'value8','value9']
|
328
|
+
#
|
329
|
+
# # Data selection:
|
330
|
+
# data.rh_get(:arr2, 0..1, :test5) # => ['value5', 'value8']
|
331
|
+
# data.rh_get(:arr2, 1..2, :test5) # => ['value8', 'value9']
|
233
332
|
def rh_get(*p)
|
234
333
|
p = p.flatten
|
235
334
|
return self if p.length == 0
|
@@ -237,6 +336,11 @@ class Hash
|
|
237
336
|
key = p[0]
|
238
337
|
sp = p.drop(1)
|
239
338
|
|
339
|
+
selected, key = _erb_select(key)
|
340
|
+
return nil unless selected
|
341
|
+
|
342
|
+
key = _erb_extract(key)
|
343
|
+
|
240
344
|
re, res, opts = _regexp(key)
|
241
345
|
return _keys_match(re, res, sp, opts) unless re.nil?
|
242
346
|
|
@@ -245,7 +349,7 @@ class Hash
|
|
245
349
|
return nil
|
246
350
|
end
|
247
351
|
|
248
|
-
return self[key].rh_get(sp) if [Array, Hash].include?(self[key].class)
|
352
|
+
return self[key].rh_get(*sp) if [Array, Hash].include?(self[key].class)
|
249
353
|
nil
|
250
354
|
end
|
251
355
|
|
@@ -505,6 +609,26 @@ end
|
|
505
609
|
class Hash
|
506
610
|
private
|
507
611
|
|
612
|
+
def _keys_match_lexist(re, res, sp, _opts)
|
613
|
+
_keys_match_loop_lexist(re, res, sp)
|
614
|
+
|
615
|
+
return 1 + res.max if res.length > 0
|
616
|
+
0
|
617
|
+
end
|
618
|
+
|
619
|
+
def _keys_match_loop_lexist(re, res, sp)
|
620
|
+
keys.sort.each do |k|
|
621
|
+
k_re = _key_to_s(k)
|
622
|
+
next unless re.match(k_re)
|
623
|
+
|
624
|
+
if sp.length == 0
|
625
|
+
res << 1
|
626
|
+
else
|
627
|
+
res << self[k].rh_lexist?(sp) if [Array, Hash].include?(self[k].class)
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
508
632
|
def _keys_match(re, res, sp, opts)
|
509
633
|
empty = false
|
510
634
|
empty = opts.include?('e') if opts
|
data/lib/rh.rb
CHANGED
@@ -14,6 +14,48 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
+
# Recursive Hash context
|
18
|
+
module RhContext
|
19
|
+
# Module attributes
|
20
|
+
class << self
|
21
|
+
attr_accessor :erb
|
22
|
+
end
|
23
|
+
|
24
|
+
# ERBConfig context for subhash selection, or filter
|
25
|
+
class ERBConfig
|
26
|
+
attr_accessor :data
|
27
|
+
attr_accessor :context
|
28
|
+
|
29
|
+
# Bind this limited class with ERB templates
|
30
|
+
def get_binding # rubocop: disable AccessorMethodName
|
31
|
+
binding
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module_function
|
36
|
+
|
37
|
+
def get(str)
|
38
|
+
return str if @erb.nil?
|
39
|
+
ERB.new(str).result(@erb.get_binding)
|
40
|
+
end
|
41
|
+
|
42
|
+
def data=(data)
|
43
|
+
@erb = ERBConfig.new if @erb.nil?
|
44
|
+
|
45
|
+
@erb.data = data
|
46
|
+
rescue
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
def context=(data)
|
51
|
+
@erb = ERBConfig.new if @erb.nil?
|
52
|
+
|
53
|
+
@erb.context = data
|
54
|
+
rescue
|
55
|
+
return
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
17
59
|
# Rh common module included in Hash and Array class.
|
18
60
|
module Rh
|
19
61
|
public
|
@@ -26,8 +68,39 @@ module Rh
|
|
26
68
|
_rh_remove_control(rh_clone)
|
27
69
|
end
|
28
70
|
|
71
|
+
def structured?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
29
75
|
private
|
30
76
|
|
77
|
+
# Return the erb call return
|
78
|
+
# true otherwise ie Selected by default.
|
79
|
+
def _erb_select(key)
|
80
|
+
return true, key unless key.is_a?(String) && key =~ /^<%=.*%>\|/
|
81
|
+
RhContext.data = self
|
82
|
+
|
83
|
+
found = /^(<%=.*%>)\|/.match(key)
|
84
|
+
key = key.clone
|
85
|
+
key[found[0]] = ''
|
86
|
+
[RhContext.get(found[1]) == 'true', _convert_key(key)]
|
87
|
+
end
|
88
|
+
|
89
|
+
def _erb_extract(key)
|
90
|
+
return key unless key.is_a?(String) && key =~ /^<%=.*%>[^|]?/
|
91
|
+
RhContext.data = self
|
92
|
+
|
93
|
+
_convert_key(RhContext.get(key))
|
94
|
+
end
|
95
|
+
|
96
|
+
def _convert_key(key)
|
97
|
+
return key unless key.is_a?(String)
|
98
|
+
# Ruby 1.8 : 'ab'[1] => 98 and 'ab'[1, 1] => 'b'
|
99
|
+
# Ruby 1.9+ : 'ab'[1] => 'b' and 'ab'[1, 1] => 'b'
|
100
|
+
return key[1..-1].to_sym if key[0, 1] == ':'
|
101
|
+
key
|
102
|
+
end
|
103
|
+
|
31
104
|
# Function which will parse arrays in hierarchie and will remove any control
|
32
105
|
# element (index 0)
|
33
106
|
def _rh_remove_control(result)
|
@@ -155,3 +228,10 @@ module RhGet
|
|
155
228
|
res[k] = v if res.is_a?(Hash)
|
156
229
|
end
|
157
230
|
end
|
231
|
+
|
232
|
+
# By default all object are considered as unstructured, ie not Hash or Array.
|
233
|
+
class Object
|
234
|
+
def structured?
|
235
|
+
false
|
236
|
+
end
|
237
|
+
end
|
data/lib/subhash/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subhash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christophe Larsonneur
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|