yard-bench 0.0.2

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/dsl/bm_dsl.rb ADDED
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+
3
+ require 'benchmark'
4
+ require_relative 'monkeypatches'
5
+
6
+ # ⌚ :meth1, :meth2
7
+ # The information should be normalized and collected in a kind of knowledge base
8
+ module YARD
9
+ module Bench
10
+ # Class to be included for benchmarking DSL.
11
+ #
12
+ # It contains `Hash` of the following structure:
13
+ # —
14
+ class Marks
15
+ include YARD::MonkeyPatches
16
+
17
+ class Mark
18
+ attr_reader :times, :memory, :power, :deviation, :ok
19
+ def initialize(times, memory)
20
+ @times = times
21
+ @memory = memory
22
+ @ok = !@times.nil? && !@memory.nil?
23
+ normalized_times = @times.inject([]) { |agg, e| agg << (e.values[0] / (10**agg.size)) }
24
+ @deviation = normalized_times.standard_deviation * 100 / normalized_times.mean
25
+ @power = normalized_times.mean / @times[0].keys[0] * 1_000_000 if @ok && @deviation < 20
26
+ end
27
+ end
28
+
29
+ protected
30
+ # Standard time for the current processor/ram to normalize benchmarks
31
+ STANDARD_TIME ||= Benchmark.measure { 1_000_000.times { "foo bar baz".capitalize }}.total
32
+
33
+ # Mark specified method of a class to be benchmarkable
34
+ #
35
+ # @param clazz [Class] the class method is defined on
36
+ # @param meth [Symbol] the method(s) to set as benchmarkable; may be a wildcard
37
+ # @return [Hash] a set of methods marked benchmarkable for the desired class
38
+ def self.∈ clazz, meth
39
+ get_methods(clazz, meth).map {|m| bm…(clazz)[:methods][m] ||= nil}
40
+ end
41
+
42
+ # Mark specified method of a class to be benchmarkable and immediately benchmark
43
+ #
44
+ # @param clazz [Class] the class method is defined on
45
+ # @param meth [Symbol] the method(s) to set as benchmarkable; may be a wildcard
46
+ # @return [Hash] a set of methods marked benchmarkable for the desired class
47
+ def self.∈! clazz, meth
48
+ get_methods(clazz, meth).map { |m| bm…(clazz)[:methods][m] ||= self.mark(clazz, m) }
49
+ end
50
+
51
+ # Calculates benchmarks for all the marked methods
52
+ def self.⌛
53
+ bm… { |c, ms| # "String" => { :class => String, :methods => {…} }
54
+ ms[:methods].each { |m, marks| # { :capitalize => …, :split => nil }
55
+ ms[:methods][m] = self.mark(ms[:class], m) if marks.nil?
56
+ yield ms[:class], m, ms[:methods][m] if block_given?
57
+ }
58
+ }
59
+ end
60
+
61
+ private
62
+ def self.mark(clazz, m)
63
+ begin
64
+ (1..10).each { # Sometimes benchmark returns 0 for unknown reason. Ugly hack to mostly avoid.
65
+ mark = Mark.new(⌚(clazz, m), ☑(clazz, m))
66
+ break mark if mark.times[0].values[0] > 0
67
+ log.warn "Benchmarks returned zeroes: #{mark.times}, remeasuring…"
68
+ }
69
+ rescue
70
+ log.warn("Error calculating benchmarks: 〈#{$!}〉")
71
+ Mark.new(nil, nil)
72
+ end
73
+ end
74
+ # Get methods by their name with wildcards.
75
+ # @param clazz [Class] the class to retrieve methods for
76
+ # @param pattern [Symbol] the pattern to get method names for, either symbol,
77
+ # representing the method, or one of the wildcards “:×”, “:××”, “:⋅”, “:⋅⋅”
78
+ # @return [Array<Symbol>] an array of methods
79
+ def self.get_methods(clazz, pattern)
80
+ case pattern
81
+ # puts all the methods, defined in this class to benchmarks
82
+ when :⋅ then clazz.instance_methods(false)
83
+ # puts all the methods, defined in this class and superclasses to benchmarks
84
+ when :⋅⋅ then clazz.instance_methods(true)
85
+ # puts all the singleton methods, defined in this class to benchmarks
86
+ when :× then clazz.singleton_methods(false)
87
+ # puts all the singleton methods, defined in this class and superclasses to benchmarks
88
+ when :×× then clazz.singleton_methods(true)
89
+ else [pattern]
90
+ end
91
+ end
92
+
93
+ # Get all the benchmarks for the class. Lazy creates a `Set` to store
94
+ # benchmarks for future use if there is no benchmarks for the given class yet.
95
+ #
96
+ # @param clazz [Class] the class to return benchmarks for
97
+ # @return [Hash] all the benchmarks, collected from DSL as following
98
+ # benchmarks = {
99
+ # "String" => <Hash: {:class => String.class, :methods => {:capitalize => {benchmarks}, :split => nil}}>,
100
+ # "AClass" => <Hash: {:class => AClass.class, :methods => {:do_it => nil}}>
101
+ # }
102
+ def self.bm… clazz = nil
103
+ it = (@@benchmarks ||= {}) # Hash { String => { :capitalize => {…}, :split => nil }}
104
+ it = (it[clazz.to_s] ||= {:class => clazz, :methods => {}}) unless clazz.nil?
105
+ if block_given?
106
+ it.each(&Proc.new)
107
+ else
108
+ it
109
+ end
110
+ end
111
+
112
+ public
113
+ # Returns benchmarks for the method given by spec (or the whole collection if none specified)
114
+ def self.get file, namespace, m
115
+ load "#{file}"
116
+ self.∈! Object.const_get(namespace), m
117
+ end
118
+
119
+ # Measures the specified method of the class given
120
+ # @param clazz [Class] the class to measure method for
121
+ # @param m [Symbol] the method to measure
122
+ # @param iterations [Fixnum] an amount of iterations to do
123
+ # @return benchmarking total, normalized by STANDARD_TIME and 1_000_000 times
124
+ def self.⌚ clazz, m, iterations = 3
125
+ # Let’ calculate the applicable range
126
+ deg = (1..10).each { |v|
127
+ break v if Benchmark.measure { (10**v).times {clazz.☏ m} }.total > 0.01
128
+ }
129
+ (deg...deg+iterations).to_a.map { |d| 10**d }.map { |e|
130
+ { e => Benchmark.measure { e.times {clazz.☏ m} }.total / STANDARD_TIME }
131
+ }
132
+ end
133
+ # Measures the memory required for a method in KBytes.
134
+ # FIXME This is VERY inaccurate and lame.
135
+ # @param clazz [Class] the class to measure method for
136
+ # @param m [Symbol] the method to measure
137
+ # @param iterations [Fixnum] an amount of iterations to do
138
+ # @return an approximate amount of kilobytes
139
+ def self.☑ clazz, m, iterations = 10
140
+ kb = `ps -o rss= -p #{$$}`.to_i
141
+ iterations.times.map {
142
+ clazz.☏ m
143
+ `ps -o rss= -p #{$$}`.to_i
144
+ }.reduce(:+) / iterations - kb
145
+ end
146
+ end
147
+
148
+ module ::Kernel
149
+ # Mark the task for benchmarking
150
+ # @param attribs [[:rest]] the list of methods to benchmark
151
+ def ⌚ *attribs
152
+ attribs.each { |a| YARD::Bench::Marks.∈ self, a.to_sym }
153
+ end
154
+ alias benchmark ⌚
155
+
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,334 @@
1
+ # encoding: utf-8
2
+
3
+ module YARD
4
+ # Monkey patches (🐵) for shorthands.
5
+ #
6
+ # This module introduces new functionality
7
+ # for creation of some standard classes “samples.” It is used to emulate
8
+ # real data to be passed to automatic benchmarks in cases, when the methods
9
+ # have parameters required.
10
+ #
11
+ # @example To produce new random +String+, +Hash+, +Array+, +Fixnum+, one simply calls:
12
+ # % pry
13
+ # > require './lib/dsl/monkeypatches'
14
+ # # ⇒ true
15
+ # > String.∀ size: 30
16
+ # # ⇒ "3XсO91Lпр490Rэщ Xза O нL с3VщB"
17
+ # > Fixnum.∀
18
+ # # ⇒ 301
19
+ # > Hash.∀ size: 3
20
+ # # ⇒ {
21
+ # # "aenvxgmsuqhpxgsbhrcjvyvhlrbexa" => "ьюWB4IVачъитяCи жH3O 8илыP Dц Kх",
22
+ # # "awohozdxdjzvombswswsfzsqfqfguxc" => 202,
23
+ # # "befqyvqhmrncboilgdjwbqpyvfgtp" => "ифMцGSь фъ BубITмPэIHрTJлъ9OдJщ9"
24
+ # # }
25
+ # > Array.∀ size: 3
26
+ # # ⇒ [
27
+ # # [0] " эвъуL P 5июоCXъXе AB0 й1DьUфв",
28
+ # # [1] 800,
29
+ # # [2] 851
30
+ # # ]
31
+ # @author Alexei Matyushkin <am@mudasobwa.ru>
32
+ module MonkeyPatches
33
+
34
+ class ::Array
35
+ # @source def … ; block_given? ? each(&Proc.new) : each ; end
36
+ alias … each
37
+ # def ≠ ; block_given? ? reject(&Proc.new) : reject ; end
38
+ alias ≠ reject
39
+ # def ≡ ; block_given? ? select(&Proc.new) : select ; end
40
+ alias ≡ select
41
+ end
42
+ class ::Hash
43
+ # def … ; block_given? ? each(&Proc.new) : each ; end
44
+ alias … each
45
+ end
46
+
47
+ # Enchancement of +String+ class to generate random sample based on the pattern given.
48
+ class ::String
49
+ # Generates random sample of +String+.
50
+ # @example To create the string of length 12, consisting of lowercased latin letters:
51
+ # s1 = ('a'..'z').to_chars.∀ 12 # ⇒ fughtksnewqp
52
+ # s2 = "".∀(12, ('a'..'z')) # ⇒ jiuuoiqwbjty
53
+ # @see Range#to_chars
54
+ # @todo Possible wanna use {http://faker.rubyforge.org Faker} here
55
+ # @param size [Fixnum] the size of the sample to generate.
56
+ # @param symbols [Array<Char>] the list of characters used to generate the sample.
57
+ # @return [String] the string of the given length, consisting of random characters from the given set.
58
+ def ∀(size: 32, symbols: [*('A'..'Z'), *('а'..'я'), *('0'..'9'), *[' ']*10])
59
+ syms = case
60
+ when !self.empty? then self.scan('.')
61
+ when !(Array === symbols) && symbols.respond_to?(:to_a) then symbols.to_a
62
+ else symbols
63
+ end
64
+ raise ArgumentError.new("`:symbols` argument class must support `#sample` method (given #{symbols})") \
65
+ unless syms.respond_to? :sample
66
+ "".tap { |v| size.times { v << syms.sample } }.squeeze
67
+ end
68
+ alias any ∀
69
+ end
70
+
71
+ # Enchancement of +Fixnum+ class to generate random number in the interval [0, Fixnum).
72
+ class ::Fixnum
73
+ # Generates random +Fixnum+ in the given interval.
74
+ # @example To create the positive number not greater than 1000:
75
+ # num = 1000.∀ # ⇒ 634
76
+ # @return a random number in the given interval.
77
+ def ∀
78
+ rand(self)
79
+ end
80
+ alias any ∀
81
+
82
+ # Generates random +Fixnum+ in the given interval. We need +Fixnum+ implementing
83
+ # +new+ method for instantiating it as parameter in common way.
84
+ # @example To create the positive number not greater than 1000:
85
+ # num = Fixnum.new 1000 # ⇒ 48
86
+ def self.new val = 1024
87
+ val.∀
88
+ end
89
+ end
90
+
91
+ # Enchancement of +Array+ class to generate random array of the given size. The array elements
92
+ # are instances of the samples given. E. g. by default, there is an array of strings and fixnums
93
+ # produced.
94
+ class ::Array
95
+ # Generates random sample of +Array+.
96
+ # @example To create an array of three string elements:
97
+ # [""].∀ size: 3
98
+ # # ⇒ [
99
+ # # [0] " пт64AVAэеыGN еCйдчDLFUL еPTюQL ",
100
+ # # [1] "лW1O Cи 4TZ Yиз моBи2 AзмсU5г о ",
101
+ # # [2] "70ZIзQOMXC0нXLPMкGдлэY7Bщ7Eх ой4"
102
+ # # ]
103
+ # @param size [Fixnum] the size of the sample array to generate.
104
+ # @param samples [Array] the array of samples used to generate the sample array.
105
+ # @return [Array] the array of the given length, consisting of random elements from the given set.
106
+ def ∀(size: 64, samples: ["", 1000])
107
+ samples = self unless self.empty?
108
+ [].tap { |v| size.times { v << ::Kernel::random(:samples => samples) } }
109
+ end
110
+ alias any ∀
111
+ end
112
+
113
+ # Enchancement of +Hash+ class to generate random hash of the given size. The hash elements
114
+ # are instances of the samples given. The keys are in the range +(‘a’..‘z’)+.
115
+ # By default, there is a hash having strings and fixnums as values.
116
+ class ::Hash
117
+ # Generates random sample of +Hash+.
118
+ # @note When called on non-empty hash, the random elements are _added_ to the existing.
119
+ # @todo Do we really need to append randoms? Isn’t +{}.∀ | {:foo ⇒ 42}+ clearer?
120
+ # @example To create a hash of three elements:
121
+ # {}.∀ size: 3
122
+ # # ⇒ {
123
+ # # "pcnoljbhibgjywosztzheuimqfawzi" => 821,
124
+ # # "rjdrhidkhrowsonpsmaskdjfbhpuwunh" => " рлшеALя н нмкж0отDщ5 MеьFKB1Mъ5",
125
+ # # "zbalqtiqysdfbartnebvkmwzvudxkzmk" => "Dе904KшNщуO7EывхJбMUV йN Zч энж"
126
+ # # }
127
+ # @param size [Fixnum] the size of the sample hash to generate.
128
+ # @param samples [Array] the array of samples used to generate the values of the sample hash.
129
+ # @return [Hash] the hash of the given length, consisting of random elements from the given set.
130
+ def ∀(size: 64, samples: ["", 1000])
131
+ self.dup.tap { |v|
132
+ size.times {
133
+ v["".∀(:symbols => [*('a'..'z')])] = ::Kernel::random(:samples => samples)
134
+ }
135
+ }
136
+ end
137
+ alias any ∀
138
+ end
139
+
140
+ # Enchancement of +Range+ class to join range elements into string.
141
+ class ::Range
142
+ # Joins range elements into string.
143
+ # @return [String] string representation of the range
144
+ def to_chars
145
+ self.to_a.join
146
+ end
147
+ end
148
+
149
+ # @private
150
+ module ::Enumerable
151
+ def sum
152
+ self.inject(0){|accum, i| accum + i }
153
+ end
154
+
155
+ def mean
156
+ self.sum/self.length.to_f
157
+ end
158
+
159
+ def sample_variance
160
+ m = self.mean
161
+ sum = self.inject(0){|accum, i| accum +(i-m)**2 }
162
+ sum/(self.length - 1).to_f
163
+ end
164
+
165
+ def standard_deviation
166
+ return Math.sqrt(self.sample_variance)
167
+ end
168
+ end
169
+
170
+ # Helper for parsing argument errors in machine-readable collection.
171
+ class ::ArgumentError
172
+ # Parses the error string and returns the machine-readable argument count contract.
173
+ # @return [Hash] consisting of an amount of arguments given,
174
+ # minimal required and (if makes sense) maximal.
175
+ def argument_data
176
+ # ⇒ wrong number of arguments (1 for 2..3)
177
+ /\((?<given>\d+)\s+\w+\s+(?<min_required>\d+)(?<modifier>\+|\.\.)?(?<max_required>\d+)\)/.match(self.to_s) { |m|
178
+ { :given => m[:given],
179
+ :min_required => m[:min_required],
180
+ :max_required => case m[:modifier]
181
+ when '+' then '∞'
182
+ when '..' then h[:max_required]
183
+ else h[:min_required]
184
+ end
185
+ }
186
+ }
187
+ end
188
+ end
189
+
190
+ # Helper for parsing type errors in machine-readable format.
191
+ class ::TypeError
192
+ # Parses the error string and returns the machine-readable expected arguments classes.
193
+ # @return [Hash] consisting of two strings representing _given_ and _required_ argument types.
194
+ def type_data
195
+ # ⇒ can't convert Hash into Integer
196
+ # There are two ways to match: either rely on us locale, or find the uppercased classes
197
+ /[^[A-Z]]*(?<given>[A-Z]\w*)[^[A-Z]]*(?<required>[A-Z]\w*)/.match(self.to_s) { |m|
198
+ { :given => m[:given], :required => m[:required] }
199
+ }
200
+ end
201
+ end
202
+
203
+ # Some aestetics in aliasing:
204
+ # @example
205
+ # my_proc = λ { |e| puts e } # ⇒ lambda, strict parameters list
206
+ # my_proc = Λ { |e| puts e } # ⇒ proc, not strict parameters list
207
+ module ::Kernel
208
+ # Alias for lambda
209
+ alias λ lambda
210
+ # Alias for proc
211
+ alias Λ proc
212
+ # default set of classes, supporting `random` feature
213
+ DEFAULT_SAMPLES ||= ["", 1024, {}, []].freeze
214
+ # @private
215
+ # The stub class for determining parameter list
216
+ class RandomVoid ; def ∀ ; NotImplementedError.new('RandomVoid class is not intended to use.') ; end ; end
217
+
218
+ protected
219
+ # Random instance of random class
220
+ # @param samples [Array] the instances of classes supporting +#random+ method.
221
+ # Those will vbe used as initial parameters for calls to `random` on them.
222
+ # @return [Object] random instance of one of the classes given as parameters
223
+ def random(samples: DEFAULT_SAMPLES)
224
+ samples.dup.sample.∀
225
+ end
226
+ end
227
+
228
+ # Helpers for calling methods and instantiate class silently, even if there are
229
+ # arguments to be passed to constructor/method. The main idea is to try to guess
230
+ # the parameters, awaited by method, generate randoms for them and finally call
231
+ # the method on the singleton instance of this class.
232
+ class ::Class
233
+ # Instance of a class, lazy initialized with guessed parameters. Cached.
234
+ # @note There is a possibility to explicitely set the singleton instance, in which case all the methods will be called on it.
235
+ # @todo Maybe we need to overwrite setter for this variable to avoid weird settings like +String.★ = Fixnum.new+
236
+ # @see ☎
237
+ attr_accessor :★
238
+ # The result of last call to method with with fake params. Cached.
239
+ # @see ☏
240
+ attr_reader :☆
241
+
242
+ # Tries to make a new instance of a class
243
+ def ☎
244
+ fake_parameters unless @★
245
+ @★
246
+ end
247
+
248
+ # Tries to call a method +m+ on a class.
249
+ # @param m [Symbol] the method to be called.
250
+ # @return [Object] the result of call to method +m+
251
+ def ☏ m = :to_s
252
+ ☎.send(m, *fake_parameters(:m => m))
253
+ end
254
+
255
+ # Instantiates the class with applicable random value.
256
+ # @param args [Array] if passed, used as sceleton for a call to {#∀} method.
257
+ # @return [Instance] a random value of this Class class.
258
+ def ∀ *args
259
+ begin
260
+ inst = self.☎
261
+ raise NotImplementedError.new("The class should implement `∀` instance method") \
262
+ unless inst.respond_to? :∀
263
+ inst.∀ *args
264
+ rescue Exception => e
265
+ raise NotImplementedError.new("No way: #{e}")
266
+ end
267
+ end
268
+
269
+ private
270
+ # First of all, let′s try to determine parameters needed:
271
+ #
272
+ # method(__method__).parameters.inject([]) { |res, v| (res << v[1]) if v[0] == :req; res }
273
+ # method(__method__).parameters.select { |a| a[0] == :req }.map { |a| a[1] }
274
+ #
275
+ # Rehearsal ----------------------------------------------
276
+ # inject 0.510000 0.000000 0.510000 ( 0.507843)
277
+ # select+map 0.470000 0.000000 0.470000 ( 0.472166)
278
+ # ------------------------------------- total: 0.980000sec
279
+ # user system total real
280
+ # inject 0.520000 0.000000 0.520000 ( 0.518626)
281
+ # select+map 0.470000 0.000000 0.470000 ( 0.473081)
282
+ #
283
+ # That’s why we are to use `select+map` version.
284
+ def required_parameters(m: :initialize)
285
+ param_selector = λ{ |type|
286
+ self.instance_method(m).parameters.select { |p| p[0] == type }.map { |p| p[1] }
287
+ }
288
+ { :req => param_selector.call(:req), :rest => param_selector.call(:rest) }
289
+ end
290
+ # Suggests random parameters for instance method of a class
291
+ # Usage: `String.fake_parameters :method`
292
+ # @param m [Symbol] the method to suggest parameters for
293
+ # @return [Array] an array of parameters suggested
294
+ def fake_parameters(m: nil)
295
+ if (@☆ ||= {})[m].nil?
296
+ # We need an instance first of all
297
+ if m.nil? || !@★
298
+ params = required_parameters
299
+ guessed = [].∀(:size => params[:req].size, :samples => [RandomVoid.new])
300
+ guessed.map! { |elem|
301
+ begin
302
+ elem if @★ ||= self.new(*guessed)
303
+ rescue TypeError => e
304
+ ::Kernel.const_get(e.type_data[:required]).new.∀
305
+ end
306
+ }
307
+ @★ ||= self.new(*guessed)
308
+ @☆[nil] = guessed.map(&:class)
309
+ end
310
+
311
+ # Let’s proceed with method
312
+ unless m.nil?
313
+ params = required_parameters :m => m
314
+
315
+ guessed = [].∀(:size => params[:req].size, :samples => [RandomVoid.new])
316
+ guessed.map! { |elem|
317
+ begin
318
+ elem if @☆=@★.send(m, *guessed)
319
+ rescue TypeError => e
320
+ ::Kernel.const_get(e.type_data[:required]).new.∀
321
+ end
322
+ }
323
+ @☆[m] = guessed.map(&:class)
324
+ end
325
+
326
+ guessed
327
+ else
328
+ @☆[m].map(&:∀)
329
+ end
330
+ end
331
+ end
332
+
333
+ end
334
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../dsl/bm_dsl'
4
+
5
+ # FIXME Probably, that class is to be made as Proxy. Then during the methods
6
+ # processing we’ll have an access to it to print the benchmarks out
7
+ # within method scope…
8
+ module YARD
9
+ module Handlers
10
+ # class BenchmarkObject < YARD::CodeObjects::Base
11
+ # def type ; :benchmark ; end
12
+ # def sep ; '%' ; end
13
+ # end
14
+
15
+ class BenchmarkHandler < YARD::Handlers::Ruby::DSLHandler
16
+ handles method_call(:benchmark)
17
+ handles method_call(:⌚)
18
+ # we should only match method calls inside a namespace (class or module), not inside a method
19
+ # namespace_only
20
+
21
+ def process
22
+ cos = []
23
+ statement.parameters.each { |astnode|
24
+ if astnode.respond_to? :jump
25
+ m = "#{astnode.jump(:string_content).source[1..-1]}" # [1..-1] is to get rid of symbol’s colon
26
+ if res = YARD::Bench::Marks.get("#{statement.file}", "#{namespace}", "#{m}")
27
+ obj = YARD::CodeObjects::MethodObject.new(namespace, "#{m}")
28
+ obj.benchmarks = res.map { |e| e.times }.flatten
29
+ obj.power = res.map { |e| e.power }.flatten[0]
30
+ obj.deviation = res.map { |e| e.deviation }.flatten[0]
31
+ obj.memory = res.map { |e| e.memory }.flatten
32
+ cos << obj
33
+ # bmo = BenchmarkObject.new(namespace, m)
34
+ end
35
+ end
36
+ }
37
+ cos
38
+ end
39
+
40
+ def find_file(file)
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ require 'yard'
2
+
3
+ module YARD
4
+ module Bench
5
+ VERSION = "0.0.2"
6
+ end
7
+ end
data/lib/yard-bench.rb ADDED
@@ -0,0 +1,8 @@
1
+ YARD::Templates::Engine.register_template_path File.dirname(__FILE__) + '/../templates'
2
+
3
+ require File.join(File.dirname(__FILE__), 'yard-bench', 'version')
4
+
5
+ require File.join(File.dirname(__FILE__), 'dsl', 'monkeypatches')
6
+ require File.join(File.dirname(__FILE__), 'dsl', 'bm_dsl')
7
+
8
+ require File.join(File.dirname(__FILE__), 'yard-bench', 'handler')
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'yard-bench'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
8
+
9
+ RSpec.configure do |config|
10
+
11
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe YardBench do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ <% if object[:benchmarks] %>
2
+ <div class="tags">
3
+ <h4>Benchmarks:</h4>
4
+ <ul class="benchmarks">
5
+ <% for bm in object[:benchmarks] %>
6
+ <% key = "#{bm.keys[0]}".length - 1 %>
7
+ <% val = "%.3f" % bm.values[0] %>
8
+ <li><span class="name">×10<sup><%= key %></sup></span> ⇒ <%= val %>
9
+ </li>
10
+ <% end %>
11
+ </ul>
12
+ <% dev = '%.2f' % object[:deviation] %>
13
+ <% pow = object[:power].nil? ? "unknown" : "#{'%.3f' % object[:power]}×10<sup>-6</sup>×O(N)" %>
14
+ <h5>Deviation: <span class="name"><%= dev %>%</span> Power: <span class="name"><%= pow %></span></h5>
15
+ </div>
16
+ <% end %>
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ def init
4
+ super
5
+ sections.last.place(:benchmarks).before(:source)
6
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ <% if object[:benchmarks] %>
4
+ Benchmarks:
5
+ -----------
6
+ <% for bm in object[:benchmarks] %>
7
+ <% key = "#{bm.keys[0]}".length - 1 %>
8
+ <% val = "%.2f" % bm.values[0] %>
9
+ <%= indent wrap("→ ×10^#{key} ⇒ #{val}" ) %>
10
+ <% end %>
11
+ <% dev = "%.2f" % object[:deviation] %>
12
+ <% pow = object[:power].nil? ? "unknown" : object[:power] %>
13
+ <%= indent wrap("→ Deviation: #{dev}" ) %>
14
+ <%= indent wrap("→ Power: #{pow}" ) %>
15
+ <% end %>
@@ -0,0 +1,36 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'yard-bench/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'yard-bench'
6
+ s.version = YARD::Bench::VERSION
7
+ s.license = 'MIT'
8
+ s.platform = Gem::Platform::RUBY
9
+ s.date = '2013-02-21'
10
+ s.authors = ['Alexei Matyushkin']
11
+ s.email = 'am@mudasobwa.ru'
12
+ s.homepage = 'http://github.com/mudasobwa/yard-bench'
13
+ s.summary = %Q{Add a benchmark functionality to Yard.}
14
+ s.description = %Q{YARD plugin, which adds a benchmarking results to YARDoc}
15
+ s.extra_rdoc_files = [
16
+ 'LICENSE',
17
+ 'README.md',
18
+ ]
19
+
20
+ s.required_rubygems_version = Gem::Requirement.new('>= 1.3.7')
21
+ s.rubygems_version = '1.3.7'
22
+ s.specification_version = 3
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+
29
+ s.add_development_dependency 'rspec'
30
+ s.add_development_dependency 'cucumber'
31
+ s.add_development_dependency 'bueller'
32
+ s.add_development_dependency 'yard'
33
+ s.add_development_dependency 'yard-cucumber'
34
+ s.add_development_dependency 'redcarpet'
35
+ end
36
+
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- Komodo Project File - DO NOT EDIT -->
3
+ <project id="d0b15997-8557-488c-afff-cce53c382e1f" kpf_version="5" name="yard-bench.komodoproject">
4
+ </project>