primetable 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,138 @@
1
+ # Not sure why this is here. I'll have to experiment with taking it out.
1
2
  require "primetable/version"
2
3
 
3
- module PrimeTable
4
-
5
- end
4
+ # This is needed for load_primes method, which loads data from a file.
5
+ require "yaml"
6
+
7
+ # I'll probably remove this later, but it's my interim table display solution.
8
+ require "awesome_print"
9
+
10
+ # It's a pretty simple program. I considered making multiple classes, but it's not necessary.
11
+ class PrimeTable
12
+
13
+ # We're going to want to get and set things from inside multiple methods, so...
14
+ attr_accessor :primes, :table
15
+
16
+ def initialize(first=1, count=10, prime_method=:calc, suppress_output=false)
17
+
18
+ # This is only for testing, I'm unlikely to implement a command-line flag for this
19
+ unless suppress_output
20
+
21
+ puts "PrimeTable is running..."
22
+ end
23
+
24
+ # Ye olde instance variables
25
+ @primes = init_primes(:load,first,count)
26
+ @table = build_data(@primes)
27
+
28
+ # I added this suppress_output so I could run certain tests without a huge, admittly
29
+ # ugly, table clobbering my nice green passing specs
30
+ unless suppress_output
31
+ display_table(@table)
32
+ end
33
+
34
+ end # def initialize()
35
+
36
+ # One way or another, we need to get an array of consecutive prime numbers.
37
+ def init_primes(prime_method, first, count)
38
+
39
+ # Of course, we calculate the primes by default. But having three methods is not only
40
+ # fancy; it's also comes in handy for testing that our calculated values are correct.
41
+ case prime_method
42
+ when :fast # Shaves off about between 10 and 40 milliseconds vs. the :load method
43
+ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
44
+
45
+ when :load # Using precalculated values saves us a lot of time vs. the :calc method
46
+ load_primes(first,count)
47
+ when :calc # The slowest, but presumably preferred, method in our arsenal
48
+ calc_primes(first,count)
49
+ end # case prime_method
50
+
51
+ end # def init_primes()
52
+
53
+ # Calculates the primes using basic math. This can be slow for higher primes or higher counts.
54
+ # TODO: Include note on computational complexity here: O(n*sqrt(n)), I think
55
+ # TODO: Include note on average run time using this method.
56
+ def calc_primes(first, count)
57
+
58
+ end
59
+
60
+ # Loads precalculated primes from a data file. The file is formatted with 10 primes per line.
61
+ # Each line is enclosed in square brackets, and the primes are comma-delimited. Thus, it's
62
+ # trivial to read each line in as an array of ten primes. Please note that this file is 995K
63
+
64
+ # and contains 13413 lines. You don't want to just slurp this file. That would be rude. Instead
65
+
66
+ # we read lines one at a time and only keep what we need. Also note the highest prime in this
67
+ # file is currently 1999993, although conceivably we could use the :calc method and extend it.
68
+ def load_primes(first, count)
69
+
70
+ # Again, we only have the first 134128 primes in here right now
71
+ if (first + count) > 134128
72
+ throw "We only have the first 134128 primes in the data file right now. Please pass -c to use calculated primes."
73
+ end
74
+
75
+ # An array to keep our prime numbers in, right?
76
+ primes = []
77
+
78
+ # Because there are ten primes on each line, we can get the line number we're looking for by
79
+ # dividing the indices we want by 10 and rounding down for the bottom of our range and up for
80
+
81
+ # the top. It's not immediately intuitive why we might want to do this, but it's because:
82
+ # 1) We don't want to slurp the whole file...what if the file was even larger? Not cool.
83
+
84
+ # 2) IO.readlines gets the file one line at a time, so we need a line number, not an index.
85
+
86
+ first_line = (first/10).floor
87
+ last_line = ((first+count)/10).ceil
88
+
89
+ # Here we read in the file one line at a time. Yes I looked for a faster way. Try :fast (-f).
90
+ IO.readlines("data/prime.dat").each_with_index{|line,ln|
91
+
92
+ # When we find the lines we want, we concatenate them into a single array. We get extra.
93
+ if (ln >= first_line and ln <= last_line)
94
+ primes.concat(YAML::load(line))
95
+ end
96
+ }
97
+
98
+ # The extra is trimmed off in this step. We know what we want. Just this, thanks!
99
+ start = first - (first_line*10) - 1
100
+ return primes.slice!(start,count)
101
+
102
+ end
103
+
104
+ def build_data(primes)
105
+
106
+ # To make this code simpler we act as if our first prime is 1 so that the matrix includes
107
+ # our header row and column of primes (multiplied by 1)...we remove the corner 1 later
108
+ primes.unshift(1)
109
+
110
+ # An empty two-dimensional array to act as the data model for our table
111
+ table = Array.new(primes.length) { Array.new(primes.length) }
112
+
113
+ # We populate the array-of-arrays with the products-of-primes ;-)
114
+ primes.each_with_index{|outerprime,i|
115
+ primes.each_with_index{|innerprime,y|
116
+ table[i][y] = outerprime*innerprime
117
+ }
118
+ }
119
+
120
+ # Here we remove the corner 1 which was added as a side-effect of the matrix generation
121
+ primes.shift(1)
122
+ table[0][0] = nil
123
+
124
+ # And send the table data to display (or, in theory, whoever called us)
125
+ return table
126
+
127
+ end
128
+
129
+ # The plan is to use Formatador to make this display nicely. For now, I'm just dumping the data,
130
+ # and making it slightly less lame with awesome_print.
131
+ def display_table(table)
132
+
133
+ # Not much to see here. But I expect to be able to justify a comment soon enough.
134
+ ap table
135
+
136
+ end
137
+
138
+ end
@@ -1,3 +1,3 @@
1
- module PrimeTable
2
- VERSION = "0.0.1"
1
+ class PrimeTable
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,28 @@
1
+ class Timer
2
+
3
+ def self.timer(&block)
4
+ start_time = Time.now
5
+ result = block.call
6
+ end_time = Time.now
7
+ @time_taken = (end_time - start_time) * 1000
8
+ result
9
+ end
10
+
11
+ def self.humanize ms
12
+ [[1000, :ms], [60, :secs], [60, :mins], [24, :hrs], [365, :days], [10000, :yrs]].map{ |count, name|
13
+ if ms > 0
14
+ ms, n = ms.divmod(count)
15
+ "#{n.to_i} #{name}"
16
+ end
17
+ }.compact.reverse.join(' ')
18
+ end
19
+
20
+ def self.elapsedTime
21
+ humanize @time_taken
22
+ end
23
+
24
+ def self.time()
25
+ elapsedTime
26
+ end
27
+
28
+ end
@@ -21,4 +21,5 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "awesome_print"
24
25
  end
@@ -1,8 +1,65 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe PrimeTable do
4
+ before(:all) do
5
+ @expected_execution_output = "PrimeTable is running...\n"
6
+ @expected_time_output = "ms"
7
+ @expected_version_output = PrimeTable::VERSION
8
+ @expected_help_output = "Common options:
9
+ -t, --time Display run time
10
+ -h, --help Show this message
11
+ -v, --version Show version"
12
+ @expected_first_ten_primes = [2,3,5,7,11,13,17,19,23,29]
13
+ @expected_table_with_first_ten_primes = [[nil,2,3,5,7,11,13,17,19,23,29],
14
+ [2,4,6,10,14,22,26,34,38,46,58],
15
+ [3,6,9,15,21,33,39,51,57,69,87],
16
+ [5,10,15,25,35,55,65,85,95,115,145],
17
+ [7,14,21,35,49,77,91,119,133,161,203],
18
+ [11,22,33,55,77,121,143,187,209,253,319],
19
+ [13,26,39,65,91,143,169,221,247,299,377],
20
+ [17,34,51,85,119,187,221,289,323,391,493],
21
+ [19,38,57,95,133,209,247,323,361,437,551],
22
+ [23,46,69,115,161,253,299,391,437,529,667],
23
+ [29,58,87,145,203,319,377,493,551,667,841]]
24
+ end
4
25
  it 'has a version number' do
5
26
  expect(PrimeTable::VERSION).not_to be nil
6
27
  end
7
-
28
+ it 'executes when called on the command line' do
29
+ expect(`primetable`).to include("PrimeTable is running...\n")
30
+ end
31
+ it 'executes *and* prints out a run time when passed -t or --time' do
32
+ execution_output = `primetable -t`
33
+ expect(execution_output).to include(@expected_execution_output)
34
+ expect(execution_output).to include(@expected_time_output)
35
+ execution_output = `primetable --time`
36
+ expect(execution_output).to include(@expected_execution_output)
37
+ expect(execution_output).to include(@expected_time_output)
38
+ end
39
+ it 'prints out the version number when passed -v or --version' do
40
+ expect(`primetable -v`).to include(@expected_version_output)
41
+ end
42
+ it 'executes *and* prints out a run time *and* prints out the version number when passed both -t and -v arguments' do
43
+ execution_output = `primetable -tv`
44
+ expect(execution_output).to include(@expected_execution_output)
45
+ expect(execution_output).to include(@expected_time_output)
46
+ expect(execution_output).to include(@expected_version_output)
47
+ end
48
+ it 'executes *and* prints out a run time *and* prints out the version number when passed both --time and --version arguments' do
49
+ execution_output = `primetable -tv`
50
+ expect(execution_output).to include(@expected_execution_output)
51
+ expect(execution_output).to include(@expected_time_output)
52
+ expect(execution_output).to include(@expected_version_output)
53
+ end
54
+ it 'prints out usage details when passed -h or --help' do
55
+ execution_output = `primetable -h`
56
+ expect(execution_output).to include(@expected_help_output)
57
+ execution_output = `primetable --help`
58
+ expect(execution_output).to include(@expected_help_output)
59
+ end
60
+ it "has the right data when we run it with :load" do
61
+ test_instance = PrimeTable.new(1,10,:load,true)
62
+ expect(test_instance.primes).to eq(@expected_first_ten_primes)
63
+ expect(test_instance.table).to eq(@expected_table_with_first_ten_primes)
64
+ end
8
65
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: primetable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Day Davis Waterbury
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-19 00:00:00.000000000 Z
11
+ date: 2015-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,11 +52,26 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: awesome_print
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Displays the products of N primes in a table format. Optionally uses
56
70
  generated primes or precalculated.
57
71
  email:
58
72
  - day.waterbury@gmail.com
59
- executables: []
73
+ executables:
74
+ - primetable
60
75
  extensions: []
61
76
  extra_rdoc_files: []
62
77
  files:
@@ -67,8 +82,11 @@ files:
67
82
  - LICENSE.txt
68
83
  - README.md
69
84
  - Rakefile
85
+ - bin/primetable
86
+ - data/prime.dat
70
87
  - lib/primetable.rb
71
88
  - lib/primetable/version.rb
89
+ - lib/timer.rb
72
90
  - primetable.gemspec
73
91
  - spec/primetable_spec.rb
74
92
  - spec/spec_helper.rb