hangman_tournament 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,6 @@
1
+ = Hangman Tounament Changelog
2
+
3
+ == Version 1.0
4
+
5
+ Initial Release
6
+ * FTW
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/gempackagetask'
4
+
5
+ desc "Run all specs"
6
+ Spec::Rake::SpecTask.new('spec') do |t|
7
+ t.spec_files = FileList['spec/**/*.rb']
8
+ t.rcov = false
9
+ end
10
+
11
+ PKG_NAME = "hangman_tournament"
12
+ PKG_VERSION = "1.0"
13
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = PKG_NAME
17
+ s.version = PKG_VERSION
18
+ s.files = FileList['lib/**/*', 'spec/**/*', 'bin/**/*', 'CHANGES', 'Rakefile'].to_a
19
+ s.require_path = 'lib'
20
+ s.test_files = Dir.glob('spec/*_spec.rb')
21
+ s.bindir = 'bin'
22
+ s.executables = ['generate_hangman_player', 'submit_hangman_player']
23
+ s.email = "sparring-hangman@rubyforge.org"
24
+ s.homepage = "http://sparring.rubyforge.org/"
25
+ s.rubyforge_project = "sparring"
26
+ s.summary = "Hangman tournament."
27
+ s.description = "This gem provides the infrastructure needed to participate in the Hangman Tournament"
28
+ s.author = "Micah Martin"
29
+ s.add_dependency('letter_letdown', ">= 1.0")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.need_zip = false
34
+ pkg.need_tar = false
35
+ end
36
+
37
+ task :verify_user do
38
+ raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
39
+ end
40
+
41
+ task :verify_password do
42
+ raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
43
+ end
44
+
45
+ task :copy_player_gems do
46
+ system "cp ../letter_letdown/pkg/hangman_letter_letdown-1.0.gem pkg"
47
+ system "cp submissions/*.gem pkg"
48
+ end
49
+
50
+ desc "Publish gem+tgz+zip on RubyForge. You must make sure lib/version.rb is aligned with the CHANGELOG file"
51
+ task :publish_packages => [:verify_user, :verify_password, :package, :copy_player_gems] do
52
+ require 'meta_project'
53
+ require 'rake/contrib/xforge'
54
+ release_files = FileList[
55
+ "pkg/#{PKG_FILE_NAME}.gem",
56
+ "pkg/hangman_letter_letdown-1.0.gem"
57
+ ]
58
+
59
+ Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new("sparring")) do |xf|
60
+ # Never hardcode user name and password in the Rakefile!
61
+ xf.user_name = ENV['RUBYFORGE_USER']
62
+ xf.password = ENV['RUBYFORGE_PASSWORD']
63
+ xf.files = release_files.to_a
64
+ xf.release_name = "Hangman Tournament #{PKG_VERSION}"
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ player_name = ARGV[0]
4
+
5
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/init")
6
+ require "limelight/templates/player_templater"
7
+
8
+ templater = Limelight::Templates::PlayerTemplater.new(player_name)
9
+ templater.generate
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ player_name = ARGV[0]
4
+
5
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/init")
6
+ require "hangman_tournament/submit"
7
+
8
+ submitter = HangmanTournament::Submit.new(player_name)
9
+ submitter.submit
@@ -0,0 +1,71 @@
1
+ require 'rubygems'
2
+ require 'digest/sha1'
3
+ require 'drb'
4
+
5
+ module HangmanTournament
6
+
7
+ class Submit
8
+
9
+ def initialize(gem_name)
10
+ @gem_name = gem_name
11
+ @input = $stdin
12
+ @output = $stdout
13
+ end
14
+
15
+ def submit
16
+ data = collect_data
17
+ password = get_password
18
+ password = Digest::SHA1.hexdigest(password)
19
+ data[:password] = password
20
+
21
+ begin
22
+ server = DRbObject.new(nil, 'druby://micahmartin.com:9697')
23
+ authorized = server.authorize(data[:name], password)
24
+ quit "Incorrect password. You are not authorized to submit this player." unless authorized
25
+ result = server.submit_profile(data)
26
+ quit "Failed to submit: #{result}" if result != true
27
+ puts "Player #{data[:name]} has been submitted."
28
+ rescue DRb::DRbConnError => e
29
+ quit "Could not connect to battleship server!"
30
+ end
31
+ end
32
+
33
+ def collect_data
34
+ spec = gem_spec
35
+ data = {}
36
+ data[:name] = spec.summary[15..-1]
37
+ data[:author] = spec.author
38
+ data[:email] = spec.email
39
+ data[:description] = spec.description
40
+ data[:gem_file_name] = spec.file_name
41
+ gem_file_path = File.expand_path(File.join(spec.full_gem_path, "..", "..", 'cache', spec.file_name))
42
+ data[:gem_content] = IO.read(gem_file_path)
43
+ return data
44
+ end
45
+
46
+ def gem_spec
47
+ if @spec.nil?
48
+ @spec = Gem.source_index.latest_specs.find do |spec|
49
+ spec.name == @gem_name
50
+ end
51
+ end
52
+ quit "Could not find installed gem named '#{@gem_name}'" if @spec.nil?
53
+ return @spec
54
+ end
55
+
56
+ def get_password
57
+ @output.puts "Password?"
58
+ @output.print "> "
59
+
60
+ password = @input.readline.strip
61
+ return password
62
+ end
63
+
64
+ def quit(message)
65
+ puts message
66
+ exit -1
67
+ end
68
+
69
+ end
70
+
71
+ end
data/lib/init.rb ADDED
@@ -0,0 +1 @@
1
+ $: << File.expand_path(File.dirname(__FILE__))
@@ -0,0 +1,35 @@
1
+ class String
2
+
3
+ # Converts Ruby style names to Java style camal case.
4
+ #
5
+ # "four_score".camalized # => "FourScore"
6
+ # "and_seven_years".camalized(:lower) # => "andSevenYears"
7
+ #
8
+ def camalized(starting_case = :upper)
9
+ value = self.downcase.gsub(/[_| ][a-z]/) { |match| match[-1..-1].upcase }
10
+ value = value[0..0].upcase + value[1..-1] if starting_case == :upper
11
+ return value
12
+ end
13
+
14
+ # Converts Java camel case names to ruby style underscored names.
15
+ #
16
+ # "FourScore".underscored # => "four_score"
17
+ # "andSevenYears".underscored # => "and_seven_years"
18
+ #
19
+ def underscored
20
+ value = self[0..0].downcase + self[1..-1]
21
+ value = value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }
22
+ return value
23
+ end
24
+
25
+
26
+ # Converts ruby style and camalcase strings into title strings where every word is capitalized and separated by a space.
27
+ #
28
+ # "four_score".titleized # => "Four Score"
29
+ #
30
+ def titleized(starting_case = :upper)
31
+ value = self.gsub(/[a-z0-9][A-Z]/) { |match| "#{match[0..0]} #{match[-1..-1]}" }
32
+ value = value.gsub(/[_| ][a-z]/) { |match| " #{match[-1..-1].upcase}" }
33
+ return value[0..0].upcase + value[1..-1]
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ require 'limelight/templates/templater'
2
+ require 'limelight/string'
3
+
4
+ module Limelight
5
+ module Templates
6
+
7
+ class PlayerTemplater < Templater
8
+
9
+ attr_reader :filename, :tokens
10
+
11
+ def initialize(player_name)
12
+ super(".")
13
+ @tokens = {}
14
+ @tokens[:PLAYER_NAME] = player_name
15
+ clean_name = player_name.gsub(/[\?\*!'\-.;:]/, "").gsub(" ", "_").downcase
16
+ @filename = @tokens[:FILENAME] = clean_name
17
+ @tokens[:CLASSNAME] = clean_name.camalized
18
+ end
19
+
20
+ # Generates the files
21
+ #
22
+ def generate
23
+ file(File.join(filename, "Rakefile"), "Rakefile.template", @tokens)
24
+ file(File.join(filename, "Hangman.Rakefile"), "Hangman.Rakefile.template", @tokens)
25
+ file(File.join(filename, "lib", filename, "#{filename}.rb"), "player.template", @tokens)
26
+ file(File.join(filename, "spec", "spec_helper.rb"), "spec_helper.template", @tokens)
27
+ file(File.join(filename, "spec", filename, "#{filename}_spec.rb"), "player_spec.template", @tokens)
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # DO NOT tamper with this file. It will lead to disqualification.
3
+
4
+ require 'rake'
5
+ require 'spec/rake/spectask'
6
+
7
+ desc "Run all examples with RCov"
8
+ Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
9
+ t.spec_files = FileList['spec/**/*.rb']
10
+ t.rcov = true
11
+ t.rcov_opts = ['-t', '--exclude', 'spec,rcov', '--no-html']
12
+ end
@@ -0,0 +1,47 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'spec/rake/spectask'
4
+ require 'hangman_tournament/submit'
5
+
6
+ desc "Run all specs"
7
+ Spec::Rake::SpecTask.new('spec') do |t|
8
+ t.spec_files = FileList['spec/**/*.rb']
9
+ t.rcov = false
10
+ end
11
+
12
+ PKG_NAME = "!-FILENAME-!"
13
+ PKG_VERSION = "1.0"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = "hangman_#{PKG_NAME}"
17
+ s.version = PKG_VERSION
18
+ s.files = Dir.glob('**/*').reject{ |f| f =~ /pkg/ }
19
+ s.require_path = 'lib'
20
+ s.test_files = Dir.glob('spec/*_spec.rb')
21
+ s.bindir = 'bin'
22
+ s.executables = []
23
+ s.summary = "Hangman Player:!-PLAYER_NAME-!"
24
+ s.rubyforge_project = "sparring"
25
+ s.homepage = "http://sparring.rubyforge.org/"
26
+
27
+ ###########################################
28
+ ##
29
+ ## You are encouraged to modify the following
30
+ ## spec attributes.
31
+ ##
32
+ ###########################################
33
+ s.description = "A hangman player"
34
+ s.author = "Anonymous"
35
+ s.email = "authors@email.com"
36
+ end
37
+
38
+ Rake::GemPackageTask.new(spec) do |pkg|
39
+ pkg.need_zip = false
40
+ pkg.need_tar = false
41
+ end
42
+
43
+ desc "Submit your player"
44
+ task :submit do
45
+ submitter = HangmanTournament::Submit.new(PKG_NAME)
46
+ submitter.submit
47
+ end
@@ -0,0 +1,169 @@
1
+ module !-CLASSNAME-!
2
+
3
+ # Battleship Player
4
+ #
5
+ # Battleship is board game between two players. See http://en.wikipedia.org/wiki/Battleship for more information and
6
+ # game rules.
7
+ #
8
+ # A player represents the conputer AI to play a game of Battleship. It should know how to place ships and target
9
+ # the opponents ships.
10
+ #
11
+ # This version of Battleship is played on a 10 x 10 grid where rows are labled by the letters A - J and
12
+ # columns are labled by the numbers 1 - 10. At the start of the game, each player will be asked for ship placements.
13
+ # Once the ships are placed, play proceeeds by each player targeting one square on their opponents map. A player
14
+ # may only target one square, reguardless of whether it resulted in a hit or not, before changing turns with her opponent.
15
+ #
16
+ class !-CLASSNAME-!
17
+
18
+ # This method is called at the beginning of each game. A player may only be instantiated once and used to play many games.
19
+ # So new_game should reset any internal state acquired in previous games so that it is prepared for a new game.
20
+ #
21
+ # The name of the opponent player is passed in. This allows for the possibility to learn opponent strategy and
22
+ # play the game differently based on the opponent.
23
+ #
24
+ def new_game(opponent_name)
25
+ reset
26
+ end
27
+
28
+ # Returns the placement of the carrier. A carrier consumes 5 squares.
29
+ #
30
+ # The return value is a string that describes the placements of the ship.
31
+ # The placement string must be in the following format:
32
+ #
33
+ # "#{ROW}#{COL} #{ORIENTATION}"
34
+ #
35
+ # eg
36
+ #
37
+ # A1 horizontal # the ship will occupy A1, A2, A3, A4, and A5
38
+ # A1 vertical # the ship will occupy A1, B1, C1, D1, and E1
39
+ # F5 horizontal # the ship will occupy F5, F6, F7, F8, and F9
40
+ # F5 vertical # the ship will occupy F5, G5, H5, I5, and J5
41
+ #
42
+ # The ship must not fall off the edge of the map. For example, a carrier placement of 'A8 horizontal' would
43
+ # not leave enough space in the A row to accomidate the carrier since it requires 5 squares.
44
+ #
45
+ # Ships may not overlap with other ships. For example a carrier placement of 'A1 horizontal' and a submarine
46
+ # placement of 'A1 vertical' would be invalid because bothe ships are trying to occupy the square A1.
47
+ #
48
+ # Invalid ship placements will result in disqualification of the player.
49
+ #
50
+ def carrier_placement
51
+ return "A1 horizontal"
52
+ end
53
+
54
+ # Returns the placement of the battleship. A battleship consumes 4 squares.
55
+ #
56
+ # See carrier_placement for details on ship placement
57
+ #
58
+ def battleship_placement
59
+ return "B1 horizontal"
60
+ end
61
+
62
+ # Returns the placement of the destroyer. A destroyer consumes 3 squares.
63
+ #
64
+ # See carrier_placement for details on ship placement
65
+ #
66
+ def destroyer_placement
67
+ return "C1 horizontal"
68
+ end
69
+
70
+ # Returns the placement of the submarine. A submarine consumes 3 squares.
71
+ #
72
+ # See carrier_placement for details on ship placement
73
+ #
74
+ def submarine_placement
75
+ return "D1 horizontal"
76
+ end
77
+
78
+ # Returns the placement of the patrolship. A patrolship consumes 2 squares.
79
+ #
80
+ # See carrier_placement for details on ship placement
81
+ #
82
+ def patrolship_placement
83
+ return "E1 horizontal"
84
+ end
85
+
86
+ # Returns the coordinates of the players next target. This method will be called once per turn. The player
87
+ # should return target coordinates as a string in the form of:
88
+ #
89
+ # "#{ROW}#{COL}"
90
+ #
91
+ # eg
92
+ #
93
+ # A1 # the square in Row A and Column 1
94
+ # F5 # the square in Row F and Column 5
95
+ #
96
+ # Since the map contains only 10 rows and 10 columns, the ROW should be A, B, C, D, E, F, G H, I, or J. And the
97
+ # COL should be 1, 2, 3, 4, 5, 6, 7, 8, 9, or 10
98
+ #
99
+ # Returning coordinates outside the range or in an invalid format will result in the players disqualification.
100
+ #
101
+ # It is illegal to illegal to target a sector more than once. Doing so will also result in disqualification.
102
+ #
103
+ def next_target
104
+ target = target_for_current_shot
105
+ @shots_taken += 1
106
+ return target
107
+ end
108
+
109
+ # target_result will be called by the system after a call to next_target. The paramters supplied inform the player
110
+ # of the results of the target.
111
+ #
112
+ # coordinates : string. The coordinates targeted. It will be the same value returned by the previous call to next_target
113
+ # was_hit : boolean. true if the target was occupied by a ship. false otherwise.
114
+ # ship_sunk : symbol. nil if the target did not result in the sinking of a ship. If the target did result in
115
+ # in the sinking of a ship, the ship type is supplied (:carrier, :battleship, :destroyer, :submarine, :patrolship).
116
+ #
117
+ # An intelligent player will use the information to better play the game. For example, if the result indicates a
118
+ # hit, a player my choose to target neighboring squares to hit and sink the remainder of the ship.
119
+ #
120
+ def target_result(coordinates, was_hit, ship_sunk)
121
+ end
122
+
123
+ # enemy_targeting is called by the system to inform a player of their apponents move. When the opponent targets
124
+ # a square, this method is called with the coordinates.
125
+ #
126
+ # Players may use this information to understand an opponents targeting strategy and place ships differently
127
+ # in subsequent games.
128
+ #
129
+ def enemy_targeting(coordinates)
130
+ end
131
+
132
+ # Called by the system at the end of a game to inform the player of the results.
133
+ #
134
+ # result : 1 of 3 possible values (:victory, :defeate, :disqualified)
135
+ # disqualification_reason : nil unless the game ended as the result of a disqualification. In the event of a
136
+ # disqualification, this paramter will hold a string description of the reason for disqualification. Both
137
+ # players will be informed of the reason.
138
+ #
139
+ # :victory # indicates the player won the game
140
+ # :defeat # indicates the player lost the game
141
+ # :disqualified # indicates the player was disqualified
142
+ #
143
+ def game_over(result, disqualification_reason=nil)
144
+ end
145
+
146
+ # Non API methods #####################################
147
+
148
+ attr_reader :opponent, :targets, :enemy_targeted_sectors, :result, :disqualification_reason #:nodoc:
149
+
150
+ def initialize #:nodoc:
151
+ reset
152
+ end
153
+
154
+ private ###############################################
155
+
156
+ def reset
157
+ @shots_taken = 0
158
+ end
159
+
160
+ ROWS = %w{ A B C D E F G H I J }
161
+ def target_for_current_shot
162
+ row = ROWS[(@shots_taken) / 10]
163
+ col = @shots_taken % 10 + 1
164
+ return "#{row}#{col}"
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,45 @@
1
+ module !-CLASSNAME-!
2
+ class !-CLASSNAME-!
3
+
4
+ # You may initialize you player but the the initialize method must take NO paramters.
5
+ # The player will only be instantiated once, and will play many games.
6
+ def initialize
7
+ end
8
+
9
+ # Before starting a game, this method will be called to inform the player of all the possible words that may be
10
+ # played.
11
+ def word_list=(list)
12
+ end
13
+
14
+ # a new game has started. The number of guesses the player has left is passed in (default 6),
15
+ # in case you want to keep track of it.
16
+ def new_game(guesses_left)
17
+ @left = ('a'..'z').to_a
18
+ end
19
+
20
+ # Each turn your player must make a guess. The word will be a bunch of underscores, one for each letter in the word.
21
+ # after your first turn, correct guesses will appear in the word parameter. If the word was "shoes" and you guessed "s",
22
+ # the word parameter would be "s___s", if you then guess 'o', the next turn it would be "s_o_s", and so on.
23
+ # guesses_left is how many guesses you have left before your player is hung.
24
+ def guess(word, guesses_left)
25
+ @left.shift
26
+ end
27
+
28
+ # notifies you that your last guess was incorrect, and passes your guess back to the method
29
+ def incorrect_guess(guess)
30
+ end
31
+
32
+ # notifies you that your last guess was correct, and passes your guess back to the method
33
+ def correct_guess(guess)
34
+ end
35
+
36
+ # you lost the game. The reason is in the reason parameter
37
+ def fail(reason)
38
+ end
39
+
40
+ # The result of the game, it'll be one of 'win', 'loss', or 'fail'.
41
+ # The spelled out word will be provided regardless of the result.
42
+ def game_result(result, word)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require '!-FILENAME-!/!-FILENAME-!'
3
+
4
+ describe !-CLASSNAME-!::!-CLASSNAME-! do
5
+
6
+ it "should be instantiable with no paramters" do
7
+
8
+ lambda { !-CLASSNAME-!::!-CLASSNAME-!.new }.should_not raise_error
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,4 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+
3
+ require 'rubygems'
4
+ require 'spec'
@@ -0,0 +1,128 @@
1
+ require 'limelight/templates/templater_logger'
2
+
3
+ module Limelight
4
+ module Templates
5
+
6
+ # A class to create directories and file templates. An instance of Templater must be provided with
7
+ # a target_root and a source_root. The target_root designates a root directory in which all directories and
8
+ # files will be created. The source_root designated a directory where all the file template can be found.
9
+ #
10
+ # A file template is a plain text file. It may optionally contain token markers in the format !-TOKEN_NAME-!.
11
+ # When a file template is installed by the templater, all the token margers will be replaced by tokens provided
12
+ # in a hash.
13
+ #
14
+ class Templater
15
+
16
+ # Return the default source_root for Limelight related file templates.
17
+ #
18
+ # $LIMELIGHT_LIB$/limelight/templates/sources
19
+ #
20
+ def self.source_dir
21
+ return File.join(File.dirname(__FILE__), "sources")
22
+ end
23
+
24
+ # Carifies a path as relative or absolute. Essentially if makes sure a path begins with a . if it's not
25
+ # an absolute path.
26
+ #
27
+ # Templater.clarity('some/path') -> './some/path'
28
+ # Templater.clarity('/root/path') -> '/root/path'
29
+ #
30
+ def self.clarify(path)
31
+ return path if path[0..0] == '.'
32
+ return path if path == File.expand_path(path)
33
+ return File.join(".", path)
34
+ end
35
+
36
+ attr_reader :target_root, :source_root
37
+
38
+ # See TemplaterLogger
39
+ #
40
+ attr_accessor :logger
41
+
42
+ # New instances Templater require a target_root. The source_root may optionally be provided. source_root
43
+ # defaults to Templater.source_dir
44
+ #
45
+ # The logger is initializes as a TemplaterLogger
46
+ #
47
+ def initialize(target_root, source_root=Templater.source_dir)
48
+ @logger = TemplaterLogger.new
49
+ @target_root = Templater.clarify(target_root)
50
+ @source_root = source_root
51
+ end
52
+
53
+ # Creates a deirectory. If the specified directory's parent directory is missing, it will be created as will its
54
+ # parent directory, and so on.
55
+ #
56
+ # After the following call,
57
+ #
58
+ # templater.directory("dir1/dir2/dir3/dir4")
59
+ #
60
+ # The following directories will exist, inside the target_root, whether they existed prior to the call or not.
61
+ #
62
+ # dir1
63
+ # dir1/dir2
64
+ # dir1/dir2/dir3
65
+ # dir1/dir2/dir3/dir4
66
+ #
67
+ def directory(path)
68
+ full_path = File.join(@target_root, path)
69
+ establish_directory(full_path)
70
+ end
71
+
72
+ # Creates the specified file from the specified file template. The file will be created withint the target_root.
73
+ # All parent diretories will be created if needed. The source paramter should be a path pointing to a
74
+ # file template in the source_root directory.
75
+ #
76
+ # Assume the the file <code>src/default.txt.template</code> exists in the source_root with the following content.
77
+ #
78
+ # !-SCORES-! score and !-YEARS-! years ago, ...
79
+ #
80
+ # When the following command is executed,
81
+ #
82
+ # templater.file('dir/foo.txt', 'src/default.txt.template', :SCORES => "Four", :YEARS => "seven")
83
+ #
84
+ # The file <code>dir/foo.txt</code> will exist in the target_root with the following content.
85
+ #
86
+ # Four score and seven years ago, ...
87
+ #
88
+ def file(target, source, tokens = {})
89
+ target_path = File.join(@target_root, target)
90
+ source_source = File.join(@source_root, source)
91
+
92
+ establish_directory(File.dirname(target_path))
93
+
94
+ if File.exists?(target_path)
95
+ @logger.file_already_exists(target_path)
96
+ else
97
+ @logger.creating_file(target_path)
98
+ content = IO.read(source_source)
99
+ content = replace_tokens(content, tokens)
100
+ File.open(target_path, 'w') { |file| file.write content }
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def establish_directory(full_path)
107
+ return if File.exists?(full_path)
108
+ parent_path = File.dirname(full_path)
109
+ while (!File.exists?(parent_path))
110
+ establish_directory(parent_path)
111
+ end
112
+
113
+ @logger.creating_directory(full_path)
114
+ Dir.mkdir(full_path)
115
+ end
116
+
117
+ def replace_tokens(content, tokens)
118
+ return content.gsub(/!-(\w+)-!/) do |value|
119
+ token_name = value[2...-2]
120
+ token = tokens[token_name] || tokens[token_name.to_sym] || "UNKNOWN TOKEN"
121
+ token
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,36 @@
1
+ module Limelight
2
+ module Templates
3
+
4
+ # Templaters uses this class to log activity.
5
+ #
6
+ class TemplaterLogger
7
+
8
+ # An accessor to the output IO. Defaults to STDOUT
9
+ #
10
+ attr_accessor :output
11
+
12
+ def initialize
13
+ @output = STDOUT
14
+ end
15
+
16
+ def creating_directory(name)
17
+ @output.puts "\tcreating directory: #{name}"
18
+ end
19
+
20
+ def creating_file(name)
21
+ @output.puts "\tcreating file: #{name}"
22
+ end
23
+
24
+ def file_already_exists(name)
25
+ @output.puts "\tfile already exists: #{name}"
26
+ end
27
+
28
+ def log(message, name)
29
+ spaces = 21 - message.length - 1
30
+ @output.puts "\t#{message}:#{' '*spaces}#{name}"
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require 'hangman_tournament/submit'
3
+
4
+ describe HangmanTournament::Submit do
5
+
6
+ before(:all) do
7
+ ENV['GEM_PATH'] = '/opt/local/lib/ruby/gems/1.8'
8
+ Gem.clear_paths
9
+ end
10
+
11
+ before(:each) do
12
+ @submit = HangmanTournament::Submit.new("letter_letdown")
13
+ end
14
+
15
+ it "should read a gem file" do
16
+ result = @submit.collect_data
17
+
18
+ result[:name].should == "Letter Letdown"
19
+ result[:author].should == "Micah Martin"
20
+ result[:email].should == "micah@8thlight.com"
21
+ result[:description].should == "A very simple player."
22
+ result[:gem_file_name].should == "letter_letdown-1.0.gem"
23
+ result[:gem_content].should == IO.read("/opt/local/lib/ruby/gems/1.8/cache/letter_letdown-1.0.gem")
24
+ end
25
+
26
+ it "should get password" do
27
+ $stdout.should_receive(:puts).with("Password?")
28
+ $stdout.should_receive(:print).with("> ")
29
+ $stdin.should_receive(:readline).and_return("blah")
30
+
31
+ password = @submit.get_password
32
+
33
+ password.should == "blah"
34
+ end
35
+
36
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
+ require 'limelight/templates/player_templater'
3
+
4
+ describe Limelight::Templates::PlayerTemplater do
5
+
6
+ it "should know names" do
7
+ templater = Limelight::Templates::PlayerTemplater.new("Simple Bot")
8
+
9
+ templater.filename.should == "simple_bot"
10
+ templater.tokens[:CLASSNAME].should == "SimpleBot"
11
+ templater.tokens[:PLAYER_NAME].should == "Simple Bot"
12
+ end
13
+
14
+ it "should know names with a little punctuation" do
15
+ templater = Limelight::Templates::PlayerTemplater.new("Satan's Revenge!")
16
+
17
+ templater.filename.should == "satans_revenge"
18
+ templater.tokens[:CLASSNAME].should == "SatansRevenge"
19
+ templater.tokens[:PLAYER_NAME].should == "Satan's Revenge!"
20
+ end
21
+
22
+ it "should know names with a lot of punctuation" do
23
+ templater = Limelight::Templates::PlayerTemplater.new("Bl'ah? *Bl-!ah.;")
24
+
25
+ templater.filename.should == "blah_blah"
26
+ templater.tokens[:CLASSNAME].should == "BlahBlah"
27
+ templater.tokens[:PLAYER_NAME].should == "Bl'ah? *Bl-!ah.;"
28
+ end
29
+
30
+ it "should generate files" do
31
+ templater = Limelight::Templates::PlayerTemplater.new("Simple Bot")
32
+
33
+ templater.should_receive(:file).with("simple_bot/Rakefile", "Rakefile.template", anything)
34
+ templater.should_receive(:file).with("simple_bot/Hangman.Rakefile", "Hangman.Rakefile.template", anything)
35
+ templater.should_receive(:file).with("simple_bot/lib/simple_bot/simple_bot.rb", "player.template", anything)
36
+ templater.should_receive(:file).with("simple_bot/spec/spec_helper.rb", "spec_helper.template", anything)
37
+ templater.should_receive(:file).with("simple_bot/spec/simple_bot/simple_bot_spec.rb", "player_spec.template", anything)
38
+
39
+ templater.generate
40
+ end
41
+
42
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hangman_tournament
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Micah Martin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-17 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: letter_letdown
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ description: This gem provides the infrastructure needed to participate in the Hangman Tournament
26
+ email: sparring-hangman@rubyforge.org
27
+ executables:
28
+ - generate_hangman_player
29
+ - submit_hangman_player
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - lib/hangman_tournament
36
+ - lib/hangman_tournament/submit.rb
37
+ - lib/init.rb
38
+ - lib/limelight
39
+ - lib/limelight/string.rb
40
+ - lib/limelight/templates
41
+ - lib/limelight/templates/player_templater.rb
42
+ - lib/limelight/templates/sources
43
+ - lib/limelight/templates/sources/bs_player.template
44
+ - lib/limelight/templates/sources/Hangman.Rakefile.template
45
+ - lib/limelight/templates/sources/player.template
46
+ - lib/limelight/templates/sources/player_spec.template
47
+ - lib/limelight/templates/sources/Rakefile.template
48
+ - lib/limelight/templates/sources/spec_helper.template
49
+ - lib/limelight/templates/templater.rb
50
+ - lib/limelight/templates/templater_logger.rb
51
+ - spec/hangman_tournament
52
+ - spec/hangman_tournament/submit_spec.rb
53
+ - spec/limelight
54
+ - spec/limelight/templates
55
+ - spec/limelight/templates/player_templater_spec.rb
56
+ - spec/spec_helper.rb
57
+ - bin/generate_hangman_player
58
+ - bin/submit_hangman_player
59
+ - CHANGES
60
+ - Rakefile
61
+ has_rdoc: false
62
+ homepage: http://sparring.rubyforge.org/
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: sparring
83
+ rubygems_version: 1.3.1
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: Hangman tournament.
87
+ test_files: []
88
+