olag 0.1.10
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/ChangeLog +24 -0
- data/LICENSE +19 -0
- data/README.rdoc +17 -0
- data/Rakefile +24 -0
- data/codnar.html +4379 -0
- data/doc/root.html +26 -0
- data/doc/system.markdown +283 -0
- data/lib/olag/application.rb +167 -0
- data/lib/olag/change_log.rb +59 -0
- data/lib/olag/data_files.rb +20 -0
- data/lib/olag/errors.rb +44 -0
- data/lib/olag/gem_specification.rb +77 -0
- data/lib/olag/globals.rb +43 -0
- data/lib/olag/hash_struct.rb +12 -0
- data/lib/olag/rake.rb +263 -0
- data/lib/olag/string_unindent.rb +19 -0
- data/lib/olag/test.rb +8 -0
- data/lib/olag/test/with_errors.rb +26 -0
- data/lib/olag/test/with_fakefs.rb +36 -0
- data/lib/olag/test/with_rake.rb +34 -0
- data/lib/olag/test/with_tempfile.rb +49 -0
- data/lib/olag/update_version.rb +53 -0
- data/lib/olag/version.rb +8 -0
- data/test/access_data_files.rb +15 -0
- data/test/collect_errors.rb +33 -0
- data/test/missing_keys.rb +17 -0
- data/test/run_application.rb +44 -0
- data/test/unindent_text.rb +26 -0
- metadata +243 -0
data/doc/root.html
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
5
|
+
<title>Olag - Oren's Library/Application Gem framework.</title>
|
6
|
+
<style type="text/css">
|
7
|
+
<embed src="codnar/data/yui/reset.css" type="x-codnar/file"/>
|
8
|
+
<embed src="codnar/data/yui/base.css" type="x-codnar/file"/>
|
9
|
+
<embed src="codnar/data/style.css" type="x-codnar/file"/>
|
10
|
+
<embed src="codnar/data/sunlight/default.css" type="x-codnar/file"/>
|
11
|
+
</style>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<div id="contents"></div>
|
15
|
+
<embed src="README.rdoc" type="x-codnar/include"/>
|
16
|
+
<embed src="doc/system.markdown" type="x-codnar/include"/>
|
17
|
+
<script type="text/javascript">
|
18
|
+
<embed src="codnar/data/contents.js" type="x-codnar/file"/>
|
19
|
+
<embed src="codnar/data/control_chunks.js" type="x-codnar/file"/>
|
20
|
+
<embed src="codnar/data/sunlight/min.js" type="x-codnar/file"/>
|
21
|
+
<embed src="codnar/data/sunlight/ruby-min.js" type="x-codnar/file"/>
|
22
|
+
Sunlight.globalOptions.lineNumbers = false;
|
23
|
+
Sunlight.highlightAll();
|
24
|
+
</script>
|
25
|
+
</body>
|
26
|
+
</html>
|
data/doc/system.markdown
ADDED
@@ -0,0 +1,283 @@
|
|
1
|
+
## Rakefile ##
|
2
|
+
|
3
|
+
Olag's Rakefile is a good example of how to use Olag's classes to create a
|
4
|
+
full-featured gem Rakefile:
|
5
|
+
|
6
|
+
[[Rakefile|named_chunk_with_containers]]
|
7
|
+
|
8
|
+
The overall Rakefile structure is as follows:
|
9
|
+
|
10
|
+
* A first line sets up the Ruby module load path to begin with
|
11
|
+
the current gem's `lib` directory. This standard idiom ensures we have access
|
12
|
+
to the current gem.
|
13
|
+
|
14
|
+
* The next line imports Olag's `rake` support module.
|
15
|
+
|
16
|
+
* This is followed by setting up the gem specification, which is enhanced by
|
17
|
+
Olag using monkey-patching.
|
18
|
+
|
19
|
+
* Finally, Olag::Rake sets up the following tasks (as reported by `rake -T`):
|
20
|
+
rake all # Version, verify, document, package
|
21
|
+
rake analyze # Analyze source code
|
22
|
+
rake changelog # Update ChangeLog from Git
|
23
|
+
rake clean # Remove any temporary products.
|
24
|
+
rake clean_codnar # Clean all split chunks
|
25
|
+
rake clobber # Remove any generated file.
|
26
|
+
rake clobber_codnar # Remove woven HTML documentation
|
27
|
+
rake clobber_coverage # Remove rcov products for coverage
|
28
|
+
rake clobber_package # Remove package products
|
29
|
+
rake clobber_rdoc # Remove rdoc products
|
30
|
+
rake codnar # Build the code narrative HTML
|
31
|
+
rake codnar_split # Split all files into chunks
|
32
|
+
rake codnar_weave # Weave chunks into HTML
|
33
|
+
rake commit # Git commit process
|
34
|
+
rake coverage # Test code covarage with RCov
|
35
|
+
rake doc # Generate all documentation
|
36
|
+
rake first_commit # Perform the 1st (main) Git commit
|
37
|
+
rake flay # Check for duplicated code with Flay
|
38
|
+
rake gem # Build the gem file olag-<version>.gem
|
39
|
+
rake package # Build all the packages
|
40
|
+
rake rdoc # Build the rdoc HTML Files
|
41
|
+
rake reek # Check for smelly code with Reek
|
42
|
+
rake repackage # Force a rebuild of the package files
|
43
|
+
rake rerdoc # Force a rebuild of the RDOC files
|
44
|
+
rake roodi # Check for smelly code with Roodi
|
45
|
+
rake saikuro # Check for complex code with Saikuro
|
46
|
+
rake second_commit # Perform the 2nd (amend) Git commit
|
47
|
+
rake test # Run tests for test
|
48
|
+
rake verify # Test, coverage, analyze code
|
49
|
+
rake version # Update version file from Git
|
50
|
+
|
51
|
+
### Gem Specification ###
|
52
|
+
|
53
|
+
The gem specification is provided as usual:
|
54
|
+
|
55
|
+
[[Gem specification|named_chunk_with_containers]]
|
56
|
+
|
57
|
+
However, the Gem::Specification class is monkey-patched to automatically
|
58
|
+
several of the specification fields, and adding some new ones:
|
59
|
+
|
60
|
+
[[lib/olag/gem_specification.rb|named_chunk_with_containers]]
|
61
|
+
|
62
|
+
### Rake tasks ###
|
63
|
+
|
64
|
+
The Olag::Rake class sets up the tasks listed above as follows:
|
65
|
+
|
66
|
+
[[lib/olag/rake.rb|named_chunk_with_containers]]
|
67
|
+
|
68
|
+
#### Task utilities ####
|
69
|
+
|
70
|
+
The following utilities are used to create the different tasks. It would have
|
71
|
+
be nicer if Rake had treated the task description as just another task
|
72
|
+
property.
|
73
|
+
|
74
|
+
[[Task utilities|named_chunk_with_containers]]
|
75
|
+
|
76
|
+
#### Verify the gem ####
|
77
|
+
|
78
|
+
The following tasks verify that the gem is correct. Testing for 100% code
|
79
|
+
coverage seems excessive but in reality it isn't that hard to do, and is really
|
80
|
+
only a modest form of test coverage verification.
|
81
|
+
|
82
|
+
[[Verify gem functionality|named_chunk_with_containers]]
|
83
|
+
|
84
|
+
The following tasks verify that the code is squeacky-clean. While passing the
|
85
|
+
code through all these verifiers seems excessive, it isn't that hard to achieve
|
86
|
+
in practice. There were several times I did refactorings "just to satisfy
|
87
|
+
`reek` (or `flay`)" and ended up with an unexpected code improvement. Anyway,
|
88
|
+
if you aren't a youch OCD about this sort of thing, Olag is probably not for
|
89
|
+
you :-)
|
90
|
+
|
91
|
+
[[Analyze the source code|named_chunk_with_containers]]
|
92
|
+
|
93
|
+
#### Generate Documentation ####
|
94
|
+
|
95
|
+
The following tasks generate the usual RDoc documentation, required to make the
|
96
|
+
gem behave well in the Ruby tool ecosystem:
|
97
|
+
|
98
|
+
[[Generate RDoc documentation|named_chunk_with_containers]]
|
99
|
+
|
100
|
+
The following tasks generate the Codnar documentation (e.g., the document you
|
101
|
+
are reading now), which goes beyond RDoc to provide an end-to-end linear
|
102
|
+
narrative describing the gem:
|
103
|
+
|
104
|
+
[[Generate Codnar documentation|named_chunk_with_containers]]
|
105
|
+
|
106
|
+
Codnar is very configurable, and the above provides a reasonable default
|
107
|
+
configuration for pure Ruby gems. You can modify the CODNAR_CONFIGURATIONS
|
108
|
+
array before creating the Rake object, by unshifting additional/overriding
|
109
|
+
patterns into it. For example, you may choose to use GVim for syntax
|
110
|
+
highlighting. This will cause splitting to become much slower, but the
|
111
|
+
generated HTML will already include the highlighting markup so it will display
|
112
|
+
instantly. Or, you may have additional source file types (Javascript, CSS,
|
113
|
+
HTML, C, etc.) to be highlighted.
|
114
|
+
|
115
|
+
#### Automate Git commit process ####
|
116
|
+
|
117
|
+
In an ideal world, committing to Git would be a simple matter of typing `git
|
118
|
+
commit -m "..."`. In our case, things get a bit complicated.
|
119
|
+
|
120
|
+
There is some information that we need to extract out of Git and inject into
|
121
|
+
our files (to be committed). Since Git pre-commit hooks do not allow us to
|
122
|
+
modify any source files, this turns commit into a two-phase process: we do an
|
123
|
+
initial commit, update some files, then `git commit --amend` to merge them with
|
124
|
+
the first commit.
|
125
|
+
|
126
|
+
[[Automate Git commit process|named_chunk_with_containers]]
|
127
|
+
|
128
|
+
The first piece of information we need to extract from Git is the current build
|
129
|
+
number, which needs to be injected into the gem's version number:
|
130
|
+
|
131
|
+
[[lib/olag/version.rb|named_chunk_with_containers]]
|
132
|
+
|
133
|
+
Documentation generation will depend on the content (and therefore modification
|
134
|
+
time) of this file. Luckily, we can update this number before the first commit,
|
135
|
+
and we can ensure it only touches the file if there is a real change, to avoid
|
136
|
+
unnecessary documentation regeneration:
|
137
|
+
|
138
|
+
[[lib/olag/update_version.rb|named_chunk_with_containers]]
|
139
|
+
|
140
|
+
The second information we extract from Git is the ChangeLog file. Here,
|
141
|
+
obviously, the ChangeLog needs to include the first commit's message, so we are
|
142
|
+
forced to regenerate the file and amend Git's history with a second commit:
|
143
|
+
|
144
|
+
[[lib/olag/change_log.rb|named_chunk_with_containers]]
|
145
|
+
|
146
|
+
## Utility classes ##
|
147
|
+
|
148
|
+
Olag provides a set of utility classes that are useful in implementing
|
149
|
+
well-behaved gems.
|
150
|
+
|
151
|
+
### Unindeting text ###
|
152
|
+
|
153
|
+
When using "here documents" (`<<EOF` data), it is nice to be able to indent the
|
154
|
+
data to match the surrounding code. There are other cases where it is useful to
|
155
|
+
"unindent" multi-line text. The following tests demonstrates using the
|
156
|
+
`unindent` function:
|
157
|
+
|
158
|
+
[[test/unindent_text.rb|named_chunk_with_containers]]
|
159
|
+
|
160
|
+
And here is the implementation extending the built-in String class:
|
161
|
+
|
162
|
+
[[lib/olag/string_unindent.rb|named_chunk_with_containers]]
|
163
|
+
|
164
|
+
### Accessing gem data files ###
|
165
|
+
|
166
|
+
Sometimes it is useful to package some files inside a gem, to be read by user
|
167
|
+
code. This is of course trivial for Ruby code files (just use `require`) but
|
168
|
+
not trivial if you want, say, to include some CSS files in your gem for
|
169
|
+
everyone to use. Olag provides a way to resolve the path of any file in any gem
|
170
|
+
(basically replicating what `require` does). Here is a simple test of using
|
171
|
+
this functionality:
|
172
|
+
|
173
|
+
[[test/access_data_files.rb|named_chunk_with_containers]]
|
174
|
+
|
175
|
+
And here is the implementation:
|
176
|
+
|
177
|
+
[[lib/olag/data_files.rb|named_chunk_with_containers]]
|
178
|
+
|
179
|
+
### Simulating objects with Hash tables ###
|
180
|
+
|
181
|
+
Javascript has an interesting convention where `hash["key"]` and `hash.key`
|
182
|
+
mean the same thing. This is very useful in cutting down boilerplate code, and
|
183
|
+
it also makes your data serialize to very clean YAML. Unlike OpenStruct, you do
|
184
|
+
not need to define all the members in advance, and you can alternate between
|
185
|
+
the `.key` and `["key"]` forms as convenient for any particular piece of code.
|
186
|
+
The down side is that you lose any semblance of type checking - misspelled
|
187
|
+
member names and other errors are silently ignored. Well, that's what we have
|
188
|
+
unit tests for, right? :-)
|
189
|
+
|
190
|
+
Olag provides an extension to the Hash class that provides the above, for these
|
191
|
+
who have chosen to follow the dark side of the force. Here is a simple test
|
192
|
+
demonstrating using this ability:
|
193
|
+
|
194
|
+
[[test/missing_keys.rb|named_chunk_with_containers]]
|
195
|
+
|
196
|
+
And here is the implementation:
|
197
|
+
|
198
|
+
[[lib/olag/hash_struct.rb|named_chunk_with_containers]]
|
199
|
+
|
200
|
+
### Collecting errors ###
|
201
|
+
|
202
|
+
In library code, it is bad practice to terminate the program on an error.
|
203
|
+
Raising an exception is preferrable, but that forces you to abort the
|
204
|
+
processing. In some cases, it is preferrable to collect the error, skip a bit
|
205
|
+
of processing, and continue (if only for detecting additional errors). For
|
206
|
+
example, one would expect a compiler to emit more than just the first syntax
|
207
|
+
error message.
|
208
|
+
|
209
|
+
Olag provides an error collection class that also automatically formats the
|
210
|
+
error to indicate its location. Here is a simple test that demonstrates
|
211
|
+
collecting errors:
|
212
|
+
|
213
|
+
[[test/collect_errors.rb|named_chunk_with_containers]]
|
214
|
+
|
215
|
+
Which uses a mix-in that helps writing tests that use errors:
|
216
|
+
|
217
|
+
[[lib/olag/test/with_errors.rb|named_chunk_with_containers]]
|
218
|
+
|
219
|
+
Here is the actual implementation:
|
220
|
+
|
221
|
+
[[lib/olag/errors.rb|named_chunk_with_containers]]
|
222
|
+
|
223
|
+
### Testing with a fake file system ###
|
224
|
+
|
225
|
+
Sometimes tests need to muck around with disk files. One way to go about it is
|
226
|
+
to create a temporary disk directory, work in there, and clean it up when done.
|
227
|
+
Another, simpler way is to use the FakeFS file system, which captures all(most)
|
228
|
+
of Ruby's file operations and redirect them to an in-memory fake file system.
|
229
|
+
Here is a mix-in that helps writing tests using FakeFS (we will use it below
|
230
|
+
when running applications inside unit tests):
|
231
|
+
|
232
|
+
[[lib/olag/test/with_fakefs.rb|named_chunk_with_containers]]
|
233
|
+
|
234
|
+
### Testing with a temporary file ###
|
235
|
+
|
236
|
+
When running external programs, actually generating a temporary disk file is
|
237
|
+
sometimes inevitable. Of course, such files need to be cleaned up when the test
|
238
|
+
is done. If we need more than just one such file, it is easier to create a
|
239
|
+
whole temporary directory which is easily cleaned up in one operation.
|
240
|
+
|
241
|
+
Here is a mix-in that helps writing tests using temporary files and folders:
|
242
|
+
|
243
|
+
[[lib/olag/test/with_tempfile.rb|named_chunk_with_containers]]
|
244
|
+
|
245
|
+
### Testing Rake tasks ###
|
246
|
+
|
247
|
+
Testing Rake tasks is tricky because tests may be run in the context of Rake.
|
248
|
+
Therefore, the best practice is to create a new Rake application and restore
|
249
|
+
the original when the test is done:
|
250
|
+
|
251
|
+
[[lib/olag/test/with_rake.rb|named_chunk_with_containers]]
|
252
|
+
|
253
|
+
### Testing in general ###
|
254
|
+
|
255
|
+
Rather than requiring each of the above test mix-in modules on its own, it is
|
256
|
+
convenient to just `require "olag/test"` and be done:
|
257
|
+
|
258
|
+
[[lib/olag/test.rb|named_chunk_with_containers]]
|
259
|
+
|
260
|
+
## Applications ##
|
261
|
+
|
262
|
+
Writing an application requires a lot of boilerplate. Olag provides an
|
263
|
+
Application base class that handles standard command line flags, execution from
|
264
|
+
within tests, and errors collection.
|
265
|
+
|
266
|
+
Here is a simple test for running such an application from unit tests:
|
267
|
+
|
268
|
+
[[test/run_application.rb|named_chunk_with_containers]]
|
269
|
+
|
270
|
+
And here is the implementation:
|
271
|
+
|
272
|
+
[[lib/olag/application.rb|named_chunk_with_containers]]
|
273
|
+
|
274
|
+
It makes use of the following utility class, for saving and restoring the
|
275
|
+
global state when running an application in a test:
|
276
|
+
|
277
|
+
[[lib/olag/globals.rb|named_chunk_with_containers]]
|
278
|
+
|
279
|
+
## License ##
|
280
|
+
|
281
|
+
Olag is published under the MIT license:
|
282
|
+
|
283
|
+
[[LICENSE|named_chunk_with_containers]]
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "olag/errors"
|
3
|
+
require "olag/globals"
|
4
|
+
require "olag/string_unindent.rb"
|
5
|
+
require "olag/version"
|
6
|
+
require "optparse"
|
7
|
+
|
8
|
+
module Olag
|
9
|
+
|
10
|
+
# Base class for Olag applications.
|
11
|
+
class Application
|
12
|
+
|
13
|
+
# Create a Olag application.
|
14
|
+
def initialize(is_test = nil)
|
15
|
+
@errors = Errors.new
|
16
|
+
@is_test = !!is_test
|
17
|
+
end
|
18
|
+
|
19
|
+
# Run the Olag application, returning its status.
|
20
|
+
def run(*arguments, &block)
|
21
|
+
parse_options
|
22
|
+
yield(*arguments) if block_given?
|
23
|
+
return print_errors
|
24
|
+
rescue ExitException => exception
|
25
|
+
return exception.status
|
26
|
+
end
|
27
|
+
|
28
|
+
# Execute a block with an overriden ARGV, typically for running an
|
29
|
+
# application.
|
30
|
+
def self.with_argv(argv)
|
31
|
+
return Globals.without_changes do
|
32
|
+
ARGV.replace(argv)
|
33
|
+
yield
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
# Parse the command line options of the program.
|
40
|
+
def parse_options
|
41
|
+
parser = OptionParser.new do |options|
|
42
|
+
(@options = options).banner = banner + "\n\nOPTIONS:\n\n"
|
43
|
+
define_flags
|
44
|
+
end
|
45
|
+
parser.parse!
|
46
|
+
parse_arguments
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parse remaining command-line file arguments. This is expected to be
|
50
|
+
# overriden by the concrete application sub-class. By default assumes there
|
51
|
+
# are no such arguments.
|
52
|
+
def parse_arguments
|
53
|
+
return if ARGV.size == 0
|
54
|
+
$stderr.puts("#{$0}: Expects no command line file arguments.")
|
55
|
+
exit(1)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Define application flags. This is expected to be overriden by the
|
59
|
+
# concrete application sub-class.
|
60
|
+
def define_flags
|
61
|
+
define_help_flag
|
62
|
+
define_version_flag
|
63
|
+
define_redirect_flag("$stdout", "output", "w")
|
64
|
+
define_redirect_flag("$stderr", "error", "w")
|
65
|
+
#! Most scripts do not use this, but they can add it.
|
66
|
+
#! define_redirect_flag("$stdin", "input", "r")
|
67
|
+
end
|
68
|
+
|
69
|
+
# Define the standard help flag.
|
70
|
+
def define_help_flag
|
71
|
+
@options.on("-h", "--help", "Print this help message and exit.") do
|
72
|
+
puts(@options)
|
73
|
+
print_additional_help
|
74
|
+
exit(0)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Print additional help message. This includes both the command line file
|
79
|
+
# arguments, if any, and a short description of the program.
|
80
|
+
def print_additional_help
|
81
|
+
arguments_name, arguments_description = arguments
|
82
|
+
puts(format(" %-33s%s", arguments_name, arguments_description)) if arguments_name
|
83
|
+
print("\nDESCRIPTION:\n\n")
|
84
|
+
print(description)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return the banner line of the help message. This is expected to be
|
88
|
+
# overriden by the concrete application sub-class. By default returns the
|
89
|
+
# path name of thje executed program.
|
90
|
+
def banner
|
91
|
+
return $0
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return the name and description of any final command-line file arguments,
|
95
|
+
# if any. This is expected to be overriden by the concrete application
|
96
|
+
# sub-class. By default, assume there are no final command-line file
|
97
|
+
# arguments (however, `parse_options` does not enforce this by default).
|
98
|
+
def arguments
|
99
|
+
return nil, nil
|
100
|
+
end
|
101
|
+
|
102
|
+
# Return a short description of the program. This is expected to be
|
103
|
+
# overriden by the concrete application sub-class. By default, provide
|
104
|
+
def description
|
105
|
+
return "Sample description\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Define the standard version flag.
|
109
|
+
def define_version_flag
|
110
|
+
version_number = version
|
111
|
+
@options.on("-v", "--version", "Print the version number (#{version_number}) and exit.") do
|
112
|
+
puts("#{$0}: Version: #{version_number}")
|
113
|
+
exit(0)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Define a flag redirecting one of the standard IO files.
|
118
|
+
def define_redirect_flag(variable, name, mode)
|
119
|
+
@options.on("-#{name[0,1]}", "--#{name} FILE", String, "Redirect standard #{name} to a file.") do |file|
|
120
|
+
eval("#{variable} = Application::redirect_file(#{variable}, file, mode)")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Redirect a standard file.
|
125
|
+
def self.redirect_file(default, file, mode)
|
126
|
+
return default if file.nil? || file == "-"
|
127
|
+
FileUtils.mkdir_p(File.dirname(File.expand_path(file))) if mode == "w"
|
128
|
+
return File.open(file, mode)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Return the application's version. This is expected to be overriden by the
|
132
|
+
# concrete application sub-class. In the base class, we just return Olag's
|
133
|
+
# version which only useful for Olag's tests.
|
134
|
+
def version
|
135
|
+
return Olag::VERSION
|
136
|
+
end
|
137
|
+
|
138
|
+
# Print all the collected errors.
|
139
|
+
def print_errors
|
140
|
+
@errors.each do |error|
|
141
|
+
$stderr.puts(error)
|
142
|
+
end
|
143
|
+
return @errors.size
|
144
|
+
end
|
145
|
+
|
146
|
+
# Exit the application, unless we are running inside a test.
|
147
|
+
def exit(status)
|
148
|
+
Kernel.exit(status) unless @is_test
|
149
|
+
raise ExitException.new(status)
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# Exception used to exit when running inside tests.
|
155
|
+
class ExitException < Exception
|
156
|
+
|
157
|
+
# The exit status.
|
158
|
+
attr_reader :status
|
159
|
+
|
160
|
+
# Create a new exception to indicate exiting the program with some status.
|
161
|
+
def initialize(status)
|
162
|
+
@status = status
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|