deep-hash-struct 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.
@@ -0,0 +1,5 @@
1
+ require "pp"
2
+ require "deep/hash/struct/pp/wrapper"
3
+ require "deep/hash/struct/pp/dashboard"
4
+ require "deep/hash/struct/pp/dashboard/table"
5
+ require "deep/hash/struct/pp/dashboard/table/row"
@@ -1,7 +1,7 @@
1
1
  module Deep
2
2
  module Hash
3
3
  module Struct
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,588 @@
1
+ module Deep
2
+ module Hash
3
+ module Struct
4
+ class Wrapper
5
+ include PP::Wrapper
6
+
7
+ attr_accessor :parent_ins,
8
+ :parent_key,
9
+ :chain
10
+
11
+ attr_reader :default
12
+
13
+ alias chain? chain
14
+
15
+ def initialize(h = {}, opt = {})
16
+ self.chain = opt[:chain].nil? ? false : opt[:chain]
17
+ self.parent_ins = opt[:parent_ins]
18
+ self.parent_key = opt[:parent_key]
19
+ return if h.nil? || h.count.zero?
20
+ wrap h, self
21
+ end
22
+
23
+ def keys
24
+ instance_variables.reject { |k| k =~ /default|parent_ins|parent_key|chain/ }.map do |k|
25
+ k.to_s[1..-1].to_sym
26
+ end
27
+ end
28
+
29
+ def values
30
+ keys.map do |k|
31
+ self[k]
32
+ end
33
+ end
34
+
35
+ def [](k)
36
+ __send__ k
37
+ end
38
+
39
+ def []=(k, v)
40
+ __send__ "#{k}=", v
41
+ end
42
+ alias add []=
43
+
44
+ def ==(hash)
45
+ if hash.class == self.class
46
+ to_h == hash.to_h
47
+ else
48
+ to_h == hash
49
+ end
50
+ end
51
+
52
+ def ===(klass)
53
+ self.class == klass
54
+ end
55
+
56
+ def each
57
+ if block_given?
58
+ keys.each do |k|
59
+ yield k, self[k]
60
+ end
61
+ else
62
+ to_h.each
63
+ end
64
+ end
65
+
66
+ def each_with_index
67
+ index = 0
68
+ keys.each do |k|
69
+ yield [k, self[k]], index
70
+ index += 1
71
+ end
72
+ end
73
+
74
+ def each_with_object(init)
75
+ each do |k, v|
76
+ yield [k, v], init
77
+ end
78
+
79
+ init
80
+ end
81
+
82
+ def each_key
83
+ keys.each do |k|
84
+ yield k
85
+ end
86
+ end
87
+
88
+ def each_value
89
+ values.each do |v|
90
+ yield v
91
+ end
92
+ end
93
+
94
+ def count
95
+ keys.size
96
+ end
97
+ alias size count
98
+
99
+ def blank?
100
+ keys.size.zero?
101
+ end
102
+
103
+ def present?
104
+ !blank?
105
+ end
106
+
107
+ def dig(*syms)
108
+ syms.inject(self) do |h, k|
109
+ h[k]
110
+ end
111
+ rescue
112
+ nil
113
+ end
114
+
115
+ def merge(hash)
116
+ klass = dup
117
+
118
+ hash.each do |k, v|
119
+ klass[k] = v
120
+ end
121
+
122
+ klass
123
+ end
124
+
125
+ def merge!(hash)
126
+ hash.each do |k, v|
127
+ self[k] = v
128
+ end
129
+ self
130
+ end
131
+ alias update merge!
132
+
133
+ def deep_merge(hash, klass = self)
134
+ klass = klass.deep_dup
135
+
136
+ hash.each do |k , v|
137
+ klass[k] = hash?(v) ? klass.deep_merge(v, klass[k]) : v
138
+ end
139
+
140
+ klass
141
+ end
142
+
143
+ def deep_merge!(hash, klass = self)
144
+ hash.each do |k, v|
145
+ klass[k] = hash?(v) ? deep_merge!(v, klass[k]) : v
146
+ end
147
+
148
+ klass
149
+ end
150
+
151
+ def reverse_merge(hash)
152
+ klass = dup
153
+
154
+ hash.each do |k, v|
155
+ klass[k] = v if klass.exclude?(k)
156
+ end
157
+
158
+ klass
159
+ end
160
+
161
+ def reverse_merge!(hash)
162
+ hash.each do |k, v|
163
+ self[k] = v if exclude?(k)
164
+ end
165
+
166
+ self
167
+ end
168
+
169
+ def reverse_deep_merge(hash, klass = self)
170
+ klass = klass.deep_dup
171
+
172
+ hash.each do |k , v|
173
+ next if !hash?(v) && klass.include?(k)
174
+ klass[k] = hash?(v) ? klass.reverse_deep_merge(v, klass[k]) : v
175
+ end
176
+
177
+ klass
178
+ end
179
+
180
+ def reverse_deep_merge!(hash)
181
+ hash.each do |k, v|
182
+ next if !hash?(v) && include?(k)
183
+ self[k] = hash?(v) ? reverse_deep_merge(v, self[k]) : v
184
+ end
185
+
186
+ self
187
+ end
188
+
189
+ def fetch(k, msg = nil)
190
+ v = self[k]
191
+ if block_given?
192
+ if v.class == self.class || v.nil?
193
+ yield k
194
+ else
195
+ v
196
+ end
197
+ else
198
+ case v
199
+ when self.class
200
+ if v.blank?
201
+ msg
202
+ else
203
+ to_h
204
+ end
205
+ when nil
206
+ msg
207
+ else
208
+ v
209
+ end
210
+ end
211
+ end
212
+
213
+ def map
214
+ if block_given?
215
+ vs = []
216
+
217
+ each do |k, v|
218
+ vs << yield(k, v)
219
+ end
220
+
221
+ vs
222
+ else
223
+ to_h.map
224
+ end
225
+ end
226
+ alias collect map
227
+
228
+ def map_key
229
+ vs = []
230
+
231
+ keys.each do |k|
232
+ vs << yield(k)
233
+ end
234
+
235
+ vs
236
+ end
237
+
238
+ def map_value
239
+ vs = []
240
+
241
+ values.each do |v|
242
+ vs << yield(v)
243
+ end
244
+
245
+ vs
246
+ end
247
+
248
+ def fetch_values(*syms)
249
+ syms.map do |sym|
250
+ if block_given?
251
+ if keys.include?(sym)
252
+ self[sym]
253
+ else
254
+ yield sym
255
+ end
256
+ else
257
+ raise KeyError, "key not found: :#{sym}" unless keys.include?(sym)
258
+ self[sym]
259
+ end
260
+ end
261
+ end
262
+
263
+ def values_at(*syms)
264
+ syms.map do |sym|
265
+ v = self[sym]
266
+ (v.nil? || (v.class == self.class && v.blank?)) ? nil : v
267
+ end
268
+ end
269
+
270
+ def invert
271
+ each_with_object({}) do |(k, v), h|
272
+ h[v] = k
273
+ end
274
+ end
275
+
276
+ def delete(k)
277
+ remove_instance_variable "@#{k}"
278
+ end
279
+
280
+ def delete_if
281
+ each do |k, v|
282
+ remove_instance_variable "@#{k}" if yield(k, v)
283
+ end
284
+ self
285
+ end
286
+
287
+ def find
288
+ klass = self.class.new
289
+
290
+ each do |k, v|
291
+ if yield(k, v)
292
+ klass[k] = v
293
+ break
294
+ end
295
+ end
296
+
297
+ klass
298
+ end
299
+
300
+ def select
301
+ klass = self.class.new
302
+
303
+ each do |k, v|
304
+ klass[k] = v if yield(k, v)
305
+ end
306
+
307
+ klass
308
+ end
309
+ alias find_all select
310
+
311
+ def reject
312
+ klass = self.class.new
313
+
314
+ each do |k, v|
315
+ klass[k] = v unless yield(k, v)
316
+ end
317
+
318
+ klass
319
+ end
320
+
321
+ def reject!
322
+ each do |k, v|
323
+ remove_instance_variable "@#{k}" if yield(k, v)
324
+ end
325
+ self
326
+ end
327
+
328
+ def inject(init = 0)
329
+ value = init.dup
330
+ each do |k, v|
331
+ val = yield init.dup, [k, v]
332
+ next if val.nil?
333
+ value += val
334
+ end
335
+ value
336
+ end
337
+ alias reduce inject
338
+
339
+ def clear
340
+ remove_instance_variable "@default" unless default.nil?
341
+ each_key do |k|
342
+ remove_instance_variable "@#{k}"
343
+ end
344
+ self
345
+ end
346
+
347
+ def replace(other)
348
+ h = if other.class == self.class
349
+ other.to_hash
350
+ elsif hash? other
351
+ other
352
+ else
353
+ other.to_hash
354
+ end
355
+
356
+ clear
357
+ wrap h, self
358
+ end
359
+
360
+ def flatten
361
+ to_h.flatten
362
+ end
363
+
364
+ def has_key?(k)
365
+ keys.include? k
366
+ end
367
+ alias include? has_key?
368
+
369
+ def has_keys?(*syms)
370
+ syms.inject(self) do |klass, sym|
371
+ val = klass[sym]
372
+ return false if val.class == self.class && val.blank?
373
+ klass[sym]
374
+ end
375
+ true
376
+ end
377
+
378
+ def exclude?(k)
379
+ !include? k
380
+ end
381
+
382
+ def sort
383
+ to_h.sort
384
+ end
385
+
386
+ def shift
387
+ k = keys.first
388
+ [k, remove_instance_variable("@#{k}")]
389
+ end
390
+
391
+ def to_a
392
+ to_h.to_a
393
+ end
394
+ alias to_ary to_a
395
+
396
+ def compact
397
+ klass = dup
398
+
399
+ klass.each do |k, v|
400
+ klass.remove_instance_variable("@#{k}") if (v.class == self.class && v.blank?) || v.nil?
401
+ end
402
+
403
+ klass
404
+ end
405
+
406
+ def compact!
407
+ each do |k, v|
408
+ remove_instance_variable("@#{k}") if (v.class == self.class && v.blank?) || v.nil?
409
+ end
410
+
411
+ self
412
+ end
413
+
414
+ def deep_compact
415
+ klass = deep_dup
416
+
417
+ klass.each do |k, v|
418
+ flag = if v.class == self.class
419
+ klass[k] = v.deep_compact
420
+ klass[k].present?
421
+ else
422
+ !v.nil?
423
+ end
424
+ next if flag
425
+ klass.remove_instance_variable("@#{k}")
426
+ end
427
+
428
+ klass
429
+ end
430
+
431
+ def deep_compact!
432
+ each do |k, v|
433
+ flag = if v.class == self.class
434
+ self[k] = v.deep_compact
435
+ self[k].present?
436
+ else
437
+ !v.nil?
438
+ end
439
+ next if flag
440
+ remove_instance_variable("@#{k}")
441
+ end
442
+
443
+ self
444
+ end
445
+
446
+ def slice(*syms)
447
+ klass = self.class.new
448
+
449
+ each_key do |k|
450
+ klass[k] = self[k] if syms.map(&:to_sym).include?(k)
451
+ end
452
+
453
+ klass
454
+ end
455
+
456
+ def slice!(*syms)
457
+ each_key do |k|
458
+ remove_instance_variable("@#{k}") unless syms.map(&:to_sym).include?(k)
459
+ end
460
+
461
+ self
462
+ end
463
+
464
+ def to_hash
465
+ deep_hash self
466
+ end
467
+ alias to_h to_hash
468
+
469
+ def to_json
470
+ to_h.to_json
471
+ end
472
+
473
+ def max_stages(klass = self, i = 1)
474
+ klass.map_value do |v|
475
+ case v
476
+ when self.class
477
+ max_stages v, i + 1
478
+ else
479
+ i
480
+ end
481
+ end.sort.last || 0
482
+ end
483
+
484
+ def min_stages(klass = self, i = 1)
485
+ klass.map_value do |v|
486
+ case v
487
+
488
+ when self.class
489
+ min_stages v, i + 1
490
+ else
491
+ i
492
+ end
493
+ end.delete_if(&:zero?).sort.first || 0
494
+ end
495
+
496
+ def to_table(side_name = nil)
497
+ if min_stages >= 2
498
+ values.flat_map(&:keys).uniq.map do |side|
499
+ map_value { |v| v[side] }.unshift side
500
+ end.unshift keys.unshift(side_name)
501
+ else
502
+ deep_table to_h
503
+ end
504
+ end
505
+
506
+ def deep_dup(klass = self)
507
+ new_klass = self.class.new
508
+
509
+ klass.each do |k, v|
510
+ new_klass[k] = hash?(v) ? v.deep_dup(v) : v
511
+ end
512
+
513
+ new_klass
514
+ end
515
+
516
+ private
517
+
518
+ def method_missing(method_name, arg = nil)
519
+ name = method_name.to_s.delete("=")
520
+
521
+ if method_name.to_s.end_with? "="
522
+ setting_chain_instance!(self, name, arg)
523
+ elsif block_given?
524
+ __send__ "#{name}=", yield
525
+ else
526
+ val = instance_variable_get "@#{name}"
527
+ return val unless val.nil?
528
+ return self.class.new({}, chain: true, parent_ins: self, parent_key: method_name) if default.nil?
529
+ default
530
+ end
531
+ rescue => e
532
+ e.backtrace.shift
533
+ raise
534
+ end
535
+
536
+ def chain!
537
+ self.chain = true
538
+ end
539
+
540
+ def setting_chain_instance!(klass, key, val)
541
+ klass.instance_variable_set "@#{key}", hash?(val) && (!(self === val.class) || klass.chain?) ? wrap(val) : val
542
+ return val unless klass.chain?
543
+ setting_chain_instance!(klass.parent_ins, klass.parent_key, klass)
544
+ end
545
+
546
+ def deep_hash(klass)
547
+ h = {}
548
+
549
+ klass.each do |k, v|
550
+ h[k] = if v.class == self.class
551
+ deep_hash(v) if v.present?
552
+ else
553
+ v
554
+ end
555
+ end
556
+
557
+ h
558
+ end
559
+
560
+ def deep_table(hash)
561
+ hash.to_a.transpose.map do |val|
562
+ val.map do |v|
563
+ if hash? v
564
+ deep_table v
565
+ else
566
+ v
567
+ end
568
+ end
569
+ end
570
+ end
571
+
572
+ def wrap(hash, klass = nil)
573
+ base = klass || self.class.new
574
+
575
+ hash.each do |k, v|
576
+ base[k] = hash?(v) ? wrap(v) : v
577
+ end
578
+
579
+ base
580
+ end
581
+
582
+ def hash?(val)
583
+ !val.is_a?(Array) && val.respond_to?(:each)
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end