bblib 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
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