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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: debe993c7a7d4324816c660a01fb9befab19a636aaf16ee403924051a12cd838
4
- data.tar.gz: 9e8f4aa2c6f6705ae982b086d536c93073e11725ccc8bf137f581c22a355fde5
3
+ metadata.gz: f2470d8a875c6066b41bcb55d580db671e5569cfe69c13241f46a7015a4f87d5
4
+ data.tar.gz: 797a23d1cc99ec3bab8d6945cd03137c1889b96a1ff5279feb07c3e4e445f4a1
5
5
  SHA512:
6
- metadata.gz: ee2dff5db783cc66d30f0f9254a538014f41fbb58f81d2ec21c721d6900b6a5aa1bc8aee06b45cc3630b6e4d304c635c754a2cb6cc152ed42db61c9298db1f4f
7
- data.tar.gz: a24156d985bded501a00d8e4e35764508dcc0a509c638c3fa9f31c528e3befe1d43014b549b4cbeb1ae5a3fbe1de6ad553ce8f489e246dc58f698f143abc7661
6
+ metadata.gz: bdbf6f7993ad6eea502e05d30d4d97a7997d815459b5816164d2d080d6292f7c3b80c31a04916785ea3afd29e92c45a797dcb728dbbe00c7fa62d26436220149
7
+ data.tar.gz: 27bfbbc391b6bd4dc92c6681fc239b7350848be6d1c0f6731a384bab266335058909fe19e9463e8c528eb77d24359580652e5f7182e232d2c51467c43ab848c4
@@ -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 = singular? ? nil : []
31
+ result = multi_value? ? [] : nil
33
32
  index = 0
34
33
  until index >= args.size
35
34
  begin
36
- unless flag_match?(args[index].to_s, index)
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 singular?
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 singular?
60
- singular && !delimiter
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.delete_at(index)
7
- raise MissingArgumentException, "No argument was provided for #{name}" if args[index].nil?
8
- format_value(args.delete_at(index).to_s)
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
@@ -8,7 +8,7 @@ module BBLib
8
8
  end
9
9
 
10
10
  def extract(index, args)
11
- args.delete_at(index).to_s
11
+ args[index].tap { args[index] = nil }
12
12
  end
13
13
 
14
14
  end
@@ -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]$/ || flags.include?(value)
8
- args.delete_at(index)
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
- BBLib::HashStruct.new.merge(self)
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.to_h)
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
- def self.are_all?(klass, *vars)
3
- vars.all? { |var| var.is_a?(klass) }
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
- def self.is_any?(obj, *klasses)
7
- klasses.any? { |klass| obj.is_a?(klass) }
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
@@ -71,7 +71,7 @@ module BBLib
71
71
  atto: {
72
72
  mult: 0.000000000000001,
73
73
  styles: { long: ' attosecond', medium: ' atto', short: 'as' },
74
- exp: %w(attoseconds atto attoseconds attos as)
74
+ exp: %w(attosecond atto attoseconds attos as)
75
75
  },
76
76
  femto: {
77
77
  mult: 0.000000000001,
data/lib/bblib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module BBLib
2
- VERSION = '2.0.3'.freeze
2
+ VERSION = '2.0.4'.freeze
3
3
  end
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.3
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-09-21 00:00:00.000000000 Z
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