hangman_tournament 1.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.
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
+