feldtruby 0.3.16 → 0.3.18
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 +7 -0
- data/Gemfile.lock +9 -2
- data/Rakefile +8 -0
- data/feldtruby.gemspec +6 -0
- data/lib/feldtruby/annotations.rb +10 -0
- data/lib/feldtruby/array/basic_stats.rb +3 -1
- data/lib/feldtruby/array/permutations_and_subsets.rb +17 -0
- data/lib/feldtruby/float.rb +23 -0
- data/lib/feldtruby/logger.rb +216 -30
- data/lib/feldtruby/minitest_extensions.rb +0 -1
- data/lib/feldtruby/mongodb.rb +16 -0
- data/lib/feldtruby/mongodb_logger.rb +245 -0
- data/lib/feldtruby/optimize/differential_evolution.rb +29 -5
- data/lib/feldtruby/optimize/elite_archive.rb +91 -0
- data/lib/feldtruby/optimize/max_steps_termination_criterion.rb +1 -1
- data/lib/feldtruby/optimize/objective.rb +343 -222
- data/lib/feldtruby/optimize/optimizer.rb +138 -60
- data/lib/feldtruby/optimize/search_space.rb +10 -0
- data/lib/feldtruby/optimize.rb +1 -26
- data/lib/feldtruby/statistics.rb +74 -3
- data/lib/feldtruby/time.rb +19 -0
- data/lib/feldtruby/version.rb +1 -1
- data/old/event_logger.rb +682 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/analyze_sampler_comparison_results.R +78 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/compare_samplers.rb +264 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_130405_175934.csv +561 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder.csv +11201 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder_all_radii_4_to_30.csv +44801 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_omnitest.csv +1401 -0
- data/spikes/mongodb_logger.rb +47 -0
- data/spikes/simple_de_run.rb +32 -0
- data/test/helper.rb +17 -1
- data/test/test_array_basic_stats.rb +5 -1
- data/test/test_array_permutations_and_subsets.rb +23 -0
- data/test/test_float.rb +15 -0
- data/test/test_html_doc_getter.rb +1 -1
- data/test/test_logger.rb +86 -48
- data/test/test_mongodb_logger.rb +116 -0
- data/test/test_object_annotations.rb +14 -0
- data/test/test_optimize.rb +7 -6
- data/test/test_optimize_differential_evolution.rb +21 -19
- data/test/test_optimize_elite_archive.rb +85 -0
- data/test/test_optimize_objective.rb +237 -74
- data/test/test_optimize_populationbasedoptimizer.rb +72 -6
- data/test/test_optimize_random_search.rb +0 -17
- data/test/test_optimize_search_space.rb +15 -0
- data/test/test_statistics.rb +30 -4
- data/test/test_time.rb +22 -0
- data/test/tmp_shorter.csv +200 -0
- metadata +62 -21
data/old/event_logger.rb
ADDED
@@ -0,0 +1,682 @@
|
|
1
|
+
class Logger
|
2
|
+
private
|
3
|
+
|
4
|
+
def description_for_metric_change newValue, oldValue, eventType, metric
|
5
|
+
|
6
|
+
if newValue.is_a?(Numeric)
|
7
|
+
|
8
|
+
pc = percent_change(oldValue, newValue)
|
9
|
+
pcs = (pc ? " (#{pc})" : "")
|
10
|
+
|
11
|
+
summary = summary_stats eventType, metric
|
12
|
+
|
13
|
+
sum_str = summary ? ", mean = #{summary}" : ""
|
14
|
+
|
15
|
+
ovstr = oldValue ? oldValue.to_significant_digits(3).to_s : ""
|
16
|
+
|
17
|
+
"#{ovstr} -> #{newValue.to_significant_digits(3)}#{pcs}#{sum_str}"
|
18
|
+
|
19
|
+
else
|
20
|
+
|
21
|
+
" was = #{oldValue.inspect}\n now = #{newValue.inspect}"
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def summary_stats eventType, metric
|
27
|
+
nil # We cannot calc summary stats since this logger does not save history
|
28
|
+
end
|
29
|
+
|
30
|
+
def percent_change oldValue, newValue
|
31
|
+
return nil if oldValue.nil?
|
32
|
+
sign = (oldValue < newValue) ? "+" : ""
|
33
|
+
"#{sign}%.3g%%" % ((newValue - oldValue) / oldValue.to_f * 100.0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# A structured logging object that logs events. Events are time-stamped
|
38
|
+
# objects that have type and can contain arbitrary data. A logger can have
|
39
|
+
# multiple IO streams to which it logs events. With each event data can be
|
40
|
+
# saved.
|
41
|
+
#
|
42
|
+
# This default logger saves events locally in a hash.
|
43
|
+
class EventLogger < Logger
|
44
|
+
# Return the number of events of type _eventType_.
|
45
|
+
def num_events eventType = nil
|
46
|
+
events(eventType).length
|
47
|
+
end
|
48
|
+
|
49
|
+
# Events are time-stamped hashes of ruby values with a named type (given
|
50
|
+
# as a string). The time stamps are always saved as UTC.
|
51
|
+
class Event
|
52
|
+
attr_reader :type, :data, :time
|
53
|
+
def initialize(type, data, time = Time.now)
|
54
|
+
@type, @data, @time = type, data, time
|
55
|
+
end
|
56
|
+
|
57
|
+
# Convert to hash that will be saved in db. Since each event type is saved in its
|
58
|
+
# own db/collection we do NOT include the event type.
|
59
|
+
def to_db_hash
|
60
|
+
# We save with minimal json tag names since we need to conserve space
|
61
|
+
# if saving this to disc or db.
|
62
|
+
{
|
63
|
+
# _id will be added automatically by MongoDB.
|
64
|
+
"t" => time.utc.iso8601, # We follow the Cube convention of saving UTC
|
65
|
+
"d" => data
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return all the events for a given _eventType_.
|
71
|
+
def events(eventType = nil)
|
72
|
+
@events[eventType]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return all events, for a given _eventType_, between the _start_ and _stop_
|
76
|
+
# times. If _includePreEvent_ is true we include the event that comes directly
|
77
|
+
# before the start time.
|
78
|
+
def events_between start, stop, eventType = nil, includePreEvent = false
|
79
|
+
|
80
|
+
all_events = events(eventType)
|
81
|
+
|
82
|
+
es = all_events.select do |e|
|
83
|
+
|
84
|
+
t = e.time
|
85
|
+
|
86
|
+
t >= start && t <= stop
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
if includePreEvent
|
91
|
+
|
92
|
+
index_to_first_selected_event = all_events.index(es.first)
|
93
|
+
|
94
|
+
if index_to_first_selected_event && index_to_first_selected_event > 0
|
95
|
+
# There is a pre-event so add it
|
96
|
+
es.unshift all_events[index_to_first_selected_event - 1]
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
es
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
# Log an event described by a _message_ optionally with an event type
|
106
|
+
# _eventType_ and data in a hash.
|
107
|
+
#
|
108
|
+
# The _printFrequency_ gives the minimum time that must elapse between
|
109
|
+
# messages for _eventType_ is printed on the IO stream(s).
|
110
|
+
def log message, eventType = nil, data = {}, saveMessageInData = true, printFrequency = 0.0
|
111
|
+
|
112
|
+
# Get current time now, before we waste time in processing this event
|
113
|
+
time, elapsed = time_and_elapsed_time_since_last_event eventType
|
114
|
+
|
115
|
+
event = nil # So we return nil if no event was created
|
116
|
+
|
117
|
+
# We only save the event if an eventType or data was given.
|
118
|
+
if eventType || data.length > 0
|
119
|
+
|
120
|
+
event = Event.new(eventType, data, time)
|
121
|
+
|
122
|
+
save_event event
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
print_message_if_needed message, eventType, printFrequency, time
|
127
|
+
|
128
|
+
event
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
# Log a _newValue_ for the _eventType_. Optionally a message and a name
|
133
|
+
# for a metric can be given but if not we use sensible defaults.
|
134
|
+
def log_value eventType, newValue, message = nil, metric = :_v, printFrequency = 0.0
|
135
|
+
|
136
|
+
log message, eventType, {metric => newValue}, false, printFrequency
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
# Get an array of values for the metric named _metric_ in events
|
141
|
+
# of type _eventType_.
|
142
|
+
def values_for_event_and_metric eventType, metric = :_v
|
143
|
+
events(eventType).map {|e| e.data[metric]}
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return the current (latest) value for a given eventType and metric.
|
147
|
+
# Return nil if no value has been set.
|
148
|
+
def current_value eventType, metric = :_v
|
149
|
+
|
150
|
+
event = events(eventType).last
|
151
|
+
|
152
|
+
return nil unless event
|
153
|
+
|
154
|
+
event.data[metric]
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
# Shortcut method to get the value saved for a certain _eventType_.
|
159
|
+
def values_for eventType
|
160
|
+
values_for_event_and_metric eventType
|
161
|
+
end
|
162
|
+
|
163
|
+
# Return the current (latest) value for a given eventType and metric.
|
164
|
+
# Return nil if no value has been set.
|
165
|
+
def previous_value eventType, metric = :_v
|
166
|
+
|
167
|
+
event = events(eventType)[-2]
|
168
|
+
|
169
|
+
return nil unless event
|
170
|
+
|
171
|
+
event.data[metric]
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
# Return the values at each _step_ between _start_ (inclusive) and _stop_
|
176
|
+
# (exclusive) for _eventType_ and _metric_. Both _start_, _stop_ can be
|
177
|
+
# either a Time object or a number of milli seconds (if they are integers).
|
178
|
+
# The _step_ should be given as milliseconds and defaults to one second,
|
179
|
+
# i.e. 1_000.
|
180
|
+
def values_in_steps_between eventType, start = UnixEpoch, stop = Time.now, step = 1_000, metric = :_v
|
181
|
+
|
182
|
+
# Get events in the given interval. Since we send true to this method
|
183
|
+
# the events will include the one event prior to _start_ time if
|
184
|
+
# it exists.
|
185
|
+
events = events_between(start, stop, eventType, true)
|
186
|
+
|
187
|
+
#puts events.inspect
|
188
|
+
|
189
|
+
current_msec = start.is_a?(Integer) ? start : start.milli_seconds
|
190
|
+
|
191
|
+
stop_msec = stop.is_a?(Integer) ? stop : stop.milli_seconds
|
192
|
+
|
193
|
+
if events.first != nil && events.first.time.milli_seconds <= current_msec
|
194
|
+
|
195
|
+
#puts "1"
|
196
|
+
|
197
|
+
prev_value = events.first.data[metric]
|
198
|
+
|
199
|
+
values_at_steps events.drop(1), current_msec, stop_msec, step, prev_value, metric
|
200
|
+
|
201
|
+
else
|
202
|
+
|
203
|
+
#puts "2"
|
204
|
+
|
205
|
+
values_at_steps events, current_msec, stop_msec, step, nil, metric
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def values_at_steps events, currentMsec, stopMsec, step, prevValue, metric
|
214
|
+
|
215
|
+
#puts "curr = #{currentMsec}, stop = #{stopMsec}, step = #{step}, prevValue = #{prevValue}"
|
216
|
+
|
217
|
+
e, *rest = events
|
218
|
+
|
219
|
+
if e.nil?
|
220
|
+
|
221
|
+
#puts "a"
|
222
|
+
|
223
|
+
return [] if currentMsec >= stopMsec
|
224
|
+
|
225
|
+
# No more events so fill up with prevValue
|
226
|
+
[prevValue] * ((stopMsec - currentMsec) / step)
|
227
|
+
|
228
|
+
else
|
229
|
+
|
230
|
+
#puts "b"
|
231
|
+
|
232
|
+
next_event_msec = e.time.milli_seconds
|
233
|
+
|
234
|
+
q, m = (next_event_msec - currentMsec).divmod(step)
|
235
|
+
|
236
|
+
vs = [prevValue] * q
|
237
|
+
|
238
|
+
if m == 0
|
239
|
+
if next_event_msec < stopMsec
|
240
|
+
vs << e.data[metric]
|
241
|
+
else
|
242
|
+
return vs
|
243
|
+
end
|
244
|
+
else
|
245
|
+
vs << prevValue
|
246
|
+
end
|
247
|
+
|
248
|
+
next_msec = currentMsec + (q + 1) * step
|
249
|
+
|
250
|
+
vs + values_at_steps( rest, next_msec, stopMsec, step, e.data[metric], metric )
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
# Set up the internal data store.
|
257
|
+
def setup_data_store
|
258
|
+
# For this default logger class we just use an array of the events for each
|
259
|
+
# event type.
|
260
|
+
@events = Hash.new {|h,k| h[k] = Array.new}
|
261
|
+
end
|
262
|
+
|
263
|
+
# Return the current time and elapsed time since we last logged an event of
|
264
|
+
# this type.
|
265
|
+
# If a filter is given it is used to filter the events (of this type)
|
266
|
+
# before selecting the one to compare current time to.
|
267
|
+
def time_and_elapsed_time_since_last_event(eventType = nil, &filter)
|
268
|
+
|
269
|
+
if filter
|
270
|
+
latest = events(eventType).reverse.find(&filter)
|
271
|
+
else
|
272
|
+
latest = events(eventType).last
|
273
|
+
end
|
274
|
+
|
275
|
+
t = Time.now
|
276
|
+
|
277
|
+
return [t, 0.0] unless latest
|
278
|
+
|
279
|
+
return t, (t - latest.time)
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
# Save the event in the data store.
|
284
|
+
def save_event event
|
285
|
+
@events[event.type] << event
|
286
|
+
event
|
287
|
+
end
|
288
|
+
|
289
|
+
def summary_stats eventType, metric
|
290
|
+
values_for_event_and_metric(eventType, metric).summary_stats
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
#describe 'EventLogger' do
|
295
|
+
#
|
296
|
+
# before do
|
297
|
+
# @sio = StringIO.new
|
298
|
+
# @l = FeldtRuby::EventLogger.new @sio, {:verbose => true}
|
299
|
+
# end
|
300
|
+
#
|
301
|
+
#
|
302
|
+
# it 'returns an event from the log method if an event was logged' do
|
303
|
+
#
|
304
|
+
# e = @l.log "1", :a
|
305
|
+
# e.must_be_instance_of FeldtRuby::EventLogger::Event
|
306
|
+
#
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# it 'does not print messages to io stream(s) if verbose flag is false' do
|
310
|
+
#
|
311
|
+
# sio = StringIO.new
|
312
|
+
# l = FeldtRuby::EventLogger.new(sio, {:verbose => false})
|
313
|
+
#
|
314
|
+
# l.log "event 1", :a
|
315
|
+
# sio.string.must_equal ""
|
316
|
+
#
|
317
|
+
# l.verbose = true
|
318
|
+
# l.log "event 2", :a
|
319
|
+
# sio.string.split("\n").last[13..-1].must_equal "{a}: event 2"
|
320
|
+
#
|
321
|
+
# l.verbose = false
|
322
|
+
# l.log "event 3", :a
|
323
|
+
# sio.string.split("\n").last[13..-1].must_equal "{a}: event 2" # Still 2 since 3 was not printed
|
324
|
+
#
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# it 'can log events of a given type' do
|
328
|
+
#
|
329
|
+
# @l.log "1", :increase
|
330
|
+
# @sio.string[13..-1].must_equal "{increase}: 1\n"
|
331
|
+
# @l.num_events.must_equal 0
|
332
|
+
# @l.num_events(:increase).must_equal 1
|
333
|
+
#
|
334
|
+
# @l.log "2", :increase
|
335
|
+
# @sio.string[40..-1].must_equal "{increase}: 2\n"
|
336
|
+
# @l.num_events.must_equal 0
|
337
|
+
# @l.num_events(:increase).must_equal 2
|
338
|
+
#
|
339
|
+
# end
|
340
|
+
#
|
341
|
+
# it 'can return old events of given type' do
|
342
|
+
#
|
343
|
+
# @l.log "1", :increase
|
344
|
+
# @l.log "2", :increase
|
345
|
+
# @l.log "0.4", :alpha
|
346
|
+
# @l.log "1", :increase
|
347
|
+
#
|
348
|
+
# ei = @l.events(:increase)
|
349
|
+
# ei.length.must_equal 3
|
350
|
+
#
|
351
|
+
# ea = @l.events(:alpha)
|
352
|
+
# ea.length.must_equal 1
|
353
|
+
#
|
354
|
+
# eb = @l.events(:beta)
|
355
|
+
# eb.length.must_equal 0
|
356
|
+
#
|
357
|
+
# end
|
358
|
+
#
|
359
|
+
# it 'time stamps each log entry' do
|
360
|
+
#
|
361
|
+
# @l.log "1", :a
|
362
|
+
# @l.log "2", :b
|
363
|
+
# @l.log "2", :a
|
364
|
+
#
|
365
|
+
# time_stamps_a = @l.events(:a).map {|e| e.time}
|
366
|
+
# time_stamps_b = @l.events(:b).map {|e| e.time}
|
367
|
+
#
|
368
|
+
# time_stamps_a[0].must_be_instance_of Time
|
369
|
+
# time_stamps_a[1].must_be_instance_of Time
|
370
|
+
# time_stamps_b[0].must_be_instance_of Time
|
371
|
+
#
|
372
|
+
# time_stamps_a[0].must_be :<, time_stamps_a[1]
|
373
|
+
# time_stamps_a[0].must_be :<, time_stamps_b[0]
|
374
|
+
# time_stamps_b[0].must_be :<, time_stamps_a[1]
|
375
|
+
#
|
376
|
+
# end
|
377
|
+
#
|
378
|
+
# it 'can log to multiple io streams' do
|
379
|
+
#
|
380
|
+
# sio2 = StringIO.new
|
381
|
+
# @l.add_io sio2
|
382
|
+
#
|
383
|
+
# @l.log "a"
|
384
|
+
#
|
385
|
+
# @sio.string[13..-1].must_equal "a\n"
|
386
|
+
# sio2.string[13..-1].must_equal "a\n"
|
387
|
+
#
|
388
|
+
# end
|
389
|
+
#
|
390
|
+
# it 'has no value for a metric without events' do
|
391
|
+
#
|
392
|
+
# @l.current_value(:fitness).must_equal nil
|
393
|
+
#
|
394
|
+
# end
|
395
|
+
#
|
396
|
+
# it 'can return the values logged so far' do
|
397
|
+
#
|
398
|
+
# @l.log_value :a, 1.0
|
399
|
+
# @l.previous_value(:a).must_equal nil
|
400
|
+
# @l.current_value(:a).must_equal 1.0
|
401
|
+
# @l.values_for_event_and_metric(:a, :_v).must_equal [1.0]
|
402
|
+
# @l.values_for(:a).must_equal [1.0]
|
403
|
+
#
|
404
|
+
# @l.log_value :a, 2.0
|
405
|
+
# @l.previous_value(:a).must_equal 1.0
|
406
|
+
# @l.current_value(:a).must_equal 2.0
|
407
|
+
# @l.values_for_event_and_metric(:a, :_v).must_equal [1.0, 2.0]
|
408
|
+
# @l.values_for(:a).must_equal [1.0, 2.0]
|
409
|
+
#
|
410
|
+
# @l.log_value :a, 3.0
|
411
|
+
# @l.previous_value(:a).must_equal 2.0
|
412
|
+
# @l.current_value(:a).must_equal 3.0
|
413
|
+
# @l.values_for_event_and_metric(:a, :_v).must_equal [1.0, 2.0, 3.0]
|
414
|
+
# @l.values_for(:a).must_equal [1.0, 2.0, 3.0]
|
415
|
+
#
|
416
|
+
# end
|
417
|
+
#
|
418
|
+
# it 'updates the value when new values are logged' do
|
419
|
+
#
|
420
|
+
# @l.current_value(:Fitness).must_equal nil
|
421
|
+
#
|
422
|
+
# @l.log_value(:Fitness, 1.0)
|
423
|
+
#
|
424
|
+
# expected1 = "{Fitness}: -> 1.0, mean = 1 (min = 1, max = 1, median = 1, stdev = 0)\n"
|
425
|
+
# @sio.string[13..-1].must_equal expected1
|
426
|
+
#
|
427
|
+
# @l.current_value(:Fitness).must_equal 1.0
|
428
|
+
#
|
429
|
+
# @l.log_value(:Fitness, 1.2)
|
430
|
+
#
|
431
|
+
# @l.current_value(:Fitness).must_equal 1.2
|
432
|
+
#
|
433
|
+
# expected2 = "{Fitness}: 1.0 -> 1.2 (+20%), mean = 1.1 (min = 1, max = 1.2, median = 1.1, stdev = 0.1)"
|
434
|
+
# @sio.string.split("\n").last[13..-1].must_equal expected2
|
435
|
+
#
|
436
|
+
# @l.log_value(:Fitness, 0.9)
|
437
|
+
#
|
438
|
+
# @l.current_value(:Fitness).must_equal 0.9
|
439
|
+
#
|
440
|
+
# expected3 = "{Fitness}: 1.2 -> 0.9 (-25%), mean = 1.03 (min = 0.9, max = 1.2, median = 1, stdev = 0.125)"
|
441
|
+
# @sio.string.split("\n").last[13..-1].must_equal expected3
|
442
|
+
#
|
443
|
+
# @l.current_value(:F).must_equal nil
|
444
|
+
#
|
445
|
+
# @l.log_value(:F, 42.0)
|
446
|
+
#
|
447
|
+
# expected4 = "{F}: -> 42.0, mean = 42 (min = 42, max = 42, median = 42, stdev = 0)"
|
448
|
+
# @sio.string.split("\n").last[13..-1].must_equal expected4
|
449
|
+
#
|
450
|
+
# end
|
451
|
+
#
|
452
|
+
# describe "an timed scenario of adding multiple events" do
|
453
|
+
#
|
454
|
+
# before do
|
455
|
+
# @t0 = Time.now
|
456
|
+
# sleep 0.01
|
457
|
+
#
|
458
|
+
# @t1 = Time.now
|
459
|
+
# sleep 0.01
|
460
|
+
#
|
461
|
+
# @l.log "1", :a
|
462
|
+
#
|
463
|
+
# e = @l.log_value :c, 10
|
464
|
+
# @tc10 = e.time
|
465
|
+
#
|
466
|
+
# @t2 = Time.now
|
467
|
+
# sleep 0.01
|
468
|
+
# e = @l.log "2", :a
|
469
|
+
# @ta2 = e.time
|
470
|
+
#
|
471
|
+
# @t3 = Time.now
|
472
|
+
# sleep 0.01
|
473
|
+
# @l.log "3", :a
|
474
|
+
#
|
475
|
+
# @t4 = Time.now
|
476
|
+
# sleep 0.01
|
477
|
+
# @l.log "1", :b
|
478
|
+
# e = @l.log_value :c, 20
|
479
|
+
# @tc20 = e.time
|
480
|
+
#
|
481
|
+
# @t5 = Time.now
|
482
|
+
# sleep 0.01
|
483
|
+
# @l.log "4", :a
|
484
|
+
#
|
485
|
+
# sleep 0.01
|
486
|
+
# @t6 = Time.now
|
487
|
+
#
|
488
|
+
# sleep 0.01
|
489
|
+
# @t7 = Time.now
|
490
|
+
# end
|
491
|
+
#
|
492
|
+
# it 'can return events between certain times' do
|
493
|
+
#
|
494
|
+
# @l.events_between(@t0, @t1, :a).length.must_equal 0
|
495
|
+
#
|
496
|
+
# @l.events_between(@t1, @t6, :a).length.must_equal 4
|
497
|
+
# @l.events_between(@t1, @t6, :a).map {|e| e.data[:_m]}.must_equal ["1", "2", "3", "4"]
|
498
|
+
#
|
499
|
+
# @l.events_between(@t2, @t6, :a).length.must_equal 3
|
500
|
+
# @l.events_between(@t2, @t6, :a).map {|e| e.data[:_m]}.must_equal ["2", "3", "4"]
|
501
|
+
#
|
502
|
+
# @l.events_between(@t3, @t6, :a).length.must_equal 2
|
503
|
+
# @l.events_between(@t3, @t6, :a).map {|e| e.data[:_m]}.must_equal ["3", "4"]
|
504
|
+
#
|
505
|
+
# @l.events_between(@t4, @t6, :a).length.must_equal 1
|
506
|
+
# @l.events_between(@t4, @t6, :a).map {|e| e.data[:_m]}.must_equal ["4"]
|
507
|
+
#
|
508
|
+
# @l.events_between(@t5, @t6, :a).length.must_equal 1
|
509
|
+
# @l.events_between(@t5, @t6, :a).map {|e| e.data[:_m]}.must_equal ["4"]
|
510
|
+
#
|
511
|
+
# @l.events_between(@t6, @t7, :a).length.must_equal 0
|
512
|
+
# @l.events_between(@t6, @t7, :a).map {|e| e.data[:_m]}.must_equal []
|
513
|
+
#
|
514
|
+
# @l.events_between(@t6, @t7, :b).length.must_equal 0
|
515
|
+
# @l.events_between(@t6, @t7, :b).map {|e| e.data[:_m]}.must_equal []
|
516
|
+
#
|
517
|
+
# @l.events_between(@t4, @t5, :b).length.must_equal 1
|
518
|
+
# @l.events_between(@t4, @t5, :b).map {|e| e.data[:_m]}.must_equal ["1"]
|
519
|
+
#
|
520
|
+
# @l.events_between(@t1, @t7, :b).map {|e| e.data[:_m]}.must_equal ["1"]
|
521
|
+
# @l.events_between(@t2, @t7, :b).map {|e| e.data[:_m]}.must_equal ["1"]
|
522
|
+
# @l.events_between(@t3, @t7, :b).map {|e| e.data[:_m]}.must_equal ["1"]
|
523
|
+
#
|
524
|
+
# @l.events_between(@t1, @t6, :c).map {|e| e.data[:_v]}.must_equal [10, 20]
|
525
|
+
# @l.events_between(@t1, @t2, :c).map {|e| e.data[:_v]}.must_equal [10]
|
526
|
+
# @l.events_between(@t2, @t5, :c).map {|e| e.data[:_v]}.must_equal [20]
|
527
|
+
# @l.events_between(@t6, @t7, :c).map {|e| e.data[:_v]}.must_equal []
|
528
|
+
#
|
529
|
+
# end
|
530
|
+
#
|
531
|
+
# it 'can return a pre-event to a time interval if asked to' do
|
532
|
+
#
|
533
|
+
# @l.events_between(@tc10, @t3, :c).length.must_equal 1
|
534
|
+
# @l.events_between(@tc10, @t3, :a).length.must_equal 1
|
535
|
+
#
|
536
|
+
# @l.events_between(@tc10, @t3, :c, true).length.must_equal 1
|
537
|
+
# @l.events_between(@tc10, @t3, :a, true).length.must_equal 2
|
538
|
+
#
|
539
|
+
# end
|
540
|
+
#
|
541
|
+
# # Sleep time above was 0.01 secs => 10 msecs. So what happened is:
|
542
|
+
# # @t0, 10ms, t1, 10ms, a="1", c=10, t2, 10ms,
|
543
|
+
# # a="2", t3, 10ms, a="3", t4, 10ms, b="1", c=20, t5, 10ms, a="4",
|
544
|
+
# # 10ms, t6, 10ms, t7
|
545
|
+
#
|
546
|
+
# it "can return values in steps in intervals when there are no events" do
|
547
|
+
#
|
548
|
+
# @l.values_in_steps_between(:c, @t0, @t1, 5).must_equal [nil, nil]
|
549
|
+
# @l.values_in_steps_between(:c, @t0, @t1, 10).must_equal [nil]
|
550
|
+
#
|
551
|
+
# @l.values_in_steps_between(:c, @t6, @t7, 5).must_equal [nil, nil]
|
552
|
+
# @l.values_in_steps_between(:c, @t6, @t7, 10).must_equal [nil]
|
553
|
+
#
|
554
|
+
# end
|
555
|
+
#
|
556
|
+
# it "can return values in steps in intervals where there are events" do
|
557
|
+
#
|
558
|
+
# sio = StringIO.new
|
559
|
+
# l = FeldtRuby::EventLogger.new sio
|
560
|
+
#
|
561
|
+
# t0 = Time.now
|
562
|
+
# sleep 0.01
|
563
|
+
# t1 = Time.now
|
564
|
+
# sleep 0.01
|
565
|
+
# td1 = l.log_value(:d, 1).time
|
566
|
+
# sleep 0.01
|
567
|
+
# td2 = l.log_value(:d, 2).time
|
568
|
+
# sleep 0.001
|
569
|
+
# t2 = Time.now # t2 should be at least one msec later than td2
|
570
|
+
# sleep 0.011
|
571
|
+
# td3 = l.log_value(:d, 3).time
|
572
|
+
# sleep 0.01
|
573
|
+
# t3 = Time.now
|
574
|
+
#
|
575
|
+
# l.values_in_steps_between(:d, t0, t1, 5).must_equal [nil, nil]
|
576
|
+
#
|
577
|
+
# diff = td2.milli_seconds - td1.milli_seconds
|
578
|
+
#
|
579
|
+
# l.values_in_steps_between(:d, td1, td2, diff-1).must_equal [1, 1]
|
580
|
+
#
|
581
|
+
# # The stop time is exclusive so should NOT be included
|
582
|
+
# l.values_in_steps_between(:d, td1, td2, diff).must_equal [1]
|
583
|
+
# l.values_in_steps_between(:d, td1, td2, diff+1).must_equal [1]
|
584
|
+
#
|
585
|
+
# l.values_in_steps_between(:d, td1, t2, diff-1).must_equal [1, 1]
|
586
|
+
# l.values_in_steps_between(:d, td1, t2, diff).must_equal [1, 2]
|
587
|
+
# l.values_in_steps_between(:d, td1, t2, diff+1).must_equal [1]
|
588
|
+
#
|
589
|
+
# vs = l.values_in_steps_between(:d, t0, t3, 1)
|
590
|
+
#
|
591
|
+
# n = 0
|
592
|
+
# d = td1.milli_seconds - t0.milli_seconds
|
593
|
+
# vs[n, d].must_equal( [nil] * d )
|
594
|
+
#
|
595
|
+
# n += d
|
596
|
+
# d = td2.milli_seconds - td1.milli_seconds
|
597
|
+
# vs[n, d].must_equal( [1] * d )
|
598
|
+
#
|
599
|
+
# n += d
|
600
|
+
# d = td3.milli_seconds - td2.milli_seconds
|
601
|
+
# vs[n, d].must_equal( [2] * d )
|
602
|
+
#
|
603
|
+
# n += d
|
604
|
+
# d = t3.milli_seconds - td3.milli_seconds
|
605
|
+
# vs[n, d].must_equal( [3] * d )
|
606
|
+
#
|
607
|
+
# end
|
608
|
+
#
|
609
|
+
# end
|
610
|
+
#end
|
611
|
+
#
|
612
|
+
#describe "Adding logging to an object and its instance vars" do
|
613
|
+
# class A
|
614
|
+
# include FeldtRuby::Logging
|
615
|
+
#
|
616
|
+
# def initialize(b)
|
617
|
+
# @b = b
|
618
|
+
# setup_logger_and_distribute_to_instance_variables()
|
619
|
+
# end
|
620
|
+
#
|
621
|
+
# def calc
|
622
|
+
# log "entering calc"
|
623
|
+
# val = 1 + @b.calc
|
624
|
+
# log_value :res, val
|
625
|
+
# val
|
626
|
+
# end
|
627
|
+
# end
|
628
|
+
#
|
629
|
+
# class B
|
630
|
+
# include FeldtRuby::Logging
|
631
|
+
#
|
632
|
+
# def initialize(l = nil)
|
633
|
+
# setup_logger_and_distribute_to_instance_variables l
|
634
|
+
# end
|
635
|
+
#
|
636
|
+
# def calc
|
637
|
+
# log "entering B#calc"
|
638
|
+
# v = rand(100)
|
639
|
+
# log_value :b_res, v
|
640
|
+
# v
|
641
|
+
# end
|
642
|
+
# end
|
643
|
+
#
|
644
|
+
# before do
|
645
|
+
# @b = B.new
|
646
|
+
# @a = A.new @b
|
647
|
+
# end
|
648
|
+
#
|
649
|
+
# it 'sets up the sam logger in both A objects and their instance vars' do
|
650
|
+
#
|
651
|
+
# @a.logger.is_a?(FeldtRuby::Logger).must_equal true
|
652
|
+
#
|
653
|
+
# @b.logger.must_equal @a.logger
|
654
|
+
#
|
655
|
+
# end
|
656
|
+
#
|
657
|
+
# it 'uses an explicit logger supplied to a instance var also in the using object' do
|
658
|
+
#
|
659
|
+
# l = FeldtRuby::EventLogger.new
|
660
|
+
# b = B.new l
|
661
|
+
# a = A.new b
|
662
|
+
#
|
663
|
+
# b.logger.must_equal a.logger
|
664
|
+
# a.logger.must_equal l
|
665
|
+
#
|
666
|
+
# end
|
667
|
+
#
|
668
|
+
# it 'logs to the logger' do
|
669
|
+
#
|
670
|
+
# l = @a.logger
|
671
|
+
# l.verbose = false # So we don't print them while testing...
|
672
|
+
#
|
673
|
+
# res = @a.calc()
|
674
|
+
# l.current_value(:res).must_equal res
|
675
|
+
# l.current_value(:b_res).must_equal res-1
|
676
|
+
#
|
677
|
+
# res = @a.calc()
|
678
|
+
# l.current_value(:res).must_equal res
|
679
|
+
# l.current_value(:b_res).must_equal res-1
|
680
|
+
#
|
681
|
+
# end
|
682
|
+
#end
|