Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
willkoehler committed Aug 21, 2016
0 parents commit 806b171
Show file tree
Hide file tree
Showing 19 changed files with 583 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
# Ignore bundler config.
/.bundle

# Ignore OSX files like:
.DS_Store
2 changes: 2 additions & 0 deletions .rspec
@@ -0,0 +1,2 @@
--color
--require spec_helper
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

gem 'rspec'
gem 'guard-rspec'
65 changes: 65 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,65 @@
GEM
remote: https://rubygems.org/
specs:
coderay (1.1.1)
diff-lcs (1.2.5)
ffi (1.9.10)
formatador (0.2.5)
guard (2.13.0)
formatador (>= 0.2.4)
listen (>= 2.7, <= 4.0)
lumberjack (~> 1.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-rspec (4.6.5)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
listen (3.1.3)
rb-fsevent (~> 0.9, >= 0.9.7)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
lumberjack (1.0.10)
method_source (0.8.2)
nenv (0.3.0)
notiffany (0.0.8)
nenv (~> 0.1)
shellany (~> 0.0)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-core (3.5.2)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-support (3.5.0)
ruby_dep (1.3.0)
shellany (0.0.1)
slop (3.6.0)
thor (0.19.1)

PLATFORMS
ruby

DEPENDENCIES
guard-rspec
rspec

BUNDLED WITH
1.12.2
46 changes: 46 additions & 0 deletions Guardfile
@@ -0,0 +1,46 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features) \
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}

## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
# $ mkdir config
# $ mv Guardfile config/
# $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"

# Note: The cmd option is now required due to the increasing number of ways
# rspec may be run, below are examples of the most common uses.
# * bundler: 'bundle exec rspec'
# * bundler binstubs: 'bin/rspec'
# * spring: 'bin/rspec' (This will use spring if running and you have
# installed the spring binstubs per the docs)
# * zeus: 'zeus rspec' (requires the server to be started separately)
# * 'just' rspec: 'rspec'

guard :rspec, cmd: "bin/rspec" do
require "guard/rspec/dsl"
dsl = Guard::RSpec::Dsl.new(self)

# Feel free to open issues for suggestions and improvements

# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)

# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)

watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end
17 changes: 17 additions & 0 deletions bin/_guard-core
@@ -0,0 +1,17 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application '_guard-core' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("guard", "_guard-core")
17 changes: 17 additions & 0 deletions bin/bundler
@@ -0,0 +1,17 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("bundler", "bundler")
17 changes: 17 additions & 0 deletions bin/guard
@@ -0,0 +1,17 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'guard' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("guard", "guard")
17 changes: 17 additions & 0 deletions bin/rspec
@@ -0,0 +1,17 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rspec-core", "rspec")
43 changes: 43 additions & 0 deletions lib/digit_parser.rb
@@ -0,0 +1,43 @@
# NOTE: This is simple now, but I'm pretty sure this class will be justified in User Story #4
class DigitParser

# TODO should this work like Number parser, taking the digit string in the constructor and
# then adding a digit member function? This will be clearer when we work on case #4
def parse(digit)
(Digits.find_index(digit) || '?').to_s
end

Digits = [
" _ " +
"| |" +
"|_|",
" "+
" |"+
" |",
" _ " +
" _|" +
"|_ ",
" _ " +
" _|" +
" _|",
" " +
"|_|" +
" |",
" _ " +
"|_ " +
" _|",
" _ " +
"|_ " +
"|_|",
" _ " +
" |" +
" |",
" _ " +
"|_|" +
"|_|",
" _ " +
"|_|" +
" _|",
]

end
6 changes: 6 additions & 0 deletions lib/file_parser.rb
@@ -0,0 +1,6 @@
# This class will read a file, parse into individual account numbers, and pass them to NumberParser,
# possibly storing them in an array for use by another class. I have't worked out exactly how it would
# work.

class FileParser
end
6 changes: 6 additions & 0 deletions lib/machine.rb
@@ -0,0 +1,6 @@
# This is the main class of the system. It will use FileParser to read and parse a file into an array of numbers
# This class would be used to produce output for User Story 3. Altough I can see another class that knows how
# to generate and format an output file. Maybe FileWriter?

class Machine
end
35 changes: 35 additions & 0 deletions lib/number_parser.rb
@@ -0,0 +1,35 @@
require 'digit_parser'

class NumberParser

def initialize(input)
@input = input
end

def value
@value ||= parse
end

def illegible?
value.include? '?'
end

def valid?
!illegible? && checksum == 0
end

private

def checksum
digit_array = value.chars.map(&:to_i)
digit_array.each_with_index.inject(0) { |sum, (digit,i)| sum + digit * (9-i) } % 11
end

def parse
(0..8).inject('') { |result, i| result += DigitParser.new.parse(digit_at(i)) }
end

def digit_at(i)
@input[i*3..2+i*3] + @input[27+i*3..29+i*3] + @input[54+i*3..56+i*3]
end
end
38 changes: 38 additions & 0 deletions readme.md
@@ -0,0 +1,38 @@
# Partial Solution of KataBankOCR

<http://codingdojo.org/cgi-bin/index.pl?KataBankOCR>

## Steps to run the code

Currently the code is exercised solely via the RSpec tests.

Start by installing necessary gems

cd [folder where you cloned the code]
bundle

Then run the tests

bin/rspec

Or use guard to run the tests automatically as you work

bundle exec guard

## Status

I completed User Story #1 and #2. While not directly testing the user stories, `number_parser_spec.rb`
contains specs that exercise the functionality of #1 and #2. There are probably some edge cases I'm not
handling. For example what happens if the string passed to NumberParser isn't exactly 27 characters? I
think that will cause an exception currently. Of course, this could be mitigated in a higher layer as
well. FileParser could be written to always parse out exactly 27 character strings. If it were a client
project, I would spend more time exploring the edge cases before moving on to #3

User Story #3 should be straightforward. It will require completing and wiring together Machine and
FileParser, and possibly a FileWriter class.

User Story #4 will require adding functionality to DigitParser that can produce all possible digits for
a given string. Then NumberParser will need to work through combinations of digits, checking each for
a validity and storing the possible values. Then Machine will need to work out what do to from there
with help of FileWriter. I haven't given this much thought beyond that.

57 changes: 57 additions & 0 deletions spec/digit_parser_spec.rb
@@ -0,0 +1,57 @@
require 'digit_parser'

describe DigitParser do

describe "#parse" do

it "parses digits" do
parser = DigitParser.new

expected = {
" _ " +
"| |" +
"|_|" => '0',
" "+
" |"+
" |" => '1',
" _ " +
" _|" +
"|_ " => '2',
" _ " +
" _|" +
" _|" => '3',
" " +
"|_|" +
" |" => '4',
" _ " +
"|_ " +
" _|" => '5',
" _ " +
"|_ " +
"|_|" => '6',
" _ " +
" |" +
" |" => '7',
" _ " +
"|_|" +
"|_|" => '8',
" _ " +
"|_|" +
" _|" => '9'
}

# NOTE: This is a technique I use when testing large numbers of inputs through a functon.
# The test doesn't abort on the first match failure. The rspec matcher outputs a nice diff
# showing the failed matches. For a small number of cases like this, it may be clearer to
# just call parse() for each string.
actual = expected.keys.each_with_object({}) do |digit, h|
h[digit] = parser.parse(digit)
end
expect(actual).to eq(expected)
end

it "returns ? if it doesn't recognize the digit" do
expect(DigitParser.new.parse('xx')).to eq('?')
end
end
end
4 changes: 4 additions & 0 deletions spec/file_parser_spec.rb
@@ -0,0 +1,4 @@
require 'file_parser'

describe FileParser do
end

0 comments on commit 806b171

Please sign in to comment.