bblib 0.1.1 → 0.2.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/.gitignore +1 -1
- data/lib/array/bbarray.rb +15 -0
- data/lib/bblib.rb +5 -1
- data/lib/bblib/version.rb +1 -1
- data/lib/file/bbfile.rb +6 -5
- data/lib/hash/bbhash.rb +24 -4
- data/lib/hash/hash_path.rb +391 -0
- data/lib/hash/hash_path_proc.rb +163 -0
- data/lib/{math/bbmath.rb → number/bbnumber.rb} +0 -0
- data/lib/object/bbobject.rb +28 -0
- data/lib/string/bbstring.rb +36 -9
- data/lib/time/bbtime.rb +55 -19
- data/lib/time/task_timer.rb +101 -0
- metadata +9 -5
- data/lib/net/bbnet.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46227889fa2341b852f07f10dd28892a0770b759
|
4
|
+
data.tar.gz: f7e8f2dae0ba5148cb77d0ec7086c87806dce3c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45f56290f00c86f5ead9f13746fe76104d87698bfd8b99a89abc2fc1660b4dc4137fb0bb85d50ed9dc8bfcfb0e987b1bef83e41e40c9599eb2205b2809a0cc7a
|
7
|
+
data.tar.gz: 50f0e4937c9857b0f66c14b748a74fec84bd835da790e01c64774005e7d9f9f24a58e0e96f2204cfcaf65a690e1ae5ce0d3eec40c0b76e9a25623f1824f6fd60
|
data/.gitignore
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def msplit *delims, keep_empty: false
|
5
|
+
self.map{ |i| i.msplit(delims, keep_empty:keep_empty)}.flatten
|
6
|
+
end
|
7
|
+
|
8
|
+
def keys_to_sym clean: false
|
9
|
+
self.map{ |v| Hash === v || Array === v ? v.keys_to_sym(clean:clean) : v }
|
10
|
+
end
|
11
|
+
|
12
|
+
def keys_to_s clean: false
|
13
|
+
self.map{ |v| Hash === v || Array === v ? v.keys_to_s : v }
|
14
|
+
end
|
15
|
+
end
|
data/lib/bblib.rb
CHANGED
@@ -3,8 +3,12 @@ require_relative "string/bbstring"
|
|
3
3
|
require_relative "file/bbfile"
|
4
4
|
require_relative "time/bbtime"
|
5
5
|
require_relative "hash/bbhash"
|
6
|
-
require_relative "
|
6
|
+
require_relative "number/bbnumber"
|
7
|
+
require_relative "object/bbobject"
|
8
|
+
require_relative "array/bbarray"
|
7
9
|
require 'fileutils'
|
10
|
+
require 'net/http'
|
11
|
+
require 'uri'
|
8
12
|
|
9
13
|
module BBLib
|
10
14
|
|
data/lib/bblib/version.rb
CHANGED
data/lib/file/bbfile.rb
CHANGED
@@ -23,11 +23,12 @@ module BBLib
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# Shorthand method to write a string to dist. By default the path is created if it doesn't exist.
|
26
|
-
|
26
|
+
# Set mode to w to truncate file or leave at a to append.
|
27
|
+
def self.string_to_file path, str, mkpath = true, mode: 'a'
|
27
28
|
if !Dir.exists?(path) && mkpath
|
28
29
|
FileUtils.mkpath File.dirname(path)
|
29
30
|
end
|
30
|
-
File.write(path, str.to_s)
|
31
|
+
File.write(path, str.to_s, mode:mode)
|
31
32
|
end
|
32
33
|
|
33
34
|
# A file size parser for strings. Extracts any known patterns for file sizes.
|
@@ -36,7 +37,7 @@ module BBLib
|
|
36
37
|
bytes = 0.0
|
37
38
|
FILE_SIZES.each do |k, v|
|
38
39
|
v[:exp].each do |e|
|
39
|
-
numbers = str.scan(/(?=\w|\D|\A)\d
|
40
|
+
numbers = str.scan(/(?=\w|\D|\A)\d*\.?\d+[[:space:]]*#{e}s?(?=\W|\d|\z)/i)
|
40
41
|
numbers.each{ |n| bytes+= n.to_f * v[:mult] }
|
41
42
|
end
|
42
43
|
end
|
@@ -64,8 +65,8 @@ class File
|
|
64
65
|
end
|
65
66
|
|
66
67
|
class String
|
67
|
-
def to_file path, mkpath = true
|
68
|
-
BBLib.string_to_file path, self, mkpath
|
68
|
+
def to_file path, mkpath = true, mode: 'a'
|
69
|
+
BBLib.string_to_file path, self, mkpath, mode:mode
|
69
70
|
end
|
70
71
|
|
71
72
|
def file_name with_extension = true
|
data/lib/hash/bbhash.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require_relative 'hash_path'
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
|
5
|
+
|
6
|
+
|
3
7
|
# Merges with another hash but also merges all nested hashes and arrays/values.
|
4
8
|
# Based on method found @ http://stackoverflow.com/questions/9381553/ruby-merge-nested-hash
|
5
9
|
def deep_merge with, merge_arrays: true, overwrite_vals: true
|
@@ -13,12 +17,23 @@ class Hash
|
|
13
17
|
|
14
18
|
# Converts the keys of the hash as well as any nested hashes to symbols.
|
15
19
|
# Based on method found @ http://stackoverflow.com/questions/800122/best-way-to-convert-strings-to-symbols-in-hash
|
16
|
-
def keys_to_sym
|
17
|
-
self.inject({}){|memo,(k,v)| memo[k.to_sym] = (Hash === v ? v.keys_to_sym : v); memo}
|
20
|
+
def keys_to_sym clean: false
|
21
|
+
self.inject({}){|memo,(k,v)| memo[clean ? k.to_s.to_clean_sym : k.to_s.to_sym] = (Hash === v || Array === v ? v.keys_to_sym(clean:clean) : v); memo}
|
22
|
+
# self.inject({}){|memo,(k,v)| memo[clean ? k.to_s.to_clean_sym : k.to_s.to_sym] = (Hash === v ? v.keys_to_sym : (Array === v ? v.flatten.map{ |a| Hash === a ? a.keys_to_sym : a } : v) ); memo}
|
23
|
+
end
|
24
|
+
|
25
|
+
def keys_to_sym! clean: false
|
26
|
+
replace(self.keys_to_sym clean:clean)
|
18
27
|
end
|
19
28
|
|
20
|
-
|
21
|
-
|
29
|
+
# Converts the keys of the hash as well as any nested hashes to strings.
|
30
|
+
def keys_to_s
|
31
|
+
self.inject({}){|memo,(k,v)| memo[k.to_s] = (Hash === v || Array === v ? v.keys_to_s : v); memo}
|
32
|
+
# self.inject({}){|memo,(k,v)| memo[k.to_s] = (Hash === v ? v.keys_to_s : (Array === v ? v.flatten.map{ |a| Hash === a ? a.keys_to_s : a } : v)); memo}
|
33
|
+
end
|
34
|
+
|
35
|
+
def keys_to_s!
|
36
|
+
replace(self.keys_to_s)
|
22
37
|
end
|
23
38
|
|
24
39
|
# Reverses the order of keys in the Hash
|
@@ -30,4 +45,9 @@ class Hash
|
|
30
45
|
replace self.reverse
|
31
46
|
end
|
32
47
|
|
48
|
+
def unshift hash, value = nil
|
49
|
+
if !hash.is_a? Hash then hash = {hash => value} end
|
50
|
+
replace hash.merge(self).merge(hash)
|
51
|
+
end
|
52
|
+
|
33
53
|
end
|
@@ -0,0 +1,391 @@
|
|
1
|
+
require_relative 'hash_path_proc'
|
2
|
+
|
3
|
+
module BBLib
|
4
|
+
|
5
|
+
def self.hash_path hashes, path, recursive: false, delimiter: '.', symbol_sensitive: false
|
6
|
+
if String === path then path = BBLib.split_and_analyze(path, delimiter) end
|
7
|
+
if !hashes.is_a? Array then hashes = [hashes] end
|
8
|
+
return hashes if path.nil? || path.empty?
|
9
|
+
if path[0][:key] == '' then return BBLib.hash_path(hashes, path[1..-1], recursive: true, symbol_sensitive:symbol_sensitive) end
|
10
|
+
matches, p = Array.new, path.first
|
11
|
+
hashes.each do |hash|
|
12
|
+
if recursive
|
13
|
+
patterns = Regexp === p[:key] ? p[:key] : p[:key].to_s == '*' ? /.*/ : (symbol_sensitive ? p[:key] : [p[:key].to_sym, p[:key].to_s])
|
14
|
+
matches.push hash.dig(patterns).flatten(1)[p[:slice]]
|
15
|
+
else
|
16
|
+
if p[:key].nil?
|
17
|
+
if hash.is_a?(Array) then matches << hash[p[:slice]] end
|
18
|
+
elsif Symbol === p[:key] || String === p[:key]
|
19
|
+
if p[:key].to_s == '*'
|
20
|
+
matches.push hash.values.flatten(1)[p[:slice]]
|
21
|
+
else
|
22
|
+
next unless symbol_sensitive ? hash.include?(p[:key]) : (hash.include?(p[:key].to_sym) || hash.include?(p[:key].to_s) )
|
23
|
+
mat = (symbol_sensitive ? hash[p[:key]] : ( if hash.include?(p[:key].to_sym) then hash[p[:key].to_sym] else hash[p[:key].to_s] end ))
|
24
|
+
matches.push mat.is_a?(Array) ? mat[p[:slice]] : mat
|
25
|
+
end
|
26
|
+
elsif Regexp === p[:key]
|
27
|
+
hash.keys.find_all{ |k| k =~ p[:key] }.each{ |m| matches << hash[m] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
matches = BBLib.analyze_hash_path_formula p[:formula], matches
|
32
|
+
if path.size > 1 && !matches.empty?
|
33
|
+
# p "MAT #{matches}"
|
34
|
+
# matches.map!{ |m| m.is_a?(Array) ? [m] : m }
|
35
|
+
BBLib.hash_path(matches.reject{ |r| !(r.is_a?(Hash) || r.is_a?(Array)) }, path[1..-1], symbol_sensitive:symbol_sensitive)
|
36
|
+
else
|
37
|
+
return matches.flatten(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.hash_path_set hash, *args
|
42
|
+
details = BBLib.hash_path_setup(hash, args)
|
43
|
+
count = 0
|
44
|
+
details[:paths].each do |path, d|
|
45
|
+
d[:hashes].each do |h|
|
46
|
+
count+=1
|
47
|
+
exists = (details[:symbol_sensitive] ? h.include?(d[:last][:key]) : (h.include?(d[:last][:key].to_sym) || h.include?(d[:last][:key].to_s) ))
|
48
|
+
next unless details[:bridge] || exists
|
49
|
+
key = details[:symbol_sensitive] ? d[:last][:key] : (h.include?(d[:last][:key].to_sym) ? d[:last][:key].to_sym : d[:last][:key].to_s)
|
50
|
+
if details[:symbols] then key = key.to_sym elsif !exists then key = d[:last][:key] end
|
51
|
+
if Fixnum === d[:last][:slice]
|
52
|
+
h[key][d[:last][:slice]] = d[:value]
|
53
|
+
else
|
54
|
+
if h.is_a?(Hash)
|
55
|
+
h[key] = d[:value]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if count == 0 && details[:bridge] then hash.bridge(path, value:d[:value], symbols:details[:symbols]) end
|
60
|
+
end
|
61
|
+
hash
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.hash_path_exists? hash, path, delimiter: '.', symbol_sensitive: false
|
65
|
+
return !BBLib.hash_path(hash, path, delimiter:delimiter, symbol_sensitive:symbol_sensitive).empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.hash_path_move hash, *args
|
69
|
+
BBLib.hash_path_copy hash, args
|
70
|
+
details = BBLib.hash_path_setup(hash, args)
|
71
|
+
opts = Hash.new
|
72
|
+
details.each do |k, v|
|
73
|
+
if HASH_PATH_PARAMS.include?(k) then opts[k] = v end
|
74
|
+
end
|
75
|
+
BBLib.hash_path_delete hash, [details[:paths].keys, opts ].flatten
|
76
|
+
return hash
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.hash_path_move_to from, to, *args
|
80
|
+
BBLib.hash_path_copy_to from, to, args
|
81
|
+
BBLib.hash_path_delete from, args
|
82
|
+
return to
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.hash_path_copy hash, *args
|
86
|
+
details = BBLib.hash_path_setup(hash, args)
|
87
|
+
details[:paths].each do |path, d|
|
88
|
+
d[:hashes].each do |h|
|
89
|
+
if Hash === h || Array === h
|
90
|
+
exist = details[:symbol_sensitive] ? h.include?(d[:last][:key]) : (h.include?(d[:last][:key].to_sym) || h.include?(d[:last][:key].to_s) )
|
91
|
+
next unless exist || details[:bridge]
|
92
|
+
value = details[:symbol_sensitive] ? h[d[:last][:key]] : (if h.include?(d[:last][:key].to_sym) then h[d[:last][:key].to_sym] else h[d[:last][:key].to_s] end )
|
93
|
+
if value
|
94
|
+
BBLib.hash_path_set hash, d[:value] => value, symbols:details[:symbols]
|
95
|
+
end
|
96
|
+
elsif !details[:stop_on_nil]
|
97
|
+
BBLib.hash_path_set hash, d[:value] => nil, symbols:details[:symbols]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
hash
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.hash_path_copy_to from, to, *args
|
105
|
+
details = BBLib.hash_path_setup(from, args)
|
106
|
+
details[:paths].each do |path, d|
|
107
|
+
value = from.hash_path(path)
|
108
|
+
if !value.empty? || !details[:stop_on_nil]
|
109
|
+
if !details[:arrays].include?(d[:value]) then value = value.first end
|
110
|
+
to = to.bridge(d[:value], value: value, symbols:details[:symbols])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
to
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.hash_path_delete hash, *args
|
117
|
+
args.flatten!
|
118
|
+
details = BBLib.hash_path_setup hash, [args.find{ |f| Hash === f }.to_h.merge(args.find_all{ |a| String === a }.zip([]).to_h)]
|
119
|
+
deleted = []
|
120
|
+
details[:paths].each do |path, d|
|
121
|
+
d[:hashes].each do |h|
|
122
|
+
next unless details[:symbol_sensitive] ? h.include?(d[:last][:key]) : (h.include?(d[:last][:key].to_sym) || h.include?(d[:last][:key].to_s) )
|
123
|
+
if Fixnum === d[:last][:slice]
|
124
|
+
(details[:symbol_sensitive] ? h[d[:last][:key]] : (if h.include?(d[:last][:key].to_sym) then h[d[:last][:key].to_sym] else h[d[:last][:key].to_s] end)).delete_at d[:last][:slice]
|
125
|
+
else
|
126
|
+
if details[:symbol_sensitive]
|
127
|
+
deleted << h.delete(d[:last][:key])
|
128
|
+
else
|
129
|
+
if h.include?(d[:last][:key].to_sym) then deleted << h.delete(d[:last][:key].to_sym) end
|
130
|
+
if h.include?(d[:last][:key].to_s) then deleted << h.delete(d[:last][:key].to_s) end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
return deleted.flatten
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.hash_path_keys hash
|
139
|
+
hash.squish.keys
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.hash_path_key_for hash, value
|
143
|
+
hash.squish.find_all{ |k,v| v == value }.to_h.keys
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.path_nav obj, path = '', delimiter = '.', &block
|
147
|
+
case [obj.class]
|
148
|
+
when [Hash]
|
149
|
+
obj.each{ |k,v| path_nav v, "#{path}#{path.nil? || path.empty? ? nil : delimiter}#{k}", delimiter, &block }
|
150
|
+
when [Array]
|
151
|
+
index = 0
|
152
|
+
obj.each{ |o| path_nav o, "#{path}#{path.end_with?(']') ? delimiter : nil}[#{index}]", delimiter, &block ; index+=1 }
|
153
|
+
else
|
154
|
+
yield path, obj
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def self.hash_path_analyze path
|
161
|
+
key = path.scan(/\A.*^[^\[\(\{]*/i).first.to_s
|
162
|
+
if key.encap_by?('/')
|
163
|
+
key = eval(key)
|
164
|
+
elsif key.start_with? ':'
|
165
|
+
key = key[1..-1].to_sym
|
166
|
+
end
|
167
|
+
slice = eval(path.scan(/(?<=\[).*?(?=\])/).first.to_s)
|
168
|
+
if !slice.is_a?(Range) && !slice.is_a?(Fixnum) then slice = (0..-1) end
|
169
|
+
if slice.nil? then slice = (0..-1) end
|
170
|
+
formula = path.scan(/(?<=\().*?(?=\))/).first
|
171
|
+
if key.empty? && slice != (0..-1) then key = nil end
|
172
|
+
{key:key, slice:slice, formula:formula}
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.split_hash_path path, delimiter = '.'
|
176
|
+
if path.to_s.start_with?(delimiter) then path = path.to_s.sub(delimiter, '') end
|
177
|
+
paths, stop, open = [], 0, false
|
178
|
+
path.chars.each do |t|
|
179
|
+
if t == '[' then open = true end
|
180
|
+
if t == ']' then open = false end
|
181
|
+
if t == delimiter && !open then paths << path[0..stop].reverse.sub(delimiter,'').reverse; path = path[stop+1..-1]; stop = -1 end
|
182
|
+
stop += 1
|
183
|
+
end
|
184
|
+
paths << path
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.split_and_analyze path, delimiter = '.'
|
188
|
+
split_hash_path(path, delimiter).collect{ |p| hash_path_analyze(p) }
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.analyze_hash_path_formula formula, hashes
|
192
|
+
return hashes unless formula
|
193
|
+
temp = []
|
194
|
+
hashes.flatten.each do |p|
|
195
|
+
begin
|
196
|
+
if eval(formula.gsub('$', p.to_s))
|
197
|
+
temp << p
|
198
|
+
end
|
199
|
+
rescue StandardError, SyntaxError => se
|
200
|
+
# Do nothing, the formula failed and we reject the value as a false
|
201
|
+
end
|
202
|
+
end
|
203
|
+
temp
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.hash_path_setup hash, *args
|
207
|
+
args.flatten!
|
208
|
+
return nil unless args && args[0].class == Hash
|
209
|
+
info = Hash.new
|
210
|
+
info[:paths] = Hash.new
|
211
|
+
map = args[0].dup
|
212
|
+
HASH_PATH_PARAMS.each do |p, h|
|
213
|
+
info[p] = (map.include?(p) ? map.delete(p) : h[:default])
|
214
|
+
end
|
215
|
+
if info[:keys_to_sym] then hash.keys_to_sym! end
|
216
|
+
map.each do |path, value|
|
217
|
+
info[:paths][path] = Hash.new
|
218
|
+
info[:paths][path][:value] = value
|
219
|
+
info[:paths][path][:paths] = BBLib.split_hash_path(path, info[:delimiter])
|
220
|
+
info[:paths][path][:last] = BBLib.hash_path_analyze info[:paths][path][:paths].last
|
221
|
+
info[:paths][path][:hashes] = BBLib.hash_path(hash, info[:paths][path][:paths][0..-2].join(info[:delimiter]), delimiter:info[:delimiter], symbol_sensitive:info[:symbol_sensitive] )
|
222
|
+
end
|
223
|
+
return info
|
224
|
+
end
|
225
|
+
|
226
|
+
HASH_PATH_PARAMS = {
|
227
|
+
delimiter: {default:'.'},
|
228
|
+
bridge: {default:true},
|
229
|
+
symbols: {default:true},
|
230
|
+
symbol_sensitive: {default:false},
|
231
|
+
stop_on_nil: {default:true},
|
232
|
+
arrays: {default:[]},
|
233
|
+
keys_to_sym: {default:true}
|
234
|
+
}
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
|
240
|
+
class Hash
|
241
|
+
|
242
|
+
def hash_path path, delimiter: '.'
|
243
|
+
BBLib.hash_path self, path, delimiter:delimiter
|
244
|
+
end
|
245
|
+
|
246
|
+
def hash_path_set *args
|
247
|
+
BBLib.hash_path_set self, args
|
248
|
+
end
|
249
|
+
|
250
|
+
def hash_path_copy *args
|
251
|
+
BBLib.hash_path_copy self, args
|
252
|
+
end
|
253
|
+
|
254
|
+
def hash_path_copy_to hash, *args
|
255
|
+
BBLib.hash_path_copy_to self, hash, args
|
256
|
+
end
|
257
|
+
|
258
|
+
def hash_path_move_to hash, *args
|
259
|
+
BBLib.hash_path_move_to self, hash, args
|
260
|
+
end
|
261
|
+
|
262
|
+
def hash_path_move *args
|
263
|
+
BBLib.hash_path_move self, args
|
264
|
+
end
|
265
|
+
|
266
|
+
def hash_path_delete *args
|
267
|
+
BBLib.hash_path_delete self, args
|
268
|
+
end
|
269
|
+
|
270
|
+
def hash_path_keys
|
271
|
+
BBLib.hash_path_keys self
|
272
|
+
end
|
273
|
+
|
274
|
+
def hash_path_exists? path, delimiter: '.', symbol_sensitive: false
|
275
|
+
BBLib.hash_path_exists? self, path, delimiter:delimiter, symbol_sensitive:symbol_sensitive
|
276
|
+
end
|
277
|
+
|
278
|
+
# Returns all matching values with a specific key (or Array of keys) recursively within a Hash (including nested Arrays)
|
279
|
+
def dig keys, search_arrays: true
|
280
|
+
keys = [keys].flatten
|
281
|
+
matches = []
|
282
|
+
self.each do |k, v|
|
283
|
+
if keys.any?{ |a| (a.is_a?(Regexp) ? a =~ k : a == k ) } then matches << v end
|
284
|
+
if v.is_a? Hash
|
285
|
+
matches+= v.dig(keys)
|
286
|
+
elsif v.is_a?(Array) && search_arrays
|
287
|
+
v.flatten.each{ |i| if i.is_a?(Hash) then matches+= i.dig(keys) end }
|
288
|
+
end
|
289
|
+
end
|
290
|
+
matches
|
291
|
+
end
|
292
|
+
|
293
|
+
# Turns nested values' keys into delimiter separated paths
|
294
|
+
def squish delimiter: '.', path_start: nil
|
295
|
+
sh = Hash.new
|
296
|
+
BBLib.path_nav(self.dup, path_start, delimiter){ |k, v| sh[k] = v }
|
297
|
+
sh
|
298
|
+
end
|
299
|
+
|
300
|
+
# Expands keys in a hash using a delimiter. Opposite of squish.
|
301
|
+
def expand delimiter: '.', symbols: false
|
302
|
+
eh = Hash.new
|
303
|
+
self.dup.each do |k,v|
|
304
|
+
eh.bridge k, delimiter: delimiter, value:v, symbols: true
|
305
|
+
end
|
306
|
+
return eh
|
307
|
+
end
|
308
|
+
|
309
|
+
# Builds out a shell of a hash path using a delimited path. Use value to set a value.
|
310
|
+
def bridge path, delimiter: '.', value: nil, symbols: false
|
311
|
+
# Ensure the path is a delimiter string. This supports arrays being passed in
|
312
|
+
path = (path.is_a?(Array) ? path.join(delimiter) : path.to_s)
|
313
|
+
#Generate the paths and set the current variable
|
314
|
+
current, paths = self, BBLib.split_and_analyze(path, delimiter)
|
315
|
+
# If symbols is true, then all keys are turned into symbols
|
316
|
+
if symbols then paths.each{ |p| p[:key] = p[:key].to_s.to_sym } end
|
317
|
+
# Check to see if there is only one path. If there is return either an Array of Hash
|
318
|
+
if paths.size == 1
|
319
|
+
# If the first value is a slice the value is inserted into an empty array
|
320
|
+
if Fixnum === paths.first[:slice]
|
321
|
+
current[paths.first[:key]] = ([].insert paths.first[:slice], value )
|
322
|
+
return self
|
323
|
+
end
|
324
|
+
# If the value does not have a slice, a hash with a single key-value pair is returned
|
325
|
+
current[paths.first[:key]] = value
|
326
|
+
return self
|
327
|
+
end
|
328
|
+
index, count = -1, 0
|
329
|
+
paths.each do |p|
|
330
|
+
count+=1
|
331
|
+
last = paths.size == count
|
332
|
+
if p[:slice].is_a?(Fixnum)
|
333
|
+
index = p[:slice]
|
334
|
+
if paths[count-2] && Fixnum === paths[count-2][:slice]
|
335
|
+
current[paths[count-2][:slice]] = current[paths[count-2][:slice]] ||= Array.new
|
336
|
+
current = current[paths[count-2][:slice]]
|
337
|
+
else
|
338
|
+
if current[p[:key]].nil?
|
339
|
+
current[p[:key]] = []
|
340
|
+
end
|
341
|
+
current = current[p[:key]]
|
342
|
+
end
|
343
|
+
if last then current[index] = value end
|
344
|
+
else
|
345
|
+
if current.is_a?(Hash)
|
346
|
+
if last
|
347
|
+
current[p[:key]] = value
|
348
|
+
else
|
349
|
+
current[p[:key]] = current[p[:key]] ||= Hash.new
|
350
|
+
end
|
351
|
+
current = current[p[:key]]
|
352
|
+
else
|
353
|
+
if last
|
354
|
+
if current[index]
|
355
|
+
if current[index].is_a? Hash
|
356
|
+
current[index].merge({p[:key] => value})
|
357
|
+
else
|
358
|
+
current[index] = ({p[:key] => value})
|
359
|
+
end
|
360
|
+
else
|
361
|
+
current.insert index, {p[:key] => value}
|
362
|
+
end
|
363
|
+
else
|
364
|
+
temp = { p[:key] => {} }
|
365
|
+
if current[index].is_a? Hash
|
366
|
+
current[index].merge!(temp)
|
367
|
+
else
|
368
|
+
current[index] = temp
|
369
|
+
end
|
370
|
+
end
|
371
|
+
if !last then current = temp[p[:key]] end
|
372
|
+
end
|
373
|
+
index = -1
|
374
|
+
end
|
375
|
+
end
|
376
|
+
return self
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
class Array
|
382
|
+
|
383
|
+
def dig keys
|
384
|
+
matches = []
|
385
|
+
self.each do |i|
|
386
|
+
matches << i.dig(keys) if i.is_a?(Hash) || i.is_a?(Array)
|
387
|
+
end
|
388
|
+
matches
|
389
|
+
end
|
390
|
+
|
391
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def hash_path_proc action, paths, *args, **params
|
5
|
+
BBLib.hash_path_proc self, action, paths, *args, **params
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module BBLib
|
10
|
+
|
11
|
+
def self.hash_path_proc hash, action, paths, *args, **params
|
12
|
+
action = HASH_PATH_PROC_TYPES.keys.find{ |k| k == action || HASH_PATH_PROC_TYPES[k][:aliases].include?(action) }
|
13
|
+
return nil unless action
|
14
|
+
paths.to_a.each do |path|
|
15
|
+
value = hash.hash_path(path).first
|
16
|
+
if params.include?(:condition) && params[:condition]
|
17
|
+
begin
|
18
|
+
next unless eval(params[:condition].gsub('$', value.to_s))
|
19
|
+
rescue
|
20
|
+
next
|
21
|
+
end
|
22
|
+
end
|
23
|
+
HashPath.send(action, hash, path, value, *args, **params)
|
24
|
+
end
|
25
|
+
return hash
|
26
|
+
end
|
27
|
+
|
28
|
+
HASH_PATH_PROC_TYPES = {
|
29
|
+
evaluate: { aliases: [:eval, :equation, :equate]},
|
30
|
+
append: { aliases: [:suffix]},
|
31
|
+
prepend: { aliases: [:prefix]},
|
32
|
+
split: { aliases: [:delimit, :delim, :separate, :msplit]},
|
33
|
+
replace: { aliases: [:swap]},
|
34
|
+
extract: { aliases: [:grab, :scan]},
|
35
|
+
extract_first: {aliases: [:grab_first, :scan_first]},
|
36
|
+
extract_last: {aliases: [:grab_last, :scan_last]},
|
37
|
+
parse_date: { aliases: [:date, :parse_time, :time]},
|
38
|
+
parse_duration: { aliases: [:duration]},
|
39
|
+
parse_file_size: { aliases: [:file_size]},
|
40
|
+
to_string: {aliases: [:to_s, :stringify]},
|
41
|
+
downcase: { aliases: [:lower, :lowercase, :to_lower]},
|
42
|
+
upcase: { aliases: [:upper, :uppercase, :to_upper]},
|
43
|
+
# titlecase: { aliases: [:title_case]},
|
44
|
+
roman: { aliases: [:convert_roman, :roman_numeral, :parse_roman]},
|
45
|
+
remove_symbols: { aliases: [:chop_symbols, :drop_symbols]},
|
46
|
+
format_articles: { aliases: [:articles]},
|
47
|
+
reverse: { aliases: [:invert]},
|
48
|
+
delete: { aliases: [:del]},
|
49
|
+
remove: { aliases: [:rem]},
|
50
|
+
custom: {aliases: [:send]}
|
51
|
+
# rename: { aliases: [:rename_key]},
|
52
|
+
# concat: { aliases: [:join, :concat_with]},
|
53
|
+
# reverse_concat: { aliases: [:reverse_join, :reverse_concat_with]}
|
54
|
+
}
|
55
|
+
|
56
|
+
module HashPath
|
57
|
+
|
58
|
+
def self.evaluate hash, path, value, args, params
|
59
|
+
exp = args.to_a.first.to_s.gsub('$', value.to_s)
|
60
|
+
hash.hash_path_set path => eval(exp)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.append hash, path, value, args, params
|
64
|
+
hash.hash_path_set path => "#{value}#{args}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.prepend hash, path, value, args, params
|
68
|
+
hash.hash_path_set path => "#{args}#{value}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.split hash, path, value, args, params
|
72
|
+
hash.hash_path_set path => value.msplit(args)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.replace hash, path, value, args, params
|
76
|
+
value = value.dup.to_s
|
77
|
+
args.each{ |k,v| value.gsub!(k.to_s, v.to_s) }
|
78
|
+
hash.hash_path_set path => value
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.extract hash, path, value, *args, **params
|
82
|
+
slice = (Array === args && args[1].nil? ? (0..-1) : args[1])
|
83
|
+
hash.hash_path_set path => value.scan(args.first)[slice]
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.extract_first hash, path, value, *args, **params
|
87
|
+
extract(hash, path, value, *args + [0])
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.extract_last hash, path, value, *args, **params
|
91
|
+
extract(hash, path, value, *args + [-1])
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.parse_date hash, path, value, *args, **params
|
95
|
+
format = params.include?(:format) ? params[:format] : '%Y-%m-%d %H:%M:%S'
|
96
|
+
formatted = nil
|
97
|
+
args.each do |pattern|
|
98
|
+
next unless formatted.nil?
|
99
|
+
begin
|
100
|
+
formatted = Time.strptime(value.to_s, pattern.to_s).strftime(format)
|
101
|
+
rescue
|
102
|
+
end
|
103
|
+
end
|
104
|
+
begin
|
105
|
+
if formatted.nil? then formatted = Time.parse(value) end
|
106
|
+
rescue
|
107
|
+
end
|
108
|
+
hash.hash_path_set path => formatted
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.parse_duration hash, path, value, args, params
|
112
|
+
hash.hash_path_set path => value.to_s.parse_duration(output: args.empty? ? :sec : args )
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.parse_file_size hash, path, value, args, params
|
116
|
+
hash.hash_path_set path => value.to_s.parse_file_size(output: args.empty? ? :bytes : args )
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.to_string hash, path, value, *args, **params
|
120
|
+
hash.hash_path_set path => value.to_s
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.downcase hash, path, value, *args, **params
|
124
|
+
hash.hash_path_set path => value.to_s.downcase
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.upcase hash, path, value, *args, **params
|
128
|
+
hash.hash_path_set path => value.to_s.upcase
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.roman hash, path, value, *args, **params
|
132
|
+
hash.hash_path_set path => (args[0] == :to ? value.to_s.to_roman : value.to_s.from_roman)
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.remove_symbols hash, path, value, *args, **params
|
136
|
+
hash.hash_path_set path => value.to_s.drop_symbols
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.format_articles hash, path, value, args, **params
|
140
|
+
hash.hash_path_set path => value.to_s.move_articles(args.nil? ? :front : args)
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.reverse hash, path, value, *args, **params
|
144
|
+
hash.hash_path_set path => value.to_s.reverse
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.delete hash, path, value, *args, **params
|
148
|
+
hash.hash_path_delete path
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.remove hash, path, value, *args, **params
|
152
|
+
removed = value.to_s
|
153
|
+
args.each{ |a| removed.gsub!(a, '')}
|
154
|
+
hash.hash_path_set path => removed
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.custom hash, path, value, *args, **params
|
158
|
+
hash.hash_path_set path => value.send(*args)
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module BBLib
|
2
|
+
|
3
|
+
def self.to_hash obj
|
4
|
+
return {obj => nil} unless !obj.instance_variables.empty?
|
5
|
+
hash = {}
|
6
|
+
obj.instance_variables.each do |var|
|
7
|
+
value = obj.instance_variable_get(var)
|
8
|
+
if value.is_a? Array
|
9
|
+
hash[var.to_s.delete("@")] = value.map{ |v| v.respond_to?(:obj_to_hash) && !v.instance_variables.empty? ? v.obj_to_hash : v }
|
10
|
+
elsif value.is_a? Hash
|
11
|
+
begin
|
12
|
+
if !hash[var.to_s.delete("@")].is_a?(Hash) then hash[var.to_s.delete("@")] = Hash.new end
|
13
|
+
rescue
|
14
|
+
hash[var.to_s.delete("@")] = Hash.new
|
15
|
+
end
|
16
|
+
value.each do |k, v|
|
17
|
+
hash[var.to_s.delete("@")][k.to_s.delete("@")] = v.respond_to?(:obj_to_hash) && !v.instance_variables.empty? ? v.obj_to_hash : v
|
18
|
+
end
|
19
|
+
elsif value.respond_to?(:obj_to_hash) && !value.instance_variables.empty?
|
20
|
+
hash[var.to_s.delete("@")] = value.obj_to_hash
|
21
|
+
else
|
22
|
+
hash[var.to_s.delete("@")] = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return hash
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/string/bbstring.rb
CHANGED
@@ -9,6 +9,10 @@ module BBLib
|
|
9
9
|
# General Functions
|
10
10
|
##############################################
|
11
11
|
|
12
|
+
# def self.title_case str
|
13
|
+
# TODO
|
14
|
+
# end
|
15
|
+
|
12
16
|
# Quickly remove any symbols from a string leaving onl alpha-numeric characters and white space.
|
13
17
|
def self.drop_symbols str
|
14
18
|
str.gsub(/[^\w\s\d]|_/, '')
|
@@ -16,17 +20,17 @@ module BBLib
|
|
16
20
|
|
17
21
|
# Extract all integers from a string. Use extract_floats if numbers may contain decimal places.
|
18
22
|
def self.extract_integers str, convert: true
|
19
|
-
str.
|
23
|
+
BBLib.extract_numbers(str, convert:false).reject{ |r| r.include?('.') }.map{ |m| convert ? m.to_i : m }
|
20
24
|
end
|
21
25
|
|
22
26
|
# Extracts all integers or decimals from a string into an array.
|
23
27
|
def self.extract_floats str, convert: true
|
24
|
-
str.
|
28
|
+
BBLib.extract_numbers(str, convert:false).reject{ |r| !r.include?('.') }.map{ |m| convert ? m.to_f : m }
|
25
29
|
end
|
26
30
|
|
27
31
|
# Alias for extract_floats
|
28
32
|
def self.extract_numbers str, convert: true
|
29
|
-
|
33
|
+
str.scan(/\d+\.?\d+|\d+/).map{ |f| convert ? (f.include?('.') ? f.to_f : f.to_i) : f }
|
30
34
|
end
|
31
35
|
|
32
36
|
# Used to move the position of the articles 'the', 'a' and 'an' in strings for normalization.
|
@@ -61,22 +65,22 @@ end
|
|
61
65
|
|
62
66
|
class String
|
63
67
|
# Multi-split. Similar to split, but can be passed an array of delimiters to split on.
|
64
|
-
def msplit delims, keep_empty: false
|
68
|
+
def msplit *delims, keep_empty: false
|
65
69
|
return [self] unless !delims.nil? && !delims.empty?
|
66
70
|
ar = [self]
|
67
|
-
delims.each do |d|
|
71
|
+
[delims].flatten.each do |d|
|
68
72
|
ar.map!{ |a| a.split d }
|
69
73
|
ar.flatten!
|
70
74
|
end
|
71
75
|
keep_empty ? ar : ar.reject{ |l| l.empty? }
|
72
76
|
end
|
73
77
|
|
74
|
-
def move_articles position, capitalize = true
|
75
|
-
BBLib.move_articles self, position, capitalize
|
78
|
+
def move_articles position = :front, capitalize = true
|
79
|
+
BBLib.move_articles self, position, capitalize:capitalize
|
76
80
|
end
|
77
81
|
|
78
|
-
def move_articles! position, capitalize = true
|
79
|
-
replace BBLib.move_articles(self, position, capitalize)
|
82
|
+
def move_articles! position = :front, capitalize = true
|
83
|
+
replace BBLib.move_articles(self, position, capitalize:capitalize)
|
80
84
|
end
|
81
85
|
|
82
86
|
def drop_symbols
|
@@ -91,7 +95,30 @@ class String
|
|
91
95
|
BBLib.extract_integers self, convert:convert
|
92
96
|
end
|
93
97
|
|
98
|
+
def extract_floats convert: true
|
99
|
+
BBLib.extract_floats self, convert:convert
|
100
|
+
end
|
101
|
+
|
94
102
|
def extract_numbers convert: true
|
95
103
|
BBLib.extract_numbers self, convert:convert
|
96
104
|
end
|
105
|
+
|
106
|
+
def to_clean_sym
|
107
|
+
self.strip.downcase.gsub('_', ' ').drop_symbols.gsub(' ', '_').to_sym
|
108
|
+
end
|
109
|
+
|
110
|
+
# Simple method to convert a string into an array containing only itself
|
111
|
+
def to_a
|
112
|
+
return [self]
|
113
|
+
end
|
114
|
+
|
115
|
+
def encap_by? str
|
116
|
+
return self.start_with?(str) && self.end_with?(str)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Symbol
|
121
|
+
def to_clean_sym
|
122
|
+
self.to_s.strip.downcase.gsub('_', ' ').drop_symbols.gsub(' ', '_').to_sym
|
123
|
+
end
|
97
124
|
end
|
data/lib/time/bbtime.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
|
1
|
+
require_relative 'task_timer'
|
2
2
|
|
3
3
|
module BBLib
|
4
4
|
|
5
5
|
# Parses known time based patterns out of a string to construct a numeric duration.
|
6
6
|
def self.parse_duration str, output: :sec
|
7
|
-
|
7
|
+
msecs = 0.0
|
8
8
|
TIME_EXPS.each do |k, v|
|
9
9
|
v[:exp].each do |e|
|
10
|
-
numbers = str.downcase.scan(/(?=\w|\D|\A)\d
|
10
|
+
numbers = str.downcase.scan(/(?=\w|\D|\A)\d*\.?\d+[[:space:]]*#{e}(?=\W|\d|\z)/i)
|
11
11
|
numbers.each do |n|
|
12
|
-
|
12
|
+
msecs+= n.to_f * v[:mult]
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
msecs / (TIME_EXPS[output][:mult] rescue 1)
|
17
17
|
end
|
18
18
|
|
19
19
|
# Turns a numeric input into a time string.
|
@@ -24,47 +24,83 @@ module BBLib
|
|
24
24
|
n, done = num * TIME_EXPS[input.to_sym][:mult], false
|
25
25
|
TIME_EXPS.reverse.each do |k, v|
|
26
26
|
next unless !done
|
27
|
+
if k == stop then done = true end
|
27
28
|
div = n / v[:mult]
|
28
|
-
if div
|
29
|
-
|
30
|
-
|
29
|
+
if div >= 1
|
30
|
+
val = (done ? div.round : div.floor)
|
31
|
+
expression << "#{val}#{v[:styles][style]}#{val > 1 && style != :short ? "s" : nil}"
|
32
|
+
n-= val.to_f * v[:mult]
|
31
33
|
end
|
32
|
-
if k == stop then done = true end
|
33
34
|
end
|
34
35
|
expression.join ' '
|
35
36
|
end
|
36
37
|
|
37
38
|
TIME_EXPS = {
|
38
|
-
|
39
|
+
yocto: {
|
40
|
+
mult: 0.000000000000000000001,
|
41
|
+
styles: {full: ' yoctosecond', medium: ' yocto', short: 'ys'},
|
42
|
+
exp: ['yoctosecond', 'yocto', 'yoctoseconds', 'yoctos', 'ys']
|
43
|
+
},
|
44
|
+
zepto: {
|
45
|
+
mult: 0.000000000000000001,
|
46
|
+
styles: {full: ' zeptosecond', medium: ' zepto', short: 'zs'},
|
47
|
+
exp: ['zeptosecond', 'zepto', 'zeptoseconds', 'zeptos', 'zs']
|
48
|
+
},
|
49
|
+
atto: {
|
50
|
+
mult: 0.000000000000001,
|
51
|
+
styles: {full: ' attosecond', medium: ' atto', short: 'as'},
|
52
|
+
exp: ['attoseconds', 'atto', 'attoseconds', 'attos', 'as']
|
53
|
+
},
|
54
|
+
femto: {
|
55
|
+
mult: 0.000000000001,
|
56
|
+
styles: {full: ' femtosecond', medium: ' fempto', short: 'fs'},
|
57
|
+
exp: ['femtosecond', 'fempto', 'femtoseconds', 'femptos', 'fs']
|
58
|
+
},
|
59
|
+
pico: {
|
60
|
+
mult: 0.000000001,
|
61
|
+
styles: {full: ' picosecond', medium: ' pico', short: 'ps'},
|
62
|
+
exp: ['picosecond', 'pico', 'picoseconds', 'picos', 'ps']
|
63
|
+
},
|
64
|
+
nano: {
|
65
|
+
mult: 0.000001,
|
66
|
+
styles: {full: ' nanosecond', medium: ' nano', short: 'ns'},
|
67
|
+
exp: ['nanosecond', 'nano', 'nanoseconds', 'nanos', 'ns']
|
68
|
+
},
|
69
|
+
micro: {
|
39
70
|
mult: 0.001,
|
40
|
-
styles: {full: '
|
71
|
+
styles: {full: ' microsecond', medium: ' micro', short: 'μs'},
|
72
|
+
exp: ['microsecond', 'micro', 'microseconds', 'micros', 'μs']
|
73
|
+
},
|
74
|
+
milli: {
|
75
|
+
mult: 1,
|
76
|
+
styles: {full: ' millisecond', medium: ' mil', short: 'ms'},
|
41
77
|
exp: ['ms', 'mil', 'mils', 'milli', 'millis', 'millisecond', 'milliseconds', 'milsec', 'milsecs', 'msec', 'msecs', 'msecond', 'mseconds']},
|
42
78
|
sec: {
|
43
|
-
mult:
|
79
|
+
mult: 1000,
|
44
80
|
styles: {full: ' second', medium: ' sec', short: 's'},
|
45
81
|
exp: ['s', 'sec', 'secs', 'second', 'seconds']},
|
46
82
|
min: {
|
47
|
-
mult:
|
83
|
+
mult: 60000,
|
48
84
|
styles: {full: ' minute', medium: ' min', short: 'm'},
|
49
85
|
exp: ['m', 'mn', 'mns', 'min', 'mins', 'minute', 'minutes']},
|
50
86
|
hour: {
|
51
|
-
mult:
|
87
|
+
mult: 3600000,
|
52
88
|
styles: {full: ' hour', medium: ' hr', short: 'h'},
|
53
89
|
exp: ['h', 'hr', 'hrs', 'hour', 'hours']},
|
54
90
|
day: {
|
55
|
-
mult:
|
91
|
+
mult: 86400000,
|
56
92
|
styles: {full: ' day', medium: ' day', short: 'd'},
|
57
|
-
exp: ['d', 'day' 'days']},
|
93
|
+
exp: ['d', 'day', 'days']},
|
58
94
|
week: {
|
59
|
-
mult:
|
95
|
+
mult: 604800000,
|
60
96
|
styles: {full: ' week', medium: ' wk', short: 'w'},
|
61
97
|
exp: ['w', 'wk', 'wks', 'week', 'weeks']},
|
62
98
|
month: {
|
63
|
-
mult:
|
99
|
+
mult: 2592000000,
|
64
100
|
styles: {full: ' month', medium: ' mo', short: 'mo'},
|
65
101
|
exp: ['mo', 'mon', 'mons', 'month', 'months', 'mnth', 'mnths', 'mth', 'mths']},
|
66
102
|
year: {
|
67
|
-
mult:
|
103
|
+
mult: 31536000000,
|
68
104
|
styles: {full: ' year', medium: ' yr', short: 'y'},
|
69
105
|
exp: ['y', 'yr', 'yrs', 'year', 'years']}
|
70
106
|
}
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module BBLib
|
2
|
+
|
3
|
+
class TaskTimer
|
4
|
+
attr_reader :tasks, :save, :retention
|
5
|
+
|
6
|
+
def initialize task:nil, retention:100
|
7
|
+
@tasks = {}
|
8
|
+
self.retention = retention
|
9
|
+
if task then start task end
|
10
|
+
end
|
11
|
+
|
12
|
+
def retention= num
|
13
|
+
@retention = num.nil? ? nil : BBLib.keep_between(num, -1, nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
def time task = :default, type = :current
|
17
|
+
return nil unless @tasks.keys.include? task
|
18
|
+
numbers = @tasks[task][:history].map{ |v| v[:time] }
|
19
|
+
case type
|
20
|
+
when :current
|
21
|
+
return nil unless @tasks[task][:current]
|
22
|
+
return Time.now.to_f - @tasks[task][:current]
|
23
|
+
when :min
|
24
|
+
return numbers.min
|
25
|
+
when :max
|
26
|
+
return numbers.max
|
27
|
+
when :avg
|
28
|
+
return numbers.inject{ |sum, n| sum + n }.to_f / numbers.size
|
29
|
+
when :sum
|
30
|
+
return numbers.inject{ |sum, n| sum + n }
|
31
|
+
when :all
|
32
|
+
return numbers
|
33
|
+
when :first
|
34
|
+
return numbers.first
|
35
|
+
when :last
|
36
|
+
return numbers.last
|
37
|
+
when :count
|
38
|
+
return numbers.size
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear task
|
43
|
+
return nil unless @tasks.keys.include?(task)
|
44
|
+
stop task
|
45
|
+
@tasks[task][:history].clear
|
46
|
+
end
|
47
|
+
|
48
|
+
def start task = :default
|
49
|
+
if !@tasks.keys.include?(task) then @tasks[task] = {history: [], current: nil} end
|
50
|
+
if @tasks[task][:current] then stop task end
|
51
|
+
@tasks[task][:current] = Time.now.to_f
|
52
|
+
return 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def stop task = :default
|
56
|
+
return nil unless @tasks.keys.include?(task) && active?(task)
|
57
|
+
time_taken = Time.now.to_f - @tasks[task][:current].to_f
|
58
|
+
@tasks[task][:history] << {start: @tasks[task][:current], stop: Time.now.to_f, time: time_taken}
|
59
|
+
@tasks[task][:current] = nil
|
60
|
+
if @retention && @tasks[task][:history].size > @retention then @tasks[task][:history].shift end
|
61
|
+
time_taken
|
62
|
+
end
|
63
|
+
|
64
|
+
def restart task = :default
|
65
|
+
start(task) unless stop(task).nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
def save= save
|
69
|
+
@save = save
|
70
|
+
end
|
71
|
+
|
72
|
+
def active? task
|
73
|
+
return false unless @tasks.keys.include? task
|
74
|
+
!@tasks[task][:current].nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing *args
|
78
|
+
temp = args.first.to_s.sub('p_','').to_sym
|
79
|
+
type, task = TIMER_TYPES.keys.find{ |k| k == temp || TIMER_TYPES[k].include?(temp) }, args[1] ||= :default
|
80
|
+
raise NoMethodError unless type
|
81
|
+
t = time task, type
|
82
|
+
args.first.to_s.start_with?('p_') && type != :count ? t.to_duration : t
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
TIMER_TYPES = {
|
88
|
+
current: [],
|
89
|
+
avg: [:average, :av],
|
90
|
+
all: [:times],
|
91
|
+
max: [:maximum, :largest],
|
92
|
+
min: [:minimum, :smallest],
|
93
|
+
sum: [],
|
94
|
+
last: [:latest],
|
95
|
+
first: [:initial],
|
96
|
+
count: [:total]
|
97
|
+
}
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
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: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Black
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,17 +70,21 @@ files:
|
|
70
70
|
- bblib.gemspec
|
71
71
|
- bin/console
|
72
72
|
- bin/setup
|
73
|
+
- lib/array/bbarray.rb
|
73
74
|
- lib/bblib.rb
|
74
75
|
- lib/bblib/version.rb
|
75
76
|
- lib/file/bbfile.rb
|
76
77
|
- lib/hash/bbhash.rb
|
77
|
-
- lib/
|
78
|
-
- lib/
|
78
|
+
- lib/hash/hash_path.rb
|
79
|
+
- lib/hash/hash_path_proc.rb
|
80
|
+
- lib/number/bbnumber.rb
|
81
|
+
- lib/object/bbobject.rb
|
79
82
|
- lib/string/bbstring.rb
|
80
83
|
- lib/string/fuzzy_matcher.rb
|
81
84
|
- lib/string/matching.rb
|
82
85
|
- lib/string/roman.rb
|
83
86
|
- lib/time/bbtime.rb
|
87
|
+
- lib/time/task_timer.rb
|
84
88
|
homepage: https://github.com/bblack16/bblib-ruby
|
85
89
|
licenses:
|
86
90
|
- MIT
|
@@ -101,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
105
|
version: '0'
|
102
106
|
requirements: []
|
103
107
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.4.
|
108
|
+
rubygems_version: 2.4.5.1
|
105
109
|
signing_key:
|
106
110
|
specification_version: 4
|
107
111
|
summary: A library containing many reusable, basic functions.
|
data/lib/net/bbnet.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# TO BE WRITTEN
|