big-o 0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -45,7 +45,9 @@ space_complexity = BigO::SpaceComplexity({
45
45
  :timeout => 10, # time in seconds
46
46
  :approximation => 0.05, # percentage
47
47
  :error_pct => 0.05, # percentage
48
- :minimum_result_set_size => 3 # minimum results
48
+ :minimum_result_set_size => 3, # minimum results
49
+ :after_hook => proc { }, # See before/after hooks
50
+ :before_hook => proc { }
49
51
  })
50
52
  ```
51
53
 
@@ -60,7 +62,7 @@ require 'big-o-matchers'
60
62
  describe 'do_something_time_consuming' do
61
63
  before :each do
62
64
  @time_complexity = BigO::TimeComplexity({
63
- :fn => lambda { |n| do_something_time_consuming(n) }
65
+ :fn => lambda { |n| do_something_time_consuming(n) }
64
66
  })
65
67
  end
66
68
 
@@ -69,7 +71,7 @@ describe 'do_something_time_consuming' do
69
71
  end
70
72
 
71
73
  it 'should not have a complexity of O(1)' do
72
- @time_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
74
+ @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
73
75
  end
74
76
  end
75
77
  ```
@@ -77,6 +79,28 @@ end
77
79
  The string used as the first parameter (e.g. `'O(n)'`) is used to describe the lambda given as the
78
80
  second parameter.
79
81
 
82
+ ### After/Before hooks
83
+
84
+ Your function depends on something which needs to run before every call of your function? You need to
85
+ cleanup whatever dirty work your function performed? These operation are time/space consuming and they will
86
+ affect the values of your function? Well, just throw these things in the before/after hooks!
87
+
88
+ ```ruby
89
+ time_complexity = BigO::TimeComplexity({
90
+ :fn => lambda { |_| whatever_action_which_doesnt_depend_on_n },
91
+ :level => lambda { |n| n**2 },
92
+ :before_hook => lambda { |n| prepare_fn_environment(n) },
93
+ :after_hook => lambda { |n| clean_up(n) }
94
+ })
95
+ time_complexity.process # will only time :fn
96
+ ```
97
+
98
+ Warning: The timeout is still in effect during before and after hooks execution (in our example, it may stop
99
+ during clean_up). There should not be any sensitive code which needs to be executed in before/after hooks.
100
+
101
+ If you need to cleanup something after `time_complexity.process`, you will prefer to place this code out of :after_hook
102
+ or :before_hook.
103
+
80
104
  ## Reference
81
105
 
82
106
  You may want to read more on the subject by reading:
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'big-o'
3
- s.version = '0.1'
4
- s.date = '2012-07-25'
3
+ s.version = '0.1.1'
4
+ s.date = '2012-07-27'
5
5
  s.summary = "Calculate function complexity (using Big O notation)"
6
6
  s.description = "Big-O is a gem which analyse an anonymous function and verify that it " +
7
7
  "follow a specific pattern in its memory usage or its execution time."
@@ -34,7 +34,9 @@ module BigO
34
34
  :timeout => 10,
35
35
  :approximation => 0.05,
36
36
  :error_pct => 0.05,
37
- :minimum_result_set_size => 3 }
37
+ :minimum_result_set_size => 3,
38
+ :before_hook => proc {},
39
+ :after_hook => proc {} }
38
40
 
39
41
  @options.merge!(options)
40
42
  end
@@ -63,7 +65,7 @@ module BigO
63
65
  begin
64
66
  Timeout::timeout(@options[:timeout]) do
65
67
  @options[:range].each do |n|
66
- next if (indicator = measure(n, &@options[:fn])) == 0
68
+ next if (indicator = measurement(n)) == 0
67
69
  real_complexity[n] = indicator
68
70
  expected_complexity[n] = @options[:level].call(n)
69
71
  end
@@ -78,6 +80,22 @@ module BigO
78
80
  [real_complexity, expected_complexity]
79
81
  end
80
82
 
83
+ # Measurement process.
84
+ #
85
+ # Composed of the measurement itself and executing two hooks :before_hook and :after_hook.
86
+ # Due to the structure of the measurement, the hooks are not (and should not) be part of the
87
+ # measure. In other words, any code executed within :before_hook or :after_hook will not affect
88
+ # the time/space measure of :fn.
89
+ #
90
+ # @param [Integer] n iteration
91
+ # @return [Float] indicator
92
+ def measurement(n)
93
+ @options[:before_hook].call(n)
94
+ indicator = measure(n, &@options[:fn])
95
+ @options[:after_hook].call(n)
96
+ indicator
97
+ end
98
+
81
99
  # Parses data from <code>#run_simulation</code>.
82
100
  #
83
101
  # <code>examine_result_set</code> will return true only if these conditions are met:
@@ -6,7 +6,7 @@ describe ComplexityBase do
6
6
  class FunctionComplexity
7
7
  include ComplexityBase
8
8
 
9
- def measure
9
+ def measure(*args, &b)
10
10
  1
11
11
  end
12
12
  end
@@ -55,4 +55,23 @@ describe ComplexityBase do
55
55
  @fn_complexity.options[:approximation].should == 0.1
56
56
  end
57
57
  end
58
+
59
+ describe 'before/after hooks' do
60
+ before :each do
61
+ @after_hook = double('lambda')
62
+ @before_hook = double('lambda')
63
+ @fn_complexity = FunctionComplexity.new({
64
+ :fn => lambda { |_| 1 },
65
+ :level => lambda { |_| 1},
66
+ :before_hook => @before_hook,
67
+ :after_hook => @after_hook })
68
+
69
+ end
70
+
71
+ it 'should be called every time we try to match a complexity level' do
72
+ @before_hook.should_receive(:call).with(kind_of(Integer)).at_most(20).times
73
+ @after_hook.should_receive(:call).with(kind_of(Integer)).at_most(20).times
74
+ @fn_complexity.process
75
+ end
76
+ end
58
77
  end
@@ -12,6 +12,14 @@ describe SpaceComplexity do
12
12
  lambda { @space_complexity.process }.should raise_error(Timeout::Error)
13
13
  end
14
14
 
15
+ it 'should ignore whatever is happening in a before/after hook' do
16
+ @space_complexity.options[:fn] = lambda { |_| simulate_memory_space(1024) }
17
+ @space_complexity.options[:before_hook] = lambda { |n| simulate_memory_space(1024 * n) }
18
+ @space_complexity.options[:after_hook] = lambda { |n| simulate_memory_space(1024 * n) }
19
+ @space_complexity.options[:approximation] = 0.2
20
+ @space_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
21
+ end
22
+
15
23
  describe '#process on complexity O(1)' do
16
24
  before :each do
17
25
  @space_complexity.options[:fn] = lambda { |_| simulate_memory_space(1024) }
@@ -35,7 +43,6 @@ describe SpaceComplexity do
35
43
  it 'should return false if the complexity does not match (too low)' do
36
44
  @space_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
37
45
  end
38
-
39
46
  end
40
47
 
41
48
  describe '#process on complexity O(n**2)' do
@@ -6,15 +6,27 @@ describe TimeComplexity do
6
6
  @time_complexity = TimeComplexity.new
7
7
  end
8
8
 
9
+ MIN_TIME = 0.01
10
+ AVG_TIME = 0.05
11
+
9
12
  it 'should raise an exception if timeout is reached and no result was found' do
10
13
  @time_complexity.options[:timeout] = 0.001
11
14
  @time_complexity.options[:fn] = proc { simulate_utime_processing(1) }
12
15
  lambda { @time_complexity.process }.should raise_error(Timeout::Error)
13
16
  end
14
17
 
18
+ it 'should ignore whatever is happening in a before/after hook' do
19
+ @time_complexity.options[:fn] = lambda { |_| simulate_utime_processing(MIN_TIME) }
20
+ @time_complexity.options[:before_hook] = lambda { |n| simulate_utime_processing(MIN_TIME * n) }
21
+ @time_complexity.options[:after_hook] = lambda { |n| simulate_utime_processing(MIN_TIME * n) }
22
+ @time_complexity.options[:approximation] = 0.2
23
+ @time_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
24
+ end
25
+
26
+
15
27
  describe '#process on complexity O(1)' do
16
28
  before :each do
17
- @time_complexity.options[:fn] = lambda { |_| simulate_utime_processing(0.5) }
29
+ @time_complexity.options[:fn] = lambda { |_| simulate_utime_processing(AVG_TIME) }
18
30
  end
19
31
 
20
32
  it 'should run the function and produce a report when time threshold is hit' do
@@ -25,7 +37,7 @@ describe TimeComplexity do
25
37
 
26
38
  describe '#process on complexity O(n)' do
27
39
  before :each do
28
- @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.5 * n) }
40
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(AVG_TIME * n) }
29
41
  end
30
42
 
31
43
  it 'should run the function and produce a report when time threshold is hit' do
@@ -36,7 +48,7 @@ describe TimeComplexity do
36
48
  describe '#process on complexity O(n**2)' do
37
49
  before :each do
38
50
  @time_complexity.options[:minimum_result_set_size] = 0
39
- @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.5 * (n**2)) }
51
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(AVG_TIME * (n**2)) }
40
52
  end
41
53
 
42
54
  it 'should run the function and produce a report when time threshold is hit' do
@@ -51,14 +63,14 @@ describe TimeComplexity do
51
63
 
52
64
  describe 'very small execution time functions (0.1 second and below)' do
53
65
  it 'should still be valid in case of O(n**2)' do
54
- @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.01 * n**2) }
66
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(MIN_TIME * n**2) }
55
67
  @time_complexity.should match_complexity_level 'O(n**2)', lambda { |n| n**2 }
56
68
  @time_complexity.should_not match_complexity_level 'O(n log(n))', lambda { |n| n * Math::log(n) }
57
69
  @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
58
70
  end
59
71
 
60
72
  it 'should still be valid in case of O(n)' do
61
- @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.01 * n) }
73
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(MIN_TIME * n) }
62
74
  @time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
63
75
  @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
64
76
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: big-o
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: 0.1.1
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-07-25 00:00:00.000000000 Z
12
+ date: 2012-07-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec