zip กับชื่อ path ภาษาไทย โดยใช้ rubyzip

ผมได้รับไฟล์ .zip มา ก็ดีใจว่าอย่างน้อย ๆ ก็ใช่ไม่ .rar ที่เวลาเปิดจะลำบากขึ้นไปอีก

สมัยผมหนุ่ม ๆ เขาตั้งเชื่อไฟล์กันได้ 8 ตัวอักษาและ extension อีก 3 ตัว นอกจากนั้นก็ยังใส่ภาษาไทยไม่ได้ เดี๋ยวนี้ไม่ ใส่ภาษาไทย ใส่ช่องว่างได้หมด งานก็เข้าอีก

โปรแกรมแตกไฟล์ zip บางตัวมันก็ไม่สนใจภาษาไทยเลย อ่านแบบคิดว่าเป็น ASCII แบบ 8 bit ตลอด ๆ  ผมก็เลยลองเอา rubyzip มาเล่นดู แล้ว encode ชื่อไฟล์ใหม่เป็น UTF-8 ก็พบว่าเจ้ง เพราะว่าบางทีชื่อไฟล์ก็ไม่ใช่ UTF-8

เลยเปลี่ยนมาใช้ TIS-620 ก่อนแล้วแปลงเป็น UTF-8 อีกที ก็อ่านได้เพิ่มขึ้น แต่ก็ยังมีตัวอักษรบางตัวแปลงไม่ได้

จึงเปลี่ยนจาก TIS-620 มาใช้ Windows 874 แทน ก็ยังมีปัญหาเหลืออีกคือบางทีชื่อไฟล์เป็น UTF-8 อยู่แล้ว ก็เลยต้องมาเขียน check ก่อน


require 'zip'

def decode_path_name(name)
  if name.force_encoding("UTF-8").valid_encoding?
    name.force_encoding("UTF-8")
  else
    name.force_encoding("WINDOWS-874").encode("UTF-8")
  end
end

Zip::File.open(ARGV[0]) do |zip_file|  
  zip_file.each do |entry|
    name = decode_path_name(entry.name)
    entry.extract(name)
  end
end

พอจัดไปครบตามนี้ก็พบว่าแตกได้ทุกไฟล์แล้ว

 

Ruby + MySQL จาก Macports

ผมใช้ ruby จาก rvm ไม่ได้ลงจาก macports ( อาจจะไม่เกี่ยวอะไรเลย ) แล้วก็ gem install ruby-mysql

ทีนี้ใน code ผมเขียนประมาณว่า


db = Mysql.connect('localhost', 'root', 'mypass', 'mydb')

แค่นี้เองพอ run แล้วเจ๊งเลยขึ้นแบบนี้ … gems/ruby-mysql-2.9.13/lib/mysql/protocol.rb:150: in`initialize’: No such file or directory – connect(2) for “/tmp/mysql.sock” (Errno::ENOENT)

แต่อันนี้ก็ทำนองว่าเจอบ่อยแล้ว mysql ที่ลงจาก macports ไม่ได้ใช้ไฟล์นั้นผมก็เลยลองเข้าไปดูไฟล์ protocol.rb ก็มีท่าแก้แบบนี้

MYSQL_UNIX_PORT=/opt/local/var/run/mysql5/mysqld.sock ruby my_prog.rb

ใช้ได้เลย

Ruby – return

เรื่องหนึ่งอาจจะยากที่สุดเวลาเขียน Ruby สำหรับคนที่เขียน Java มาก่อนอาจจะเป็นเรื่อง return

ผมว่าดูตัวอย่างพวกนี้แล้วก็จะเข้าใจได้ไม่ยาก

เหมือนกัน


def func1
  return 10
end

def func1
  10
end

ไม่แน่ใจว่าเหมือนกันไหมแต่ return ค่าเดียวกัน


def func2 a
  if a > 100
    return 10
  else
    return 20
  end
end

def func2 a
  if a > 100
    10
  else
    20
  end
end

แต่ถ้ามันมีหลาย ๆ คำสั่ง มันก็จะเอาคำสั่งสุดท้าย แบบข้างล่างนี่ก็จะได้ผลเหมือนกัน

def func3
  func4(10)
  return func5(20)
end

def func3 a
  func4(10)
  func5(20)
end

มีคนถามว่าแล้วจะมี return ไปทำไม มีคนตอบว่ามันทำให้ function หยุดตรงกลางได้ เช่น

แบบข้างล่างถ้า a = 101 มันก็จะ return 20 แล้วก็ไม่ไปทำ puts ข้างล่าง

def func6 a
  if a > 100
    return 20
  end
  puts 30
  puts 40
  50
end

ปกติแล้วเวลาเขียน Ruby เราต้องติดเสมอว่าจะ return อะไร

… ถ้ามั่วก็ขออภัย

ป.ล. ท่าพวกนี้ Ruby น่าจะได้มาจาก Scheme แต Scheme จะเขียนหลาย ๆ คำสั่งต่อกันเลยไม่ได้ ต้องมีบางทีต้องไปอยู่ใน (begin ) … แต่ช่างเถอะ😛

ผมเขียน Ruby แล้วติดว่า JSON parser มันช้า วิธีแก้คือใช้ yajl-ruby