bblib 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +502 -8
- data/lib/bblib.rb +1 -28
- data/lib/bblib/all.rb +5 -0
- data/lib/{time → bblib/classes}/cron.rb +0 -0
- data/lib/{string → bblib/classes}/fuzzy_matcher.rb +0 -0
- data/lib/bblib/cli.rb +3 -0
- data/lib/bblib/cli/color.rb +51 -0
- data/lib/bblib/cli/exceptions/invalid_argument.rb +5 -0
- data/lib/bblib/cli/exceptions/missing_argument.rb +5 -0
- data/lib/bblib/cli/exceptions/missing_required_argument.rb +5 -0
- data/lib/bblib/cli/exceptions/opts_parser.rb +9 -0
- data/lib/bblib/cli/option.rb +116 -0
- data/lib/bblib/cli/options/basic_option.rb +19 -0
- data/lib/bblib/cli/options/bool.rb +19 -0
- data/lib/bblib/cli/options/command.rb +11 -0
- data/lib/bblib/cli/options/date.rb +14 -0
- data/lib/bblib/cli/options/float.rb +14 -0
- data/lib/bblib/cli/options/integer.rb +14 -0
- data/lib/bblib/cli/options/json.rb +16 -0
- data/lib/bblib/cli/options/regexp.rb +17 -0
- data/lib/bblib/cli/options/string.rb +13 -0
- data/lib/bblib/cli/options/symbol.rb +13 -0
- data/lib/bblib/cli/options/time.rb +14 -0
- data/lib/bblib/cli/options/toggle.rb +27 -0
- data/lib/bblib/cli/options/untoggle.rb +18 -0
- data/lib/bblib/cli/opts_parser.rb +65 -0
- data/lib/bblib/core.rb +37 -0
- data/lib/{hash → bblib/core/classes}/hash_struct.rb +9 -2
- data/lib/bblib/core/classes/splitter.rb +101 -0
- data/lib/{time → bblib/core/classes}/task_timer.rb +0 -0
- data/lib/{hash → bblib/core/classes}/tree_hash.rb +22 -22
- data/lib/bblib/core/exceptions/abstract.rb +3 -0
- data/lib/bblib/core/exceptions/exception.rb +5 -0
- data/lib/{hash_path → bblib/core/hash_path}/hash_path.rb +0 -2
- data/lib/{hash_path → bblib/core/hash_path}/part.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/attrs.rb +17 -7
- data/lib/{mixins → bblib/core/mixins}/bbmixins.rb +1 -0
- data/lib/{mixins → bblib/core/mixins}/bridge.rb +0 -0
- data/lib/bblib/core/mixins/delegator.rb +90 -0
- data/lib/{class → bblib/core/mixins}/effortless.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/family_tree.rb +1 -1
- data/lib/{mixins → bblib/core/mixins}/hooks.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/logger.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/prototype.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/serializer.rb +0 -0
- data/lib/{mixins → bblib/core/mixins}/simple_init.rb +41 -3
- data/lib/{mixins → bblib/core/mixins}/type_init.rb +0 -0
- data/lib/{array/bbarray.rb → bblib/core/util/array.rb} +0 -0
- data/lib/{string → bblib/core/util}/cases.rb +0 -0
- data/lib/{file/bbfile.rb → bblib/core/util/file.rb} +31 -7
- data/lib/{hash/bbhash.rb → bblib/core/util/hash.rb} +0 -3
- data/lib/{logging/bblogging.rb → bblib/core/util/logging.rb} +11 -2
- data/lib/{string → bblib/core/util}/matching.rb +0 -0
- data/lib/{number/bbnumber.rb → bblib/core/util/number.rb} +0 -0
- data/lib/{object/bbobject.rb → bblib/core/util/object.rb} +2 -0
- data/lib/{opal/bbopal.rb → bblib/core/util/opal.rb} +0 -0
- data/lib/{os/bbos.rb → bblib/core/util/os.rb} +0 -0
- data/lib/{string → bblib/core/util}/pluralization.rb +0 -0
- data/lib/{string → bblib/core/util}/regexp.rb +0 -0
- data/lib/{string → bblib/core/util}/roman.rb +0 -0
- data/lib/{string/bbstring.rb → bblib/core/util/string.rb} +18 -24
- data/lib/{time/bbtime.rb → bblib/core/util/time.rb} +1 -5
- data/lib/bblib/cron.rb +2 -0
- data/lib/bblib/fuzzy_matcher.rb +2 -0
- data/lib/bblib/html.rb +4 -0
- data/lib/{html → bblib/html}/builder.rb +0 -0
- data/lib/{html → bblib/html}/tag.rb +0 -0
- data/lib/{html → bblib/html}/tag_set.rb +0 -0
- data/lib/bblib/system.rb +3 -0
- data/lib/bblib/system/command.rb +7 -0
- data/lib/bblib/system/system.rb +39 -0
- data/lib/bblib/version.rb +1 -1
- metadata +71 -44
- data/lib/error/abstract.rb +0 -3
- data/lib/hash_path/path_hash.rb +0 -84
- data/lib/hash_path/proc.rb +0 -93
- data/lib/hash_path/processors.rb +0 -239
- data/lib/html/bbhtml.rb +0 -3
- data/lib/system/bbsystem.rb +0 -42
@@ -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
|
data/lib/bblib/core.rb
ADDED
@@ -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
|
-
|
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
|
File without changes
|
@@ -22,10 +22,10 @@ class TreeHash
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def child(key, symbol_sensitive = false)
|
25
|
-
case
|
26
|
-
when
|
25
|
+
case
|
26
|
+
when Hash >= node_class
|
27
27
|
children[key] || (symbol_sensitive ? nil : children[key.to_s.to_sym])
|
28
|
-
when
|
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
|
-
|
37
|
-
when
|
38
|
-
children
|
39
|
-
when
|
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
|
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
|
210
|
-
when
|
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
|
262
|
-
when
|
263
|
-
children.
|
264
|
-
when
|
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
|
274
|
-
when
|
273
|
+
case
|
274
|
+
when Hash >= parent.node_class
|
275
275
|
parent.keys[index]
|
276
|
-
when
|
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
|
331
|
-
when
|
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
|
334
|
+
when Array >= node_class
|
335
335
|
children.delete(key.to_i)
|
336
336
|
else
|
337
337
|
nil
|
@@ -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.
|
File without changes
|
@@ -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[:
|
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
|