guard 1.4.0 → 2.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -677
- data/LICENSE +4 -2
- data/README.md +91 -753
- data/bin/_guard-core +11 -0
- data/bin/guard +108 -3
- data/lib/guard/aruba_adapter.rb +59 -0
- data/lib/guard/cli/environments/bundler.rb +22 -0
- data/lib/guard/cli/environments/evaluate_only.rb +35 -0
- data/lib/guard/cli/environments/valid.rb +69 -0
- data/lib/guard/cli.rb +129 -128
- data/lib/guard/commander.rb +104 -0
- data/lib/guard/commands/all.rb +37 -0
- data/lib/guard/commands/change.rb +31 -0
- data/lib/guard/commands/notification.rb +26 -0
- data/lib/guard/commands/pause.rb +29 -0
- data/lib/guard/commands/reload.rb +36 -0
- data/lib/guard/commands/scope.rb +38 -0
- data/lib/guard/commands/show.rb +24 -0
- data/lib/guard/config.rb +18 -0
- data/lib/guard/deprecated/dsl.rb +45 -0
- data/lib/guard/deprecated/evaluator.rb +39 -0
- data/lib/guard/deprecated/guard.rb +328 -0
- data/lib/guard/deprecated/guardfile.rb +84 -0
- data/lib/guard/deprecated/watcher.rb +27 -0
- data/lib/guard/dsl.rb +332 -363
- data/lib/guard/dsl_describer.rb +132 -122
- data/lib/guard/dsl_reader.rb +51 -0
- data/lib/guard/group.rb +34 -14
- data/lib/guard/guardfile/evaluator.rb +232 -0
- data/lib/guard/guardfile/generator.rb +128 -0
- data/lib/guard/guardfile.rb +24 -60
- data/lib/guard/interactor.rb +31 -255
- data/lib/guard/internals/debugging.rb +68 -0
- data/lib/guard/internals/groups.rb +40 -0
- data/lib/guard/internals/helpers.rb +13 -0
- data/lib/guard/internals/plugins.rb +53 -0
- data/lib/guard/internals/queue.rb +51 -0
- data/lib/guard/internals/scope.rb +121 -0
- data/lib/guard/internals/session.rb +180 -0
- data/lib/guard/internals/state.rb +25 -0
- data/lib/guard/internals/tracing.rb +33 -0
- data/lib/guard/internals/traps.rb +10 -0
- data/lib/guard/jobs/base.rb +21 -0
- data/lib/guard/jobs/pry_wrapper.rb +336 -0
- data/lib/guard/jobs/sleep.rb +26 -0
- data/lib/guard/notifier.rb +46 -212
- data/lib/guard/options.rb +22 -0
- data/lib/guard/plugin.rb +303 -0
- data/lib/guard/plugin_util.rb +191 -0
- data/lib/guard/rake_task.rb +42 -0
- data/lib/guard/runner.rb +80 -140
- data/lib/guard/templates/Guardfile +14 -0
- data/lib/guard/terminal.rb +13 -0
- data/lib/guard/ui/colors.rb +56 -0
- data/lib/guard/ui/config.rb +70 -0
- data/lib/guard/ui/logger.rb +30 -0
- data/lib/guard/ui.rb +163 -128
- data/lib/guard/version.rb +1 -2
- data/lib/guard/watcher/pattern/deprecated_regexp.rb +45 -0
- data/lib/guard/watcher/pattern/match_result.rb +18 -0
- data/lib/guard/watcher/pattern/matcher.rb +33 -0
- data/lib/guard/watcher/pattern/pathname_path.rb +15 -0
- data/lib/guard/watcher/pattern/simple_path.rb +23 -0
- data/lib/guard/watcher/pattern.rb +24 -0
- data/lib/guard/watcher.rb +52 -95
- data/lib/guard.rb +108 -376
- data/lib/tasks/releaser.rb +116 -0
- data/man/guard.1 +12 -9
- data/man/guard.1.html +18 -12
- metadata +148 -77
- data/images/guard.png +0 -0
- data/lib/guard/guard.rb +0 -156
- data/lib/guard/hook.rb +0 -120
- data/lib/guard/interactors/coolline.rb +0 -64
- data/lib/guard/interactors/helpers/completion.rb +0 -32
- data/lib/guard/interactors/helpers/terminal.rb +0 -46
- data/lib/guard/interactors/readline.rb +0 -94
- data/lib/guard/interactors/simple.rb +0 -19
- data/lib/guard/notifiers/emacs.rb +0 -69
- data/lib/guard/notifiers/gntp.rb +0 -118
- data/lib/guard/notifiers/growl.rb +0 -99
- data/lib/guard/notifiers/growl_notify.rb +0 -92
- data/lib/guard/notifiers/libnotify.rb +0 -96
- data/lib/guard/notifiers/notifysend.rb +0 -84
- data/lib/guard/notifiers/rb_notifu.rb +0 -102
- data/lib/guard/notifiers/terminal_notifier.rb +0 -66
- data/lib/guard/notifiers/tmux.rb +0 -69
- data/lib/guard/version.rbc +0 -130
@@ -0,0 +1,53 @@
|
|
1
|
+
require "guard/plugin_util"
|
2
|
+
require "guard/group"
|
3
|
+
require "guard/plugin"
|
4
|
+
|
5
|
+
module Guard
|
6
|
+
# @private api
|
7
|
+
module Internals
|
8
|
+
class Plugins
|
9
|
+
def initialize
|
10
|
+
@plugins = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def all(filter = nil)
|
14
|
+
return @plugins if filter.nil?
|
15
|
+
matcher = matcher_for(filter)
|
16
|
+
@plugins.select { |plugin| matcher.call(plugin) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove(plugin)
|
20
|
+
@plugins.delete(plugin)
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: should it allow duplicates? (probably yes because of different
|
24
|
+
# configs or groups)
|
25
|
+
def add(name, options)
|
26
|
+
@plugins << PluginUtil.new(name).initialize_plugin(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def matcher_for(filter)
|
32
|
+
case filter
|
33
|
+
when String, Symbol
|
34
|
+
shortname = filter.to_s.downcase.delete("-")
|
35
|
+
->(plugin) { plugin.name == shortname }
|
36
|
+
when Regexp
|
37
|
+
->(plugin) { plugin.name =~ filter }
|
38
|
+
when Hash
|
39
|
+
lambda do |plugin|
|
40
|
+
filter.all? do |k, v|
|
41
|
+
case k
|
42
|
+
when :name
|
43
|
+
plugin.name == v.to_s.downcase.delete("-")
|
44
|
+
when :group
|
45
|
+
plugin.group.name == v.to_sym
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Guard
|
2
|
+
module Internals
|
3
|
+
class Queue
|
4
|
+
def initialize(commander)
|
5
|
+
@commander = commander
|
6
|
+
@queue = ::Queue.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# Process the change queue, running tasks within the main Guard thread
|
10
|
+
def process
|
11
|
+
actions = []
|
12
|
+
changes = { modified: [], added: [], removed: [] }
|
13
|
+
|
14
|
+
while pending?
|
15
|
+
if (item = @queue.pop).first.is_a?(Symbol)
|
16
|
+
actions << item
|
17
|
+
else
|
18
|
+
item.each { |key, value| changes[key] += value }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
_run_actions(actions)
|
23
|
+
return if changes.values.all?(&:empty?)
|
24
|
+
Runner.new.run_on_changes(*changes.values)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pending?
|
28
|
+
!@queue.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def <<(changes)
|
32
|
+
@queue << changes
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def _run_actions(actions)
|
38
|
+
actions.each do |action_args|
|
39
|
+
args = action_args.dup
|
40
|
+
namespaced_action = args.shift
|
41
|
+
action = namespaced_action.to_s.sub(/^guard_/, "")
|
42
|
+
if @commander.respond_to?(action)
|
43
|
+
@commander.send(action, *args)
|
44
|
+
else
|
45
|
+
fail "Unknown action: #{action.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "guard"
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
# @private api
|
5
|
+
module Internals
|
6
|
+
class Scope
|
7
|
+
def initialize
|
8
|
+
@interactor_plugin_scope = []
|
9
|
+
@interactor_group_scope = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
{
|
14
|
+
plugins: _hashify_scope(:plugin),
|
15
|
+
groups: _hashify_scope(:group)
|
16
|
+
}.dup.freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: refactor
|
20
|
+
def grouped_plugins(scope = { plugins: [], groups: [] })
|
21
|
+
items = nil
|
22
|
+
plugins = _find_non_empty_scope(:plugins, scope)
|
23
|
+
if plugins
|
24
|
+
items = Array(plugins).map { |plugin| _instantiate(:plugin, plugin) }
|
25
|
+
end
|
26
|
+
|
27
|
+
unless items
|
28
|
+
# TODO: no coverage here!!
|
29
|
+
found = _find_non_empty_scope(:groups, scope)
|
30
|
+
found ||= Guard.state.session.groups.all
|
31
|
+
groups = Array(found).map { |group| _instantiate(:group, group) }
|
32
|
+
if groups.any? { |g| g.name == :common }
|
33
|
+
items = groups
|
34
|
+
else
|
35
|
+
items = ([_instantiate(:group, :common)] + Array(found)).compact
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
items.map do |plugin_or_group|
|
40
|
+
group = nil
|
41
|
+
plugins = [plugin_or_group]
|
42
|
+
if plugin_or_group.is_a?(Group)
|
43
|
+
# TODO: no coverage here!
|
44
|
+
group = plugin_or_group
|
45
|
+
plugins = Guard.state.session.plugins.all(group: group.name)
|
46
|
+
end
|
47
|
+
[group, plugins]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def from_interactor(scope)
|
52
|
+
@interactor_plugin_scope = Array(scope[:plugins])
|
53
|
+
@interactor_group_scope = Array(scope[:groups])
|
54
|
+
end
|
55
|
+
|
56
|
+
def titles(scope = nil)
|
57
|
+
hash = scope || to_hash
|
58
|
+
plugins = hash[:plugins]
|
59
|
+
groups = hash[:groups]
|
60
|
+
return plugins.map(&:title) unless plugins.nil? || plugins.empty?
|
61
|
+
return hash[:groups].map(&:title) unless groups.nil? || groups.empty?
|
62
|
+
["all"]
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# TODO: move to session
|
68
|
+
def _scope_names(new_scope, name)
|
69
|
+
items = Array(new_scope[:"#{name}s"] || new_scope[name]) if items.empty?
|
70
|
+
|
71
|
+
# Convert objects to names
|
72
|
+
items.map { |p| p.respond_to?(:name) ? p.name : p }
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: let the Plugins and Groups classes handle this?
|
76
|
+
# TODO: why even instantiate?? just to check if it exists?
|
77
|
+
def _hashify_scope(type)
|
78
|
+
# TODO: get cmdline passed to initialize above?
|
79
|
+
cmdline = Array(Guard.state.session.send("cmdline_#{type}s"))
|
80
|
+
guardfile = Guard.state.session.send(:"guardfile_#{type}_scope")
|
81
|
+
interactor = instance_variable_get(:"@interactor_#{type}_scope")
|
82
|
+
|
83
|
+
# TODO: session should decide whether to use cmdline or guardfile -
|
84
|
+
# since it has access to both variables
|
85
|
+
items = [interactor, cmdline, guardfile].detect do |source|
|
86
|
+
!source.empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
# TODO: not tested when groups/plugins given don't exist
|
90
|
+
|
91
|
+
# TODO: should already be instantiated
|
92
|
+
Array(items).map do |obj|
|
93
|
+
if obj.respond_to?(:name)
|
94
|
+
obj
|
95
|
+
else
|
96
|
+
name = obj
|
97
|
+
(type == :group ? _groups : _plugins).all(name).first
|
98
|
+
end
|
99
|
+
end.compact
|
100
|
+
end
|
101
|
+
|
102
|
+
def _instantiate(meth, obj)
|
103
|
+
# TODO: no coverage
|
104
|
+
return obj unless obj.is_a?(Symbol) || obj.is_a?(String)
|
105
|
+
Guard.state.session.send("#{meth}s".to_sym).all(obj).first
|
106
|
+
end
|
107
|
+
|
108
|
+
def _find_non_empty_scope(type, local_scope)
|
109
|
+
[Array(local_scope[type]), to_hash[type]].map(&:compact).detect(&:any?)
|
110
|
+
end
|
111
|
+
|
112
|
+
def _groups
|
113
|
+
Guard.state.session.groups
|
114
|
+
end
|
115
|
+
|
116
|
+
def _plugins
|
117
|
+
Guard.state.session.plugins
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require "guard/internals/plugins"
|
2
|
+
require "guard/internals/groups"
|
3
|
+
|
4
|
+
require "guard/options"
|
5
|
+
|
6
|
+
module Guard
|
7
|
+
# @private api
|
8
|
+
module Internals
|
9
|
+
# TODO: split into a commandline class and session (plugins, groups)
|
10
|
+
# TODO: swap session and metadata
|
11
|
+
class Session
|
12
|
+
attr_reader :plugins
|
13
|
+
attr_reader :groups
|
14
|
+
|
15
|
+
DEFAULT_OPTIONS = {
|
16
|
+
clear: false,
|
17
|
+
debug: false,
|
18
|
+
no_bundler_warning: false,
|
19
|
+
|
20
|
+
# User defined scopes
|
21
|
+
group: [],
|
22
|
+
plugin: [],
|
23
|
+
|
24
|
+
# Notifier
|
25
|
+
notify: true,
|
26
|
+
|
27
|
+
# Interactor
|
28
|
+
no_interactions: false,
|
29
|
+
|
30
|
+
# Guardfile options:
|
31
|
+
# guardfile_contents
|
32
|
+
guardfile: nil,
|
33
|
+
|
34
|
+
# Listener options
|
35
|
+
# TODO: rename to watchdirs?
|
36
|
+
watchdir: Dir.pwd,
|
37
|
+
latency: nil,
|
38
|
+
force_polling: false,
|
39
|
+
wait_for_delay: nil,
|
40
|
+
listen_on: nil
|
41
|
+
}
|
42
|
+
|
43
|
+
def cmdline_groups
|
44
|
+
@cmdline_groups.dup.freeze
|
45
|
+
end
|
46
|
+
|
47
|
+
def cmdline_plugins
|
48
|
+
@cmdline_plugins.dup.freeze
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(new_options)
|
52
|
+
@options = Options.new(new_options, DEFAULT_OPTIONS)
|
53
|
+
|
54
|
+
@plugins = Plugins.new
|
55
|
+
@groups = Groups.new
|
56
|
+
|
57
|
+
@cmdline_groups = @options[:group]
|
58
|
+
@cmdline_plugins = @options[:plugin]
|
59
|
+
|
60
|
+
@clear = @options[:clear]
|
61
|
+
@debug = @options[:debug]
|
62
|
+
@watchdirs = Array(@options[:watchdir])
|
63
|
+
@notify = @options[:notify]
|
64
|
+
@interactor_name = @options[:no_interactions] ? :sleep : :pry_wrapper
|
65
|
+
|
66
|
+
@guardfile_plugin_scope = []
|
67
|
+
@guardfile_group_scope = []
|
68
|
+
@guardfile_ignore = []
|
69
|
+
@guardfile_ignore_bang = []
|
70
|
+
|
71
|
+
@guardfile_notifier_options = {}
|
72
|
+
end
|
73
|
+
|
74
|
+
def guardfile_scope(scope)
|
75
|
+
opts = scope.dup
|
76
|
+
|
77
|
+
groups = Array(opts.delete(:groups))
|
78
|
+
group = Array(opts.delete(:group))
|
79
|
+
@guardfile_group_scope = Array(groups) + Array(group)
|
80
|
+
|
81
|
+
plugins = Array(opts.delete(:plugins))
|
82
|
+
plugin = Array(opts.delete(:plugin))
|
83
|
+
@guardfile_plugin_scope = Array(plugins) + Array(plugin)
|
84
|
+
|
85
|
+
fail "Unknown options: #{opts.inspect}" unless opts.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
# TODO: create a EvaluatorResult class?
|
89
|
+
attr_reader :guardfile_group_scope
|
90
|
+
attr_reader :guardfile_plugin_scope
|
91
|
+
attr_accessor :guardfile_ignore_bang
|
92
|
+
|
93
|
+
attr_reader :guardfile_ignore
|
94
|
+
def guardfile_ignore=(ignores)
|
95
|
+
@guardfile_ignore += Array(ignores).flatten
|
96
|
+
end
|
97
|
+
|
98
|
+
def clearing(on)
|
99
|
+
@clear = on
|
100
|
+
end
|
101
|
+
|
102
|
+
def clearing?
|
103
|
+
@clear
|
104
|
+
end
|
105
|
+
|
106
|
+
alias :clear? :clearing?
|
107
|
+
|
108
|
+
def debug?
|
109
|
+
@debug
|
110
|
+
end
|
111
|
+
|
112
|
+
def watchdirs
|
113
|
+
@watchdirs_from_guardfile ||= nil
|
114
|
+
@watchdirs_from_guardfile || @watchdirs
|
115
|
+
end
|
116
|
+
|
117
|
+
# set by Dsl with :directories() command
|
118
|
+
def watchdirs=(dirs)
|
119
|
+
dirs = [Dir.pwd] if dirs.empty?
|
120
|
+
@watchdirs_from_guardfile = dirs.map { |dir| File.expand_path dir }
|
121
|
+
end
|
122
|
+
|
123
|
+
def listener_args
|
124
|
+
if @options[:listen_on]
|
125
|
+
[:on, @options[:listen_on]]
|
126
|
+
else
|
127
|
+
listener_options = {}
|
128
|
+
[:latency, :force_polling, :wait_for_delay].each do |option|
|
129
|
+
listener_options[option] = @options[option] if @options[option]
|
130
|
+
end
|
131
|
+
expanded_watchdirs = watchdirs.map { |dir| File.expand_path dir }
|
132
|
+
[:to, *expanded_watchdirs, listener_options]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def evaluator_options
|
137
|
+
opts = { guardfile: @options[:guardfile] }
|
138
|
+
# TODO: deprecate :guardfile_contents
|
139
|
+
if @options[:guardfile_contents]
|
140
|
+
opts[:contents] = @options[:guardfile_contents]
|
141
|
+
end
|
142
|
+
opts
|
143
|
+
end
|
144
|
+
|
145
|
+
def notify_options
|
146
|
+
names = @guardfile_notifier_options.keys
|
147
|
+
return { notify: false } if names.include?(:off)
|
148
|
+
|
149
|
+
{
|
150
|
+
notify: @options[:notify],
|
151
|
+
notifiers: @guardfile_notifier_options
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
def guardfile_notification=(config)
|
156
|
+
@guardfile_notifier_options.merge!(config)
|
157
|
+
end
|
158
|
+
|
159
|
+
attr_reader :interactor_name
|
160
|
+
|
161
|
+
# TODO: call this from within action, not within interactor command
|
162
|
+
def convert_scope(entries)
|
163
|
+
scopes = { plugins: [], groups: [] }
|
164
|
+
unknown = []
|
165
|
+
|
166
|
+
entries.each do |entry|
|
167
|
+
if plugin = plugins.all(entry).first
|
168
|
+
scopes[:plugins] << plugin
|
169
|
+
elsif group = groups.all(entry).first
|
170
|
+
scopes[:groups] << group
|
171
|
+
else
|
172
|
+
unknown << entry
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
[scopes, unknown]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "guard/group"
|
2
|
+
|
3
|
+
require "guard/plugin_util"
|
4
|
+
require "guard/internals/session"
|
5
|
+
require "guard/internals/scope"
|
6
|
+
require "guard/runner"
|
7
|
+
|
8
|
+
module Guard
|
9
|
+
module Internals
|
10
|
+
class State
|
11
|
+
# Minimal setup for non-interactive commands (list, init, show, etc.)
|
12
|
+
def initialize(cmdline_opts)
|
13
|
+
@session = Session.new(cmdline_opts)
|
14
|
+
|
15
|
+
@scope = Scope.new
|
16
|
+
|
17
|
+
# NOTE: must be set before anything calls Guard::UI.debug
|
18
|
+
Debugging.start if session.debug?
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :scope
|
22
|
+
attr_reader :session
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Guard
|
2
|
+
module Internals
|
3
|
+
module Tracing
|
4
|
+
def self.trace(mod, meth)
|
5
|
+
meta = (class << mod; self; end)
|
6
|
+
original_meth = "original_#{meth}".to_sym
|
7
|
+
|
8
|
+
if mod.respond_to?(original_meth)
|
9
|
+
fail "ALREADY TRACED: #{mod}.#{meth}"
|
10
|
+
end
|
11
|
+
|
12
|
+
meta.send(:alias_method, original_meth, meth)
|
13
|
+
meta.send(:define_method, meth) do |*args, &block|
|
14
|
+
yield(*args) if block_given?
|
15
|
+
mod.send original_meth, *args, &block
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.untrace(mod, meth)
|
20
|
+
meta = (class << mod; self; end)
|
21
|
+
original_meth = "original_#{meth}".to_sym
|
22
|
+
|
23
|
+
unless mod.respond_to?(original_meth)
|
24
|
+
fail "NOT TRACED: #{mod}.#{meth} (no method: #{original_meth})"
|
25
|
+
end
|
26
|
+
|
27
|
+
meta.send(:remove_method, meth)
|
28
|
+
meta.send(:alias_method, meth, original_meth)
|
29
|
+
meta.send(:undef_method, original_meth)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Guard
|
2
|
+
module Jobs
|
3
|
+
class Base
|
4
|
+
def initialize(_options)
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Symbol] :stopped once job is finished
|
8
|
+
# @return [Symbol] :exit to tell Guard to terminate
|
9
|
+
def foreground
|
10
|
+
end
|
11
|
+
|
12
|
+
def background
|
13
|
+
end
|
14
|
+
|
15
|
+
# Signal handler calls this, so avoid actually doing
|
16
|
+
# anything other than signaling threads
|
17
|
+
def handle_interrupt
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|