rutema 2.0.1 → 2.0.2
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 +4 -4
- data/History.txt +4 -2
- data/README.md +12 -12
- data/bin/rutema +4 -4
- data/lib/rutema/application.rb +34 -31
- data/lib/rutema/core/configuration.rb +123 -117
- data/lib/rutema/core/engine.rb +101 -113
- data/lib/rutema/core/framework.rb +54 -54
- data/lib/rutema/core/objectmodel.rb +101 -90
- data/lib/rutema/core/parser.rb +8 -8
- data/lib/rutema/core/reporter.rb +78 -68
- data/lib/rutema/core/runner.rb +116 -97
- data/lib/rutema/elements/minimal.rb +29 -25
- data/lib/rutema/parsers/xml.rb +100 -93
- data/lib/rutema/reporters/json.rb +18 -20
- data/lib/rutema/reporters/junit.rb +88 -80
- data/lib/rutema/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce001ba104b5a1bb8b574e10a02a9d74d3a6af1e65b0e40b74aa5c41e6652451
|
|
4
|
+
data.tar.gz: 4e8c71a5ebb6f960a874d186bd555927699606045e2aba4e7f277e923fc5ba03
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d90e9c5bcb2adb9ebd6f6c9cdd1df33a30521796014d5bb6f451651ac096fa5a88d149a4bd5c398fc95e7f4cc98df0e65fd7bf7512feff01477a70cd031cc464
|
|
7
|
+
data.tar.gz: 68e7173406f270d158af6a2acca1066b3539937ae07c30affa46f6a9c9ebab8327c49a22e7ff67341bac39782b1fd83d662bb744b7a56b71b60e9a50fb5d08b1
|
data/History.txt
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
== 2.0.
|
|
1
|
+
== 2.0.2 /2026-03-26
|
|
2
|
+
* Modernize the code base. Code style updated, gem versions updated, ruby 3.x and 4.x deprecations handled
|
|
3
|
+
== 2.0.1/2026-03-02
|
|
2
4
|
* Release the 10 year old changes that fix handling of execution context within steps
|
|
3
|
-
== 2.0.0/
|
|
5
|
+
== 2.0.0 /2017-09-23
|
|
4
6
|
* Parsing behaviour has changed, parsing errors are not accepted and the run fails immediately
|
|
5
7
|
== 2.0.0.pre15 /2017-02-08
|
|
6
8
|
* Update gem dependencies
|
data/README.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
[](http://travis-ci.org/damphyr/rutema) [](https://coveralls.io/r/damphyr/rutema) [](https://codeclimate.com/github/damphyr/rutema)  [](https://badge.fury.io/rb/rutema)
|
|
1
|
+
# rutema
|
|
3
2
|
|
|
4
|
-
rutema [
|
|
3
|
+
[](https://dl.circleci.com/status-badge/redirect/gh/damphyr/rutema/tree/master) [](https://coveralls.io/r/damphyr/rutema) [](https://qlty.sh/gh/damphyr/projects/rutema)  [](https://badge.fury.io/rb/rutema)
|
|
5
4
|
|
|
6
|
-
rutema is a test execution tool and a framework for organizing and managing test execution across different tools.
|
|
5
|
+
rutema [http://github.com/damphyr/rutema](http://github.com/damphyr/rutema) is a test execution tool and a framework for organizing and managing test execution across different tools.
|
|
7
6
|
|
|
8
7
|
It enables the combination of different test tools while it takes care of logging, reporting, archiving of results and formalizes execution of automated and manual tests.
|
|
9
8
|
|
|
10
|
-
It's purpose is to make testing in heterogeneous environments easier.
|
|
9
|
+
It's purpose is to make testing in heterogeneous environments easier.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
## Why?
|
|
13
12
|
|
|
14
13
|
Require consistency, repeatability and reliability from your test infrastructure while gathering data on every run.
|
|
15
14
|
|
|
@@ -17,15 +16,15 @@ Whether running through a checklist of manual steps, or executing a sequence of
|
|
|
17
16
|
|
|
18
17
|
rutema will gather all logs, timestamp them, store them and report on them.
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
rutema core provides a reference implementation of a parser for a simple but extensible XML test specification format which works well out of the box but the framework provides clearly defined interfaces so you can write the parser for your own format and add reporters that log wherever is needed.
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
## The dry stuff
|
|
23
22
|
|
|
24
23
|
* Unified test execution environment for automated and manual tests
|
|
25
24
|
* Extensible reports and notifications in various formats (email, rss, pdf, html etc.)
|
|
26
25
|
* A well defined way to create a project specific test specification format
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
## Further Reading
|
|
29
28
|
|
|
30
29
|
* [Configuring rutema](doc/CONFIGURATION.md)
|
|
31
30
|
* An [example](doc/EXAMPLE.md) of a (very simple) testing DSL with rutema
|
|
@@ -38,14 +37,15 @@ Rutema core provides a reference implementation of a parser for a simple but ext
|
|
|
38
37
|
## Dependencies
|
|
39
38
|
|
|
40
39
|
The core functionality of rutema depends on the following gems:
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
|
|
41
|
+
* [patir](http://github.com/damphyr/patir)
|
|
42
|
+
* [highline](http://highline.rubyforge.org/)
|
|
43
43
|
|
|
44
44
|
## License
|
|
45
45
|
|
|
46
46
|
(The MIT License)
|
|
47
47
|
|
|
48
|
-
Copyright (c) 2007-
|
|
48
|
+
Copyright (c) 2007-2026 Vassilis Rizopoulos
|
|
49
49
|
|
|
50
50
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
51
51
|
a copy of this software and associated documentation files (the
|
data/bin/rutema
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
# Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
|
|
4
4
|
|
|
5
|
-
require
|
|
5
|
+
require "rutema/application"
|
|
6
6
|
begin
|
|
7
|
-
|
|
7
|
+
Rutema::App.new(ARGV)
|
|
8
8
|
rescue Rutema::RutemaError
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
puts $!.message
|
|
10
|
+
exit 1
|
|
11
11
|
end
|
data/lib/rutema/application.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Copyright (c) 2021 Vassilis Rizopoulos. All rights reserved.
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "optparse"
|
|
4
4
|
|
|
5
5
|
require_relative "core/configuration"
|
|
6
6
|
require_relative "core/engine"
|
|
@@ -15,17 +15,17 @@ module Rutema
|
|
|
15
15
|
##
|
|
16
16
|
# Configure and start the application flow according to the passed
|
|
17
17
|
# commandline options
|
|
18
|
-
def initialize
|
|
18
|
+
def initialize(command_line_args)
|
|
19
19
|
parse_command_line(command_line_args)
|
|
20
|
-
@configuration=Rutema::Configuration.new(@config_file)
|
|
21
|
-
@configuration.context||={}
|
|
22
|
-
@configuration.context[:config_file]=File.expand_path(@config_file)
|
|
23
|
-
@configuration.context[:config_name]=File.basename(@config_file)
|
|
24
|
-
@configuration.context[:start_time]=Time.now
|
|
25
|
-
@configuration.reporters||={}
|
|
26
|
-
@configuration.reporters[Rutema::Reporters::Console]||={:class=>Rutema::Reporters::Console, "silent"
|
|
27
|
-
@configuration.reporters[Rutema::Reporters::Summary]||={:class=>Rutema::Reporters::Summary, "silent"=>
|
|
28
|
-
@engine=Rutema::Engine.new(@configuration)
|
|
20
|
+
@configuration = Rutema::Configuration.new(@config_file)
|
|
21
|
+
@configuration.context ||= {}
|
|
22
|
+
@configuration.context[:config_file] = File.expand_path(@config_file)
|
|
23
|
+
@configuration.context[:config_name] = File.basename(@config_file)
|
|
24
|
+
@configuration.context[:start_time] = Time.now
|
|
25
|
+
@configuration.reporters ||= {}
|
|
26
|
+
@configuration.reporters[Rutema::Reporters::Console] ||= { :class => Rutema::Reporters::Console, "silent" => @silent } unless @bare
|
|
27
|
+
@configuration.reporters[Rutema::Reporters::Summary] ||= { :class => Rutema::Reporters::Summary, "silent" => @silent || @bare }
|
|
28
|
+
@engine = Rutema::Engine.new(@configuration)
|
|
29
29
|
application_flow
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -34,30 +34,34 @@ module Rutema
|
|
|
34
34
|
##
|
|
35
35
|
# Define the available commandline options and parse the given commandline
|
|
36
36
|
# accordingly
|
|
37
|
-
def parse_command_line
|
|
37
|
+
def parse_command_line(args)
|
|
38
38
|
args.options do |opt|
|
|
39
39
|
opt.on("rutema v#{Version::STRING}")
|
|
40
40
|
opt.on("Options:")
|
|
41
|
-
opt.on("--config FILE", "-c FILE",String,"Loads the configuration from FILE") { |config_file| @config_file=config_file}
|
|
42
|
-
opt.on("--check","Runs just the suite setup test"){@check=true}
|
|
43
|
-
#opt.on("--step","Runs test cases step by step"){@step=true}
|
|
44
|
-
opt.on("--silent","Suppresses console output (only for the default reporters)") { @silent=true}
|
|
45
|
-
opt.on("--bare","No default reporters whatsoever") { @bare=true}
|
|
46
|
-
#opt.on("--color","Adds color to the Console reporter") { @color=true}
|
|
47
|
-
opt.on("-v", "--version","Displays the version")
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
opt.on("--config FILE", "-c FILE", String, "Loads the configuration from FILE") { |config_file| @config_file = config_file }
|
|
42
|
+
opt.on("--check", "Runs just the suite setup test") { @check = true }
|
|
43
|
+
# opt.on("--step","Runs test cases step by step"){@step=true}
|
|
44
|
+
opt.on("--silent", "Suppresses console output (only for the default reporters)") { @silent = true }
|
|
45
|
+
opt.on("--bare", "No default reporters whatsoever") { @bare = true }
|
|
46
|
+
# opt.on("--color","Adds color to the Console reporter") { @color=true}
|
|
47
|
+
opt.on("-v", "--version", "Displays the version") do
|
|
48
|
+
$stdout.puts("rutema v#{Version::STRING}")
|
|
49
|
+
exit 0
|
|
50
|
+
end
|
|
51
|
+
opt.on("--help", "-h", "-?", "This text") do
|
|
52
|
+
$stdout.puts opt
|
|
53
|
+
exit 0
|
|
54
|
+
end
|
|
55
|
+
opt.on("--debug", "-d", "Turn on debug messages") { $DEBUG = true }
|
|
50
56
|
opt.on("You can provide a specification filename in order to run a single test")
|
|
51
57
|
opt.parse!
|
|
52
|
-
#and now the rest
|
|
58
|
+
# and now the rest
|
|
53
59
|
unless @config_file
|
|
54
60
|
puts "No configuration file defined!\n"
|
|
55
|
-
$stdout.puts opt
|
|
61
|
+
$stdout.puts opt
|
|
56
62
|
exit 1
|
|
57
63
|
end
|
|
58
|
-
|
|
59
|
-
@test_identifier=args.shift
|
|
60
|
-
end
|
|
64
|
+
@test_identifier = args.shift unless args.empty?
|
|
61
65
|
end
|
|
62
66
|
end
|
|
63
67
|
|
|
@@ -66,11 +70,10 @@ module Rutema
|
|
|
66
70
|
def application_flow
|
|
67
71
|
if @check
|
|
68
72
|
# run just the suite setup test if requested
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
end
|
|
73
|
+
raise Rutema::RutemaError, "There is no suite setup test defined in the configuration." unless @configuration.suite_setup
|
|
74
|
+
|
|
75
|
+
exit @engine.run(@configuration.suite_setup)
|
|
76
|
+
|
|
74
77
|
else
|
|
75
78
|
# run everything
|
|
76
79
|
exit @engine.run(@test_identifier)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
require "ostruct"
|
|
4
|
+
require_relative "parser"
|
|
5
|
+
require_relative "reporter"
|
|
6
|
+
module Rutema
|
|
7
7
|
##
|
|
8
8
|
# Mix-in module defining all configuration directives available for rutema
|
|
9
9
|
#
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
# the language including _require_ directives.
|
|
17
17
|
#
|
|
18
18
|
# require "rake/file_list"
|
|
19
|
-
#
|
|
19
|
+
#
|
|
20
20
|
# configure do |cfg|
|
|
21
21
|
# cfg.parser = { :class => Rutema::Parsers::XML }
|
|
22
22
|
# cfg.tests = FileList['all/of/the/tests/**/*.*']
|
|
23
23
|
# end
|
|
24
|
-
|
|
24
|
+
module ConfigurationDirectives
|
|
25
25
|
##
|
|
26
26
|
# Hash of context data which may be utilized throughout test runs
|
|
27
27
|
#
|
|
@@ -99,10 +99,11 @@
|
|
|
99
99
|
# The path to NUnit can be accessed the following way:
|
|
100
100
|
#
|
|
101
101
|
# @configuration.tools["nunit"][:path]
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
def tool=(definition)
|
|
103
|
+
raise ConfigurationException, "required key :name is missing from #{definition}" unless definition[:name]
|
|
104
|
+
|
|
105
|
+
@tools[definition[:name]] = definition
|
|
106
|
+
end
|
|
106
107
|
|
|
107
108
|
##
|
|
108
109
|
# Add a path indexed by a representative name to the paths attribute
|
|
@@ -118,11 +119,12 @@
|
|
|
118
119
|
# configure do |cfg|
|
|
119
120
|
# cfg.path = { :name => "doc", :path => "/usr/local/share/doc" }
|
|
120
121
|
# end
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
def path=(definition)
|
|
123
|
+
raise ConfigurationException, "required key :name is missing from #{definition}" unless definition[:name]
|
|
124
|
+
raise ConfigurationException, "required key :path is missing from #{definition}" unless definition[:path]
|
|
125
|
+
|
|
126
|
+
@paths[definition[:name]] = definition[:path]
|
|
127
|
+
end
|
|
126
128
|
|
|
127
129
|
##
|
|
128
130
|
# Path to a setup specification (optional)
|
|
@@ -130,9 +132,9 @@
|
|
|
130
132
|
# This setup specification will be run before every test specification.
|
|
131
133
|
#
|
|
132
134
|
# Later calls override earlier ones.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
def setup=(path)
|
|
136
|
+
@setup = check_path(path)
|
|
137
|
+
end
|
|
136
138
|
|
|
137
139
|
##
|
|
138
140
|
# Path to a teardown specification (optional)
|
|
@@ -140,9 +142,9 @@
|
|
|
140
142
|
# This teardown specification will be run after every test specification.
|
|
141
143
|
#
|
|
142
144
|
# Later calls override earlier ones.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
def teardown=(path)
|
|
146
|
+
@teardown = check_path(path)
|
|
147
|
+
end
|
|
146
148
|
|
|
147
149
|
##
|
|
148
150
|
# Path to a suite setup specification (optional)
|
|
@@ -154,12 +156,12 @@
|
|
|
154
156
|
# This is aliased as #check= for backwards compatibility.
|
|
155
157
|
#
|
|
156
158
|
# Later calls override earlier ones.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
def suite_setup=(path)
|
|
160
|
+
@suite_setup = check_path(path)
|
|
161
|
+
end
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
alias check suite_setup
|
|
164
|
+
alias check= suite_setup=
|
|
163
165
|
|
|
164
166
|
##
|
|
165
167
|
# Path to a suite teardown specification (optional)
|
|
@@ -168,9 +170,9 @@
|
|
|
168
170
|
# specifications have been executed.
|
|
169
171
|
#
|
|
170
172
|
# Later calls override earlier ones.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
def suite_teardown=(path)
|
|
174
|
+
@suite_teardown = check_path(path)
|
|
175
|
+
end
|
|
174
176
|
|
|
175
177
|
##
|
|
176
178
|
# Context information which shall be accessible during test execution
|
|
@@ -180,20 +182,21 @@
|
|
|
180
182
|
#
|
|
181
183
|
# This could be used e.g. to pass data as tester names, version numbers,
|
|
182
184
|
# etc. to the reporters.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
def context=(definition)
|
|
186
|
+
@context ||= {}
|
|
187
|
+
raise ConfigurationException, "Only accepting hash values as context_data" unless definition.is_a?(Hash)
|
|
188
|
+
|
|
189
|
+
@context.merge!(definition)
|
|
190
|
+
end
|
|
188
191
|
|
|
189
192
|
##
|
|
190
193
|
# Add an array of (paths of) test specifications to be executed
|
|
191
194
|
#
|
|
192
195
|
# Usually an array of file paths would be given. Generally the passed array
|
|
193
196
|
# can contain anything intelligible for the parser.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
def tests=(array_of_identifiers)
|
|
198
|
+
@tests += array_of_identifiers.map { |f| full_path(f) }
|
|
199
|
+
end
|
|
197
200
|
|
|
198
201
|
##
|
|
199
202
|
# Set the parser class which shall be used to parse test specifications
|
|
@@ -208,10 +211,11 @@
|
|
|
208
211
|
# configure do |cfg|
|
|
209
212
|
# cfg.parser = { :class => Rutema::Parsers::XML }
|
|
210
213
|
# end
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
def parser=(definition)
|
|
215
|
+
raise ConfigurationException, "required key :class is missing from #{definition}" unless definition[:class]
|
|
216
|
+
|
|
217
|
+
@parser = definition
|
|
218
|
+
end
|
|
215
219
|
|
|
216
220
|
##
|
|
217
221
|
# Set the runner which shall be used to execute the tests
|
|
@@ -229,10 +233,11 @@
|
|
|
229
233
|
# configure do |cfg|
|
|
230
234
|
# cfg.runner = { :class => Rutema::Runners::Default }
|
|
231
235
|
# end
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
def runner=(definition)
|
|
237
|
+
raise ConfigurationException, "required key :class is missing from #{definition}" unless definition[:class]
|
|
238
|
+
|
|
239
|
+
@runner = definition
|
|
240
|
+
end
|
|
236
241
|
|
|
237
242
|
##
|
|
238
243
|
# Add a reporter for the test execution
|
|
@@ -248,47 +253,50 @@
|
|
|
248
253
|
# cfg.reporters = { :class => Rutema::Reporters::Console }
|
|
249
254
|
# cfg.reporters = { :class => Rutema::Reporters::JUnit }
|
|
250
255
|
# end
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
def reporter=(definition)
|
|
257
|
+
raise ConfigurationException, "required key :class is missing from #{definition}" unless definition[:class]
|
|
258
|
+
|
|
259
|
+
@reporters[definition[:class]] = definition
|
|
260
|
+
end
|
|
255
261
|
|
|
256
262
|
##
|
|
257
263
|
# Initialize member variables which are needed to process a configuration
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
def init
|
|
265
|
+
@reporters = {}
|
|
266
|
+
@context = {}
|
|
267
|
+
@tests = []
|
|
268
|
+
@tools = OpenStruct.new
|
|
269
|
+
@paths = OpenStruct.new
|
|
270
|
+
end
|
|
265
271
|
|
|
266
|
-
|
|
272
|
+
private
|
|
267
273
|
|
|
268
274
|
##
|
|
269
275
|
# Check if the given path exists and raise a ConfigurationException if not
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
def check_path(path)
|
|
277
|
+
path = File.expand_path(path)
|
|
278
|
+
raise ConfigurationException, "#{path} does not exist" unless File.exist?(path)
|
|
279
|
+
|
|
280
|
+
return path
|
|
281
|
+
end
|
|
275
282
|
|
|
276
283
|
##
|
|
277
284
|
# Return a string in the form of "key=value,key=value" for a given hash
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
285
|
+
def definition_string(definition)
|
|
286
|
+
msg = definition.map { |k, v| "#{k}=#{v}" }
|
|
287
|
+
# definition.each { |k, v| msg << "#{k}=#{v}" }
|
|
288
|
+
return msg.join(",")
|
|
289
|
+
end
|
|
283
290
|
|
|
284
291
|
##
|
|
285
292
|
# Convert the given filename to an absolute path if the file exists or
|
|
286
293
|
# otherwise return the passed filename as is
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
294
|
+
def full_path(filename)
|
|
295
|
+
return File.expand_path(filename) if File.exist?(filename)
|
|
296
|
+
|
|
297
|
+
return filename
|
|
291
298
|
end
|
|
299
|
+
end
|
|
292
300
|
|
|
293
301
|
##
|
|
294
302
|
# Exception which is being raised upon errors concerning configurations passed
|
|
@@ -299,8 +307,8 @@
|
|
|
299
307
|
# * a file or path could not be found/does not exist
|
|
300
308
|
# * passed hash arguments being of an unexpected/unhandled type
|
|
301
309
|
# * passed hash arguments missing required keys
|
|
302
|
-
|
|
303
|
-
|
|
310
|
+
class ConfigurationException < RuntimeError
|
|
311
|
+
end
|
|
304
312
|
|
|
305
313
|
##
|
|
306
314
|
# Class for reading, parsing and representing the configuration for a rutema
|
|
@@ -310,24 +318,24 @@
|
|
|
310
318
|
# component which tests to execute how.
|
|
311
319
|
#
|
|
312
320
|
# Rutema::ConfigurationDirectives defines all relevant methods and attributes.
|
|
313
|
-
|
|
314
|
-
|
|
321
|
+
class Configuration
|
|
322
|
+
include ConfigurationDirectives
|
|
315
323
|
|
|
316
324
|
##
|
|
317
325
|
# The filename of the root configuration file from which the Configuration
|
|
318
326
|
# instance was built
|
|
319
|
-
|
|
327
|
+
attr_reader :filename
|
|
320
328
|
|
|
321
329
|
##
|
|
322
330
|
# Create a new instance by parsing the given configuration file
|
|
323
331
|
#
|
|
324
332
|
# * +config_file+ - the configuration file which shall be parsed on
|
|
325
333
|
# initializing the new instance
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
334
|
+
def initialize(config_file)
|
|
335
|
+
@filename = config_file
|
|
336
|
+
init
|
|
337
|
+
load_configuration(@filename)
|
|
338
|
+
end
|
|
331
339
|
|
|
332
340
|
##
|
|
333
341
|
# Yield the instance itself if a block is given
|
|
@@ -335,11 +343,11 @@
|
|
|
335
343
|
# This can be used e.g. in configuration files to execute a block on the
|
|
336
344
|
# Configuration instance itself (e.g. to modify it through the setter
|
|
337
345
|
# methods of the ConfigurationDirectives module).
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
346
|
+
def configure
|
|
347
|
+
return unless block_given?
|
|
348
|
+
|
|
349
|
+
yield self
|
|
350
|
+
end
|
|
343
351
|
|
|
344
352
|
##
|
|
345
353
|
# Load and import the configuration from a file
|
|
@@ -353,42 +361,40 @@
|
|
|
353
361
|
# the specialized configurations can import the "main.rutema" as follows:
|
|
354
362
|
#
|
|
355
363
|
# import("main.rutema")
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
+
def import(filename)
|
|
365
|
+
fnm = File.expand_path(filename)
|
|
366
|
+
raise ConfigurationException, "Import error: Can't find #{fnm}" unless File.exist?(fnm)
|
|
367
|
+
|
|
368
|
+
load_configuration(fnm)
|
|
369
|
+
end
|
|
364
370
|
|
|
365
|
-
|
|
371
|
+
private
|
|
366
372
|
|
|
367
373
|
##
|
|
368
374
|
# Load the configuration from the file given by +filename+
|
|
369
375
|
#
|
|
370
376
|
# On many common parsing errors a ConfigurationException is being raised.
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
end
|
|
377
|
+
def load_configuration(filename)
|
|
378
|
+
cfg_txt = File.read(filename)
|
|
379
|
+
cwd = File.expand_path(File.dirname(filename))
|
|
380
|
+
# WORKAROUND for ruby 2.3.1
|
|
381
|
+
fname = File.basename(filename)
|
|
382
|
+
# evaluate in the working directory to enable relative paths in
|
|
383
|
+
# configuration
|
|
384
|
+
# rubocop:disable Security/Eval
|
|
385
|
+
Dir.chdir(cwd) { eval(cfg_txt, binding, fname, __LINE__) }
|
|
386
|
+
# rubocop:enable Security/Eval
|
|
387
|
+
rescue ConfigurationException
|
|
388
|
+
# pass it on, do not wrap again
|
|
389
|
+
raise
|
|
390
|
+
rescue SyntaxError
|
|
391
|
+
# just wrap the exception so we can differentiate
|
|
392
|
+
raise ConfigurationException.new, "Syntax error in the configuration file '#{filename}':\n#{$!.message}"
|
|
393
|
+
rescue NoMethodError
|
|
394
|
+
raise ConfigurationException.new, "Encountered an unknown directive in configuration file '#{filename}':\n#{$!.message}"
|
|
395
|
+
rescue StandardError
|
|
396
|
+
# just wrap the exception so we can differentiate
|
|
397
|
+
raise ConfigurationException.new, $!.message
|
|
393
398
|
end
|
|
394
399
|
end
|
|
400
|
+
end
|