Ruby-Programmierung: Aufgaben

Zurück zum Inhaltsverzeichnis.

Dieses Kapitel soll dieses Buch mit Aufgaben zu verschiedenen Themen abschließen. Dabei können Sie versuchen die verschiedenen Aufgaben an jeder Stelle des Buches versuchen zu lösen, eventuell ist es dadurch jedoch schwerer oder unmöglich die Aufgabe zu lösen, da Ihnen bestimmte Mittel aus späteren Kapiteln fehlen. Das kann auch dazu führen, dass Sie eventuell die vorgestellte Lösung nicht nachvollziehen können.

Mindestens sollten Sie an dieser Stelle den Abschnitt Grundlagen durchgearbeitet haben, um die Aufgaben lösen zu können.

Die Aufgaben bestehen aus einem Thema und einer Aufgabenbeschreibung, sowie Gedanken zur Lösung des Problems. Wenn Sie eine Aufgabe bearbeiten sollten Sie das tun, ohne auf die hier vorgestellte Lösung zu schauen, um am meisten aus der Bearbeitung der Aufgabe zu lernen.

Passwortgenerator

Bearbeiten

Diese Aufgabe besteht darin ein Programm zu entwickeln, das zufällig generierte Passwörter ausgibt. Dabei könnte das Programm den folgenden Funktionsumfang haben:

  • Variable Länge der Passwörter
  • Auswahl legitimer Zeichen
  • Speichern der letzten Einstellungen
  • Erneutes Erzeugen von Standardeinstellungen

Musterlösung

#Encoding: utf-8

require "yaml"
require "set"

class Preferences < Hash
  def initialize
    super
    self[:length] = 10
    self[:chars] = ::Set.new
    ("a".."z").each { |c| self[:chars] << c }
    ("A".."Z").each { |c| self[:chars] << c }
    "!\"§$%&/()=?*_:;{[]}\\+#-.,".split("").each { |c| self[:chars] << c }
  end
end

class Password
  def self.gen(pref)
    pw = ""
    pref[:length].times { pw << pref[:chars].to_a.shuffle[0] }

    pw
  end
end

if File.file? ".pref"
  pref = YAML.load_file(".pref")
else
  pref = Preferences.new
end

catch :exit do
  input = ""

  loop do
    input = gets.chomp
    value = input[/[^=]+$/]

    case input
    when /!e/
      throw :exit
    when /!n/
      pref = Preferences.new
    when /!a/
      value.split("").each { |c| pref[:chars] << c }
    when /!r/
      value.split("").each { |c| pref[:chars].delete c }
    when /!l/
      pref[:length] = value.to_i
    else
      puts "Generated password: " + Password.gen(pref)
    end
  end
end

open(".pref","w") { |f| YAML.dump(pref,f) }

Primzahlprüfer

Bearbeiten

Das Programm soll bei Eingabe einer Zahl überprüfen, ob es sich um eine Primzahl handelt oder nicht. Es kann sowohl als Kommandozeilenapplikation, als auch als interaktive Applikation gestalltet werden.

Musterlösung

#Encoding: utf-8
require "prime"

class PrimeChecker
  def self.run(argv)
    if argv.empty?
      interactive_prime_checker
    else
      prime_checker(argv.map(&:to_i))
    end
  end

  def self.prime_checker(numbers)
    numbers.each do |num|
      puts "#{ num } #{ Prime.prime?(num) ? "is a prime." : "isn't a prime." }"
    end
  end

  def self.interactive_prime_checker
    puts "Please enter some numbers or nothing to exit."
    loop do
      input = gets.chomp
      break if input.empty?
      numbers = input.split(/\s+/).map(&:to_i)
      prime_checker(numbers)
    end
  end
end

PrimeChecker::run(ARGV)

Konvertieren in das metrische System

Bearbeiten

Im amerikanischen Sprachraum wird häufig anstelle des metrischen das imperiale Einheitensystem verwendet, was bei Menschen zu Konfusionen führen kann, die die Einheiten nicht gewohnt sind. Die Aufgabe ist es also einen Konverter für imperiale Einheiten wie Zoll, Fuß, Gallonen und so weiter zu schreiben, der dann eine metrische Ausgabe vornimmt. Bedenken Sie, dass es viele solcher Einheiten gibt und das die Struktur ihres Program das Hinzufügen neuer Einheiten so leicht wie möglich machen sollte. Die Beispiellösung erlaubt das Aufrufen des Programms mittels ruby converter.rb 200lbs 6ft 3inch.

Musterlösung

module Converter
  def self.run(args)
    puts convert(args)
  end

  def self.convert(args)
    args.map { |arg| Unit.parse(arg).to_metric }
  end

  class Unit
    def self.units
      {
        "lbs" => Pound,
        "ft" => Feet,
        "inch" => Inch
      }
    end

    def self.parse(arg)
      unit = arg[/\D+\Z/i]
      value = arg[/\d+(\.\d+)?/].to_f

      units.fetch(unit).new(value)
    end

    def initialize(value)
      @value = value
    end

    def to_s
      "#{ @value }#{ unit_string }"
    end
  end

  class Kilogram < Unit
    def to_metric
      self
    end

    def unit_string
      "kg"
    end
  end

  class Pound < Unit
    def to_metric
      Kilogram.new(@value * 0.454)
    end

    def unit_string
      "lbs"
    end
  end

  class Meter < Unit
    def to_metric
      self
    end

    def unit_string
      "m"
    end
  end

  class Feet < Unit
    def to_metric
      Meter.new(@value * 0.3048)
    end

    def unit_string
      "ft"
    end
  end

  class Inch < Unit
    def to_metric
      Meter.new(@value * 0.0254)
    end

    def unit_string
      "inch"
    end
  end
end

Converter::run(ARGV)