big-o 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ .yardoc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format d
2
+ --require spec_helper
3
+ --color
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ gem 'yard', '~>0.8.2', :groups => [:development, :test]
4
+
5
+ group :test do
6
+ gem "rspec", '~>2.10.0'
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Vincent Bonmalais
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ # Big-O
2
+
3
+ Big-O is a gem which analyse an anonymous function and verify that it follow a specific pattern
4
+ in its memory usage or its execution time.
5
+
6
+ ## Requirements
7
+
8
+ Calculation of memory space is done via `ps`, and therefore, doesn't work on Windows.
9
+
10
+ This gem has been tested on Mac OS X, using Ruby 1.9.3.
11
+
12
+ ## Install
13
+
14
+ Installation is made through RubyGem:
15
+
16
+ ```
17
+ gem install big-o
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Directly in your code
23
+
24
+ Checking if a function has a complexity of O(n) is as simple as this:
25
+
26
+ ```ruby
27
+ require 'big-o'
28
+
29
+ time_complexity = BigO::TimeComplexity({
30
+ :fn => lambda { |n| do_something_time_consuming(n) },
31
+ :level => lambda { |n| n }
32
+ })
33
+ time_complexity.process # => true if it is growing in time constantly.
34
+ ```
35
+
36
+ It is also possible to define multiple configuration parameters:
37
+
38
+ ```ruby
39
+ require 'big-o'
40
+
41
+ space_complexity = BigO::SpaceComplexity({
42
+ :fn => lambda { |n| do_something_space_consuming(n) }
43
+ :level => lambda { |n| n },
44
+ :range => 1..20, # value of n
45
+ :timeout => 10, # time in seconds
46
+ :approximation => 0.05, # percentage
47
+ :error_pct => 0.05, # percentage
48
+ :minimum_result_set_size => 3 # minimum results
49
+ })
50
+ ```
51
+
52
+ ### RSpec Matchers
53
+
54
+ If you are using RSpec, there is a matcher already defined for matching a complexity level:
55
+
56
+ ```ruby
57
+ require 'big-o'
58
+ require 'big-o-matchers'
59
+
60
+ describe 'do_something_time_consuming' do
61
+ before :each do
62
+ @time_complexity = BigO::TimeComplexity({
63
+ :fn => lambda { |n| do_something_time_consuming(n) }
64
+ })
65
+ end
66
+
67
+ it 'should have a complexity of O(n)' do
68
+ @time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
69
+ end
70
+
71
+ it 'should not have a complexity of O(1)' do
72
+ @time_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
73
+ end
74
+ end
75
+ ```
76
+
77
+ The string used as the first parameter (e.g. `'O(n)'`) is used to describe the lambda given as the
78
+ second parameter.
79
+
80
+ ## Reference
81
+
82
+ You may want to read more on the subject by reading:
83
+ * http://en.wikipedia.org/wiki/Analysis_of_algorithms
84
+ * http://en.wikipedia.org/wiki/Big_O_notation
85
+
86
+ ## License
87
+
88
+ Complexity is licensed under the MIT License - see the LICENSE file for details
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'big-o'
3
+ s.version = '0.1'
4
+ s.date = '2012-07-25'
5
+ s.summary = "Calculate function complexity (using Big O notation)"
6
+ s.description = "Big-O is a gem which analyse an anonymous function and verify that it " +
7
+ "follow a specific pattern in its memory usage or its execution time."
8
+ s.authors = ["Vincent Bonmalais"]
9
+ s.email = 'vbonmalais@gmail.com'
10
+ s.files = `git ls-files`.split("\n")
11
+ s.test_files = `git ls-files -- spec`.split("\n")
12
+ s.homepage = 'https://github.com/kouno/big-o'
13
+
14
+ s.add_development_dependency('rspec', '~>2.10.0')
15
+ end
@@ -0,0 +1 @@
1
+ require 'big-o/matchers/match_complexity_level'
@@ -0,0 +1,7 @@
1
+ require 'timeout'
2
+ require 'benchmark'
3
+
4
+ require 'big-o/complexity_base'
5
+ require 'big-o/time_complexity'
6
+ require 'big-o/space_complexity'
7
+ require 'big-o/exceptions'
@@ -0,0 +1,128 @@
1
+ module BigO
2
+ # ComplexityBase regroup every process common to the benchmarking of a function.
3
+ module ComplexityBase
4
+
5
+ # @return [Boolean] Result from measurement
6
+ attr_accessor :result
7
+
8
+ # @return [Hash] Contains the whole benchmark
9
+ attr_accessor :result_set
10
+
11
+ # @return [Float] Element on which the whole benchmark is based (for <code>n = 1</code>)
12
+ attr_accessor :scale
13
+
14
+ # @return [Hash] Contains the different configurable options
15
+ attr_accessor :options
16
+
17
+ # Configures default values.
18
+ #
19
+ # @param [Hash] options the options necessary to benchmark the given lambda. Any of these options
20
+ # can be defined just before running a simulation using <code>options</code>.
21
+ #
22
+ # {
23
+ # :fn => lambda { |n| do_something(n) } # function which will be measured [required]
24
+ # :level => lambda { |n| n } # complexity of the function [required]
25
+ # :range => 1..20, # values of `n` for which it will run the function
26
+ # :timeout => 10, # time (in seconds) after which the simulation will stop running
27
+ # :approximation => 0.05, # percentage by which we approximate our expected results
28
+ # :error_pct => 0.05, # percentage of times where we allow errors due to concurrent processing
29
+ # :minimum_result_set_size => 3 # minimum number of results we need to have consistent data
30
+ # }
31
+ # @return [void]
32
+ def initialize(options = {})
33
+ @options = { :range => 1..20,
34
+ :timeout => 10,
35
+ :approximation => 0.05,
36
+ :error_pct => 0.05,
37
+ :minimum_result_set_size => 3 }
38
+
39
+ @options.merge!(options)
40
+ end
41
+
42
+ # Benchmarks the given function (<code>@fn</code>) and tells if it follows the given pattern
43
+ # (<code>@options[:level]</code>).
44
+ #
45
+ # @return [Boolean]
46
+ def process
47
+ @scale ||= get_scale
48
+ examine_result_set(*run_simulation)
49
+ end
50
+
51
+ # Runs simulation.
52
+ #
53
+ # A simulation can fail to execute every element in <code>range</code> because it exceeded the timeout limit. If no result
54
+ # was returned in the `timeout` time frame, this method will generate an exception.
55
+ #
56
+ # @return [Array] contains an array (first element) of values which are the measurement of the function
57
+ # and another array (second element) of values which are the expected values for the first one.
58
+ # @raise [Timeout::Error]
59
+ def run_simulation
60
+ real_complexity = {}
61
+ expected_complexity = {}
62
+
63
+ begin
64
+ Timeout::timeout(@options[:timeout]) do
65
+ @options[:range].each do |n|
66
+ next if (indicator = measure(n, &@options[:fn])) == 0
67
+ real_complexity[n] = indicator
68
+ expected_complexity[n] = @options[:level].call(n)
69
+ end
70
+ end
71
+ rescue Timeout::Error => e
72
+ if real_complexity.empty? || expected_complexity.empty?
73
+ raise e
74
+ end
75
+ end
76
+
77
+ @result_set = real_complexity
78
+ [real_complexity, expected_complexity]
79
+ end
80
+
81
+ # Parses data from <code>#run_simulation</code>.
82
+ #
83
+ # <code>examine_result_set</code> will return true only if these conditions are met:
84
+ # - expected complexity is never exceeded. Some inconsistencies may however be allowed
85
+ # (see <code>@options[:error_pct]</code>).
86
+ # - there is a minimum of X results in real_complexity, where X is <code>@options[:minimum_result_set_size]</code>.
87
+ # if this condition is not met, an exception will be thrown.
88
+ #
89
+ # @param [Array] real_complexity
90
+ # @param [Array] expected_complexity
91
+ # @return [Boolean]
92
+ # @raise [SmallResultSetError]
93
+ def examine_result_set(real_complexity, expected_complexity)
94
+ if real_complexity.size <= @options[:minimum_result_set_size]
95
+ raise SmallResultSetError.new(@options[:minimum_result_set_size])
96
+ end
97
+
98
+ allowed_inconsistencies = (expected_complexity.size * @options[:error_pct]).floor
99
+ expected_complexity.each do |n, level|
100
+ next if n == 1
101
+ estimated_complexity = @scale * level
102
+ estimated_complexity += estimated_complexity * @options[:approximation]
103
+ if estimated_complexity <= real_complexity[n]
104
+ if allowed_inconsistencies > 0
105
+ allowed_inconsistencies -= 1
106
+ next
107
+ end
108
+ @result = false
109
+ break
110
+ end
111
+ end
112
+
113
+ @result = true if @result.nil?
114
+ @result
115
+ end
116
+
117
+ # Finds what is the first measure of our function.
118
+ #
119
+ # @return [Float]
120
+ def get_scale
121
+ runs = []
122
+ 10.times do
123
+ runs << measure(1, &@options[:fn])
124
+ end
125
+ runs.inject(:+) / 10
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,21 @@
1
+ module BigO
2
+ # The function could not be run more than X times (where X is a configurable value).
3
+ #
4
+ # This exception happens if the function is too slow to run, or if the timeout is too short.
5
+ class SmallResultSetError < StandardError
6
+ # @param [Integer] resultset_size number of values the result set contains.
7
+ def initialize(resultset_size)
8
+ super "Less than #{resultset_size} values could be retrieved." +
9
+ " Try using longer timeout or a different range. (function complexity may be too high)"
10
+ end
11
+ end
12
+
13
+ # The function runs too fast and can't be quantified by our measurement tool.
14
+ #
15
+ # To fix this error, it is possible to augment the number of times the function should run.
16
+ class InstantaneousExecutionError < StandardError
17
+ def initialize
18
+ super "Function execution time can't be quantified. (execution speed close to instantaneous)"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ RSpec::Matchers.define :match_complexity_level do |o_notation, complexity_level|
2
+ match do |complexity|
3
+ complexity.options[:level] = complexity_level
4
+ complexity.process
5
+ end
6
+
7
+ failure_message_for_should do |complexity|
8
+ # since we are playing around with floating values,
9
+ # sorting the result_set helps minimising issues with addition of floats
10
+ result_set = complexity.result_set.sort
11
+ total = result_set.inject(0) { |sum, r| sum + r[1] }.to_f
12
+ "expected a complexity level of #{o_notation}, " +
13
+ "got scale: #{complexity.scale} min: #{result_set[0][1]} " +
14
+ "max: #{result_set[-1][1]} " +
15
+ "avg: #{total / result_set.size} " +
16
+ "total values: #{result_set.size} on #{complexity.options[:range]}"
17
+ end
18
+
19
+ failure_message_for_should_not do |complexity|
20
+ result_set = complexity.result_set.sort
21
+ total = result_set.inject(0) { |sum, r| sum + r[1] }.to_f
22
+ "expected a complexity level over #{o_notation}, " +
23
+ "got scale: #{complexity.scale} min: #{result_set[0][1]} " +
24
+ "max: #{result_set[-1][1]} " +
25
+ "avg: #{total / result_set.size} " +
26
+ "total values: #{result_set.size} on #{complexity.options[:range]}"
27
+ end
28
+
29
+ description do
30
+ "should match complexity level #{o_notation}"
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ module BigO
2
+ # Measure space complexity.
3
+ class SpaceComplexity
4
+ include ComplexityBase
5
+
6
+ # Measures the memory space that <code>fn</code> is using.
7
+ #
8
+ # @param [Array] args arguments which the given block should take
9
+ # @yield function which should be measured (fn)
10
+ # @return [Float] measurement
11
+ def measure(*args, &b)
12
+ memory_measures = []
13
+ GC.disable
14
+
15
+ pid = Process.fork do
16
+ memory_measures << `ps -o rss= -p #{Process.pid}`.to_i
17
+ b.call(*args)
18
+ memory_measures << `ps -o rss= -p #{Process.pid}`.to_i
19
+ exit
20
+ end
21
+
22
+ while (memory_indicator = `ps -o rss= -p #{pid}`.to_i)
23
+ break if memory_indicator == 0
24
+ memory_measures << memory_indicator
25
+ end
26
+
27
+ Process.wait
28
+
29
+ GC.enable
30
+
31
+ if memory_measures.size > 2
32
+ memory_measures.max - memory_measures.min
33
+ else
34
+ 0
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module BigO
2
+ # Measure time complexity.
3
+ class TimeComplexity
4
+ include ComplexityBase
5
+
6
+ # Raises the error percentage due to possible concurrency issue on the system (which in
7
+ # certain cases may cause some measures to be far longer than others).
8
+ def initialize(options = {})
9
+ options = { :error_pct => 0.1 }.merge(options)
10
+ super(options)
11
+ end
12
+
13
+ # Checks if the function can be measured and throw an error if it could not.
14
+ def process
15
+ @scale ||= get_scale
16
+ raise InstantaneousExecutionError.new unless @scale > 0
17
+ super
18
+ end
19
+
20
+ # Measures the execution time that <code>fn</code> is using.
21
+ #
22
+ # @param [Array] args arguments which the given block should take
23
+ # @yield function which should be measured (fn)
24
+ # @return [Float] measurement
25
+ def measure(*args, &b)
26
+ t0 = Process.times
27
+ b.call(*args)
28
+ t1 = Process.times
29
+ t1.utime - t0.utime
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ include BigO
3
+
4
+ describe ComplexityBase do
5
+ before :all do
6
+ class FunctionComplexity
7
+ include ComplexityBase
8
+
9
+ def measure
10
+ 1
11
+ end
12
+ end
13
+ end
14
+
15
+ context 'with default values' do
16
+ before :each do
17
+ @fn_complexity = FunctionComplexity.new
18
+ end
19
+
20
+ it 'should have a timeout of 10 seconds' do
21
+ @fn_complexity.options[:timeout].should == 10
22
+ end
23
+
24
+ it 'should have no result defined' do
25
+ @fn_complexity.result.should be_nil
26
+ end
27
+
28
+ it 'should have an approximation of 5%' do
29
+ @fn_complexity.options[:approximation].should == 0.05
30
+ end
31
+
32
+ it 'should refuse to process less than 4 values when processing a function' do
33
+ real_complexity = {}
34
+ expected_complexity = {}
35
+ 3.times do |i|
36
+ real_complexity[i] = i
37
+ expected_complexity[i] = i
38
+ end
39
+
40
+ @fn_complexity.scale = 1
41
+ lambda {
42
+ @fn_complexity.examine_result_set(real_complexity, expected_complexity)
43
+ }.should raise_error(SmallResultSetError)
44
+ end
45
+ end
46
+
47
+ context 'with overwritten values' do
48
+ before :each do
49
+ @fn_complexity = FunctionComplexity.new({ :timeout => 1,
50
+ :approximation => 0.1 })
51
+ end
52
+
53
+ it 'should have the configured values' do
54
+ @fn_complexity.options[:timeout].should == 1
55
+ @fn_complexity.options[:approximation].should == 0.1
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ include BigO
3
+
4
+ describe SpaceComplexity do
5
+ before :each do
6
+ @space_complexity = SpaceComplexity.new
7
+ end
8
+
9
+ it 'should raise an exception if timeout is reached and no result was found' do
10
+ @space_complexity.options[:timeout] = 0.001
11
+ @space_complexity.options[:fn] = lambda { |_| simulate_memory_space(1) }
12
+ lambda { @space_complexity.process }.should raise_error(Timeout::Error)
13
+ end
14
+
15
+ describe '#process on complexity O(1)' do
16
+ before :each do
17
+ @space_complexity.options[:fn] = lambda { |_| simulate_memory_space(1024) }
18
+ end
19
+
20
+ it 'should run the function and produce a report when time threshold is hit' do
21
+ @space_complexity.options[:approximation] = 0.2
22
+ @space_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
23
+ end
24
+ end
25
+
26
+ describe '#process on complexity O(n)' do
27
+ before :each do
28
+ @space_complexity.options[:fn] = lambda { |n| simulate_memory_space(1024 * n) }
29
+ end
30
+
31
+ it 'should run the function and produce a report when time threshold is hit' do
32
+ @space_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
33
+ end
34
+
35
+ it 'should return false if the complexity does not match (too low)' do
36
+ @space_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
37
+ end
38
+
39
+ end
40
+
41
+ describe '#process on complexity O(n**2)' do
42
+ before :each do
43
+ @space_complexity.options[:fn] = lambda { |n| simulate_memory_space(1024 * n**2) }
44
+ end
45
+
46
+ it 'should run the function and produce a report when time threshold is hit' do
47
+ @space_complexity.should match_complexity_level 'O(n^2)', lambda { |n| n**2 }
48
+ end
49
+
50
+ it 'should return false if the complexity does not match (too low)' do
51
+ @space_complexity.should_not match_complexity_level 'O(n)', lambda { |n| n }
52
+
53
+ @space_complexity.options[:approximation] = 0.2
54
+ @space_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ include BigO
3
+
4
+ describe TimeComplexity do
5
+ before :each do
6
+ @time_complexity = TimeComplexity.new
7
+ end
8
+
9
+ it 'should raise an exception if timeout is reached and no result was found' do
10
+ @time_complexity.options[:timeout] = 0.001
11
+ @time_complexity.options[:fn] = proc { simulate_utime_processing(1) }
12
+ lambda { @time_complexity.process }.should raise_error(Timeout::Error)
13
+ end
14
+
15
+ describe '#process on complexity O(1)' do
16
+ before :each do
17
+ @time_complexity.options[:fn] = lambda { |_| simulate_utime_processing(0.5) }
18
+ end
19
+
20
+ it 'should run the function and produce a report when time threshold is hit' do
21
+ @time_complexity.options[:approximation] = 0.2
22
+ @time_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
23
+ end
24
+ end
25
+
26
+ describe '#process on complexity O(n)' do
27
+ before :each do
28
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.5 * n) }
29
+ end
30
+
31
+ it 'should run the function and produce a report when time threshold is hit' do
32
+ @time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
33
+ end
34
+ end
35
+
36
+ describe '#process on complexity O(n**2)' do
37
+ before :each do
38
+ @time_complexity.options[:minimum_result_set_size] = 0
39
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.5 * (n**2)) }
40
+ end
41
+
42
+ it 'should run the function and produce a report when time threshold is hit' do
43
+ @time_complexity.should match_complexity_level 'O(n^2)', lambda { |n| n**2 }
44
+ end
45
+
46
+ it 'should return false if the complexity does not match (too low)' do
47
+ @time_complexity.options[:approximation] = 0.2
48
+ @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
49
+ end
50
+ end
51
+
52
+ describe 'very small execution time functions (0.1 second and below)' do
53
+ 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) }
55
+ @time_complexity.should match_complexity_level 'O(n**2)', lambda { |n| n**2 }
56
+ @time_complexity.should_not match_complexity_level 'O(n log(n))', lambda { |n| n * Math::log(n) }
57
+ @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
58
+ end
59
+
60
+ it 'should still be valid in case of O(n)' do
61
+ @time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(0.01 * n) }
62
+ @time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
63
+ @time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
64
+ end
65
+
66
+ it 'should throw an error if execution time is not measurable for n = 1 (execution time close to ~0.001 second)' do
67
+ @time_complexity.options[:fn] = lambda { |n| 0.001 * n**2 }
68
+ lambda { @time_complexity.process }.should raise_error(InstantaneousExecutionError)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ module BigO
2
+ module Helpers
3
+ ONE_KILO_OCTET = 'a' * 1024
4
+
5
+ def simulate_utime_processing(seconds)
6
+ t0 = Process.times
7
+ begin
8
+ t1 = Process.times
9
+ end while (t1.utime - t0.utime) < seconds
10
+ end
11
+
12
+ def simulate_memory_space(ko)
13
+ space = ONE_KILO_OCTET * ko
14
+ sleep(0.01)
15
+ space
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ include BigO
3
+
4
+ describe 'match_complexity_level matcher' do
5
+ before :each do
6
+ @test_complexity = SpaceComplexity.new({ :fn => lambda { |n| simulate_memory_space(1024 * n) } })
7
+ end
8
+
9
+ it "should not match O(1) for a constant augmentation" do
10
+ @matcher = match_complexity_level('O(1)', lambda { |_| 1 })
11
+ @matcher.matches?(@test_complexity).should be_false
12
+ end
13
+
14
+ it "should match O(n) for a constant augmentation" do
15
+ @matcher = match_complexity_level('O(n)', lambda { |n| n })
16
+ @matcher.matches?(@test_complexity).should be_true
17
+ end
18
+
19
+ context 'when using should' do
20
+ before :each do
21
+ @matcher = match_complexity_level('O(1)', lambda { |_| 1 })
22
+ end
23
+
24
+ it "should provide a descriptive error message" do
25
+ @matcher.matches?(@test_complexity)
26
+ @matcher.failure_message_for_should.should =~ /\Aexpected a complexity level of O\(1\)/
27
+ @matcher.failure_message_for_should.should =~ /got scale: [0-9.]+ min: [0-9.]+/
28
+ @matcher.failure_message_for_should.should =~ /max: [0-9.]+ avg: [0-9.]+/
29
+ @matcher.failure_message_for_should.should =~ /total values: [0-9]+ on 1\.\.20\Z/
30
+ end
31
+ end
32
+
33
+ context 'when using should_not' do
34
+ before :each do
35
+ @matcher = match_complexity_level('O(n)', lambda { |n| n })
36
+ end
37
+
38
+ it "should provide a descriptive error message" do
39
+ @matcher.matches?(@test_complexity)
40
+ @matcher.failure_message_for_should_not.should =~ /\Aexpected a complexity level over O\(n\)/
41
+ @matcher.failure_message_for_should_not.should =~ /got scale: [0-9.]+ min: [0-9.]+/
42
+ @matcher.failure_message_for_should_not.should =~ /max: [0-9.]+ avg: [0-9.]+/
43
+ @matcher.failure_message_for_should_not.should =~ /total values: [0-9]+ on 1\.\.20\Z/
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,8 @@
1
+ require 'helpers/simulation'
2
+ require File.expand_path('../../lib/big-o.rb', __FILE__)
3
+ require File.expand_path('../../lib/big-o-matchers.rb', __FILE__)
4
+
5
+ RSpec.configure do |c|
6
+ c.include BigO
7
+ c.include BigO::Helpers
8
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: big-o
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vincent Bonmalais
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.10.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.10.0
30
+ description: Big-O is a gem which analyse an anonymous function and verify that it
31
+ follow a specific pattern in its memory usage or its execution time.
32
+ email: vbonmalais@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.md
42
+ - big-o.gemspec
43
+ - lib/big-o-matchers.rb
44
+ - lib/big-o.rb
45
+ - lib/big-o/complexity_base.rb
46
+ - lib/big-o/exceptions.rb
47
+ - lib/big-o/matchers/match_complexity_level.rb
48
+ - lib/big-o/space_complexity.rb
49
+ - lib/big-o/time_complexity.rb
50
+ - spec/big-o/complexity_base_spec.rb
51
+ - spec/big-o/space_complexity_spec.rb
52
+ - spec/big-o/time_complexity_spec.rb
53
+ - spec/helpers/simulation.rb
54
+ - spec/matchers/match_complexity_level_spec.rb
55
+ - spec/spec_helper.rb
56
+ homepage: https://github.com/kouno/big-o
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.23
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Calculate function complexity (using Big O notation)
80
+ test_files:
81
+ - spec/big-o/complexity_base_spec.rb
82
+ - spec/big-o/space_complexity_spec.rb
83
+ - spec/big-o/time_complexity_spec.rb
84
+ - spec/helpers/simulation.rb
85
+ - spec/matchers/match_complexity_level_spec.rb
86
+ - spec/spec_helper.rb
87
+ has_rdoc: