naplug 1.6.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.
data/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2013 by Evernote Corporation, All rights reserved.
3
+ *
4
+ * Use of the source code and binary libraries included in this package
5
+ * is permitted under the following terms:
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
29
+ * not use this file except in compliance with the License. You may obtain a
30
+ * copy of the License at http://www.apache.org/licenses/LICENSE-2.0
31
+ */
data/README.md ADDED
@@ -0,0 +1,471 @@
1
+ # Naplug
2
+
3
+ *Naplug* is a [Nagios plugin](http://nagiosplug.sourceforge.net/developer-guidelines.html) library for Ruby focused on plugin internals: organization, status, performance data, output and exit code handling. It does not implement any functionality related to option and argument parsing, as there are fine tools already available for this purpose. It aims to ease the task of writing Nagios plugins in Ruby and _handling the paperwork_, allowing the plugin developer to concentrate on the test logic of the plugin. Its internal design is largely modeled after the very excellent [Worlkflow](https://github.com/geekq/workflow) library.
4
+
5
+ *Naplug* allows plugins to contain other plugins (referred to as *plugs*), which are a useful abstraction to break up significant tasks that the plugin as a whole must perform in order to determine the state of a service or host. The status and output of these plugs is thus used to determine the overall status of the plugin and build the output depending on said status.
6
+
7
+ While *Naplug* handles the nitty-gritty of Nagios plugins, it is important to have familiarity with the [Nagios Plugin Developer Guidelines](http://nagiosplug.sourceforge.net/developer-guidelines.html).
8
+
9
+ #### Note
10
+
11
+ * *Naplug* `1.x` is incompatible with *Naplug* `0.x` (`0.x` was never released as a Gem)
12
+ * *Naplug* `1.x` is only supported on Ruby 1.9 and above; it will not be backported to 1.8
13
+
14
+ ## Overview
15
+
16
+ Naplug approaches Nagios plugins as Ruby classes (note that `plugin` is a reserved keyword at both the class and instance levels). To use *Naplug*, install the gem and:
17
+
18
+ #!/usr/bin/end ruby -rubygems
19
+ require 'naplug'
20
+
21
+ class MyPlugin
22
+ include Naplug
23
+ plugin do |p|
24
+ ...
25
+ end
26
+ end
27
+
28
+ MyPlugin.new.exec!
29
+
30
+
31
+ All examples will omit the `require`s for readability.
32
+
33
+ A very simple plugin that always returns an OK status:
34
+
35
+ class AlwaysOkPlugin
36
+
37
+ include Naplug
38
+
39
+ plugin do |p|
40
+ p.status.ok!
41
+ p.output! "Optimism level: 100%"
42
+ end
43
+ end
44
+
45
+ AlwaysOkPlugin.new.exec!
46
+
47
+ In the above example, a new class `AlwaysOkPlugin` is defined (the class name is arbitrary), and within this class, a plugin is created, which performs some work to set the status and output of the plugin. Once the class is defined, a new instance of the plugin is created and executed. The `exec!` method executes the plugin, evaluates status, produces correctly formatted output, and exits with the appropriate exit code:
48
+
49
+ naplug@plugin:~: alwaysok
50
+ OK: Optimism level: 100%
51
+ naplug@plugin:~: echo $?
52
+ 0
53
+
54
+ A less optimistic example, this time with arguments:
55
+
56
+ class AlmostAlwaysOkPlugin
57
+
58
+ include Naplug
59
+
60
+ plugin do |p|
61
+
62
+ p.output! "Optimism level: #{p[:optimism]}%"
63
+
64
+ case p[:optimism]
65
+ when 23..100 then p.status.ok!
66
+ when 6..22 then p.status.warning!
67
+ when 0..5 then p.status.critical!
68
+ else
69
+ p.output! "utterly confused"
70
+ end
71
+
72
+ end
73
+ end
74
+
75
+ plugin = AlmostAlwaysOkPlugin.new :optimism => Random.rand(100)
76
+ plugin.exec!
77
+
78
+ Which yields:
79
+
80
+ naplug@plugin:~: almostalwaysok
81
+ OK: Optimism level: 96%
82
+ naplug@plugin:~: echo $?
83
+ 0
84
+
85
+ And
86
+
87
+ naplug@plugin:~: almostalwaysok
88
+ WARNING: Optimism level: 9%
89
+ naplug@plugin:~: echo $?
90
+ 1
91
+
92
+ ## Plugins
93
+
94
+ *Plugins* are defined inside a new class with the `plugin` keyword. Plugins are always initialized in an `UNKNOWN` state and with their output set to `uninitialized plugin`, since at that point, the status of the plugin has not been determined. This ensures that misbehaved plugins correctly notify Nagios that they are failing in some way (for instance, if there's an unhandled exception, at which point the output will be set to useful information about the exception).
95
+
96
+ ### Tags
97
+
98
+ Plugins can be tagged, and tags *must* be unique within a class. Tags are used to identify a plugin, which is useful when multiple plugins are defined in a single class, which may be necessary in cases where several implementations of tests are required. A plugin's tag defaults to `main` when not specified.
99
+
100
+ Plugins can be accessed through _tag_ methods, and executed through _tag!_ methods.
101
+
102
+ class MultiPlugin
103
+
104
+ include Naplug
105
+
106
+ plugin :foo do |p|
107
+ ...
108
+ end
109
+
110
+ plugin :bar do |p|
111
+ ...
112
+ end
113
+
114
+ end
115
+
116
+ plugin = MultiPlugin.new
117
+ case condition
118
+ when true then plugin.foo!
119
+ else plugin.bar!
120
+ end
121
+
122
+ When defining multiple plugins, invoking `exec!` will execute the `main` plugin (if defined; otherwise, `exec!` is unable to decide which one to execute). When defining a single plugin, `exec!` will execute it regardess of tag.
123
+
124
+
125
+ ### Arguments
126
+
127
+ A plugin can accept [mostly] arbitrary arguments, which are entirely optional and are available through the *[]* notation. *Naplug* (again, mostly) attaches no special meaning to them, i.e., they can be used in any way they need to be used.
128
+
129
+ A more realistic example that checks the staleness of a marker file:
130
+
131
+ class MarkerFilePlugin
132
+
133
+ include Naplug
134
+
135
+ plugin do |p|
136
+ if Time.now - File.mtime(p[:marker_file]) > p[:critical]
137
+ p.status.critical!
138
+ p.output! "marker file #{p[:marker_file]} mtime greater than #{p[:critical]} seconds"
139
+ else
140
+ p.status.ok!
141
+ p.output! "marker #{p[:marker_file]} is up to date"
142
+ end
143
+ end
144
+ end
145
+
146
+ plugin = MarkerFilePlugin.new :marker_file => '/tmp/my_marker', :critical => 120
147
+ plugin.exec!
148
+
149
+ There are some worthwhile observations about the above example. A missing marker file prevents determining the stalesness of said file (infinite staleness?), implicitly resulting in an `UNKNOWN` status and output corresponding to the message of the exception. For finer control of this behavior, exceptions can be raised inside the plugin, which will be handled internally:
150
+
151
+ plugin do |p|
152
+ raise Errno::ENOENT, p[:marker_file] unless File.exists? p[:marker_file]
153
+ ...
154
+ end
155
+
156
+ The exception object is available through the `payload`. This only applies to exceptions raised *inside* the `plugin` block.
157
+
158
+ Arguments can also be specified via the `args!` method:
159
+
160
+ class ArgumentsPlugin
161
+
162
+ include Naplug
163
+
164
+ plugin do |p|
165
+ ...
166
+ end
167
+
168
+ end
169
+
170
+ plugin = ArgumentsPlugin.new :foo => 'old argument'
171
+ plugin.args! :foo => 'new argument'
172
+
173
+ The above code will override the `:foo` argument with a value of `new argument`.
174
+
175
+ ### Exceptions and `eject!`
176
+
177
+ Plugins operate in restricted runtime environments: Nagios expects the proper exit code and output. Naplug makes every effort to properly handle unexpected exceptions when executing plugins, and where it can't, it propagates them bundled in the `Naplug::Error` exception, which is about the only exception (from Naplug's point of view) that needs to be handled:
178
+
179
+ class ExceptionPlugin
180
+
181
+ include Naplug
182
+
183
+ plugin do |p|
184
+ raise p[:exception], "raised exception: #{p[:exception]}"
185
+ end
186
+
187
+ end
188
+
189
+ begin
190
+ plugin = ExceptionPlugin.new :exception => StandardError
191
+ plugin.exec!
192
+ rescue Naplug::Error => e
193
+ plugin.eject! e
194
+ end
195
+
196
+ Which produces:
197
+
198
+ naplug@plugin:~: examples/exception
199
+ UNKNOWN: exception:18: raised exception: StandardError
200
+ naplug@plugin:~: echo $?
201
+ 3
202
+
203
+ The `eject!` method, which accepts a message string or an exception object as an argument, provides a last-ditch effort, out-of-band, escape hatch to bail out of executing a plugin, producing an `UNKNOWN` status and output from the message string or exception object.
204
+
205
+ While Naplug will internally handle exceptions within a plugin, it may be desirable to handle them especifically:
206
+
207
+ class ExceptionPlusPlugin
208
+
209
+ include Naplug
210
+
211
+ EXCEPTIONS = [ ArgumentError, ZeroDivisionError, TypeError ]
212
+
213
+ plugin do |p|
214
+
215
+ exception = EXCEPTIONS[p[:exception]]
216
+
217
+ begin
218
+ raise exception, "raising exception: #{exception}"
219
+ rescue ArgumentError => e
220
+ raise
221
+ rescue ZeroDivisionError => e
222
+ p.status.ok!
223
+ p.output! "divided by zero is infinity"
224
+ rescue => e
225
+ p.status.critical!
226
+ p.output! "got exception #{e.class}"
227
+ end
228
+
229
+ end
230
+
231
+ end
232
+
233
+ begin
234
+ plugin = ExceptionPluginPlus.new :exception => Random.rand(3)
235
+ plugin.exec!
236
+ rescue Naplug::Error => e
237
+ plugin.eject! e
238
+ end
239
+
240
+ Which produces:
241
+
242
+ naplug@plugin:~: examples/exception+
243
+ UNKNOWN: exception+:24: raising exception: ArgumentError
244
+ naplug@plugin:~: examples/exception+
245
+ CRITICAL: got exception TypeError
246
+ naplug@plugin:~: examples/exception+
247
+ OK: divided by zero is infinity
248
+
249
+ ### Plugs: Plugins within Plugins
250
+
251
+ Up until now, *Naplug* has essentially provided *syntactic sugar* to define and use what amounts to single-purpose plugins, along with some convenience methods to represent status and produce output. But plugins sometimes need to perform a number of possibly independent tasks to reach a final, _aggregated_ status.
252
+
253
+ In *Naplug*, these tasks are _nested plugins_ or _subplugins_, and are referred to as *plugs* scoped to a _parent_ plugin. When a plugin is created, we can define *plugs* inside the plugin through the `plugin` instance method. Again, these can be tagged, and plug tags must be unique, this time within a plugin.
254
+
255
+ class PlugPlugin
256
+
257
+ include Naplug
258
+
259
+ plugin do |p|
260
+
261
+ plugin :plug1 do |p1|
262
+ ...
263
+ end
264
+
265
+ plugin :plug2 do |p2|
266
+ ...
267
+ end
268
+
269
+ end
270
+ end
271
+
272
+ Defining plugs imposes one important limitation: no other code besides plug definitions is allowed (in reality, it is allowed, just never really during executed).
273
+
274
+ class PluggedPlugin
275
+
276
+ include Naplug
277
+
278
+ plugin do |p|
279
+
280
+ <do something here> # will not be executed
281
+
282
+ plugin :plug1 do |p1|
283
+ ...
284
+ end
285
+
286
+ plugin :plug2 do |p2|
287
+ ...
288
+ end
289
+
290
+ <do somthing else here> # will not be executed
291
+ end
292
+
293
+ end
294
+
295
+ #### Order of Execution
296
+
297
+ When `exec!` is invoked on a plugin, plugs are executed in the order in which they are defined, which is a side-effect of the fact that plugs are inserted into a Hash to keep track of them: [Hashes enumerate their values in the order that the corresponding keys were inserted](http://www.ruby-doc.org/core-1.9.3/Hash.html). Execution order can only be controlled manually:
298
+
299
+ plugin.exec :plug2
300
+ plugin.exex :plug1
301
+
302
+ #### Arguments
303
+
304
+ With the introduction of *plugs*, arguments do become more structured, as arguments keys are matched to plugin and plug tags to route them appropriately.
305
+
306
+ plugin = PlugPlugin.new(:plug1 => { :critical => 120, :warning => 60 },
307
+ :plug2 => { :ok => 0, :warning => 5, :critical => 10 })
308
+
309
+ Any keys not matching plug tags are considered to be shared among all plugs:
310
+
311
+ plugin = PlugPlugin.new(:file => '/tmp/file',
312
+ :plug1 => { :critical => 120, :warning => 60 },
313
+ :plug2 => { :ok => 0, :warning => 5, :critical => 10 })
314
+
315
+ Tagged arguments have priority over shared ones.
316
+
317
+ plugin = PlugPlugin.new(:file => '/tmp/file',
318
+ :plug1 => { :file => '/var/tmp/file', :critical => 120 },
319
+ :plug2 => { :ok => 0, :warning => 5, :critical => 10 })
320
+
321
+ #### A Plugged Plugin Example
322
+
323
+ Take a service for which we wish to monitor three conditions:
324
+
325
+ * that the service is running one and only one process
326
+ * that the log file has seen activity within the last 60 seconds
327
+ * that some metric related to the service (number of files in a queue) is within acceptable thresholds
328
+
329
+ Each of these tasks can be a plug, and Naplug will take care of aggregating the statuses to yield a plugin status (worst always wins).
330
+
331
+ require 'sys/proctable'
332
+ require 'naplug'
333
+
334
+ class MultiPlugServicePlugin
335
+
336
+ include Naplug
337
+
338
+ plugin do |p|
339
+
340
+ plug :proc_count do |p1|
341
+ pids = Sys::ProcTable.ps.each do |ps|...
342
+ case pids.size
343
+ when 1
344
+ p1.status.ok
345
+ p1.output "process #{p1[:name]} running with pid #{pids[0]}"
346
+ when 0
347
+ p1.status.critical
348
+ p1.output "process #{p1[:name]} not running"
349
+ else
350
+ p1.status.critical
351
+ p1.output "multiple #{p1[:name]} processes found, pids #{pids.join(',')}"
352
+ end
353
+ end
354
+
355
+ plug :log_mtime do |p2|
356
+ delta = Time.now - File.mtime(p2[:log_file])
357
+ if delta > p2[:critical]
358
+ p2.status.critical
359
+ p2.output "p2[:name] log file #{p2[:log_file]} mtime greater than #{p2[:critical]} seconds"
360
+ else
361
+ p2.status.ok
362
+ p2.output "marker #{p2[:log_file]} is up to date"
363
+ end
364
+ end
365
+
366
+ plug :queue_depth do |p3|
367
+ num_files = Dir.entries(p3[:dir]).length - 2
368
+ p3.output "queue depth: #{num_files} items"
369
+
370
+ case num_files
371
+ when 0..100 then p3.status.ok
372
+ when 101..1000 then p3.status.warning
373
+ else p3.status.critical
374
+ end
375
+ end
376
+
377
+ end
378
+ end
379
+
380
+ plugin = MultiPlugServicePlugin.new :name => 'foobard'
381
+ plugin[:log_mtime] = { :log_file => '/var/log/foobard.log' }
382
+ plugin[:queue_depth] = { :dir => '/var/spool/foobard' }
383
+ plugin.exec!
384
+
385
+ ## Naplug Methods
386
+
387
+ ### Class Methods
388
+
389
+ Whenever Naplug in included in a class, the following class methods are available:
390
+
391
+ * `plugin`, which is used to create plugins
392
+ * `tags`, which returns an array of defined plugin tags
393
+
394
+ ### Instance Methods
395
+
396
+ In addition to the above class methods, the followingh instance methods are available:
397
+
398
+ * `args` and `args!` to retrieve and set arguments
399
+ * `exec!`, `exec` and `eval` to exec-to-exit, exec and evaluate plugins, respectively
400
+ * `has_plugins?`, which evaluates to true if a plugin has plugs
401
+ * `[]` and `[]=` to get and set specific arguments
402
+ * `to_str` to produce formatted plugin output
403
+ * `eject!`, to quickly bail out
404
+ * `enable!` and `enabled?`, `disable!` and `disabled?`, for enable and disabled plugs
405
+
406
+ Overriding these will likely cause *Naplug* to misbehave, to say the least.
407
+
408
+ Other methods can be defined in the class as necessary, and they can be used in the defined plugins or plugs, generally to provide helpers services. These should be defined as `private` or `protected` as necessary.
409
+
410
+ ### Status
411
+
412
+ Status is a special object that represent the status of a plugin for each of the defined states in the [Nagios Plugin Guidelines](http://nagiosplug.sourceforge.net/developer-guidelines.html): `OK`, `WARNING`, `CRITICAL` and `UNKNOWN`. Each of these states is itself an instance method which sets the state, and you can obtain the string and numeric representation through the usual methods `to_s` and `to_i`. The initial (and default) status of a `Status` object is `UNKNOWN`. Statuses are comparable in that larger statuses represent worse states, a feature that will come handy shortly.
413
+
414
+ require 'naplug/status'
415
+
416
+ puts "All statuses:"
417
+ Naplug::Status.states.each do |state|
418
+ status = Naplug::Status.new state
419
+ puts " status #{status} has exit code #{status.to_i}"
420
+ end
421
+
422
+ puts "Working with a status:"
423
+ status = Naplug::Status.new
424
+ puts " status #{status} has exit code #{status.to_i}"
425
+ status.ok!
426
+ puts " status #{status} has exit code #{status.to_i}"
427
+
428
+ puts "Comparing statuses:"
429
+ status1 = Naplug::Status.new :warning
430
+ if status < status1
431
+ puts " status [#{status}] < status1 [#{status1}] is true"
432
+ end
433
+
434
+ which produces
435
+
436
+ naplug@plugin:~: status
437
+ All statuses:
438
+ status OK has exit code 0
439
+ status WARNING has exit code 1
440
+ status CRITICAL has exit code 2
441
+ status UNKNOWN has exit code 3
442
+ Working with a status:
443
+ status UNKNOWN has exit code 3 after initialization
444
+ status OK has exit code 0 after status.ok
445
+ Comparing statuses:
446
+ status [OK] < status1 [WARNING] is true
447
+
448
+ # Futures
449
+
450
+ There following are some ideas on future Naplug features.
451
+
452
+ ### Order of Execution
453
+
454
+ A future release will allow the execution order to be changed through an `order!` instance method, which will accept a list of tags in the desired order of execution.
455
+
456
+ plugin.order! :plug2, :plug1
457
+
458
+ If tags are omitted from the list, the missing plugs are pushed to the end of the line in the last order set.
459
+
460
+ #### Enabling and Disabling Plugs
461
+
462
+ Currently, when plugs are defined, they are assumed to be enabled and will be executed when `exec!` is invoked. There may be cases when it may be desirable or necessary to disable specific plugins, which will be accomplished through the `disable!` instance method. A disabled plug can be re-enabled via the `enable!` plugin method:
463
+
464
+ plugin.disable! :plug2
465
+
466
+ Disabled plugs will not be executed and will not be taken into account when evaluating status. The active state of a plugin can be queried via the `enabled?` and `disabled?` methods.
467
+
468
+ plugin.enabled? :plug2 => false
469
+ plugin.disabled? :plug2 => true
470
+
471
+ Aditionally, `is_<tag>_enabled?` and `is_<tag>_disabled?` methods will be available for each plug.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'naplug'
8
+
9
+ module Naplug
10
+
11
+ module Examples
12
+
13
+ class AlmostAlwaysOkPlugin
14
+
15
+ include Naplug
16
+
17
+ plugin do |p|
18
+
19
+ p.output! "Optimism level: #{p[:optimism]}%"
20
+
21
+ case p[:optimism]
22
+ when 23..100 then p.status.ok!
23
+ when 6..22 then p.status.warning!
24
+ when 0..5 then p.status.critical!
25
+ else
26
+ p.output! 'utterly confused'
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ plugin = Naplug::Examples::AlmostAlwaysOkPlugin.new :optimism => Random.rand(100)
38
+ plugin.exec!
data/examples/alwaysok ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'naplug'
8
+
9
+ module Naplug
10
+
11
+ module Examples
12
+
13
+ class AlwaysOkPlugin
14
+
15
+ include Naplug
16
+
17
+ plugin do |p|
18
+
19
+ p.status.ok!
20
+ p.output! 'Optimism level: 100%'
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ Naplug::Examples::AlwaysOkPlugin.new.exec!
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'naplug'
8
+
9
+ module Naplug
10
+
11
+ module Examples
12
+
13
+ class AlwaysUnknownPlugin
14
+
15
+ include Naplug
16
+
17
+ plugin do |p|
18
+
19
+ p2.status.ok!
20
+ p.output! 'Optimism level: 100%'
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ Naplug::Examples::AlwaysUnknownPlugin.new.exec!
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'naplug'
8
+
9
+ class DupPlugin
10
+
11
+ include Naplug
12
+
13
+ plugin do |p|
14
+ p.status.ok!
15
+ p.output! 'not really; will fail'
16
+ end
17
+
18
+ plugin do |p|
19
+ p.status.ok!
20
+ p.output! 'not really; will fail'
21
+ end
22
+ end
23
+
24
+ plugin = DupPlugin.new
25
+ plugin.exec!
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'naplug'
8
+
9
+ module Naplug
10
+
11
+ module Examples
12
+
13
+ class ExceptionPlugin
14
+
15
+ include Naplug
16
+
17
+ plugin do |p|
18
+ raise p[:exception], "raised exception: #{p[:exception]}"
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ begin
28
+ plugin = Naplug::Examples::ExceptionPlugin.new :exception => StandardError
29
+ plugin.exec!
30
+ rescue Naplug::Error => e
31
+ plugin.eject! e
32
+ end