primetable 0.0.1 → 0.2.0

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.
@@ -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