marmalade 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in marmalade.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Rusty Geldmacher
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Marmalade
2
+
3
+ A Ruby library for helping with the boring, mechanical part of Google Code Jam puzzles, letting you focus on solving the problem instead of setting up the scaffolding.
4
+
5
+ Most Code Jam input files look like something like this:
6
+
7
+ 100 # Number of test cases
8
+ 5 3 # Some data about case 1, say a number then some numnber of lines to read next
9
+ 123 # First line to read
10
+ 456 # Second line to read
11
+ 789 # Third line to read
12
+ 9 8 # Start of test case 2
13
+
14
+ When beginning a puzzle, wouldn't it be nice to focus on what you need to do to solve it rather than messing with read in the file in the right increments, debugging it, and making sure its doing what you expect? This is where Marmalade comes in. It gives you tools to use in order to quickly get down to the work of solving the actual problem. After all, time is of the essence!
15
+
16
+ ## Installation
17
+
18
+ Install via RubyGems:
19
+
20
+ $ gem install marmalade
21
+
22
+ ## Usage
23
+
24
+ ### Basic Usage
25
+
26
+ Once you create a Ruby file for solving a Code Jam puzzle, simply require the Marmalade gem:
27
+
28
+ #!/usr/bin/env ruby
29
+
30
+ require 'rubygems'
31
+ require 'marmalade'
32
+
33
+ Make the file executable and Marmalade is ready to do the dirty work for you. Say we have an input file like the one described above. The first number in each test case is called `k` and the second is `n`, which is the number of `lines` to read in for each puzzle. Assuming we have a method called `solve_case` that returns the result we're looking for, we can instruct Marmalade to read that for us like so:
34
+
35
+ Marmalade.jam(:file => 'input.txt') do
36
+ read :num_cases, :type => :int
37
+ test_cases do
38
+ read [:k, :n], :type => :int
39
+ read :lines, :count => @n
40
+ puts_res solve_case(@k, @lines)
41
+ end
42
+
43
+ Marmalade reads in each line and will assign the values to instance variables that you specify. When the result is ready to be printed, calling `puts_res` will output the proper format that Code Jam usually requires, much like:
44
+
45
+ Case #1: 12
46
+ Case #2: 55
47
+ # and so on...
48
+
49
+ ### Other Stuff
50
+
51
+ - --debug and puts_dbg
52
+ _ --case
53
+ - --step and run_case
54
+ - reading with :split
55
+ - reading strings
56
+
57
+ ## Contributing
58
+
59
+ 1. Fork it
60
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
61
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
62
+ 4. Push to the branch (`git push origin my-new-feature`)
63
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require 'rake'
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+ require 'bundler/gem_tasks'
6
+
7
+ desc 'Default: run the specs'
8
+ task :default => 'spec'
9
+
10
+ desc "Run specs"
11
+ RSpec::Core::RakeTask.new('spec') do |t|
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ end
@@ -0,0 +1,52 @@
1
+ module Marmalade
2
+ # A class to help parsing out values from a Code Jam input file
3
+ class FileReader
4
+ attr_accessor :file_handle
5
+
6
+ def initialize(file_handle)
7
+ self.file_handle = file_handle
8
+ end
9
+
10
+ # Reads the next values from the file and returns them as a hash
11
+ def read(assignments, options = {})
12
+ line_count = options[:count]
13
+ read_options = options.dup
14
+ if assignments.is_a?(Array)
15
+ read_options[:split] = true
16
+ end
17
+ lines = 1.upto(line_count || 1).map { read_line(file_handle, read_options) }
18
+ lines = line_count.nil? ? lines.first : lines
19
+ assign_results(assignments, lines)
20
+ end
21
+
22
+ private
23
+
24
+ def read_line(file_handle, options)
25
+ line = file_handle.gets.strip
26
+ integers = [:int, :integer].include?(options[:type])
27
+ if options[:split]
28
+ line_a = line.split(' ')
29
+ if integers
30
+ line_a = line_a.map(&:to_i)
31
+ end
32
+ line_a
33
+ elsif integers
34
+ line = line.to_i
35
+ else
36
+ line
37
+ end
38
+ end
39
+
40
+ def assign_results(assignments, lines)
41
+ Hash.new.tap do |assigns|
42
+ if assignments.is_a?(Symbol)
43
+ assigns[assignments] = lines
44
+ elsif assignments.is_a?(Array)
45
+ assignments.each_with_index do |var, i|
46
+ assigns[var] = lines[i]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ module Marmalade
2
+ class Puzzle
3
+ attr_accessor :reader
4
+
5
+ def initialize(file_reader, options = {})
6
+ @options = options.dup
7
+ @debug = (@options.delete(:debug) == true)
8
+ self.reader = file_reader
9
+ end
10
+
11
+ def read(assignments, options = {})
12
+ # TODO: Check if we're in a 'run_case' block, if so throw an error
13
+ options = @options.merge(options)
14
+ assigns = reader.read(assignments, options)
15
+ assigns.each do |k, v|
16
+ instance_variable_set("@#{k.to_s}", v)
17
+ end
18
+ end
19
+
20
+ def test_cases(options = {}, &block)
21
+ # TODO: Make sure @num_cases is set
22
+ options = options.merge(@options)
23
+ 1.upto(@num_cases) do |case_num|
24
+ @case_num = case_num
25
+ instance_eval(&block)
26
+ return if options[:case] == case_num
27
+ STDIN.getc if options[:step]
28
+ end
29
+ end
30
+
31
+ def run_case(&block)
32
+ if @options[:case].nil? || @options[:case] == @case_num
33
+ instance_eval(&block)
34
+ end
35
+ end
36
+
37
+ def puts(*args)
38
+ puts_with_case(*args)
39
+ end
40
+
41
+ def puts_dbg(*args)
42
+ puts_with_case(*args) if @debug
43
+ end
44
+
45
+ private
46
+
47
+ def puts_with_case(*args)
48
+ print "Case ##{@case_num}: ", *args
49
+ print "\n"
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module Marmalade
2
+ VERSION = "0.0.1"
3
+ end
data/lib/marmalade.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'trollop'
3
+
4
+ require 'marmalade/file_reader'
5
+ require 'marmalade/puzzle'
6
+ require 'marmalade/version'
7
+
8
+ module Marmalade
9
+
10
+ def self.jam(options = {}, &block)
11
+ options = parse_options.merge(options)
12
+ File.open(options[:file], 'r') do |file|
13
+ reader = FileReader.new(file)
14
+ puzzle = Puzzle.new(reader, options)
15
+ puzzle.instance_eval(&block)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def self.parse_options
22
+ options = Trollop::options do
23
+ opt :file, "Input file to read", :short => 'f', :type => :string
24
+ opt :debug, "Debug mode", :short => 'd', :default => false
25
+ opt :step, "Step through each case", :short => 's', :default => false
26
+ opt :case, "Only run the given case", :short => 'c', :type => :integer, :default => nil
27
+ end
28
+ end
29
+
30
+ end
data/marmalade.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/marmalade/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Rusty Geldmacher"]
6
+ gem.email = ["russell.geldmacher@gmail.com"]
7
+ gem.description = %q{Marmalade gives you ready-to-go parsing and other helpers for Google Code Jam puzzles}
8
+ gem.summary = %q{Helper for Google Code Jam puzzles}
9
+ gem.homepage = "http://www.github.com/rustygeldmacher/marmalade"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "marmalade"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Marmalade::VERSION
17
+
18
+ gem.add_dependency 'trollop', '~>1.16.2'
19
+
20
+ gem.add_development_dependency 'rspec', '~>2.9.0'
21
+ gem.add_development_dependency 'mocha', '~>0.10.5'
22
+ end
@@ -0,0 +1,11 @@
1
+ 3
2
+ 1 2
3
+ foo
4
+ bar
5
+ 9 4
6
+ a
7
+ b
8
+ c
9
+ d
10
+ 3 1
11
+ hello world
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Marmalade::FileReader do
4
+
5
+ context "reading strings" do
6
+ it "will read a line from a file handle" do
7
+ reader = build_reader("hello world")
8
+ reader.read(:foo).should == { :foo => "hello world" }
9
+ end
10
+
11
+ it "will read a line and split it into an array" do
12
+ reader = build_reader("a b c")
13
+ reader.read(:foo, :split => true).should == { :foo => ['a', 'b', 'c'] }
14
+ end
15
+
16
+ it "will read multiple values from a line" do
17
+ reader = build_reader("hello world")
18
+ reader.read([:foo, :bar]).should == { :foo => "hello", :bar => "world" }
19
+ end
20
+
21
+ it "will strip whitespace from the end of the line" do
22
+ reader = build_reader("\thello world ")
23
+ reader.read(:foo).should == { :foo => "hello world" }
24
+ end
25
+ end
26
+
27
+ context "reading integers" do
28
+ it "will read an integer value from a file" do
29
+ reader = build_reader("9")
30
+ reader.read(:foo, :type => :int).should == { :foo => 9 }
31
+ end
32
+
33
+ it "will read multiple integer values from a line" do
34
+ reader = build_reader("15 22")
35
+ reader.read([:foo, :bar], :type => :int).should == { :foo => 15, :bar => 22 }
36
+ end
37
+
38
+ it "will read an array of integers from a line" do
39
+ reader = build_reader("1 2 3")
40
+ reader.read(:foo, :type => :int, :split => true).should == { :foo => [1, 2, 3] }
41
+ end
42
+ end
43
+
44
+ context "reading multiple lines" do
45
+ it "will read multiple lines into a value" do
46
+ reader = build_reader('a b', 'c d', 'e f')
47
+ reader.read(:foo, :count => 3).should == { :foo => ['a b', 'c d', 'e f'] }
48
+ end
49
+
50
+ it "will read multiple values and split them into arrays" do
51
+ reader = build_reader('a b', 'c', 'd e')
52
+ reader.read(:foo, :count => 3, :split => true).should == { :foo => [['a', 'b'], ['c'], ['d', 'e']] }
53
+ end
54
+
55
+ it "will read multiple lines of integers" do
56
+ reader = build_reader('1', '2', '3')
57
+ reader.read(:foo, :count => 3, :type => :int).should == { :foo => [1, 2, 3] }
58
+ end
59
+
60
+ it "will return an array of lines even if asking for one line" do
61
+ reader = build_reader('abc')
62
+ reader.read(:foo, :count => 1).should == { :foo => ['abc'] }
63
+ end
64
+ end
65
+
66
+ def build_reader(*lines)
67
+ seq = sequence('file_handle')
68
+ file_handle = mock('file_handle')
69
+ lines.each do |line|
70
+ file_handle.expects(:gets).in_sequence(seq).returns(line)
71
+ end
72
+ Marmalade::FileReader.new(file_handle)
73
+ end
74
+
75
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Marmalade do
4
+
5
+ it "will coordinate opening and reading a file full of test cases" do
6
+ cases = {}
7
+ Marmalade.jam(:file => fixture_file('input_0.txt')) do
8
+ read :num_cases, :type => :int
9
+ test_cases do
10
+ read [:dummy, :n], :type => :int
11
+ read :lines, :count => @n
12
+ run_case do
13
+ cases[@case_num] = { :dummy => @dummy, :lines => @lines }
14
+ end
15
+ end
16
+ end
17
+ cases.should == { 1 => { :dummy => 1, :lines => ['foo', 'bar'] },
18
+ 2 => { :dummy => 9, :lines => ['a', 'b', 'c', 'd'] },
19
+ 3 => { :dummy => 3, :lines => ['hello world'] } }
20
+ end
21
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Marmalade::Puzzle do
4
+
5
+ describe "#read" do
6
+ it "will pass the options to the reader and assign instance varialbes based on the results" do
7
+ reader = mock()
8
+ reader.expects(:read).with([:foo, :bar], { :a => 1, :b => 2}).returns({:foo => "a", :bar => 2})
9
+ puzzle = Marmalade::Puzzle.new(reader, :a => 1)
10
+ puzzle.read([:foo, :bar], :b => 2)
11
+ puzzle.instance_eval do
12
+ @foo.should == 'a'
13
+ @bar.should == 2
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "#test_cases" do
19
+ it "will run through all the test cases" do
20
+ run_test_cases.should == [1, 2, 3]
21
+ end
22
+
23
+ it "will return after the specified case as part of support for run_case" do
24
+ run_test_cases(:case => 2).should == [1, 2]
25
+ end
26
+
27
+ it "will pause after each case if the :step option is set" do
28
+ STDIN.expects(:getc).times(3)
29
+ run_test_cases(:step => true)
30
+ end
31
+
32
+ def run_test_cases(options = {})
33
+ puzzle = Marmalade::Puzzle.new(mock('reader'))
34
+ puzzle.instance_eval do
35
+ @num_cases = 3
36
+ end
37
+ case_numbers = []
38
+ puzzle.test_cases(options) do
39
+ case_numbers << @case_num
40
+ end
41
+ case_numbers
42
+ end
43
+ end
44
+
45
+ describe "#run_case" do
46
+ before do
47
+ @puzzle = Marmalade::Puzzle.new(mock('file_reader'))
48
+ end
49
+
50
+ it "will evaluate the given block if no case options are specified" do
51
+ build_puzzle(3).run_case do
52
+ 'foo'
53
+ end.should == 'foo'
54
+ end
55
+
56
+ it "will evaluate the block if the given case and the current case match" do
57
+ build_puzzle(3, :case => 3).run_case do
58
+ 'foo'
59
+ end.should == 'foo'
60
+ end
61
+
62
+ it "will not evalulate the block if the case numbers don't match" do
63
+ build_puzzle(3, :case => 4).run_case do
64
+ 'foo'
65
+ end.should be_nil
66
+ end
67
+ end
68
+
69
+ describe "#puts" do
70
+ it "will print the message along with the current case number" do
71
+ puzzle = build_puzzle(4)
72
+ puzzle.expects(:print).with("Case #4: ", "hello")
73
+ puzzle.expects(:print).with("\n")
74
+ puzzle.puts("hello")
75
+ end
76
+ end
77
+
78
+ describe "#puts_dbg" do
79
+ it "will print the message with the case number if in debug mode" do
80
+ puzzle = build_puzzle(4, :debug => true)
81
+ puzzle.expects(:print).with("Case #4: ", "hello")
82
+ puzzle.expects(:print).with("\n")
83
+ puzzle.puts_dbg('hello')
84
+ end
85
+
86
+ it "will not print the message if the puzzle isn't in debug mode" do
87
+ puzzle = build_puzzle(4)
88
+ puzzle.expects(:print).never
89
+ puzzle.puts_dbg('hello')
90
+ end
91
+ end
92
+
93
+ def build_puzzle(case_num, options = {})
94
+ puzzle = Marmalade::Puzzle.new(mock('file_reader'), options)
95
+ puzzle.instance_eval do
96
+ @case_num = case_num
97
+ end
98
+ puzzle
99
+ end
100
+
101
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'marmalade'
3
+
4
+ RSpec.configure do |config|
5
+ config.mock_framework = :mocha
6
+ end
7
+
8
+ def fixture_file(file_name)
9
+ File.join(File.expand_path("../fixtures", __FILE__), file_name)
10
+ end
11
+
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marmalade
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Rusty Geldmacher
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-03-28 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: trollop
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 83
29
+ segments:
30
+ - 1
31
+ - 16
32
+ - 2
33
+ version: 1.16.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 43
45
+ segments:
46
+ - 2
47
+ - 9
48
+ - 0
49
+ version: 2.9.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: mocha
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 61
61
+ segments:
62
+ - 0
63
+ - 10
64
+ - 5
65
+ version: 0.10.5
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: Marmalade gives you ready-to-go parsing and other helpers for Google Code Jam puzzles
69
+ email:
70
+ - russell.geldmacher@gmail.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files: []
76
+
77
+ files:
78
+ - .gitignore
79
+ - Gemfile
80
+ - LICENSE
81
+ - README.md
82
+ - Rakefile
83
+ - lib/marmalade.rb
84
+ - lib/marmalade/file_reader.rb
85
+ - lib/marmalade/puzzle.rb
86
+ - lib/marmalade/version.rb
87
+ - marmalade.gemspec
88
+ - spec/fixtures/input_0.txt
89
+ - spec/marmalade/file_reader_spec.rb
90
+ - spec/marmalade/marmalade_spec.rb
91
+ - spec/marmalade/puzzle_spec.rb
92
+ - spec/spec_helper.rb
93
+ homepage: http://www.github.com/rustygeldmacher/marmalade
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options: []
98
+
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ requirements: []
120
+
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.10
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Helper for Google Code Jam puzzles
126
+ test_files:
127
+ - spec/fixtures/input_0.txt
128
+ - spec/marmalade/file_reader_spec.rb
129
+ - spec/marmalade/marmalade_spec.rb
130
+ - spec/marmalade/puzzle_spec.rb
131
+ - spec/spec_helper.rb
132
+ has_rdoc: