bblib 2.0.3 → 2.0.4
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/lib/bblib/cli/option.rb +9 -9
- data/lib/bblib/cli/options/basic_option.rb +3 -3
- data/lib/bblib/cli/options/command.rb +1 -1
- data/lib/bblib/cli/options/element_of.rb +24 -0
- data/lib/bblib/cli/options/toggle.rb +2 -2
- data/lib/bblib/cli/opts_parser.rb +2 -1
- data/lib/bblib/core.rb +2 -0
- data/lib/bblib/core/classes/hash_struct.rb +3 -2
- data/lib/bblib/core/hash_path/hash_path.rb +1 -1
- data/lib/bblib/core/hash_path/part.rb +8 -0
- data/lib/bblib/core/mixins/numeric_enhancements.rb +42 -0
- data/lib/bblib/core/util/number.rb +2 -22
- data/lib/bblib/core/util/object.rb +56 -4
- data/lib/bblib/core/util/time.rb +1 -1
- data/lib/bblib/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2470d8a875c6066b41bcb55d580db671e5569cfe69c13241f46a7015a4f87d5
|
|
4
|
+
data.tar.gz: 797a23d1cc99ec3bab8d6945cd03137c1889b96a1ff5279feb07c3e4e445f4a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bdbf6f7993ad6eea502e05d30d4d97a7997d815459b5816164d2d080d6292f7c3b80c31a04916785ea3afd29e92c45a797dcb728dbbe00c7fa62d26436220149
|
|
7
|
+
data.tar.gz: 27bfbbc391b6bd4dc92c6681fc239b7350848be6d1c0f6731a384bab266335058909fe19e9463e8c528eb77d24359580652e5f7182e232d2c51467c43ab848c4
|
data/lib/bblib/cli/option.rb
CHANGED
|
@@ -19,7 +19,6 @@ module BBLib
|
|
|
19
19
|
attr_of [Integer, Range], :position, default: nil, allow_nil: true
|
|
20
20
|
attr_hash :sub_commands, keys: String, values: OptsParser, aliases: [:sub_cmds, :subcommands], default: nil, allow_nil: true, pre_proc: proc { |hash| hash.is_a?(Hash) ? hash.keys_to_s : hash }
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
def to_s
|
|
24
23
|
(flags.sort_by(&:size).join(', ') + " #{placeholder}").strip.ljust(40, ' ') + "\t#{description}"
|
|
25
24
|
end
|
|
@@ -29,35 +28,36 @@ module BBLib
|
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
def retrieve(args, parsed)
|
|
32
|
-
result =
|
|
31
|
+
result = multi_value? ? [] : nil
|
|
33
32
|
index = 0
|
|
34
33
|
until index >= args.size
|
|
35
34
|
begin
|
|
36
|
-
|
|
35
|
+
if args[index].nil? || !flag_match?(args[index].to_s, index)
|
|
37
36
|
index += 1
|
|
38
37
|
next
|
|
39
38
|
end
|
|
40
39
|
values = split(extract(index, args))
|
|
41
40
|
values.each do |value|
|
|
42
41
|
valid!(value)
|
|
43
|
-
if
|
|
44
|
-
result = value
|
|
45
|
-
index = args.size
|
|
46
|
-
else
|
|
42
|
+
if multi_value?
|
|
47
43
|
result << value
|
|
44
|
+
else
|
|
45
|
+
result = value
|
|
48
46
|
end
|
|
47
|
+
index = args.size if singular?
|
|
49
48
|
end
|
|
50
49
|
rescue OptsParserException => e
|
|
51
50
|
raise e if raise_errors?
|
|
52
51
|
end
|
|
52
|
+
index += 1
|
|
53
53
|
end
|
|
54
54
|
raise MissingArgumentException, "A required argument is missing: #{name}" if required? && result.nil?
|
|
55
55
|
result = processor.call(result) if !result.nil? && processor
|
|
56
56
|
process_result(result.nil? ? default : result, args, parsed)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
def
|
|
60
|
-
singular
|
|
59
|
+
def multi_value?
|
|
60
|
+
!singular || delimiter
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def flag_match?(str, index = 0)
|
|
@@ -3,9 +3,9 @@ module BBLib
|
|
|
3
3
|
class BasicOption < Option
|
|
4
4
|
|
|
5
5
|
def extract(index, args)
|
|
6
|
-
args
|
|
7
|
-
raise MissingArgumentException, "No argument was provided for #{name}" if args[index].nil?
|
|
8
|
-
format_value(args.
|
|
6
|
+
args[index] = nil
|
|
7
|
+
raise MissingArgumentException, "No argument was provided for #{name}" if args[index + 1].nil?
|
|
8
|
+
format_value(args[index + 1].tap { args[index + 1] = nil })
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
protected
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module BBLib
|
|
2
|
+
class OptsParser
|
|
3
|
+
class ElementOf < BasicOption
|
|
4
|
+
|
|
5
|
+
attr_ary :options, aliases: :opts
|
|
6
|
+
attr_of Proc, :comparitor, default: proc { |opt, val| opt == val }
|
|
7
|
+
|
|
8
|
+
def valid?(value)
|
|
9
|
+
return false unless options.any? { |opt| comparitor.call(opt, value) }
|
|
10
|
+
return true if validators.empty?
|
|
11
|
+
validators.all? do |validator|
|
|
12
|
+
validator.call(value)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def format_value(value)
|
|
19
|
+
value.to_s
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -4,8 +4,8 @@ module BBLib
|
|
|
4
4
|
|
|
5
5
|
def extract(index, args)
|
|
6
6
|
value = args[index].to_s
|
|
7
|
-
if value =~ /^\-[\w\d]
|
|
8
|
-
args
|
|
7
|
+
if value =~ /^\-[\w\d]$|^\-{2}/ || flags.include?(value)
|
|
8
|
+
args[index] = nil
|
|
9
9
|
elsif value =~ /^\-[\w\d]+$/
|
|
10
10
|
flag = flags.find do |flag|
|
|
11
11
|
next unless flag =~ /^\-[\w\d]$/
|
|
@@ -13,6 +13,7 @@ require_relative 'options/regexp'
|
|
|
13
13
|
require_relative 'options/symbol'
|
|
14
14
|
require_relative 'options/toggle'
|
|
15
15
|
require_relative 'options/untoggle'
|
|
16
|
+
require_relative 'options/element_of'
|
|
16
17
|
|
|
17
18
|
module BBLib
|
|
18
19
|
class OptsParser
|
|
@@ -49,7 +50,7 @@ module BBLib
|
|
|
49
50
|
options.sort_by { |opt| opt.position || 10**100 }.each do |option|
|
|
50
51
|
option.retrieve(args, hash)
|
|
51
52
|
end
|
|
52
|
-
end.merge(arguments: args)
|
|
53
|
+
end.merge(arguments: args.compact)
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def help
|
data/lib/bblib/core.rb
CHANGED
|
@@ -28,6 +28,8 @@ require_relative 'core/util/array'
|
|
|
28
28
|
require_relative 'core/util/logging'
|
|
29
29
|
require_relative 'core/util/os'
|
|
30
30
|
|
|
31
|
+
require_relative 'core/mixins/numeric_enhancements'
|
|
32
|
+
|
|
31
33
|
require_relative 'core/classes/hash_struct'
|
|
32
34
|
require_relative 'core/classes/task_timer'
|
|
33
35
|
require_relative 'core/classes/tree_hash'
|
|
@@ -35,7 +35,8 @@ module BBLib
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
class Hash
|
|
38
|
-
def to_hash_struct
|
|
39
|
-
|
|
38
|
+
def to_hash_struct(recursive = true)
|
|
39
|
+
hash = recursive ? self.hmap { |k, v| [k, v.respond_to?(:to_hash_struct) ? v.to_hash_struct(recursive) : v] } : self
|
|
40
|
+
BBLib::HashStruct.new.merge(hash)
|
|
40
41
|
end
|
|
41
42
|
end
|
|
@@ -44,7 +44,7 @@ end
|
|
|
44
44
|
|
|
45
45
|
module BBLib
|
|
46
46
|
def self.hash_path(hash, *paths, multi_path: false, multi_join: false, multi_join_hash: false)
|
|
47
|
-
tree = TreeHash.new(hash
|
|
47
|
+
tree = TreeHash.new(hash)
|
|
48
48
|
if multi_path
|
|
49
49
|
tree.find_multi(*paths).map { |r| r.map { |sr| sr.value } }
|
|
50
50
|
elsif multi_join
|
|
@@ -47,6 +47,14 @@ class HashPath
|
|
|
47
47
|
matches << v if key_match?(k, object) && evaluates?(v)
|
|
48
48
|
matches += matches(v) if recursive? && v.children?
|
|
49
49
|
end
|
|
50
|
+
else
|
|
51
|
+
casted = case
|
|
52
|
+
when !object.value.is_a?(Hash) && !object.value.is_a?(Array) && object.value.respond_to?(:to_tree_hash) && object.method(:to_tree_hash).arity <= 0
|
|
53
|
+
object.value.to_tree_hash
|
|
54
|
+
when object.value.is_a?(BBLib::Effortless)
|
|
55
|
+
object.value.serialize.to_tree_hash
|
|
56
|
+
end
|
|
57
|
+
matches += matches(casted) if casted
|
|
50
58
|
end
|
|
51
59
|
matches
|
|
52
60
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module BBLib
|
|
2
|
+
# This module contains methods that are intended to be mixed in to
|
|
3
|
+
# Integer and Float classes. They mostly provide convenience methods.
|
|
4
|
+
module NumericEnhancements
|
|
5
|
+
|
|
6
|
+
# Create a method for all types of times. Makes it easy
|
|
7
|
+
# to convert to any range of seconds. e.g. 5.hours returns 3600
|
|
8
|
+
TIME_EXPS.each do |name, data|
|
|
9
|
+
[name, name.to_s.pluralize].each do |method|
|
|
10
|
+
define_method(method) {
|
|
11
|
+
(self * data[:mult]) / 1000
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Converts a number to english (only language supported currently)
|
|
17
|
+
# For example, 501.spell_out returns 'five hundred and one'
|
|
18
|
+
def spell_out(include_and: true)
|
|
19
|
+
BBLib.number_spelled_out(self, include_and: include_and)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Convert this integer into a string with every three digits separated by a delimiter
|
|
23
|
+
# on the left side of the decimal
|
|
24
|
+
def to_delimited_s(delim = ',')
|
|
25
|
+
split = self.to_s.split('.')
|
|
26
|
+
split[0] = split.first.reverse.gsub(/(\d{3})/, "\\1#{delim}").reverse
|
|
27
|
+
split.join('.').uncapsulate(',')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns the time x seconds ago from now (x == this number)
|
|
31
|
+
def ago
|
|
32
|
+
Time.now - self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns the time x seconds ago from now (x == this number)
|
|
36
|
+
def from_now
|
|
37
|
+
Time.now + self
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Numeric.send(:include, NumericEnhancements)
|
|
42
|
+
end
|
|
@@ -57,6 +57,7 @@ module BBLib
|
|
|
57
57
|
]
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
# TODO: Support floats eventually?
|
|
60
61
|
def self.number_spelled_out(number, range = 0, include_and: true)
|
|
61
62
|
number = number.to_i
|
|
62
63
|
negative = number.negative?
|
|
@@ -73,7 +74,7 @@ module BBLib
|
|
|
73
74
|
when 100..999
|
|
74
75
|
str << NUMBER_WORDS[:special][three_digit.to_s[0].to_i]
|
|
75
76
|
str << 'hundred'
|
|
76
|
-
str << 'and' if include_and
|
|
77
|
+
str << 'and' if include_and && !three_digit.to_s.end_with?('00')
|
|
77
78
|
if three_digit.to_s[-2].to_i == 1
|
|
78
79
|
str << NUMBER_WORDS[:special][three_digit.to_s[-2..-1].to_i]
|
|
79
80
|
else
|
|
@@ -87,24 +88,3 @@ module BBLib
|
|
|
87
88
|
str.compact.join(' ')).gsub(/\s+/, ' ')
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
|
-
|
|
91
|
-
class Integer
|
|
92
|
-
# Convert this integer into a string with every three digits separated by a delimiter
|
|
93
|
-
def to_delimited_s(delim = ',')
|
|
94
|
-
self.to_s.reverse.gsub(/(\d{3})/, "\\1#{delim}").reverse.uncapsulate(',')
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def spell_out
|
|
98
|
-
BBLib.number_spelled_out(self)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
class Float
|
|
103
|
-
# Convert this integer into a string with every three digits separated by a delimiter
|
|
104
|
-
# on the left side of the decimal
|
|
105
|
-
def to_delimited_s(delim = ',')
|
|
106
|
-
split = self.to_s.split('.')
|
|
107
|
-
split[0] = split.first.reverse.gsub(/(\d{3})/, "\\1#{delim}").reverse
|
|
108
|
-
split.join('.').uncapsulate(',')
|
|
109
|
-
end
|
|
110
|
-
end
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
module BBLib
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
# Easy way to see if all objects in an array are of a given class.
|
|
3
|
+
def self.are_all?(klass, *objects)
|
|
4
|
+
objects.all? { |object| object.is_a?(klass) }
|
|
4
5
|
end
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
# Easy way to see if any of the passed objects are of the given class.
|
|
8
|
+
def self.are_any?(klass, *objects)
|
|
9
|
+
objects.any? { |object| object.is_a?(klass) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Checks to see if an object is of any of the given classes.
|
|
13
|
+
def self.is_any?(object, *klasses)
|
|
14
|
+
klasses.any? { |klass| object.is_a?(klass) }
|
|
8
15
|
end
|
|
9
16
|
|
|
10
17
|
# Takes any type of object and converts it into a hash based on its instance
|
|
@@ -34,10 +41,14 @@ module BBLib
|
|
|
34
41
|
hash
|
|
35
42
|
end
|
|
36
43
|
|
|
44
|
+
# Extracts all hash based arguments from an ary of arguments. Only hash pairs with
|
|
45
|
+
# a symbol as the key are returned. Use hash_args if you also want to treat
|
|
46
|
+
# String keys as named arguments.
|
|
37
47
|
def self.named_args(*args)
|
|
38
48
|
args.last.is_a?(Hash) && args.last.keys.all? { |k| k.is_a?(Symbol) } ? args.last : {}
|
|
39
49
|
end
|
|
40
50
|
|
|
51
|
+
# Same as standard named_args but removes the named arguments from the array.
|
|
41
52
|
def self.named_args!(*args)
|
|
42
53
|
if args.last.is_a?(Hash) && args.last.keys.all? { |k| k.is_a?(Symbol) }
|
|
43
54
|
args.delete_at(-1)
|
|
@@ -46,10 +57,12 @@ module BBLib
|
|
|
46
57
|
end
|
|
47
58
|
end
|
|
48
59
|
|
|
60
|
+
# Similar to named_args but also treats String keys as named arguments.
|
|
49
61
|
def self.hash_args(*args)
|
|
50
62
|
args.find_all { |a| a.is_a?(Hash) }.each_with_object({}) { |a, h| h.merge!(a) }
|
|
51
63
|
end
|
|
52
64
|
|
|
65
|
+
# Send a chain of methods to an object and each result of the previous method.
|
|
53
66
|
def self.recursive_send(obj, *methods)
|
|
54
67
|
methods.each do |args|
|
|
55
68
|
obj = obj.send(*args)
|
|
@@ -57,13 +70,52 @@ module BBLib
|
|
|
57
70
|
obj
|
|
58
71
|
end
|
|
59
72
|
|
|
73
|
+
# Returns the encapsulating object space of a given class.
|
|
74
|
+
# Ex: For a class called BBLib::String, this method will return BBLib as the namespace.
|
|
75
|
+
# Ex2: For a class BBLib::String::Char, this method will return BBLib::String as the namespace.
|
|
60
76
|
def self.namespace_of(klass)
|
|
61
77
|
split = klass.to_s.split('::')
|
|
62
78
|
return klass if split.size == 1
|
|
63
79
|
Object.const_get(split[0..-2].join('::'))
|
|
64
80
|
end
|
|
65
81
|
|
|
82
|
+
# Returns the root namespace of a given class if it is nested.
|
|
66
83
|
def self.root_namespace_of(klass)
|
|
67
84
|
Object.const_get(klass.to_s.gsub(/::.*/, ''))
|
|
68
85
|
end
|
|
86
|
+
|
|
87
|
+
# Create a new class or module recursively within a provided namespace. If a
|
|
88
|
+
# constant matching the requested one already exist it is returned. Any
|
|
89
|
+
# block passed to this method will be evaled in the created/found constant.
|
|
90
|
+
def self.const_create(name, value, strict: true, base: Object, type_of_missing: nil, &block)
|
|
91
|
+
namespace = base
|
|
92
|
+
unless base.const_defined?(name)
|
|
93
|
+
type_of_missing = Module unless type_of_missing
|
|
94
|
+
name = name.uncapsulate('::')
|
|
95
|
+
if name.include?('::')
|
|
96
|
+
namespaces = name.split('::')
|
|
97
|
+
name = namespaces.pop
|
|
98
|
+
namespaces.each do |constant|
|
|
99
|
+
unless namespace.const_defined?(constant)
|
|
100
|
+
match = namespace.const_set(constant, type_of_missing.new)
|
|
101
|
+
end
|
|
102
|
+
namespace = namespace.const_get(constant)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
namespace.const_set(name, value)
|
|
106
|
+
end
|
|
107
|
+
object = namespace.const_get(name)
|
|
108
|
+
raise TypeError, "Expected a #{value.class} but #{namespace}::#{name} is a #{object.class}" if strict && object.class != value.class
|
|
109
|
+
object.tap do |constant|
|
|
110
|
+
constant.send(:class_exec, &block) if block
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.class_create(name, *args, **opts, &block)
|
|
115
|
+
const_create(name, Class.new(*args), **opts, &block)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.module_create(name, *args, **opts, &block)
|
|
119
|
+
const_create(name, Module.new(*args), **opts, &block)
|
|
120
|
+
end
|
|
69
121
|
end
|
data/lib/bblib/core/util/time.rb
CHANGED
data/lib/bblib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bblib
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brandon Black
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-11-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -99,6 +99,7 @@ files:
|
|
|
99
99
|
- lib/bblib/cli/options/bool.rb
|
|
100
100
|
- lib/bblib/cli/options/command.rb
|
|
101
101
|
- lib/bblib/cli/options/date.rb
|
|
102
|
+
- lib/bblib/cli/options/element_of.rb
|
|
102
103
|
- lib/bblib/cli/options/float.rb
|
|
103
104
|
- lib/bblib/cli/options/integer.rb
|
|
104
105
|
- lib/bblib/cli/options/json.rb
|
|
@@ -127,6 +128,7 @@ files:
|
|
|
127
128
|
- lib/bblib/core/mixins/family_tree.rb
|
|
128
129
|
- lib/bblib/core/mixins/hooks.rb
|
|
129
130
|
- lib/bblib/core/mixins/logger.rb
|
|
131
|
+
- lib/bblib/core/mixins/numeric_enhancements.rb
|
|
130
132
|
- lib/bblib/core/mixins/prototype.rb
|
|
131
133
|
- lib/bblib/core/mixins/serializer.rb
|
|
132
134
|
- lib/bblib/core/mixins/simple_init.rb
|