bblib 0.4.1 → 1.0.2

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.
data/lib/mixins/hooks.rb CHANGED
@@ -83,17 +83,21 @@ module BBLib
83
83
  # modify_args - Replaces the original args with the returned value of the
84
84
  # send_method - Sends the method name as an argument to the hooked method.
85
85
  # before hook method.
86
+ # try_first - Sends the args to the desired hook first and if the result
87
+ # is non-nil, the result is sent instead of calling the hooked
88
+ # method.
86
89
  def _hook_before_method(method, hook, opts = {})
87
90
  return false if method == hook
88
91
  _add_hooked_method(:before, hook, method)
89
92
  original = instance_method(method)
90
93
  @_defining_hook = true
91
94
  define_method(method) do |*args, &block|
92
- if opts[:send_args] || opts[:send_arg] || opts[:modify_args] || opts[:send_method]
95
+ if opts[:send_args] || opts[:send_arg] || opts[:modify_args] || opts[:send_method] || opts[:try_first]
93
96
  margs = args
94
97
  margs = [method] + args if opts[:send_method]
95
98
  margs = args + [opts[:add_args]].flatten(1) if opts[:add_args]
96
99
  result = method(hook).call(*margs)
100
+ return result if result && opts[:try_first]
97
101
  args = result if opts[:modify_args]
98
102
  else
99
103
  method(hook).call
@@ -112,6 +116,7 @@ module BBLib
112
116
  # modify_value - Opts must also include one of the two above. Passes the returned
113
117
  # => value of the method to the hook and returns the hooks value
114
118
  # => rather than the original methods value.
119
+ # send_all - Sends a hash containing the args, method and value (return).
115
120
  def _hook_after_method(method, hook, opts = {})
116
121
  return false if method == hook
117
122
  _add_hooked_method(:after, hook, method)
@@ -127,6 +132,8 @@ module BBLib
127
132
  elsif opts[:send_return_ary] || opts[:send_value_ary]
128
133
  result = method(hook).call(*rtr)
129
134
  rtr = result if opts[:modify_value] || opts[:modify_return]
135
+ elsif opts[:send_all]
136
+ result = method(hook).call(args: args, value: rtr, method: method)
130
137
  else
131
138
  method(hook).call
132
139
  end
data/lib/mixins/logger.rb CHANGED
@@ -5,11 +5,11 @@ module BBLib
5
5
  self.class.logger
6
6
  end
7
7
 
8
- [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
9
- define_method(sev) do |msg = nil, &block|
10
- logger.send(sev) { "[#{self.class}] #{msg ? msg : block.call}" }
11
- end
12
- end
8
+ # [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
9
+ # define_method(sev) do |msg = nil, &block|
10
+ # logger.send(sev) { "[#{self.class}] #{msg ? msg : block.call}" }
11
+ # end
12
+ # end
13
13
 
14
14
  def self.included(base)
15
15
  base.extend ClassMethods
@@ -20,11 +20,11 @@ module BBLib
20
20
  BBLib.logger
21
21
  end
22
22
 
23
- [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
24
- define_method(sev) do |msg = nil, &block|
25
- logger.send(sev) { "[#{self}] #{msg ? msg : block.call}" }
26
- end
27
- end
23
+ # [:debug, :info, :warn, :error, :fatal, :unknown].each do |sev|
24
+ # define_method(sev) do |msg = nil, &block|
25
+ # logger.send(sev) { "[#{self}] #{msg ? msg : block.call}" }
26
+ # end
27
+ # end
28
28
  end
29
29
 
30
30
  end
@@ -0,0 +1,26 @@
1
+
2
+ module BBLib
3
+ module Prototype
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def prototype(opts = prototype_defaults)
10
+ @prototype ||= self.new(*prototype_defaults)
11
+ end
12
+
13
+ def prototype_defaults
14
+ []
15
+ end
16
+
17
+ def method_missing(method, *args, &block)
18
+ prototype.respond_to?(method) ? prototype.send(method, *args, &block) : super
19
+ end
20
+
21
+ def respond_to_missing?(method, include_private = false)
22
+ prototype.respond_to?(method) || super
23
+ end
24
+ end
25
+ end
26
+ end
@@ -14,32 +14,56 @@ module BBLib
14
14
  define_method(:initialize) do |*args, &block|
15
15
  send(:simple_setup) if respond_to?(:simple_setup, true)
16
16
  send(:simple_preinit, *args, &block) if respond_to?(:simple_preinit, true)
17
- _initialize(*args)
17
+ _initialize(*args, &block)
18
18
  send(:simple_init, *args, &block) if respond_to?(:simple_init, true)
19
- instance_eval(&block) if block
19
+ if block && !_attrs.any? { |k, v| v[:options][:arg_at] == :block }
20
+ result = instance_eval(&block)
21
+ simple_init_block_result(result) if respond_to?(:simple_init_block_result, true)
22
+ end
23
+ end
24
+ end
25
+
26
+ if BBLib.in_opal?
27
+ base.singleton_class.class_eval do
28
+ alias __new new
29
+
30
+ def new(*args, &block)
31
+ named = BBLib.named_args(*args)
32
+ if init_foundation && named[init_foundation_method] && ((named[init_foundation_method] != self.send(init_foundation_method)) rescue false)
33
+ klass = [self, descendants].flatten.find do |k|
34
+ if init_foundation_compare
35
+ init_foundation_compare.call(k.send(init_foundation_method), named[init_foundation_method])
36
+ else
37
+ k.send(init_foundation_method).to_s == named[init_foundation_method].to_s
38
+ end
39
+ end
40
+ raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\" for #{self}" unless klass
41
+ klass == self ? __new(*args, &block) : klass.new(*args, &block)
42
+ else
43
+ __new(*args, &block)
44
+ end
45
+ end
20
46
  end
21
47
  end
22
48
  end
23
49
 
24
50
  module ClassMethods
25
51
 
26
- # TODO: Currently init foundation breaks when running in opal.
27
52
  unless BBLib.in_opal?
28
53
  # Overriden new method that allows parent classes to dynamically generate
29
- # instantiations of descendants by using the named :_class argument.
30
- # :_class needs to be the fully qualified name of the descendant.
54
+ # instantiations of descendants by using the named init_foundation_method argument.
31
55
  def new(*args, &block)
32
56
  named = BBLib.named_args(*args)
33
57
  if init_foundation && named[init_foundation_method] && ((named[init_foundation_method] != self.send(init_foundation_method)) rescue false)
34
- klass = descendants.find do |k|
58
+ klass = [self, descendants].flatten.find do |k|
35
59
  if init_foundation_compare
36
60
  init_foundation_compare.call(k.send(init_foundation_method), named[init_foundation_method])
37
61
  else
38
62
  k.send(init_foundation_method).to_s == named[init_foundation_method].to_s
39
63
  end
40
64
  end
41
- raise ArgumentError, "Unknown class type #{named[init_foundation_method]}" unless klass
42
- klass.new(*args, &block)
65
+ raise ArgumentError, "Unknown #{init_foundation_method} \"#{named[init_foundation_method]}\"" unless klass
66
+ klass == self ? super : klass.new(*args, &block)
43
67
  else
44
68
  super
45
69
  end
@@ -65,14 +89,14 @@ module BBLib
65
89
  end
66
90
 
67
91
  def init_foundation_compare(&block)
68
- @init_foundation_compare = block if block_given?
92
+ @init_foundation_compare = block if block
69
93
  @init_foundation_compare
70
94
  end
71
95
 
72
96
  def setup_init_foundation(method, &block)
73
97
  self.init_foundation = true
74
98
  self.init_foundation_method(method)
75
- self.init_foundation_compare(&block) if block_given?
99
+ self.init_foundation_compare(&block) if block
76
100
  end
77
101
 
78
102
  def ancestor_init_foundation_method
@@ -127,17 +151,23 @@ module BBLib
127
151
 
128
152
  protected
129
153
 
130
- def _initialize(*args)
154
+ def _initialize(*args, &block)
131
155
  named = BBLib.named_args(*args)
132
156
  if self.class.respond_to?(:_attrs)
133
157
  set_v_arg = self.class._attrs.map do |method, details|
134
- next unless details[:options][:arg_at] && details[:options][:arg_at].is_a?(Integer)
158
+ next unless details[:options][:arg_at] && (details[:options][:arg_at].is_a?(Integer) || details[:options][:arg_at] == :block)
159
+ if details[:options][:arg_at] == :block
160
+ send("#{method}=", block) if block
161
+ method
162
+ else
135
163
  index = details[:options][:arg_at]
136
- if args.size > index
137
- accept = details[:options][:arg_at_accept]
138
- if accept.nil? || [accept].flatten.any? { |a| a >= args[index].class }
139
- send("#{method}=", args[index])
140
- method
164
+ if args.size > index
165
+ accept = details[:options][:arg_at_accept]
166
+ next if args[index].is_a?(Hash) && (accept.nil? || ![accept].flatten.include?(Hash))
167
+ if accept.nil? || [accept].flatten.any? { |a| a >= args[index].class }
168
+ send("#{method}=", args[index])
169
+ method
170
+ end
141
171
  end
142
172
  end
143
173
  end.compact
@@ -0,0 +1,21 @@
1
+ module BBLib
2
+ # Requires Simple init to be loaded first. This sets up a very basic
3
+ # init foundation by adding a method called type and setting the init
4
+ # foundation method to it.
5
+ module TypeInit
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ base.send(:bridge_method, :type)
10
+ base.send(:serialize_method, :type, always: true)
11
+ base.send(:setup_init_foundation, :type) { |a, b| a && b && a.to_s.to_sym == b.to_s.to_sym }
12
+ end
13
+
14
+ module ClassMethods
15
+ def type
16
+ to_s.split('::').last.method_case.to_sym
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -17,4 +17,94 @@ module BBLib
17
17
  num = min if max && num > max
18
18
  num
19
19
  end
20
+
21
+ NUMBER_WORDS = {
22
+ special: {
23
+ 0 => nil,
24
+ 1 => 'one',
25
+ 2 => 'two',
26
+ 3 => 'three',
27
+ 4 => 'four',
28
+ 5 => 'five',
29
+ 6 => 'six',
30
+ 7 => 'seven',
31
+ 8 => 'eight',
32
+ 9 => 'nine',
33
+ 10 => 'ten',
34
+ 11 => 'eleven',
35
+ 12 => 'twleve',
36
+ 13 => 'thirteen',
37
+ 14 => 'fourteen',
38
+ 15 => 'fifteen',
39
+ 16 => 'sixteen',
40
+ 17 => 'seventeen',
41
+ 18 => 'eighteen',
42
+ 19 => 'nineteen'
43
+ },
44
+ double_range: {
45
+ 2 => 'twenty',
46
+ 3 => 'thirty',
47
+ 4 => 'forty',
48
+ 5 => 'fifty',
49
+ 6 => 'sixty',
50
+ 7 => 'seventy',
51
+ 8 => 'eighty',
52
+ 9 => 'ninety'
53
+ },
54
+ ranges: [
55
+ nil, 'thousand', 'million', 'billion', 'trillion', 'quadrillion',
56
+ 'quintillion', 'sextillion', 'septillion'
57
+ ]
58
+ }
59
+
60
+ def self.number_spelled_out(number, range = 0, include_and: true)
61
+ number = number.to_i
62
+ negative = number.negative?
63
+ number = number * -1 if negative
64
+ return 'zero' if number.zero?
65
+ str = []
66
+ three_digit = number > 999 ? number.to_s[-3..-1].to_i : number
67
+ case three_digit
68
+ when 1..19
69
+ str << NUMBER_WORDS[:special][three_digit]
70
+ when 20..99
71
+ str << NUMBER_WORDS[:double_range][three_digit.to_s[-2].to_i]
72
+ str << NUMBER_WORDS[:special][three_digit.to_s[-1].to_i]
73
+ when 100..999
74
+ str << NUMBER_WORDS[:special][three_digit.to_s[0].to_i]
75
+ str << 'hundred'
76
+ str << 'and' if include_and
77
+ if three_digit.to_s[-2].to_i == 1
78
+ str << NUMBER_WORDS[:special][three_digit.to_s[-2..-1].to_i]
79
+ else
80
+ str << NUMBER_WORDS[:double_range][three_digit.to_s[-2].to_i]
81
+ str << NUMBER_WORDS[:special][three_digit.to_s[-1].to_i]
82
+ end
83
+ end
84
+ str << NUMBER_WORDS[:ranges][range] unless str.compact.empty?
85
+ (negative ? 'negative ' : '') +
86
+ ((number.to_s.size > 3 ? "#{number_spelled_out(number.to_s[0..-4].to_i, range + 1)} " : '') +
87
+ str.compact.join(' ')).gsub(/\s+/, ' ')
88
+ end
89
+ 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
20
110
  end
@@ -1,13 +1,9 @@
1
- # frozen_string_literal: true
2
- # require_relative 'attr'
3
- # require_relative 'hooks'
4
-
5
1
  module BBLib
6
2
  def self.are_all?(klass, *vars)
7
3
  vars.all? { |var| var.is_a?(klass) }
8
4
  end
9
5
 
10
- def self.is_a?(obj, *klasses)
6
+ def self.is_any?(obj, *klasses)
11
7
  klasses.any? { |klass| obj.is_a?(klass) }
12
8
  end
13
9
 
data/lib/opal/bbopal.rb CHANGED
@@ -2,11 +2,16 @@ module BBLib
2
2
  def self.in_opal?
3
3
  RUBY_ENGINE == 'opal'
4
4
  end
5
+
6
+ # Used when a method is called while in the wrong engine (such as Opal)
7
+ class WrongEngineError < StandardError; end
5
8
  end
6
9
 
7
10
  if BBLib.in_opal?
8
11
  class Element
9
12
  alias_native :replace_with, :replaceWith
10
13
  alias_native :prepend
14
+ alias_native :insert_after, :insertAfter
15
+ alias_native :insert_before, :insertBefore
11
16
  end
12
17
  end
data/lib/os/bbos.rb CHANGED
@@ -1,5 +1,3 @@
1
- require_relative 'bbsys'
2
-
3
1
  module BBLib
4
2
  module OS
5
3
  def self.os
@@ -26,67 +24,6 @@ module BBLib
26
24
  !(/#{builds.join('|')}/i =~ RUBY_PLATFORM).nil?
27
25
  end
28
26
 
29
- def self.os_info
30
- if windows?
31
- data = `wmic os get manufacturer,name,organization,osarchitecture,version /format:list`
32
- data = data.split("\n").reject { |r| r.strip == '' }.map do |m|
33
- spl = m.split('=')
34
- [spl.first.to_clean_sym.downcase, spl[1..-1].join('=')]
35
- end.to_h
36
- data[:name] = data[:name].split('|').first
37
- data[:osarchitecture] = data[:osarchitecture].extract_integers.first
38
- data.hpath_move('osarchitecture' => 'bits')
39
- data[:host] = `hostname`.strip
40
- data[:os] = os
41
- data
42
- else
43
- release = {}
44
- begin
45
- # First attempt to get release info uses lsb_release
46
- release = `lsb_release -a`.split("\n").map do |l|
47
- spl = l.split(':')
48
- [
49
- spl.first.downcase.to_clean_sym,
50
- spl[1..-1].join(':').strip
51
- ]
52
- end.to_h
53
- release.hpath_move('description' => 'name', 'release' => 'name', 'distributor_id' => 'manufacturer')
54
- rescue
55
- # Try finding the release file and parsing it instead of lsb_release
56
- begin
57
- release = `cat /etc/*release`
58
- .split("\n")
59
- .reject { |l| !(l.include?(':') || l.include?('=')) }
60
- .map { |l| l.msplit('=', ':') }
61
- .map { |a| [a.first.downcase.to_clean_sym, a[1..-1].join(':').uncapsulate] }
62
- .to_h
63
- rescue StandardError => e
64
- # Both attempts failed
65
- end
66
- end
67
- {
68
- release: `uname -r`.strip,
69
- bits: `uname -r` =~ /x86_64/i ? 64 : 32,
70
- host: `uname -n`.strip,
71
- os: os
72
- }.merge(release)
73
- end
74
- end
75
-
76
- # The following is Windows specific code
77
- if windows?
78
-
79
- def self.parse_wmic(cmd)
80
- `#{cmd} /format:list`
81
- .split("\n\n\n").reject(&:empty?)
82
- .map do |l|
83
- l.split("\n\n")
84
- .map { |l| spl = l.split('='); [spl.first.strip.downcase.to_clean_sym, spl[1..-1].join('=').strip] }.to_h
85
- end.reject(&:empty?)
86
- end
87
-
88
- end
89
-
90
27
  # Mostly platform agnost way to find the full path of an executable in the current env path.
91
28
  def self.which(cmd)
92
29
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
@@ -94,6 +94,27 @@ module BBLib
94
94
  str_b
95
95
  end
96
96
  end
97
+
98
+ # Pattern render takes (by default) a mustache style template and then uses
99
+ # a context (either a Hash or Object) to then interpolate in placeholders.
100
+ # The default pattern looks for {{method_name}} within the string but can be
101
+ # customized to a different pattern by setting the pattern named argument.
102
+ def self.pattern_render(text, context = {}, pattern: /\{{2}.*?\}{2}/, field_pattern: /(?<=^\{{2}).*(?=\}{2})/)
103
+ raise ArgumentError, "Expected text argument to be a String, got a #{text.class}" unless text.is_a?(String)
104
+ txt = text.dup
105
+ txt.scan(pattern).each do |match|
106
+ field = match.scan(field_pattern).first
107
+ next unless field
108
+ value = case context
109
+ when Hash
110
+ context[field.to_sym] || context[field]
111
+ else
112
+ context.send(field) if context.respond_to?(field)
113
+ end.to_s
114
+ txt.sub!(match, value)
115
+ end
116
+ txt
117
+ end
97
118
  end
98
119
 
99
120
  class String
@@ -130,7 +151,7 @@ class String
130
151
  else
131
152
  encapsulator
132
153
  end
133
- patterns = delimiters.map { |d| /#{d}(?=(?:[^#{pattern}]|[#{pattern}][^#{pattern}]*[#{pattern}])*$)/}
154
+ patterns = delimiters.map { |d| /#{Regexp.escape(d)}(?=(?:[^#{pattern}]|[#{pattern}][^#{pattern}]*[#{pattern}])*$)/}
134
155
  msplit(*patterns)
135
156
  end
136
157