All pastes #837643 Raw Edit

dthacker

public ruby v1 · immutable
#837643 ·published 2007-12-29 20:51 UTC
rendered paste body
I'm trying to extend a class roster to add a delete_player method.  Below is the program I'm running to work with the roster class, the error messages, and the roster.rb itself with my added code highlighted.  I #!/usr/bin/ruby$: << 'lib'require 'roster'roster_klass = RosterClass.new('cfg/roster_cfg.txt')myroster = roster_klass.new("xx9.txt")if myroster.player_exists?("G_Lyne")   print "Yep. He's still here\n"else   print "I cut that slacker last week!!\n"endif myroster.player_exists?("D_Thacker")   print "Yep. He's still here\n"else   print "I cut that slacker last week!!\n"endmyroster["G_Lyne"].min = 15myroster.player_remove("X_Mosis")myroster.write_roster("xx9_modified.txt")Results:dthacker@buckbeak:~/dev/esms4/esmsdev$ ./rosterboy.rbYep. He's still hereI cut that slacker last week!!./lib/roster.rb:112:in `delete': wrong number of arguments (0 for 1) (ArgumentError)        from ./lib/roster.rb:112:in `player_remove'        from ./rosterboy.rb:22Library rosters.rb~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# ESMS - Electronic Soccer Management Simulator## Copyright (C) <2006> Eli Bendersky# License: LGPL (http://www.gnu.org/licenses/lgpl.html)#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~require 'yaml'require 'eliben_utils'# A factory for Rosters. Generates a Roster class from a roster# configuration file.## The configuration file defines which columns the roster contains,# in what order, and the manner in which these columns are stored# in roster files. A Roster class represents this information, by# means of an auxiliary class derived from a Struct - RosterPlayer.# This RosterPlayer class represents all the information stored# for a player. Each column defined in the configuration file is# represented by a field in the structure.## Once a some Roster class, named klass, is created, klass::RosterPlayer# can be used to access the underlying player type.## Each instance of a Roster class represents some roster file# that complies to the roster format defined by the class. The roster# is an Hash of RosterPlayer objects, keyed by names (Name is a# required column in rosters)## Usage:##  # Create a new Roster class from a configuration file#  roster_klass = RosterClass.new('roster_cfg.xml')##  # instantiate a new Roster object from a roster file#  roster = roster_klass.new("atl.txt")##  # access, change or add players#  minutes = roster["J_Doe"].min#  roster["J_Doe"].min = 15#  roster["New_Player"] = roster_klass::RosterPlayer.new#  roster["New_Player"].min = 67#  ...#  if roster.player_exists?("D_Od") ...#    ...###  # write a roster into a roster file#  roster.write_roster("atl_modified.txt")#module RosterClass    def self.new(config_filename)        roster_klass = Class.new        roster_klass.class_eval do            @@columns = RosterClass.parse_roster_config(config_filename)            include Enumerable            # Build the RosterPlayer class            #            @@column_ids = @@columns.map {|column| column[:id]}            self.const_set('RosterPlayer', Struct.new(*@@column_ids))            # Get the column ids            #            def self.column_ids                @@column_ids            end            # Create a new Roster. When no file name is given, the Roster            # will be empty - you can fill it in later with calls to read_roster            # or add_player            #            def initialize(roster_filename = nil)                # @players is a Hash mapping from player name to a full RosterPlayer                # object.                # @players_order is an Array of player names, to retain the order in                # which the players were stored in the roster                #                @players = Hash.new                @players_order = Array.new                if roster_filename                    read_roster(roster_filename)                end            end            # Get a player (RosterPlayer) by name            #            def [](name)                @players[name]            end            # Does this player exist in the roster ?            #            def player_exists?(name)                !@players[name].nil?            end            # Change or add a player. If an unexisting player name is specified,            # it is added to the roster            #            def []=(name, player)                unless @players.include?(name)                    @players_order << name                end                @players[name] = player            end###############################################My attempt at new method for removing player ##################            def player_remove(name)                @players.delete[name]            end############################################## End of new code ################################################            # Generic /each/ iterator - iterates over players in the            # roster, in the order of their appearance in the roster file.            # Each yielded object is a RosterPlayer struct.            #            def each                @players_order.each do |name|                    yield @players[name]                end            end            # Reads in a roster file (verifying that it is in the correct format)            #            def read_roster(roster_filename)                File.open(roster_filename) do |roster_file|                    @players = Hash.new                    @players_order = Array.new                    roster_lines = roster_file.readlines                    # Compare the first line with the columns definition                    # of the class, making sure it's a correctly formatted roster                    #                    first_line = roster_lines.shift                    if first_line.split.size != @@columns.size                        fail "Incorrect number of columns in header: expecting #{@@columns.size}"                    end                    first_line.split.each_with_index do |column, i|                        if @@columns[i][:name].casecmp(column) != 0                            fail "Column name doesn't match configuration: '#{column}' while expecting '#{@@columns[i][:name]}'"                        end                    end                    # Ignore the second line - it is supposed to be a string of hyphens (---)                    # but we don't really care what's in it                    #                    roster_lines.shift                    # The rest of the roster lines are parsed and read into @players. Empty                    # lines are ignored.                    #                    roster_lines.each do |line|                        line_columns = line.split                        if line_columns.empty?                            next                        elsif line_columns.size != @@columns.size                            fail "Incorrect number of columns: expecting #{@@columns.size} in line:\n#{line}"                        end                        roster_player = self.class::RosterPlayer.new                        # Read each column from the line into roster_player, checking                        # the types of columns (and converting, where necessary) on                        # the way.                        #                        @@columns.each do |column|                            column_value = line_columns.shift                            if column[:type] == "Integer"                                if column_value.integer?                                    column_value = Integer(column_value)                                else                                    fail "Expected an Integer in column #{column[:name]}, got '#{column_value}' in line:\n#{line}"                                end                            elsif column[:type] == "Float"                                if column_value.float?                                    column_value = Float(column_value)                                else                                    fail "Expected a Float in column #{column[:name]}, got '#{column_value}' in line:\n#{line}"                                end                            end                            roster_player[column[:id]] = column_value                        end                        @players[roster_player.name] = roster_player                        @players_order << roster_player.name                    end                end            end            # Writes a roster into a file            #            def write_roster(roster_filename)                File.open(roster_filename, "w") do |roster_file|                    # Use make_roster_line to create the header line, providing column                    # names as the data                    #                    roster_file.puts(make_roster_line(@@columns.map {|c| c[:name]}, false))                    # Create the header separation line of dashes                    #                    num_of_dashes = @@columns.inject(0) {|sum, c| sum += (c[:width] + 1)} - 1                    roster_file.puts('-' * num_of_dashes)                    # Now dump all the players into the file                    #                    @players_order.each do |name|                        roster_file.puts(make_roster_line(@players[name]))                    end                end            end            private            # Given a RosterPlayer object, creates the line that stores this            # player's details, according to the format of @@columns.            #            # The second optional parameter tells the method to resolve types            # of columns:            #   true - use the format (f, d, s, etc) appropriate for the type            #   false - use s for all columns            #            def make_roster_line(player, resolve_types = true)                # Build a line format from the column specification                #                line_format = ""                @@columns.each do |column|                    fmt = '%'                    fmt += '-' if column[:align] == 'left'                    if resolve_types and column[:type] == 'Float'                        if column[:width] < 4                            fail "Expecting width of at least 4 in 'Float' column #{column[:name]}"                        end                        fmt += format("%d.%d", column[:width], column[:width] - 3)                    else                        fmt += column[:width].to_s                    end                    fmt += if resolve_types                                case column[:type]                                    when 'Integer' then 'd'                                    when 'Float' then 'f'                                    else 's'                                end                            else                                's'                            end                    fmt += ' '                    line_format += fmt                end                # remove the trailing space that the loop added                #                line_format.chop!                # Fill in the format with the player's data                #                format(line_format, *player.to_a)            end        end        roster_klass    end    # Reads and parses a YAML file containing the roster configuration.    # On success returns the configuration in an internal format:    #    # An Array of columns, where each column is a Hash with the keys    #  :id, :name, :width, :align, :type    #    # :id is a 'symbol' version of :name (e.g. :nat for "Nat"), for internal    # usage with the RosterPlayer type    #    def self.parse_roster_config(config_filename)        File.open(config_filename) do |config_file|            cfg = YAML::load(config_file)            cfg_lines = cfg['esms_roster_format']            if cfg_lines.nil?                fail "expecing 'esms_roster_format' configuration"            end            columns = []            cfg_lines.each_with_index do |line, line_index|                unless line.keys.size == 1                    fail "expecting a single entry in column number #{line_index + 1}"                end                name = line.keys[0]                properties = line[name]                column_spec = {}                %w(width type).each do |required_property|                    if properties[required_property].nil?                        fail "column #{name} lacks a #{required_property} property"                    end                    column_spec[required_property.to_sym] = properties[required_property]                end                column_spec[:id] = name.downcase.to_sym                column_spec[:name] = name                column_spec[:align] = properties['align'].nil? ? 'right' : properties['align']                allowed_property_values = { :type => %w(Integer String Float),                                            :align => %w(right left)}                allowed_property_values.each do |property, values|                    unless values.contains?(column_spec[property])                        fail "value '#{column_spec[property]}' of property '#{property.to_s}' in column #{name} is illegal"                    end                end                columns << column_spec            end            columns        end    end#########################################################################################################Program I'm using to access library is below. ###########################################################################################################