linux_stat 0.7.5 → 1.0.1

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.
@@ -76,17 +76,23 @@ MARKDOWN, HTML = hash[:markdown], hash[:html]
76
76
 
77
77
  # Print time each method takes unless --no-time or -nt option is passed
78
78
  PRINT_TIME = (MARKDOWN || HTML) ? false : !ARGV.any? { |x| x[/^\-\-no-time$/] || x[/^\-nt$/] }
79
-
80
- %w(--markdown -md --no-time -nt --html -html).each(&ARGV.method(:delete))
79
+ PRINT_TYPE = ARGV.any? { |x| x[/^\-(\-show\-type|t)$/] }
80
+ %w(--markdown -md --no-time -nt --html -html --show-type -t).each(&ARGV.method(:delete))
81
81
 
82
82
  # Run only desired classes / modules
83
83
  constants = LinuxStat.constants
84
84
 
85
+ # Modules to delete from documentation and testing
86
+ %i(
87
+ Nproc
88
+ ).each(&constants.method(:delete))
89
+
85
90
  execute = constants.map(&:downcase).map.with_index { |x, i|
86
91
  constants[i] if ARGV.find { |y| y.downcase.to_sym == x }
87
92
  }.compact
88
93
 
89
94
  execute.replace(constants) if execute.empty?
95
+ HEXAGONS = %W(\u2b22 \u2b23 \u2B53 \u2B1F)
90
96
 
91
97
  execute.sort.each do |c|
92
98
  e = eval("LinuxStat::#{c}")
@@ -138,36 +144,51 @@ execute.sort.each do |c|
138
144
  disp_meth.concat(arg ? "(#{param} = #{arg.inspect})" : "(#{param})")
139
145
 
140
146
  time = Time.now
141
- v = arg ? e.send(meth, arg) : e.send(meth)
147
+ ret = arg ? e.send(meth, arg) : e.send(meth)
142
148
  time2 = Time.now
143
149
  time = time2.-(time).*(1_000_000).round(3)
144
150
 
145
- v = v.inspect
151
+ v = ret.inspect
146
152
  dis = v.length > 253 ? v[0..250].strip + '...'.freeze : v
147
153
 
148
154
  source = e.singleton_method(meth).source_location.to_a
149
- src, src_meth = '', ''
155
+ src, src_meth, src_ret = '', '', ''
150
156
 
151
157
  unless source.empty?
152
- src << " File: #{File.split(source[0])[-1]} | Line: #{source[1]}\n"
153
- src_meth << " Definition: #{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
158
+ src << " File:\t\t#{File.split(source[0])[-1]} | Line: #{source[1]}\n"
159
+ src_meth << " Definition:\t#{IO.foreach(source[0]).first(source[1])[-1].strip}\n"
160
+
161
+ src_ret << " Returns:\t" << case ret
162
+ when Array then 'Array | Empty Array'
163
+ when Complex then 'Complex | nil'
164
+ when Float then 'Float | nil'
165
+ when Hash then 'Hash | Empty Hash'
166
+ when Integer then 'Integer | nil'
167
+ when Rational then 'Rational | nil'
168
+ when String then "String | (Frozen) Empty String"
169
+ when Time then 'Time | nil'
170
+ when true, false then 'True or False | nil'
171
+ when nil then 'nil'
172
+ else ''
173
+ end << ?\n.freeze if PRINT_TYPE
154
174
 
155
175
  if MARKDOWN || HTML
156
176
  src.prepend('#'.freeze)
157
177
  src_meth.prepend('#'.freeze)
178
+ src_ret.prepend(?#.freeze) if PRINT_TYPE
158
179
  else
159
- src.prepend(?\u2B23.freeze)
160
- src_meth.prepend(?\u2B23.freeze)
180
+ src.prepend(HEXAGONS.rotate![0].freeze)
181
+ src_meth.prepend(HEXAGONS.rotate![0].freeze)
182
+ src_ret.prepend(HEXAGONS.rotate![0].freeze) if PRINT_TYPE
161
183
  end
162
184
  end
163
185
 
164
-
165
186
  if MARKDOWN
166
- puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
187
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
167
188
  elsif HTML
168
- puts "#{src}#{src_meth}#{e}.#{disp_meth}\n=> #{dis}"
189
+ puts "#{src}#{src_meth}#{src_ret}#{e}.#{disp_meth}\n=> #{dis}"
169
190
  else
170
- puts "\e[1m#{src.colourize}\e[1m#{src_meth.colourize(4)}\e[0m\e[1;38;2;80;80;255m#{e}.#{disp_meth}\e[0m\n=> #{dis}"
191
+ puts "\e[1m#{src.colourize}\e[1m#{src_meth.colourize(6)}\e[1m#{src_ret.colourize(1)}\e[0m\e[1;38;2;80;80;255m#{e}.#{disp_meth}\e[0m\n=> #{dis}"
171
192
  end
172
193
 
173
194
  puts( "(" +
@@ -1,8 +1,15 @@
1
1
  #include <sys/statvfs.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static VALUE statfs(VALUE obj, VALUE dir) {
8
15
  struct statvfs buf ;
@@ -0,0 +1,11 @@
1
+ require 'mkmf'
2
+
3
+ unless have_const('linux') || RbConfig::CONFIG['arch'].to_s[/linux/]
4
+ abort('Platform is not linux')
5
+ end
6
+
7
+ unless have_header('sched.h') && have_header('ruby.h')
8
+ abort('Missing header')
9
+ end
10
+
11
+ create_makefile 'linux_stat/nproc'
@@ -0,0 +1,31 @@
1
+ #ifndef _GNU_SOURCE
2
+ #define _GNU_SOURCE
3
+ #endif
4
+
5
+ #include <sched.h>
6
+ #include "ruby.h"
7
+
8
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
9
+ #pragma GCC optimize ("O3")
10
+ #pragma GCC diagnostic warning "-Wall"
11
+ #elif defined(__clang__)
12
+ #pragma clang optimize on
13
+ #pragma clang diagnostic warning "-Wall"
14
+ #elif defined(__INTEL_COMPILER)
15
+ #pragma intel optimization_level 3
16
+ #endif
17
+
18
+ static VALUE count_cpu_for_pid(VALUE obj, VALUE pid) {
19
+ cpu_set_t set ;
20
+ CPU_ZERO(&set) ;
21
+ short int stat = sched_getaffinity(FIX2INT(pid), sizeof(set), &set) ;
22
+
23
+ if (stat < 0) return Qnil ;
24
+ return INT2FIX(CPU_COUNT(&set)) ;
25
+ }
26
+
27
+ void Init_nproc() {
28
+ VALUE _linux_stat = rb_define_module("LinuxStat") ;
29
+ VALUE _nproc = rb_define_module_under(_linux_stat, "Nproc") ;
30
+ rb_define_module_function(_nproc, "count_cpu_for_pid", count_cpu_for_pid, 1) ;
31
+ }
@@ -1,43 +1,105 @@
1
1
  #include <unistd.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static VALUE getTick(VALUE obj) {
8
- return INT2FIX(sysconf(_SC_CLK_TCK)) ;
15
+ short int val = sysconf(_SC_CLK_TCK) ;
16
+ if (val < 0) return Qnil ;
17
+
18
+ return INT2FIX(val) ;
9
19
  }
10
20
 
11
21
  static VALUE getChildMax(VALUE obj) {
12
- return INT2FIX(sysconf(_SC_CHILD_MAX)) ;
22
+ short int val = sysconf(_SC_CHILD_MAX) ;
23
+ if (val < 0) return Qnil ;
24
+
25
+ return INT2FIX(val) ;
13
26
  }
14
27
 
15
28
  static VALUE getHostnameMax(VALUE obj) {
16
- return INT2FIX(sysconf(_SC_HOST_NAME_MAX)) ;
29
+ short int val = sysconf(_SC_HOST_NAME_MAX) ;
30
+ if (val < 0) return Qnil ;
31
+
32
+ return INT2FIX(val) ;
17
33
  }
18
34
 
19
35
  static VALUE getLoginNameMax(VALUE obj) {
20
- return INT2FIX(sysconf(_SC_LOGIN_NAME_MAX)) ;
36
+ short int val = sysconf(_SC_LOGIN_NAME_MAX) ;
37
+ if (val < 0) return Qnil ;
38
+
39
+ return INT2FIX(val) ;
21
40
  }
22
41
 
23
42
  static VALUE getOpenMax(VALUE obj) {
24
- return INT2FIX(sysconf(_SC_OPEN_MAX)) ;
43
+ short int val = sysconf(_SC_OPEN_MAX) ;
44
+ if (val < 0) return Qnil ;
45
+
46
+ return INT2FIX(val) ;
25
47
  }
26
48
 
27
49
  static VALUE getPageSize(VALUE obj) {
28
- return INT2FIX(sysconf(_SC_PAGESIZE)) ;
50
+ short int val = sysconf(_SC_PAGESIZE) ;
51
+ if (val < 0) return Qnil ;
52
+
53
+ return INT2FIX(val) ;
29
54
  }
30
55
 
31
56
  static VALUE getStreamMax(VALUE obj) {
32
- return INT2FIX(sysconf(_SC_STREAM_MAX)) ;
57
+ short int val = sysconf(_SC_STREAM_MAX) ;
58
+ if (val < 0) return Qnil ;
59
+
60
+ return INT2FIX(val) ;
33
61
  }
34
62
 
35
63
  static VALUE getTTYNameMax(VALUE obj) {
36
- return INT2FIX(sysconf(_SC_TTY_NAME_MAX)) ;
64
+ short int val = sysconf(_SC_TTY_NAME_MAX) ;
65
+ if (val < 0) return Qnil ;
66
+
67
+ return INT2FIX(val) ;
37
68
  }
38
69
 
39
70
  static VALUE getPosixVersion(VALUE obj) {
40
- return INT2FIX(sysconf(_SC_VERSION)) ;
71
+ short int val = sysconf(_SC_VERSION) ;
72
+ if (val < 0) return Qnil ;
73
+
74
+ return INT2FIX(val) ;
75
+ }
76
+
77
+ static VALUE getLineMax(VALUE obj) {
78
+ short int val = sysconf(_SC_LINE_MAX) ;
79
+ if (val < 0) return Qnil ;
80
+
81
+ return INT2FIX(val) ;
82
+ }
83
+
84
+ static VALUE getExprNestMax(VALUE obj) {
85
+ short int val = sysconf(_SC_EXPR_NEST_MAX) ;
86
+ if (val < 0) return Qnil ;
87
+
88
+ return INT2FIX(val) ;
89
+ }
90
+
91
+ static VALUE getProcessorConfigured(VALUE obj) {
92
+ short int val = sysconf(_SC_NPROCESSORS_CONF) ;
93
+ if (val < 0) return Qnil ;
94
+
95
+ return INT2FIX(val) ;
96
+ }
97
+
98
+ static VALUE getProcessorOnline(VALUE obj) {
99
+ short int val = sysconf(_SC_NPROCESSORS_ONLN) ;
100
+ if (val < 0) return Qnil ;
101
+
102
+ return INT2FIX(val) ;
41
103
  }
42
104
 
43
105
  static VALUE getUser(VALUE obj) {
@@ -70,6 +132,11 @@ void Init_sysconf() {
70
132
  rb_define_module_function(_sysconf, "stream_max", getStreamMax, 0) ;
71
133
  rb_define_module_function(_sysconf, "tty_name_max", getTTYNameMax, 0) ;
72
134
  rb_define_module_function(_sysconf, "posix_version", getPosixVersion, 0) ;
135
+ rb_define_module_function(_sysconf, "line_max", getLineMax, 0) ;
136
+ rb_define_module_function(_sysconf, "expr_nest_max", getExprNestMax, 0) ;
137
+
138
+ rb_define_module_function(_sysconf, "processor_online", getProcessorOnline, 0) ;
139
+ rb_define_module_function(_sysconf, "processor_configured", getProcessorConfigured, 0) ;
73
140
 
74
141
  rb_define_module_function(_sysconf, "get_uid", getUID, 0) ;
75
142
  rb_define_module_function(_sysconf, "get_gid", getGID, 0) ;
@@ -1,39 +1,51 @@
1
1
  #include <sys/utsname.h>
2
2
  #include "ruby.h"
3
3
 
4
- #pragma GCC optimize ("O3")
5
- #pragma clang optimize on
4
+ #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
5
+ #pragma GCC optimize ("O3")
6
+ #pragma GCC diagnostic warning "-Wall"
7
+ #elif defined(__clang__)
8
+ #pragma clang optimize on
9
+ #pragma clang diagnostic warning "-Wall"
10
+ #elif defined(__INTEL_COMPILER)
11
+ #pragma intel optimization_level 3
12
+ #endif
6
13
 
7
14
  static struct utsname buf ;
8
- static short status ;
15
+
16
+ static char *sysname = "", *nodename = "" ;
17
+ static char *release = "", *version = "", *machine = "" ;
9
18
 
10
19
  void init_buf() {
11
- status = uname(&buf) ;
20
+ short status = uname(&buf) ;
21
+
22
+ if (status > -1) {
23
+ sysname = buf.sysname ;
24
+ nodename = buf.nodename ;
25
+ release = buf.release ;
26
+ version = buf.version ;
27
+ machine = buf.machine ;
28
+ }
12
29
  }
13
30
 
14
31
  static VALUE getSysname(VALUE obj) {
15
- VALUE sysname = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.sysname) ;
16
- return sysname ;
32
+ return rb_str_new_cstr(sysname) ;
17
33
  }
18
34
 
19
35
  static VALUE getNodename(VALUE obj) {
20
- VALUE nodename = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.nodename) ;
21
- return nodename ;
36
+ return rb_str_new_cstr(nodename) ;
22
37
  }
23
38
 
24
39
  static VALUE getRelease(VALUE obj) {
25
- VALUE release = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.release) ;
26
- return release ;
40
+ return rb_str_new_cstr(release) ;
27
41
  }
28
42
 
29
43
  static VALUE getVersion(VALUE obj) {
30
- VALUE version = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.version) ;
31
- return version ;
44
+ return rb_str_new_cstr(version) ;
32
45
  }
33
46
 
34
47
  static VALUE getMachine(VALUE obj) {
35
- VALUE machine = status < 0 ? rb_str_new_cstr("") : rb_str_new_cstr(buf.machine) ;
36
- return machine ;
48
+ return rb_str_new_cstr(machine) ;
37
49
  }
38
50
 
39
51
  void Init_utsname() {
@@ -23,15 +23,19 @@ require 'linux_stat/prettify_bytes'
23
23
  # But might be required by other module functions in "Dependent Modules" section
24
24
  require "linux_stat/battery"
25
25
  require "linux_stat/bios"
26
- require "linux_stat/cpu"
27
26
  require "linux_stat/memory"
28
27
  require "linux_stat/net"
29
28
  require "linux_stat/process"
30
29
  require "linux_stat/swap"
30
+ require "linux_stat/usb"
31
31
 
32
32
  # Dependent Modules
33
33
  # Modules that can have reverse dependency
34
34
 
35
+ # LinuxStat::CPU.nproc dependent modules
36
+ require "linux_stat/cpu"
37
+ require "linux_stat/nproc"
38
+
35
39
  # LinuxStat::Uname dependent modules
36
40
  require 'linux_stat/utsname'
37
41
  require "linux_stat/os"
@@ -46,3 +50,6 @@ require "linux_stat/sysconf"
46
50
  require "linux_stat/kernel"
47
51
  require 'linux_stat/user'
48
52
  require "linux_stat/process_info"
53
+
54
+ # A short alias to LinuxStat
55
+ LS = LinuxStat
@@ -1,6 +1,6 @@
1
1
  module LinuxStat
2
2
  module Battery
3
- PATH = "/sys/class/power_supply/BAT0"
3
+ PATH = "/sys/class/power_supply/BAT0".freeze
4
4
 
5
5
  class << self
6
6
  ##
@@ -34,8 +34,10 @@ module LinuxStat
34
34
  #
35
35
  # If the battery is not present or the information isn't available it will return an empty String.
36
36
  def model
37
- return ''.freeze unless model_readable?
38
- IO.read(File.join(PATH, 'model_name')).tap(&:strip!)
37
+ @@mn_file = File.join(PATH, 'model_name')
38
+ return ''.freeze unless File.readable?(@@mn_file)
39
+
40
+ IO.read(@@mn_file).tap(&:strip!)
39
41
  end
40
42
 
41
43
  ##
@@ -43,8 +45,9 @@ module LinuxStat
43
45
  #
44
46
  # If the battery is not present or the information is not available, it will return an empty String.
45
47
  def manufacturer
48
+ @@manufacturer_file ||= File.join(PATH, 'manufacturer')
46
49
  return ''.freeze unless manufacturer_readable?
47
- IO.read(File.join(PATH, 'manufacturer')).tap(&:strip!)
50
+ IO.read(@@manufacturer_file).tap(&:strip!)
48
51
  end
49
52
 
50
53
  ##
@@ -52,8 +55,9 @@ module LinuxStat
52
55
  #
53
56
  # If the battery is not present or the information is not available, it will return an empty String.
54
57
  def technology
58
+ @@technology_file ||= File.join(PATH, 'technology')
55
59
  return ''.freeze unless tech_readable?
56
- IO.read(File.join(PATH, 'technology')).tap(&:strip!)
60
+ IO.read(@@technology_file).tap(&:strip!)
57
61
  end
58
62
 
59
63
  ##
@@ -62,8 +66,9 @@ module LinuxStat
62
66
  #
63
67
  # If the battery is not present or the information is not available, it will return an empty frozen String.
64
68
  def status
69
+ @@status_file ||= File.join(PATH, 'status'.freeze)
65
70
  return ''.freeze unless status_readable?
66
- IO.read(File.join(PATH, 'status')).tap(&:strip!)
71
+ IO.read(@@status_file).tap(&:strip!)
67
72
  end
68
73
 
69
74
  ##
@@ -81,7 +86,7 @@ module LinuxStat
81
86
  # If the battery is not present or the information is not available, it will return nil.
82
87
  def discharging?
83
88
  return nil if status.empty?
84
- status.downcase == 'discharging'
89
+ status.downcase == 'discharging'.freeze
85
90
  end
86
91
 
87
92
  ##
@@ -90,7 +95,7 @@ module LinuxStat
90
95
  # If the battery is not present or the information is not available, it will return nil.
91
96
  def full?
92
97
  return nil if status.empty?
93
- status.downcase == 'full'
98
+ status.downcase == 'full'.freeze
94
99
  end
95
100
 
96
101
  ##
@@ -98,19 +103,182 @@ module LinuxStat
98
103
  #
99
104
  # If the battery is not present or the information is not available, it will return nil.
100
105
  def charge
101
- return nil unless charge_now_readable?
102
- charge_now = IO.read(File.join(PATH, 'charge_now')).to_i
103
- charge_full = IO.read(File.join(PATH, 'charge_full')).to_i
106
+ @@charge_now_file ||= File.join(PATH, 'charge_now')
107
+ @@charge_full_file ||= File.join(PATH, 'charge_full')
108
+
109
+ @@charge_now_readable ||= File.readable?(@@charge_now_file) && File.readable?(@@charge_full_file)
110
+ return nil unless @@charge_now_readable
111
+
112
+ charge_now = IO.read(@@charge_now_file).to_i
113
+ charge_full = IO.read(@@charge_full_file).to_i
104
114
 
105
115
  percentage = charge_now.*(100).fdiv(charge_full)
106
- percentage = percentage > 100 ? 100.0 : percentage < 0 ? 0.0 : percentage
116
+ percentage > 100 ? 100.0 : percentage < 0 ? 0.0 : percentage
107
117
  end
108
118
 
109
- private
110
- def model_readable?
111
- @@model_readable ||= File.readable?(File.join(PATH, 'model_name'))
119
+ ##
120
+ # Returns the charge full design WH of the battery as Integer
121
+ # However if the info isn't available or there's no BAT0 in the system, this will return nil
122
+ def charge_full_design_wh
123
+ # voltage min design
124
+ @@vmd_f ||= File.join(PATH, 'voltage_min_design'.freeze)
125
+ v_m_d = File.readable?(@@vmd_f) ? IO.read(@@vmd_f).to_i : nil
126
+
127
+ # charge full design
128
+ @@cfd_f ||= File.join(PATH, 'charge_full_design'.freeze)
129
+ c_f_d = File.readable?(@@cfd_f) ? IO.read(@@cfd_f).to_i : nil
130
+
131
+ if v_m_d && c_f_d
132
+ v_m_d.fdiv(1_000_000).*(c_f_d.fdiv(1_000_000)).round(2)
133
+ else
134
+ nil
135
+ end
136
+ end
137
+
138
+ ##
139
+ # Returns the charge full WH of the battery as Integer
140
+ # However if the info isn't available or there's no BAT0 in the system, this will return nil
141
+ def charge_full_wh
142
+ # voltage min design
143
+ @@vmd_f ||= File.join(PATH, 'voltage_min_design'.freeze)
144
+ v_m_d = File.readable?(@@vmd_f) ? IO.read(@@vmd_f).to_i : nil
145
+
146
+ # charge full
147
+ @@cf_f ||= File.join(PATH, 'charge_full'.freeze)
148
+ c_f = File.readable?(@@cf_f) ? IO.read(@@cf_f).to_i : nil
149
+
150
+ if v_m_d && c_f
151
+ v_m_d.fdiv(1_000_000).*(c_f.fdiv(1_000_000)).round(2)
152
+ else
153
+ nil
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Returns the voltage of the battery as Integer
159
+ # However if the info isn't available or there's no BAT0 in the system, this will return nil
160
+ def voltage_now
161
+ @@voltage_file ||= File.join(PATH, 'voltage_now'.freeze)
162
+ @@voltage_readable ||= File.readable?(@@voltage_file)
163
+ return nil unless @@voltage_readable
164
+
165
+ IO.read(@@voltage_file, 16).to_f.fdiv(1000000)
166
+ end
167
+
168
+ ##
169
+ # A linux system can have multiple batteries. This method attempts to
170
+ # find all of them and return a Hash based on the availibility of the
171
+ # information.
172
+ #
173
+ # This method is somewhat slower than other Battery module singleton methods.
174
+ # Because it does various checks and opens various files from /sys/
175
+ #
176
+ # For example, a sample output can be like this (taken on a test system):
177
+ #
178
+ # LinuxStat::Battery.devices_stat
179
+ # => {:AC=>{:type=>"Mains", :online=>1}, :BAT0=>{:model=>"DELL CYMGM77", :manufacturer=>"Samsung SDI", :type=>"Battery", :status=>"Full", :capacity=>100, :voltage_min_design=>11.4, :charge_full_design=>3.684, :charge_full_design_wh=>42.0, :voltage_now=>12.558, :charge_now=>2.087, :charge_now_wh=>26.21, :charge_full_wh=>23.79, :charge_percentage=>100.0}, :hidpp_battery_0=>{:model=>"Wireless Keyboard", :manufacturer=>"Logitech", :type=>"Battery", :status=>"Discharging", :online=>1}}
180
+ #
181
+ # If you need info about lots of batteries, use this method.
182
+ # If the informations are not available, it will return empty Hash for each devices.
183
+ # If the system has no batteries, it will return an empty Hash.
184
+ def devices_stat
185
+ h = {}
186
+ Dir["/sys/class/power_supply/*/".freeze].tap(&:sort!).each do |x|
187
+ # model name
188
+ mn_file = File.join(x, 'model_name'.freeze).freeze
189
+ model_name = File.readable?(mn_file) ? IO.read(mn_file).strip : nil
190
+
191
+ # manufacturer
192
+ m_f = File.join(x, 'manufacturer'.freeze).freeze
193
+ manufacturer = File.readable?(m_f) ? IO.read(m_f).strip : nil
194
+
195
+ # type
196
+ t_f = File.join(x, 'type'.freeze).freeze
197
+ type = File.readable?(t_f) ? IO.read(t_f).strip : nil
198
+
199
+ # capacity
200
+ c_file = File.join(x, 'capacity'.freeze).freeze
201
+ capacity = File.readable?(c_file) ? IO.read(c_file).to_i : nil
202
+
203
+ # voltage now
204
+ vn_f = File.join(x, 'voltage_now'.freeze).freeze
205
+ voltage_now = File.readable?(vn_f) ? IO.read(vn_f).to_i.fdiv(1_000_000) : nil
206
+
207
+ # charge now
208
+ cn_f = File.join(x, 'charge_now'.freeze).freeze
209
+ charge_now = File.readable?(cn_f) ? IO.read(cn_f).to_i.fdiv(1_000_000) : nil
210
+
211
+ # voltage min design
212
+ vmd_f = File.join(x, 'voltage_min_design'.freeze).freeze
213
+ v_m_d = File.readable?(vmd_f) ? IO.read(vmd_f).to_i.fdiv(1_000_000) : nil
214
+
215
+ # charge full design
216
+ cfd_f = File.join(x, 'charge_full_design'.freeze).freeze
217
+ c_f_d = File.readable?(cfd_f) ? IO.read(cfd_f).to_i.fdiv(1_000_000) : nil
218
+
219
+ # charge full
220
+ cf_f = File.join(x, 'charge_full'.freeze).freeze
221
+ charge_full = File.readable?(cf_f) ? IO.read(cf_f).to_i.fdiv(1_000_000) : nil
222
+
223
+ # status
224
+ s_f = File.join(x, 'status'.freeze).freeze
225
+ status = File.readable?(s_f) ? IO.read(s_f).strip : nil
226
+
227
+ # online
228
+ o_f = File.join(x, 'online'.freeze).freeze
229
+ online = File.readable?(o_f) ? IO.read(o_f).to_i : nil
230
+
231
+ charge_percentage = if charge_now && charge_full
232
+ charge_now.*(100).fdiv(charge_full).round(2)
233
+ else
234
+ nil
235
+ end
236
+
237
+ # full_charge_design (WH)
238
+ c_f_d_wh = if c_f_d && v_m_d
239
+ v_m_d.*(c_f_d).round(2)
240
+ else
241
+ nil
242
+ end
243
+
244
+ c_n_wh = if voltage_now && charge_now
245
+ voltage_now.*(charge_now).round(2)
246
+ else
247
+ nil
248
+ end
249
+
250
+ c_f_wh = if v_m_d && charge_full
251
+ v_m_d.*(charge_full).round(2)
252
+ else
253
+ nil
254
+ end
255
+
256
+ ret = {}
257
+ ret[:model] = model_name if model_name
258
+ ret[:manufacturer] = manufacturer if manufacturer
259
+ ret[:type] = type if type
260
+
261
+ ret[:status] = status if status
262
+ ret[:online] = online if online
263
+ ret[:capacity] = capacity if capacity
264
+
265
+ ret[:voltage_min_design] = v_m_d if v_m_d
266
+ ret[:charge_full_design] = c_f_d if c_f_d
267
+ ret[:charge_full_design_wh] = c_f_d_wh if c_f_d_wh
268
+
269
+ ret[:voltage_now] = voltage_now if voltage_now
270
+ ret[:charge_now] = charge_now if charge_now
271
+
272
+ ret[:charge_now_wh] = c_n_wh if c_n_wh
273
+ ret[:charge_full_wh] = c_f_wh if c_f_wh
274
+ ret[:charge_percentage] = charge_percentage if charge_percentage
275
+
276
+ h.merge!(File.split(x)[-1].to_sym => ret)
277
+ end
278
+ h
112
279
  end
113
280
 
281
+ private
114
282
  def manufacturer_readable?
115
283
  @@manufacturer_readable ||= File.readable?(File.join(PATH, 'manufacturer'))
116
284
  end
@@ -122,11 +290,6 @@ module LinuxStat
122
290
  def status_readable?
123
291
  @@status_readable ||= File.readable?(File.join(PATH, 'status'))
124
292
  end
125
-
126
- def charge_now_readable?
127
- @@charge_now_readable ||= File.readable?(File.join(PATH, 'charge_now')) &&
128
- File.readable?(File.join(PATH, 'charge_full'))
129
- end
130
293
  end
131
294
  end
132
295
  end