big-o 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.
@@ -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: