keight 0.0.1

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +263 -0
  4. data/Rakefile +92 -0
  5. data/bench/bench.rb +278 -0
  6. data/bench/benchmarker.rb +502 -0
  7. data/bin/k8rb +496 -0
  8. data/keight.gemspec +36 -0
  9. data/lib/keight/skeleton/.gitignore +10 -0
  10. data/lib/keight/skeleton/app/action.rb +98 -0
  11. data/lib/keight/skeleton/app/api/hello.rb +39 -0
  12. data/lib/keight/skeleton/app/form/.keep +0 -0
  13. data/lib/keight/skeleton/app/helper/.keep +0 -0
  14. data/lib/keight/skeleton/app/model/.keep +0 -0
  15. data/lib/keight/skeleton/app/model.rb +144 -0
  16. data/lib/keight/skeleton/app/page/welcome.rb +17 -0
  17. data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
  18. data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
  19. data/lib/keight/skeleton/app/usecase/.keep +0 -0
  20. data/lib/keight/skeleton/config/app.rb +29 -0
  21. data/lib/keight/skeleton/config/app_dev.private +11 -0
  22. data/lib/keight/skeleton/config/app_dev.rb +8 -0
  23. data/lib/keight/skeleton/config/app_prod.rb +7 -0
  24. data/lib/keight/skeleton/config/app_stg.rb +5 -0
  25. data/lib/keight/skeleton/config/app_test.private +11 -0
  26. data/lib/keight/skeleton/config/app_test.rb +8 -0
  27. data/lib/keight/skeleton/config/server_puma.rb +22 -0
  28. data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
  29. data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
  30. data/lib/keight/skeleton/config.rb +44 -0
  31. data/lib/keight/skeleton/config.ru +21 -0
  32. data/lib/keight/skeleton/index.txt +38 -0
  33. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
  34. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
  35. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
  36. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
  37. data/lib/keight/skeleton/tmp/upload/.keep +0 -0
  38. data/lib/keight.rb +2017 -0
  39. data/test/data/example1.jpg +0 -0
  40. data/test/data/example1.png +0 -0
  41. data/test/data/multipart.form +0 -0
  42. data/test/data/wabisabi.js +77 -0
  43. data/test/data/wabisabi.js.gz +0 -0
  44. data/test/keight_test.rb +3161 -0
  45. data/test/oktest.rb +1537 -0
  46. metadata +114 -0
@@ -0,0 +1,502 @@
1
+ ###
2
+ ### $Release: 0.0.1 $
3
+ ### $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
4
+ ### $License: MIT License $
5
+ ###
6
+
7
+
8
+ module Benchmarker
9
+
10
+ VERSION = "$Release: 0.0.1 $".split(/ /)[1]
11
+
12
+ def self.new(opts={}, &block)
13
+ #: creates runner object and returns it.
14
+ runner = RUNNER.new(opts)
15
+ if block
16
+ runner._before_all()
17
+ runner._run(&block)
18
+ runner._after_all()
19
+ end
20
+ runner
21
+ end
22
+
23
+ def self.bm(width=30, &block) # for compatibility with benchmark.rb
24
+ return self.new(:width=>30, &block)
25
+ end
26
+
27
+ def self.platform()
28
+ #: returns platform information.
29
+ return <<END
30
+ benchmarker.rb: release #{VERSION}
31
+ RUBY_VERSION: #{RUBY_VERSION}
32
+ RUBY_PATCHLEVEL: #{RUBY_PATCHLEVEL}
33
+ RUBY_PLATFORM: #{RUBY_PLATFORM}
34
+ END
35
+ end
36
+
37
+
38
+ class Runner
39
+
40
+ def initialize(opts={})
41
+ #: takes :loop, :cycle, and :extra options.
42
+ @loop = opts[:loop]
43
+ @cycle = opts[:cycle]
44
+ @extra = opts[:extra]
45
+ #:
46
+ @tasks = []
47
+ @report = REPORTER.new(opts)
48
+ @stats = STATS.new(@report, opts)
49
+ @_section_title = ""
50
+ @_section_started = false
51
+ end
52
+
53
+ attr_accessor :tasks, :report, :stats
54
+
55
+ def task(label, opts={}, &block)
56
+ #: prints section title if not printed yet.
57
+ #: creates task objet and returns it.
58
+ #: runs task when :skip option is not specified.
59
+ #: skip block and prints message when :skip option is specified.
60
+ #: subtracts times of empty task if exists.
61
+ skip_message = opts[:skip]
62
+ t = _new_task(label, skip_message, &block)
63
+ #: saves created task object unless :skip optin is not specified.
64
+ @tasks << t unless skip_message
65
+ t
66
+ end
67
+
68
+ alias report task # for compatibility with benchmark.rb
69
+
70
+ def empty_task(label="(Empty)", &block)
71
+ #:: clear @_empty_task.
72
+ @_empty_task = nil
73
+ #: prints section title if not printed yet.
74
+ #: creates empty task object and returns it.
75
+ t = _new_task(label, &block)
76
+ #: saves empty task object.
77
+ #:: don't add empty task to @tasks.
78
+ @_empty_task = t
79
+ t
80
+ end
81
+
82
+ #--
83
+ #def skip_task(label, message=" ** skipped **")
84
+ # #: prints section title if not printed yet.
85
+ # t = _new_task(label)
86
+ # #: prints task label and message instead of times.
87
+ # @report.write(message + "\n")
88
+ # #: don't change @tasks.
89
+ #end
90
+ #++
91
+
92
+ def _before_all # :nodoc:
93
+ #: prints Benchmarker.platform().
94
+ print Benchmarker.platform()
95
+ end
96
+
97
+ def _after_all # :nodoc:
98
+ #: prints statistics out benchmarks.
99
+ @stats.all(@tasks)
100
+ end
101
+
102
+ def _run # :nodoc:
103
+ #: when @cycle > 1...
104
+ if @cycle && @cycle > 1
105
+ @all_tasks = []
106
+ #: prints output of cycle into stderr.
107
+ @report._switch_out_to_err do
108
+ #: yields block @cycle times when @extra is not specified.
109
+ #: yields block @cycle + 2*@extra times when @extra is specified.
110
+ i = 0
111
+ cycle = @cycle
112
+ cycle += 2 * @extra if @extra
113
+ cycle.times do
114
+ _reset_section("(##{i+=1})")
115
+ @all_tasks << (@tasks = [])
116
+ #: yields block with self as block paramter.
117
+ yield self
118
+ end
119
+ end
120
+ #: reports average of results.
121
+ @tasks = _calc_averages(@all_tasks, @extra)
122
+ _report_average_section(@tasks)
123
+ #: when @cycle == 0 or not specified...
124
+ else
125
+ #: yields block only once.
126
+ _reset_section("")
127
+ #: yields block with self as block paramter.
128
+ yield self
129
+ end
130
+ end
131
+
132
+ private
133
+
134
+ def _reset_section(section_title)
135
+ @_section_started = false
136
+ @_section_title = section_title
137
+ end
138
+
139
+ def _new_task(label, skip_message=nil, &block)
140
+ #: prints section title if not printed yet.
141
+ _report_section_title_if_not_printed_yet()
142
+ #: creates task objet and returns it.
143
+ t = TASK.new(label, @loop)
144
+ @report.task_label(label)
145
+ #: skip block and prints message when :skip option is specified.
146
+ if skip_message
147
+ @report.write(skip_message + "\n")
148
+ #: runs task when :skip option is not specified.
149
+ elsif block
150
+ t.run(&block)
151
+ #: subtracts times of empty task if exists.
152
+ t.sub(@_empty_task) if @_empty_task
153
+ @report.task_times(t.user, t.sys, t.total, t.real)
154
+ end
155
+ t
156
+ end
157
+
158
+ def _report_section_title_if_not_printed_yet
159
+ if ! @_section_started
160
+ @_section_started = true
161
+ @report.section_title(@_section_title)\
162
+ .section_headers("user", "sys", "total", "real")
163
+ end
164
+ end
165
+
166
+ def _calc_averages(all_tasks, extra)
167
+ #: calculates average times of tasks.
168
+ tasks_list = _transform_all_tasks(all_tasks)
169
+ if extra
170
+ @report.section_title("Remove Min & Max").section_headers("min", "cycle", "max", "cycle")
171
+ tasks_list = tasks_list.collect {|tasks| _remove_min_max(tasks, extra) }
172
+ end
173
+ avg_tasks = tasks_list.collect {|tasks| Task.average(tasks) }
174
+ avg_tasks
175
+ end
176
+
177
+ def _transform_all_tasks(all_tasks)
178
+ tasks_list = []
179
+ all_tasks.each do |tasks|
180
+ tasks.each_with_index do |task, i|
181
+ (tasks_list[i] ||= []) << task
182
+ end
183
+ end
184
+ tasks_list
185
+ end
186
+
187
+ def _remove_min_max(tasks, extra)
188
+ #: reports min and max tasks.
189
+ idx = -1
190
+ pairs = tasks.collect {|task| [task, idx+=1] }
191
+ pairs = pairs.sort_by {|task, idx| task.real } # 1.8 doesn't support sort_by!
192
+ j = -1
193
+ while (j += 1) < extra
194
+ @report.task_label(j == 0 ? pairs[j].first.label : '')
195
+ task, idx = pairs[j] # min
196
+ @report.task_time(task.real).task_index(idx+1)
197
+ task, idx = pairs[-j-1] # max
198
+ @report.task_time(task.real).task_index(idx+1)
199
+ @report.text("\n")
200
+ end
201
+ #: removes min and max tasks, and returns remained tasks.
202
+ remained_tasks = pairs[extra...-extra].collect {|task, idx| task }
203
+ remained_tasks
204
+ end
205
+
206
+ def _report_average_section(tasks)
207
+ title = _get_average_section_title()
208
+ @report.section_title(title).section_headers("user", "sys", "total", "real")
209
+ tasks.each do |t|
210
+ @report.task_label(t.label).task_times(t.user, t.sys, t.total, t.real)
211
+ end
212
+ end
213
+
214
+ def _get_average_section_title()
215
+ #: returns 'Average of N (=x-2*y)' string if label width is enough wide.
216
+ #: returns 'Average of N' string if label width is not enough wide.
217
+ title = "Average of #{@cycle}"
218
+ if @extra
219
+ s = " (=#{@cycle+2*@extra}-2*#{@extra})"
220
+ title << s if "## #{title}#{s}".length <= @report.label_width
221
+ end
222
+ title
223
+ end
224
+
225
+ end
226
+
227
+ RUNNER = Runner
228
+
229
+
230
+ class Task
231
+
232
+ def initialize(label, loop=1, &block)
233
+ #: takes label and loop.
234
+ @label = label
235
+ @loop = loop
236
+ #: sets all times to zero.
237
+ @user = @sys = @total = @real = 0.0
238
+ end
239
+
240
+ attr_accessor :label, :loop, :user, :sys, :total, :real
241
+
242
+ def run
243
+ #: yields block for @loop times.
244
+ ntimes = @loop || 1
245
+ pt1 = Process.times
246
+ t1 = Time.now
247
+ if ntimes > 1
248
+ ntimes.times { yield }
249
+ else
250
+ yield
251
+ end
252
+ pt2 = Process.times
253
+ t2 = Time.now
254
+ #: measures times.
255
+ @user = pt2.utime - pt1.utime
256
+ @sys = pt2.stime - pt1.stime
257
+ @total = @user + @sys
258
+ @real = t2 - t1
259
+ return self
260
+ end
261
+
262
+ def add(other)
263
+ #: adds other's times into self.
264
+ @user += other.user
265
+ @sys += other.sys
266
+ @total += other.total
267
+ @real += other.real
268
+ #: returns self.
269
+ return self
270
+ end
271
+
272
+ def sub(other)
273
+ #: substracts other's times from self.
274
+ @user -= other.user
275
+ @sys -= other.sys
276
+ @total -= other.total
277
+ @real -= other.real
278
+ #: returns self.
279
+ return self
280
+ end
281
+
282
+ def mul(n)
283
+ #: multiplies times with n.
284
+ @user *= n
285
+ @sys *= n
286
+ @total *= n
287
+ @real *= n
288
+ #: returns self.
289
+ return self
290
+ end
291
+
292
+ def div(n)
293
+ #: divides times by n.
294
+ @user /= n
295
+ @sys /= n
296
+ @total /= n
297
+ @real /= n
298
+ #: returns self.
299
+ return self
300
+ end
301
+
302
+ def self.average(tasks)
303
+ #: returns empty task when argument is empty.
304
+ n = tasks.length
305
+ return self.new(nil) if n == 0
306
+ #: create new task with label.
307
+ task = self.new(tasks.first.label)
308
+ #: returns averaged task.
309
+ tasks.each {|t| task.add(t) }
310
+ task.div(n)
311
+ return task
312
+ end
313
+
314
+ end
315
+
316
+ TASK = Task
317
+
318
+
319
+ class Reporter
320
+
321
+ def initialize(opts={})
322
+ #: takes :out, :err, :width, and :format options.
323
+ @out = opts[:out] || $stdout
324
+ @err = opts[:err] || $stderr
325
+ self.label_width = opts[:width] || 30
326
+ self.format_time = opts[:format] || "%9.4f"
327
+ end
328
+
329
+ attr_accessor :out, :err
330
+ attr_reader :label_width, :format_time
331
+
332
+ def _switch_out_to_err() # :nodoc:
333
+ #: switches @out to @err temporarily.
334
+ begin
335
+ out = @out
336
+ @out = @err
337
+ yield
338
+ ensure
339
+ @out = out
340
+ end
341
+ end
342
+
343
+ def label_width=(width)
344
+ #: sets @label_width.
345
+ @label_width = width
346
+ #: sets @format_label, too.
347
+ @format_label = "%-#{width}s"
348
+ end
349
+
350
+ def format_time=(format)
351
+ #: sets @format_time.
352
+ @format_time = format
353
+ #: sets @format_header, too.
354
+ m = /%-?(\d+)\.\d+/.match(format)
355
+ @format_header = "%#{$1.to_i}s" if m
356
+ end
357
+
358
+ def write(*args)
359
+ #: writes arguments to @out with '<<' operator.
360
+ args.each {|x| @out << x.to_s }
361
+ #: saves the last argument.
362
+ @_prev = args[-1]
363
+ #: returns self.
364
+ return self
365
+ end
366
+ alias text write
367
+
368
+ def report_section_title(title)
369
+ #: prints newline at first.
370
+ write "\n"
371
+ #: prints section title with @format_label.
372
+ write @format_label % "## #{title}"
373
+ #: returns self.
374
+ return self
375
+ end
376
+ alias section_title report_section_title
377
+
378
+ def report_section_headers(*headers)
379
+ #: prints headers.
380
+ headers.each do |header|
381
+ report_section_header(header)
382
+ end
383
+ #: prints newline at end.
384
+ write "\n"
385
+ #: returns self.
386
+ return self
387
+ end
388
+ alias section_headers report_section_headers
389
+
390
+ def report_section_header(header)
391
+ #: prints header with @format_header.
392
+ write " ", @format_header % header
393
+ #: returns self.
394
+ return self
395
+ end
396
+ alias section_header report_section_header
397
+
398
+ def report_task_label(label)
399
+ #: prints task label with @format_label.
400
+ write @format_label % label
401
+ #: returns self.
402
+ return self
403
+ end
404
+ alias task_label report_task_label
405
+
406
+ def report_task_times(user, sys, total, real)
407
+ #: prints task times with @format_time.
408
+ fmt = @format_time
409
+ write " ", fmt % user, " ", fmt % sys, " ", fmt % total, " ", fmt % real, "\n"
410
+ #: returns self.
411
+ return self
412
+ end
413
+ alias task_times report_task_times
414
+
415
+ def report_task_time(time)
416
+ #: prints task time with @format_titme.
417
+ write " ", @format_time % time
418
+ #: returns self.
419
+ return self
420
+ end
421
+ alias task_time report_task_time
422
+
423
+ def report_task_index(index)
424
+ #: prints task time with @format_titme.
425
+ write " ", @format_header % "(##{index})"
426
+ #: returns self.
427
+ return self
428
+ end
429
+ alias task_index report_task_index
430
+
431
+ end
432
+
433
+ REPORTER = Reporter
434
+
435
+
436
+ class Stats
437
+
438
+ def initialize(reporter, opts={})
439
+ #: takes reporter object.
440
+ @report = reporter
441
+ @key = opts[:key] || 'real'
442
+ @sort_key = opts[:sort_key] || 'real'
443
+ @loop = opts[:loop]
444
+ @numerator = opts[:numerator]
445
+ end
446
+
447
+ def all(tasks)
448
+ ranking(tasks)
449
+ ratio_matrix(tasks)
450
+ end
451
+
452
+ def ranking(tasks)
453
+ tasks = tasks.sort_by {|t| t.__send__(@sort_key) } if @sort_key
454
+ #: prints ranking.
455
+ key = @key
456
+ @report.section_title("Ranking").section_headers(key.to_s)
457
+ #base = tasks.min_by {|t| t.__send__(key) }.__send__(key) # min_by() is available since 1.8.7
458
+ base = tasks.collect {|t| t.__send__(key) }.min
459
+ tasks.each do |task|
460
+ sec = task.__send__(key).to_f
461
+ val = 100.0 * base / sec
462
+ @report.task_label(task.label).task_time(sec).text(" (%5.1f%%) " % val)
463
+ #: prints barchart if @numerator is not specified.
464
+ if ! @numerator
465
+ bar = '*' * (val / 5.0).round
466
+ @report.text(bar).text("\n")
467
+ #: prints inverse number if @numerator specified.
468
+ else
469
+ @report.text("%12.2f per sec" % (@numerator/ sec)).text("\n")
470
+ end
471
+ end
472
+ end
473
+
474
+ def ratio_matrix(tasks)
475
+ tasks = tasks.sort_by {|t| t.__send__(@sort_key) } if @sort_key
476
+ #: prints matrix.
477
+ key = @key
478
+ @report.section_title("Matrix").section_header("real")
479
+ tasks.each_with_index do |t, i|
480
+ @report.text(" %8s" % ("[%02d]" % (i+1)))
481
+ end
482
+ @report.text("\n")
483
+ i = 0
484
+ tasks.each do |base_task|
485
+ i += 1
486
+ base = base_task.__send__(key).to_f
487
+ @report.task_label("[%02d] %s" % [i, base_task.label]).task_time(base)
488
+ tasks.each do |t|
489
+ sec = t.__send__(key).to_f
490
+ val = 100.0 * sec / base
491
+ @report.text(" %7.1f%%" % val)
492
+ end
493
+ @report.text("\n")
494
+ end
495
+ end
496
+
497
+ end
498
+
499
+ STATS = Stats
500
+
501
+
502
+ end