bblib 1.0.2 → 2.0.0

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +502 -8
  3. data/lib/bblib.rb +1 -28
  4. data/lib/bblib/all.rb +5 -0
  5. data/lib/{time → bblib/classes}/cron.rb +0 -0
  6. data/lib/{string → bblib/classes}/fuzzy_matcher.rb +0 -0
  7. data/lib/bblib/cli.rb +3 -0
  8. data/lib/bblib/cli/color.rb +51 -0
  9. data/lib/bblib/cli/exceptions/invalid_argument.rb +5 -0
  10. data/lib/bblib/cli/exceptions/missing_argument.rb +5 -0
  11. data/lib/bblib/cli/exceptions/missing_required_argument.rb +5 -0
  12. data/lib/bblib/cli/exceptions/opts_parser.rb +9 -0
  13. data/lib/bblib/cli/option.rb +116 -0
  14. data/lib/bblib/cli/options/basic_option.rb +19 -0
  15. data/lib/bblib/cli/options/bool.rb +19 -0
  16. data/lib/bblib/cli/options/command.rb +11 -0
  17. data/lib/bblib/cli/options/date.rb +14 -0
  18. data/lib/bblib/cli/options/float.rb +14 -0
  19. data/lib/bblib/cli/options/integer.rb +14 -0
  20. data/lib/bblib/cli/options/json.rb +16 -0
  21. data/lib/bblib/cli/options/regexp.rb +17 -0
  22. data/lib/bblib/cli/options/string.rb +13 -0
  23. data/lib/bblib/cli/options/symbol.rb +13 -0
  24. data/lib/bblib/cli/options/time.rb +14 -0
  25. data/lib/bblib/cli/options/toggle.rb +27 -0
  26. data/lib/bblib/cli/options/untoggle.rb +18 -0
  27. data/lib/bblib/cli/opts_parser.rb +65 -0
  28. data/lib/bblib/core.rb +37 -0
  29. data/lib/{hash → bblib/core/classes}/hash_struct.rb +9 -2
  30. data/lib/bblib/core/classes/splitter.rb +101 -0
  31. data/lib/{time → bblib/core/classes}/task_timer.rb +0 -0
  32. data/lib/{hash → bblib/core/classes}/tree_hash.rb +22 -22
  33. data/lib/bblib/core/exceptions/abstract.rb +3 -0
  34. data/lib/bblib/core/exceptions/exception.rb +5 -0
  35. data/lib/{hash_path → bblib/core/hash_path}/hash_path.rb +0 -2
  36. data/lib/{hash_path → bblib/core/hash_path}/part.rb +0 -0
  37. data/lib/{mixins → bblib/core/mixins}/attrs.rb +17 -7
  38. data/lib/{mixins → bblib/core/mixins}/bbmixins.rb +1 -0
  39. data/lib/{mixins → bblib/core/mixins}/bridge.rb +0 -0
  40. data/lib/bblib/core/mixins/delegator.rb +90 -0
  41. data/lib/{class → bblib/core/mixins}/effortless.rb +0 -0
  42. data/lib/{mixins → bblib/core/mixins}/family_tree.rb +1 -1
  43. data/lib/{mixins → bblib/core/mixins}/hooks.rb +0 -0
  44. data/lib/{mixins → bblib/core/mixins}/logger.rb +0 -0
  45. data/lib/{mixins → bblib/core/mixins}/prototype.rb +0 -0
  46. data/lib/{mixins → bblib/core/mixins}/serializer.rb +0 -0
  47. data/lib/{mixins → bblib/core/mixins}/simple_init.rb +41 -3
  48. data/lib/{mixins → bblib/core/mixins}/type_init.rb +0 -0
  49. data/lib/{array/bbarray.rb → bblib/core/util/array.rb} +0 -0
  50. data/lib/{string → bblib/core/util}/cases.rb +0 -0
  51. data/lib/{file/bbfile.rb → bblib/core/util/file.rb} +31 -7
  52. data/lib/{hash/bbhash.rb → bblib/core/util/hash.rb} +0 -3
  53. data/lib/{logging/bblogging.rb → bblib/core/util/logging.rb} +11 -2
  54. data/lib/{string → bblib/core/util}/matching.rb +0 -0
  55. data/lib/{number/bbnumber.rb → bblib/core/util/number.rb} +0 -0
  56. data/lib/{object/bbobject.rb → bblib/core/util/object.rb} +2 -0
  57. data/lib/{opal/bbopal.rb → bblib/core/util/opal.rb} +0 -0
  58. data/lib/{os/bbos.rb → bblib/core/util/os.rb} +0 -0
  59. data/lib/{string → bblib/core/util}/pluralization.rb +0 -0
  60. data/lib/{string → bblib/core/util}/regexp.rb +0 -0
  61. data/lib/{string → bblib/core/util}/roman.rb +0 -0
  62. data/lib/{string/bbstring.rb → bblib/core/util/string.rb} +18 -24
  63. data/lib/{time/bbtime.rb → bblib/core/util/time.rb} +1 -5
  64. data/lib/bblib/cron.rb +2 -0
  65. data/lib/bblib/fuzzy_matcher.rb +2 -0
  66. data/lib/bblib/html.rb +4 -0
  67. data/lib/{html → bblib/html}/builder.rb +0 -0
  68. data/lib/{html → bblib/html}/tag.rb +0 -0
  69. data/lib/{html → bblib/html}/tag_set.rb +0 -0
  70. data/lib/bblib/system.rb +3 -0
  71. data/lib/bblib/system/command.rb +7 -0
  72. data/lib/bblib/system/system.rb +39 -0
  73. data/lib/bblib/version.rb +1 -1
  74. metadata +71 -44
  75. data/lib/error/abstract.rb +0 -3
  76. data/lib/hash_path/path_hash.rb +0 -84
  77. data/lib/hash_path/proc.rb +0 -93
  78. data/lib/hash_path/processors.rb +0 -239
  79. data/lib/html/bbhtml.rb +0 -3
  80. data/lib/system/bbsystem.rb +0 -42
@@ -0,0 +1,18 @@
1
+ module BBLib
2
+ class OptsParser
3
+ class Untoggle < Toggle
4
+
5
+ def extract(index, args)
6
+ super
7
+ false
8
+ end
9
+
10
+ protected
11
+
12
+ def simple_setup
13
+ self.default = true
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'option'
2
+ require_relative 'exceptions/opts_parser'
3
+ require_relative 'options/basic_option'
4
+
5
+ BBLib.scan_files(File.expand_path('../options', __FILE__), '*.rb') do |file|
6
+ require_relative file
7
+ end
8
+
9
+ module BBLib
10
+ class OptsParser
11
+ include BBLib::Effortless
12
+
13
+ attr_ary_of Option, :options, add_rem: true
14
+ attr_str :usage, default: nil, allow_nil: true
15
+
16
+ def usage(text = nil)
17
+ @usage = text unless text.nil?
18
+ @usage
19
+ end
20
+
21
+ def on(*flags, **opts, &block)
22
+ opts[:type] = :string unless opts[:type]
23
+ add_options(opts.merge(flags: flags, processor: block))
24
+ end
25
+
26
+ def parse(args = ARGV)
27
+ parse!(args.dup)
28
+ end
29
+
30
+ def parse!(args = ARGV)
31
+ HashStruct.new.tap do |hash|
32
+ options.each do |option|
33
+ option.retrieve(args, hash)
34
+ end
35
+ end.merge(arguments: args)
36
+ end
37
+
38
+ def help
39
+ usage.to_s + "\n\t" +
40
+ options.join("\n\t")
41
+ end
42
+
43
+ def to_s
44
+ help
45
+ end
46
+
47
+ protected
48
+
49
+ def method_missing(method, *args, &block)
50
+ if Option.types.include?(method)
51
+ define_singleton_method(method) do |*flags, **opts, &block|
52
+ on(*flags, **opts.merge(type: method), &block)
53
+ end
54
+ send(method, *args, &block)
55
+ else
56
+ super
57
+ end
58
+ end
59
+
60
+ def respond_to_missing?(method, include_private = false)
61
+ Option.types.include?(method) || super
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'version'
2
+
3
+ require_relative 'core/exceptions/exception'
4
+
5
+ require_relative 'core/util/opal'
6
+ require_relative 'core/util/object'
7
+ require_relative 'core/util/hash'
8
+
9
+ require_relative 'core/mixins/simple_init'
10
+ require_relative 'core/mixins/attrs'
11
+ require_relative 'core/mixins/family_tree'
12
+ require_relative 'core/mixins/hooks'
13
+ require_relative 'core/mixins/serializer'
14
+ require_relative 'core/mixins/logger'
15
+ require_relative 'core/mixins/bridge'
16
+ require_relative 'core/mixins/effortless'
17
+ require_relative 'core/mixins/prototype'
18
+ require_relative 'core/mixins/type_init'
19
+ require_relative 'core/mixins/delegator'
20
+
21
+ require_relative 'core/hash_path/hash_path'
22
+
23
+ require_relative 'core/util/string'
24
+ require_relative 'core/util/file'
25
+ require_relative 'core/util/time'
26
+ require_relative 'core/util/number'
27
+ require_relative 'core/util/array'
28
+ require_relative 'core/util/logging'
29
+ require_relative 'core/util/os'
30
+
31
+ require_relative 'core/classes/hash_struct'
32
+ require_relative 'core/classes/task_timer'
33
+ require_relative 'core/classes/tree_hash'
34
+ require_relative 'core/classes/splitter'
35
+
36
+ require 'fileutils'
37
+ require 'time'
@@ -7,10 +7,17 @@ module BBLib
7
7
 
8
8
  def method_missing(method, *args, &block)
9
9
  if args.empty? && ![:to_ary].include?(method)
10
- define_singleton_method(method) do
10
+ if method.to_s.end_with?('?')
11
+ define_singleton_method(method) do
12
+ self[method[0..-2].to_sym] ? true : false
13
+ end
14
+ send(method)
15
+ else
16
+ define_singleton_method(method) do
17
+ self[method]
18
+ end
11
19
  self[method]
12
20
  end
13
- self[method]
14
21
  elsif method.to_s.end_with?('=')
15
22
  define_singleton_method(method) do |arg|
16
23
  self[method[0..-2].to_sym] = arg
@@ -0,0 +1,101 @@
1
+ module BBLib
2
+ class Splitter
3
+ include BBLib::Effortless
4
+
5
+ attr_hash :expressions, required: true, pre_proc: :process_expressions
6
+ attr_ary_of [String, Regexp], :delimiters, required: true
7
+
8
+ attr_bool :inside, default: false
9
+ attr_int :current_start, :current_depth, default: 0
10
+ attr_of [String, Symbol, Regexp], :current_expression, allow_nil: true
11
+ attr_str :current_match, :current_delimiter_match, :current_expression_match, allow_nil: true, default: nil
12
+ attr_str :part, default: ''
13
+ attr_bool :ignore_escaped_chars, default: true
14
+ attr_bool :escaped, default: false
15
+ attr_str :escape_char, default: '\\'
16
+
17
+ def self.split(string, *delimiters, **opts)
18
+ new(opts.except(:count).merge(delimiters: delimiters)).split(string, opts.delete(:count))
19
+ end
20
+
21
+ def split(string, count = nil)
22
+ return string if count == 1
23
+ index = 0
24
+ splits = 1
25
+ [].tap do |array|
26
+ until index >= string.size
27
+ sub_string = string[index..-1]
28
+ escaped = string[index - 1] == escape_char if ignore_escaped_chars?
29
+
30
+ if inside?
31
+ open_match = match(sub_string, current_expression)
32
+ close_match = match(sub_string, expressions[current_expression])
33
+ if current_start != index && close_match && !escaped
34
+ self.inside = false if (self.current_depth -= 1).zero?
35
+ elsif open_match && !escaped
36
+ self.current_depth += 1
37
+ self.part += open_match
38
+ index += open_match.size
39
+ next
40
+ end
41
+ elsif expression = check_expressions(sub_string)
42
+ self.inside = true
43
+ self.current_start = index
44
+ self.current_expression = expression
45
+ self.current_depth += 1
46
+ self.part += current_expression_match
47
+ index += current_expression_match.size
48
+ next
49
+ elsif !escaped? && (count.nil? || splits < count) && delimiter_check(sub_string)
50
+ array << self.part
51
+ splits += 1
52
+ self.part = ''
53
+ index += current_delimiter_match.size
54
+ next
55
+ end
56
+ self.part += string[index].to_s
57
+ index += 1
58
+ end
59
+ array << self.part
60
+ end
61
+ end
62
+
63
+ protected
64
+
65
+ def match(sub_string, expression)
66
+ case expression
67
+ when Regexp
68
+ (sub_string =~ expression)&.zero? ? sub_string.scan(expression).first : nil
69
+ when String, Symbol
70
+ sub_string.start_with?(expression.to_s) ? expression.to_s : nil
71
+ else
72
+ nil
73
+ end
74
+ end
75
+
76
+ def check_expressions(sub_string)
77
+ expressions.find do |open_expression, _close_expression|
78
+ self.current_expression_match = match(sub_string, open_expression)
79
+ end&.first
80
+ end
81
+
82
+ def delimiter_check(sub_string)
83
+ delimiters.find do |delimiter|
84
+ self.current_delimiter_match = match(sub_string, delimiter)
85
+ end
86
+ end
87
+
88
+ def process_expressions(expressions)
89
+ case expressions
90
+ when Array
91
+ expressions.hmap { |exp| [exp, exp] }
92
+ when String, Symbol, Regexp
93
+ { expressions => expressions }
94
+ when Hash
95
+ expressions
96
+ else
97
+ raise ArgumentError, "Unknown expression format: #{expressions.class}"
98
+ end
99
+ end
100
+ end
101
+ end
@@ -22,10 +22,10 @@ class TreeHash
22
22
  end
23
23
 
24
24
  def child(key, symbol_sensitive = false)
25
- case [node_class]
26
- when [Hash]
25
+ case
26
+ when Hash >= node_class
27
27
  children[key] || (symbol_sensitive ? nil : children[key.to_s.to_sym])
28
- when [Array]
28
+ when Array >= node_class
29
29
  children[key.to_i]
30
30
  else
31
31
  nil
@@ -33,14 +33,14 @@ class TreeHash
33
33
  end
34
34
 
35
35
  def child_exists?(key, symbol_sensitive = false)
36
- !case [node_class]
37
- when [Hash]
38
- children[key] || (!symbol_sensitive && children[key.to_s.to_sym])
39
- when [Array]
36
+ case
37
+ when Hash >= node_class
38
+ children.include?(key) || (!symbol_sensitive && children.include?(key.to_s.to_sym))
39
+ when Array >= node_class
40
40
  [0...children.size] === key.to_i
41
41
  else
42
42
  false
43
- end.nil?
43
+ end
44
44
  end
45
45
 
46
46
  def children?
@@ -197,8 +197,8 @@ class TreeHash
197
197
  self
198
198
  end
199
199
 
200
- def process(processor)
201
-
200
+ def process(processor, &block)
201
+ # TODO Add ability to process values or keys in tree hashes
202
202
  end
203
203
 
204
204
  def size
@@ -206,8 +206,8 @@ class TreeHash
206
206
  end
207
207
 
208
208
  def paths
209
- case [node_class]
210
- when [Array], [Hash]
209
+ case
210
+ when Array >= node_class, Hash >= node_class
211
211
  value.squish.keys
212
212
  else
213
213
  []
@@ -258,10 +258,10 @@ class TreeHash
258
258
  end
259
259
 
260
260
  def value
261
- case [node_class]
262
- when [Hash]
263
- children.map { |k, v| [k, v.value] }.to_h
264
- when [Array]
261
+ case
262
+ when Hash >= node_class
263
+ children.hmap { |k, v| [k, v.value] }
264
+ when Array >= node_class
265
265
  children.values.map(&:value)
266
266
  else
267
267
  children
@@ -270,10 +270,10 @@ class TreeHash
270
270
 
271
271
  def key
272
272
  return nil if root?
273
- case [parent.node_class]
274
- when [Hash]
273
+ case
274
+ when Hash >= parent.node_class
275
275
  parent.keys[index]
276
- when [Array]
276
+ when Array >= parent.node_class
277
277
  index
278
278
  else
279
279
  nil
@@ -327,11 +327,11 @@ class TreeHash
327
327
  end
328
328
 
329
329
  def delete_child(key, symbol_sensitive = false)
330
- case [node_class]
331
- when [Hash]
330
+ case
331
+ when Hash >= node_class
332
332
  child = symbol_sensitive ? nil : children.delete(key.to_s.to_sym)
333
333
  child = children.delete(key) unless child
334
- when [Array]
334
+ when Array >= node_class
335
335
  children.delete(key.to_i)
336
336
  else
337
337
  nil
@@ -0,0 +1,3 @@
1
+ class AbstractError < BBLib::Exception
2
+ # Enhance at some point
3
+ end
@@ -0,0 +1,5 @@
1
+ module BBLib
2
+ class Exception < StandardError; end
3
+ end
4
+
5
+ require_relative 'abstract'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'part'
3
- require_relative 'proc'
4
- require_relative 'path_hash'
5
3
 
6
4
  # This classes parses dot delimited hash path strings and wraps the corresponding parts. Then hashes or arrays can be
7
5
  # passed to the find method to find all matching elements for the path.
@@ -100,6 +100,14 @@ module BBLib
100
100
  end
101
101
  end
102
102
 
103
+ if opts[:aliases]
104
+ [opts[:aliases]].flatten.each do |als|
105
+ obj = opts[:singleton] ? self.singleton_class : self
106
+ obj.send(:alias_method, als, method)
107
+ obj.send(:alias_method, "#{als}=", "#{method}=")
108
+ end
109
+ end
110
+
103
111
  unless opts[:singleton]
104
112
  protected method if opts[:protected] || opts[:protected_reader]
105
113
  protected "#{method}=".to_sym if opts[:protected] || opts[:protected_writer]
@@ -126,7 +134,7 @@ module BBLib
126
134
  elsif arg && (!opts.include?(:pack) || opts[:pack]) && arg = _attr_pack(arg, klasses, opts)
127
135
  arg
128
136
  else
129
- raise TypeError, "#{method} must be set to a class of #{allowed.join_terms(:or)}, not #{arg.class}" unless opts[:suppress]
137
+ raise TypeError, "#{method} must be set to a class of #{allowed.join_terms(:or)}, not #{arg.class} (#{self})" unless opts[:suppress]
130
138
  end
131
139
  end
132
140
  end
@@ -208,9 +216,11 @@ module BBLib
208
216
  def attr_element_of(list, *methods, **opts)
209
217
  methods.each do |method|
210
218
  attr_custom(method, opts.merge(list: list)) do |arg|
211
- ls = list.is_a?(Proc) ? list.call : list
219
+ ls = list.is_a?(Proc) ? list.call(self) : list
212
220
  if ls.include?(arg) || (opts[:allow_nil] && arg.nil?)
213
221
  arg
222
+ elsif opts[:fallback]
223
+ opts[:fallback]
214
224
  else
215
225
  raise ArgumentError, "Invalid option '#{arg}' for #{method}." unless opts.include?(:raise) && !opts[:raise]
216
226
  end
@@ -222,7 +232,7 @@ module BBLib
222
232
  opts[:default] = [] unless opts.include?(:default) || opts.include?(:default_proc)
223
233
  methods.each do |method|
224
234
  attr_custom(method, opts.merge(list: list)) do |args|
225
- ls = list.is_a?(Proc) ? list.call : list
235
+ ls = list.is_a?(Proc) ? list.call(self) : list
226
236
  [].tap do |final|
227
237
  [args].flatten(1).each do |arg|
228
238
  if ls.include?(arg) || (opts[:allow_nil] && arg.nil?)
@@ -272,7 +282,7 @@ module BBLib
272
282
  elsif arg && (!opts.include?(:pack) || opts[:pack]) && arg = _attr_pack(arg, klasses, opts)
273
283
  array.push(arg)
274
284
  else
275
- raise TypeError, "Invalid class passed to #{method} on #{self}: #{arg.class}. Must be a #{klasses.join_terms(:or)}." unless opts[:raise] == false
285
+ raise TypeError, "Invalid class passed to #{method} on #{self}: #{arg.class}. Must be a #{klasses.join_terms(:or)}." unless opts[:suppress]
276
286
  end
277
287
  end
278
288
  end
@@ -397,7 +407,7 @@ module BBLib
397
407
  elsif (opts.include?(:pack_key) && opts[:pack_key]) && new_key = _attr_pack(key, klasses, opts)
398
408
  arg[new_key] = arg.delete(key)
399
409
  else
400
- raise ArgumentError, "Invalid key type for #{method}: #{key.class}. Must be #{opts[:keys].join_terms(:or)}."
410
+ raise ArgumentError, "Invalid key type for #{method}: #{key.class}. Must be #{[opts[:keys]].flatten.join_terms(:or)}."
401
411
  end
402
412
  end
403
413
  end
@@ -418,10 +428,10 @@ module BBLib
418
428
  end
419
429
  end
420
430
 
421
- def _attr_pack(arg, klasses, opts = {})
431
+ def _attr_pack(arg, klasses, opts = {}, &block)
422
432
  klasses = [klasses].flatten
423
433
  unless BBLib.is_any?(arg, *klasses)
424
- return klasses.first.new(*[arg].flatten(1)) if klasses.first.respond_to?(:new)
434
+ return klasses.first.new(*[arg].flatten(1), &block) if klasses.first.respond_to?(:new)
425
435
  end
426
436
  nil
427
437
  end
@@ -7,3 +7,4 @@ require_relative 'logger'
7
7
  require_relative 'bridge'
8
8
  require_relative 'prototype'
9
9
  require_relative 'type_init'
10
+ require_relative 'delegator'