laborantin 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rake/gempackagetask'
3
3
 
4
4
  spec = Gem::Specification.new do |s|
5
5
  s.name = 'laborantin'
6
- s.version = '0.0.9'
6
+ s.version = '0.0.10'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.summary = "A measurement batch facilitator"
9
9
 
@@ -33,7 +33,7 @@ spec = Gem::Specification.new do |s|
33
33
  s.bindir = 'bin'
34
34
  s.executables = ['labor']
35
35
 
36
- s.has_rdoc = false
36
+ s.has_rdoc = true
37
37
  end
38
38
 
39
39
  Rake::GemPackageTask.new(spec) do |pkg|
data/TODO CHANGED
@@ -3,6 +3,4 @@ replay / pause / restart
3
3
  => interaction with rubydrill?
4
4
  => or direct stats
5
5
 
6
- export results via ftp
7
-
8
6
  creation of a script that doesn't depends on laborantin for export?
data/bin/labor CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'optparse'
4
3
  require 'rubygems'
5
4
  require 'laborantin'
6
5
  #require '../lib/laborantin'
6
+ require 'optparse'
7
7
  require 'fileutils'
8
8
  require 'find'
9
9
  require 'erb'
@@ -28,8 +28,27 @@ require File.join(File.dirname(__FILE__), 'laborantin', 'core', 'environment')
28
28
  require File.join(File.dirname(__FILE__), 'laborantin', 'core', 'monkey_patches')
29
29
 
30
30
  module Laborantin
31
- VERSION = '0.0.9'
31
+ VERSION = '0.0.10'
32
32
  AUTHORS = ['Lucas Di Cioccio']
33
33
  WEBSITE = 'http://dicioccio.fr'
34
34
  LICENSE = 'GNU GPL version 3'
35
+
36
+ @@rootdir = '.'
37
+
38
+ # The root of the arborescence for Laborantin. Usually the directory created
39
+ # via the scripts.
40
+ def self.rootdir
41
+ @@rootdir || '.'
42
+ end
43
+
44
+ # Specifies the rootdir, dir is a path (instance of String, not a Dir object).
45
+ def self.rootdir=(dir='.')
46
+ @@rootdir = dir
47
+ end
48
+
49
+ # The path to the results (needs the Laborantin.rootdir).
50
+ def self.resultdir
51
+ File.join(Laborantin.rootdir, 'results')
52
+ end
53
+
35
54
  end
@@ -26,10 +26,22 @@ require 'logger'
26
26
  require 'fileutils'
27
27
 
28
28
  module Laborantin
29
+
30
+ # An Environment represents the surrounding of an experiment. Basically, it
31
+ # should only contains things that are hard to change during an experiment.
32
+ # Let's say you have two computers, A and B. A can be a server and B a client
33
+ # or vice-versa. Hence, this is a good choice for two differents environments.
34
+ #
35
+ # As a normal user, you should only subclass Environment, and let the script
36
+ # creates it for you. But it is easy to monkey-patch or to subclass by hand.
37
+ # If you want to do that, you must know that Environment @@all class variable
38
+ # holds a reference to every child class from Environment.
29
39
  class Environment
30
40
  @@all = []
31
- @@rootdir = '.'
32
41
 
42
+ # Populates loaded (i.e. put in @@all class variable when self.inherited
43
+ # is called) environment classes from existing results that are stored in
44
+ # the dir parameter.
33
45
  def self.scan_resdir(dir)
34
46
  ret = []
35
47
  Dir.entries(dir).each do |f|
@@ -48,20 +60,22 @@ module Laborantin
48
60
  end
49
61
 
50
62
  class << self
51
- attr_accessor :verifications, :description, :envdir, :hooks
52
63
 
53
- def rootdir=(dir='.')
54
- @@rootdir = dir
55
- end
64
+ # An array of methods called to ensure that the environment run is the
65
+ # wanted one (e.g. a way to specify a RUBY_PLATFORM).
66
+ # CURRENTLY NOT HERITED
67
+ attr_accessor :verifications
56
68
 
57
- def rootdir
58
- @@rootdir || '.'
59
- end
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
60
73
 
61
- def resultdir
62
- @@resultdir = File.join(@@rootdir, 'results')
63
- end
74
+ # A hash to store setup/teardown hooks.
75
+ # CURRENTLY NOT HERITED
76
+ attr_accessor :hooks
64
77
 
78
+ # Prepares attributes' default values whenever a subclass is created.
65
79
  def inherited(klass)
66
80
  klass.verifications = []
67
81
  klass.description = ''
@@ -69,18 +83,23 @@ module Laborantin
69
83
  @@all << klass
70
84
  end
71
85
 
86
+ # Registers new verifiers.
72
87
  def verify(*args)
73
88
  self.verifications = [*args].flatten
74
89
  end
75
90
 
91
+ # Sets the description.
76
92
  def describe(str)
77
93
  self.description = str
78
94
  end
79
95
 
96
+ # Registers setup hooks, called before any scenario is instantiated.
80
97
  def setup(*args)
81
98
  self.hooks[:setup] = [*args].flatten
82
99
  end
83
100
 
101
+ # Registers teardown hooks, called after every scenarii has been
102
+ # performed and analyzed.
84
103
  def teardown(*args)
85
104
  self.hooks[:teardown] = [*args].flatten
86
105
  end
@@ -89,20 +108,31 @@ module Laborantin
89
108
  "#{self.name}:\n\t#{self.description}"
90
109
  end
91
110
 
111
+ # Returns all the known subklasses of Environment.
92
112
  def all
93
113
  @@all
94
114
  end
95
115
 
116
+ # The path where the results for instance of a subklass of Environment
117
+ # are stored (needs the Laborantin.resultdir).
96
118
  def envdir
97
- File.join(resultdir, self.name.duck_case)
119
+ File.join(Laborantin.resultdir, self.name.duck_case)
98
120
  end
99
-
100
121
  end
101
122
 
102
- #XXX: rundir is the easier way to override the rundir (instead of parsing a date)
103
- attr_accessor :rundir, :date, :loggers
123
+ # An attribute that holds the directory where the logfile and the scenarii results
124
+ # are stored. Can be overridden (e.g. Environment.scan_resdir does that).
125
+ attr_accessor :rundir
126
+
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
+ # An array of loggers objects.
133
+ attr_accessor :loggers
104
134
 
105
- def initialize(dir='.')
135
+ def initialize
106
136
  @date = Time.now
107
137
  @rundir = File.join(self.class.envdir, date_str)
108
138
  @loggers = []
@@ -112,6 +142,13 @@ module Laborantin
112
142
  self.class.verifications.find{|v| not send(v)}.nil?
113
143
  end
114
144
 
145
+ # In the following order:
146
+ # * Creates the envdir if needed.
147
+ # * Adds some loggers.
148
+ # * Calls the setup hooks methods
149
+ # BEWARE : currently does not ensure unicity of envdir,
150
+ # so wait one sec between several runs of same env
151
+ #
115
152
  def prepare!
116
153
  FileUtils.mkdir_p(rundir) #TODO: ensure unicity
117
154
  @loggers << Logger.new(File.join(rundir, 'environment.log'))
@@ -121,14 +158,18 @@ module Laborantin
121
158
  call_hooks :setup
122
159
  end
123
160
 
161
+ # Calls the teardown hooks methods.
124
162
  def teardown!
125
163
  call_hooks :teardown
126
164
  end
127
165
 
166
+ # Send str log message at the levele lvl to every loggers.
128
167
  def log(str, lvl=:debug)
129
168
  @loggers.each{|l| l.send(lvl, str)}
130
169
  end
131
170
 
171
+ # Returns an array of Scenario objects from the results in the envdir.
172
+ # The scenarii classes must be loaded before, else, some results might be ignored.
132
173
  def populate
133
174
  Laborantin::Scenario.scan_env(self)
134
175
  end
@@ -21,10 +21,16 @@ Copyright (c) 2009, Lucas Di Cioccio
21
21
 
22
22
  =end
23
23
 
24
+ # Some monkey patches on String. Will be moved later to a subclass.
24
25
  class String
26
+ # Returns a camelized version of a duck_case self
27
+ # 'some_string'.camelize # => 'SomeString'
25
28
  def camelize
26
29
  self.split('_').map{|i| i.capitalize}.join('')
27
30
  end
31
+
32
+ # Returns a duck cased version of camel-like self
33
+ # 'SomeString'.duck_case # => 'some_string'
28
34
  def duck_case
29
35
  self.gsub(/([A-Z])/){|s| "_#{$1.downcase}"}.sub(/^_/,'')
30
36
  end
@@ -22,25 +22,39 @@ Copyright (c) 2009, Lucas Di Cioccio
22
22
  =end
23
23
 
24
24
  module Laborantin
25
+
26
+ # A ParameterRange instance is more or less a wrapper over an Array of allowed values.
25
27
  class ParameterRange
26
- attr_accessor :name, :description
28
+
29
+ # The name of the parameter (should be unique in a Scenario's parameters)
30
+ # Usually a symbol.
31
+ attr_accessor :name
32
+
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
+
27
37
  def initialize(name)
28
38
  @name = name
29
39
  @values = []
30
40
  @description = ''
31
41
  end
32
42
 
43
+ # Sets the allowed values. Currently only supports Array like.
44
+ # It is planned to support Iterable, but deterministic ones only.
33
45
  def values(*args)
34
46
  @values = args.flatten unless args.empty?
35
47
  @values
36
48
  end
37
49
 
50
+ # Iterates on allowed values for this parameter.
38
51
  def each
39
52
  @values.each do |v|
40
- yield v
53
+ yield v
41
54
  end
42
55
  end
43
56
 
57
+ # Sets the description.
44
58
  def describe(str)
45
59
  @description = str
46
60
  end
@@ -23,16 +23,20 @@ Copyright (c) 2009, Lucas Di Cioccio
23
23
 
24
24
 
25
25
  module Laborantin
26
+ # A kind of Hash that can yields all possible configuration recursively.
27
+ # It should contains ParameterRange like definitions objects.
26
28
  class ParameterHash < Hash
29
+ # Recursively yields all the possible configurations of parameters (a new hash).
30
+ # No order is supported on the recursion, and it is not planned to.
27
31
  def each_config(remaining=self.keys, cfg={}, &blk)
28
32
  key = remaining.pop
29
33
  if key
30
- self[key].each do |val|
31
- cfg[key] = val
32
- each_config(remaining.dup, cfg, &blk)
33
- end
34
+ self[key].each do |val|
35
+ cfg[key] = val
36
+ each_config(remaining.dup, cfg, &blk)
37
+ end
34
38
  else
35
- yield cfg
39
+ yield cfg
36
40
  end
37
41
  end
38
42
 
@@ -28,9 +28,25 @@ require 'fileutils'
28
28
  require 'yaml'
29
29
 
30
30
  module Laborantin
31
+
32
+ # A Scenario represents a measurement done in a given environment. Some of
33
+ # its parameters will change, and we are interested in varying these parameters and
34
+ # then study their impact.
35
+ #
36
+ # An user will usually creates a Scenario subklass which represents such
37
+ # a measurement. For that he must defines a run method that will yield consecutive
38
+ # lines added to the raw result file. Then this file can be processed to give
39
+ # intermediary or final results.
40
+ #
41
+ # Like the Environment, all the subklasses will be stored in a @@all
42
+ # class variable for convenience purpose.
31
43
  class Scenario
32
44
  @@all = []
33
45
 
46
+ # 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.
34
50
  def self.scan_env(env)
35
51
  scs = []
36
52
  Dir.entries(env.rundir).each do |s|
@@ -50,8 +66,26 @@ module Laborantin
50
66
  end
51
67
 
52
68
  class << self
53
- attr_accessor :description, :parameters, :products, :hooks
54
69
 
70
+ # A description used for printing summary and debug purposes. Will be
71
+ # used to create .tex report in the future.
72
+ # CURRENTLY NOT HERITED
73
+ attr_accessor :description
74
+
75
+ # A hash to store setup/teardown hooks.
76
+ # CURRENTLY NOT HERITED
77
+ attr_accessor :hooks
78
+
79
+ # The set of parameters that will vary for this Scenario.
80
+ attr_accessor :parameters
81
+
82
+ # Some special products that are done after an analysis on a measurement
83
+ # scenario. The intended way is to store raw results (e.g. a command output) in
84
+ # a file and then parse them and store the parsed result in another file etc.
85
+ # TODO : products that compares scenarii
86
+ attr_accessor :products
87
+
88
+ # Prepares attributes' default values whenever a subclass is created.
55
89
  def inherited(klass)
56
90
  klass.parameters = ParameterHash.new
57
91
  klass.description = ''
@@ -60,19 +94,30 @@ module Laborantin
60
94
  @@all << klass
61
95
  end
62
96
 
97
+ # Sets the description.
63
98
  def describe(str)
64
99
  self.description = str
65
100
  end
66
101
 
102
+ # Registers setup hooks.
67
103
  def setup(*args)
68
104
  self.hooks[:setup] = [*args].flatten
69
105
  end
70
106
 
107
+ # Register teardown hooks.
71
108
  def teardown(*args)
72
109
  self.hooks[:teardown] = [*args].flatten
73
110
  end
74
111
 
75
-
112
+ # Defines a new ParameterRange instance for this Scenario.
113
+ # A block should be passed that will be evaluated in this
114
+ # ParameterRange instance's context.
115
+ #
116
+ # parameter(:size) do
117
+ # values 10, 20, 30
118
+ # describe "We expect a linear RTT increase with the size"
119
+ # end
120
+ #
76
121
  def parameter(name, &blk)
77
122
  raise ArgumentError.new("Parameter #{name} already exists") if self.parameters[name]
78
123
  param = ParameterRange.new(name)
@@ -80,6 +125,9 @@ module Laborantin
80
125
  self.parameters[name] = param
81
126
  end
82
127
 
128
+ # Defines the products names.
129
+ # IMPORTANT: products are built in the provided order, and they must be
130
+ # valid instance methods name for a Scenario object (hence user defined).
83
131
  def produces(*args)
84
132
  self.products = [*args].flatten
85
133
  end
@@ -88,17 +136,34 @@ module Laborantin
88
136
  "#{self.name}:\n\t#{self.description}\n#{self.parameters}"
89
137
  end
90
138
 
139
+ # Returns all the known subklasses of Scenario.
91
140
  def all
92
141
  @@all
93
142
  end
94
143
 
144
+ # Returns the path where the results of the instances of this Scenario
145
+ # will be stored given that we are in the env Environment. If env is nil,
146
+ # will use '.' as rootdir for the Scenario results.
95
147
  def scenardir(env=nil)
96
148
  envdir = env.rundir || '.'
97
149
  File.join(envdir, self.name.duck_case)
98
150
  end
99
151
  end # class <<
100
152
 
101
- attr_accessor :params, :environment, :date, :rundir
153
+ # A hash of parameters for this run.
154
+ attr_accessor :params
155
+
156
+ # The environment in which we run this scenario.
157
+ attr_accessor :environment
158
+
159
+ # A date that holds the creation of the instance, it is not meaningful
160
+ # when an env was created by a call to Environment.scan_resdir.
161
+ # TODO better
162
+ attr_accessor :date
163
+
164
+ # An attribute that holds the directory where the config and the results
165
+ # are stored. Can be overridden (e.g. Scenario.scan_env does that).
166
+ attr_accessor :rundir
102
167
 
103
168
  def initialize(env, params={})
104
169
  @environment = env
@@ -107,6 +172,13 @@ module Laborantin
107
172
  @rundir = File.join(self.class.scenardir(environment), date_str)
108
173
  end
109
174
 
175
+ # In the following order:
176
+ # * Log some info in the environment
177
+ # * Creates the rundir to store the result and the config
178
+ # * Stores the configuration as well as the run date
179
+ # BEWARE : currently does not ensure unicity of rundir,
180
+ # so wait one sec between several runs of same Scenario
181
+ #
110
182
  def prepare!
111
183
  log(self.class.description, :info) unless self.class.description.empty?
112
184
  log self.params.inspect, :info
@@ -116,6 +188,15 @@ module Laborantin
116
188
  File.open( config_path, 'w') {|f| f.puts YAML.dump( [date, params] ) }
117
189
  end
118
190
 
191
+ # In the following order:
192
+ # * Calls the setup hooks
193
+ # * Logs some info
194
+ # * Creates the raw result file
195
+ # * Calls the run method (user defined)
196
+ # * ... for each yielded line, store it into the raw result file
197
+ # * once completed (or on error) closes the raw result file
198
+ # * Logs some info
199
+ # * Calls the teardown hooks
119
200
  def perform!
120
201
  call_hooks :setup
121
202
  log "Starting measurement"
@@ -128,6 +209,10 @@ module Laborantin
128
209
  call_hooks :teardown
129
210
  end
130
211
 
212
+ # For each product define with Scenario.produces, and in its order,
213
+ # create a file with a canonic name in the scenario rundir.
214
+ # Call the instance method which has the product name.
215
+ # Appends each yielded line from this method.
131
216
  def analyze!
132
217
  self.class.products.each do |name|
133
218
  log "Producing #{name}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: laborantin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Di Cioccio Lucas
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-27 00:00:00 +02:00
12
+ date: 2009-07-28 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -40,7 +40,7 @@ files:
40
40
  - lib/laborantin/core/parameter_hash.rb
41
41
  - lib/laborantin/core/scenario.rb
42
42
  - lib/laborantin/core/monkey_patches.rb
43
- has_rdoc: false
43
+ has_rdoc: true
44
44
  homepage: http://rubyforge.org/projects/laborantin
45
45
  post_install_message:
46
46
  rdoc_options: []