היום למדתי: ההבדל בין File.read ל IO.read ברובי

24/09/2024

הרבה זמן חשבתי שבגלל ש File יורש מ IO, אין שום בעיה לקרוא ל File.read או ל IO.read ותמיד מקבלים אותה תוצאה. מבחן הניסיון גם הראה לי תמיד שאני צודק לדוגמה:

3.1.1 :003 > File.read('/etc/shells')
 => "# List of acceptable shells for chpass(1).\n# Ftpd will not allow users to connect who are not using\n# one of these shells.\n\n/bin/bash\n/bin/csh\n/bin/dash\n/bin/ksh\n/bin/sh\n/bin/tcsh\n/bin/zsh\n/usr/local/bin/pwsh\n/usr/local/bin/bash\n/usr/local/bin/zsh\n"
3.1.1 :004 > IO.read('/etc/shells')

 => "# List of acceptable shells for chpass(1).\n# Ftpd will not allow users to connect who are not using\n# one of these shells.\n\n/bin/bash\n/bin/csh\n/bin/dash\n/bin/ksh\n/bin/sh\n/bin/tcsh\n/bin/zsh\n/usr/local/bin/pwsh\n/usr/local/bin/bash\n/usr/local/bin/zsh\n"

אז למה בכל זאת רובוקופ התרגז עליי כשכתבתי IO.read? מסתבר של IO.read יש פונקציונאליות נסתרת - אם נפעיל אותו עם קו אנכי ואחריו שם של פקודה, הוא יפעיל את הפקודה וייתן לנו גישה לפלט שלה, לדוגמה:

3.1.1 :007 > IO.read('|whoami')
 => "ynonp\n"

3.1.1 :008 > File.read('|whoami')
(irb):8:in `read': No such file or directory @ rb_sysopen - |whoami (Errno::ENOENT)
        from (irb):8:in `<main>'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/bin/irb:25:in `load'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/bin/irb:25:in `<main>'

בעולם האמיתי אף פעם אי אפשר לדעת מאיפה הגיע שם הקובץ אותו רוצים לפתוח, ולכן כשהמטרה היא לפתוח קובץ תמיד נעדיף להשתמש בפונקציה שלא תוכל להריץ תוכנית בטעות.