subhash 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b002bfeab90a25d4208f184c8892ca90bd2a8761
4
- data.tar.gz: df518060d1c2ae5f428b7eaa2302a6dd6cb8ba3e
3
+ metadata.gz: 9f0a051059b11209331fa863d593e6e7d2b0714c
4
+ data.tar.gz: 989f14524b03c77768a03e8d30588548d477980a
5
5
  SHA512:
6
- metadata.gz: a183bffb2589c4f51b84de71436a2f562563e74b3a87f809471803303c490b9c005abc0320530c2c9f176c7f79bb0ed79e3fa3184e665b4699eeb237beeda106
7
- data.tar.gz: 04f7c7a78f569b549a21f5b058109a2502b7225ae8f3976826de3b5c8d6f998259d8f8f4eedd3fc8ae9de8ba51bf2bc8dd33c38db0352d1a4e9b6dc9d89e99ca
6
+ metadata.gz: db164809d9c9bdd2e6f0c68e6e74c995d4ceb845c03ca2eaeef5e3f26ca00fed1123f39c1dd098e1e1cb63f58a4bc664121c084845039993e8d754d0892e9b21
7
+ data.tar.gz: cdcbc82160fa22fb53d1beca45df9cc2e0c43fa899151d87b3d6ae5fa6b9b62a279ed74ef65a4332acad9b297c75a9b3fc37f93c66f2a768923062620e4a7544
data/.rubocop.yml CHANGED
@@ -31,3 +31,6 @@ Metrics/ClassLength:
31
31
  # allow arguments to be longer than 15
32
32
  Metrics/AbcSize:
33
33
  Max: 40
34
+
35
+ Metrics/CyclomaticComplexity:
36
+ Max: 7
@@ -41,7 +41,7 @@ fi
41
41
  if [ "$http_proxy" = "" ]
42
42
  then
43
43
  echo "Currently, no proxy is set. Running docker without proxy"
44
- docker build $TAG
44
+ docker build $TAG .
45
45
  exit
46
46
  fi
47
47
 
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
- return _lexist_array(sp, key) if key.is_a?(Fixnum)
29
+ re, _, opts = _regexp(key)
30
+ return _keys_match_lexist(re, [], sp, opts) unless re.nil?
30
31
 
31
- _loop_lexist_array(sp, key)
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 key.is_a?(Fixnum)
60
+ return _get_array(sp, key) if [Fixnum, Range].include?(key.class)
58
61
 
59
- _loop_get_array(sp, key)
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(sp, key)
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[key]
200
- else
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
- return ret if ret.length > 0
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
- self[key].rh_get(sp) if [Array, Hash].include?(self[key].class)
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 unless key >= 0 && key < length
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 [Array, Hash].include?(self[key].class)
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
- def _loop_lexist_array(sp, key)
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.is_a?(Hash)
226
- next unless e.key?(key)
264
+ next unless e.structured?
227
265
 
228
- if sp.length == 0
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 [Array, Hash].include?(e[k].class)
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
- if p.length == 1
74
- return 1 if self.key?(p[0])
75
- return 0
76
- end
77
- return 0 unless self.key?(p[0])
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
- if [Hash, Array].include?(self[p[0]].class)
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 if the object
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
@@ -1,5 +1,5 @@
1
1
  # Recursive Hash
2
2
  module SubHash
3
- VERSION = '0.1.2'
4
- DATE = '2015-06-03'
3
+ VERSION = '0.1.3'
4
+ DATE = '2015-06-15'
5
5
  end
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.2
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-03 00:00:00.000000000 Z
11
+ date: 2015-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler