helper_classes 0.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2cc2efbfcfed05e72c9003554b4a7e3c344f925
4
+ data.tar.gz: 3426825c61f9d9b782dc46d507c20bca84164f43
5
+ SHA512:
6
+ metadata.gz: b19fbe9429c4097b68464cdfc05ec33bb91d9da52ebc6ae04236e88359bb33c11caa85ff9af718260df64f2f940ddf127df56ae39da1ee3adea1cbcfb8dfee45
7
+ data.tar.gz: 3d71d53497721d7e8fdeb724707d81d8363a3feaceb7db61db57aae6a28e47317214b6cec7a7bd68867062aa429d593f9b1215c465e4dc9105243e45b043e45c
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ /nbproject
3
+ .hg*
4
+ .idea
5
+ commit
6
+ .DS_Store
7
+ test/test_config
data/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ == HelperClasses
2
+
3
+ GPLv3 or any later version
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ == HelperClasses
2
+
3
+ Some simple classes to help in everyday tasks
4
+
5
+ === DPuts
6
+
7
+ Ever wanted to have detailed debug-output, but in the end even PRODUCING the
8
+ string without printing it was too long? Here comes DPuts! It let's you define
9
+ different debug-levels and the strings are only evaluated if they're about
10
+ to be printed! Great for that 10MB-dump that you only want for debugging...
11
+
12
+ Usage:
13
+
14
+ ```
15
+ include HelperClasses::DPuts
16
+
17
+ DEBUG_LVL = 5
18
+ dputs(5){ "String with some #{huge_db.inspect}" }
19
+ ```
20
+
21
+ This will evaluate and print the ```huge_db``` variable, while
22
+
23
+ ```
24
+ include HelperClasses::DPuts
25
+
26
+ DEBUG_LVL = 4
27
+ dputs(5){ "String with some #{huge_db.inspect}" }
28
+ ```
29
+
30
+ will NOT evaluate it! The debug-levels are arbitrarily chosen like this:
31
+
32
+ 0 - Errors
33
+ 1 - Info and warnings, important
34
+ 2 - Often used debug-messages - limit of production-use
35
+ 3 - More detailed debugging
36
+ 4
37
+ 5 - Dumping lots of raw data
38
+
39
+ ==== Fine-grained debugging
40
+
41
+ If you have a function with lots of _dputs_ in it, and you'd like to output
42
+ all debugging messages just from that function, you simply add
43
+
44
+ ```
45
+ dputs_func
46
+ ```
47
+
48
+ at the beginning of your function.
49
+
50
+ If you want just one specific _dputs_ to be evaluated, just change its name to
51
+ _ddputs_:
52
+
53
+ ```
54
+ DEBUG_LVL = 0
55
+
56
+ ddputs(5){"String with lots of data#{huge_var.inspect}"}
57
+ ```
58
+
59
+ will be evaluated!
60
+
61
+ === Arraysym
62
+
63
+ to_sym and to_sym! - calls .to_sym on all elements. Usage:
64
+
65
+ ```
66
+ using HelperClasses::ArraySym
67
+
68
+ p [ "a", "b" ].to_sym
69
+ ```
70
+
71
+ Produces "[ :a, :b ]"
72
+
73
+ === HashAccessor
74
+
75
+ This should be standard ruby. Access all elements of an array by
76
+ prepending a "_".
77
+
78
+ ==== Getting a value
79
+
80
+ ```
81
+ using HelperClasses::HashAccessor
82
+
83
+ p { :a => 2, "a" => 3 }._a
84
+ ```
85
+
86
+ Will print "2". So symbols have precedence over string-keys.
87
+
88
+ ==== Setting a value
89
+
90
+ ```
91
+ using HelperClasses::HashAccessor
92
+
93
+ a = { :a => 2, "a" => 3 }
94
+ a._a = 4
95
+ a._b = 5
96
+
97
+ p a
98
+ ```
99
+
100
+ Will print ```{ :a => 4, "a" => 3, :b => "5" }```
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'helper_classes'
3
+ s.version = '0.2.1'
4
+ s.date = '2015-05-12'
5
+ s.summary = 'Hash._accessor Array.to_sym and DPuts'
6
+ s.description = 'Added accessors to Hash, to_sym to Array and a nice debugging-interface called DPuts'
7
+ s.authors = ['Linus Gasser']
8
+ s.email = 'ineiti@linusetviviane.ch'
9
+
10
+ s.files = `git ls-files -z`.split("\x0")
11
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
12
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
13
+ s.require_paths = ['lib']
14
+
15
+ s.homepage =
16
+ 'https://github.com/ineiti/HelperClasses'
17
+ s.license = 'GPLv3'
18
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module HelperClasses
3
+ module ArraySym
4
+ class Array
5
+ # Comptaibility for Ruby <= 2.0
6
+ if ![].respond_to? :to_h
7
+ def to_h
8
+ Hash[*self.flatten]
9
+ end
10
+ end
11
+
12
+ def to_sym
13
+ collect{|v| v.to_sym }
14
+ end
15
+
16
+ def to_sym!
17
+ self.replace( to_sym() )
18
+ end
19
+
20
+ def to_s
21
+ "[#{join(",")}]"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,111 @@
1
+ module HelperClasses
2
+ require 'thread'
3
+ require 'singleton'
4
+
5
+ module DPuts
6
+ extend self
7
+ attr_accessor :mutex, :silent, :show_time, :terminal_width, :log_file
8
+
9
+ @mutex = Mutex.new
10
+ @silent = false
11
+ @show_time = false
12
+ @terminal_width = 160
13
+ @log_file = false
14
+
15
+ def dputs_out(n, s, call)
16
+ return if DPuts.silent
17
+ if precision = DPuts.show_time
18
+ $dputs_time ||= Time.now - 120
19
+ now = Time.now
20
+ show = false
21
+ case precision
22
+ when /sec/
23
+ show = now.to_i != $dputs_time.to_i
24
+ when /min/
25
+ show = (now.to_i / 60).floor != ($dputs_time.to_i / 60).floor
26
+ when /hour/
27
+ show = (now.to_i / 3600).floor != ($dputs_time.to_i / 3600).floor
28
+ end
29
+ if show
30
+ puts "\n *** It is now: " +
31
+ Time.now.strftime('%Y-%m-%d %H:%M:%S')
32
+ $dputs_time = now
33
+ end
34
+ end
35
+ DPuts.mutex.synchronize do
36
+ width = DPuts.terminal_width.to_i || 160
37
+ width = [width - 30.0, 10].max
38
+ file, func = call.split(' ')
39
+ file = file[/^.*\/([^.]*)/, 1]
40
+ who = (':' + n.to_s + ':' + file.to_s +
41
+ func.to_s).ljust(30, ['X', 'x', '*', '-', '.', ' '][n])
42
+ lines = []
43
+ pos = 0
44
+ while (pos < s.length)
45
+ len = width
46
+ if s.length - pos > width
47
+ len = s.rindex(/[, .;=&>]/, pos + width)
48
+ len = len ? len - pos + 1 : width
49
+ if len < width / 2
50
+ len = width
51
+ end
52
+ end
53
+ lines.push s.slice(pos, len)
54
+ pos += len
55
+ end
56
+ puts who + ' ' + lines.shift.to_s
57
+ lines.each { |l|
58
+ puts ' ' * (32) + l
59
+ }
60
+ end
61
+ end
62
+
63
+
64
+ def dputs_getcaller
65
+ caller(0)[2].sub(/:.*:in/, '').sub(/block .*in /, '')
66
+ end
67
+
68
+ def dputs_func
69
+ $DPUTS_FUNCS ||= []
70
+ $DPUTS_FUNCS.push(dputs_getcaller) unless $DPUTS_FUNCS.index(dputs_getcaller)
71
+ end
72
+
73
+ def dputs_unfunc
74
+ $DPUTS_FUNCS ||= []
75
+ $DPUTS_FUNCS.index(dputs_getcaller) and $DPUTS_FUNCS.delete(dputs_getcaller)
76
+ end
77
+
78
+ def dputs(n, &s)
79
+ n *= -1 if ($DPUTS_FUNCS and $DPUTS_FUNCS.index(dputs_getcaller))
80
+ if !self.class.const_defined?(:DEBUG_LVL) or
81
+ self.class.const_get(:DEBUG_LVL) >= n
82
+ s = yield s
83
+ dputs_out(n, s, caller(0)[1])
84
+ end
85
+ end
86
+
87
+ def ddputs(n, &s)
88
+ s = yield s
89
+ #dp caller(0)
90
+ dputs_out(-n, s, caller(0)[1])
91
+ end
92
+
93
+ def dp(s)
94
+ dputs_out(0, s.class == String ? s : s.inspect, caller(0)[1])
95
+ s
96
+ end
97
+
98
+ def log_msg(mod, msg)
99
+ dputs(1) { "Info from #{mod}: #{msg}" }
100
+ return if not DPuts.log_file
101
+ File.open(DPuts.log_file, 'a') { |f|
102
+ str = Time.now.strftime("%a %y.%m.%d-%H:%M:%S #{mod}: #{msg}")
103
+ f.puts str
104
+ }
105
+ end
106
+
107
+ def dlog_msg(mod, msg)
108
+ ddputs(1){"Info from #{mod}: #{msg}"}
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,44 @@
1
+ module HelperClasses
2
+ module HashAccessor
3
+ refine Hash do
4
+ end
5
+ end
6
+ end
7
+
8
+ class Hash
9
+ # Converts all keys of a hash to syms recursively
10
+ def to_sym
11
+ ret = {}
12
+ each { |k, v|
13
+ ret[k.to_sym] = v.class == Hash ? v.to_sym : v
14
+ }
15
+ ret
16
+ end
17
+
18
+ def to_sym!
19
+ self.replace(to_sym())
20
+ end
21
+
22
+ def method_missing(s, *args)
23
+ case s.to_s
24
+ when "to_ary"
25
+ super(s, args)
26
+ when /^_.*[^=]$/
27
+ key = s.to_s.sub(/^_{1,2}/, '').to_sym
28
+ self.has_key? key and return self[key]
29
+ self.has_key? key.to_s and return self[key.to_s]
30
+ if s.to_s =~ /^__/
31
+ return self[key] = {}
32
+ else
33
+ return nil
34
+ end
35
+ when /^_.*=$/
36
+ key = /^_{1,2}(.*)=$/.match(s.to_s)[1].to_sym
37
+ self.has_key? key and return self[key] = args[0]
38
+ self.has_key? key.to_s and return self[key.to_s] = args[0]
39
+ return self[key] = args[0]
40
+ else
41
+ super(s, args)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ module HelperClasses
2
+ module ReadConfig
3
+ extend self
4
+
5
+ # Searches in this order:
6
+ # ~/.config
7
+ # ~
8
+ # /etc
9
+ #
10
+ # Returns nil if nothing found
11
+ def file_name(file)
12
+ %w( ~/.config ~ /etc ).each { |d|
13
+ file_abs = File.expand_path("#{d}/#{file}")
14
+ File.exists?(file_abs) and return file_abs
15
+ }
16
+ nil
17
+ end
18
+
19
+ # Very simple bash-reader, doesn't do array or multi-line configurations
20
+ def bash(file, downcase = false)
21
+ return nil unless File.exists? file
22
+ IO.readlines(file).collect { |l|
23
+ if l =~ /^#/
24
+ nil
25
+ elsif l =~ /([^ ]+)=(.*)/
26
+ [(downcase ? $1.downcase : $1).to_sym, $2]
27
+ end
28
+ }.compact.to_h
29
+ end
30
+
31
+ # Ruby file-reader, returns created hash
32
+ # THIS IS ABSOLUTELY INSECURE AND WILL EAT YOUR KITTENS!
33
+ # It returns what the file returns at the end - so most probably you'll want
34
+ # something like
35
+ #
36
+ # { one: 1,
37
+ # two: 2 }
38
+ #
39
+ # in that config-file
40
+ def ruby(file)
41
+ return {} unless File.exists? file.to_s
42
+ return eval(IO.readlines(file).join)
43
+ end
44
+
45
+ def json(file)
46
+ p 'Not implemented yet'
47
+ exit
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,104 @@
1
+ require 'helperclasses/dputs'
2
+ require 'helperclasses/system'
3
+
4
+ module HelperClasses
5
+ module Service
6
+ attr_accessor :system, :services
7
+
8
+ extend self
9
+ extend HelperClasses::DPuts
10
+ @system = case System.run_str 'uname -a'
11
+ when /ARCH/
12
+ :ArchLinux
13
+ when /Ubuntu/
14
+ :Ubuntu
15
+ when /Darwin/
16
+ :MacOSX
17
+ else
18
+ nil
19
+ end
20
+
21
+ @services = {
22
+ samba: {ArchLinux: %w( smbd nmbd ), Ubuntu: %w(smbd nmbd)},
23
+ cups: {ArchLinux: 'org.cups.cupsd', Ubuntu: 'cupsd'}
24
+ }
25
+
26
+ def service_get(service)
27
+ begin
28
+ @services[service.to_sym][@system]
29
+ rescue NoMethodError => _e
30
+ service.to_s
31
+ end
32
+ end
33
+
34
+ def service_run(service, cmd)
35
+ return unless @system
36
+ if !cmd
37
+ log_msg :Services, "System #{@system} can't start services"
38
+ return false
39
+ end
40
+ service_name = service_get(service)
41
+ if !service_name
42
+ log_msg :Services, "System #{@system} doesn't have service #{service}"
43
+ return false
44
+ end
45
+ cmd_system = cmd[@system]
46
+ if !cmd_system
47
+ log_msg :Services, "System #{@system} doesn't know how to do #{cmd}"
48
+ return false
49
+ end
50
+ [service_name].flatten.each { |s|
51
+ c = cmd_system.sub(/##/, s)
52
+ if !System.run_bool(c)
53
+ log_msg :Services, "Command #{c} failed"
54
+ return false
55
+ end
56
+ }
57
+ end
58
+
59
+ def start(service)
60
+ service_run(service, {ArchLinux: 'systemctl start ##',
61
+ Ubuntu: '/etc/init.d/## start',
62
+ MacOSX: nil}
63
+ )
64
+ end
65
+
66
+ def stop(service)
67
+ service_run(service, {ArchLinux: 'systemctl stop ##',
68
+ Ubuntu: '/etc/init.d/## stop',
69
+ MacOSX: nil}
70
+ )
71
+ end
72
+
73
+ def restart(service)
74
+ service_run(service, {ArchLinux: 'systemctl restart ##',
75
+ Ubuntu: '/etc/init.d/## restart',
76
+ MacOSX: nil}
77
+ )
78
+ end
79
+
80
+ def enable(service)
81
+ service_run(service, {ArchLinux: 'systemctl enable ##',
82
+ Ubuntu: nil,
83
+ MacOSX: nil}
84
+ )
85
+ end
86
+
87
+ def disable(service)
88
+ service_run(service, {ArchLinux: 'systemctl disable ##',
89
+ Ubuntu: nil,
90
+ MacOSX: nil}
91
+ )
92
+ end
93
+
94
+ def enable_start(service)
95
+ enable(service)
96
+ start(service)
97
+ end
98
+
99
+ def stop_disable(service)
100
+ disable(service)
101
+ stop(service)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,53 @@
1
+ # System-interaction for different flavours of Unix
2
+ require 'helperclasses/dputs'
3
+
4
+ module HelperClasses
5
+ module System
6
+ extend self
7
+ extend HelperClasses::DPuts
8
+ include HelperClasses::DPuts
9
+
10
+ def run_str(cmd)
11
+ dputs(3) { "Running command --#{cmd}--" }
12
+ %x[ #{cmd} ]
13
+ end
14
+
15
+ def run_bool(cmd)
16
+ dputs(3) { "Running command --#{cmd}--" }
17
+ Kernel.system("#{cmd} > /dev/null 2>&1")
18
+ end
19
+
20
+ def exists?(cmd)
21
+ dputs(3) { "Exist command --#{cmd}--?" }
22
+ run_bool("which #{cmd} > /dev/null 2>&1")
23
+ end
24
+
25
+ def rescue_all(msg = 'Error')
26
+ begin
27
+ yield
28
+ rescue Exception => e
29
+ dputs(0) { "#{Time.now.strftime('%a %y.%m.%d-%H:%M:%S')} - #{msg}" }
30
+ dputs(0) { "#{e.inspect}" }
31
+ dputs(0) { "#{e.to_s}" }
32
+ e.backtrace.each { |l| dputs(0) { l } }
33
+ end
34
+ end
35
+
36
+ def iptables(*args)
37
+ if !@iptables_cmd
38
+ if System.exists?('iptables')
39
+ @iptables_cmd = 'iptables'
40
+ @iptables_wait = (System.run_str('iptables --help') =~ /\s-w\s/) ? '-w' : ''
41
+ else
42
+ @iptables_cmd = ''
43
+ end
44
+ end
45
+
46
+ if @iptables_cmd != ''
47
+ System.run_str("#{@iptables_cmd} #{@iptables_wait} #{args.join(' ')}")
48
+ else
49
+ return ''
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ module HelperClasses
2
+ class Timing
3
+ def initialize(dbg = 0)
4
+ @dbg_lvl = dbg
5
+ @time = Time.now
6
+ end
7
+
8
+ def probe(msg = '')
9
+ t = sprintf('%6f', (Time.now - @time).to_f)
10
+ dputs(@dbg_lvl) { "#{msg}: #{t}" }
11
+ @time = Time.now
12
+ end
13
+
14
+ def self.measure(msg = '', dbg = 0)
15
+ t = Timing.new(dbg)
16
+ ret = yield
17
+ t.probe(msg)
18
+ ret
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'helperclasses/arraysym'
2
+ require 'helperclasses/dputs'
3
+ require 'helperclasses/hashaccessor'
4
+ require 'helperclasses/readconfig'
5
+ require 'helperclasses/service'
6
+ require 'helperclasses/system'
7
+ require 'helperclasses/timing'
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ class TC_Service < Test::Unit::TestCase
5
+
6
+ def setup
7
+ end
8
+
9
+ def test_service_get
10
+ Service.system = :ArchLinux
11
+
12
+ assert_equal %w(smbd nmbd), Service.service_get(:samba)
13
+ assert_equal 'dnsmasq', Service.service_get(:dnsmasq)
14
+ end
15
+ end
data/test/test.rb ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.push '../lib', '.'
3
+
4
+ require 'test/unit'
5
+ require 'helperclasses'
6
+ include HelperClasses
7
+
8
+ tests = Dir.glob( 'hc_*.rb' )
9
+ #tests = %w( )
10
+
11
+ tests.each{|t|
12
+ begin
13
+ require "hc_#{t}"
14
+ rescue LoadError => e
15
+ require t
16
+ end
17
+ }
@@ -0,0 +1,5 @@
1
+ require 'helperclasses/arraysym'
2
+
3
+ using HelperClasses::ArraySym
4
+
5
+ p ["a", "b"].to_sym
@@ -0,0 +1,12 @@
1
+ require "helperclasses/dputs"
2
+
3
+ DEBUG_LVL = 5
4
+
5
+ include HelperClasses
6
+
7
+ DPuts.dputs(5){"Hello"}
8
+
9
+ include DPuts
10
+
11
+ dputs( 5 ){"Hello there"}
12
+
@@ -0,0 +1,9 @@
1
+ require 'helperclasses/hashaccessor'
2
+
3
+ using HelperClasses::HashAccessor
4
+
5
+ a = { :a => 3, "b" => 4 }
6
+
7
+ p a.to_sym
8
+ p a._a
9
+ p a._b
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.push('../lib')
4
+ require 'helperclasses/readconfig'
5
+
6
+ include HelperClasses
7
+
8
+ testfile = 'test_config'
9
+ IO.write(testfile, "#!/bin/bash
10
+ # This is an example config
11
+ TEST=hi
12
+ DB=foo.db
13
+ # This shouldn't pass
14
+ TEST2 = hi
15
+ # And some unrelated stuff
16
+ if '$1'; then
17
+ fi
18
+ ")
19
+
20
+ test = ReadConfig.bash( testfile )
21
+ p test
22
+
23
+ def printit
24
+ p test
25
+ end
26
+
27
+ printit
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.push '../lib'
4
+
5
+ require 'helperclasses/system'
6
+ include HelperClasses::System
7
+
8
+ rescue_all do
9
+ puts 'Hello there'
10
+ end
11
+ puts
12
+
13
+ rescue_all do
14
+ puts "Some math: #{10/0}"
15
+ end
16
+ puts
17
+
18
+ rescue_all('math-error') do
19
+ puts "Some math: #{10/0}"
20
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: helper_classes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Linus Gasser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Added accessors to Hash, to_sym to Array and a nice debugging-interface
14
+ called DPuts
15
+ email: ineiti@linusetviviane.ch
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - LICENSE
22
+ - README.md
23
+ - helper_classes.gemspec
24
+ - lib/helperclasses.rb
25
+ - lib/helperclasses/arraysym.rb
26
+ - lib/helperclasses/dputs.rb
27
+ - lib/helperclasses/hashaccessor.rb
28
+ - lib/helperclasses/readconfig.rb
29
+ - lib/helperclasses/service.rb
30
+ - lib/helperclasses/system.rb
31
+ - lib/helperclasses/timing.rb
32
+ - test/hc_service.rb
33
+ - test/test.rb
34
+ - test/test_arraysym.rb
35
+ - test/test_dputs.rb
36
+ - test/test_hashaccessor.rb
37
+ - test/test_readconfig.rb
38
+ - test/test_system.rb
39
+ homepage: https://github.com/ineiti/HelperClasses
40
+ licenses:
41
+ - GPLv3
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.2.2
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Hash._accessor Array.to_sym and DPuts
63
+ test_files:
64
+ - test/hc_service.rb
65
+ - test/test.rb
66
+ - test/test_arraysym.rb
67
+ - test/test_dputs.rb
68
+ - test/test_hashaccessor.rb
69
+ - test/test_readconfig.rb
70
+ - test/test_system.rb