ruby — συγκεντρωτικός οδηγός — DedSec Project
ruby — συγκεντρωτικός οδηγός Ruby Έννοια Η Ruby χρησιμοποιεί αντικείμενα, blocks και Enumerable μετασχηματισμούς· η standard library αρκεί για πολλά scripts. Παράδειγμα πηγαίου κώδικα ή…
Ruby
Έννοια
Η Ruby χρησιμοποιεί αντικείμενα, blocks και Enumerable μετασχηματισμούς· η standard library αρκεί για πολλά scripts.
Παράδειγμα πηγαίου κώδικα ή χρήσης
numbers = [1, 2, 3]
puts numbers.select(&:odd?).sum
Άσκηση με συγκεκριμένο στόχο
Πρόβλεψε το άθροισμα περιττών και δοκίμασε κενό array.
Έλεγχος και διάγνωση
Τα methods με ! ακολουθούν σύμβαση, όχι απόλυτο κανόνα ότι μεταβάλλουν δεδομένα.
Σημείωσε την είσοδο, το αναμενόμενο αποτέλεσμα και το πραγματικό αποτέλεσμα στην εγκατεστημένη έκδοση της Ruby. Αν ο κώδικας δεν είναι προσβάσιμος από το κινητό, κράτησε το παράδειγμα ως μη δοκιμασμένο και εξήγησε τη σημασιολογία αντί να ισχυριστείς επιτυχία. Κάνε μια δεύτερη δοκιμή που απομονώνει μόνο τον μηχανισμό της άσκησης και κράτησε ακριβές σφάλμα με τρόπο που να μην εκθέτει προσωπικά δεδομένα.
Ruby — Αναλυτικός οδηγός εξάσκησης
Αναπαραγώγιμα δεδομένα
Δημιούργησε προσωρινό count_names.rb με κενά, διαφορετικά πεζά/κεφαλαία και nil. Η απλή καταμέτρηση χωρίς κανονικοποίηση θα χωρίσει το ίδιο όνομα σε διαφορετικά κλειδιά:
records = [" Ada ", "Lin", nil, "ada", " "]
counts = records.compact.map(&:strip).reject(&:empty?).map(&:downcase).tally
raise "bad counts" unless counts == {"ada" => 2, "lin" => 1}
p counts
Εκτέλεσε ruby count_names.rb. Αναμένονται {"ada"=>2, "lin"=>1}. Το συγκεκριμένο δείγμα ελέγχθηκε και με διαθέσιμο διερμηνευτή Ruby. Η compact αφαιρεί τα nil, η strip κόβει τα εξωτερικά κενά, η reject αποκλείει τις άδειες τιμές και η tally καταμετρά ίσα στοιχεία. Η σειρά των σταδίων έχει σημασία: αν καλούσες strip πριν αφαιρεθούν τα nil, θα υπήρχε σφάλμα.
Μετάλλαξη ή νέα συλλογή
Η map επιστρέφει νέο Array, ενώ η map! μεταβάλλει το ίδιο αντικείμενο. Φτιάξε original = [" Ada "], κάλεσε original.map(&:strip) και διαπίστωσε ότι η αρχική τιμή διατηρεί τα κενά. Κάνε δεύτερο πείραμα με map! σε ανεξάρτητο αντίγραφο. Μην επιλέγεις μετάλλαξη μόνο επειδή φαίνεται συντομότερη: μπορεί να αλλάξει μη αναμενόμενα τα δεδομένα άλλου τμήματος.
Ελεγχόμενη αποτυχία
Αφαίρεσε την compact. Η κλήση strip στο nil πρέπει να δημιουργήσει NoMethodError. Πρόσθεσε έπειτα αριθμό στη λίστα και αποφάσισε αν το πρόγραμμα πρέπει να τον απορρίψει ή να τον μετατρέψει. Το αυθαίρετο to_s μπορεί να κρύψει προβληματική εισαγωγή δεδομένων.
Πρόσθετοι έλεγχοι
Με minitest/autorun γράψε assertions για κανονική λίστα, μόνο κενά στοιχεία (αναμένεται {}), εντελώς άδεια λίστα και όνομα με Unicode. Η downcase δεν λύνει αυτόματα κάθε γλωσσικό κανόνα σύγκρισης Unicode. Κατάγραψε έκδοση Ruby και πραγματικά αποτελέσματα. Αναφορά: https://ruby-doc.org/core/Enumerable.html
Ruby — Παραδείγματα πραγματικού κώδικα
Εκτέλεση των παραδειγμάτων
Τα παραδείγματα είναι μικρά και αυτοτελή. Χρησιμοποίησε τη σχετική εγκατεστημένη γλώσσα. Ενδεικτικά: ruby {file}. Μη συγχέεις τα ονόματα αρχείων με αυτόματη εγκατάσταση. Δούλεψε σε δοκιμαστικό φάκελο.
Ruby — Διαδρομή ουσιαστικής εξάσκησης
Ακριβές ζητούμενο
Διάβασε εγγραφές CSV με αναγνωριστικό, κατηγορία και πλήθος. Κόμματα μέσα σε εισαγωγικά ανήκουν στο ίδιο πεδίο. Το πλήθος πρέπει να είναι μη αρνητικός ακέραιος. Απέρριψε διπλούς κωδικούς, ελλιπή πεδία, αλλαγμένη σειρά επικεφαλίδων και μη ακέραια ή αρνητικά πλήθη. Παρουσίασε ταξινομημένα σύνολα ανά κατηγορία. Ο έλεγχος των δεδομένων δεν απαιτεί να διαβάσεις προσωπικά αρχεία.
Εκτελέσιμο πρόγραμμα Ruby
Αποθήκευσε ως ruby_lab.rb και εκτέλεσε ruby -c ruby_lab.rb και ruby ruby_lab.rb. Χρησιμοποιούνται οι ενσωματωμένες βιβλιοθήκες CSV και StringIO.
require 'csv'
require 'stringio'
def summarize(input)
totals = Hash.new(0)
seen = {}
csv = CSV.new(input, headers: true)
csv.each.with_index(2) do |row, line|
raise ArgumentError, "row #{line}: bad header" unless row.headers == %w[id category count]
raise ArgumentError, "row #{line}: malformed" if row.fields.length != 3 || row.fields.any?(&:nil?)
id, category, count = row.fields
raise ArgumentError, "row #{line}: duplicate/empty ID" if id.empty? || seen.key?(id)
raise ArgumentError, "row #{line}: category" if category.strip.empty?
raise ArgumentError, "row #{line}: count" unless count.match?(/\A(?:0|[1-9][0-9]*)\z/)
seen[id] = true
totals[category] += Integer(count, 10)
end
raise ArgumentError, 'missing or reordered header' unless csv.headers == %w[id category count]
totals.sort.to_h
end
def rejected?(s)
summarize(StringIO.new(s))
false
rescue ArgumentError, CSV::MalformedCSVError
true
end
sample = "id,category,count\na1,\"red,green\",2\na2,blue,3\n"
raise unless summarize(StringIO.new(sample)) == { 'blue' => 3, 'red,green' => 2 }
raise unless summarize(StringIO.new("id,category,count\n")) == {}
[
"id,category,count\na1,blue,-1\n",
"id,category,count\na1,blue,2\na1,blue,3\n",
"id,category,count\na1,blue,2.0\n",
"id,category,count\na1,blue\n",
"id,category,count\na1,,2\n",
"category,id,count\nblue,a1,2\n"
].each { |fixture| raise "bad fixture accepted: #{fixture}" unless rejected?(fixture) }
original = %w[beta alpha]
result = original.map(&:upcase)
raise if original != %w[beta alpha] || result != %w[BETA ALPHA]
puts 'PASS: CSV, duplicate IDs, strict counts, non-mutating Enumerable'
Ιδιαιτερότητες που πρέπει να κατανοήσεις
Η CSV.new υποστηρίζει διαδοχική επεξεργασία γραμμών αντί να φορτώνει όλο το αρχείο. Η Hash.new(0) επιστρέφει αρχικό μηδέν όταν αθροίζουμε, αλλά δεν νομιμοποιεί κενά ονόματα κατηγοριών. Ο πίνακας seen επιτρέπει τον έλεγχο διπλών κωδικών, όμως αυξάνει τη χρήση μνήμης. Η Integer(count,10) ακολουθεί τον αυστηρό έλεγχο μορφής ώστε τα 2.0 και -1 να μην γίνονται αποδεκτά. Η map επιστρέφει νέο πίνακα, ενώ η map! αλλάζει τον αρχικό. Το παράδειγμα ελέγχει αυτήν τη διαφορά στην πράξη.
Ελεγχόμενες ασκήσεις
- Πρόσθεσε αλλαγή γραμμής μέσα σε κατηγορία με εισαγωγικά και σύγκρινε λογικές εγγραφές με φυσικές γραμμές.
- Επανάλαβε τις έξι αποτυχίες, μετά δοκίμασε κενό αρχείο με έγκυρες επικεφαλίδες και έλεγξε το κενό αποτέλεσμα.
- Ανάλυσε 100.000 τεχνητές εγγραφές μέσω CSV.foreach και σύγκρινε τη μνήμη με CSV.read. Εξήγησε γιατί το seen συνεχίζει να μεγαλώνει.
- Αντικατάστησε προσωρινά τη map με map! και παρατήρησε τη μεταβολή του αρχικού πίνακα. Επανέφερε τον μη καταστροφικό χειρισμό.
Παραδοτέα: συντακτικός έλεγχος, PASS, έξι καταγεγραμμένες απορρίψεις, ταξινομημένο αποτέλεσμα και εξήγηση του κόστους μνήμης.
Ruby — Τεχνικά σημεία και συχνές παγίδες
Τεχνική γνώση
- Τα blocks είναι βασικό εργαλείο για επαναλήψεις και διαχείριση πόρων.
- Τα symbols διαφέρουν από strings· ξεχώρισε μεταβαλλόμενα αντικείμενα.
- Μην κρύβεις εξαιρέσεις που ο καλών πρέπει να χειριστεί.