laborantin 0.0.14 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/INFO +1 -0
  2. data/README +148 -4
  3. data/Rakefile +73 -27
  4. data/TODO +27 -6
  5. data/bin/labor +2 -404
  6. data/lib/laborantin.rb +13 -26
  7. data/lib/laborantin/core/analysis.rb +231 -0
  8. data/lib/laborantin/core/command.rb +234 -0
  9. data/lib/laborantin/core/completeable.rb +30 -0
  10. data/lib/laborantin/core/configurable.rb +28 -0
  11. data/lib/laborantin/core/datable.rb +13 -0
  12. data/lib/laborantin/core/describable.rb +11 -0
  13. data/lib/laborantin/core/environment.rb +90 -52
  14. data/lib/laborantin/core/hookable.rb +20 -0
  15. data/lib/laborantin/core/monkey_patches.rb +0 -1
  16. data/lib/laborantin/core/multi_name.rb +25 -0
  17. data/lib/laborantin/core/parameter.rb +5 -12
  18. data/lib/laborantin/core/parameter_hash.rb +6 -2
  19. data/lib/laborantin/core/scenario.rb +93 -70
  20. data/lib/laborantin/core/table.rb +84 -0
  21. data/lib/laborantin/extra/commands/git.rb +40 -0
  22. data/lib/laborantin/extra/commands/git/check.rb +25 -0
  23. data/lib/laborantin/extra/commands/git/run.rb +100 -0
  24. data/lib/laborantin/extra/vectorial_product.rb +31 -0
  25. data/lib/laborantin/runner.rb +247 -0
  26. data/lib/laborantin/runner/commands/analyze.rb +58 -0
  27. data/lib/laborantin/runner/commands/cleanup.rb +40 -0
  28. data/lib/laborantin/runner/commands/complete.rb +111 -0
  29. data/lib/laborantin/runner/commands/config.rb +169 -0
  30. data/lib/laborantin/runner/commands/create.rb +61 -0
  31. data/lib/laborantin/runner/commands/describe.rb +215 -0
  32. data/lib/laborantin/runner/commands/find.rb +82 -0
  33. data/lib/laborantin/runner/commands/load_classes.rb +75 -0
  34. data/lib/laborantin/runner/commands/load_results.rb +143 -0
  35. data/lib/laborantin/runner/commands/note.rb +35 -0
  36. data/lib/laborantin/runner/commands/replay.rb +89 -0
  37. data/lib/laborantin/runner/commands/rm.rb +107 -0
  38. data/lib/laborantin/runner/commands/run.rb +131 -0
  39. data/lib/laborantin/runner/commands/scan.rb +77 -0
  40. metadata +45 -13
  41. data/bin/files/README.erb +0 -29
  42. data/bin/files/TODO.erb +0 -2
  43. data/bin/files/config/ftp.yaml.erb +0 -6
  44. data/bin/files/config/xmpp.yaml.erb +0 -7
  45. data/bin/files/environments/environment.rb.erb +0 -10
  46. data/bin/files/scenarii/scenario.rb.erb +0 -13
@@ -0,0 +1,30 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module Completeable
5
+ # A block to propose completion on this option
6
+ attr_reader :completion_block
7
+
8
+ # Stores the block argument in the completion_block, usage is for DSLs
9
+ def complete(&blk)
10
+ @completion_block = blk
11
+ end
12
+
13
+
14
+ # Provides completion facility for comma-separated lists of args, and returns the propositions
15
+ # - removes items already in list
16
+ # - prepends commas for items not already in list
17
+ def completion_propositions_iterating_on(cmd, list)
18
+ envs_on_cli = cmd.split.last.split(',').reject{|s| s.start_with?('-')}
19
+ last_env_on_cli = envs_on_cli.last unless cmd.end_with?(',')
20
+ last_env_on_cli ||= ''
21
+ complete_envs_on_cli = envs_on_cli - [last_env_on_cli]
22
+
23
+ list = list.select{|str| str.start_with?(last_env_on_cli)}
24
+ candidate_envs = list - envs_on_cli
25
+ candidate_envs.map{|str| (complete_envs_on_cli + [str]).join(',') }
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module Configurable
5
+ # A hash placeholder for extra config (e.g. git revision for the git implementation)
6
+ attr_accessor :config
7
+
8
+ # saves the @config in a YAML config file
9
+ def save_config
10
+ File.open(config_path, 'w') do |f|
11
+ f.puts YAML.dump(config)
12
+ end
13
+ end
14
+
15
+ # restore the configuration from the config file
16
+ def load_config!(path=config_path)
17
+ if File.file?(path)
18
+ @config = YAML.load_file(path)
19
+ end
20
+ @config ||= {}
21
+ end
22
+
23
+ def config_path
24
+ "config.yaml"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module Datable
5
+ attr_accessor :date
6
+
7
+ # Format the date of as a string (rounded at 1second).
8
+ def date_str
9
+ date.strftime("%Y-%h-%d_%H-%M-%S")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module Describable
5
+ # A description used for printing summary and debug purposes.
6
+ attr_accessor :description
7
+
8
+ alias :describe :description=
9
+ end
10
+ end
11
+ end
@@ -21,9 +21,15 @@ Copyright (c) 2009, Lucas Di Cioccio
21
21
 
22
22
  =end
23
23
 
24
- require 'time'
25
- require 'logger'
26
- require 'fileutils'
24
+ autoload :Time, 'time'
25
+ autoload :Logger, 'logger'
26
+ autoload :FileUtils, 'fileutils'
27
+
28
+ require 'laborantin/core/datable'
29
+ require 'laborantin/core/describable'
30
+ require 'laborantin/core/hookable'
31
+ require 'laborantin/core/configurable'
32
+ require 'laborantin/core/multi_name'
27
33
 
28
34
  module Laborantin
29
35
 
@@ -37,26 +43,38 @@ module Laborantin
37
43
  # If you want to do that, you must know that Environment @@all class variable
38
44
  # holds a reference to every child class from Environment.
39
45
  class Environment
46
+ include Metaprog::Datable
47
+ include Metaprog::Configurable
48
+ extend Metaprog::Describable
49
+ extend Metaprog::Hookable
50
+ extend Metaprog::MultiName
51
+
40
52
  @@all = []
41
53
 
42
54
  # Populates loaded (i.e. put in @@all class variable when self.inherited
43
55
  # is called) environment classes from existing results that are stored in
44
56
  # the dir parameter.
45
57
  def self.scan_resdir(dir)
46
- ret = []
58
+ list = []
47
59
  Dir.entries(dir).each do |f|
48
- envklass = Laborantin::Environment.all.find{|e| e.name.duck_case == f}
60
+ envklass = Laborantin::Environment.all.find{|e| e.fs_name == f}
49
61
  if envklass
50
62
  Dir.entries(envklass.envdir).each do |e|
51
63
  if e =~ /\d+-\w+-\d+_\d+-\d+-\d+/
52
- env = envklass.new #XXX don't prepare! it hence don't overwrite logs
53
- env.rundir = File.join(envklass.envdir, e)
54
- ret << env
64
+ env = envklass.new_loading_from_dir(File.join(envklass.envdir, e))
65
+ list << env
55
66
  end
56
67
  end
57
68
  end
58
69
  end
59
- ret
70
+ list
71
+ end
72
+
73
+ def self.new_loading_from_dir(path)
74
+ obj = self.new
75
+ obj.load_config!
76
+ obj.rundir = path
77
+ obj
60
78
  end
61
79
 
62
80
  class << self
@@ -66,15 +84,6 @@ module Laborantin
66
84
  # CURRENTLY NOT HERITED
67
85
  attr_accessor :verifications
68
86
 
69
- # A description used for printing summary and debug purposes. Will be
70
- # used to create .tex report in the future.
71
- # CURRENTLY NOT HERITED
72
- attr_accessor :description
73
-
74
- # A hash to store setup/teardown hooks.
75
- # CURRENTLY NOT HERITED
76
- attr_accessor :hooks
77
-
78
87
  # Prepares attributes' default values whenever a subclass is created.
79
88
  def inherited(klass)
80
89
  klass.verifications = []
@@ -83,40 +92,20 @@ module Laborantin
83
92
  @@all << klass
84
93
  end
85
94
 
86
- # Registers new verifiers.
95
+ # Registers new verifiers methods that will be verified at beginning.
87
96
  def verify(*args)
88
97
  self.verifications = [*args].flatten
89
98
  end
90
99
 
91
- # Sets the description.
92
- def describe(str)
93
- self.description = str
94
- end
95
-
96
- # Registers setup hooks, called before any scenario is instantiated.
97
- def setup(*args)
98
- self.hooks[:setup] = [*args].flatten
99
- end
100
-
101
- # Registers teardown hooks, called after every scenarii has been
102
- # performed and analyzed.
103
- def teardown(*args)
104
- self.hooks[:teardown] = [*args].flatten
105
- end
106
-
107
- def to_s
108
- "#{self.name}:\n\t#{self.description}"
109
- end
110
-
111
100
  # Returns all the known subklasses of Environment.
112
101
  def all
113
102
  @@all
114
103
  end
115
104
 
116
105
  # The path where the results for instance of a subklass of Environment
117
- # are stored (needs the Laborantin.resultdir).
106
+ # are stored (needs the Runner's resultdir).
118
107
  def envdir
119
- File.join(Laborantin.resultdir, self.name.duck_case)
108
+ File.join(Runner.instance.resultdir, self.fs_name)
120
109
  end
121
110
  end
122
111
 
@@ -124,28 +113,76 @@ module Laborantin
124
113
  # are stored. Can be overridden (e.g. Environment.scan_resdir does that).
125
114
  attr_accessor :rundir
126
115
 
127
- # A date that holds the creation of the instance, it is not meaningful
128
- # when an env was created by a call to Environment.scan_resdir.
129
- # TODO better
130
- attr_accessor :date
131
-
132
116
  # An array of loggers objects.
133
117
  attr_accessor :loggers
134
118
 
135
- def initialize
119
+ # The (optional) commmand instanciating this environment
120
+ attr_accessor :command
121
+
122
+ # Initializes a new instance:
123
+ # the date is Time.now
124
+ # the rundir is the Environment.envdir followed by the date_str
125
+ # the loggers contains an empty Array
126
+ # Does NOT create any directory, so the accessors can be overwritten if needed.
127
+ def initialize(command=nil)
128
+ @command = command
136
129
  @date = Time.now
137
130
  @rundir = File.join(self.class.envdir, date_str)
138
131
  @loggers = []
132
+ @config = {}
139
133
  end
140
134
 
135
+ def runner
136
+ command.runner if command
137
+ end
138
+
139
+ # sends all the methods registered in Environment.verify
140
+ # returns the method symbol of the failed verification if any
141
141
  def valid?
142
142
  self.class.verifications.find{|v| not send(v)}.nil?
143
143
  end
144
144
 
145
+ # complete path to the environment.log file
145
146
  def logfile_path
146
147
  File.join(rundir, 'environment.log')
147
148
  end
148
149
 
150
+ # complete path to the config.yaml file
151
+ def config_path
152
+ File.join(rundir, 'config.yaml')
153
+ end
154
+
155
+ def scenarii_dirs
156
+ config[:scenarii_dirs]
157
+ end
158
+
159
+ def record_scenario_dir(dir, save=false)
160
+ config[:scenarii_dirs] ||= []
161
+ config[:scenarii_dirs] << dir
162
+ save_config if save
163
+ end
164
+
165
+ # gets the state of the environment
166
+ def state
167
+ config[:state]
168
+ end
169
+
170
+ # changes the state of the environment
171
+ def state=(val, save=true)
172
+ config[:state] = val
173
+ save_config if save
174
+ end
175
+
176
+ # returns if the environment succeeded
177
+ def successful?
178
+ config[:state] == :success
179
+ end
180
+
181
+ # returns if the environment exited with error
182
+ def failed?
183
+ config[:state] == :error
184
+ end
185
+
149
186
  # In the following order:
150
187
  # * Creates the envdir if needed.
151
188
  # * Adds some loggers.
@@ -159,6 +196,8 @@ module Laborantin
159
196
  @loggers << Logger.new(STDOUT)
160
197
  log(self.class.description, :info) unless self.class.description.empty?
161
198
  log "Directories prepared"
199
+ log "Writing config file"
200
+ save_config
162
201
  call_hooks :setup
163
202
  end
164
203
 
@@ -178,15 +217,14 @@ module Laborantin
178
217
  Laborantin::Scenario.scan_env(self)
179
218
  end
180
219
 
181
- def date_str
182
- date.strftime("%Y-%h-%d_%H-%M-%S")
183
- end
184
-
185
220
  private
186
221
 
187
222
  def call_hooks(name)
188
223
  log "Calling #{name} hooks"
189
- self.class.hooks[name].each{|sym| send sym}
224
+ self.class.hooks[name].each do |sym|
225
+ log "(#{sym})"
226
+ send sym
227
+ end
190
228
  end
191
229
 
192
230
  end # class
@@ -0,0 +1,20 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module Hookable
5
+ # A hash to store setup/teardown hooks.
6
+ attr_accessor :hooks
7
+
8
+ # Registers setup hooks.
9
+ def setup(*args)
10
+ hooks[:setup] = [*args].flatten
11
+ end
12
+
13
+ # Register teardown hooks.
14
+ def teardown(*args)
15
+ hooks[:teardown] = [*args].flatten
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -35,4 +35,3 @@ class String
35
35
  self.gsub(/([A-Z])/){|s| "_#{$1.downcase}"}.sub(/^_/,'')
36
36
  end
37
37
  end
38
-
@@ -0,0 +1,25 @@
1
+
2
+ module Laborantin
3
+ module Metaprog
4
+ module MultiName
5
+ AVAILABLE_NAMES = [:cli, :fs]
6
+
7
+ def set_name(sym, val)
8
+ raise ArgumentError, "invalid name sym: #{sym}, expected in #{AVAILABLE_NAMES.inspect}" unless AVAILABLE_NAMES.include?(sym)
9
+ send "#{sym}_name=", val
10
+ end
11
+
12
+ # a way to name on the command line
13
+ attr_writer :cli_name
14
+ def cli_name
15
+ @cli_name || name.duck_case
16
+ end
17
+
18
+ # a way to name on the filesystem
19
+ attr_writer :fs_name
20
+ def fs_name
21
+ @fs_name || name.duck_case
22
+ end
23
+ end
24
+ end
25
+ end
@@ -21,19 +21,20 @@ Copyright (c) 2009, Lucas Di Cioccio
21
21
 
22
22
  =end
23
23
 
24
+ require 'laborantin/core/describable'
25
+
24
26
  module Laborantin
25
27
 
26
28
  # A ParameterRange instance is more or less a wrapper over an Array of allowed values.
27
29
  class ParameterRange
28
30
 
31
+ include Metaprog::Describable
32
+
29
33
  # The name of the parameter (should be unique in a Scenario's parameters)
30
34
  # Usually a symbol.
31
35
  attr_accessor :name
32
36
 
33
- # A description used for printing summary and debug purposes. Will be
34
- # used to create .tex report in the future.
35
- attr_accessor :description
36
-
37
+ # initialize a new instance with the desired name
37
38
  def initialize(name)
38
39
  @name = name
39
40
  @values = []
@@ -54,13 +55,5 @@ module Laborantin
54
55
  end
55
56
  end
56
57
 
57
- # Sets the description.
58
- def describe(str)
59
- @description = str
60
- end
61
-
62
- def to_s
63
- "#{values.inspect}\n\t\t#{@description}"
64
- end
65
58
  end
66
59
  end
@@ -40,8 +40,12 @@ module Laborantin
40
40
  end
41
41
  end
42
42
 
43
- def to_s
44
- keys.inject(''){|s,k| s + "\t- #{k}: #{self[k]}.\n"}
43
+ def each_config_with_index
44
+ idx = 0
45
+ each_config do |cfg|
46
+ yield cfg, idx
47
+ idx += 1
48
+ end
45
49
  end
46
50
  end
47
51
  end
@@ -21,11 +21,18 @@ Copyright (c) 2009, Lucas Di Cioccio
21
21
 
22
22
  =end
23
23
 
24
- require File.join(File.dirname(__FILE__), 'parameter')
25
- require File.join(File.dirname(__FILE__), 'parameter_hash')
24
+ require 'laborantin/core/parameter'
25
+ require 'laborantin/core/parameter_hash'
26
26
 
27
- require 'fileutils'
28
- require 'yaml'
27
+ autoload :FileUtils, 'fileutils'
28
+ autoload :YAML, 'yaml'
29
+
30
+ require 'laborantin/core/datable'
31
+ require 'laborantin/core/describable'
32
+ require 'laborantin/core/hookable'
33
+ require 'laborantin/core/configurable'
34
+ require 'laborantin/core/multi_name'
35
+ require 'laborantin/core/table'
29
36
 
30
37
  module Laborantin
31
38
 
@@ -41,42 +48,45 @@ module Laborantin
41
48
  # Like the Environment, all the subklasses will be stored in a @@all
42
49
  # class variable for convenience purpose.
43
50
  class Scenario
51
+ include Metaprog::Datable
52
+ include Metaprog::Configurable
53
+ extend Metaprog::Describable
54
+ extend Metaprog::Hookable
55
+ extend Metaprog::MultiName
56
+
44
57
  @@all = []
45
58
 
46
59
  # Scans the env's envdir (should be an Environment) for scenarii results.
47
- # It will set their configuration according to the stored config.yaml
48
- # in YAML format.
49
- # Returns an array of such built scenarii.
60
+ # It will set their configuration (i.e. run date and parameters hash)
61
+ # according to the stored config.yaml in YAML format. Returns an array of
62
+ # such built scenarii.
50
63
  def self.scan_env(env)
51
- scs = []
64
+ list = []
52
65
  Dir.entries(env.rundir).each do |s|
53
- scklass = Laborantin::Scenario.all.find{|t| t.name.duck_case == s}
66
+ scklass = Laborantin::Scenario.all.find{|t| t.fs_name == s}
54
67
  if scklass
55
68
  Dir.entries(scklass.scenardir(env)).each do |r|
56
69
  if r =~ /\d+-\w+-\d+_\d+-\d+-\d+/
57
- scenar = scklass.new(env)
58
- scs << scenar
59
- scenar.rundir = File.join(scklass.scenardir(env), r)
60
- tst, params = YAML.load_file(File.join(scenar.rundir, 'config.yaml'))
61
- scenar.params = params
70
+ scenar = scklass.new_loading_from_dir(env, File.join(scklass.scenardir(env), r))
71
+ list << scenar
62
72
  end
63
73
  end
64
74
  end
65
75
  end
66
- scs
76
+ list
67
77
  end
68
78
 
69
- class << self
70
-
71
- # A description used for printing summary and debug purposes. Will be
72
- # used to create .tex report in the future.
73
- # CURRENTLY NOT HERITED
74
- attr_accessor :description
75
-
76
- # A hash to store setup/teardown hooks.
77
- # CURRENTLY NOT HERITED
78
- attr_accessor :hooks
79
+ def self.new_loading_from_dir(env, path)
80
+ obj = self.new(env)
81
+ yml_path = File.join(path, 'config.yaml')
82
+ tst, params = obj.load_config!(yml_path)
83
+ obj.params = params
84
+ obj.date = tst
85
+ obj.rundir = path
86
+ obj
87
+ end
79
88
 
89
+ class << self
80
90
  # The set of parameters that will vary for this Scenario.
81
91
  attr_accessor :parameters
82
92
 
@@ -95,21 +105,6 @@ module Laborantin
95
105
  @@all << klass
96
106
  end
97
107
 
98
- # Sets the description.
99
- def describe(str)
100
- self.description = str
101
- end
102
-
103
- # Registers setup hooks.
104
- def setup(*args)
105
- self.hooks[:setup] = [*args].flatten
106
- end
107
-
108
- # Register teardown hooks.
109
- def teardown(*args)
110
- self.hooks[:teardown] = [*args].flatten
111
- end
112
-
113
108
  # Defines a new ParameterRange instance for this Scenario.
114
109
  # A block should be passed that will be evaluated in this
115
110
  # ParameterRange instance's context.
@@ -133,10 +128,6 @@ module Laborantin
133
128
  self.products = [*args].flatten
134
129
  end
135
130
 
136
- def to_s
137
- "#{self.name}:\n\t#{self.description}\n#{self.parameters}"
138
- end
139
-
140
131
  # Returns all the known subklasses of Scenario.
141
132
  def all
142
133
  @@all
@@ -147,7 +138,7 @@ module Laborantin
147
138
  # will use '.' as rootdir for the Scenario results.
148
139
  def scenardir(env=nil)
149
140
  envdir = env.rundir || '.'
150
- File.join(envdir, self.name.duck_case)
141
+ File.join(envdir, self.fs_name)
151
142
  end
152
143
  end # class <<
153
144
 
@@ -157,19 +148,20 @@ module Laborantin
157
148
  # The environment in which we run this scenario.
158
149
  attr_accessor :environment
159
150
 
160
- # A date that holds the creation of the instance, it is not meaningful
161
- # when an env was created by a call to Environment.scan_resdir.
162
- # TODO better
163
- attr_accessor :date
164
-
165
151
  # An attribute that holds the directory where the config and the results
166
152
  # are stored. Can be overridden (e.g. Scenario.scan_env does that).
167
153
  attr_accessor :rundir
168
154
 
155
+ # Initializes a new instance contains in the env Environment, and
156
+ # for the parameter set params.
157
+ # Sets the date to Time.now for unicity (with 1sec granularity)
158
+ # Sets the rundir accessor in the directory.
159
+ # Does NOT create any directory, so the accessors can be overwritten if needed.
169
160
  def initialize(env, params={})
170
161
  @environment = env
171
162
  @params = params
172
163
  @date = Time.now
164
+ @config = {}
173
165
  @rundir = File.join(self.class.scenardir(environment), date_str)
174
166
  end
175
167
 
@@ -185,8 +177,10 @@ module Laborantin
185
177
  log self.params.inspect, :info
186
178
  log "Preparing directory #{rundir}"
187
179
  FileUtils.mkdir_p(rundir) #TODO: ensure unicity
180
+ environment.record_scenario_dir(rundir, true)
188
181
  log "Storing configuration in YAML format"
189
- File.open( config_path, 'w') {|f| f.puts YAML.dump( [date, params] ) }
182
+ @config = [date, params]
183
+ save_config
190
184
  end
191
185
 
192
186
  # In the following order:
@@ -216,53 +210,82 @@ module Laborantin
216
210
  # Appends each yielded line from this method.
217
211
  def analyze!
218
212
  self.class.products.each do |name|
219
- log "Producing #{name}"
213
+ log "(#{name})"
220
214
  product_file(name.to_s, 'w') do |f|
221
- send name do |l|
215
+ send(name) do |l|
222
216
  f.puts l
223
217
  end
224
218
  end
225
- log "Product #{name} done"
226
219
  end
227
220
  end
228
221
 
229
- def date_str
230
- date.strftime("%Y-%h-%d_%H-%M-%S")
231
- end
232
-
233
- private
234
-
235
- def call_hooks(name)
236
- log "Calling #{name} hooks"
237
- self.class.hooks[name].each{|sym| send sym}
238
- end
239
-
240
- def log(*args)
241
- environment.log *args
242
- end
243
-
222
+ # Returns the absolute path to a product file (see File.join) If brutname
223
+ # is true, then resultname is appended to the rundir of the scenario. If
224
+ # brutname is false, then before being appended to the rundir of the
225
+ # scenario, the name is surronded by result.<resultname>.txt
226
+ #
227
+ # The idea behind this is to avoid name collisions between simple users of
228
+ # Laborantin, and people developping extensions or modules.
244
229
  def product_path(resultname, brutname=false)
245
230
  resultname = "result.#{resultname}.txt" unless brutname
246
231
  File.join(rundir, resultname)
247
232
  end
248
233
 
234
+ # Yields an open file for a given product, will make sure it is closed.
235
+ # mode is the mode in which the file is opened (you should leave it to 'r')
236
+ # see the doc for product_path to understand the role of brutname
249
237
  def product_file(resultname, mode='r', brutname=false)
250
238
  File.open(product_path(resultname, brutname), mode) do |f|
251
239
  yield f
252
240
  end
253
241
  end
254
242
 
243
+ # The path to the config.yaml file that holds the scenario parameters.
255
244
  def config_path
256
245
  product_path('config.yaml', true)
257
246
  end
258
247
 
248
+ # The path to the "raw result", i.e. the one built when you yield in the
249
+ # run method.
259
250
  def raw_result_path
260
251
  product_path('result.raw', true)
261
252
  end
262
253
 
254
+ # Yield the opened raw result file, will close it afterwards.
255
+ # mode is the mode in which the file is opened (default to 'r')
256
+ # never open the file in another mode, unless you know what you're doing,
257
+ # because this file most likely contains the value of your work, i.e., your
258
+ # data.
263
259
  def raw_result_file(mode='r')
264
- product_file('result.raw', mode, true){|f| yield f}
260
+ product_file('result.raw', mode, true) do |f|
261
+ yield f
262
+ end
263
+ end
264
+
265
+ def table(name, struct)
266
+ Table.new(name, struct, self.product_path(name))
265
267
  end
266
268
 
269
+ private
270
+
271
+ def call_hooks(name)
272
+ log "Calling #{name} hooks"
273
+ self.class.hooks[name].each do |sym|
274
+ log "(#{sym})"
275
+ send sym
276
+ end
277
+ end
278
+
279
+ def log(*args)
280
+ environment.log *args
281
+ end
282
+
283
+ def command
284
+ environment.command
285
+ end
286
+
287
+ def runner
288
+ environment.runner
289
+ end
267
290
  end # class
268
291
  end