tryouts 0.8.8 → 2.0.0

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.
@@ -1,132 +0,0 @@
1
-
2
- require 'benchmark'
3
-
4
-
5
- class Tryouts; class Drill; module Sergeant
6
-
7
- # = RBenchmark
8
- #
9
- # This is an implementation of Better-Benchmark:
10
- # http://github.com/Pistos/better-benchmark/
11
- #
12
- # NOTE: It's a work in progress and currently not functioning
13
- #
14
- # See also: http://www.graphpad.com/articles/interpret/Analyzing_two_groups/wilcoxon_matched_pairs.htm
15
- #
16
- module RBenchmark
17
-
18
- VERSION = '0.7.0'
19
-
20
- class ComparisonPartial
21
- def initialize( block, options )
22
- @block1 = block
23
- @options = options
24
- end
25
-
26
- def with( &block2 )
27
- times1 = []
28
- times2 = []
29
-
30
- (1..@options[ :iterations ]).each do |iteration|
31
- if @options[ :verbose ]
32
- $stdout.print "."; $stdout.flush
33
- end
34
-
35
- times1 << ::Benchmark.realtime do
36
- @options[ :inner_iterations ].times do |i|
37
- @block1.call( iteration )
38
- end
39
- end
40
- times2 << ::Benchmark.realtime do
41
- @options[ :inner_iterations ].times do |i|
42
- block2.call( iteration )
43
- end
44
- end
45
- end
46
-
47
- r = RSRuby.instance
48
- wilcox_result = r.wilcox_test( times1, times2 )
49
-
50
- {
51
- :results1 => {
52
- :times => times1,
53
- :mean => r.mean( times1 ),
54
- :stddev => r.sd( times1 ),
55
- },
56
- :results2 => {
57
- :times => times2,
58
- :mean => r.mean( times2 ),
59
- :stddev => r.sd( times2 ),
60
- },
61
- :p => wilcox_result[ 'p.value' ],
62
- :W => wilcox_result[ 'statistic' ][ 'W' ],
63
- :significant => (
64
- wilcox_result[ 'p.value' ] < @options[ :required_significance ]
65
- ),
66
- }
67
- end
68
- alias to with
69
- end
70
-
71
- # Options:
72
- # :iterations
73
- # The number of times to execute the pair of blocks.
74
- # :inner_iterations
75
- # Used to increase the time taken per iteration.
76
- # :required_significance
77
- # Maximum allowed p value in order to declare the results statistically significant.
78
- # :verbose
79
- # Whether to print a dot for each iteration (as a sort of progress meter).
80
- #
81
- # To use better-benchmark properly, it is important to set :iterations and
82
- # :inner_iterations properly. There are a few things to bear in mind:
83
- #
84
- # (1) Do not set :iterations too high. It should normally be in the range
85
- # of 10-20, but can be lower. Over 25 should be considered too high.
86
- # (2) Execution time for one run of the blocks under test should not be too
87
- # small (or else random variance will muddle the results). Aim for at least
88
- # 1.0 seconds per iteration.
89
- # (3) Minimize the proportion of any warmup time (and cooldown time) of one
90
- # block run.
91
- #
92
- # In order to achieve these goals, you will need to tweak :inner_iterations
93
- # based on your situation. The exact number you should use will depend on
94
- # the strength of the hardware (CPU, RAM, disk), and the amount of work done
95
- # by the blocks. For code blocks that execute extremely rapidly, you may
96
- # need hundreds of thousands of :inner_iterations.
97
- def self.compare_realtime( options = {}, &block1 )
98
- require 'rsruby'
99
-
100
- options[ :iterations ] ||= 20
101
- options[ :inner_iterations ] ||= 1
102
- options[ :required_significance ] ||= 0.01
103
-
104
- if options[ :iterations ] > 30
105
- warn "The number of iterations is set to #{options[ :iterations ]}. " +
106
- "Using too many iterations may make the test results less reliable. " +
107
- "It is recommended to increase the number of :inner_iterations instead."
108
- end
109
-
110
- ComparisonPartial.new( block1, options )
111
- end
112
-
113
- def self.report_on( result )
114
- puts
115
- puts( "Set 1 mean: %.3f s" % [ result[ :results1 ][ :mean ] ] )
116
- puts( "Set 1 std dev: %.3f" % [ result[ :results1 ][ :stddev ] ] )
117
- puts( "Set 2 mean: %.3f s" % [ result[ :results2 ][ :mean ] ] )
118
- puts( "Set 2 std dev: %.3f" % [ result[ :results2 ][ :stddev ] ] )
119
- puts "p.value: #{result[ :p ]}"
120
- puts "W: #{result[ :W ]}"
121
- puts(
122
- "The difference (%+.1f%%) %s statistically significant." % [
123
- ( ( result[ :results2 ][ :mean ] - result[ :results1 ][ :mean ] ) / result[ :results1 ][ :mean ] ) * 100,
124
- result[ :significant ] ? 'IS' : 'IS NOT'
125
- ]
126
- )
127
- end
128
- end
129
-
130
- end; end; end
131
-
132
-
data/lib/tryouts/drill.rb DELETED
@@ -1,224 +0,0 @@
1
-
2
-
3
- class Tryouts
4
-
5
- # = Drill
6
- #
7
- # This class represents a drill. A drill is single test.
8
- #
9
- class Drill
10
-
11
- require 'tryouts/drill/context'
12
- require 'tryouts/drill/response'
13
- require 'tryouts/drill/dream'
14
- require 'tryouts/drill/reality'
15
- require 'tryouts/drill/sergeant/cli'
16
- require 'tryouts/drill/sergeant/api'
17
- require 'tryouts/drill/sergeant/benchmark'
18
- #require 'tryouts/drill/sergeant/rbenchmark'
19
-
20
- class NoSergeant < Tryouts::Exception; end
21
- class UnknownFormat < Tryouts::Exception; end
22
-
23
- # A symbol specifying the drill type. One of: :cli, :api
24
- attr_reader :dtype
25
- # The name of the drill. This should match the name used in the dreams file.
26
- attr_reader :name
27
- # A Proc object which contains the drill logic.
28
- attr_reader :drill
29
- # A Sergeant object which executes the drill
30
- attr_reader :sergeant
31
- # An Array of Dream objects (the expected output of the test)
32
- attr_reader :dreams
33
- # A Reality object (the actual output of the test)
34
- attr_reader :reality
35
-
36
- @@valid_dtypes = [:api, :cli, :benchmark]
37
-
38
- # * +name+ The display name of this drill
39
- # * +dtype+ A Symbol representing the drill type. One of: :api, :benchmark
40
- # * +args+ These are dependent on the drill type. See the Sergeant classes
41
- # * +&drill+ The body of the drill. The return value of this block
42
- # is compared to the exepected output of the dreams.
43
- #
44
- # The DSL syntax:
45
- # * dream OUTPUT
46
- # * dream FORMAT, OUTPUT
47
- # * dream FORMAT, OUTPUT, REPS (benchmark only)
48
- #
49
- def initialize(name, dtype, *args, &drill)
50
- @name, @dtype, @drill, @skip = name, dtype, drill, false
51
- @dreams = []
52
-
53
- # We create a default empty reality but if the drill runs correctly
54
- # this reality gets replaced with the return value from the drill.
55
- @reality = Tryouts::Drill::Reality.new
56
-
57
- case @dtype
58
- when :cli
59
- # For CLI drills, a block takes precedence over inline args.
60
- # A block will contain multiple shell commands (see Rye::Box#batch)
61
- args = [] if dtype == :cli && drill.is_a?(Proc)
62
- @sergeant = Tryouts::Drill::Sergeant::CLI.new *args
63
- when :api
64
- default_output = drill.nil? ? args.shift : nil
65
- @sergeant = Tryouts::Drill::Sergeant::API.new default_output
66
- unless args.empty?
67
- if args.size == 1
68
- dream_output, format = args.first, nil
69
- else
70
- dream_output, format = args[1], args[0]
71
- end
72
- @dreams << Tryouts::Drill::Dream.new(dream_output, format)
73
- end
74
- when :benchmark
75
- if args.size == 1
76
- reps = args.first
77
- else
78
- dream_output, format, reps = args[1], args[0], args[2]
79
- end
80
- @sergeant = Tryouts::Drill::Sergeant::Benchmark.new reps
81
- @dreams << Tryouts::Drill::Dream.new(Hash, :class)
82
- unless dream_output.nil?
83
- @dreams << Tryouts::Drill::Dream.new(dream_output, format)
84
- end
85
- when :skip
86
- @skip = true
87
- else
88
- raise NoSergeant, "Weird drill sergeant: #{@dtype}"
89
- end
90
- @clr = :red
91
-
92
-
93
- end
94
-
95
- def self.valid_dtypes; @@valid_dtypes; end
96
- def self.valid_dtype?(t); @@valid_dtypes.member?(t); end
97
-
98
- def skip?; @skip; end
99
-
100
- def run(context=nil)
101
- unless @dreams.empty?
102
- @dreams.each { |d| d.execute_output_block }
103
- end
104
- begin
105
- @reality = @sergeant.run @drill, context
106
- # Store the stash from the drill block
107
- @reality.stash = context.stash if context.respond_to? :stash
108
- # If the drill block returned true we assume success if there's no dream
109
- if @dreams.empty? && @reality.output == true
110
- @dreams << Tryouts::Drill::Dream.new
111
- @dreams.first.output = true
112
- end
113
- rescue => ex
114
- @reality.ecode, @reality.etype = -2, ex.class
115
- @reality.error, @reality.trace = ex.message, ex.backtrace
116
- end
117
- self.success?
118
- end
119
-
120
- def flag
121
- if skip?
122
- "SKIP"
123
- elsif success?
124
- "PASS".color(@clr).bright
125
- else
126
- note = @dreams.empty? ? '[nodream]' : ''
127
- "FAIL #{note}".color(@clr).bright
128
- end
129
- end
130
-
131
- def info
132
- out = StringIO.new
133
- if Tryouts.verbose > 0
134
- if @dtype == :benchmark
135
- unless @reality.output.nil?
136
- Sergeant::Benchmark.fields.each do |f|
137
- s = @reality.output[f]
138
- ar = [s.name, s.mean, s.min, s.max, s.sdev, s.sum]
139
- pa = '%6s: %.4f (min:%.4f max:%.4f sdev:%.4f sum:%.4f)'.color(@clr)
140
- out.puts pa % ar
141
- end
142
- ar = ['', @reality.output[:rtotal].mean]
143
- out.puts '%8s%3.4f (run time)'.color(@clr) % ar
144
- end
145
- elsif @dtype == :cli
146
- out.puts '%6s%s'.color(@clr) % ['', @reality.command]
147
- output = @reality.output
148
- output = output.join($/ + ' '*6) if output.kind_of?(Array)
149
- out.puts '%6s%s'.color(@clr) % ['', output]
150
- else
151
- out.puts '%6s%s'.color(@clr) % ['', @reality.output.inspect]
152
- end
153
- unless @reality.stash.empty?
154
- @reality.stash.each_pair do |n,v|
155
- out.puts '%18s: %s'.color(@clr) % [n,v.inspect]
156
- end
157
- end
158
- end
159
- if Tryouts.verbose > 1
160
-
161
- @dreams.each do |dream|
162
- if dream != @reality
163
- out.puts '%6s%s'.color(:red) % ['', dream.test_to_string(@reality)]
164
- else
165
- out.puts '%6s%s'.color(:green) % ["", dream.test_to_string(@reality)]
166
- end
167
- end
168
- out.puts
169
-
170
- end
171
- out.rewind
172
- out.read
173
- end
174
-
175
- def report
176
- return if skip?
177
- out = StringIO.new
178
-
179
- out.puts '%12s'.color(:red) % '[nodream]' if @dreams.empty?
180
-
181
- @dreams.each do |dream|
182
- next if dream == reality #? :normal : :red
183
- out.puts '%12s: %s'.color(@clr) % ["failed", dream.test_to_string(@reality)]
184
- out.puts '%12s: %s' % ["drill", @reality.comparison_value(dream).inspect]
185
- out.puts '%12s: %s' % ["dream", dream.comparison_value.inspect]
186
- out.puts
187
- end
188
-
189
- unless @reality.error.nil?
190
- out.puts '%14s: %s' % [@reality.etype, @reality.error.to_s.split($/).join($/ + ' '*16)]
191
- end
192
- unless @reality.trace.nil?
193
- trace = Tryouts.verbose > 1 ? @reality.trace : [@reality.trace.first]
194
- out.puts '%14s %s' % ['', trace.join($/ + ' '*16)]
195
- out.puts
196
- end
197
-
198
- out.rewind
199
- out.read
200
- end
201
-
202
- def has_error?
203
- !@reality.error.nil?
204
- end
205
-
206
- def success?
207
- return false if @dreams.empty? && @reality.output != true
208
- begin
209
- @dreams.each { |d| return false unless d == @reality }
210
- rescue => ex
211
- puts ex.message, ex.backtrace if Tryouts.debug?
212
- return false
213
- end
214
- @clr = :green
215
- true
216
- end
217
-
218
-
219
- def add_dream(d); @dreams << d; end
220
- def add_dreams(*d); @dreams += d; end
221
-
222
- private
223
-
224
- end; end
@@ -1,37 +0,0 @@
1
-
2
- class Hash
3
-
4
- # A depth-first look to find the deepest point in the Hash.
5
- # The top level Hash is counted in the total so the final
6
- # number is the depth of its children + 1. An example:
7
- #
8
- # ahash = { :level1 => { :level2 => {} } }
9
- # ahash.deepest_point # => 3
10
- #
11
- def deepest_point(h=self, steps=0)
12
- if h.is_a?(Hash)
13
- steps += 1
14
- h.each_pair do |n,possible_h|
15
- ret = deepest_point(possible_h, steps)
16
- steps = ret if steps < ret
17
- end
18
- else
19
- return 0
20
- end
21
- steps
22
- end
23
-
24
- unless method_defined?(:last)
25
- # Ruby 1.9 doesn't have a Hash#last (but Tryouts::OrderedHash does).
26
- # It's used in Tryouts to return the most recently added instance of
27
- # Tryouts to @@instances.
28
- #
29
- # NOTE: This method is defined only when Hash.method_defined?(:last)
30
- # returns false.
31
- def last
32
- self[ self.keys.last ]
33
- end
34
- end
35
-
36
- end
37
-
@@ -1,199 +0,0 @@
1
- # AUTHOR
2
- # jan molic /mig/at/1984/dot/cz/
3
- #
4
- # DESCRIPTION
5
- # Hash with preserved order and some array-like extensions
6
- # Public domain.
7
- #
8
- # THANKS
9
- # Andrew Johnson for his suggestions and fixes of Hash[],
10
- # merge, to_a, inspect and shift
11
- class Tryouts::OrderedHash < ::Hash
12
- attr_accessor :order
13
-
14
- class << self
15
- def [] *args
16
- hsh = Tryouts::OrderedHash.new
17
- if Hash === args[0]
18
- hsh.replace args[0]
19
- elsif (args.size % 2) != 0
20
- raise ArgumentError, "odd number of elements for Hash"
21
- else
22
- 0.step(args.size - 1, 2) do |a|
23
- b = a + 1
24
- hsh[args[a]] = args[b]
25
- end
26
- end
27
- hsh
28
- end
29
- end
30
- def initialize(*a, &b)
31
- super
32
- @order = []
33
- end
34
- def store_only a,b
35
- store a,b
36
- end
37
- alias orig_store store
38
- def store a,b
39
- @order.push a unless has_key? a
40
- super a,b
41
- end
42
- alias []= store
43
- def == hsh2
44
- return false if @order != hsh2.order
45
- super hsh2
46
- end
47
- def clear
48
- @order = []
49
- super
50
- end
51
- def delete key
52
- @order.delete key
53
- super
54
- end
55
- def each_key
56
- @order.each { |k| yield k }
57
- self
58
- end
59
- def each_value
60
- @order.each { |k| yield self[k] }
61
- self
62
- end
63
- def each
64
- @order.each { |k| yield k,self[k] }
65
- self
66
- end
67
- alias each_pair each
68
- def delete_if
69
- @order.clone.each { |k|
70
- delete k if yield(k)
71
- }
72
- self
73
- end
74
- def values
75
- ary = []
76
- @order.each { |k| ary.push self[k] }
77
- ary
78
- end
79
- def keys
80
- @order
81
- end
82
- def first
83
- {@order.first => self[@order.first]}
84
- end
85
- def last
86
- {@order.last => self[@order.last]}
87
- end
88
- def invert
89
- hsh2 = Hash.new
90
- @order.each { |k| hsh2[self[k]] = k }
91
- hsh2
92
- end
93
- def reject &block
94
- self.dup.delete_if &block
95
- end
96
- def reject! &block
97
- hsh2 = reject &block
98
- self == hsh2 ? nil : hsh2
99
- end
100
- def replace hsh2
101
- @order = hsh2.keys
102
- super hsh2
103
- end
104
- def shift
105
- key = @order.first
106
- key ? [key,delete(key)] : super
107
- end
108
- def unshift k,v
109
- unless self.include? k
110
- @order.unshift k
111
- orig_store(k,v)
112
- true
113
- else
114
- false
115
- end
116
- end
117
- def push k,v
118
- unless self.include? k
119
- @order.push k
120
- orig_store(k,v)
121
- true
122
- else
123
- false
124
- end
125
- end
126
- def pop
127
- key = @order.last
128
- key ? [key,delete(key)] : nil
129
- end
130
- def to_a
131
- ary = []
132
- each { |k,v| ary << [k,v] }
133
- ary
134
- end
135
- def to_s
136
- self.to_a.to_s
137
- end
138
- def inspect
139
- ary = []
140
- each {|k,v| ary << k.inspect + "=>" + v.inspect}
141
- '{' + ary.join(", ") + '}'
142
- end
143
- def update hsh2
144
- hsh2.each { |k,v| self[k] = v }
145
- self
146
- end
147
- alias :merge! update
148
- def merge hsh2
149
- ##self.dup update(hsh2) ## 2009-05-12 -- delano
150
- update hsh2 ## dup doesn't take an argument
151
- ## and there's no need for it here
152
- end
153
- def select
154
- ary = []
155
- each { |k,v| ary << [k,v] if yield k,v }
156
- ary
157
- end
158
- def class
159
- Hash
160
- end
161
- def __class__
162
- Tryouts::OrderedHash
163
- end
164
-
165
- attr_accessor "to_yaml_style"
166
- def yaml_inline= bool
167
- if respond_to?("to_yaml_style")
168
- self.to_yaml_style = :inline
169
- else
170
- unless defined? @__yaml_inline_meth
171
- @__yaml_inline_meth =
172
- lambda {|opts|
173
- YAML::quick_emit(object_id, opts) {|emitter|
174
- emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
175
- }
176
- }
177
- class << self
178
- def to_yaml opts = {}
179
- begin
180
- @__yaml_inline ? @__yaml_inline_meth[ opts ] : super
181
- rescue
182
- @to_yaml_style = :inline
183
- super
184
- end
185
- end
186
- end
187
- end
188
- end
189
- @__yaml_inline = bool
190
- end
191
- def yaml_inline!() self.yaml_inline = true end
192
-
193
- def each_with_index
194
- @order.each_with_index { |k, index| yield k, self[k], index }
195
- self
196
- end
197
- end # class Tryouts::OrderedHash
198
-
199
-
data/lib/tryouts/stats.rb DELETED
@@ -1,96 +0,0 @@
1
- # Copyright (c) 2005 Zed A. Shaw
2
- # You can redistribute it and/or modify it under the same terms as Ruby.
3
- #
4
- # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
- # for more information.
6
-
7
- # Stolen from:
8
- # http://mongrel.rubyforge.org/browser/trunk/lib/mongrel/stats.rb
9
- #
10
- # A very simple little class for doing some basic fast statistics sampling.
11
- # You feed it either samples of numeric data you want measured or you call
12
- # Stats.tick to get it to add a time delta between the last time you called it.
13
- # When you're done either call sum, sumsq, n, min, max, mean or sd to get
14
- # the information. The other option is to just call dump and see everything.
15
- #
16
- # It does all of this very fast and doesn't take up any memory since the samples
17
- # are not stored but instead all the values are calculated on the fly.
18
- class Tryouts
19
- class Stats
20
- attr_reader :sum, :sumsq, :n, :min, :max, :name
21
-
22
- def initialize(name=:unknown)
23
- @name = name
24
- reset
25
- end
26
-
27
- # Resets the internal counters so you can start sampling again.
28
- def reset
29
- @sum = 0.0
30
- @sumsq = 0.0
31
- @last_time = Time.new
32
- @n = 0.0
33
- @min = 0.0
34
- @max = 0.0
35
- end
36
-
37
- def samples; @n; end
38
-
39
- # Adds a sampling to the calculations.
40
- def sample(s)
41
- @sum += s
42
- @sumsq += s * s
43
- if @n == 0
44
- @min = @max = s
45
- else
46
- @min = s if @min > s
47
- @max = s if @max < s
48
- end
49
- (@n+=1).to_f
50
- end
51
-
52
- # Dump this Stats object with an optional additional message.
53
- def dump(msg = "", out=STDERR)
54
- out.puts "#{msg}: #{self.to_s}"
55
- end
56
-
57
- # Returns a common display (used by dump)
58
- def to_s
59
- "[#{@name}]: SUM=%0.4f, SUMSQ=%0.4f, N=%0.4f, MEAN=%0.4f, SD=%0.4f, MIN=%0.4f, MAX=%0.4f" % [@sum, @sumsq, @n, mean, sd, @min, @max]
60
- end
61
-
62
-
63
- # Calculates and returns the mean for the data passed so far.
64
- def mean
65
- @sum / @n
66
- end
67
-
68
- # Calculates the standard deviation of the data so far.
69
- def sdev
70
- # (sqrt( ((s).sumsq - ( (s).sum * (s).sum / (s).n)) / ((s).n-1) ))
71
- begin
72
- Math.sqrt( (@sumsq - ( @sum * @sum / @n)) / (@n-1) ).to_f
73
- rescue Errno::EDOM
74
- 0.0
75
- end
76
- end
77
-
78
-
79
- # Adds a time delta between now and the last time you called this. This
80
- # will give you the average time between two activities.
81
- #
82
- # An example is:
83
- #
84
- # t = Stats.new("do_stuff")
85
- # 10000.times { do_stuff(); t.tick }
86
- # t.dump("time")
87
- #
88
- def tick
89
- now = Time.now
90
- sample(now - @last_time)
91
- @last_time = now
92
- end
93
-
94
-
95
- end
96
- end