ROUTES

گیرهای روبی

خیلی از تازه‌کارهای Ruby on Rails شیفته‌ی کار کردن با این فریم‌ورک قدرتمند میشن و بدون اطلاع دقیق از زبان روبی شروع به ساخت برنامه‌هاشون باهاش میکنن. و البته که هیچ اشکالی تو این قضیه نیست. مگر اینکه این تازه‌کارها روی روش‌هاشون پافشاری کنن و تبدیل به یک توسعه‌دهنده ارشد بشن، بدون اینکه بازم از زبان روبی اطلاعی داشته باشن.

به‌هرحال، دیر یا زود، تازه‌کارها یا توسعه‌دهنده‌های باتجربه، هر دو به گیرهای روبی برخورد میکنن. پیچیدگی‌های خیلی کوچیکی که توی زبان مخفی هستن و ساعت‌ها دیباگ طاقت‌فرسا آخرش منتهی به «مشکل همین بود؟!!» میشه.

اینجا یک لیست از این گیرهای کوچیک روبی رو گذاشتم که توسعه دهنده‌های روبی باید ازشون مطلع باشن. برای هر مورد یک مثال و راهکار قرار دادم.

and/or مثل &&/|| نیستند

surprise = true and false # => surprise is true
surprise = true && false  # => surprise is false

عادت خوب

همیشه از &&/|| استفاده کنید.

جزئیات

میتونیم مثال اول رو با گذاشتن پرانتز روشن‌تر کنیم، که نشون خواهد داد چطور استفاده از and از && متفاوت هست:

(surprise = true) and false # => surprise is true
surprise = (true && false)  # => surprise is false

eql? مثل == نیست (حتی مشابه equal? و === هم نیست)

1 == 1.0   # => true
1.eql? 1.0 # => false

عادت خوب

فقط از == استفاده کنید

جزئیات

==، ===، eql? و equal? رفتارهای متفاوتی دارن، که برای شرایط و استفاده متفاوت بکار میرن. برای مقایسه‌ی چیزها باید همیشه از == استفاده کنین، مگر اینکه واقعا احتیاج به موارد خاصی داشته باشین (مثل اینکه بخواین واقعا بین 1.0 و 1 تفاوت بزارین) یا اینکه هر کدوم از اینها رو بیاین بازنویسی کنین.

بله، eql? هوشمندتر از == عمل میکنه، ولی آیا این واقعا اون چیزی هست که بهش احتیاج دارین؟

super مشابه super() نیست

class Foo
  def show
    puts 'Foo#show'
  end
end

class Bar < Foo
  def show(text)
    super

    puts text
  end
end

Bar.new.show('test') # ArgumentError: wrong number of arguments (1 for 0)

عادت خوب

این یکی، یکی از مواردی هست که برداشتن پرانتزها نه تنها سلیقه‌ای نیست، بلکه منطق برنامه رو عوض میکنه.

جزئیات

exceptionهای شما نباید Exception باشند

class MyException < Exception
end

begin
  raise MyException
rescue
  puts 'Caught it!'
end

# MyException: MyException
#       from (irb):17
#       from /Users/karol/.rbenv/versions/2.1.0/bin/irb:11:in `<main>'

(در این کد عبارت rescue برای MyException هیچ‌وقت اجرا نمی‌شود و پیام 'Caught it!' هم نمایش داده نخواهد شد)

عادت خوب

جزئیات

class Foo::Bar مثل module Foo; class Bar نیست

MY_SCOPE = 'Global'

module Foo
  MY_SCOPE = 'Foo Module'

  class Bar
    def scope1
      puts MY_SCOPE
    end
  end
end

class Foo::Bar
  def scope2
    puts MY_SCOPE
  end
end

Foo::Bar.new.scope1 # => "Foo Module"
Foo::Bar.new.scope2 # => "Global"

عادت خوب

همیشه از نسخه طولانی‌تر و با جزئیات بیشتر استفاده کنید:

module Foo
  class Bar
  end
end

جزئیات

اکثر متدهای bang! وقتی کاری نمی‌کنن مقدار nil بر می‌گردونن

'foo'.upcase! # => "FOO"
'FOO'.upcase! # => nil

عادت خوب

هیچ‌وقت به خروجی متدهای bang! پیش‌ساخته وابسته نباشین مثلا:

@name.upcase! and render :show

کد بالا میتونه یکسری رفتارهای غیرمنتظره ازش سر بزنه (یا اینکه یک رفتار کاملا قابل انتظار وقتی که @name از قبل uppercase باشه). همینطور این یک مثال دیگه‌اس که نباید از and/or استفاده کنین. هیچ درختی قطع نخواهد شد اگر این دو خط رو اضافه کنید:

@name.upcase!
render :show

متدهای attribute=(value) همیشه مقدار ارسال شده رو به عنوان خروجی برمی‌گردونن

class Foo
  def self.bar=(value)
    @foo = value

    return 'OK'
  end
end

Foo.bar = 3 # => 3

دقت کنید که این متد bar= مقدار 3 رو برمی‌گردونه با اینکه به مشخصا return 'OK' رو استفاده کردیم.

عادت خوب

هیچ‌وقت بر اتفاقاتی که در این نوع متدها میافته وابسته نباشید. برای مثال در عبارت‌های شرطی مثل این:

puts 'Assigned' if (Foo.bar = 3) == 'OK' # => nil

مشخصا این کار نخوهد کرد.

private متدهای self.method رو private نخواهد کرد

class Foo

  private
  def self.bar
    puts 'Not-so-private class method called'
  end

end

Foo.bar # => "Not-so-private class method called"

دقت کنید اگه private بود عبارت Foo.bar خطای NoMethodError بر می‌گردوند.

عادت خوب

برای اینکه متدهای کلاس‌تون رو private کنید باید از private_class_method :method_name استفاده کنین یا اینکه متدهای private رو درون class << self بزارین:

class Foo

  class << self
    private
    def bar
      puts 'Class method called'
    end
  end

  def self.baz
    puts 'Another class method called'
  end
  private_class_method :baz

end

Foo.bar # => NoMethodError: private method `bar' called for Foo:Class
Foo.baz # => NoMethodError: private method `baz' called for Foo:Class

پایان

فهرست بالا در ابتدا شاید چیز خاصی به نظر نیاد، ولی بعدا میاد خرتون رو میگیره. پس بهتره که در موردشون اطلاع داشته باشین. اطلاع داشتن در مورد اینها، ساعت‌ها وقت شما رو برای دیباگ کردن کدها زنده می‌کنه و از سردردهای آتی می‌کاهد :D

(منبع)