stud 0.0.5 → 0.0.6
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/lib/stud/benchmark.rb +124 -0
- data/lib/stud/pool.rb +1 -1
- data/lib/stud/secret.rb +35 -0
- data/lib/stud/try.rb +6 -3
- metadata +6 -4
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Benchmark Use Cases
|
3
|
+
# * Compare performance of different implementations.
|
4
|
+
# * run each implementation N times, compare runtimes (histogram, etc)
|
5
|
+
|
6
|
+
module Stud
|
7
|
+
module Benchmark
|
8
|
+
def self.run(iterations=1, &block)
|
9
|
+
i = 0
|
10
|
+
data = []
|
11
|
+
full_start = Time.now
|
12
|
+
while i < iterations
|
13
|
+
start = Time.now
|
14
|
+
block.call
|
15
|
+
duration = Time.now - start
|
16
|
+
data << duration
|
17
|
+
i += 1
|
18
|
+
end
|
19
|
+
return Results.new(data)
|
20
|
+
end # def run
|
21
|
+
|
22
|
+
class Results
|
23
|
+
include Enumerable
|
24
|
+
# Stolen from https://github.com/holman/spark/blob/master/spark
|
25
|
+
TICKS = %w{▁ ▂ ▃ ▄ ▅ ▆ ▇ █}
|
26
|
+
|
27
|
+
def initialize(data)
|
28
|
+
@data = data
|
29
|
+
end # def initialize
|
30
|
+
|
31
|
+
def environment
|
32
|
+
# Older rubies don't have the RUBY_ENGINE defiend
|
33
|
+
engine = (RUBY_ENGINE rescue "ruby")
|
34
|
+
# Include jruby version in the engine
|
35
|
+
engine += (JRUBY_VERSION rescue "")
|
36
|
+
version = RUBY_VERSION
|
37
|
+
|
38
|
+
return "#{engine} #{version}"
|
39
|
+
end # def environment
|
40
|
+
|
41
|
+
def each(&block)
|
42
|
+
@data.each(&block)
|
43
|
+
end # def each
|
44
|
+
|
45
|
+
def log_distribution
|
46
|
+
return distribution do |value|
|
47
|
+
if value == 0
|
48
|
+
0 ... 0
|
49
|
+
else
|
50
|
+
tick = (Math.log2(value).floor).to_f rescue 0
|
51
|
+
(2 ** tick) ... (2 ** (tick+1))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end # def log_distribution
|
55
|
+
|
56
|
+
def distribution(&range_compute)
|
57
|
+
raise ArgumentError.new("Missing range computation block") if !block_given?
|
58
|
+
|
59
|
+
max = @data.max
|
60
|
+
dist = Hash.new { |h,k| h[k] = 0 }
|
61
|
+
each do |value|
|
62
|
+
range = range_compute.call(value)
|
63
|
+
dist[range] += 1
|
64
|
+
end
|
65
|
+
return dist
|
66
|
+
end # def distribution
|
67
|
+
|
68
|
+
def mean
|
69
|
+
if @mean.nil?
|
70
|
+
total = Float(@data.count)
|
71
|
+
@mean = sum / total
|
72
|
+
end
|
73
|
+
return @mean
|
74
|
+
end # def mean
|
75
|
+
|
76
|
+
def stddev
|
77
|
+
# sum of square deviations of mean divided by total values
|
78
|
+
return Math.sqrt(inject(0) { |s, v| s + (v - mean) ** 2 } / (@data.count - 1))
|
79
|
+
end # def stddev
|
80
|
+
|
81
|
+
def sum
|
82
|
+
if @sum.nil?
|
83
|
+
@sum = inject(0) { |s,v| s + v }
|
84
|
+
end
|
85
|
+
return @sum
|
86
|
+
end # def sum
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
return "#{environment}: avg: #{mean} stddev: #{stddev}"
|
90
|
+
end # def to_s
|
91
|
+
|
92
|
+
def pretty_print
|
93
|
+
min = @data.min
|
94
|
+
max = @data.max
|
95
|
+
zmax = Float(max - min) # "zero" at the 'min' value, offset the max.
|
96
|
+
incr = 0.1 # 10% increments
|
97
|
+
#dist = distribution do |value|
|
98
|
+
#percent = (value - min) / zmax
|
99
|
+
#if percent == 1
|
100
|
+
#(1 - incr ... 1.0)
|
101
|
+
#else
|
102
|
+
#start = ((percent * 10).floor / 10.0)
|
103
|
+
#start ... (start + incr)
|
104
|
+
#end
|
105
|
+
#end
|
106
|
+
dist = log_distribution
|
107
|
+
|
108
|
+
total = dist.inject(0) { |sum, (step, count)| sum + count }
|
109
|
+
sorted = dist.sort { |a,b| a.first.begin <=> b.first.begin }
|
110
|
+
puts sorted.collect { |lower_bound, count|
|
111
|
+
#puts lower_bound
|
112
|
+
percent = (count / Float(total))
|
113
|
+
"%40s: %s" % [lower_bound, (TICKS.last * (50 * percent).ceil)]
|
114
|
+
}.join("\n")
|
115
|
+
|
116
|
+
end # def pretty_print
|
117
|
+
end # class Stud::Benchmark::Result
|
118
|
+
end # module Benchmark
|
119
|
+
end # module Stud
|
120
|
+
|
121
|
+
#require "thread"
|
122
|
+
#mutex = Mutex.new
|
123
|
+
#results = Stud::Benchmark.run(20) { mutex.synchronize { rand; rand; rand } }
|
124
|
+
#results.pretty_print
|
data/lib/stud/pool.rb
CHANGED
data/lib/stud/secret.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
# A class for holding a secret. The main goal is to prevent the common mistake
|
3
|
+
# of accidentally logging or printing passwords or other secrets.
|
4
|
+
#
|
5
|
+
# See
|
6
|
+
# <https://github.com/jordansissel/software-patterns/blob/master/dont-log-secrets/ruby/>
|
7
|
+
# for a discussion of why this implementation is useful.
|
8
|
+
module Stud
|
9
|
+
class Secret
|
10
|
+
# Initialize a new secret with a given value.
|
11
|
+
#
|
12
|
+
# value - anything you want to keep secret from loggers, etc.
|
13
|
+
def initialize(secret_value)
|
14
|
+
# Redefine the 'value' method on this instance. This exposes no instance
|
15
|
+
# variables to be accidentally leaked by things like awesome_print, etc.
|
16
|
+
# This makes any #value call return the secret value.
|
17
|
+
(class << self; self; end).class_eval do
|
18
|
+
define_method(:value) { secret_value }
|
19
|
+
end
|
20
|
+
end # def initialize
|
21
|
+
|
22
|
+
# Emit simply "<secret>" when printed or logged.
|
23
|
+
def to_s
|
24
|
+
return "<secret>"
|
25
|
+
end # def to_s
|
26
|
+
|
27
|
+
alias_method :inspect, :to_s
|
28
|
+
|
29
|
+
# Get the secret value.
|
30
|
+
def value
|
31
|
+
# Nothing, this will be filled in by Secret.new
|
32
|
+
# But we'll still document this so rdoc/yard know the method exists.
|
33
|
+
end # def value
|
34
|
+
end # class Secret
|
35
|
+
end # class Stud
|
data/lib/stud/try.rb
CHANGED
@@ -72,10 +72,10 @@ module Stud
|
|
72
72
|
def try(enumerable=FOREVER, &block)
|
73
73
|
if block.arity == 0
|
74
74
|
# If the block takes no arguments, give none
|
75
|
-
procedure = lambda { |val| block.call }
|
75
|
+
procedure = lambda { |val| return block.call }
|
76
76
|
else
|
77
77
|
# Otherwise, pass the current 'enumerable' value to the block.
|
78
|
-
procedure = lambda { |val| block.call(val) }
|
78
|
+
procedure = lambda { |val| return block.call(val) }
|
79
79
|
end
|
80
80
|
|
81
81
|
# Track the last exception so we can reraise it on failure.
|
@@ -89,6 +89,9 @@ module Stud
|
|
89
89
|
# If the 'procedure' (the block, really) succeeds, we'll break
|
90
90
|
# and return the return value of the block. Win!
|
91
91
|
return procedure.call(val)
|
92
|
+
rescue NoMethodError, NameError
|
93
|
+
# Abort immediately on exceptions that are unlikely to recover.
|
94
|
+
raise
|
92
95
|
rescue => exception
|
93
96
|
last_exception = exception
|
94
97
|
fail_count += 1
|
@@ -112,7 +115,7 @@ module Stud
|
|
112
115
|
|
113
116
|
TRY = Try.new
|
114
117
|
# A simple try method for the common case.
|
115
|
-
def try(enumerable=Stud::Try::
|
118
|
+
def try(enumerable=Stud::Try::FOREVER, &block)
|
116
119
|
return TRY.try(enumerable, &block)
|
117
120
|
end # def try
|
118
121
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -50,10 +50,12 @@ executables: []
|
|
50
50
|
extensions: []
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
|
+
- lib/stud/try.rb
|
54
|
+
- lib/stud/interval.rb
|
55
|
+
- lib/stud/benchmark.rb
|
53
56
|
- lib/stud/task.rb
|
57
|
+
- lib/stud/secret.rb
|
54
58
|
- lib/stud/pool.rb
|
55
|
-
- lib/stud/interval.rb
|
56
|
-
- lib/stud/try.rb
|
57
59
|
- LICENSE
|
58
60
|
- CHANGELIST
|
59
61
|
- README.md
|