Skip to content

Latest commit

 

History

History
4333 lines (3434 loc) · 120 KB

README-EgAr.md

File metadata and controls

4333 lines (3434 loc) · 120 KB

مقدمة

وجود مثل أعلي مهم
-- أليكس ج. ميرفي / روبوكب

شئ كان دايما بيضايقني ك روبي ديفيلوبر—مطورين البايثون عندهم مرجع عظيم لطريقة كتابة الكود (راجع ستايل البايثون) و احنا مش عندنا واحد رسمي زيه يوثق طريقة الكتابة بالروبي و افضل التطبيقات. و انا مؤمن جدا ان دا حاجة مهمة , و ايضا مؤمن ان مجتمع عظيم زي بتاع الروبي لازم يكون قادر يطلع ستايل زي ده.

المرجع او الدليل دا ابتدا ك مرجع داخلي خاص لشركتنا دليل البرمجة بالروبي (اتكتب عشانك بجد). في لحظة كدا قررت ان اللي انا بعمله دا ممكن ناس كتيرة من مجتمع الروبي تهتم بيه عامة , و ان العالم في احتياج اقل ل توجيه داخلي اخر لشركة . بس بكل تأكيد العالم هيستنفع من اللي هنقدر نسجله و نتوصل ايه من تطبيقات و ممارسات تسهل كتابة لغة الروبي

من ساعة ما بدأت الدليلل دا و انا بيجيلي رد فعل من اعضاء مجتمع الروبي من جميع انحاء العالم. الفضل ل كل الاقتراحات و الدعم! مع بعض هنقدر نعمل مصدر مفيد لكل مطزر بلغة الروبي.

علي فكرة لو انت شغال رايلز برضه ممكن تحتاج تبص بصة علي دليل أسلوب الروبي اون رايلز.

دليل أسلوب كتابة الروبي

الدليل دا بيقترح عليك افضل التطبيقات عشان مبرمج الروبي الحقيقي يقدر يكتب حاجة مبرمج روبي حقيقي تاني يقدر يعدل عليها دليل بيعكس الاستخدام بتاعه في العالم الحقيقي , في حين ان الدليل المتمسك بالمثالية بيترفض من الناس , و هو المفروض يساعد علي التخلص من المشاكل نهائيا بغض النظر هو كويس اد ايه .

الدليل دا متقسم ل اجزاء ليها علاقة ببعض . و انا حاولت اضيف المنطق علي القواعد (لو حاجة منها اهملت ف انا حاطط افتراض انها واضحة)

انا مجبتش القواعد دي من عندي, هم غالبا مستندين علي حياتي المهنية ك مهندس برمجيات محترف و الاقتراحات و الاراء من اعضاء مجتمع الروبي و مصادر محترمة ل برمجة الروبي مثل :- "Programming Ruby" و "The Ruby Programming Language".

في بعض النواحي مبتلاقيش توافق واضح للاراء في مجتمع الروبي بالنسبة لاسلوب معين (زي طريقة تعريف السترينج, المسافات اللي جوا الهاش, مكان النقطة في تسلسل الدوال, الخ .. ) في الحالات اللي زي دي يتم التعريف بجميع الانماط المشهورة و يسيبك براحتك تطبق اللي تحبه .

الدليل دا بيتطور علي طول مع الوقت ,عشان عرف جديد بيتحط او واحد قديم يتشال عشان تغير بيحصل في لغة الروبي نفسها

كتير من المشاريع عندهم دليل كتابة كود خاص بيهم (غالبا بيكون مشتق من الدليل دا). في حالة وجود اي خلاف فان الاولوية تكون للدليل دا.

ممكن تعمل نسخة من الدليل PDF او HTML باستخدام Pandoc.

و دا يقدر يحلل الكود بتاعك , بناء علي الدليل دا RuboCop .

الترجمات المتاحة للدليل دا موجودة بالغات دي :-

المحتويات

نموذج السورس كود

تقريبا كل واحد شايف ان كل الستيلات معفنة و متتقريش معادا بتاعهم , شيل كدا "بتاعهم" . تقريبا كدا هم صح

تقريبا كل واحد شايف ان كل الستيلات معفنة و متتقريش معادا بتاعهم , شيل كدا "بتاعهم" تقريبا كدا هم صح...
-- جيري كوفين

  • استخدم UTF-8 لل انكودين بتاع فايل الكود بتاعك. [link]

  • استخدم مسافتين لكل مستوي ف كودك (زي السوفت تاب) مستخدمش هارد تاب [link]

    # سئ - اربع مسافات
    def some_method
        do_something
    end
    
    # جيد
    def some_method
      do_something
    end
  • استخدم ستايل اليونكس في نهاية السطور. (*BSD/Solaris/Linux/macOS مستخدمين نظم التشغيل دول عنهم بشكل افتراضي , الويندوز يوزر بس هو اللي محتاج ياخد باله.) [link]

    • لو انت بتستخدم ال جيت ف ممكن تكون محتاج تحط تعريف لحماية مشروعك من نهاية السطور في نظام الويندوز:

      $ git config --global core.autocrlf true
  • متسدخدمش ; عشان تفرق بين الستاتمينت و للتانية استخدم ستاتمينت واحدة في السطر [link]

    # سئ
    puts 'foobar'; # فاصلة منقوطة ملهاش لازمة
    
    puts 'foo'; puts 'bar' # اتنين اكسبريشن في سطر واحد
    
    # جيد
    puts 'foobar'
    
    puts 'foo'
    puts 'bar'
    
    puts 'foo', 'bar' # دا وضع خاص بس
  • يفضل تعريف الكلاس اللي منغير محتوي في سطر واحد. [link]

    # سئ
    class FooError < StandardError
    end
    
    # شغال
    class FooError < StandardError; end
    
    # جيد
    FooError = Class.new(StandardError)
  • بلاش تكتب دالة في سطر واحد, مع انها مشهورة عامة في شوية خوصيات في السينتاكس بتاعها بتخلي استخدامها غير مرغوب فيه علي اي حال مينفعش يبقي في اكتر من اكسبرشن ف سطر واحد في الدالة بتاعتك [link]

    # سئ
    def too_much; something; something_else; end
    
    # شغال - لاحظ ان اول ; ضرورية
    def no_braces_method; body end
    
    # شغال - لاحظ ان تاني ;  اختيارية
    def no_braces_method; body; end
    
    # شغال - بس منغير ;  بتبقي صعب تقراه
    def some_method() body end
    
    # جيد
    def some_method
      body
    end

    استثناء وحيد للقاعدة و هي الدالة الفاضية

    # جيد
    def no_op; end
  • استخدم المسافات جوالين ال فواصل و النقطتان و الفواصل المنقوطة ممكن يكون المسافات (او غالبا) ملهاش علاقة بمترجم الروبي . بس الهدف الاساسي منه كتابة كود سهل القراية [link]

    sum = 1 + 2
    a, b = 1, 2
    class FooError < StandardError; end

    في بعض الاستثنائات منها علامة الأس:

    # سئ
    e = M * c ** 2
    
    # جيد
    e = M * c**2

    استثناء اخر عشان الجذر:

    # سئ
    o_scale = 1 / 48r
    
    # جيد
    o_scale = 1/48r
  • مفيش مسافات بعد (, [ او بعد ], ). Use spaces around { and before }. [link]

    # سئ
    some( arg ).other
    [ 1, 2, 3 ].each{|e| puts e}
    
    # جيد
    some(arg).other
    [1, 2, 3].each { |e| puts e }

    { و } محتاجين بعض التوضيح خاصة اننا بنستخدمه للهاش و البلوك و السترينج

    في الهاش الطريقتين يعتبروا مقبولين. بس الطريقة الاولي اوضح شوية (و اكتر شعبية و استخداما في مجتمع الروبي عامة). انما الطريقة التانية ميزيتها انها بتعمل فرق مرئي لشكل الهاش و البلوك . ايا يكن الطريقة اللي هتخترها استخدمها باتساق.

    # جيد - مسافة بعد { و قبل  }
    { one: 1, two: 2 }
    
    # جيد - مفيش مسافة قبل  { و بعد }
    {one: 1, two: 2}

    مع استخدامها جوا السترينج, متسيبش مسافة فاضية من جوا .

    # سئ
    "From: #{ user.first_name }, #{ user.last_name }"
    
    # جيد
    "From: #{user.first_name}, #{user.last_name}"
  • متسيبش مسافة بعد !. [link]

    # سئ
    ! something
    
    # جيد
    !something
  • مفيش مسافات جوا تعريف الراينج. [link]

    # سئ
    1 .. 3
    'a' ... 'z'
    
    # جيد
    1..3
    'a'...'z'
  • خلي when و case. الاتتنين علي نفس المستوي دا اللي موجود في كتابين "The Ruby Programming Language" و "Programming Ruby". [link]

    # سئ
    case
      when song.name == 'Misty'
        puts 'Not again!'
      when song.duration > 120
        puts 'Too long!'
      when Time.now.hour > 21
        puts "It's too late"
      else
        song.play
    end
    
    # جيد
    case
    when song.name == 'Misty'
      puts 'Not again!'
    when song.duration > 120
      puts 'Too long!'
    when Time.now.hour > 21
      puts "It's too late"
    else
      song.play
    end
  • لما تيجي تحط ناتج الكونداشن بتاعك في متغير , حافظ عليهم بحيث يكونوا في نفس البرانش. [link]

    # سئ - معقد شوية
    kind = case year
    when 1850..1889 then 'Blues'
    when 1890..1909 then 'Ragtime'
    when 1910..1929 then 'New Orleans Jazz'
    when 1930..1939 then 'Swing'
    when 1940..1950 then 'Bebop'
    else 'Jazz'
    end
    
    result = if some_cond
      calc_something
    else
      calc_something_else
    end
    
    # جيد - واضح اووي ايه اللي بيحصل
    kind = case year
           when 1850..1889 then 'Blues'
           when 1890..1909 then 'Ragtime'
           when 1910..1929 then 'New Orleans Jazz'
           when 1930..1939 then 'Swing'
           when 1940..1950 then 'Bebop'
           else 'Jazz'
           end
    
    result = if some_cond
               calc_something
             else
               calc_something_else
             end
    
    # جيد (اكثر كفاءة في الشكل)
    kind =
      case year
      when 1850..1889 then 'Blues'
      when 1890..1909 then 'Ragtime'
      when 1910..1929 then 'New Orleans Jazz'
      when 1930..1939 then 'Swing'
      when 1940..1950 then 'Bebop'
      else 'Jazz'
      end
    
    result =
      if some_cond
        calc_something
      else
        calc_something_else
      end
  • Use empty lines between method definitions and also to break up methods into logical paragraphs internally. [link]

    def some_method
      data = initialize(options)
    
      data.manipulate!
    
      data.result
    end
    
    def some_method
      result
    end
  • متحطش كذا سطر فاضي ورا بعض. [link]

    # سئ - فيها سطرين فاضيين.
    some_method
    
    
    some_method
    
    # جيد
    some_method
    
    some_method
  • حط سطر فاضي بعد الاكسيس موديفاير. [link]

    # bad
    class Foo
      attr_reader :foo
      def foo
        # do something...
      end
    end
    
    # good
    class Foo
      attr_reader :foo
    
      def foo
        # do something...
      end
    end
  • متحطش سطور فاضية حوالين الدوال و الكلاسيس و الموديول . [link]

    # سئ
    class Foo
    
      def foo
    
        begin
    
          do_something do
    
            something
    
          end
    
        rescue
    
          something
    
        end
    
      end
    
    end
    
    # جيد
    class Foo
      def foo
        begin
          do_something do
            something
          end
        rescue
          something
        end
      end
    end
  • لما تيجي تستخدم دالة متحطش اخر فاصلة ,خاصة لما يكون الباراميتيرز بتوعها مش علي خطوط منفصلة [link]

    # سئ - اسهل ل تحريك/اضافة/ازالة باراميتير, بس برضه مش احسن حاجة
    some_method(
      size,
      count,
      color,
    )
    
    # سئ
    some_method(size, count, color, )
    
    # جيد
    some_method(size, count, color)
  • حط مسافات حوالين علامة = لما تيجي تحط قيمة افتراضية للبراميتيرز : [link]

    # سئ
    def some_method(arg1=:default, arg2=nil, arg3=[])
      # do something...
    end
    
    # جيد
    def some_method(arg1 = :default, arg2 = nil, arg3 = [])
      # do something...
    end

    في حين ان بعض الكتب بتقترح الطريقة الاولي, التاني احسن في الاستخدام (تقدر تقول كدا مقري اكتر).

  • متكملش في سطر جديد لو انت مش محتاج كدا \ عمليا متكملش في سطر جديد الا لو محتاج كدا في سترانج مثلا [link]

    # سئ
    result = 1 - \
             2
    
    # جيد (بس شكلها وحش زي الزفت)
    result = 1 \
             - 2
    
    long_string = 'First part of the long string' \
                  ' and second part of the long string'
  • عشان تنسق تسلسل الدوال متعدد السطور. There are two popular في طريقتين مشهورين في مجتمع الروبي, و الاتنين يعتبروا كويسين—قدام . (الاختيار أ) و تابعة . (الاختيار ب). [link]

    • (الاختيار أ) لما تيجي تستخدم التسلسل في سطر جديد سيب ال. في السطر التاني.

      # سئ - محتاج تراجع السطر الاول عشان تفهم السطر التاني.
      one.two.three.
        four
      
      # جيد - انت فاهم كويس ايه اللي بيحصل في السطر التاني.
      one.two.three
        .four
    • (الاختيار ب) لما تيجي تستخدم التسلسل في سطر جديد سيب ال. في السطر الاول عشان يبقي فاهم ان في تكملة تحت.

      # سئ - انت محتاج توصل للسطر التاني عشان تفهم ان لسة التسلسل مخلصش .
      one.two.three
        .four
      
      # جيد - واضحة اووي من السطر الاول ان لسة في تكملة .
      one.two.three.
        four

    هتلاقي مناقشة هنا فيها المزايا بتاعت الطريقتين here.

  • حاذي علي بارامتر الدالة لو هياخدوا اكتر من سطر. لما تيجي تحاذيهم و ميبقوش مناسبين عشان كول السطر , حط واحد بس ف كل سطر و مقبول برضه لو بعد اول واحد [link]

    # نقطة البداية (السطر طويل اوي)
    def send_mail(source)
      Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)
    end
    
    # سئ (مزدوج المسافة)
    def send_mail(source)
      Mailer.deliver(
          to: 'bob@example.com',
          from: 'us@example.com',
          subject: 'Important message',
          body: source.text)
    end
    
    # جيد
    def send_mail(source)
      Mailer.deliver(to: 'bob@example.com',
                     from: 'us@example.com',
                     subject: 'Important message',
                     body: source.text)
    end
    
    # جيد - (مسافة عادية)
    def send_mail(source)
      Mailer.deliver(
        to: 'bob@example.com',
        from: 'us@example.com',
        subject: 'Important message',
        body: source.text
      )
    end
  • حاذي عناصر الاراي اللي بتاخد اكتر من سطر . [link]

    # سئ - مسافة البداية
    menu_item = ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
      'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
    
    # جيد
    menu_item = [
      'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
      'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam'
    ]
    
    # جيد
    menu_item =
      ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
       'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
  • حط اندرسكور ل الارقام الكبيرة عشان نعرف نقراها. [link]

    # سئ - في كام صفر موجود ؟
    num = 1000000
    
    # جيد - كدا مخك يقدر يفهمها
    num = 1_000_000
  • بيفضل تخلي الحروف سمول لما تستخدم الحروف الرقمية.

    0o ل الاوكتل , 0x لل الهيكساديسيمل و 0b لل بيناري. متستخدمش ال 0d في او الدسيمال . [link]

    # سئ
    num = 01234
    num = 0O1234
    num = 0X12AB
    num = 0B10101
    num = 0D1234
    num = 0d1234
    
    # جيد - اسهل عشان تفصل الارقام من البداية
    num = 0o1234
    num = 0x12AB
    num = 0b10101
    num = 1234
  • استخدم Rdoc و طريقيتها في شرح او توثيق ال API. متسيبش سطر فاضي بين ال كومنت بلوك و ال def. [link]

  • اخرك في السطر 80 رمز [link]

  • تجنب المسافات الزيادة اللي ملهاش لازمة [link]

  • في نهاية كل صفحة حط سطر فاضي. [link]

  • متستخدمش البلوك كومنت. مبتتسبقش بمسافة و مش سهل تتفهم زي الكومنتات العادية. [link]

    # سئ
    =begin
    comment line
    another comment line
    =end
    
    # جيد
    # comment line
    # another comment line

تركيب الجملة

  • استخدم :: ك مرجع للثوابت (زي الكلاسيس و الموديل) و برضه (زي Array() او Nokogiri::HTML()). متستخدمش :: لل الدوال العادية . [link]

    # سئ
    SomeClass::some_method
    some_object::some_method
    
    # جيد
    SomeClass.some_method
    some_object.some_method
    SomeModule::SomeClass::SOME_CONST
    SomeModule::SomeClass()
  • استخدم def ب اقواس لما تكون بتاخد براميتيرز. و شيلهم لو هي مش بتاخد حاجة. [link]

    # سئ
    def some_method()
      # اللي جوا اتشال
    end
    
    # جيد
    def some_method
      # اللي جوا اتشال
    end
    
    # سئ
    def some_method_with_parameters param1, param2
      # اللي جوا اتشال
    end
    
    # جيد
    def some_method_with_parameters(param1, param2)
      # اللي جوا اتشال
    end
  • استخدم الاقواس حوالين الارجيومنت الدوال المستعاه خاصة لو اول ارجيومنت بيبدا ب قوس مفتوح ), زي هنا f((3 + 2) + 1). [link]

    # سئ
    x = Math.sin y
    # جيد
    x = Math.sin(y)
    
    # سئ
    array.delete e
    # جيد
    array.delete(e)
    
    # سئ
    temperance = Person.new 'Temperance', 30
    # جيد
    temperance = Person.new('Temperance', 30)

    دايما شيل الاقواس في الحالات دي

    • دالة مش بتاخد ارجيومنت:

      # سئ
      Kernel.exit!()
      2.even?()
      fork()
      'test'.upcase()
      
      # جيد
      Kernel.exit!
      2.even?
      fork
      'test'.upcase
    • دوال هم جزي من DSL الداخلي (زي ال, Rake, Rails, RSpec):

      # سئ
      validates(:name, presence: true)
      # جيد
      validates :name, presence: true
    • الدوال الي ليها صفة "الكلمة" في الروبي:

      class Person
        # سئ
        attr_reader(:name, :age)
        # جيد
        attr_reader :name, :age
      
        # شلنا باقي الكلاس
      end

    ممكن نشيل الاقواس ل

    • الدوال الي ليها صفة "الكلمة" في الروبي, بس تكون مش معبرة:

      # جيد
      puts(temperance.age)
      system('ls')
      # برضه جيد
      puts temperance.age
      system 'ls'
  • عرف الارجيومنت الاختيارية في النهاية. الروبي عندها شويه نتايج غير متوقعة لما تيجي تنادي دوال و يكون عندها ارجيومنت اختيارية في النص. [link]

    # سئ
    def some_method(a = 1, b = 2, c, d)
      puts "#{a}, #{b}, #{c}, #{d}"
    end
    
    some_method('w', 'x') # => '1, 2, w, x'
    some_method('w', 'x', 'y') # => 'w, 2, x, y'
    some_method('w', 'x', 'y', 'z') # => 'w, x, y, z'
    
    # جيد
    def some_method(c, d, a = 1, b = 2)
      puts "#{a}, #{b}, #{c}, #{d}"
    end
    
    some_method('w', 'x') # => '1, 2, w, x'
    some_method('w', 'x', 'y') # => 'y, 2, w, x'
    some_method('w', 'x', 'y', 'z') # => 'y, z, w, x'
  • تحجنب التعريف المتوازي للمتغيرات. هو بيبقي مسموح في حالة القيمة راجعة من دالة . استخدمه مع علامة النجمة , او تبديل قيم المتغيرات من الاخر هو صعب يتقري مش زي اما تعرف كل حاجة لوحدها [link]

    # سئ
    a, b, c, d = 'foo', 'bar', 'baz', 'foobar'
    
    # جيد
    a = 'foo'
    b = 'bar'
    c = 'baz'
    d = 'foobar'
    
    # جيد - استبدال قيم المتغيرات
    # استبدال قيم المتغيرات حالة خاصة , عشان هتسمحلك
    # انك تغير القيم بتاعت كل متغير.
    a = 'foo'
    b = 'bar'
    
    a, b = b, a
    puts a # => 'bar'
    puts b # => 'foo'
    
    # جيد - اللي الدالة بترجعه
    def multi_return
      [1, 2]
    end
    
    first, second = multi_return
    
    # جيد - بيستخدم علامة النجمة
    first, *list = [1, 2, 3, 4] # first => 1, list => [2, 3, 4]
    
    hello_array = *'Hello' # => ["Hello"]
    
    a = *(1..3) # => [1, 2, 3]
  • تجنب استخدام اسامي الاندرسكور في المتغيرات خلال ال التعريف الموازي . التسمية المتغيرات بالاندرس سكور بيبقي مفضل عشان السياق اللي بتوفره . هي بتبقي مهمة لما بيكون في متغير من سبلات و متعرف علي شمال التعريف. المتغير من نوع سبلات مش بيكون اندر سكور [link]

    # سئ
    foo = 'one,two,three,four,five'
    # تعريف عديم النفع بيقول معلمات مش مهمة
    first, second, _ = foo.split(',')
    first, _, _ = foo.split(',')
    first, *_ = foo.split(',')
    
    
    # جيد
    foo = 'one,two,three,four,five'
    # لاندر سكور مهم عشان يوضحلك انك محتاجهم كلهم
    # معادا اخر واحد اللي هو اندرسكور
    *beginning, _ = foo.split(',')
    *beginning, something, _ = foo.split(',')
    
    a, = foo.split(',')
    a, b, = foo.split(',')
    # تعريف غير مهم ل متغير غير مستخدم , بس التعريف دا
    # بيوفر معلومات مهمة.
    first, _second = foo.split(',')
    first, _second, = foo.split(',')
    first, *_ending = foo.split(',')
  • مستخدمش for لحد ما تعرف السبب بالظبط . اغلب الوقت حاجات كتير المفروض تستخدمها بدلها . for اتعملت علي طراز ال each (كدا انت بتعمل مستوي جديد غير مباشر), الفكرة كلها ان ال for مبتعملش سكوب جديد, بمعني الفاريبال اللي هتعملها جوه هتتشاف برا عادي. [link]

    arr = [1, 2, 3]
    
    # سئ
    for elem in arr do
      puts elem
    end
    
    # لاحظ هنا elem  بيستخدموها برا اللوب عادي .
    elem # => 3
    
    # جيد
    arr.each { |elem| puts elem }
    
    # هنا بقي متقدرش تستخدم elem برا البلوك
    elem # => NameError: undefined local variable or method `elem'
  • متستخدمش then لبلوك متعددة السطورif/unless. [link]

    # سئ
    if some_condition then
      # اللي هنا اتشال
    end
    
    # جيد
    if some_condition
      # اللي هنا اتشال
    end
  • حط دايما الشرط بتاع if/unless علي نفس السطر. في حالات تعدد سطور الكوندشن [link]

    # سئ
    if
      some_condition
      do_something
      do_something_else
    end
    
    # جيد
    if some_condition
      do_something
      do_something_else
    end
  • بيفضل استخدام علامات ال (:?) عن if/then/else/end. عشان هي اكتر انتشارا و واضحة اكتر . [link]

    # سئ
    result = if some_condition then something else something_else end
    
    # جيد
    result = some_condition ? something : something_else
  • متكتبش اكتر من واحدة في نفس السطر . فيما معناه مينفعش تكتب واحدة و جواها واحدة تانية . في الحالة دي بيفضل تعملها ب if/else . [link]

    # سئ
    some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
    
    # جيد
    if some_condition
      nested_condition ? nested_something : nested_something_else
    else
      something_else
    end
  • متعملش if x; .... استخدم بدالهم علامة الترناري. [link]

    # سئ
    result = if some_condition; something else something_else end
    
    # جيد
    result = some_condition ? something : something_else
  • استفيد من ان if و case بيرجعوا الناتج . [link]

    # سئ
    if condition
      result = x
    else
      result = y
    end
    
    # جيد
    result =
      if condition
        x
      else
        y
      end
  • استخدم when x then ... في حالات السطر الواحد . عشان الطريقة المختلفة بتاعت when x:... اتشالت من الروبي نسخة 1.9 . [link]

  • متستخدمش when x; .... بص علي القاعدة اللي فاتت . [link]

  • استخدم ! بدل not . [link]

    # سئ - عشان اولوية الاقواس.
    x = (not something)
    
    # جيد
    x = !something
  • تجنب استخدام !!. [link] !! بتحول القيمة ل بوليان, بس انت مش محتاج الكلام دا في الكوندشن. لو عاوز تتاكد من ان قيمتها nil استخدم nil?

    # سئ
    x = 'test'
    # طريقة تاكيد غير واضحة
    if !!x
      # اللي هنا اتشال
    end
    
    # جيد
    x = 'test'
    if x
      # اللي هنا اتشال
    end
  • علامتين ال and و or محظور استخدامهم . هي بتضيف قابلية بسيطة علي قرايه اسهل بس بتبقي سبب لوجود اخطاء برمجية . في البوليان اكسبريشنز دايما يفضل تستخدم && و || بدلهم . استخدام if و unless; && و || مقبولين برضه بس مش واضحين اووي . [link]

    # سئ
    # boolean expression
    ok = got_needed_arguments and arguments_are_valid
    
    # control flow
    document.save or fail(RuntimeError, "Failed to save document!")
    
    # جيد
    # boolean expression
    ok = got_needed_arguments && arguments_are_valid
    
    # control flow
    fail(RuntimeError, "Failed to save document!") unless document.save
    
    # تمام
    # control flow
    document.save || fail(RuntimeError, "Failed to save document!")
  • تجنب استخدام اكتر من سطر مع ?: (the ternary operator); استخدم if/unless بدالهم . [link]

  • بيفضل استخدام if/unless لما تكون هتعملها في سطر واحد . برضه حل تاني مختلف انك تستخدم &&/||. [link]

    # سئ
    if some_condition
      do_something
    end
    
    # جيد
    do_something if some_condition
    
    # حل تاني كويس
    some_condition && do_something
  • ابعد عن استخدام if/unless في اخر البلوك اللي بيتكون من اكتر من سطر . [link]

    # سئ
    10.times do
      # multi-line body omitted
    end if some_condition
    
    # جيد
    if some_condition
      10.times do
        # multi-line body omitted
      end
    end
  • بلاش تعمل if/unless/while/until جوا بعض . يفضل &&/|| لو هينفع يعني . [link]

    # سئ
    do_something if other_condition if some_condition
    
    # جيد
    do_something if some_condition && other_condition
  • استخدم unless احسن من if لو بتتاكد من الحالة غلط . [link]

    # سئ
    do_something if !some_condition
    
    # سئ
    do_something if not some_condition
    
    # جيد
    do_something unless some_condition
    
    # حالة تانية كويسة
    some_condition || do_something
  • متستخدمش unless مع else. اكتبها من اول و جديد وحط الحالة الايجابية الاول . [link]

    # سئ
    unless success?
      puts 'failure'
    else
      puts 'success'
    end
    
    # جيد
    if success?
      puts 'success'
    else
      puts 'failure'
    end
  • متستخدمش الاقواس حوالين الكونديشن [link]

    # سئ
    if (x > 10)
      # اللي هنا اتشال
    end
    
    # جيد
    if x > 10
      # اللي هنا اتشال
    end

خد بالك ان في استثناء للقاعدة دي, اللي هي safe assignment in condition.

  • متستخدمش while/until condition do لاكتر من سطر استخدم while/until. [link]

    # سئ
    while x > 5 do
      # اللي هنا اتشال
    end
    
    until x > 5 do
      # اللي هنا اتشال
    end
    
    # جيد
    while x > 5
      # اللي هنا اتشال
    end
    
    until x > 5
      # اللي هنا اتشال
    end
  • يفضل استخدام while/until في حالة هتكتبها ف سطر واحد . [link]

    # سئ
    while some_condition
      do_something
    end
    
    # جيد
    do_something while some_condition
  • يفضل until عن while في الحالات السلبية [link]

    # سئ
    do_something while !some_condition
    
    # جيد
    do_something until some_condition
  • لما تكون عاوز تعمل لوب لا نهائي استخدم Kernel#loop بدل while/until . [link]

    # سئ
    while true
      do_something
    end
    
    until false
      do_something
    end
    
    # جيد
    loop do
      do_something
    end
  • استخدم Kernel#loop مع ال breakبدل من begin/end/until او begin/end/while في حالة ال post-loop [link]

    # سئ
    begin
      puts val
      val += 1
    end while val < 0
    
    # جيد
    loop do
      puts val
      val += 1
      break unless val < 0
    end
  • شيل الاقواس الخارجيه اللي حوالين الهاش . [link]

    # سئ
    user.set({ name: 'John', age: 45, permissions: { read: true } })
    
    # جيد
    user.set(name: 'John', age: 45, permissions: { read: true })
  • شيل الاقواس الخارجية للدوال الجزء من DSL . [link]

    class Person < ActiveRecord::Base
      # سئ
      validates(:name, { presence: true, length: { within: 1..10 } })
    
      # جيد
      validates :name, presence: true, length: { within: 1..10 }
    end
  • استخدم اختصار ال Proc في حالة الدوال اللي بتعمل عملية واحدة. [link]

    # سئ
    names.map { |name| name.upcase }
    
    # جيد
    names.map(&:upcase)
  • يفضل استخدام {...} عن do...end في حالة البلوك اللي بيتكون من سطر. تجنب استخدام {...} في حالة البلوك بيتكون من اكتر من سطر (تسلسل السطور دايما وحش). دايما استخدم do...end لل control flow و تعريف الدوال (زي اللي في Rakefiles و DSL ) ابعد عن do...end في التسلسل . [link]

    names = %w[Bozhidar Steve Sarah]
    
    # سئ
    names.each do |name|
      puts name
    end
    
    # جيد
    names.each { |name| puts name }
    
    # سئ
    names.select do |name|
      name.start_with?('S')
    end.map { |name| name.upcase }
    
    # جيد
    names.select { |name| name.start_with?('S') }.map(&:upcase)

    في ناس هتجادل و تقول ان استخدام الاقواس دي {...} شكلها احسن, بس المفروض يسألوا نفسهم - هل الكود دا فعلا ينفع يتقري , و محتوي الدالة ممكن تخرجه بسهوله ؟

  • حط في اعتبارك استخدام البلوك ك ارجيومنت بدل ما تضطر تبعت بلوك من جوا. خد بالك ان دا بيأثر علي الاداء , عشان البلوك بيتحول ل بروك. [link]

    require 'tempfile'
    
    # سئ
    def with_tmp_dir
      Dir.mktmpdir do |tmp_dir|
        Dir.chdir(tmp_dir) { |dir| yield dir }  # block just passes arguments
      end
    end
    
    # جيد
    def with_tmp_dir(&block)
      Dir.mktmpdir do |tmp_dir|
        Dir.chdir(tmp_dir, &block)
      end
    end
    
    with_tmp_dir do |dir|
      puts "dir is accessible as a parameter and pwd is set: #{dir}"
    end
  • متحطش return لما ميبقاش ليها لازمة. [link]

    # سئ
    def some_method(some_arr)
      return some_arr.size
    end
    
    # جيد
    def some_method(some_arr)
      some_arr.size
    end
  • متستخدمش self لما ميبقاش ليها لازمة (هي مهمة بس لما بتستخدم self write accessor, او تعيد كتابة علامة, تسميه دالة باسم متاخد اصلا) [link]

    # سئ
    def ready?
      if self.last_reviewed_at > self.last_updated_at
        self.worker.update(self.content, self.options)
        self.status = :in_progress
      end
      self.status == :verified
    end
    
    # جيد
    def ready?
      if last_reviewed_at > last_updated_at
        worker.update(content, options)
        self.status = :in_progress
      end
      status == :verified
    end
  • و نتيجة لكدا, بطل تضلل الدوال بتاعتك بالمتغيرا طالما يعني الاتنين واحد . [link]

    class Foo
      attr_accessor :options
    
      # تمام
      def initialize(options)
        self.options = options
        # both options and self.options are equivalent here
      end
    
      # سئ
      def do_something(options = {})
        unless options[:when] == :later
          output(self.options[:message])
        end
      end
    
      # جيد
      def do_something(params = {})
        unless params[:when] == :later
          output(options[:message])
        end
      end
    end
  • متستخدمش القيمة اللي راجعة من = (علامة اليساوي) في الكونديشنز طالما مش محطوطين بين اقواس. و دي حاجة مشهورة جا عند مبرمجين الروبي و شاعات بيحبوا يسموها safe assignment in condition [link]

    # سئ
    if v = array.grep(/foo/)
      do_something(v)
      # شوية كود
    end
    
    # جيد (MRI هيقولك انها غلط بس روبوكب هيشتغل عادي قشطة)
    if (v = array.grep(/foo/))
      do_something(v)
      # شوية كود
    end
    
    # جيد
    v = array.grep(/foo/)
    if v
      do_something(v)
      # some code
    end
  • استخدم الاختصارات لما تيجي تخلي المتغير يزود علي نفسه لما يكون ينفع. [link]

    # سئ
    x = x + y
    x = x * y
    x = x**y
    x = x / y
    x = x || y
    x = x && y
    
    # جيد
    x += y
    x *= y
    x **= y
    x /= y
    x ||= y
    x &&= y
  • استخدم ||= لما تعرف المتغير بقيمة اذا كان مش متعرف . [link]

    # سئ
    name = name ? name : 'Bozhidar'
    
    # سئ
    name = 'Bozhidar' unless name
    
    # جيد حطلها القيمة دي 'Bozhidar' لو كانت هي ب nil  او false
    name ||= 'Bozhidar'
  • متستخدمش ال ||= لما تيجي تعرف boolean . (حط في اعتبارك اللي ممكن يحصل لو القيمة اللي موجودة ب false) [link]

    # سئ - القيمة هتبقي ب true  حتي لو متعرفة قبل كدا ب false.
    enabled ||= true
    
    # جيد
    enabled = true if enabled.nil?
  • استخدم &&= مع المتغيرات اللي ممكن او مش ممكن تكون موجودة. استخدام &&= هيغير قيمة المتغير في حالة انه فعلا موجود بس, بيوفر عليك انك تتاكد من وجوده ب if. [link]

    # سئ
    if something
      something = something.downcase
    end
    
    # سئ
    something = something ? something.downcase : nil
    
    # تمام
    something = something.downcase if something
    
    # جيد
    something = something && something.downcase
    
    # احسن
    something &&= something.downcase
  • تجنب استخدام === (case equality operator). من اسمها كدا باين معناها انها بترجع ل تعبير ال case و بعيدا عن كدا هي بتخلي كودك يلغبط . [link]

    # سئ
    Array === something
    (1..100) === 7
    /something/ === some_string
    
    # جيد
    something.is_a?(Array)
    (1..100).include?(7)
    some_string =~ /something/
  • متستخدمش eql? لما ينفع تستخدم == . عملية المقارنة اللي بتحصل بالعلامة دي eql? الاحتياج لاستخدامها نادر عمليا . [link]

    # سئ - eql? هتعمل نفس الي == بتعمله مع السترينج
    'ruby'.eql? some_str
    
    # جيد
    'ruby' == some_str
    1.0.eql? x # eql? استخدامها هنا اكتر منطقية لو حابب تفرق بين الاعداد الصحيحة و العشرية
  • تجنب استخدام المتغيات اللي علي طراز لغة بيرل (زي $:, $;, و هكذا ). هم مخفيين جدا دا غير ان استخدامهم محدش بيحبذه طالما مش في one-liner scripts . استخدم حاجة الني ادمين يفهموها و تكون موجوده في مكتبة ال English . [link]

    # سئ
    $:.unshift File.dirname(__FILE__)
    
    # جيد
    require 'English'
    $LOAD_PATH.unshift File.dirname(__FILE__)
  • متسيبش مسافة فاضية ما بين اسم الدالة و الاقواس . [link]

    # سئ
    f (3 + 2) + 1
    
    # جيد
    f(3 + 2) + 1
  • دايما لما تيجي تشغل كود روبي ابعتله -w عشان يحذرك لو نسيت حاجة من اللي قلناهم فوق ! [link]

  • متحطش دالة جوا دالة, استخدم lambda بدالها . تعريف دالتين في مكان واحد بينتج عنه دوال عندهم نفس السكوب . غير كدا كمان "الدوال اللي جوا بعض" هيتم تعريفهم من جديد في كل مرة الدالة تتعرف فيه . [link]

    # سئ
    def foo(x)
      def bar(y)
        # اللي هنا اتشال
      end
    
      bar(x)
    end
    
    # جيد - بتعمل زيها زي اللي فاتت بس مبيحصلش تعريف جديد للدوال كل مرة .
    def bar(y)
      # اللي هنا اتشال 
    end
    
    def foo(x)
      bar(x)
    end
    
    # برضه جيد
    def foo(x)
      bar = ->(y) { ... }
      bar.call(x)
    end
  • لو هتكتب ال lambda في سطر واحد استخدم السنتاكس الجديد بتاعها. و لو اكتر من سطر يبقي استخدم بتاع ال lambda اللي بياخد كذا سطر . [link]

    # سئ
    l = lambda { |a, b| a + b }
    l.call(1, 2)
    
    # هو صح, بس متعملش الهبل دا .
    l = ->(a, b) do
      tmp = a * 7
      tmp * b / 50
    end
    
    # جيد
    l = ->(a, b) { a + b }
    l.call(1, 2)
    
    l = lambda do |a, b|
      tmp = a * 7
      tmp * b / 50
    end
  • متشيلش الاقواس بتاعت البراميتر لما تيجي تعمل stabby lambda معاها براميتير. [link]

    # سئ
    l = ->x, y { something(x, y) }
    
    # جيد
    l = ->(x, y) { something(x, y) }
  • شيل الاقواس لما تيجي تعمل stabby lambda منغير براميتير. [link]

    # سئ
    l = ->() { something }
    
    # جيد
    l = -> { something }
  • يفصل proc عن Proc.new. [link]

    # سئ
    p = Proc.new { |n| puts n }
    
    # جيد
    p = proc { |n| puts n }
  • بيفضل proc.call() عن proc[] او proc.() في الحالتين lambdas و procs. [link]

    # سئ - كانك بتستخدم Enumeration.
    l = ->(v) { puts v }
    l[1]
    
    # also bad - uncommon syntax
    l = ->(v) { puts v }
    l.(1)
    
    # جيد
    l = ->(v) { puts v }
    l.call(1)
  • حط _ قبل اي اسم متغير او براميتر مش هتستخدمهم. ممكن برضه تستخدم _ بس (بس برضه هي مش معبرة اوي). الطريقة دي بيفهمها محلل الروبي و ادوات تانية زي روبوكب و مش هيطلعلك تحذر لعدم استخدام المتغير المعرف . [link]

    # سئ
    result = hash.map { |k, v| v + 1 }
    
    def something(x)
      unused_var, used_var = something_else(x)
      # شوية كود
    end
    
    # جيد
    result = hash.map { |_k, v| v + 1 }
    
    def something(x)
      _unused_var, used_var = something_else(x)
      # some code
    end
    
    # جيد
    result = hash.map { |_, v| v + 1 }
    
    def something(x)
      _, used_var = something_else(x)
      # some code
    end
  • استخدم $stdout/$stderr/$stdin بدل من STDOUT/STDERR/STDIN. عشان STDOUT/STDERR/STDIN ثوابت تمبتتغيش . في حين ان انت ممكن تغير قيميتهم (ممكن عاوز تغير مسار حاجة) ساعتها هيجيلك نحذير من محول الروبي . [link]

  • استخدم warn بدلا من $stderr.puts. بغض النظر انها بتقول المختصر المفيد . بس warn بتسمحلك انك تمنع التحذيرات لو عاوز . (عن طريق ان تجط مستوي التحذير ل 0 عن طريق -W0). [link]

  • يفضل استخدام sprintf و اللي زيها format عن انك تستخدم String#% [link]

    # سئ
    '%d %d' % [20, 10]
    # => '20 10'
    
    # جيد
    sprintf('%d %d', 20, 10)
    # => '20 10'
    
    # جيد
    sprintf('%<first>d %<second>d', first: 20, second: 10)
    # => '20 10'
    
    format('%d %d', 20, 10)
    # => '20 10'
    
    # جيد
    format('%<first>d %<second>d', first: 20, second: 10)
    # => '20 10'
  • لما تيجي تستخد الاسامي في ال format string tokens . يفضل %<name>s عن %{name} عشان يحدد معلومات نوع المتغير . [link]

    # سئ
    format('Hello, %{name}', name: 'John')
    
    # جيد
    format('Hello, %<name>s', name: 'John')
  • يفضل استخدام Array#join عن اللي ممكن تخدعك شوية Array#* لما تيجي تبعتلها سترنج . [link]

    # سئ
    %w[one two three] * ', '
    # => 'one, two, three'
    
    # جيد
    %w[one two three].join(', ')
    # => 'one, two, three'
  • Use Array() instead of explicit Array check or [*var], when dealing with a variable you want to treat as an Array, but you're not certain it's an array. [link]

    # سئ
    paths = [paths] unless paths.is_a? Array
    paths.each { |path| do_something(path) }
    
    # سئ (دايما هعمل array جديد)
    [*paths].each { |path| do_something(path) }
    
    # جيد (و مقري اكتر شوية)
    Array(paths).each { |path| do_something(path) }
  • استخدم ranges او Comparable#between? بدل ما تعمل علامات مقارنة منطقية تبقي معقدة طالما ممكن تعملها . [link]

    # سئ
    do_something if x >= 1000 && x <= 2000
    
    # جيد
    do_something if (1000..2000).include?(x)
    
    # جيد
    do_something if x.between?(1000, 2000)
  • يفضل استخدام الدوال الجاهزة اللي زي ==. مقارنات الارقام كويسة برضه. [link]

    # سئ
    if x % 2 == 0
    end
    
    if x % 2 == 1
    end
    
    if x == nil
    end
    
    # جيد
    if x.even?
    end
    
    if x.odd?
    end
    
    if x.nil?
    end
    
    if x.zero?
    end
    
    if x == 0
    end
  • اتاكد من ان القيمة nil بشكل مباشر . طالما مش بتتعامل مع قيمة boolean . [link]

    # سئ
    do_something if !something.nil?
    do_something if something != nil
    
    # جيد
    do_something if something
    
    # جيد - لانه بيتعامل مع boolean
    def value_set?
      !@some_boolean.nil?
    end
  • تجنب استخدام BEGIN في البلوك . [link]

  • متسخدمش END . استخدم بدالها Kernel#at_exit . [link]

    # سئ
    END { puts 'Goodbye!' }
    
    # جيد
    at_exit { puts 'Goodbye!' }
  • تجنب استخدام flip-flops. [link]

  • تجنب استخدام كوندشن جوا بعض . [link] يفضل guard clause لما يكون متاح ليك تتاكد من عدم صحة البيانات . دي حاجة بتبقي موجودة ف الاول خالص بس بترجع الناتج في اقرب وقت ممكن .

    # سئ
    def compute_thing(thing)
      if thing[:foo]
        update_with_bar(thing[:foo])
        if thing[:foo][:bar]
          partial_compute(thing)
        else
          re_compute(thing)
        end
      end
    end
    
    # جيد
    def compute_thing(thing)
      return unless thing[:foo]
      update_with_bar(thing[:foo])
      return re_compute(thing) unless thing[:foo][:bar]
      partial_compute(thing)
    end

    بيفضل استخدام next بدل من الكوندشن جوا.

    # سئ
    [0, 1, 2, 3].each do |item|
      if item > 1
        puts item
      end
    end
    
    # جيد
    [0, 1, 2, 3].each do |item|
      next unless item > 1
      puts item
    end
  • بيفضل map عن collect, find عن detect, select عن find_all, reduce عن inject و size عن length. دا مش متطلب صعب; لو استخدام الحاجات الشبيهة بتحسب طريقة قراية الكود, في يحالة دي قشطة استخدمها. الدوال دي اتاخدت من smalltalk و مش موجودة في لغات البرمجة التانيه. السبب في استخدام select للتشجيع عنها عن find_all تمام زيها زي reject و اسمها كمان معبر عن نفسه اووي. [link]

  • متسخدمش count كبديل ل size. في حالة Enumerable objects تكون غير ال Array عشان في الحالة دي هيلف حوالين المجموعة كلها عشان يقولك الحجم . [link]

    # سئ
    some_hash.count
    
    # جيد
    some_hash.size
  • استخدم flat_map بدل من map + flatten. الكلام دا مش لل Array اللي عمقة اكتر من 2 زي دا مثلا users.first.songs == ['a', ['b','c']], استخدم map + flatten بدل من flat_map. flat_map بتسطح الاراي لعمق 1 بس flatten بتسطحه بكل الطرق . [link]

    # سئ
    all_songs = users.map(&:songs).flatten.uniq
    
    # جيد
    all_songs = users.flat_map(&:songs).uniq
  • يفضل reverse_each عن reverse.each عشان بعض ال classes اللي بتضم include Enumerable هتوفر تطبيق فعال ليها. حتي في السواء الحالات لما مبتكنش بتدعم التطبيق دا, التطبيق الهام بتاعها اللي متاخد من Enumerable هيعمل نفس اللي بيعمله reverse.each. [link]

    # سئ
    array.reverse.each { ... }
    
    # جيد
    array.reverse_each { ... }

Naming

الحاجات الوحيدة الصعبة في البرمجة هي cache invalidation و تسمية الاشياء.
-- Phil Karlton

  • الاسامي لازم تكون بالانجليزي . [link]

    # سئ - اسامي لا تدعم الاسكي كود
    заплата = 1_000
    
    # سئ - كلمة بلغارية مكتوبة بحروف لاتينية
    zaplata = 1_000
    
    # جيد
    salary = 1_000
  • استخدم snake_case للرموز , و المتغيرات و الدوال. [link]

    # سئ
    :'some symbol'
    :SomeSymbol
    :someSymbol
    
    someVar = 5
    var_10  = 10
    
    def someMethod
      # some code
    end
    
    def SomeMethod
      # some code
    end
    
    # جيد
    :some_symbol
    
    some_var = 5
    var10    = 10
    
    def some_method
      # some code
    end
  • متفصلش الارقام عن الحروف في الرموز و الممتغيرات و الدوال . [link]

    # سئ
    :some_sym_1
    
    some_var_1 = 1
    
    def some_method_1
      # شوية كود هنا 
    end
    
    # جيد
    :some_sym1
    
    some_var1 = 1
    
    def some_method1
      # شوية كود هنا 
    end
  • استخدم CamelCase في حالات classes و modules. (خلي الاختصارات زي دي HTTP, RFC, XML كبيرة زي ما هي .) [link]

    # سئ
    class Someclass
      # شوية كود هنا
    end
    
    class Some_Class
      # شوية كود هنا
    end
    
    class SomeXml
      # شوية كود هنا 
    end
    
    class XmlSomething
      # some code
    end
    
    # جيد
    class SomeClass
      # شوية كود هنا 
    end
    
    class SomeXML
      # شوية كود هنا
    end
    
    class XMLSomething
      # شوية كود هنا 
    end
  • استخدم snake_caseفي يتسمية الملفات, زي hello_world.rb. [link]

  • استخدم snake_case لتسميه المجلدات زي lib/hello_world/hello_world.rb. [link]

  • احرص انك يكو عندك class/module وحيد جوا ملف الكود الواحد . سمي الملف زيه زي اسم ال class/module بس الفرق حول الاسم من CamelCase ل snake_case. [link]

  • استخدم SCREAMING_SNAKE_CASE لجميع الثوابت التانية . [link]

    # سئ
    SomeConst = 5
    
    # جيد
    SOME_CONST = 5
  • اسامي الدوال التأكيد ( اللي بترجع قيمة boolean) المفروض تنتهي بعلامة استفهام. مثال علي كدا (زي Array#empty?) . الدوال بقي اللي مش بترجع القيم دي مش المفروض تخلص بعلامة استفهام. [link]

  • تجنب بدء الدوال التأكيديه بالافعال المساعدة اللي زي is,does, او can. الكلمات دي تعتبر زيادة و ملهاش لازمة بالنسبة للاسلوي اللي اساس لغة الروبي كاتب بيه دوال ال boolean, اللي هي مثلا زي empty? و include?. [link]

    # سئ
    class Person
      def is_tall?
        true
      end
    
      def can_play_basketball?
        false
      end
    
      def does_like_candy?
        true
      end
    end
    
    # جيد
    class Person
      def tall?
        true
      end
    
      def basketball_player?
        false
      end
    
      def likes_candy?
        true
      end
    end
  • اسامي الدوال الخطيرة (الدوال اللي بتعدل self او ال arguments), exit! (مبترجعش القيمة النهائية زي ما exit بتعمل و هكذا ) المفروض تنتهي بعلامة تعجب لو في نسخة امنة من الدالة دي . [link]

    # شئ مفيش نسخة تانيه 'امنة' منها 
    class Person
      def update!
      end
    end
    
    # جيد
    class Person
      def update
      end
    end
    
    # جيد
    class Person
      def update!
      end
    
      def update
      end
    end
  • عرف الدوال اللي منغي علامة استفهام (الامنة) من نفس الناحية او الطريقة اللي مكتوب بيها اللي بعلامة تعجب (الخطرة) لو ممكن يعني . [link]

    class Array
      def flatten_once!
        res = []
    
        each do |e|
          [*e].each { |f| res << f }
        end
    
        replace(res)
      end
    
      def flatten_once
        dup.flatten_once!
      end
    end
  • لما تيجي تعرف علامات ال binary سمي البرامتر other (<< و [] دول حالات خاصة للحالة دي, خاصة ان دول ليهم دلالات مختلفة). [link]

    def +(other)
      # body omitted
    end

التعليقات

الكود الجيد بيرجع للشرح الكويس بتاعه . لما تيجي تحط تعليق, أسال نفسك , "ازاي اقدر احسن الحتة دي من الكود عشان متكنش محتاجة تعليق يوضحها" حسن كودك و بعدين اشرحه مدا هيكون اوضح كتير.
-- Steve McConnell

  • خلي الكود بتاعك بيشح نفسه و انت مش هتحتاج تقرأ الكلام اللي جاي كله , بجد! [link]

  • Write comments in English. [link]

  • استخدم مسافة واحد فاضية ما بين الرمز دا # و الكلام اللي بعده اللي مكتوب في الكومنت. [link]

  • التعليقات اللي اكتر من كلمة بتكبر الحروف الاولي منها و بتستخدم علامات الترقيم. استخدم [مسافة واحدة](https://en.wikipedia.org/wiki/Sentence_spacing. [link]

  • بلاش التعليقات اللي ملهاش لازمة. [link]

    # سئ
    counter += 1 # Increments counter by one.
  • حدث التعليقات اول بأول, لان التعليقات القديمة اسواء من عدمه بكتيير. [link]

الكود الحلو زي النكتة الحلوة: مش محتاج تشرحها
— المبرمج القديم maxim, خلال Russ Olsen

  • تجنب كتابة تعليقات تشرح الكود الوحش . عدل الكود بتاعك عشان يشرح نفسه . . ("Do or do not—there is no try." Yoda) [link]

التعليقات التوضيحية للتعليقات

  • التعليقات التوضيحيه عادة بتكتب في سطر فوق بالظبط الكود اللي عاوز يتوضح. [link]

  • الكلمات اللي بتميزها لازم يجي بعدها نقطتين فوق بعض و مسافة, و بعدها الملاحظة اللي بتفسر المشكلة. [link]

  • لو المشكلة محتاجة اكتر من سطر عشان تتشرح , اشرحها في السطور اللي بعدها و سيب 3 مسافات بعد # (مسافة واحدة كدا كدا بتبقي محطوطه, الاتنين التانين معناهم التكملة). [link]

    def bar
      # FIXME: This has crashed occasionally since v3.2.1. It may
      #   be related to the BarBazUtil upgrade.
      baz(:quux)
    end
  • في الحالات اللي بتكون الحالة واضحة اووي و اي توضيح هيعتبر اعادة, التعليقات التوضيحية بتتساب اخر السطر منغير تفسير . الموضوع دا استثناء و مش قاعدة. [link]

    def bar
      sleep 100 # OPTIMIZE
    end
  • استخدم TODO عشان تسيب ملاحظة علي خاصية او ميزة متعملوش و المفروض يتعملوا بعدين. [link]

  • استخدم FIXME ك ملاحظة ل كود بايظ محتاج يتصلح . [link]

  • استخدم OPTIMIZE ك ملاحظة لل بطء او عدم فاعلية الكود, اللي مكن يعمل مشاكل ف الاداء بعدين. [link]

  • استخدم HACK ك ملاحظة ل حاجة اتكروتت و المفروض تتظبط . [link]

  • استخدم REVIEW ك ملاحظة ل حاجة محتاجة تأكيد انها كدا بتعمل المطلوب. علي سبيل المثال: REVIEW: Are we sure this is how the client does X currently? [link]

  • استخدم كلمات مختلفة للتعليقات التوضيحية لو شايف انها كدا هتوضح اكتر, بس اتاكد انك شارحها في مكان وي ال README بتاع المشروهع او حاجة زيه . [link]

التعليقات السحرية

  • حط ال التعليقات السحرية فوق كل الاكواد و الشرح. هي بس بتتحط لو انت محتاجهم في ملف الكود بتاعك [link]

    # جيد
    # frozen_string_literal: true
    # Some documentation about Person
    class Person
    end
    
    # سئ
    # Some documentation about Person
    # frozen_string_literal: true
    class Person
    end