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.
- 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
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
module BBLib
|
|
3
|
+
module Delegator
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
base.send(:attr_ary, :instance_delegates)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def delegates
|
|
10
|
+
(instance_delegates + self.class.delegates).uniq
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def method_missing(method, *args, &block)
|
|
16
|
+
delegates.each do |delegate|
|
|
17
|
+
case delegate
|
|
18
|
+
when Symbol
|
|
19
|
+
next unless respond_to?(delegate) && method(delegate).arity == 0
|
|
20
|
+
object = send(delegate)
|
|
21
|
+
next unless object.respond_to?(method)
|
|
22
|
+
return object.send(method, *args, &block)
|
|
23
|
+
else
|
|
24
|
+
next unless delegate.respond_to?(method)
|
|
25
|
+
return delegate.send(method, *args, &block)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def respond_to_missing?(method, include_private = false)
|
|
32
|
+
return super if self.class.delegate_fast
|
|
33
|
+
super || delegates.any? do |delegate|
|
|
34
|
+
next if delegate == self # Protection from recursion
|
|
35
|
+
case delegate
|
|
36
|
+
when Symbol
|
|
37
|
+
self.method(delegate)&.arity == 0 &&
|
|
38
|
+
send(delegate).respond_to?(method)
|
|
39
|
+
else
|
|
40
|
+
delegate.respond_to?(method)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def delegate_to(*mthds)
|
|
46
|
+
mthds.flatten.each do |method|
|
|
47
|
+
next if instance_delegates.include?(method)
|
|
48
|
+
instance_delegates << method
|
|
49
|
+
end
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module ClassMethods
|
|
54
|
+
# When turned on the respond_to_missing method is left unchanged.
|
|
55
|
+
# This GREATLY speeds up the instantiation of classes with lots of
|
|
56
|
+
# calls to respond_to?
|
|
57
|
+
def delegate_fast(*args)
|
|
58
|
+
return @delegate_fast ||= _ancestor_delegate_fast if args.empty?
|
|
59
|
+
@delegate_fast = args.first ? true : false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def delegate_to(*mthds)
|
|
63
|
+
mthds.flatten.each do |method|
|
|
64
|
+
next if delegates.include?(method)
|
|
65
|
+
delegates << method
|
|
66
|
+
end
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def _ancestor_delegate_fast
|
|
71
|
+
ancestors.reverse.find do |anc|
|
|
72
|
+
next unless anc.respond_to?(:delegate_fast)
|
|
73
|
+
return anc.delegate_fast
|
|
74
|
+
end
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def delegates
|
|
79
|
+
@delegates ||= ancestor_delegates
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def ancestor_delegates
|
|
83
|
+
ancestors.reverse.flat_map do |anc|
|
|
84
|
+
next if anc == self || !anc.respond_to?(:delegates)
|
|
85
|
+
anc.delegates
|
|
86
|
+
end.compact.uniq
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
File without changes
|
|
@@ -18,7 +18,7 @@ module BBLib
|
|
|
18
18
|
def direct_descendants(include_singletons = false)
|
|
19
19
|
return _inherited_by if BBLib.in_opal?
|
|
20
20
|
ObjectSpace.each_object(Class).select do |c|
|
|
21
|
-
(include_singletons || !c.singleton_class?) && c.ancestors[1] == self
|
|
21
|
+
(include_singletons || !c.singleton_class?) && c.ancestors[1..-1].find { |k| k.is_a?(Class) } == self
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -6,7 +6,11 @@ module BBLib
|
|
|
6
6
|
module SimpleInit
|
|
7
7
|
attr_reader :_init_type
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# strict - Raise exceptions for unknown named attributes
|
|
10
|
+
# loose - Ignore unknown named attributes
|
|
11
|
+
# collect - Put unknown named attributes into the attribute
|
|
12
|
+
# configured by collect_attribute
|
|
13
|
+
INIT_TYPES = [:strict, :loose, :collect].freeze
|
|
10
14
|
|
|
11
15
|
def self.included(base)
|
|
12
16
|
base.extend ClassMethods
|
|
@@ -20,6 +24,8 @@ module BBLib
|
|
|
20
24
|
result = instance_eval(&block)
|
|
21
25
|
simple_init_block_result(result) if respond_to?(:simple_init_block_result, true)
|
|
22
26
|
end
|
|
27
|
+
send(:simple_postinit, *args, &block) if respond_to?(:simple_postinit, true)
|
|
28
|
+
self
|
|
23
29
|
end
|
|
24
30
|
end
|
|
25
31
|
|
|
@@ -39,6 +45,8 @@ module BBLib
|
|
|
39
45
|
end
|
|
40
46
|
raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\" for #{self}" unless klass
|
|
41
47
|
klass == self ? __new(*args, &block) : klass.new(*args, &block)
|
|
48
|
+
elsif named[init_foundation_method].nil? && init_foundation_default_class != self
|
|
49
|
+
init_foundation_default_class.new(*args, &block)
|
|
42
50
|
else
|
|
43
51
|
__new(*args, &block)
|
|
44
52
|
end
|
|
@@ -64,6 +72,8 @@ module BBLib
|
|
|
64
72
|
end
|
|
65
73
|
raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\"" unless klass
|
|
66
74
|
klass == self ? super : klass.new(*args, &block)
|
|
75
|
+
elsif named[init_foundation_method].nil? && init_foundation_default_class != self && init_foundation_default_class < self
|
|
76
|
+
init_foundation_default_class.new(*args, &block)
|
|
67
77
|
else
|
|
68
78
|
super
|
|
69
79
|
end
|
|
@@ -99,6 +109,23 @@ module BBLib
|
|
|
99
109
|
self.init_foundation_compare(&block) if block
|
|
100
110
|
end
|
|
101
111
|
|
|
112
|
+
def init_foundation_default_class
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def collect_method(name = nil)
|
|
117
|
+
@collect_method = name if name
|
|
118
|
+
@collect_method ||= _super_collect_method
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def _super_collect_method
|
|
122
|
+
ancestors.each do |ancestor|
|
|
123
|
+
next if ancestor == self
|
|
124
|
+
return ancestor.collect_method if ancestor.respond_to?(:collect_method)
|
|
125
|
+
end
|
|
126
|
+
:attributes
|
|
127
|
+
end
|
|
128
|
+
|
|
102
129
|
def ancestor_init_foundation_method
|
|
103
130
|
anc = ancestors.find do |a|
|
|
104
131
|
next if a == self
|
|
@@ -175,16 +202,27 @@ module BBLib
|
|
|
175
202
|
next unless !set_v_arg.include?(method) && details[:options][:required] && !named.include?(method) && !send(method)
|
|
176
203
|
method
|
|
177
204
|
end.compact
|
|
178
|
-
raise ArgumentError, "You are missing the following required #{BBLib.pluralize('argument', missing.size)}: #{missing.join_terms}" unless missing.empty?
|
|
205
|
+
raise ArgumentError, "You are missing the following required #{BBLib.pluralize('argument', missing.size)} for #{self.class}: #{missing.join_terms}" unless missing.empty?
|
|
179
206
|
end
|
|
180
207
|
named.each do |method, value|
|
|
181
208
|
next if method == self.class.init_foundation_method
|
|
182
209
|
setter = "#{method}="
|
|
183
210
|
exists = respond_to?(setter)
|
|
184
|
-
|
|
211
|
+
if !exists && self.class.init_type == :strict
|
|
212
|
+
raise ArgumentError, "Undefined attribute #{setter} for class #{self.class}."
|
|
213
|
+
elsif !exists && self.class.init_type == :collect
|
|
214
|
+
_collect_attribute(method, value)
|
|
215
|
+
end
|
|
185
216
|
next unless exists
|
|
186
217
|
send(setter, value)
|
|
187
218
|
end
|
|
188
219
|
end
|
|
220
|
+
|
|
221
|
+
def _collect_attribute(method, value)
|
|
222
|
+
inst_name = "@#{self.class.collect_method}"
|
|
223
|
+
hash = instance_variable_get(inst_name)
|
|
224
|
+
hash = instance_variable_set(inst_name, {}) unless hash.is_a?(Hash)
|
|
225
|
+
hash[method] = value
|
|
226
|
+
end
|
|
189
227
|
end
|
|
190
228
|
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -14,7 +14,7 @@ module BBLib
|
|
|
14
14
|
# @param [Boolean] files If true, paths to files matching the filter will be returned.
|
|
15
15
|
# @param [Boolean] dirs If true, paths to dirs matching the filter will be returned.
|
|
16
16
|
# @param [Array] exclude Can be an array of regular expressions or strings that should be ignored when scanning. * in a string is expanded into .*, but all other characters are literal.
|
|
17
|
-
def self.scan_dir(path, *filters, recursive: false, files: true, dirs: true, exclude: [], &block)
|
|
17
|
+
def self.scan_dir(path, *filters, recursive: false, files: true, dirs: true, exclude: [], filter_base: true, &block)
|
|
18
18
|
return [] unless Dir.exist?(path)
|
|
19
19
|
filters = filters.map { |filter| filter.is_a?(Regexp) ? filter : /^#{Regexp.quote(filter).gsub('\\*', '.*')}$/ }
|
|
20
20
|
exclude = exclude ? [exclude].flatten.map { |exp| exp.is_a?(Regexp) ? exp : /^#{Regexp.quote(exp).gsub('\\*', '.*')}$/ } : []
|
|
@@ -22,12 +22,12 @@ module BBLib
|
|
|
22
22
|
next if item =~ /^\.{1,2}$/ || (!exclude.empty? && exclude.any? { |exp| item =~ exp })
|
|
23
23
|
item = "#{path}/#{item}".gsub('\\', '/')
|
|
24
24
|
if File.file?(item)
|
|
25
|
-
if files && (filters.empty? || filters.any? { |filter| item =~ filter })
|
|
25
|
+
if files && (filters.empty? || filters.any? { |filter| item =~ filter || filter_base && item.file_name =~ filter })
|
|
26
26
|
block_given? ? yield(item) : item
|
|
27
27
|
end
|
|
28
28
|
elsif File.directory?(item)
|
|
29
29
|
recur = recursive ? scan_dir(item, *filters, recursive: recursive, exclude: exclude, files: files, dirs: dirs, &block) : []
|
|
30
|
-
if dirs && (filters.empty? || filters.any? { |filter| item =~ filter })
|
|
30
|
+
if dirs && (filters.empty? || filters.any? { |filter| item =~ filter || filter_base && item.file_name =~ filter })
|
|
31
31
|
(block_given? ? yield(item) : [item] + recur)
|
|
32
32
|
elsif recursive
|
|
33
33
|
recur
|
|
@@ -37,13 +37,13 @@ module BBLib
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Uses BBLib.scan_dir but returns only files
|
|
40
|
-
def self.scan_files(path, *filters, recursive: false, exclude: [], &block)
|
|
41
|
-
scan_dir(path, *filters, recursive: recursive, dirs: false, exclude: exclude, &block)
|
|
40
|
+
def self.scan_files(path, *filters, recursive: false, exclude: [], filter_base: true, &block)
|
|
41
|
+
scan_dir(path, *filters, recursive: recursive, dirs: false, exclude: exclude, filter_base: filter_base, &block)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Uses BBLib.scan_dir but returns only directories.
|
|
45
|
-
def self.scan_dirs(path, *filters, recursive: false, exclude: [], &block)
|
|
46
|
-
scan_dir(path, *filters, recursive: recursive, files: false, exclude: exclude, &block)
|
|
45
|
+
def self.scan_dirs(path, *filters, recursive: false, exclude: [], filter_base: true, &block)
|
|
46
|
+
scan_dir(path, *filters, recursive: recursive, files: false, exclude: exclude, filter_base: filter_base, &block)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# Shorthand method to write a string to disk. By default the
|
|
@@ -104,6 +104,30 @@ module BBLib
|
|
|
104
104
|
zettabyte: { mult: 1024**7, exp: %w(zb zetta z zbyte zettabyte), styles: { short: 'ZB', long: ' zettabyte' } },
|
|
105
105
|
yottabyte: { mult: 1024**8, exp: %w(yb yotta y ybyte yottabyte), styles: { short: 'YB', long: ' yottabyte' } }
|
|
106
106
|
}.freeze
|
|
107
|
+
|
|
108
|
+
# Basic detection for whether or not a file is binary or not
|
|
109
|
+
def self.binary?(file, bytes: 1024, ctrl_threshold: 0.5, binary_threshold: 0.05)
|
|
110
|
+
ascii = 0
|
|
111
|
+
ctrl = 0
|
|
112
|
+
binary = 0
|
|
113
|
+
|
|
114
|
+
read_bytes = File.open(file, 'rb') { |io| io.read(bytes) }
|
|
115
|
+
|
|
116
|
+
return false if read_bytes.nil? || read_bytes.empty?
|
|
117
|
+
|
|
118
|
+
read_bytes.each_byte do |byte|
|
|
119
|
+
case byte
|
|
120
|
+
when 0..31
|
|
121
|
+
ctrl += 1
|
|
122
|
+
when 32..127
|
|
123
|
+
ascii += 1
|
|
124
|
+
else
|
|
125
|
+
binary += 1
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
ctrl.to_f / ascii > ctrl_threshold || binary.to_f / ascii > binary_threshold
|
|
130
|
+
end
|
|
107
131
|
end
|
|
108
132
|
|
|
109
133
|
# Monkey patches for the Numeric class
|
|
@@ -10,10 +10,11 @@ module BBLib
|
|
|
10
10
|
log = ::Logger.new(STDOUT)
|
|
11
11
|
log.level = ::Logger::INFO
|
|
12
12
|
log.formatter = proc do |severity, datetime, progname, msg|
|
|
13
|
+
severity = severity.to_s.to_color(severity) if BBLib.color_logs
|
|
13
14
|
if msg.is_a?(Exception)
|
|
14
15
|
msg = msg.inspect + "\n\t" + msg.backtrace.join("\n\t")
|
|
15
16
|
end
|
|
16
|
-
"
|
|
17
|
+
"#{datetime} [#{severity}] #{msg.to_s.chomp}\n"
|
|
17
18
|
end
|
|
18
19
|
log.datetime_format = '%Y-%m-%d %H:%M:%S'
|
|
19
20
|
log
|
|
@@ -32,10 +33,18 @@ module BBLib
|
|
|
32
33
|
@logger_on
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
def self.color_logs
|
|
37
|
+
@color_logs
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.color_logs=(toggle)
|
|
41
|
+
@color_logs = (toggle ? true : false)
|
|
42
|
+
end
|
|
43
|
+
|
|
35
44
|
class << self
|
|
36
45
|
[:fatal, :error, :warn, :info, :debug].each do |sev|
|
|
37
46
|
define_method(sev) do |*args|
|
|
38
|
-
logger.send(sev, *args)
|
|
47
|
+
logger.send(sev, *args) if logger
|
|
39
48
|
end
|
|
40
49
|
end
|
|
41
50
|
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
# frozen_string_literal: true
|
|
3
1
|
require_relative 'matching'
|
|
4
2
|
require_relative 'roman'
|
|
5
|
-
require_relative 'fuzzy_matcher'
|
|
6
3
|
require_relative 'cases'
|
|
7
4
|
require_relative 'regexp'
|
|
8
5
|
require_relative 'pluralization'
|
|
@@ -25,9 +22,12 @@ module BBLib
|
|
|
25
22
|
.map { |m| convert ? m.to_f : m }
|
|
26
23
|
end
|
|
27
24
|
|
|
25
|
+
EXTRACT_NUMBER_REGEXP = /(?<=[^\.]|^)\d+\.\d+(?=[^\.]|$)|(?<=[^\.\d]|^)\d+(?=[^\.\d]|$)/
|
|
26
|
+
EXTRACT_NUMBER_REGEXP_NO_INNER = /(?<=[^\.]|^)\d+\.\d+(?=[^\.]|$)|(?<=[^\.\d\w]|^)\d+(?=[^\.\d\w]|$)/
|
|
27
|
+
|
|
28
28
|
# Extracts any correctly formed integers or floats from a string
|
|
29
|
-
def self.extract_numbers(str, convert: true)
|
|
30
|
-
str.scan(
|
|
29
|
+
def self.extract_numbers(str, convert: true, include_inner: true)
|
|
30
|
+
str.scan(include_inner ? EXTRACT_NUMBER_REGEXP : EXTRACT_NUMBER_REGEXP_NO_INNER)
|
|
31
31
|
.map { |f| convert ? (f.include?('.') ? f.to_f : f.to_i) : f }
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -99,15 +99,18 @@ module BBLib
|
|
|
99
99
|
# a context (either a Hash or Object) to then interpolate in placeholders.
|
|
100
100
|
# The default pattern looks for {{method_name}} within the string but can be
|
|
101
101
|
# customized to a different pattern by setting the pattern named argument.
|
|
102
|
-
def self.pattern_render(text, context = {}
|
|
102
|
+
def self.pattern_render(text, context = {})
|
|
103
103
|
raise ArgumentError, "Expected text argument to be a String, got a #{text.class}" unless text.is_a?(String)
|
|
104
|
-
|
|
104
|
+
# TODO Make patterns customizable
|
|
105
|
+
pattern = /\{{2}.*?\}{2}/
|
|
106
|
+
field_pattern = /(?<=^\{{2}).*(?=\}{2})/
|
|
107
|
+
txt = text.dup
|
|
105
108
|
txt.scan(pattern).each do |match|
|
|
106
109
|
field = match.scan(field_pattern).first
|
|
107
110
|
next unless field
|
|
108
111
|
value = case context
|
|
109
112
|
when Hash
|
|
110
|
-
context
|
|
113
|
+
context.hpath(field).first
|
|
111
114
|
else
|
|
112
115
|
context.send(field) if context.respond_to?(field)
|
|
113
116
|
end.to_s
|
|
@@ -130,7 +133,7 @@ class String
|
|
|
130
133
|
|
|
131
134
|
# Split on delimiters
|
|
132
135
|
def quote_split(*delimiters)
|
|
133
|
-
encap_split(
|
|
136
|
+
encap_split(%w{" '}, *delimiters)
|
|
134
137
|
end
|
|
135
138
|
|
|
136
139
|
alias qsplit quote_split
|
|
@@ -138,21 +141,12 @@ class String
|
|
|
138
141
|
# Split on only delimiters not between specific encapsulators
|
|
139
142
|
# Various characters are special and automatically recognized such as parens
|
|
140
143
|
# which automatically match anything between a begin and end character.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
when '{'
|
|
148
|
-
'\\{\\}'
|
|
149
|
-
when '<'
|
|
150
|
-
'\\<\\>'
|
|
151
|
-
else
|
|
152
|
-
encapsulator
|
|
153
|
-
end
|
|
154
|
-
patterns = delimiters.map { |d| /#{Regexp.escape(d)}(?=(?:[^#{pattern}]|[#{pattern}][^#{pattern}]*[#{pattern}])*$)/}
|
|
155
|
-
msplit(*patterns)
|
|
144
|
+
#
|
|
145
|
+
# Regex below is no longer used because of how inefficient it is.
|
|
146
|
+
# Comment is left in case it is ever useful again
|
|
147
|
+
# /(?<group>\((?:[^\(\)]*|\g<group>)*\)[^\(\)]*?),|,(?<=[^\(\)|$])/
|
|
148
|
+
def encap_split(expressions, *delimiters, **opts)
|
|
149
|
+
BBLib::Splitter.split(self, *delimiters, **opts.merge(expressions: expressions))
|
|
156
150
|
end
|
|
157
151
|
|
|
158
152
|
alias esplit encap_split
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require_relative 'task_timer'
|
|
3
|
-
require_relative 'cron'
|
|
4
|
-
|
|
5
1
|
module BBLib
|
|
6
2
|
# Parses known time based patterns out of a string to construct a numeric duration.
|
|
7
3
|
def self.parse_duration(str, output: :sec, min_interval: :sec)
|
|
@@ -173,7 +169,7 @@ end
|
|
|
173
169
|
|
|
174
170
|
class Numeric
|
|
175
171
|
include BBLib::Durations
|
|
176
|
-
|
|
172
|
+
|
|
177
173
|
def to_duration(input: :sec, stop: :milli, style: :medium)
|
|
178
174
|
BBLib.to_duration self, input: input, stop: stop, style: style
|
|
179
175
|
end
|