Dwa programy do "skrócenia"

Witam

Witam stworzyłem dwa skrypty w rubym, najpierw może wyjaśnie co robią. Pierwszy z listy osób w pliku tekstowym gdzie każda osoba jest w innej linijce, a ich szczegółowe dane oddzielone średnikiem robi plik rtf z kolorową tabelką, czyli takie jakby wizytówki. Drugi robi to samo tylko do pliku html. W pierwszym mogę użyć biblioteki (gema) w drugim nie.

Mój nauczyciel mi powiedział, że w obu przypadkach kod może być 2x razy krótszy no i nie organizuje wszystkiego w metody co ma mi sprawić problem w pisaniu bardziej zaawansowanego kody w przyszłości. Wstawiam kod i pytam gdzie/jak mógłbym coś poprawić by kod był krótszy i schludniejszy :wink: Moje adnotacje umieściłem w komentarzach.

require 'rubygems'
require 'rtf'
include RTF

def wizytowka(t, osoba, styl1, styl2, i)
	styl = CharacterStyle.new
	x = i/2.0.floor
	y = i % 2
	if x % 2 == 0
		styl = styl1
		t[x][y].shading_colour = $olive
	else
		styl = styl2
		t[x][y].shading_colour = $maroon
	end
	osoba = osoba.split(";")
	t[x][y].apply(styl) << "imie: " + osoba[0]
	
	# Tutaj założę się, że jest jakiś sposób by komenda o następnej
	#  lini automatycznie wywoływała się po każdej operacji na komórce
	
	t[x][y].line_break
	t[x][y].apply(styl) << "nazwisko: " + osoba[1]
	t[x][y].line_break
	t[x][y].apply(styl) << "data_urodzenia: " + osoba[2]
	t[x][y].line_break
	t[x][y].apply(styl) << "wynagrodzenie: " + osoba[3]
	t[x][y].line_break
	t[x][y].apply(styl) << "nr_telefonu: " + osoba[4]
	t[x][y].line_break
	t[x][y].apply(styl) << "stanowisko: " + osoba[5]
	t[x][y].line_break
	t[x][y].apply(styl) << "email: "+ osoba[6]
end	

dokument = Document.new(Font.new(Font::ROMAN, 'Times New Roman'), nil, Document::CS_PC, Document::LC_POLISH)

# nie podoba mi się użycie tu zmiennych globalnych, 
# ale tworzenie ich bezpośrednio w funkcji,
# nie wpłynęło by dobrze na wydajność skryptu

$maroon = Colour.new(125, 0, 0)
$olive = Colour.new(125, 125, 0)
styl1 = CharacterStyle.new
styl1.font = Font.new(Font::MODERN, 'Calibri')
styl1.foreground = $maroon
styl1.underline = true
styl2 = CharacterStyle.new
styl2.font = Font.new(Font::ROMAN, 'Times New Roman')
styl2.bold = true
styl2.foreground = $olive
ludzie = []
f = open('baza.txt', "r:UTF-8") { |f| f.read }
f.each_line { |ln| ludzie << ln }
tabela = dokument.table(ludzie.length/2.0.ceil,2, 4000,4000,4000)

# Tak samo jak w programie niżej nie podoba mi się wprowadzanie zmiennej "i"
# Czyli licznika, który mówi w której komórce tabeli się znajduje

i = 0
ludzie.each {|osoba|
	wizytowka(tabela, osoba, styl1, styl2, i)
	i += 1
}
File.open('wizytowki.rtf', 'w:UTF-8') {|f| f.write(dokument.to_rtf)}

Program 2

  def b(tekst)
    	"<b>#{tekst}</b>"
    end
    
    def tabela(dokument, osoba, i)
    	osoba = osoba.split(';')
    	
    	# Nie podoba mi się ta instrukcja warunkowa i
    	# wprowadzenie dodatkowej zmiennej "i".
    	# Jestem pewny, że w Rubym można jakoś inaczej
    	# robić "coś" dla co drugiego elementu, tylko nie wiem jak.
    	if i % 2 == 0
    		dokument << "<tr>"
    		kolor1 = 'maroon'
    		kolor2 = 'olive'
    	else
    		kolor1 = 'olive'
    		kolor2 = 'maroon'
    	end
    	
    	# Tutaj byłoby fajnie gdybym w jakiś sposób tabele i
    	# styl zorganizował w metody.
    	
    	dokument << "<td><p style='background-color:#{kolor1};font-family:arial;color:#{kolor2};font-size:20px;'>"
    	dokument << b("imie: ") + osoba[0] + "<br />"
    	dokument << b("nazwisko: ") + osoba[1] + "<br />"
    	dokument << b("data_urodzenia: ") + osoba[2] + "<br />"
    	dokument << b("wynagrodzenie: ") + osoba[3] + "<br />"
    	dokument << b("nr_telefonu: ") + osoba[4] + "<br />"
    	dokument << b("stanowisko: ") + osoba[5] + "<br />"
    	dokument << b("email: ") + osoba[6] + "<br />"
    	dokument << "</p></td>"
    	if i % 2 == 1
    		dokument << "</tr>"
    	end
    end	
    
    ludzie = []
    f = open('baza.txt', "r:UTF-8") { |f| f.read }
    f.each_line { |ln| ludzie << ln }
    dokument = ''
    
    # To też mi się nie podoba wolałbym,
    # że dokument był obiektem jakiejś klasy i
    # żeby to było dodawane wraz z utworzeniem obiekt,
    # a nie dopisywane do ciągu znaków.
    
    dokument << 
    	"<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>
    	<html>
    	<head>
    	<meta content='text/html; charset=ISO-8859-2'
    	http-equiv='content-type'>
    	<title></title>
    	</head>
    	<body>
    	<table>"
    
    i = 0
    ludzie.each { |osoba|
    	tabela(dokument, osoba, i)
    	i += 1
    }
    
    dokument << 
    	"</table>
    	</body>
    	</html>"
    
    File.open('dokument.html', 'w:ISO-8859-2') { |f| f.write dokument }

Nie chcę robić zadania za ciebie więc kilka porad:

Tutaj jest sporo sporo powtórzeń, zastanów się co można by było uzyskać korzystając z pętli?

Ja bym jeszcze zapytał czy wykładowca wspominał o tym, że Ruby to język zorientowany obiektowo?

Pod tym linkiem jest ciekawie wytłumaczone o co biega: https://www.youtube.com/watch?v=A-Nk2j1i5p8, ale jest mnóstwo alternatywnych źródeł.

DOKUMENTACJA JĘZYKA. Tam dowiesz się też co to jest ‘newline character’, albo metody ‘odd/even’.
Faktycznie jeśli ludzie mają tutaj wklejać Tobie rozwiązania zadań i czytać dokumentację za Ciebie, to nauczysz się z tego niewiele i będziesz miał straszną lipę.

No i jeszcze te “zmienne globalne a wydajność skryptu”. Srsly, to nie ma znaczenia. A jak bardzo ci na tym zależy, do przekaż je jako argumenty do wizytówki.

A tak tego nie zauwazyłem, uwierz mi stary, wydajność naprawdę nie jest czymś o co musisz się martwić na tym poziomie.

Najładniej było by jakbyś wpakował to wszystko do klasy, to co teraz masz w zmiennych globalnych zmienił na obiektowe i inicjalizował wszystko w initialize

Dodając do tego, co w komentarzach wyżej:

ludzie.each {|osoba|
	wizytowka(tabela, osoba, styl1, styl2, i)
	i += 1
}

Generalnie nie powinno się używać nawiasów klamrowych w wielolinijkowych blokach (w idiomatycznym rubim zapis jest nieco inny). Jeśli chcesz, aby twój kod był napisany w stylu bliższym standardom rubiowym, możesz poczytać jeszcze o tym, gdzie w kodzie spacje być powinny. Sprawdź też indentacje, choć może winne jest po prostu przeklejanie tekstu. To niby małe szczegóły, ale dobrze od początku wpajać sobie dobre nawyki. :smile:

Generalnie, to można to zapisać jako #each_with_index

ludzie.each_with_index {|osoba, i| wizytowka(tabela, osoba, styl1, styl2, i) }