From b63bb5b575728555bfa356cc4880f72450710a06 Mon Sep 17 00:00:00 2001 From: John Prince Date: Mon, 26 Aug 2013 23:28:36 -0600 Subject: [PATCH] in process of adding back in specs with rspec --- .gitignore | 5 +- histogram.gemspec | 5 +- lib/histogram.rb | 16 ++-- spec/histogram_spec.rb | 208 +++++++++++++++++++++++------------------ 4 files changed, 131 insertions(+), 103 deletions(-) diff --git a/.gitignore b/.gitignore index ec414a8..c231a30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -*.swp -pkg +/*.swp +/pkg +/coverage diff --git a/histogram.gemspec b/histogram.gemspec index 5aa8c7d..22f281f 100644 --- a/histogram.gemspec +++ b/histogram.gemspec @@ -20,8 +20,9 @@ Gem::Specification.new do |spec| [ "bundler ~> 1.3", - "rake", - "simplecov" + "rake ~> 10.1.0", + "simplecov ~> 0.7.1", + "rspec ~> 2.13.0", ].each do |argline| spec.add_development_dependency *argline.split(' ', 2).compact end diff --git a/lib/histogram.rb b/lib/histogram.rb index c97718d..1d0305d 100644 --- a/lib/histogram.rb +++ b/lib/histogram.rb @@ -96,8 +96,8 @@ def number_bins(methd=:fd) # give the number of bins # specify the bins themselves # - # :tp => :avg boundary is the avg between bins (default) - # :min bins specify the minima for binning + # :bin_boundary => :avg boundary is the avg between bins (default) + # :min bins specify the minima for binning # # :bin_width => width of a bin (overrides :bins) # :min => # explicitly set the min @@ -111,10 +111,10 @@ def number_bins(methd=:fd) # ar = [-2,1,2,3,3,3,4,5,6,6] # # these return: [bins, freqencies] # ar.histogram(20) # use 20 bins - # ar.histogram([-3,-1,4,5,6], :tp => :avg) # custom bins + # ar.histogram([-3,-1,4,5,6], :bin_boundary => :avg) # custom bins # # # returns [bins, freq1, freq2 ...] - # (bins, *freqs) = ar.histogram(30, :tp => :avg, :other_sets => [3,3,4,4,5], [-1,0,0,3,3,6]) + # (bins, *freqs) = ar.histogram(30, :bin_boundary => :avg, :other_sets => [3,3,4,4,5], [-1,0,0,3,3,6]) # (ar_freqs, other1, other2) = freqs # # # histogramming with heights (uses the second array for heights) @@ -171,12 +171,12 @@ def histogram(*args) raise ArgumentError, "accepts no more than 2 args" end - opts = ({ :tp => :avg, :other_sets => [] }).merge(opts) + opts = ({ :bin_boundary => :avg, :other_sets => [] }).merge(opts) bins = opts[:bins] if opts[:bins] bins = :fd unless bins - tp = opts[:tp] + bin_boundary = opts[:bin_boundary] other_sets = opts[:other_sets] bins_array_like = bins.kind_of?(Array) || bins.kind_of?(NArray) || opts[:bin_width] @@ -218,7 +218,7 @@ def histogram(*args) elsif bins.is_a?(NArray) bins.to_f end - case tp + case bin_boundary when :avg freqs_ar = all.map do |vec| @@ -313,7 +313,7 @@ def histogram(*args) # Create the bins: iconv = 1.0/conv - case tp + case bin_boundary when :avg (0...bins).each do |i| _bins[i] = ((i+0.5) * iconv) + dmin diff --git a/spec/histogram_spec.rb b/spec/histogram_spec.rb index b46f823..f95c0f4 100644 --- a/spec/histogram_spec.rb +++ b/spec/histogram_spec.rb @@ -1,116 +1,142 @@ -require File.expand_path(File.dirname(__FILE__) + "/spec_helper.rb") +require 'spec_helper' + +require 'histogram' class Array def to_f self.map {|v| v.to_f } end -end - -shared 'a histogram' do - - before do - #@obj1 = (0..10).to_a - #@obj2 = [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9] - end - it 'can make histograms (bins created on the fly)' do - # Test with # bins: - bins,freqs = @obj1.histogram(5) - bins.isa @obj1.class - freqs.isa @obj1.class - bins.enums [1,3,5,7,9].to_f - freqs.enums [2,2,2,2,3].to_f - - bins,freqs = @obj1.histogram(5, :tp => :min) - bins.enums [0,2,4,6,8].to_f - freqs.enums [2,2,2,2,3].to_f + def round(n=nil) + self.map {|v| v.to_f.round(n) } end +end - it 'can make histograms (given bins)' do - # Test with given bins: - bins, freqs = @obj2.histogram([1,3,5,7,9], :tp => :avg) - bins.enums [1,3,5,7,9].to_f - freqs.enums [3,1,1,2,3].to_f - bins, freqs = @obj3.histogram([1,3,5,7,9], :tp => :min) - bins.enums [1,3,5,7,9].to_f - freqs.enums [3,0,2,2,3].to_f +shared_examples 'something that can histogram' do + it 'makes histograms with the specified number of bins' do + (bins, freqs) = obj0.histogram(5) + bins.should be_a(obj0.class) + freqs.should be_a(obj0.class) + bins.round(8).should == [1,3,5,7,9].round(8) + freqs.round(8).should == [2,2,2,2,3].round(8) end - it 'can histogram multiple sets' do - (bins, freq1, freq2, freq3) = @obj4.histogram([1,2,3,4], :tp => :avg, :other_sets => [@obj5, @obj5]) - bins.enums [1,2,3,4].to_f - freq1.enums [2.0, 2.0, 2.0, 3.0] - freq2.enums [0.0, 5.0, 0.0, 1.0] - freq3.enums freq2 + it 'returns bins as the min boundary if given that option' do + (bins, freqs) = obj0.histogram(5, :bin_boundary => :min) + bins.round(8).should == [0,2,4,6,8].round(8) + freqs.round(8).should == [2,2,2,2,3].round(8) end - it 'can take height values' do - obj2 = [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9] - heights = Array.new(obj2.size, 3) - obj = [obj2, heights] - bins, freqs = obj.histogram([1,3,5,7,9], :tp => :avg) - bins.enums [1,3,5,7,9].to_f - freqs.enums [3,1,1,2,3].map {|v| v * 3} - - obj2 = [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9] - heights = [10, 0, 0, 0, 50, 0, 0, 0, 0.2, 0.2] - obj = [obj2, heights] - (bins, freqs) = obj.histogram([1,3,5,7,9], :tp => :avg) - bins.enums [1,3,5,7,9].to_f - freqs.enums [10, 0, 50, 0, 0.4] + it 'makes histograms when given the bins' do + bins, freqs = obj1.histogram([1,3,5,7,9], :bin_boundary => :avg) + bins.round(8).should == [1,3,5,7,9].round(8) + freqs.round(8).should == [3,1,1,2,3].round(8) end - it 'works with given min and max vals' do - [1,2,3,3,3,4,5,6,7,8].histogram(4, :min => 2, :tp => :min).first.first.is 2.0 - [1,2,3,3,3,4,5,6,7,8].histogram(4, :max => 7, :tp => :min).first.last.is 5.5 # since the bin-width is 1.5 - bs = [1,2,3,3,3,4,5,6,7,8].histogram(4, :min => 2, :max => 7, :tp => :min) - bs.first.first.is 2.0 - bs.first.last.is 5.75 # bin-width of 1.25 + it 'interprets bins as the min boundary when given the bin_boundary option' do + bins, freqs = obj2.histogram([1,3,5,7,9], :bin_boundary => :min) + bins.round(8).should == [1,3,5,7,9].round(8) + freqs.round(8).should == [3,0,2,2,3].round(8) end -end - -TestArrays = [[0,1,2,3,4,5,6,7,8,9,10], [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9], - [-1, 0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9, 10], [1, 1, 2, 2, 3, 3, 4, 4, 4], - [2, 2, 2, 2, 2, 4]] +# it 'can histogram multiple sets' do + #(bins, freq1, freq2, freq3) = @obj4.histogram([1,2,3,4], :tp => :avg, :other_sets => [@obj5, @obj5]) + #bins.enums [1,2,3,4].to_f + #freq1.enums [2.0, 2.0, 2.0, 3.0] + #freq2.enums [0.0, 5.0, 0.0, 1.0] + #freq3.enums freq2 + #end -require 'histogram/array' -class LilClass < Array - include Histogram end -describe 'calculating bins' do - it 'calculates :sturges, :scott, :fd, or :middle' do - answers = [6,3,4,4] - [:sturges, :scott, :fd, :middle].zip(answers) do |mth, answ| - ar = LilClass.new([0,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,5,5,9,9,10,20,15,15,15,16,17]) - # these are merely frozen, not checked to see if correct - ar.number_bins(mth).is answ - end - end -end - -describe 'histogramming an Array' do - before do - TestArrays.each_with_index do |ar,i| - instance_variable_set("@obj#{i+1}", ar) - end +describe Histogram do + let(:data) do + [ (0..10).to_a, + [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9], + [-1, 0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9, 10], + ].to_f end - behaves_like 'a histogram' -end -begin - require 'histogram/narray' - describe 'histogramming an NArray' do - before do - TestArrays.each_with_index do |ar,i| - instance_variable_set("@obj#{i+1}", NArray.to_na(ar).to_f) + describe Array do + it_behaves_like 'something that can histogram' do + [:obj0, :obj1, :obj2].each_with_index do |obj,i| + let(obj) { data[i].dup.extend(Histogram) } end end - behaves_like 'a histogram' end -rescue LoadError - puts "" - puts "YOU NEED NArray installed to run NArray tests!" - puts "" end + + + #it 'can take height values' do + #obj2 = [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9] + #heights = Array.new(obj2.size, 3) + #obj = [obj2, heights] + #bins, freqs = obj.histogram([1,3,5,7,9], :tp => :avg) + #bins.enums [1,3,5,7,9].to_f + #freqs.enums [3,1,1,2,3].map {|v| v * 3} + + #obj2 = [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9] + #heights = [10, 0, 0, 0, 50, 0, 0, 0, 0.2, 0.2] + #obj = [obj2, heights] + #(bins, freqs) = obj.histogram([1,3,5,7,9], :tp => :avg) + #bins.enums [1,3,5,7,9].to_f + #freqs.enums [10, 0, 50, 0, 0.4] + #end + + #it 'works with given min and max vals' do + #[1,2,3,3,3,4,5,6,7,8].histogram(4, :min => 2, :tp => :min).first.first.is 2.0 + #[1,2,3,3,3,4,5,6,7,8].histogram(4, :max => 7, :tp => :min).first.last.is 5.5 # since the bin-width is 1.5 + #bs = [1,2,3,3,3,4,5,6,7,8].histogram(4, :min => 2, :max => 7, :tp => :min) + #bs.first.first.is 2.0 + #bs.first.last.is 5.75 # bin-width of 1.25 + #end + + + + + + +#TestArrays = [[0,1,2,3,4,5,6,7,8,9,10], [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9], + #[-1, 0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9, 10], [1, 1, 2, 2, 3, 3, 4, 4, 4], + #[2, 2, 2, 2, 2, 4]] + +#require 'histogram/array' +#class LilClass < Array + #include Histogram +#end + +#describe 'calculating bins' do + #it 'calculates :sturges, :scott, :fd, or :middle' do + #answers = [6,3,4,4] + #[:sturges, :scott, :fd, :middle].zip(answers) do |mth, answ| + #ar = LilClass.new([0,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,5,5,9,9,10,20,15,15,15,16,17]) + ## these are merely frozen, not checked to see if correct + #ar.number_bins(mth).is answ + #end + #end +#end + +#describe 'histogramming an Array' do + #before do + #TestArrays.each_with_index do |ar,i| + #instance_variable_set("@obj#{i+1}", ar) + #end + #end + #behaves_like 'a histogram' +#end + +#begin + #require 'histogram/narray' + #describe 'histogramming an NArray' do + #before do + #TestArrays.each_with_index do |ar,i| + #instance_variable_set("@obj#{i+1}", NArray.to_na(ar).to_f) + #end + #end + #behaves_like 'a histogram' + #end +#rescue LoadError + #puts "" + #puts "YOU NEED NArray installed to run NArray tests!" + #puts "" +#end