big-o 0.1 → 0.1.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.
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