bblib 0.2.2 → 0.3.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.
@@ -1,3 +1,7 @@
1
+ require_relative 'attr'
2
+ require_relative 'hooks'
3
+ require_relative 'simple_serialize'
4
+
1
5
  module BBLib
2
6
 
3
7
  def self.to_hash obj
@@ -25,4 +29,16 @@ module BBLib
25
29
  return hash
26
30
  end
27
31
 
32
+ def self.named_args *args
33
+ args.last.is_a?(Hash) && args.last.keys.all?{|k|k.is_a?(Symbol)} ? args.last : Hash.new
34
+ end
35
+
36
+ def self.named_args! *args
37
+ if args.last.is_a?(Hash) && args.last.keys.all?{|k|k.is_a?(Symbol)}
38
+ args.delete_at(-1)
39
+ else
40
+ Hash.new
41
+ end
42
+ end
43
+
28
44
  end
@@ -0,0 +1,69 @@
1
+ module BBLib::Hooks
2
+
3
+ def method_added name
4
+ before_hooks_for(name).each do |hook|
5
+ next if before_hooked_methods[hook] && before_hooked_methods[hook].include?(name)
6
+ add_before_hook(name, hook)
7
+ end
8
+ after_hooks_for(name).each do |hook|
9
+ next if after_hooked_methods[hook] && after_hooked_methods[hook].include?(name)
10
+ add_after_hook(name, hook)
11
+ end
12
+ end
13
+
14
+ def before hook, *methods
15
+ methods.each{ |m| before_hooks[hook] = methods }
16
+ end
17
+
18
+ def before_hooks
19
+ @before_hooks ||= {}
20
+ end
21
+
22
+ def before_hooked_methods
23
+ @before_hooked_methods ||= {}
24
+ end
25
+
26
+ def before_hooks_for name
27
+ before_hooks.map{ |n, m| m.include?(name)? n : nil }.reject(&:nil?)
28
+ end
29
+
30
+ def add_before_hook method, hook
31
+ before_hooked_methods[hook] = Array.new unless before_hooked_methods[hook]
32
+ before_hooked_methods[hook] += [method]
33
+ original = instance_method(method)
34
+ define_method(method) do |*args, &block|
35
+ # puts "ARGS: #{args}"
36
+ method(hook).call
37
+ original.bind(self).call(*args, &block)
38
+ end
39
+ end
40
+
41
+ def after hook, *methods
42
+ methods.each{ |m| after_hooks[hook] = methods }
43
+ end
44
+
45
+ def after_hooks
46
+ @after_hooks ||= {}
47
+ end
48
+
49
+ def after_hooked_methods
50
+ @after_hooked_methods ||= {}
51
+ end
52
+
53
+ def after_hooks_for name
54
+ after_hooks.map{ |n, m| m.include?(name) ? n : nil }.reject(&:nil?)
55
+ end
56
+
57
+ def add_after_hook method, hook
58
+ after_hooked_methods[hook] = Array.new unless after_hooked_methods[hook]
59
+ after_hooked_methods[hook] += [method]
60
+ original = instance_method(method)
61
+
62
+ define_method(method) do |*args, &block|
63
+ rtr = original.bind(self).call(*args, &block)
64
+ method(hook).call
65
+ rtr
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,73 @@
1
+
2
+ module BBLib
3
+
4
+ class LazyClass
5
+ extend Hooks
6
+ extend Attr
7
+ attr_reader :_serialize_fields
8
+
9
+ def initialize *args
10
+ _pre_setup
11
+ lazy_setup
12
+ _lazy_init(*args)
13
+ end
14
+
15
+ def serialize
16
+ _serialize_fields.map do |name, h|
17
+ value = send(h[:method])
18
+ if !h[:always] && value == h[:ignore]
19
+ nil
20
+ else
21
+ [ name, value ]
22
+ end
23
+ end.reject(&:nil?).to_h
24
+ end
25
+
26
+ protected
27
+
28
+ def lazy_setup
29
+ # Instantiate necessary variables here
30
+ end
31
+
32
+ def _lazy_init *args
33
+ BBLib::named_args(*args).each do |k,v|
34
+ if self.respond_to?("#{k}=".to_sym)
35
+ send("#{k}=".to_sym, v)
36
+ end
37
+ end
38
+ lazy_init *args
39
+ custom_lazy_init BBLib::named_args(*args), *args
40
+ end
41
+
42
+ def _pre_setup
43
+ self.methods.each do |m|
44
+ if m.to_s.start_with?('__reset_')
45
+ send(m) rescue nil
46
+ end
47
+ end
48
+ end
49
+
50
+ def lazy_init *args
51
+ # Define custom initialization here...
52
+ end
53
+
54
+ def custom_lazy_init *args
55
+ # Left in for legacy support...don't use this!
56
+ end
57
+
58
+ def serialize_method name, method = nil, ignore: nil, always: false
59
+ return if method == :serialize || name == :serialize && method.nil?
60
+ _serialize_fields[name.to_sym] = {
61
+ method: (method.nil? ? name.to_sym : method.to_sym),
62
+ ignore: ignore,
63
+ always: always
64
+ }
65
+ end
66
+
67
+ def _serialize_fields
68
+ @_serialize_fields ||= Hash.new
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,16 @@
1
+ module BBLib
2
+
3
+ def self.in_opal?
4
+ RUBY_ENGINE == 'opal'
5
+ end
6
+
7
+ end
8
+
9
+ if BBLib.in_opal?
10
+ class Element
11
+
12
+ alias_native :replace_with, :replaceWith
13
+ alias_native :prepend
14
+ alias_native :get_context, :getContext
15
+ end
16
+ end
@@ -0,0 +1,93 @@
1
+ require_relative 'bbsys'
2
+
3
+ module BBLib
4
+
5
+ module OS
6
+
7
+ def self.os
8
+ return :windows if windows?
9
+ return :mac if mac?
10
+ return :linux if linux?
11
+ end
12
+
13
+ def self.windows?
14
+ builds = ['mingw', 'mswin', 'cygwin', 'bccwin']
15
+ !(/#{builds.join('|')}/i =~ RUBY_PLATFORM).nil?
16
+ end
17
+
18
+ def self.linux?
19
+ !windows? && !mac?
20
+ end
21
+
22
+ def self.unix?
23
+ !windows?
24
+ end
25
+
26
+ def self.mac?
27
+ builds = ['darwin']
28
+ !(/#{builds.join('|')}/i =~ RUBY_PLATFORM).nil?
29
+ end
30
+
31
+ def self.os_info
32
+ if windows?
33
+ data = `wmic os get manufacturer,name,organization,osarchitecture,version /format:list`
34
+ data = data.split("\n").reject{ |r| r.strip == '' }.map do |m|
35
+ spl = m.split('=')
36
+ [spl.first.to_clean_sym.downcase, spl[1..-1].join('=')]
37
+ end.to_h
38
+ data[:name] = data[:name].split('|').first
39
+ data[:osarchitecture] = data[:osarchitecture].extract_integers.first
40
+ data.hpath_move( 'osarchitecture' => 'bits' )
41
+ data[:host] = `hostname`.strip
42
+ data[:os] = os
43
+ data
44
+ else
45
+ release = {}
46
+ begin
47
+ # First attempt to get release info uses lsb_release
48
+ release = `lsb_release -a`.split("\n").map do |l|
49
+ spl = l.split(':')
50
+ [
51
+ spl.first.downcase.to_clean_sym,
52
+ spl[1..-1].join(':').strip
53
+ ]
54
+ end.to_h
55
+ release.hpath_move('description' => 'name', 'release' => 'name', 'distributor_id' => 'manufacturer')
56
+ rescue
57
+ # Try finding the release file and parsing it instead of lsb_release
58
+ begin
59
+ release = `cat /etc/*release`
60
+ .split("\n")
61
+ .reject{ |l| !(l.include?(':') || l.include?('=')) }
62
+ .map{|l| l.msplit('=',':') }
63
+ .map{ |a| [a.first.downcase.to_clean_sym, a[1..-1].join(':').uncapsulate] }
64
+ .to_h
65
+ rescue
66
+ # Both attempts failed
67
+ end
68
+ end
69
+ {
70
+ release: `uname -r`.strip,
71
+ bits: `uname -r` =~ /x86_64/i ? 64 : 32,
72
+ host: `uname -n`.strip,
73
+ os: os
74
+ }.merge(release)
75
+ end
76
+ end
77
+
78
+ # The following is Windows specific code
79
+ if windows?
80
+
81
+ def self.parse_wmic cmd
82
+ `#{cmd} /format:list`
83
+ .split("\n\n\n").reject(&:empty?)
84
+ .map{ |l| l.split("\n\n")
85
+ .map{ |l| spl = l.split('='); [spl.first.strip.downcase.to_clean_sym, spl[1..-1].join('=').strip ] }.to_h
86
+ }.reject(&:empty?)
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,238 @@
1
+
2
+
3
+
4
+ module BBLib
5
+ module OS
6
+
7
+ def self.cpu_usages
8
+ if windows?
9
+ {
10
+ total: `wmic cpu get loadpercentage /format:value`.extract_numbers.first.to_f
11
+ }
12
+ elsif linux? || mac?
13
+ system_stats[:cpu]
14
+ else
15
+ nil
16
+ end
17
+ end
18
+
19
+ def self.uptime
20
+ if windows?
21
+ uptime = `net statistics server`.split("\n").find{|l| l.start_with?('Statistics since ')}.split(/since /i).last.strip
22
+ Time.now - Time.strptime(uptime, '%m/%d/%Y %l:%M:%S %p')
23
+ else
24
+ `cat /proc/uptime`.extract_numbers.first
25
+ end
26
+ end
27
+
28
+ def self.cpu_used_p
29
+ cpu_usages[:total]
30
+ end
31
+
32
+ def self.cpu_free_p
33
+ 100 - cpu_used
34
+ end
35
+
36
+ def self.mem_total
37
+ if windows?
38
+ `wmic computersystem get TotalPhysicalMemory`.extract_numbers.first / 1024.0
39
+ elsif linux?
40
+ system_stats.hpath('memory.total')
41
+ else
42
+ nil
43
+ end
44
+ end
45
+
46
+ def self.mem_used
47
+ mem_total.to_f - mem_free.to_f
48
+ end
49
+
50
+ def self.mem_used_p
51
+ (mem_used.to_f / mem_total.to_f) * 100.0
52
+ end
53
+
54
+ def self.mem_free
55
+ if windows?
56
+ `wmic os get freephysicalmemory /format:value`.extract_numbers.first
57
+ elsif linux?
58
+ system_stats.hpath('memory.free')
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def self.mem_free_p
65
+ (mem_free.to_f / mem_total.to_f) * 100.0
66
+ end
67
+
68
+ def self.system_stats
69
+ if windows?
70
+ memfree = mem_free
71
+ memtotal = mem_total
72
+ memused = memtotal - memfree
73
+ {
74
+ cpu: cpu_usages,
75
+ memory: {
76
+ free: memfree,
77
+ used: memused,
78
+ total: memtotal,
79
+ free_p: (memfree / memtotal.to_f) * 100,
80
+ used_p: (memused / memtotal.to_f) * 100
81
+ },
82
+ uptime: uptime
83
+ }
84
+ else
85
+ stats = `top -b -n2 -d 0.1`.split("\n")
86
+ cpu = stats.find_all{|l| l =~ /\A\%?Cpu\(s\)/i }.last.extract_numbers
87
+ loads = stats.find_all{|l| l =~ / load average\: /i }.last.scan(/load average:.*/i).first.extract_numbers
88
+ mem = stats.find_all{|l| l =~ /KiB Mem|Mem\:/i }.last.extract_numbers
89
+ time = `cat /proc/uptime`.extract_numbers
90
+ {
91
+ cpu: {
92
+ user: cpu[0],
93
+ system: cpu[1],
94
+ nice: cpu[2],
95
+ total: cpu[0..2].inject(0){ |sum, v| sum += v.to_f },
96
+ idle: cpu[3],
97
+ wait: cpu[4],
98
+ hardware_interrupts: cpu[5],
99
+ software_interrupts: cpu[6],
100
+ hypervisor: cpu[7]
101
+ },
102
+ uptime: time[0],
103
+ uptime_idle: time[1],
104
+ memory: {
105
+ free: mem[1],
106
+ used: mem[2],
107
+ total: mem[0],
108
+ cache: mem[3],
109
+ free_p: (mem[1] / mem[0].to_f) * 100,
110
+ used_p: (mem[2] / mem[0].to_f) * 100
111
+ },
112
+ load_average: {
113
+ 1 => loads[0],
114
+ 5 => loads[1],
115
+ 15 => loads[2]
116
+ }
117
+ }
118
+ end
119
+ end
120
+
121
+ def self.processes
122
+ if windows?
123
+ tasks = `tasklist /v`
124
+ cpu = `wmic path win32_perfformatteddata_perfproc_process get PercentProcessorTime,percentusertime,IDProcess /format:list`
125
+ cpu = cpu.split("\n\n\n\n").reject(&:empty?)
126
+ .map{ |l| l.scan(/\d+/).map(&:to_i)}
127
+ .map{ |n|[ n[0], {cpu: n[1], user: n[2] }]}.to_h
128
+ lines = tasks.split("\n")[3..-1].map{ |l| l.split(/\s{2,}/) }
129
+ mem = mem_total
130
+ cmds = `wmic process get processid,commandline /format:csv`.split("\n")[1..-1].reject{ |r| r.strip == ''}.map{ |l| l.split(',')[1..-1] }.map{ |l| [l.last.to_i, l[0..-2].join(',')]}.to_h
131
+ lines.map do |l|
132
+ pid = l[1].extract_numbers.first
133
+ {
134
+ name: l[0],
135
+ pid: pid,
136
+ user: l[4],
137
+ mem: (((l[3].gsub(',', '').extract_numbers.first / mem_total) * 100) rescue nil),
138
+ cpu: (cpu[pid][:cpu] rescue nil),
139
+ cmd: cmds[pid]
140
+ }
141
+ end
142
+ else
143
+ t = `ps -e -o comm,pid,ruser,%cpu,%mem,cmd`
144
+ lines = t.split("\n")[1..-1].map{ |l| l.split(/\s+/) }
145
+ lines.map{ |l| l.size == 6 ? l : [l[0], l[1], l[2], l[3], l[4], l[5..-1].join(' ')] }
146
+ lines.map do |l|
147
+ {
148
+ name: l[0],
149
+ pid: l[1].to_i,
150
+ user: l[2],
151
+ cpu: l[3].to_f,
152
+ mem: l[4].to_f,
153
+ cmd: l[5]
154
+ }
155
+ end
156
+ end
157
+ end
158
+
159
+ def self.filesystems
160
+ if windows?
161
+ types = {
162
+ 0 => 'Unknown',
163
+ 1 => 'No Root Directory',
164
+ 2 => 'Removable Disk',
165
+ 3 => 'Local Disk',
166
+ 4 => 'Network Drive',
167
+ 5 => 'Compact Disc',
168
+ 6 => 'RAM Disk'
169
+ }
170
+ parse_wmic('wmic logicaldisk get name,description,filesystem,freespace,size,volumename,volumeserialnumber,providername,drivetype')
171
+ .map do |v|
172
+ v.hpath_move(
173
+ 'freespace' => 'free',
174
+ 'providername' => 'provider',
175
+ 'volumename' => 'volume_name',
176
+ 'volumeserialnumber' => 'serial_number',
177
+ 'filesystem' => 'filesystem_type',
178
+ 'name' => 'disk'
179
+ )
180
+ dt = v.delete(:drivetype).to_i
181
+ v[:type] = types[dt]
182
+ if (2..4) === dt
183
+ v[:free] = v[:free].to_i
184
+ v[:size] = v[:size].to_i
185
+ v[:used] = v[:size] - v[:free]
186
+ v[:free_p] = (v[:free] / v[:size].to_f) * 100
187
+ v[:used_p] = (v[:used] / v[:size].to_f) * 100
188
+ end
189
+ v
190
+ end
191
+ else
192
+ `df -aTB 1`
193
+ .split("\n")[1..-1]
194
+ .map{ |l| l.split(/\s{2,}|(?<=\d)\s|(?<=%)\s|(?<=\-)\s|(?<=\w)\s+(?=\w+\s+\d)/)}
195
+ .map do |i|
196
+ {
197
+ filesystem: i[0],
198
+ type: i[1],
199
+ size: i[2].to_i,
200
+ used: i[3].to_i,
201
+ available: i[4].to_i,
202
+ used_p: i[5].extract_integers.first.to_f,
203
+ mount: i[6],
204
+ }
205
+ end
206
+ end
207
+ end
208
+
209
+
210
+ # A mostly platform agnostic call to get root volumes
211
+ def self.root_volumes
212
+ if BBLib.windows?
213
+ begin # For windows
214
+ `wmic logicaldisk get name`.split("\n").map{ |m| m.strip }[1..-1].reject{ |r| r == '' }
215
+ rescue
216
+ begin # Windows attempt 2
217
+ `fsutil fsinfo drives`.scan(/(?<=\s)\w\:/)
218
+ rescue
219
+ nil
220
+ end
221
+ end
222
+ else
223
+ begin
224
+ `ls /`.split("\n").map{ |m| m.strip }.reject{ |r| r == '' }
225
+ rescue # All attempts failed
226
+ nil
227
+ end
228
+ end
229
+ end
230
+
231
+ # Windows only method to get the volume labels of disk drives
232
+ def self.root_volume_labels
233
+ return nil unless BBLib.windows?
234
+ `wmic logicaldisk get caption,volumename`.split("\n")[1..-1].map{ |m| [m.split(" ").first.to_s.strip, m.split(" ")[1..-1].to_a.join(' ').strip] }.reject{ |o,t| o == '' }.to_h
235
+ end
236
+
237
+ end
238
+ end