svutil 0.9.4 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/svutil.rb +1 -1
- data/lib/svutil/config.rb +113 -106
- data/lib/svutil/process_manager.rb +1 -0
- data/test/test_config.rb +40 -39
- data/test/test_config_handle_options.rb +8 -7
- data/test/test_process_manager.rb +10 -16
- data/test/test_validations.rb +6 -7
- metadata +7 -7
data/lib/svutil.rb
CHANGED
data/lib/svutil/config.rb
CHANGED
@@ -4,9 +4,11 @@ require 'ostruct'
|
|
4
4
|
require 'pp'
|
5
5
|
|
6
6
|
module SVUtil
|
7
|
-
|
8
|
-
|
7
|
+
def self.config
|
8
|
+
Config.config_class
|
9
|
+
end
|
9
10
|
|
11
|
+
class Defaults
|
10
12
|
def initialize
|
11
13
|
@attrs = {}
|
12
14
|
end
|
@@ -24,39 +26,43 @@ module SVUtil
|
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
29
|
+
# TODO: We could make Config a module so that it cannot be instantiated (see http://dalibornasevic.com/posts/9-ruby-singleton-pattern-again)
|
27
30
|
class Config
|
28
|
-
|
29
|
-
|
31
|
+
|
32
|
+
class << self
|
33
|
+
attr_writer :config_file
|
34
|
+
attr_reader :attrs
|
35
|
+
attr_reader :defaults
|
36
|
+
# Used mainly for testing
|
37
|
+
attr_accessor :option_source
|
30
38
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
{}
|
39
|
+
attr_accessor :cli_options
|
40
|
+
attr_accessor :cli_option_handlers
|
41
|
+
|
42
|
+
def clear_all
|
43
|
+
@attrs = {}
|
37
44
|
end
|
38
|
-
end
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
def set(options = {})
|
47
|
+
@attrs ||= {}
|
48
|
+
if block_given?
|
49
|
+
yield self
|
50
|
+
end
|
51
|
+
self.validate
|
43
52
|
end
|
44
|
-
self.validate
|
45
|
-
end
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
54
|
+
def defaults(&block)
|
55
|
+
@defaults ||= Defaults.new
|
56
|
+
yield @defaults
|
57
|
+
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
attr_reader :validate_block
|
59
|
+
def config_file
|
60
|
+
@config_file ||= "settings"
|
61
|
+
end
|
55
62
|
|
56
|
-
def
|
57
|
-
@
|
58
|
-
|
59
|
-
return @defaults
|
63
|
+
def set_cli_option(option, value)
|
64
|
+
@cli_options ||= {}
|
65
|
+
@cli_options[option.to_s] = value
|
60
66
|
end
|
61
67
|
|
62
68
|
def handle_options(&block)
|
@@ -67,101 +73,102 @@ module SVUtil
|
|
67
73
|
def validator(&block)
|
68
74
|
@validate_block = block
|
69
75
|
end
|
70
|
-
end
|
71
76
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
err("PID file must be a writable file")
|
77
|
+
def validate
|
78
|
+
# TODO: Check file perms
|
79
|
+
if ((pid_file.nil? or pid_file.empty? or File.directory?(pid_file)) && self.daemon)
|
80
|
+
err("PID file must be a writable file")
|
81
|
+
end
|
82
|
+
# TODO: Validate the writability of the log file
|
83
|
+
@validate_block.call(self) unless @validate_block.nil?
|
84
|
+
true
|
81
85
|
end
|
82
|
-
# TODO: Validate the writability of the log file
|
83
|
-
self.instance_exec(self, &self.class.validate_block) unless self.class.validate_block.nil?
|
84
|
-
true
|
85
|
-
end
|
86
|
-
|
87
|
-
def init(test_options = nil)
|
88
|
-
set do |c|
|
89
|
-
self.config_provided_on_cli = false
|
90
|
-
OptionParser.new do |opts|
|
91
|
-
opts.on("-f", "--config [filename]", "Config file to use (default 'settings')") do |filename|
|
92
|
-
self.config_file = filename.strip
|
93
|
-
self.config_provided_on_cli = true
|
94
|
-
end
|
95
|
-
opts.on("-d", "--daemon", "Run in the background as a daemon") do
|
96
|
-
set_cli_option(:daemon, true)
|
97
|
-
end
|
98
|
-
opts.on("-l", "--debug-log [log-file]", "Debug Log File") do |log|
|
99
|
-
set_cli_option(:log_file, log)
|
100
|
-
end
|
101
|
-
opts.on("-T", "--trace", "Display backtrace on errors") do
|
102
|
-
set_cli_option(:trace, true)
|
103
|
-
end
|
104
|
-
opts.on("-P", "--pid [pid-file]", "PID File") do |pid|
|
105
|
-
set_cli_option(:pid_file, pid)
|
106
|
-
end
|
107
|
-
# Handle CLI passed options
|
108
|
-
(self.class.cli_option_handlers || []).each do |handler|
|
109
|
-
self.instance_exec(opts, &handler)
|
110
|
-
end
|
111
|
-
end.parse!(test_options || ARGV)
|
112
86
|
|
87
|
+
def init
|
88
|
+
set do |c|
|
89
|
+
self.config_provided_on_cli = false
|
90
|
+
OptionParser.new do |opts|
|
91
|
+
opts.on("-f", "--config [filename]", "Config file to use (default 'settings')") do |filename|
|
92
|
+
self.config_file = filename.strip
|
93
|
+
self.config_provided_on_cli = true
|
94
|
+
end
|
95
|
+
opts.on("-d", "--daemon", "Run in the background as a daemon") do
|
96
|
+
set_cli_option(:daemon, true)
|
97
|
+
end
|
98
|
+
opts.on("-l", "--debug-log [log-file]", "Debug Log File") do |log|
|
99
|
+
set_cli_option(:log_file, log)
|
100
|
+
end
|
101
|
+
opts.on("-T", "--trace", "Display backtrace on errors") do
|
102
|
+
set_cli_option(:trace, true)
|
103
|
+
end
|
104
|
+
opts.on("-P", "--pid [pid-file]", "PID File") do |pid|
|
105
|
+
set_cli_option(:pid_file, pid)
|
106
|
+
end
|
107
|
+
# Handle CLI passed options
|
108
|
+
(cli_option_handlers || []).each do |handler|
|
109
|
+
handler.call(opts)
|
110
|
+
end
|
111
|
+
end.parse!(self.option_source || ARGV)
|
113
112
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
113
|
+
# Process the config file
|
114
|
+
if (self.config_file && File.exists?(self.config_file)) || self.config_provided_on_cli
|
115
|
+
load_config_file
|
116
|
+
end
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
|
118
|
+
# Finally apply any CLI options
|
119
|
+
(cli_options || {}).each do |(k,v)|
|
120
|
+
c.send("#{k}=", v)
|
121
|
+
end
|
122
122
|
end
|
123
123
|
end
|
124
|
-
end
|
125
124
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
@attrs
|
130
|
-
|
131
|
-
|
125
|
+
private
|
126
|
+
def method_missing(method_id, *args)
|
127
|
+
@defaults ||= Defaults.new
|
128
|
+
@attrs ||= {}
|
129
|
+
if method_id.to_s =~ /=$/
|
130
|
+
@attrs[method_id.to_s[0...-1]] = args.first
|
131
|
+
else
|
132
|
+
value = @attrs[method_id.to_s]
|
133
|
+
if !value && @defaults
|
134
|
+
@defaults.default_for(method_id.to_s)
|
135
|
+
else
|
136
|
+
value
|
137
|
+
end
|
138
|
+
end
|
132
139
|
end
|
133
|
-
end
|
134
140
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
141
|
+
def load_config_file
|
142
|
+
contents = ""
|
143
|
+
File.open(config_file, "r") { |file| contents << file.read }
|
144
|
+
contents.split("\n").each_with_index do |line, index|
|
145
|
+
pair = line.split("=")
|
146
|
+
if pair.size != 2
|
147
|
+
err("Invalid config file '#{config_file}'. Syntax error at line #{index + 1}")
|
148
|
+
end
|
149
|
+
self.send("#{pair[0].strip}=", pair[1].strip)
|
142
150
|
end
|
143
|
-
self.send("#{pair[0].strip}=", pair[1].strip)
|
144
151
|
end
|
145
|
-
end
|
146
152
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
153
|
+
# TODO: This should be moved out to a Validator class
|
154
|
+
def err(message)
|
155
|
+
STDERR.puts(message)
|
156
|
+
exit 1
|
157
|
+
end
|
152
158
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
159
|
+
def subclasses_of(*superclasses) #:nodoc:
|
160
|
+
subclasses = []
|
161
|
+
superclasses.each do |sup|
|
162
|
+
ObjectSpace.each_object(Class) do |k|
|
163
|
+
if superclasses.any? { |superclass| k < superclass } &&
|
164
|
+
(k.name.nil? || k.name.empty? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
|
165
|
+
subclasses << k
|
166
|
+
end
|
160
167
|
end
|
168
|
+
subclasses.uniq!
|
161
169
|
end
|
162
|
-
subclasses
|
170
|
+
subclasses
|
163
171
|
end
|
164
|
-
|
165
|
-
end
|
172
|
+
end
|
166
173
|
end
|
167
174
|
end
|
data/test/test_config.rb
CHANGED
@@ -3,7 +3,6 @@ require File.expand_path(File.dirname(__FILE__) + '/test_helper.rb')
|
|
3
3
|
class CustomConfig < SVUtil::Config
|
4
4
|
defaults do |c|
|
5
5
|
c.foo = 'bar'
|
6
|
-
c.manager = 'daniel'
|
7
6
|
end
|
8
7
|
end
|
9
8
|
|
@@ -11,75 +10,77 @@ class TestConfig < Test::Unit::TestCase
|
|
11
10
|
include SVUtil
|
12
11
|
|
13
12
|
def setup
|
14
|
-
@custom_config = CustomConfig.new
|
15
13
|
end
|
16
14
|
|
17
15
|
def test_set
|
18
|
-
assert
|
19
|
-
|
20
|
-
assert_equal 'abc',
|
21
|
-
|
22
|
-
assert_equal 10,
|
16
|
+
assert !CustomConfig.my_symbol
|
17
|
+
CustomConfig.my_symbol = 'abc'
|
18
|
+
assert_equal 'abc', CustomConfig.my_symbol
|
19
|
+
CustomConfig.my_var = 10
|
20
|
+
assert_equal 10, CustomConfig.my_var
|
23
21
|
end
|
24
22
|
|
25
23
|
def test_set_with_block
|
26
|
-
|
27
|
-
|
24
|
+
CustomConfig.expects(:validate).times(1)
|
25
|
+
CustomConfig.set do |c|
|
28
26
|
c.another = 'abc'
|
29
27
|
c.some_var = 123
|
30
28
|
c.foobar = true
|
31
29
|
end
|
32
|
-
assert_equal 'abc',
|
33
|
-
assert_equal 123,
|
34
|
-
assert
|
30
|
+
assert_equal 'abc', CustomConfig.another
|
31
|
+
assert_equal 123, CustomConfig.some_var
|
32
|
+
assert CustomConfig.foobar
|
35
33
|
end
|
36
34
|
|
37
35
|
def test_standard_cli_options
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
assert_equal "
|
43
|
-
|
44
|
-
assert
|
45
|
-
assert @custom_config.trace
|
36
|
+
CustomConfig.expects(:validate).times(1)
|
37
|
+
CustomConfig.option_source = [ "-f", "test/settings", "-d", "-l", "debug", "-T" ]
|
38
|
+
CustomConfig.init
|
39
|
+
assert_equal "test/settings", CustomConfig.config_file
|
40
|
+
assert_equal "debug", CustomConfig.log_file
|
41
|
+
assert CustomConfig.daemon
|
42
|
+
assert CustomConfig.trace
|
46
43
|
end
|
47
44
|
|
48
45
|
def test_config_file
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
assert_equal 'bar',
|
46
|
+
CustomConfig.expects(:validate).times(1)
|
47
|
+
CustomConfig.config_file = "test/settings"
|
48
|
+
CustomConfig.init
|
49
|
+
assert_equal 'bar', CustomConfig.foo
|
53
50
|
end
|
54
51
|
|
55
52
|
def test_load_config_file
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
assert_equal 'bar',
|
53
|
+
CustomConfig.expects(:load_config_file).times(1)
|
54
|
+
CustomConfig.config_file = "test/settings"
|
55
|
+
CustomConfig.init
|
56
|
+
assert_equal 'bar', CustomConfig.foo
|
60
57
|
end
|
61
58
|
|
62
59
|
def test_validations_on_cli_with_no_config_file
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
CustomConfig.expects(:validate).times(1)
|
61
|
+
CustomConfig.config_file = nil
|
62
|
+
CustomConfig.init
|
66
63
|
end
|
67
64
|
|
68
65
|
# Command Line wins!
|
69
66
|
def test_file_overide
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
CustomConfig.expects(:validate).times(1)
|
68
|
+
CustomConfig.config_file = "test/settings"
|
69
|
+
CustomConfig.option_source = [ "-l", "logfile_set_on_cli" ]
|
70
|
+
CustomConfig.init
|
71
|
+
assert_equal "logfile_set_on_cli", CustomConfig.log_file
|
74
72
|
end
|
75
73
|
|
76
74
|
def test_defaults
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
CustomConfig.defaults do |c|
|
76
|
+
c.manager = 'daniel'
|
77
|
+
end
|
78
|
+
assert_equal 'daniel', CustomConfig.manager
|
79
|
+
CustomConfig.manager = 'james'
|
80
|
+
assert_equal 'james', CustomConfig.manager
|
80
81
|
end
|
81
82
|
|
82
83
|
def test_custom_defaults
|
83
|
-
assert_equal 'bar',
|
84
|
+
assert_equal 'bar', CustomConfig.foo
|
84
85
|
end
|
85
86
|
end
|
@@ -15,18 +15,19 @@ class TestConfigHandleOptions < Test::Unit::TestCase
|
|
15
15
|
include SVUtil
|
16
16
|
|
17
17
|
def setup
|
18
|
-
@my_config = MyConfig.new
|
19
18
|
end
|
20
19
|
|
21
20
|
def test_handle_options
|
22
|
-
|
23
|
-
|
24
|
-
assert
|
25
|
-
assert
|
21
|
+
MyConfig.option_source = [ "-P", "foo", "-x", "12345", "-Q" ]
|
22
|
+
MyConfig.init
|
23
|
+
assert MyConfig.pid_file = "foo"
|
24
|
+
assert MyConfig.x = '1234'
|
25
|
+
assert MyConfig.restless
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_built_in_options
|
29
|
-
|
30
|
-
|
29
|
+
MyConfig.option_source = [ "-d", "-P", "foo" ]
|
30
|
+
MyConfig.init
|
31
|
+
assert MyConfig.daemon
|
31
32
|
end
|
32
33
|
end
|
@@ -13,25 +13,23 @@ class TestProcesManager < Test::Unit::TestCase
|
|
13
13
|
@klass = mock
|
14
14
|
@klass.stubs(:new).returns(@instance)
|
15
15
|
@klass.stubs(:instance_of?).with(Class).returns(true)
|
16
|
+
ServerConfig.clear_all
|
16
17
|
end
|
17
18
|
|
18
19
|
def test_initialize
|
19
|
-
|
20
|
-
ProcessManager.new(@klass, config)
|
20
|
+
ProcessManager.new(@klass, ServerConfig)
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_initialize_and_start_with_server_instance
|
24
|
-
|
25
|
-
pm = ProcessManager.new(@instance, config)
|
24
|
+
pm = ProcessManager.new(@instance, ServerConfig)
|
26
25
|
@instance.expects(:run)
|
27
26
|
assert_exit { pm.start }
|
28
27
|
end
|
29
28
|
|
30
29
|
# TODO: Could probably test this better by actually forking
|
31
30
|
def test_start_as_daemon
|
32
|
-
|
33
|
-
|
34
|
-
pm = ProcessManager.new(@klass, config)
|
31
|
+
ServerConfig.daemon = true
|
32
|
+
pm = ProcessManager.new(@klass, ServerConfig)
|
35
33
|
pm.expects(:daemonize)
|
36
34
|
pm.expects(:write_pid_file)
|
37
35
|
pm.expects(:shutdown)
|
@@ -40,9 +38,8 @@ class TestProcesManager < Test::Unit::TestCase
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def test_start_with_trace
|
43
|
-
|
44
|
-
|
45
|
-
pm = ProcessManager.new(@klass, config)
|
41
|
+
ServerConfig.trace = true
|
42
|
+
pm = ProcessManager.new(@klass, ServerConfig)
|
46
43
|
pm.expects(:write_pid_file)
|
47
44
|
@instance.expects(:run).raises(Exception)
|
48
45
|
Log.expects(:error).times(2)
|
@@ -50,8 +47,7 @@ class TestProcesManager < Test::Unit::TestCase
|
|
50
47
|
end
|
51
48
|
|
52
49
|
def test_shutdown
|
53
|
-
|
54
|
-
pm = ProcessManager.new(@klass, config)
|
50
|
+
pm = ProcessManager.new(@klass, ServerConfig)
|
55
51
|
pm.expects(:write_pid_file)
|
56
52
|
@instance.expects(:run)
|
57
53
|
assert_exit { pm.start }
|
@@ -63,9 +59,8 @@ class TestProcesManager < Test::Unit::TestCase
|
|
63
59
|
end
|
64
60
|
|
65
61
|
def test_shutdown_with_trace
|
66
|
-
|
67
|
-
|
68
|
-
pm = ProcessManager.new(@klass, config)
|
62
|
+
ServerConfig.trace = true
|
63
|
+
pm = ProcessManager.new(@klass, ServerConfig)
|
69
64
|
pm.expects(:write_pid_file)
|
70
65
|
@instance.expects(:run)
|
71
66
|
assert_exit { pm.start }
|
@@ -77,6 +72,5 @@ class TestProcesManager < Test::Unit::TestCase
|
|
77
72
|
assert_exit { pm.send(:shutdown) }
|
78
73
|
end
|
79
74
|
|
80
|
-
|
81
75
|
# TODO: Test all of the exceptions
|
82
76
|
end
|
data/test/test_validations.rb
CHANGED
@@ -10,18 +10,17 @@ class TestValidations < Test::Unit::TestCase
|
|
10
10
|
include SVUtil
|
11
11
|
|
12
12
|
def setup
|
13
|
-
@validated_config = ValidatedConfig.new
|
14
13
|
end
|
15
14
|
|
16
15
|
def test_custom_validation_error
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
ValidatedConfig.expects(:err).times(1)
|
17
|
+
ValidatedConfig.output_dir = nil
|
18
|
+
ValidatedConfig.validate
|
20
19
|
end
|
21
20
|
|
22
21
|
def test_custom_validation
|
23
|
-
|
24
|
-
|
25
|
-
assert
|
22
|
+
ValidatedConfig.expects(:err).never
|
23
|
+
ValidatedConfig.output_dir = "foo"
|
24
|
+
assert ValidatedConfig.validate
|
26
25
|
end
|
27
26
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svutil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-01-04 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: newgem
|
16
|
-
requirement: &
|
16
|
+
requirement: &70183734200680 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.5.3
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70183734200680
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: hoe
|
27
|
-
requirement: &
|
27
|
+
requirement: &70183734199780 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '2.12'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70183734199780
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rdoc
|
38
|
-
requirement: &
|
38
|
+
requirement: &70183729865820 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '3.10'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70183729865820
|
47
47
|
description: A simple managed process builder for Ruby projects
|
48
48
|
email:
|
49
49
|
- daniel@netfox.com
|