├── .gitattributes ├── CONTRIBUTING.md └── README-EgAr.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md whitespace=trailing-space,tab-in-indent 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | * [Fork](https://help.github.com/articles/fork-a-repo) the project on GitHub. 2 | * Make your feature addition or bug fix in a feature branch. (Include a description of your changes) 3 | * Push your feature branch to GitHub. 4 | * Send a [Pull Request](https://help.github.com/articles/using-pull-requests). -------------------------------------------------------------------------------- /README-EgAr.md: -------------------------------------------------------------------------------- 1 | # مقدمة 2 | 3 | > وجود مثل أعلي مهم
4 | > -- أليكس ج. ميرفي / روبوكب 5 | 6 | 7 | شئ كان دايما بيضايقني ك روبي ديفيلوبر—مطورين البايثون عندهم مرجع عظيم لطريقة كتابة الكود 8 | ([راجع ستايل البايثون](https://www.python.org/dev/peps/pep-0008/)) و احنا مش عندنا واحد رسمي زيه يوثق طريقة الكتابة بالروبي و افضل التطبيقات. 9 | و انا مؤمن جدا ان دا حاجة مهمة , و ايضا مؤمن ان مجتمع عظيم زي بتاع الروبي لازم يكون قادر يطلع ستايل زي ده. 10 | 11 | المرجع او الدليل دا ابتدا ك مرجع داخلي خاص لشركتنا دليل البرمجة بالروبي (اتكتب عشانك بجد). 12 | في لحظة كدا قررت ان اللي انا بعمله دا ممكن ناس كتيرة من مجتمع الروبي تهتم بيه عامة , و ان العالم في احتياج اقل ل توجيه داخلي اخر لشركة . 13 | بس بكل تأكيد العالم هيستنفع من اللي هنقدر نسجله و نتوصل ايه من تطبيقات و ممارسات تسهل كتابة لغة الروبي 14 | 15 | من ساعة ما بدأت الدليلل دا و انا بيجيلي رد فعل من اعضاء مجتمع الروبي من جميع انحاء العالم. 16 | الفضل ل كل الاقتراحات و الدعم! مع بعض هنقدر نعمل مصدر مفيد لكل مطزر بلغة الروبي. 17 | 18 | علي فكرة لو انت شغال رايلز برضه ممكن تحتاج تبص بصة علي [دليل أسلوب الروبي اون رايلز][rails-style-guide]. 19 | 20 | 21 | # دليل أسلوب كتابة الروبي 22 | 23 | الدليل دا بيقترح عليك افضل التطبيقات عشان مبرمج الروبي الحقيقي يقدر يكتب حاجة مبرمج روبي حقيقي تاني يقدر يعدل عليها 24 | دليل بيعكس الاستخدام بتاعه في العالم الحقيقي , في حين ان الدليل المتمسك بالمثالية بيترفض من الناس , 25 | و هو المفروض يساعد علي التخلص من المشاكل نهائيا بغض النظر هو كويس اد ايه . 26 | 27 | 28 | الدليل دا متقسم ل اجزاء ليها علاقة ببعض . و انا حاولت اضيف المنطق علي القواعد (لو حاجة منها اهملت ف انا حاطط افتراض انها واضحة) 29 | 30 | انا مجبتش القواعد دي من عندي, هم غالبا مستندين علي حياتي المهنية ك مهندس برمجيات محترف و الاقتراحات و الاراء من اعضاء مجتمع الروبي و مصادر محترمة ل برمجة الروبي 31 | مثل :- 32 | ["Programming Ruby"][pickaxe] و 33 | ["The Ruby Programming Language"][trpl]. 34 | 35 | في بعض النواحي مبتلاقيش توافق واضح للاراء في مجتمع الروبي بالنسبة لاسلوب معين (زي طريقة تعريف السترينج, المسافات اللي جوا الهاش, مكان النقطة في تسلسل الدوال, الخ .. ) 36 | في الحالات اللي زي دي يتم التعريف بجميع الانماط المشهورة و يسيبك براحتك تطبق اللي تحبه . 37 | 38 | 39 | الدليل دا بيتطور علي طول مع الوقت ,عشان عرف جديد بيتحط او واحد قديم يتشال عشان تغير بيحصل في لغة الروبي نفسها 40 | 41 | كتير من المشاريع عندهم دليل كتابة كود خاص بيهم (غالبا بيكون مشتق من الدليل دا). 42 | في حالة وجود اي خلاف فان الاولوية تكون للدليل دا. 43 | 44 | ممكن تعمل نسخة من الدليل PDF او HTML باستخدام [Pandoc][]. 45 | 46 | و دا يقدر يحلل الكود بتاعك , بناء علي الدليل دا [RuboCop][] . 47 | 48 | 49 | الترجمات المتاحة للدليل دا موجودة بالغات دي :- 50 | 51 | 52 | * [الانجليزية](https://github.com/bbatsov/ruby-style-guide/blob/master/README.md) 53 | * [الصينية المبسطة](https://github.com/JuanitoFatas/ruby-style-guide/blob/master/README-zhCN.md) 54 | * [الصينية التقليدية](https://github.com/JuanitoFatas/ruby-style-guide/blob/master/README-zhTW.md) 55 | * [الفرنسية](https://github.com/gauthier-delacroix/ruby-style-guide/blob/master/README-frFR.md) 56 | * [اليابانية](https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md) 57 | * [الكورية](https://github.com/dalzony/ruby-style-guide/blob/master/README-koKR.md) 58 | * [البرتغالية](https://github.com/rubensmabueno/ruby-style-guide/blob/master/README-PT-BR.md) 59 | * [الروسية](https://github.com/arbox/ruby-style-guide/blob/master/README-ruRU.md) 60 | * [الاسبانية](https://github.com/alemohamad/ruby-style-guide/blob/master/README-esLA.md) 61 | * [الفيتنامية](https://github.com/CQBinh/ruby-style-guide/blob/master/README-viVN.md) 62 | 63 | ## المحتويات 64 | 65 | 66 | 67 | * [نموذج السورس كود](#source-code-layout) 68 | * [تركيب الجملة](#syntax) 69 | * [التسمية](#naming) 70 | * [التعليقات](#comments) 71 | * [التعليقات التوضيحية للتعليقات](#comment-annotations) 72 | * [التعليقات السحرية](#magic-comments) 73 | * [الفئات و الوحدات](#classes--modules) 74 | * [الاستثنائات](#exceptions) 75 | * [المجموعات](#collections) 76 | * [الارقام](#numbers) 77 | * [strings](#strings) 78 | * [الوقت و التاريخ](#date--time) 79 | * [التعبيرات العادية](#regular-expressions) 80 | * [حرف النسبة المئوية](#percent-literals) 81 | * [ميتابروجرامينج](#metaprogramming) 82 | * [متفرقات](#misc) 83 | * [ادوات](#tools) 84 | 85 | ## نموذج السورس كود 86 | تقريبا كل واحد شايف ان كل الستيلات معفنة و متتقريش معادا بتاعهم , شيل كدا "بتاعهم" . تقريبا كدا هم صح 87 | > تقريبا كل واحد شايف ان كل الستيلات معفنة و متتقريش 88 | > معادا بتاعهم , شيل كدا "بتاعهم" 89 | > تقريبا كدا هم صح...
90 | > -- جيري كوفين 91 | 92 | * 93 | استخدم `UTF-8` لل انكودين بتاع فايل الكود بتاعك. 94 | [[link](#utf-8)] 95 | 96 | * 97 | استخدم **مسافتين** لكل مستوي ف كودك (زي السوفت تاب) مستخدمش هارد تاب 98 | [[link](#spaces-indentation)] 99 | 100 | ```ruby 101 | # سئ - اربع مسافات 102 | def some_method 103 | do_something 104 | end 105 | 106 | # جيد 107 | def some_method 108 | do_something 109 | end 110 | ``` 111 | 112 | * 113 | استخدم ستايل اليونكس في نهاية السطور. (\*BSD/Solaris/Linux/macOS مستخدمين نظم التشغيل دول عنهم بشكل افتراضي , الويندوز يوزر بس هو اللي محتاج ياخد باله.) 114 | [[link](#crlf)] 115 | 116 | * لو انت بتستخدم ال جيت ف ممكن تكون محتاج تحط 117 | تعريف لحماية مشروعك من نهاية السطور في نظام الويندوز: 118 | 119 | ```bash 120 | $ git config --global core.autocrlf true 121 | ``` 122 | 123 | * 124 | متسدخدمش `;` عشان تفرق بين الستاتمينت و للتانية 125 | استخدم ستاتمينت واحدة في السطر 126 | [[link](#no-semicolon)] 127 | 128 | ```ruby 129 | # سئ 130 | puts 'foobar'; # فاصلة منقوطة ملهاش لازمة 131 | 132 | puts 'foo'; puts 'bar' # اتنين اكسبريشن في سطر واحد 133 | 134 | # جيد 135 | puts 'foobar' 136 | 137 | puts 'foo' 138 | puts 'bar' 139 | 140 | puts 'foo', 'bar' # دا وضع خاص بس 141 | ``` 142 | 143 | * 144 | يفضل تعريف الكلاس اللي منغير محتوي في سطر واحد. 145 | [[link](#single-line-classes)] 146 | 147 | ```ruby 148 | # سئ 149 | class FooError < StandardError 150 | end 151 | 152 | # شغال 153 | class FooError < StandardError; end 154 | 155 | # جيد 156 | FooError = Class.new(StandardError) 157 | ``` 158 | 159 | * 160 | بلاش تكتب دالة في سطر واحد, مع انها مشهورة عامة 161 | في شوية خوصيات في السينتاكس بتاعها بتخلي استخدامها غير مرغوب فيه 162 | علي اي حال مينفعش يبقي في اكتر من اكسبرشن ف سطر واحد في الدالة بتاعتك 163 | [[link](#no-single-line-methods)] 164 | 165 | ```ruby 166 | # سئ 167 | def too_much; something; something_else; end 168 | 169 | # شغال - لاحظ ان اول ; ضرورية 170 | def no_braces_method; body end 171 | 172 | # شغال - لاحظ ان تاني ; اختيارية 173 | def no_braces_method; body; end 174 | 175 | # شغال - بس منغير ; بتبقي صعب تقراه 176 | def some_method() body end 177 | 178 | # جيد 179 | def some_method 180 | body 181 | end 182 | ``` 183 | 184 | استثناء وحيد للقاعدة و هي الدالة الفاضية 185 | 186 | ```ruby 187 | # جيد 188 | def no_op; end 189 | ``` 190 | 191 | * 192 | استخدم المسافات جوالين ال فواصل و النقطتان و الفواصل المنقوطة 193 | ممكن يكون المسافات (او غالبا) ملهاش علاقة بمترجم الروبي . 194 | بس الهدف الاساسي منه كتابة كود سهل القراية 195 | [[link](#spaces-operators)] 196 | 197 | ```ruby 198 | sum = 1 + 2 199 | a, b = 1, 2 200 | class FooError < StandardError; end 201 | ``` 202 | 203 | في بعض الاستثنائات منها علامة الأس: 204 | 205 | ```ruby 206 | # سئ 207 | e = M * c ** 2 208 | 209 | # جيد 210 | e = M * c**2 211 | ``` 212 | 213 | استثناء اخر عشان الجذر: 214 | 215 | ```ruby 216 | # سئ 217 | o_scale = 1 / 48r 218 | 219 | # جيد 220 | o_scale = 1/48r 221 | ``` 222 | 223 | * 224 | مفيش مسافات بعد `(`, `[` او بعد `]`, `)`. 225 | Use spaces around `{` and before `}`. 226 | [[link](#spaces-braces)] 227 | 228 | ```ruby 229 | # سئ 230 | some( arg ).other 231 | [ 1, 2, 3 ].each{|e| puts e} 232 | 233 | # جيد 234 | some(arg).other 235 | [1, 2, 3].each { |e| puts e } 236 | ``` 237 | 238 | `{` و `}` محتاجين بعض التوضيح خاصة اننا بنستخدمه للهاش و البلوك و السترينج 239 | 240 | في الهاش الطريقتين يعتبروا مقبولين. 241 | بس الطريقة الاولي اوضح شوية (و اكتر شعبية و استخداما في مجتمع الروبي عامة). 242 | انما الطريقة التانية ميزيتها انها بتعمل فرق مرئي لشكل الهاش و البلوك . 243 | ايا يكن الطريقة اللي هتخترها استخدمها باتساق. 244 | 245 | ```ruby 246 | # جيد - مسافة بعد { و قبل } 247 | { one: 1, two: 2 } 248 | 249 | # جيد - مفيش مسافة قبل { و بعد } 250 | {one: 1, two: 2} 251 | ``` 252 | 253 | مع استخدامها جوا السترينج, متسيبش مسافة فاضية من جوا . 254 | 255 | ```ruby 256 | # سئ 257 | "From: #{ user.first_name }, #{ user.last_name }" 258 | 259 | # جيد 260 | "From: #{user.first_name}, #{user.last_name}" 261 | ``` 262 | 263 | * 264 | متسيبش مسافة بعد `!`. 265 | [[link](#no-space-bang)] 266 | 267 | ```ruby 268 | # سئ 269 | ! something 270 | 271 | # جيد 272 | !something 273 | ``` 274 | 275 | * 276 | مفيش مسافات جوا تعريف الراينج. 277 | [[link](#no-space-inside-range-literals)] 278 | 279 | ```ruby 280 | # سئ 281 | 1 .. 3 282 | 'a' ... 'z' 283 | 284 | # جيد 285 | 1..3 286 | 'a'...'z' 287 | ``` 288 | 289 | * 290 | خلي `when` و `case`. الاتتنين علي نفس المستوي دا اللي موجود في كتابين 291 | "The Ruby Programming Language" و "Programming Ruby". 292 | [[link](#indent-when-to-case)] 293 | 294 | ```ruby 295 | # سئ 296 | case 297 | when song.name == 'Misty' 298 | puts 'Not again!' 299 | when song.duration > 120 300 | puts 'Too long!' 301 | when Time.now.hour > 21 302 | puts "It's too late" 303 | else 304 | song.play 305 | end 306 | 307 | # جيد 308 | case 309 | when song.name == 'Misty' 310 | puts 'Not again!' 311 | when song.duration > 120 312 | puts 'Too long!' 313 | when Time.now.hour > 21 314 | puts "It's too late" 315 | else 316 | song.play 317 | end 318 | ``` 319 | 320 | * 321 | لما تيجي تحط ناتج الكونداشن بتاعك في متغير , 322 | حافظ عليهم بحيث يكونوا في نفس البرانش. 323 | [[link](#indent-conditional-assignment)] 324 | 325 | ```ruby 326 | # سئ - معقد شوية 327 | kind = case year 328 | when 1850..1889 then 'Blues' 329 | when 1890..1909 then 'Ragtime' 330 | when 1910..1929 then 'New Orleans Jazz' 331 | when 1930..1939 then 'Swing' 332 | when 1940..1950 then 'Bebop' 333 | else 'Jazz' 334 | end 335 | 336 | result = if some_cond 337 | calc_something 338 | else 339 | calc_something_else 340 | end 341 | 342 | # جيد - واضح اووي ايه اللي بيحصل 343 | kind = case year 344 | when 1850..1889 then 'Blues' 345 | when 1890..1909 then 'Ragtime' 346 | when 1910..1929 then 'New Orleans Jazz' 347 | when 1930..1939 then 'Swing' 348 | when 1940..1950 then 'Bebop' 349 | else 'Jazz' 350 | end 351 | 352 | result = if some_cond 353 | calc_something 354 | else 355 | calc_something_else 356 | end 357 | 358 | # جيد (اكثر كفاءة في الشكل) 359 | kind = 360 | case year 361 | when 1850..1889 then 'Blues' 362 | when 1890..1909 then 'Ragtime' 363 | when 1910..1929 then 'New Orleans Jazz' 364 | when 1930..1939 then 'Swing' 365 | when 1940..1950 then 'Bebop' 366 | else 'Jazz' 367 | end 368 | 369 | result = 370 | if some_cond 371 | calc_something 372 | else 373 | calc_something_else 374 | end 375 | ``` 376 | 377 | * 378 | Use empty lines between method definitions and also to break up methods 379 | into logical paragraphs internally. 380 | [[link](#empty-lines-between-methods)] 381 | 382 | ```ruby 383 | def some_method 384 | data = initialize(options) 385 | 386 | data.manipulate! 387 | 388 | data.result 389 | end 390 | 391 | def some_method 392 | result 393 | end 394 | ``` 395 | 396 | * 397 | متحطش كذا سطر فاضي ورا بعض. 398 | [[link](#two-or-more-empty-lines)] 399 | 400 | ```ruby 401 | # سئ - فيها سطرين فاضيين. 402 | some_method 403 | 404 | 405 | some_method 406 | 407 | # جيد 408 | some_method 409 | 410 | some_method 411 | ``` 412 | 413 | * 414 | حط سطر فاضي بعد الاكسيس موديفاير. 415 | [[link](#empty-lines-around-access-modifier)] 416 | 417 | ```ruby 418 | # bad 419 | class Foo 420 | attr_reader :foo 421 | def foo 422 | # do something... 423 | end 424 | end 425 | 426 | # good 427 | class Foo 428 | attr_reader :foo 429 | 430 | def foo 431 | # do something... 432 | end 433 | end 434 | ``` 435 | 436 | * 437 | متحطش سطور فاضية حوالين الدوال و الكلاسيس و الموديول . 438 | [[link](#empty-lines-around-bodies)] 439 | 440 | ```ruby 441 | # سئ 442 | class Foo 443 | 444 | def foo 445 | 446 | begin 447 | 448 | do_something do 449 | 450 | something 451 | 452 | end 453 | 454 | rescue 455 | 456 | something 457 | 458 | end 459 | 460 | end 461 | 462 | end 463 | 464 | # جيد 465 | class Foo 466 | def foo 467 | begin 468 | do_something do 469 | something 470 | end 471 | rescue 472 | something 473 | end 474 | end 475 | end 476 | ``` 477 | 478 | * 479 | لما تيجي تستخدم دالة متحطش اخر فاصلة ,خاصة لما يكون الباراميتيرز بتوعها مش علي خطوط منفصلة 480 | [[link](#no-trailing-params-comma)] 481 | 482 | ```ruby 483 | # سئ - اسهل ل تحريك/اضافة/ازالة باراميتير, بس برضه مش احسن حاجة 484 | some_method( 485 | size, 486 | count, 487 | color, 488 | ) 489 | 490 | # سئ 491 | some_method(size, count, color, ) 492 | 493 | # جيد 494 | some_method(size, count, color) 495 | ``` 496 | 497 | * 498 | حط مسافات حوالين علامة `=` لما تيجي تحط قيمة افتراضية للبراميتيرز : 499 | [[link](#spaces-around-equals)] 500 | 501 | ```ruby 502 | # سئ 503 | def some_method(arg1=:default, arg2=nil, arg3=[]) 504 | # do something... 505 | end 506 | 507 | # جيد 508 | def some_method(arg1 = :default, arg2 = nil, arg3 = []) 509 | # do something... 510 | end 511 | ``` 512 | 513 | في حين ان بعض الكتب بتقترح الطريقة الاولي, التاني احسن في الاستخدام (تقدر تقول كدا مقري اكتر). 514 | 515 | * 516 | متكملش في سطر جديد لو انت مش محتاج كدا `\` 517 | عمليا متكملش في سطر جديد الا لو محتاج كدا في سترانج مثلا 518 | [[link](#no-trailing-backslash)] 519 | 520 | ```ruby 521 | # سئ 522 | result = 1 - \ 523 | 2 524 | 525 | # جيد (بس شكلها وحش زي الزفت) 526 | result = 1 \ 527 | - 2 528 | 529 | long_string = 'First part of the long string' \ 530 | ' and second part of the long string' 531 | ``` 532 | 533 | * 534 | عشان تنسق تسلسل الدوال متعدد السطور. There are two popular 535 | في طريقتين مشهورين في مجتمع الروبي, و الاتنين يعتبروا كويسين—قدام `.` (الاختيار أ) و تابعة `.` (الاختيار ب). 536 | [[link](#consistent-multi-line-chains)] 537 | 538 | * **(الاختيار أ)** 539 | لما تيجي تستخدم التسلسل في سطر جديد سيب ال`.` في السطر التاني. 540 | 541 | ```ruby 542 | # سئ - محتاج تراجع السطر الاول عشان تفهم السطر التاني. 543 | one.two.three. 544 | four 545 | 546 | # جيد - انت فاهم كويس ايه اللي بيحصل في السطر التاني. 547 | one.two.three 548 | .four 549 | ``` 550 | 551 | * **(الاختيار ب)** لما تيجي تستخدم التسلسل في سطر جديد سيب ال`.` في السطر الاول عشان يبقي فاهم ان في تكملة تحت. 552 | 553 | ```ruby 554 | # سئ - انت محتاج توصل للسطر التاني عشان تفهم ان لسة التسلسل مخلصش . 555 | one.two.three 556 | .four 557 | 558 | # جيد - واضحة اووي من السطر الاول ان لسة في تكملة . 559 | one.two.three. 560 | four 561 | ``` 562 | 563 | هتلاقي مناقشة هنا فيها المزايا بتاعت الطريقتين 564 | [here](https://github.com/bbatsov/ruby-style-guide/pull/176). 565 | 566 | * 567 | حاذي علي بارامتر الدالة لو هياخدوا اكتر من سطر. 568 | لما تيجي تحاذيهم و ميبقوش مناسبين عشان كول السطر , 569 | حط واحد بس ف كل سطر و مقبول برضه لو بعد اول واحد 570 | [[link](#no-double-indent)] 571 | 572 | ```ruby 573 | # نقطة البداية (السطر طويل اوي) 574 | def send_mail(source) 575 | Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text) 576 | end 577 | 578 | # سئ (مزدوج المسافة) 579 | def send_mail(source) 580 | Mailer.deliver( 581 | to: 'bob@example.com', 582 | from: 'us@example.com', 583 | subject: 'Important message', 584 | body: source.text) 585 | end 586 | 587 | # جيد 588 | def send_mail(source) 589 | Mailer.deliver(to: 'bob@example.com', 590 | from: 'us@example.com', 591 | subject: 'Important message', 592 | body: source.text) 593 | end 594 | 595 | # جيد - (مسافة عادية) 596 | def send_mail(source) 597 | Mailer.deliver( 598 | to: 'bob@example.com', 599 | from: 'us@example.com', 600 | subject: 'Important message', 601 | body: source.text 602 | ) 603 | end 604 | ``` 605 | 606 | * 607 | حاذي عناصر الاراي اللي بتاخد اكتر من سطر . 608 | [[link](#align-multiline-arrays)] 609 | 610 | ```ruby 611 | # سئ - مسافة البداية 612 | menu_item = ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 613 | 'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam'] 614 | 615 | # جيد 616 | menu_item = [ 617 | 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 618 | 'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam' 619 | ] 620 | 621 | # جيد 622 | menu_item = 623 | ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 624 | 'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam'] 625 | ``` 626 | 627 | * 628 | حط اندرسكور ل الارقام الكبيرة عشان نعرف نقراها. 629 | [[link](#underscores-in-numerics)] 630 | 631 | ```ruby 632 | # سئ - في كام صفر موجود ؟ 633 | num = 1000000 634 | 635 | # جيد - كدا مخك يقدر يفهمها 636 | num = 1_000_000 637 | ``` 638 | 639 | * 640 | بيفضل تخلي الحروف سمول لما تستخدم الحروف الرقمية. 641 | 642 | `0o` ل الاوكتل , `0x` لل الهيكساديسيمل و `0b` لل بيناري. 643 | متستخدمش ال `0d` في او الدسيمال . 644 | [[link](#numeric-literal-prefixes)] 645 | 646 | ```ruby 647 | # سئ 648 | num = 01234 649 | num = 0O1234 650 | num = 0X12AB 651 | num = 0B10101 652 | num = 0D1234 653 | num = 0d1234 654 | 655 | # جيد - اسهل عشان تفصل الارقام من البداية 656 | num = 0o1234 657 | num = 0x12AB 658 | num = 0b10101 659 | num = 1234 660 | ``` 661 | 662 | * 663 | استخدم [Rdoc][rdoc] و طريقيتها في شرح او توثيق ال API. 664 | متسيبش سطر فاضي بين ال كومنت بلوك و ال `def`. 665 | [[link](#rdoc-conventions)] 666 | 667 | * 668 | اخرك في السطر 80 رمز 669 | [[link](#80-character-limits)] 670 | 671 | * 672 | تجنب المسافات الزيادة اللي ملهاش لازمة 673 | [[link](#no-trailing-whitespace)] 674 | 675 | * 676 | في نهاية كل صفحة حط سطر فاضي. 677 | [[link](#newline-eof)] 678 | 679 | * 680 | متستخدمش البلوك كومنت. 681 | مبتتسبقش بمسافة و مش سهل تتفهم زي الكومنتات العادية. 682 | [[link](#no-block-comments)] 683 | 684 | ```ruby 685 | # سئ 686 | =begin 687 | comment line 688 | another comment line 689 | =end 690 | 691 | # جيد 692 | # comment line 693 | # another comment line 694 | ``` 695 | 696 | ## تركيب الجملة 697 | 698 | * 699 | استخدم `::` ك مرجع للثوابت (زي الكلاسيس و الموديل) 700 | و برضه (زي `Array()` او `Nokogiri::HTML()`). 701 | متستخدمش `::` لل الدوال العادية . 702 | [[link](#double-colons)] 703 | 704 | ```ruby 705 | # سئ 706 | SomeClass::some_method 707 | some_object::some_method 708 | 709 | # جيد 710 | SomeClass.some_method 711 | some_object.some_method 712 | SomeModule::SomeClass::SOME_CONST 713 | SomeModule::SomeClass() 714 | ``` 715 | 716 | * 717 | استخدم `def` ب اقواس لما تكون بتاخد براميتيرز. 718 | و شيلهم لو هي مش بتاخد حاجة. 719 | [[link](#method-parens)] 720 | 721 | ```ruby 722 | # سئ 723 | def some_method() 724 | # اللي جوا اتشال 725 | end 726 | 727 | # جيد 728 | def some_method 729 | # اللي جوا اتشال 730 | end 731 | 732 | # سئ 733 | def some_method_with_parameters param1, param2 734 | # اللي جوا اتشال 735 | end 736 | 737 | # جيد 738 | def some_method_with_parameters(param1, param2) 739 | # اللي جوا اتشال 740 | end 741 | ``` 742 | 743 | * 744 | استخدم الاقواس حوالين الارجيومنت الدوال المستعاه 745 | خاصة لو اول ارجيومنت بيبدا ب قوس مفتوح `)`, 746 | زي هنا `f((3 + 2) + 1)`. 747 | [[link](#method-invocation-parens)] 748 | 749 | ```ruby 750 | # سئ 751 | x = Math.sin y 752 | # جيد 753 | x = Math.sin(y) 754 | 755 | # سئ 756 | array.delete e 757 | # جيد 758 | array.delete(e) 759 | 760 | # سئ 761 | temperance = Person.new 'Temperance', 30 762 | # جيد 763 | temperance = Person.new('Temperance', 30) 764 | ``` 765 | 766 | دايما شيل الاقواس في الحالات دي 767 | 768 | * دالة مش بتاخد ارجيومنت: 769 | 770 | ```ruby 771 | # سئ 772 | Kernel.exit!() 773 | 2.even?() 774 | fork() 775 | 'test'.upcase() 776 | 777 | # جيد 778 | Kernel.exit! 779 | 2.even? 780 | fork 781 | 'test'.upcase 782 | ``` 783 | 784 | * دوال هم جزي من DSL الداخلي (زي ال, Rake, Rails, RSpec): 785 | 786 | ```ruby 787 | # سئ 788 | validates(:name, presence: true) 789 | # جيد 790 | validates :name, presence: true 791 | ``` 792 | 793 | * الدوال الي ليها صفة "الكلمة" في الروبي: 794 | 795 | ```ruby 796 | class Person 797 | # سئ 798 | attr_reader(:name, :age) 799 | # جيد 800 | attr_reader :name, :age 801 | 802 | # شلنا باقي الكلاس 803 | end 804 | ``` 805 | 806 | ممكن نشيل الاقواس ل 807 | 808 | * الدوال الي ليها صفة "الكلمة" في الروبي, بس تكون مش معبرة: 809 | 810 | ```Ruby 811 | # جيد 812 | puts(temperance.age) 813 | system('ls') 814 | # برضه جيد 815 | puts temperance.age 816 | system 'ls' 817 | ``` 818 | * 819 | عرف الارجيومنت الاختيارية في النهاية. 820 | الروبي عندها شويه نتايج غير متوقعة لما تيجي تنادي دوال 821 | و يكون عندها ارجيومنت اختيارية في النص. 822 | [[link](#optional-arguments)] 823 | 824 | ```ruby 825 | # سئ 826 | def some_method(a = 1, b = 2, c, d) 827 | puts "#{a}, #{b}, #{c}, #{d}" 828 | end 829 | 830 | some_method('w', 'x') # => '1, 2, w, x' 831 | some_method('w', 'x', 'y') # => 'w, 2, x, y' 832 | some_method('w', 'x', 'y', 'z') # => 'w, x, y, z' 833 | 834 | # جيد 835 | def some_method(c, d, a = 1, b = 2) 836 | puts "#{a}, #{b}, #{c}, #{d}" 837 | end 838 | 839 | some_method('w', 'x') # => '1, 2, w, x' 840 | some_method('w', 'x', 'y') # => 'y, 2, w, x' 841 | some_method('w', 'x', 'y', 'z') # => 'y, z, w, x' 842 | ``` 843 | 844 | * 845 | تحجنب التعريف المتوازي للمتغيرات. 846 | هو بيبقي مسموح في حالة القيمة راجعة من دالة . 847 | استخدمه مع علامة النجمة , او تبديل قيم المتغيرات 848 | من الاخر هو صعب يتقري مش زي اما تعرف كل حاجة لوحدها 849 | [[link](#parallel-assignment)] 850 | 851 | ```ruby 852 | # سئ 853 | a, b, c, d = 'foo', 'bar', 'baz', 'foobar' 854 | 855 | # جيد 856 | a = 'foo' 857 | b = 'bar' 858 | c = 'baz' 859 | d = 'foobar' 860 | 861 | # جيد - استبدال قيم المتغيرات 862 | # استبدال قيم المتغيرات حالة خاصة , عشان هتسمحلك 863 | # انك تغير القيم بتاعت كل متغير. 864 | a = 'foo' 865 | b = 'bar' 866 | 867 | a, b = b, a 868 | puts a # => 'bar' 869 | puts b # => 'foo' 870 | 871 | # جيد - اللي الدالة بترجعه 872 | def multi_return 873 | [1, 2] 874 | end 875 | 876 | first, second = multi_return 877 | 878 | # جيد - بيستخدم علامة النجمة 879 | first, *list = [1, 2, 3, 4] # first => 1, list => [2, 3, 4] 880 | 881 | hello_array = *'Hello' # => ["Hello"] 882 | 883 | a = *(1..3) # => [1, 2, 3] 884 | ``` 885 | 886 | * 887 | تجنب استخدام اسامي الاندرسكور في المتغيرات خلال ال التعريف الموازي . 888 | التسمية المتغيرات بالاندرس سكور بيبقي مفضل عشان السياق اللي بتوفره . 889 | هي بتبقي مهمة لما بيكون في متغير من سبلات و متعرف علي شمال التعريف. 890 | المتغير من نوع سبلات مش بيكون اندر سكور 891 | [[link]](#trailing-underscore-variables) 892 | 893 | ```ruby 894 | # سئ 895 | foo = 'one,two,three,four,five' 896 | # تعريف عديم النفع بيقول معلمات مش مهمة 897 | first, second, _ = foo.split(',') 898 | first, _, _ = foo.split(',') 899 | first, *_ = foo.split(',') 900 | 901 | 902 | # جيد 903 | foo = 'one,two,three,four,five' 904 | # لاندر سكور مهم عشان يوضحلك انك محتاجهم كلهم 905 | # معادا اخر واحد اللي هو اندرسكور 906 | *beginning, _ = foo.split(',') 907 | *beginning, something, _ = foo.split(',') 908 | 909 | a, = foo.split(',') 910 | a, b, = foo.split(',') 911 | # تعريف غير مهم ل متغير غير مستخدم , بس التعريف دا 912 | # بيوفر معلومات مهمة. 913 | first, _second = foo.split(',') 914 | first, _second, = foo.split(',') 915 | first, *_ending = foo.split(',') 916 | ``` 917 | 918 | * 919 | مستخدمش `for` لحد ما تعرف السبب بالظبط . 920 | اغلب الوقت حاجات كتير المفروض تستخدمها بدلها . 921 | `for` اتعملت علي طراز ال `each` 922 | (كدا انت بتعمل مستوي جديد غير مباشر), الفكرة كلها ان ال `for` 923 | مبتعملش سكوب جديد, بمعني الفاريبال اللي هتعملها جوه هتتشاف برا عادي. 924 | [[link](#no-for-loops)] 925 | 926 | ```ruby 927 | arr = [1, 2, 3] 928 | 929 | # سئ 930 | for elem in arr do 931 | puts elem 932 | end 933 | 934 | # لاحظ هنا elem بيستخدموها برا اللوب عادي . 935 | elem # => 3 936 | 937 | # جيد 938 | arr.each { |elem| puts elem } 939 | 940 | # هنا بقي متقدرش تستخدم elem برا البلوك 941 | elem # => NameError: undefined local variable or method `elem' 942 | ``` 943 | 944 | * 945 | متستخدمش `then` لبلوك متعددة السطور`if`/`unless`. 946 | [[link](#no-then)] 947 | 948 | ```ruby 949 | # سئ 950 | if some_condition then 951 | # اللي هنا اتشال 952 | end 953 | 954 | # جيد 955 | if some_condition 956 | # اللي هنا اتشال 957 | end 958 | ``` 959 | 960 | * 961 | حط دايما الشرط بتاع `if`/`unless` علي نفس السطر. 962 | في حالات تعدد سطور الكوندشن 963 | [[link](#same-line-condition)] 964 | 965 | ```ruby 966 | # سئ 967 | if 968 | some_condition 969 | do_something 970 | do_something_else 971 | end 972 | 973 | # جيد 974 | if some_condition 975 | do_something 976 | do_something_else 977 | end 978 | ``` 979 | 980 | * 981 | بيفضل استخدام علامات ال (`:?`) عن `if/then/else/end`. 982 | عشان هي اكتر انتشارا و واضحة اكتر . 983 | [[link](#ternary-operator)] 984 | 985 | ```ruby 986 | # سئ 987 | result = if some_condition then something else something_else end 988 | 989 | # جيد 990 | result = some_condition ? something : something_else 991 | ``` 992 | 993 | * 994 | متكتبش اكتر من واحدة في نفس السطر . 995 | فيما معناه مينفعش تكتب واحدة و جواها واحدة تانية . 996 | في الحالة دي بيفضل تعملها ب `if/else` . 997 | [[link](#no-nested-ternary)] 998 | 999 | ```ruby 1000 | # سئ 1001 | some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else 1002 | 1003 | # جيد 1004 | if some_condition 1005 | nested_condition ? nested_something : nested_something_else 1006 | else 1007 | something_else 1008 | end 1009 | ``` 1010 | 1011 | * 1012 | متعملش `if x; ...`. 1013 | استخدم بدالهم علامة الترناري. 1014 | [[link](#no-semicolon-ifs)] 1015 | 1016 | ```ruby 1017 | # سئ 1018 | result = if some_condition; something else something_else end 1019 | 1020 | # جيد 1021 | result = some_condition ? something : something_else 1022 | ``` 1023 | 1024 | * 1025 | استفيد من ان `if` و `case` بيرجعوا الناتج . 1026 | [[link](#use-if-case-returns)] 1027 | 1028 | ```ruby 1029 | # سئ 1030 | if condition 1031 | result = x 1032 | else 1033 | result = y 1034 | end 1035 | 1036 | # جيد 1037 | result = 1038 | if condition 1039 | x 1040 | else 1041 | y 1042 | end 1043 | ``` 1044 | 1045 | * 1046 | استخدم `when x then ...` في حالات السطر الواحد . 1047 | عشان الطريقة المختلفة بتاعت `when x:...` اتشالت من الروبي نسخة 1.9 . 1048 | [[link](#one-line-cases)] 1049 | 1050 | * 1051 | متستخدمش `when x; ...`. بص علي القاعدة اللي فاتت . 1052 | [[link](#no-when-semicolons)] 1053 | 1054 | * 1055 | استخدم `!` بدل `not` . 1056 | [[link](#bang-not-not)] 1057 | 1058 | ```ruby 1059 | # سئ - عشان اولوية الاقواس. 1060 | x = (not something) 1061 | 1062 | # جيد 1063 | x = !something 1064 | ``` 1065 | 1066 | * 1067 | تجنب استخدام `!!`. 1068 | [[link](#no-bang-bang)] 1069 | `!!` بتحول القيمة ل بوليان, بس انت مش محتاج الكلام دا في الكوندشن. 1070 | لو عاوز تتاكد من ان قيمتها `nil` استخدم `nil?` 1071 | ```ruby 1072 | # سئ 1073 | x = 'test' 1074 | # طريقة تاكيد غير واضحة 1075 | if !!x 1076 | # اللي هنا اتشال 1077 | end 1078 | 1079 | # جيد 1080 | x = 'test' 1081 | if x 1082 | # اللي هنا اتشال 1083 | end 1084 | ``` 1085 | 1086 | * 1087 | علامتين ال `and` و `or` محظور استخدامهم . 1088 | هي بتضيف قابلية بسيطة علي قرايه اسهل بس بتبقي سبب لوجود اخطاء برمجية . 1089 | في البوليان اكسبريشنز دايما يفضل تستخدم `&&` و `||` بدلهم . 1090 | استخدام `if` و `unless`; `&&` و `||` مقبولين برضه بس مش واضحين اووي . 1091 | [[link](#no-and-or-or)] 1092 | 1093 | ```ruby 1094 | # سئ 1095 | # boolean expression 1096 | ok = got_needed_arguments and arguments_are_valid 1097 | 1098 | # control flow 1099 | document.save or fail(RuntimeError, "Failed to save document!") 1100 | 1101 | # جيد 1102 | # boolean expression 1103 | ok = got_needed_arguments && arguments_are_valid 1104 | 1105 | # control flow 1106 | fail(RuntimeError, "Failed to save document!") unless document.save 1107 | 1108 | # تمام 1109 | # control flow 1110 | document.save || fail(RuntimeError, "Failed to save document!") 1111 | ``` 1112 | 1113 | * 1114 | تجنب استخدام اكتر من سطر مع `?:` (the ternary operator); استخدم `if`/`unless` بدالهم . 1115 | [[link](#no-multiline-ternary)] 1116 | 1117 | * 1118 | بيفضل استخدام `if`/`unless` لما تكون هتعملها في سطر واحد . 1119 | برضه حل تاني مختلف انك تستخدم `&&`/`||`. 1120 | [[link](#if-as-a-modifier)] 1121 | 1122 | ```ruby 1123 | # سئ 1124 | if some_condition 1125 | do_something 1126 | end 1127 | 1128 | # جيد 1129 | do_something if some_condition 1130 | 1131 | # حل تاني كويس 1132 | some_condition && do_something 1133 | ``` 1134 | 1135 | * 1136 | ابعد عن استخدام `if`/`unless` في اخر البلوك اللي بيتكون من اكتر من سطر . 1137 | [[link](#no-multiline-if-modifiers)] 1138 | 1139 | ```ruby 1140 | # سئ 1141 | 10.times do 1142 | # multi-line body omitted 1143 | end if some_condition 1144 | 1145 | # جيد 1146 | if some_condition 1147 | 10.times do 1148 | # multi-line body omitted 1149 | end 1150 | end 1151 | ``` 1152 | 1153 | * 1154 | بلاش تعمل `if`/`unless`/`while`/`until` جوا بعض . 1155 | يفضل `&&`/`||` لو هينفع يعني . 1156 | [[link](#no-nested-modifiers)] 1157 | 1158 | ```ruby 1159 | # سئ 1160 | do_something if other_condition if some_condition 1161 | 1162 | # جيد 1163 | do_something if some_condition && other_condition 1164 | ``` 1165 | 1166 | * 1167 | استخدم `unless` احسن من `if` لو بتتاكد من الحالة غلط . 1168 | [[link](#unless-for-negatives)] 1169 | 1170 | ```ruby 1171 | # سئ 1172 | do_something if !some_condition 1173 | 1174 | # سئ 1175 | do_something if not some_condition 1176 | 1177 | # جيد 1178 | do_something unless some_condition 1179 | 1180 | # حالة تانية كويسة 1181 | some_condition || do_something 1182 | ``` 1183 | 1184 | * 1185 | متستخدمش `unless` مع `else`. 1186 | اكتبها من اول و جديد وحط الحالة الايجابية الاول . 1187 | [[link](#no-else-with-unless)] 1188 | 1189 | ```ruby 1190 | # سئ 1191 | unless success? 1192 | puts 'failure' 1193 | else 1194 | puts 'success' 1195 | end 1196 | 1197 | # جيد 1198 | if success? 1199 | puts 'success' 1200 | else 1201 | puts 'failure' 1202 | end 1203 | ``` 1204 | 1205 | * 1206 | متستخدمش الاقواس حوالين الكونديشن 1207 | [[link](#no-parens-around-condition)] 1208 | 1209 | ```ruby 1210 | # سئ 1211 | if (x > 10) 1212 | # اللي هنا اتشال 1213 | end 1214 | 1215 | # جيد 1216 | if x > 10 1217 | # اللي هنا اتشال 1218 | end 1219 | ``` 1220 | خد بالك ان في استثناء للقاعدة دي, اللي هي 1221 | [safe assignment in condition](#safe-assignment-in-condition). 1222 | * 1223 | متستخدمش `while/until condition do` لاكتر من سطر استخدم `while/until`. 1224 | [[link](#no-multiline-while-do)] 1225 | 1226 | ```ruby 1227 | # سئ 1228 | while x > 5 do 1229 | # اللي هنا اتشال 1230 | end 1231 | 1232 | until x > 5 do 1233 | # اللي هنا اتشال 1234 | end 1235 | 1236 | # جيد 1237 | while x > 5 1238 | # اللي هنا اتشال 1239 | end 1240 | 1241 | until x > 5 1242 | # اللي هنا اتشال 1243 | end 1244 | ``` 1245 | 1246 | * 1247 | يفضل استخدام `while/until` في حالة هتكتبها ف سطر واحد . 1248 | [[link](#while-as-a-modifier)] 1249 | 1250 | ```ruby 1251 | # سئ 1252 | while some_condition 1253 | do_something 1254 | end 1255 | 1256 | # جيد 1257 | do_something while some_condition 1258 | ``` 1259 | 1260 | * 1261 | يفضل `until` عن `while` في الحالات السلبية 1262 | [[link](#until-for-negatives)] 1263 | 1264 | ```ruby 1265 | # سئ 1266 | do_something while !some_condition 1267 | 1268 | # جيد 1269 | do_something until some_condition 1270 | ``` 1271 | 1272 | * 1273 | لما تكون عاوز تعمل لوب لا نهائي استخدم `Kernel#loop` بدل `while/until` . 1274 | [[link](#infinite-loop)] 1275 | 1276 | ```ruby 1277 | # سئ 1278 | while true 1279 | do_something 1280 | end 1281 | 1282 | until false 1283 | do_something 1284 | end 1285 | 1286 | # جيد 1287 | loop do 1288 | do_something 1289 | end 1290 | ``` 1291 | 1292 | * 1293 | استخدم `Kernel#loop` مع ال `break`بدل من `begin/end/until` او `begin/end/while` 1294 | في حالة ال post-loop 1295 | [[link](#loop-with-break)] 1296 | 1297 | ```ruby 1298 | # سئ 1299 | begin 1300 | puts val 1301 | val += 1 1302 | end while val < 0 1303 | 1304 | # جيد 1305 | loop do 1306 | puts val 1307 | val += 1 1308 | break unless val < 0 1309 | end 1310 | ``` 1311 | 1312 | * 1313 | شيل الاقواس الخارجيه اللي حوالين الهاش . 1314 | [[link](#no-braces-opts-hash)] 1315 | 1316 | ```ruby 1317 | # سئ 1318 | user.set({ name: 'John', age: 45, permissions: { read: true } }) 1319 | 1320 | # جيد 1321 | user.set(name: 'John', age: 45, permissions: { read: true }) 1322 | ``` 1323 | 1324 | * 1325 | شيل الاقواس الخارجية للدوال الجزء من DSL . 1326 | [[link](#no-dsl-decorating)] 1327 | 1328 | ```ruby 1329 | class Person < ActiveRecord::Base 1330 | # سئ 1331 | validates(:name, { presence: true, length: { within: 1..10 } }) 1332 | 1333 | # جيد 1334 | validates :name, presence: true, length: { within: 1..10 } 1335 | end 1336 | ``` 1337 | 1338 | * 1339 | استخدم اختصار ال Proc في حالة الدوال اللي بتعمل عملية واحدة. 1340 | [[link](#single-action-blocks)] 1341 | 1342 | ```ruby 1343 | # سئ 1344 | names.map { |name| name.upcase } 1345 | 1346 | # جيد 1347 | names.map(&:upcase) 1348 | ``` 1349 | 1350 | * 1351 | يفضل استخدام `{...}` عن `do...end` في حالة البلوك اللي بيتكون من سطر. 1352 | تجنب استخدام `{...}` في حالة البلوك بيتكون من اكتر من سطر (تسلسل السطور دايما وحش). 1353 | دايما استخدم `do...end` لل control flow و تعريف الدوال (زي اللي في Rakefiles و DSL ) 1354 | ابعد عن `do...end` في التسلسل . 1355 | [[link](#single-line-blocks)] 1356 | 1357 | ```ruby 1358 | names = %w[Bozhidar Steve Sarah] 1359 | 1360 | # سئ 1361 | names.each do |name| 1362 | puts name 1363 | end 1364 | 1365 | # جيد 1366 | names.each { |name| puts name } 1367 | 1368 | # سئ 1369 | names.select do |name| 1370 | name.start_with?('S') 1371 | end.map { |name| name.upcase } 1372 | 1373 | # جيد 1374 | names.select { |name| name.start_with?('S') }.map(&:upcase) 1375 | ``` 1376 | في ناس هتجادل و تقول ان استخدام الاقواس دي {...} شكلها احسن, 1377 | بس المفروض يسألوا نفسهم - هل الكود دا فعلا ينفع يتقري , و محتوي الدالة ممكن تخرجه بسهوله ؟ 1378 | 1379 | * 1380 | حط في اعتبارك استخدام البلوك ك ارجيومنت بدل ما تضطر تبعت بلوك من جوا. 1381 | خد بالك ان دا بيأثر علي الاداء , عشان البلوك بيتحول ل بروك. 1382 | [[link](#block-argument)] 1383 | 1384 | ```ruby 1385 | require 'tempfile' 1386 | 1387 | # سئ 1388 | def with_tmp_dir 1389 | Dir.mktmpdir do |tmp_dir| 1390 | Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments 1391 | end 1392 | end 1393 | 1394 | # جيد 1395 | def with_tmp_dir(&block) 1396 | Dir.mktmpdir do |tmp_dir| 1397 | Dir.chdir(tmp_dir, &block) 1398 | end 1399 | end 1400 | 1401 | with_tmp_dir do |dir| 1402 | puts "dir is accessible as a parameter and pwd is set: #{dir}" 1403 | end 1404 | ``` 1405 | 1406 | * 1407 | متحطش `return` لما ميبقاش ليها لازمة. 1408 | [[link](#no-explicit-return)] 1409 | 1410 | ```ruby 1411 | # سئ 1412 | def some_method(some_arr) 1413 | return some_arr.size 1414 | end 1415 | 1416 | # جيد 1417 | def some_method(some_arr) 1418 | some_arr.size 1419 | end 1420 | ``` 1421 | 1422 | * 1423 | متستخدمش `self` لما ميبقاش ليها لازمة 1424 | (هي مهمة بس لما بتستخدم self write accessor, او تعيد كتابة علامة, تسميه دالة باسم متاخد اصلا) 1425 | [[link](#no-self-unless-required)] 1426 | 1427 | ```ruby 1428 | # سئ 1429 | def ready? 1430 | if self.last_reviewed_at > self.last_updated_at 1431 | self.worker.update(self.content, self.options) 1432 | self.status = :in_progress 1433 | end 1434 | self.status == :verified 1435 | end 1436 | 1437 | # جيد 1438 | def ready? 1439 | if last_reviewed_at > last_updated_at 1440 | worker.update(content, options) 1441 | self.status = :in_progress 1442 | end 1443 | status == :verified 1444 | end 1445 | ``` 1446 | 1447 | * 1448 | و نتيجة لكدا, بطل تضلل الدوال بتاعتك بالمتغيرا طالما يعني الاتنين واحد . 1449 | [[link](#no-shadowing)] 1450 | 1451 | ```ruby 1452 | class Foo 1453 | attr_accessor :options 1454 | 1455 | # تمام 1456 | def initialize(options) 1457 | self.options = options 1458 | # both options and self.options are equivalent here 1459 | end 1460 | 1461 | # سئ 1462 | def do_something(options = {}) 1463 | unless options[:when] == :later 1464 | output(self.options[:message]) 1465 | end 1466 | end 1467 | 1468 | # جيد 1469 | def do_something(params = {}) 1470 | unless params[:when] == :later 1471 | output(options[:message]) 1472 | end 1473 | end 1474 | end 1475 | ``` 1476 | 1477 | * 1478 | متستخدمش القيمة اللي راجعة من `=` (علامة اليساوي) في الكونديشنز طالما مش محطوطين بين اقواس. 1479 | و دي حاجة مشهورة جا عند مبرمجين الروبي و شاعات بيحبوا يسموها *safe assignment in condition* 1480 | [[link](#safe-assignment-in-condition)] 1481 | 1482 | ```ruby 1483 | # سئ 1484 | if v = array.grep(/foo/) 1485 | do_something(v) 1486 | # شوية كود 1487 | end 1488 | 1489 | # جيد (MRI هيقولك انها غلط بس روبوكب هيشتغل عادي قشطة) 1490 | if (v = array.grep(/foo/)) 1491 | do_something(v) 1492 | # شوية كود 1493 | end 1494 | 1495 | # جيد 1496 | v = array.grep(/foo/) 1497 | if v 1498 | do_something(v) 1499 | # some code 1500 | end 1501 | ``` 1502 | 1503 | * 1504 | استخدم الاختصارات لما تيجي تخلي المتغير يزود علي نفسه لما يكون ينفع. 1505 | [[link](#self-assignment)] 1506 | 1507 | ```ruby 1508 | # سئ 1509 | x = x + y 1510 | x = x * y 1511 | x = x**y 1512 | x = x / y 1513 | x = x || y 1514 | x = x && y 1515 | 1516 | # جيد 1517 | x += y 1518 | x *= y 1519 | x **= y 1520 | x /= y 1521 | x ||= y 1522 | x &&= y 1523 | ``` 1524 | 1525 | * 1526 | استخدم `||=` لما تعرف المتغير بقيمة اذا كان مش متعرف . 1527 | [[link](#double-pipe-for-uninit)] 1528 | 1529 | ```ruby 1530 | # سئ 1531 | name = name ? name : 'Bozhidar' 1532 | 1533 | # سئ 1534 | name = 'Bozhidar' unless name 1535 | 1536 | # جيد حطلها القيمة دي 'Bozhidar' لو كانت هي ب nil او false 1537 | name ||= 'Bozhidar' 1538 | ``` 1539 | 1540 | * 1541 | متستخدمش ال `||=` لما تيجي تعرف boolean . 1542 | (حط في اعتبارك اللي ممكن يحصل لو القيمة اللي موجودة ب `false`) 1543 | [[link](#no-double-pipes-for-bools)] 1544 | 1545 | ```ruby 1546 | # سئ - القيمة هتبقي ب true حتي لو متعرفة قبل كدا ب false. 1547 | enabled ||= true 1548 | 1549 | # جيد 1550 | enabled = true if enabled.nil? 1551 | ``` 1552 | 1553 | * 1554 | استخدم `&&=` مع المتغيرات اللي ممكن او مش ممكن تكون موجودة. 1555 | استخدام `&&=` هيغير قيمة المتغير في حالة انه فعلا موجود بس, بيوفر عليك انك تتاكد من وجوده ب `if`. 1556 | [[link](#double-amper-preprocess)] 1557 | 1558 | ```ruby 1559 | # سئ 1560 | if something 1561 | something = something.downcase 1562 | end 1563 | 1564 | # سئ 1565 | something = something ? something.downcase : nil 1566 | 1567 | # تمام 1568 | something = something.downcase if something 1569 | 1570 | # جيد 1571 | something = something && something.downcase 1572 | 1573 | # احسن 1574 | something &&= something.downcase 1575 | ``` 1576 | 1577 | * 1578 | تجنب استخدام `===` (case equality operator). 1579 | من اسمها كدا باين معناها انها بترجع ل تعبير ال `case` 1580 | و بعيدا عن كدا هي بتخلي كودك يلغبط . 1581 | [[link](#no-case-equality)] 1582 | 1583 | ```ruby 1584 | # سئ 1585 | Array === something 1586 | (1..100) === 7 1587 | /something/ === some_string 1588 | 1589 | # جيد 1590 | something.is_a?(Array) 1591 | (1..100).include?(7) 1592 | some_string =~ /something/ 1593 | ``` 1594 | 1595 | * 1596 | متستخدمش `eql?` لما ينفع تستخدم `==` . 1597 | عملية المقارنة اللي بتحصل بالعلامة دي `eql?` الاحتياج لاستخدامها نادر عمليا . 1598 | [[link](#eql)] 1599 | 1600 | ```ruby 1601 | # سئ - eql? هتعمل نفس الي == بتعمله مع السترينج 1602 | 'ruby'.eql? some_str 1603 | 1604 | # جيد 1605 | 'ruby' == some_str 1606 | 1.0.eql? x # eql? استخدامها هنا اكتر منطقية لو حابب تفرق بين الاعداد الصحيحة و العشرية 1607 | ``` 1608 | 1609 | * 1610 | تجنب استخدام المتغيات اللي علي طراز لغة بيرل (زي `$:`, `$;`, و هكذا ). 1611 | هم مخفيين جدا دا غير ان استخدامهم محدش بيحبذه طالما مش في one-liner scripts . 1612 | استخدم حاجة الني ادمين يفهموها و تكون موجوده في مكتبة ال `English` . 1613 | [[link](#no-cryptic-perlisms)] 1614 | 1615 | ```ruby 1616 | # سئ 1617 | $:.unshift File.dirname(__FILE__) 1618 | 1619 | # جيد 1620 | require 'English' 1621 | $LOAD_PATH.unshift File.dirname(__FILE__) 1622 | ``` 1623 | 1624 | * 1625 | متسيبش مسافة فاضية ما بين اسم الدالة و الاقواس . 1626 | [[link](#parens-no-spaces)] 1627 | 1628 | ```ruby 1629 | # سئ 1630 | f (3 + 2) + 1 1631 | 1632 | # جيد 1633 | f(3 + 2) + 1 1634 | ``` 1635 | 1636 | * 1637 | دايما لما تيجي تشغل كود روبي ابعتله `-w` عشان يحذرك لو نسيت حاجة من اللي قلناهم فوق ! 1638 | [[link](#always-warn-at-runtime)] 1639 | 1640 | * 1641 | متحطش دالة جوا دالة, استخدم lambda بدالها . 1642 | تعريف دالتين في مكان واحد بينتج عنه دوال عندهم نفس السكوب . 1643 | غير كدا كمان "الدوال اللي جوا بعض" هيتم تعريفهم من جديد في كل مرة الدالة تتعرف فيه . 1644 | [[link](#no-nested-methods)] 1645 | 1646 | ```ruby 1647 | # سئ 1648 | def foo(x) 1649 | def bar(y) 1650 | # اللي هنا اتشال 1651 | end 1652 | 1653 | bar(x) 1654 | end 1655 | 1656 | # جيد - بتعمل زيها زي اللي فاتت بس مبيحصلش تعريف جديد للدوال كل مرة . 1657 | def bar(y) 1658 | # اللي هنا اتشال 1659 | end 1660 | 1661 | def foo(x) 1662 | bar(x) 1663 | end 1664 | 1665 | # برضه جيد 1666 | def foo(x) 1667 | bar = ->(y) { ... } 1668 | bar.call(x) 1669 | end 1670 | ``` 1671 | 1672 | * 1673 | لو هتكتب ال lambda في سطر واحد استخدم السنتاكس الجديد بتاعها. 1674 | و لو اكتر من سطر يبقي استخدم بتاع ال `lambda` اللي بياخد كذا سطر . 1675 | [[link](#lambda-multi-line)] 1676 | 1677 | ```ruby 1678 | # سئ 1679 | l = lambda { |a, b| a + b } 1680 | l.call(1, 2) 1681 | 1682 | # هو صح, بس متعملش الهبل دا . 1683 | l = ->(a, b) do 1684 | tmp = a * 7 1685 | tmp * b / 50 1686 | end 1687 | 1688 | # جيد 1689 | l = ->(a, b) { a + b } 1690 | l.call(1, 2) 1691 | 1692 | l = lambda do |a, b| 1693 | tmp = a * 7 1694 | tmp * b / 50 1695 | end 1696 | ``` 1697 | 1698 | * 1699 | متشيلش الاقواس بتاعت البراميتر لما تيجي تعمل stabby lambda معاها براميتير. 1700 | [[link](#stabby-lambda-with-args)] 1701 | 1702 | ```ruby 1703 | # سئ 1704 | l = ->x, y { something(x, y) } 1705 | 1706 | # جيد 1707 | l = ->(x, y) { something(x, y) } 1708 | ``` 1709 | 1710 | * 1711 | شيل الاقواس لما تيجي تعمل stabby lambda منغير براميتير. 1712 | [[link](#stabby-lambda-no-args)] 1713 | 1714 | ```ruby 1715 | # سئ 1716 | l = ->() { something } 1717 | 1718 | # جيد 1719 | l = -> { something } 1720 | ``` 1721 | 1722 | * 1723 | يفصل `proc` عن `Proc.new`. 1724 | [[link](#proc)] 1725 | 1726 | ```ruby 1727 | # سئ 1728 | p = Proc.new { |n| puts n } 1729 | 1730 | # جيد 1731 | p = proc { |n| puts n } 1732 | ``` 1733 | 1734 | * 1735 | بيفضل `proc.call()` عن `proc[]` او `proc.()` في الحالتين lambdas و procs. 1736 | [[link](#proc-call)] 1737 | 1738 | ```ruby 1739 | # سئ - كانك بتستخدم Enumeration. 1740 | l = ->(v) { puts v } 1741 | l[1] 1742 | 1743 | # also bad - uncommon syntax 1744 | l = ->(v) { puts v } 1745 | l.(1) 1746 | 1747 | # جيد 1748 | l = ->(v) { puts v } 1749 | l.call(1) 1750 | ``` 1751 | 1752 | * 1753 | حط `_` قبل اي اسم متغير او براميتر مش هتستخدمهم. 1754 | ممكن برضه تستخدم `_` بس (بس برضه هي مش معبرة اوي). 1755 | الطريقة دي بيفهمها محلل الروبي و ادوات تانية زي روبوكب 1756 | و مش هيطلعلك تحذر لعدم استخدام المتغير المعرف . 1757 | [[link](#underscore-unused-vars)] 1758 | 1759 | ```ruby 1760 | # سئ 1761 | result = hash.map { |k, v| v + 1 } 1762 | 1763 | def something(x) 1764 | unused_var, used_var = something_else(x) 1765 | # شوية كود 1766 | end 1767 | 1768 | # جيد 1769 | result = hash.map { |_k, v| v + 1 } 1770 | 1771 | def something(x) 1772 | _unused_var, used_var = something_else(x) 1773 | # some code 1774 | end 1775 | 1776 | # جيد 1777 | result = hash.map { |_, v| v + 1 } 1778 | 1779 | def something(x) 1780 | _, used_var = something_else(x) 1781 | # some code 1782 | end 1783 | ``` 1784 | 1785 | * 1786 | استخدم `$stdout/$stderr/$stdin` بدل من `STDOUT/STDERR/STDIN`. 1787 | عشان `STDOUT/STDERR/STDIN` ثوابت تمبتتغيش . 1788 | في حين ان انت ممكن تغير قيميتهم (ممكن عاوز تغير مسار حاجة) ساعتها هيجيلك نحذير من محول الروبي . 1789 | [[link](#global-stdout)] 1790 | 1791 | * 1792 | استخدم `warn` بدلا من `$stderr.puts`. 1793 | بغض النظر انها بتقول المختصر المفيد . 1794 | بس `warn` بتسمحلك انك تمنع التحذيرات لو عاوز . 1795 | (عن طريق ان تجط مستوي التحذير ل 0 عن طريق `-W0`). 1796 | [[link](#warn)] 1797 | 1798 | * 1799 | يفضل استخدام `sprintf` و اللي زيها `format` عن انك تستخدم `String#%` 1800 | [[link](#sprintf)] 1801 | 1802 | ```ruby 1803 | # سئ 1804 | '%d %d' % [20, 10] 1805 | # => '20 10' 1806 | 1807 | # جيد 1808 | sprintf('%d %d', 20, 10) 1809 | # => '20 10' 1810 | 1811 | # جيد 1812 | sprintf('%d %d', first: 20, second: 10) 1813 | # => '20 10' 1814 | 1815 | format('%d %d', 20, 10) 1816 | # => '20 10' 1817 | 1818 | # جيد 1819 | format('%d %d', first: 20, second: 10) 1820 | # => '20 10' 1821 | ``` 1822 | 1823 | * 1824 | لما تيجي تستخد الاسامي في ال format string tokens . 1825 | يفضل `%s` عن `%{name}` عشان يحدد معلومات نوع المتغير . 1826 | [[link]](#named-format-tokens) 1827 | 1828 | ```ruby 1829 | # سئ 1830 | format('Hello, %{name}', name: 'John') 1831 | 1832 | # جيد 1833 | format('Hello, %s', name: 'John') 1834 | ``` 1835 | 1836 | * 1837 | يفضل استخدام `Array#join` عن اللي ممكن تخدعك شوية `Array#*` لما تيجي تبعتلها سترنج . 1838 | [[link](#array-join)] 1839 | 1840 | ```ruby 1841 | # سئ 1842 | %w[one two three] * ', ' 1843 | # => 'one, two, three' 1844 | 1845 | # جيد 1846 | %w[one two three].join(', ') 1847 | # => 'one, two, three' 1848 | ``` 1849 | 1850 | * 1851 | Use `Array()` instead of explicit `Array` check or `[*var]`, when dealing 1852 | with a variable you want to treat as an Array, but you're not certain it's an 1853 | array. 1854 | [[link](#array-coercion)] 1855 | 1856 | ```ruby 1857 | # سئ 1858 | paths = [paths] unless paths.is_a? Array 1859 | paths.each { |path| do_something(path) } 1860 | 1861 | # سئ (دايما هعمل array جديد) 1862 | [*paths].each { |path| do_something(path) } 1863 | 1864 | # جيد (و مقري اكتر شوية) 1865 | Array(paths).each { |path| do_something(path) } 1866 | ``` 1867 | 1868 | * 1869 | استخدم ranges او `Comparable#between?` بدل ما تعمل علامات مقارنة منطقية تبقي معقدة طالما ممكن تعملها . 1870 | [[link](#ranges-or-between)] 1871 | 1872 | ```ruby 1873 | # سئ 1874 | do_something if x >= 1000 && x <= 2000 1875 | 1876 | # جيد 1877 | do_something if (1000..2000).include?(x) 1878 | 1879 | # جيد 1880 | do_something if x.between?(1000, 2000) 1881 | ``` 1882 | 1883 | * 1884 | يفضل استخدام الدوال الجاهزة اللي زي `==`. 1885 | مقارنات الارقام كويسة برضه. 1886 | [[link](#predicate-methods)] 1887 | 1888 | ```ruby 1889 | # سئ 1890 | if x % 2 == 0 1891 | end 1892 | 1893 | if x % 2 == 1 1894 | end 1895 | 1896 | if x == nil 1897 | end 1898 | 1899 | # جيد 1900 | if x.even? 1901 | end 1902 | 1903 | if x.odd? 1904 | end 1905 | 1906 | if x.nil? 1907 | end 1908 | 1909 | if x.zero? 1910 | end 1911 | 1912 | if x == 0 1913 | end 1914 | ``` 1915 | 1916 | * 1917 | اتاكد من ان القيمة `nil` بشكل مباشر . 1918 | طالما مش بتتعامل مع قيمة boolean . 1919 | [[link](#no-non-nil-checks)] 1920 | 1921 | ```ruby 1922 | # سئ 1923 | do_something if !something.nil? 1924 | do_something if something != nil 1925 | 1926 | # جيد 1927 | do_something if something 1928 | 1929 | # جيد - لانه بيتعامل مع boolean 1930 | def value_set? 1931 | !@some_boolean.nil? 1932 | end 1933 | ``` 1934 | 1935 | * 1936 | تجنب استخدام `BEGIN` في البلوك . 1937 | [[link](#no-BEGIN-blocks)] 1938 | 1939 | * 1940 | متسخدمش `END` . استخدم بدالها `Kernel#at_exit` . 1941 | [[link](#no-END-blocks)] 1942 | 1943 | ```ruby 1944 | # سئ 1945 | END { puts 'Goodbye!' } 1946 | 1947 | # جيد 1948 | at_exit { puts 'Goodbye!' } 1949 | ``` 1950 | 1951 | * 1952 | تجنب استخدام flip-flops. 1953 | [[link](#no-flip-flops)] 1954 | 1955 | * 1956 | تجنب استخدام كوندشن جوا بعض . 1957 | [[link](#no-nested-conditionals)] 1958 | يفضل guard clause لما يكون متاح ليك تتاكد من عدم صحة البيانات . 1959 | دي حاجة بتبقي موجودة ف الاول خالص بس بترجع الناتج في اقرب وقت ممكن . 1960 | 1961 | ```ruby 1962 | # سئ 1963 | def compute_thing(thing) 1964 | if thing[:foo] 1965 | update_with_bar(thing[:foo]) 1966 | if thing[:foo][:bar] 1967 | partial_compute(thing) 1968 | else 1969 | re_compute(thing) 1970 | end 1971 | end 1972 | end 1973 | 1974 | # جيد 1975 | def compute_thing(thing) 1976 | return unless thing[:foo] 1977 | update_with_bar(thing[:foo]) 1978 | return re_compute(thing) unless thing[:foo][:bar] 1979 | partial_compute(thing) 1980 | end 1981 | ``` 1982 | 1983 | بيفضل استخدام `next` بدل من الكوندشن جوا. 1984 | 1985 | ```ruby 1986 | # سئ 1987 | [0, 1, 2, 3].each do |item| 1988 | if item > 1 1989 | puts item 1990 | end 1991 | end 1992 | 1993 | # جيد 1994 | [0, 1, 2, 3].each do |item| 1995 | next unless item > 1 1996 | puts item 1997 | end 1998 | ``` 1999 | 2000 | * 2001 | بيفضل `map` عن `collect`, `find` عن `detect`, `select` عن `find_all`, 2002 | `reduce` عن `inject` و `size` عن `length`. دا مش متطلب صعب; 2003 | لو استخدام الحاجات الشبيهة بتحسب طريقة قراية الكود, في يحالة دي قشطة استخدمها. 2004 | الدوال دي اتاخدت من smalltalk و مش موجودة في لغات البرمجة التانيه. 2005 | السبب في استخدام `select` للتشجيع عنها عن `find_all` تمام زيها زي `reject` 2006 | و اسمها كمان معبر عن نفسه اووي. 2007 | [[link](#map-find-select-reduce-size)] 2008 | 2009 | * 2010 | متسخدمش `count` كبديل ل `size`. 2011 | في حالة `Enumerable` objects تكون غير ال Array عشان في الحالة دي هيلف حوالين المجموعة كلها عشان يقولك الحجم . 2012 | [[link](#count-vs-size)] 2013 | 2014 | ```ruby 2015 | # سئ 2016 | some_hash.count 2017 | 2018 | # جيد 2019 | some_hash.size 2020 | ``` 2021 | 2022 | * 2023 | استخدم `flat_map` بدل من `map` + `flatten`. 2024 | الكلام دا مش لل Array اللي عمقة اكتر من 2 2025 | زي دا مثلا `users.first.songs == ['a', ['b','c']]`, 2026 | استخدم `map + flatten` بدل من `flat_map`. 2027 | `flat_map` بتسطح الاراي لعمق 1 2028 | بس `flatten` بتسطحه بكل الطرق . 2029 | [[link](#flat-map)] 2030 | 2031 | ```ruby 2032 | # سئ 2033 | all_songs = users.map(&:songs).flatten.uniq 2034 | 2035 | # جيد 2036 | all_songs = users.flat_map(&:songs).uniq 2037 | ``` 2038 | 2039 | * 2040 | يفضل `reverse_each` عن `reverse.each` 2041 | عشان بعض ال classes اللي بتضم `include Enumerable` هتوفر تطبيق فعال ليها. 2042 | حتي في السواء الحالات لما مبتكنش بتدعم التطبيق دا, التطبيق الهام بتاعها اللي متاخد من `Enumerable` 2043 | هيعمل نفس اللي بيعمله `reverse.each`. 2044 | [[link](#reverse-each)] 2045 | 2046 | ```ruby 2047 | # سئ 2048 | array.reverse.each { ... } 2049 | 2050 | # جيد 2051 | array.reverse_each { ... } 2052 | ``` 2053 | 2054 | ## Naming 2055 | 2056 | > الحاجات الوحيدة الصعبة في البرمجة هي cache invalidation و 2057 | > تسمية الاشياء.
2058 | > -- Phil Karlton 2059 | 2060 | * 2061 | الاسامي لازم تكون بالانجليزي . 2062 | [[link](#english-identifiers)] 2063 | 2064 | ```ruby 2065 | # سئ - اسامي لا تدعم الاسكي كود 2066 | заплата = 1_000 2067 | 2068 | # سئ - كلمة بلغارية مكتوبة بحروف لاتينية 2069 | zaplata = 1_000 2070 | 2071 | # جيد 2072 | salary = 1_000 2073 | ``` 2074 | 2075 | * 2076 | استخدم `snake_case` للرموز , و المتغيرات و الدوال. 2077 | [[link](#snake-case-symbols-methods-vars)] 2078 | 2079 | ```ruby 2080 | # سئ 2081 | :'some symbol' 2082 | :SomeSymbol 2083 | :someSymbol 2084 | 2085 | someVar = 5 2086 | var_10 = 10 2087 | 2088 | def someMethod 2089 | # some code 2090 | end 2091 | 2092 | def SomeMethod 2093 | # some code 2094 | end 2095 | 2096 | # جيد 2097 | :some_symbol 2098 | 2099 | some_var = 5 2100 | var10 = 10 2101 | 2102 | def some_method 2103 | # some code 2104 | end 2105 | ``` 2106 | 2107 | * 2108 | متفصلش الارقام عن الحروف في الرموز و الممتغيرات و الدوال . 2109 | [[link](#snake-case-symbols-methods-vars-with-numbers)] 2110 | 2111 | ```ruby 2112 | # سئ 2113 | :some_sym_1 2114 | 2115 | some_var_1 = 1 2116 | 2117 | def some_method_1 2118 | # شوية كود هنا 2119 | end 2120 | 2121 | # جيد 2122 | :some_sym1 2123 | 2124 | some_var1 = 1 2125 | 2126 | def some_method1 2127 | # شوية كود هنا 2128 | end 2129 | ``` 2130 | 2131 | 2132 | * 2133 | استخدم `CamelCase` في حالات classes و modules. 2134 | (خلي الاختصارات زي دي HTTP, RFC, XML كبيرة زي ما هي .) 2135 | [[link](#camelcase-classes)] 2136 | 2137 | ```ruby 2138 | # سئ 2139 | class Someclass 2140 | # شوية كود هنا 2141 | end 2142 | 2143 | class Some_Class 2144 | # شوية كود هنا 2145 | end 2146 | 2147 | class SomeXml 2148 | # شوية كود هنا 2149 | end 2150 | 2151 | class XmlSomething 2152 | # some code 2153 | end 2154 | 2155 | # جيد 2156 | class SomeClass 2157 | # شوية كود هنا 2158 | end 2159 | 2160 | class SomeXML 2161 | # شوية كود هنا 2162 | end 2163 | 2164 | class XMLSomething 2165 | # شوية كود هنا 2166 | end 2167 | ``` 2168 | 2169 | * 2170 | استخدم `snake_case`في يتسمية الملفات, زي `hello_world.rb`. 2171 | [[link](#snake-case-files)] 2172 | 2173 | * 2174 | استخدم `snake_case` لتسميه المجلدات زي 2175 | `lib/hello_world/hello_world.rb`. 2176 | [[link](#snake-case-dirs)] 2177 | 2178 | * 2179 | احرص انك يكو عندك class/module وحيد جوا ملف الكود الواحد . 2180 | سمي الملف زيه زي اسم ال class/module 2181 | بس الفرق حول الاسم من CamelCase ل snake_case. 2182 | [[link](#one-class-per-file)] 2183 | 2184 | * 2185 | استخدم `SCREAMING_SNAKE_CASE` لجميع الثوابت التانية . 2186 | [[link](#screaming-snake-case)] 2187 | 2188 | ```ruby 2189 | # سئ 2190 | SomeConst = 5 2191 | 2192 | # جيد 2193 | SOME_CONST = 5 2194 | ``` 2195 | 2196 | * 2197 | اسامي الدوال التأكيد ( اللي بترجع قيمة boolean) المفروض تنتهي بعلامة استفهام. 2198 | مثال علي كدا (زي `Array#empty?`) . 2199 | الدوال بقي اللي مش بترجع القيم دي مش المفروض تخلص بعلامة استفهام. 2200 | [[link](#bool-methods-qmark)] 2201 | 2202 | * 2203 | تجنب بدء الدوال التأكيديه بالافعال المساعدة اللي زي `is`,`does`, او `can`. 2204 | الكلمات دي تعتبر زيادة و ملهاش لازمة بالنسبة للاسلوي اللي اساس لغة الروبي كاتب بيه 2205 | دوال ال boolean, اللي هي مثلا زي `empty?` و `include?`. 2206 | [[link](#bool-methods-prefix)] 2207 | 2208 | ```ruby 2209 | # سئ 2210 | class Person 2211 | def is_tall? 2212 | true 2213 | end 2214 | 2215 | def can_play_basketball? 2216 | false 2217 | end 2218 | 2219 | def does_like_candy? 2220 | true 2221 | end 2222 | end 2223 | 2224 | # جيد 2225 | class Person 2226 | def tall? 2227 | true 2228 | end 2229 | 2230 | def basketball_player? 2231 | false 2232 | end 2233 | 2234 | def likes_candy? 2235 | true 2236 | end 2237 | end 2238 | ``` 2239 | 2240 | * 2241 | اسامي الدوال *الخطيرة* (الدوال اللي بتعدل `self` او ال arguments), 2242 | `exit!` (مبترجعش القيمة النهائية زي ما `exit` بتعمل و هكذا ) 2243 | المفروض تنتهي بعلامة تعجب لو في نسخة امنة من الدالة دي . 2244 | [[link](#dangerous-method-bang)] 2245 | 2246 | ```ruby 2247 | # شئ مفيش نسخة تانيه 'امنة' منها 2248 | class Person 2249 | def update! 2250 | end 2251 | end 2252 | 2253 | # جيد 2254 | class Person 2255 | def update 2256 | end 2257 | end 2258 | 2259 | # جيد 2260 | class Person 2261 | def update! 2262 | end 2263 | 2264 | def update 2265 | end 2266 | end 2267 | ``` 2268 | 2269 | * 2270 | عرف الدوال اللي منغي علامة استفهام (الامنة) 2271 | من نفس الناحية او الطريقة اللي مكتوب بيها اللي بعلامة تعجب (الخطرة) 2272 | لو ممكن يعني . 2273 | [[link](#safe-because-unsafe)] 2274 | 2275 | ```ruby 2276 | class Array 2277 | def flatten_once! 2278 | res = [] 2279 | 2280 | each do |e| 2281 | [*e].each { |f| res << f } 2282 | end 2283 | 2284 | replace(res) 2285 | end 2286 | 2287 | def flatten_once 2288 | dup.flatten_once! 2289 | end 2290 | end 2291 | ``` 2292 | 2293 | * 2294 | لما تيجي تعرف علامات ال binary سمي البرامتر `other` 2295 | (`<<` و `[]` دول حالات خاصة للحالة دي, خاصة ان دول ليهم دلالات مختلفة). 2296 | [[link](#other-arg)] 2297 | 2298 | ```ruby 2299 | def +(other) 2300 | # body omitted 2301 | end 2302 | ``` 2303 | 2304 | ## التعليقات 2305 | 2306 | > الكود الجيد بيرجع للشرح الكويس بتاعه . لما تيجي تحط تعليق, 2307 | > أسال نفسك , "ازاي اقدر احسن الحتة دي من الكود 2308 | > عشان متكنش محتاجة تعليق يوضحها" حسن كودك و بعدين اشرحه 2309 | > مدا هيكون اوضح كتير.
2310 | > -- Steve McConnell 2311 | 2312 | * 2313 | خلي الكود بتاعك بيشح نفسه و انت مش هتحتاج تقرأ الكلام اللي جاي كله , بجد! 2314 | [[link](#no-comments)] 2315 | 2316 | * 2317 | Write comments in English. 2318 | [[link](#english-comments)] 2319 | 2320 | * 2321 | استخدم مسافة واحد فاضية ما بين الرمز دا `#` و الكلام اللي بعده اللي مكتوب في الكومنت. 2322 | [[link](#hash-space)] 2323 | 2324 | * 2325 | التعليقات اللي اكتر من كلمة بتكبر الحروف الاولي منها و بتستخدم علامات الترقيم. 2326 | استخدم [مسافة واحدة](https://en.wikipedia.org/wiki/Sentence_spacing. 2327 | [[link](#english-syntax)] 2328 | 2329 | * 2330 | بلاش التعليقات اللي ملهاش لازمة. 2331 | [[link](#no-superfluous-comments)] 2332 | 2333 | ```ruby 2334 | # سئ 2335 | counter += 1 # Increments counter by one. 2336 | ``` 2337 | 2338 | * 2339 | حدث التعليقات اول بأول, لان التعليقات القديمة اسواء من عدمه بكتيير. 2340 | [[link](#comment-upkeep)] 2341 | 2342 | > الكود الحلو زي النكتة الحلوة: مش محتاج تشرحها
2343 | > — المبرمج القديم maxim, خلال [Russ Olsen](http://eloquentruby.com/blog/2011/03/07/good-code-and-good-jokes/) 2344 | 2345 | * 2346 | تجنب كتابة تعليقات تشرح الكود الوحش . 2347 | عدل الكود بتاعك عشان يشرح نفسه . 2348 | . ("Do or do not—there is no try." Yoda) 2349 | [[link](#refactor-dont-comment)] 2350 | 2351 | ### التعليقات التوضيحية للتعليقات 2352 | 2353 | * 2354 | التعليقات التوضيحيه عادة بتكتب في سطر فوق بالظبط الكود اللي عاوز يتوضح. 2355 | [[link](#annotate-above)] 2356 | 2357 | * 2358 | الكلمات اللي بتميزها لازم يجي بعدها نقطتين فوق بعض و مسافة, 2359 | و بعدها الملاحظة اللي بتفسر المشكلة. 2360 | [[link](#annotate-keywords)] 2361 | 2362 | * 2363 | لو المشكلة محتاجة اكتر من سطر عشان تتشرح , اشرحها في السطور اللي بعدها و سيب 3 مسافات بعد `#` 2364 | (مسافة واحدة كدا كدا بتبقي محطوطه, الاتنين التانين معناهم التكملة). 2365 | [[link](#indent-annotations)] 2366 | 2367 | ```ruby 2368 | def bar 2369 | # FIXME: This has crashed occasionally since v3.2.1. It may 2370 | # be related to the BarBazUtil upgrade. 2371 | baz(:quux) 2372 | end 2373 | ``` 2374 | 2375 | * 2376 | في الحالات اللي بتكون الحالة واضحة اووي و اي توضيح هيعتبر اعادة, 2377 | التعليقات التوضيحية بتتساب اخر السطر منغير تفسير . 2378 | الموضوع دا استثناء و مش قاعدة. 2379 | [[link](#rare-eol-annotations)] 2380 | 2381 | ```ruby 2382 | def bar 2383 | sleep 100 # OPTIMIZE 2384 | end 2385 | ``` 2386 | 2387 | * 2388 | استخدم `TODO` عشان تسيب ملاحظة علي خاصية او ميزة متعملوش 2389 | و المفروض يتعملوا بعدين. 2390 | [[link](#todo)] 2391 | 2392 | * 2393 | استخدم `FIXME` ك ملاحظة ل كود بايظ محتاج يتصلح . 2394 | [[link](#fixme)] 2395 | 2396 | * 2397 | استخدم `OPTIMIZE` ك ملاحظة لل بطء او عدم فاعلية الكود, 2398 | اللي مكن يعمل مشاكل ف الاداء بعدين. 2399 | [[link](#optimize)] 2400 | 2401 | * 2402 | استخدم `HACK` ك ملاحظة ل حاجة اتكروتت و المفروض تتظبط . 2403 | [[link](#hack)] 2404 | 2405 | * 2406 | استخدم `REVIEW` ك ملاحظة ل حاجة محتاجة تأكيد انها كدا بتعمل المطلوب. 2407 | علي سبيل المثال: `REVIEW: Are we sure this is how the client does X currently?` 2408 | [[link](#review)] 2409 | 2410 | * 2411 | استخدم كلمات مختلفة للتعليقات التوضيحية لو شايف انها كدا هتوضح اكتر, 2412 | بس اتاكد انك شارحها في مكان وي ال `README` بتاع المشروهع او حاجة زيه . 2413 | [[link](#document-annotations)] 2414 | 2415 | ### التعليقات السحرية 2416 | 2417 | * 2418 | حط ال التعليقات السحرية فوق كل الاكواد و الشرح. 2419 | هي بس بتتحط لو انت محتاجهم في ملف الكود بتاعك 2420 | [[link](#magic-comments-first)] 2421 | 2422 | ```ruby 2423 | # جيد 2424 | # frozen_string_literal: true 2425 | # Some documentation about Person 2426 | class Person 2427 | end 2428 | 2429 | # سئ 2430 | # Some documentation about Person 2431 | # frozen_string_literal: true 2432 | class Person 2433 | end 2434 | ``` 2435 | 2436 | ```ruby 2437 | # جيد 2438 | #!/usr/bin/env ruby 2439 | # frozen_string_literal: true 2440 | App.parse(ARGV) 2441 | 2442 | # سئ 2443 | # frozen_string_literal: true 2444 | #!/usr/bin/env ruby 2445 | App.parse(ARGV) 2446 | ``` 2447 | 2448 | * 2449 | استخدم تعليق سحري وحيد ف كل سطر لو محتاج اكتر من واحد. 2450 | [[link](#one-magic-comment-per-line)] 2451 | 2452 | ```ruby 2453 | # جيد 2454 | # frozen_string_literal: true 2455 | # encoding: ascii-8bit 2456 | 2457 | # سئ 2458 | # -*- frozen_string_literal: true; encoding: ascii-8bit -*- 2459 | ``` 2460 | 2461 | * 2462 | فرق ما بين التعليقات السحرية و الاخري ب سطر واحد فاضي . 2463 | [[link](#separate-magic-comments-from-code)] 2464 | 2465 | ```ruby 2466 | # جيد 2467 | # frozen_string_literal: true 2468 | 2469 | # Some documentation for Person 2470 | class Person 2471 | # شوية كود هنا 2472 | end 2473 | 2474 | # سئ 2475 | # frozen_string_literal: true 2476 | # Some documentation for Person 2477 | class Person 2478 | # Some code 2479 | end 2480 | ``` 2481 | 2482 | ## الفئات و الوحدات 2483 | 2484 | * 2485 | استخدم شكل متناسق لما تيجي تعرف ال class . 2486 | [[link](#consistent-classes)] 2487 | 2488 | ```ruby 2489 | class Person 2490 | # extend و include بيبقوا الاول 2491 | extend SomeModule 2492 | include AnotherModule 2493 | 2494 | # inner classes 2495 | CustomError = Class.new(StandardError) 2496 | 2497 | # و بعد كدا الثوابت 2498 | SOME_CONSTANT = 20 2499 | 2500 | # بعد كدا بنحط العناصر 2501 | attr_reader :name 2502 | 2503 | # بعد كدا بتحط اي macro لو موجود 2504 | validates :name 2505 | 2506 | # و بعدهم بقي يجي دور ال public class methods 2507 | def self.some_method 2508 | end 2509 | 2510 | # الدالة ةالتعريفية بتكون ما بين ال class methods و ال instance methods 2511 | def initialize 2512 | end 2513 | 2514 | # بيجي بعدها public instance methods 2515 | def some_method 2516 | end 2517 | 2518 | # الوال protected و private بيتجمعوا قبل كلمة end 2519 | protected 2520 | 2521 | def some_protected_method 2522 | end 2523 | 2524 | private 2525 | 2526 | def some_private_method 2527 | end 2528 | end 2529 | ``` 2530 | 2531 | * 2532 | قسم اكتر من mixins في اكتر من سطر . 2533 | [[link](#mixin-grouping)] 2534 | 2535 | ```ruby 2536 | # سئ 2537 | class Person 2538 | include Foo, Bar 2539 | end 2540 | 2541 | # جيد 2542 | class Person 2543 | # اكتر من mixins انفصلوا في سطور مختفلة 2544 | include Foo 2545 | include Bar 2546 | end 2547 | ``` 2548 | 2549 | * 2550 | تجنب تحط classes بتتكون من اكتر من سطر جوا classes تانية. 2551 | حطه جوا بعض في كل واحدة في الملف بتاعها و خلي اسم الفايل نفس اسم الكلاس اللي جوا. 2552 | [[link](#file-classes)] 2553 | 2554 | ```ruby 2555 | # سئ 2556 | 2557 | # foo.rb 2558 | class Foo 2559 | class Bar 2560 | # 30 دالة جوا 2561 | end 2562 | 2563 | class Car 2564 | # 20 دالة جوا 2565 | end 2566 | 2567 | # 30 دالة جوا 2568 | end 2569 | 2570 | # good 2571 | 2572 | # foo.rb 2573 | class Foo 2574 | # 30 دالة جوا 2575 | end 2576 | 2577 | # foo/bar.rb 2578 | class Foo 2579 | class Bar 2580 | # 30 دالة جوا 2581 | end 2582 | end 2583 | 2584 | # foo/car.rb 2585 | class Foo 2586 | class Car 2587 | # 20 دالة جوا 2588 | end 2589 | end 2590 | ``` 2591 | 2592 | * 2593 | عرف (و اعد فتح) namespaced classes و modules عن طريق ال explicit nesting. 2594 | عن طريق استخدام علامة ال scope resolution هيؤدي ل استدعاء مفاجي لل ثوابت طبقا ل الروبي [lexical scoping](https://cirw.in/blog/constant-lookup.html), 2595 | و اللي بتعتمد علي طريقة تعريف جوا عض في لحظة التعريف. 2596 | [[link](#namespace-definition)] 2597 | 2598 | ```Ruby 2599 | module Utilities 2600 | class Queue 2601 | end 2602 | end 2603 | 2604 | # سئ 2605 | class Utilities::Store 2606 | Module.nesting # => [Utilities::Store] 2607 | 2608 | def initialize 2609 | # بيرجع ل اعلي مستوي عشان ال ::Queue class 2610 | # مش في التسلسل الداخلي لل Utilities 2611 | @queue = Queue.new 2612 | end 2613 | end 2614 | 2615 | # جيد 2616 | module Utilities 2617 | class WaitingList 2618 | Module.nesting # => [Utilities::WaitingList, Utilities] 2619 | 2620 | def initialize 2621 | @queue = Queue.new # بترجع ل Utilities::Queue 2622 | end 2623 | end 2624 | end 2625 | ``` 2626 | 2627 | * 2628 | بيفضل انه يكون modules عن classes لما بتكون عبارة عن دوال بس. 2629 | بنستخددم ال classes بس لما بيكون في سبب منطقي اننا نعمل نسخة منها. 2630 | [[link](#modules-vs-classes)] 2631 | 2632 | ```ruby 2633 | # سئ 2634 | class SomeClass 2635 | def self.some_method 2636 | # اللي هنا اتشال 2637 | end 2638 | 2639 | def self.some_other_method 2640 | # اللي هنا اتشال 2641 | end 2642 | end 2643 | 2644 | # جيد 2645 | module SomeModule 2646 | module_function 2647 | 2648 | def some_method 2649 | # اللي هنا اتشال 2650 | end 2651 | 2652 | def some_other_method 2653 | # اللي هنا اتشال 2654 | end 2655 | end 2656 | ``` 2657 | 2658 | * 2659 | يفضل استخدام `module_function` عن `extend self` لما تحب تحول 2660 | نسخة الدوال بتاعت ال module ب دوال بتاعت class. 2661 | [[link](#module-function)] 2662 | 2663 | ```ruby 2664 | # سئ 2665 | module Utilities 2666 | extend self 2667 | 2668 | def parse_something(string) 2669 | # شوية حاجات هنا 2670 | end 2671 | 2672 | def other_utility_method(number, string) 2673 | # شوية حاجات هنا 2674 | end 2675 | end 2676 | 2677 | # جيد 2678 | module Utilities 2679 | module_function 2680 | 2681 | def parse_something(string) 2682 | # شوية حاجات هنا 2683 | end 2684 | 2685 | def other_utility_method(number, string) 2686 | # شوية حاجات هنا 2687 | end 2688 | end 2689 | ``` 2690 | 2691 | * 2692 | لما تيجي تصمم التسلسل الهرمي للكلاس اتاكد انها بتتبع [Liskov 2693 | Substitution 2694 | Principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle). 2695 | [[link](#liskov)] 2696 | 2697 | * 2698 | حاول تخلي الكلاس بتاعتك زي دي 2699 | [SOLID](https://en.wikipedia.org/wiki/SOLID_\(object-oriented_design\)) as 2700 | علي اد ما تقدر. 2701 | [[link](#solid-design)] 2702 | 2703 | * 2704 | دايما خالي عندك دالة ال `to_s` متعرفة في الكلاسس بتوعك اللي بعبروا عن ال domain objects. 2705 | [[link](#define-to-s)] 2706 | 2707 | ```ruby 2708 | class Person 2709 | attr_reader :first_name, :last_name 2710 | 2711 | def initialize(first_name, last_name) 2712 | @first_name = first_name 2713 | @last_name = last_name 2714 | end 2715 | 2716 | def to_s 2717 | "#{@first_name} #{@last_name}" 2718 | end 2719 | end 2720 | ``` 2721 | 2722 | * 2723 | استخدم `attr` و الحاجات اللي زيه عشان تعرف trivial accessors او mutators 2724 | [[link](#attr_family)] 2725 | 2726 | ```ruby 2727 | # سئ 2728 | class Person 2729 | def initialize(first_name, last_name) 2730 | @first_name = first_name 2731 | @last_name = last_name 2732 | end 2733 | 2734 | def first_name 2735 | @first_name 2736 | end 2737 | 2738 | def last_name 2739 | @last_name 2740 | end 2741 | end 2742 | 2743 | # جيد 2744 | class Person 2745 | attr_reader :first_name, :last_name 2746 | 2747 | def initialize(first_name, last_name) 2748 | @first_name = first_name 2749 | @last_name = last_name 2750 | end 2751 | end 2752 | ``` 2753 | 2754 | * 2755 | في حالة استخدام accessors and mutators, تجنب اسامي الدوال اللي بتبداء ب `get_` و `set_`. 2756 | دا طريقة الروبي لتعريف الاسامي بتعتهم يا بتتب اسمه لو عاوز تاخد القيمة. 2757 | يا بتحط اسمه و بعده علامة يساوي لو هتديله قيمه كدهو `attr_name=`. 2758 | [[link](#accessor_mutator_method_names)] 2759 | 2760 | ```ruby 2761 | # سئ 2762 | class Person 2763 | def get_name 2764 | "#{@first_name} #{@last_name}" 2765 | end 2766 | 2767 | def set_name(name) 2768 | @first_name, @last_name = name.split(' ') 2769 | end 2770 | end 2771 | 2772 | # جيد 2773 | class Person 2774 | def name 2775 | "#{@first_name} #{@last_name}" 2776 | end 2777 | 2778 | def name=(name) 2779 | @first_name, @last_name = name.split(' ') 2780 | end 2781 | end 2782 | ``` 2783 | 2784 | * 2785 | تجنب استخدام ال `attr`, استخدم بدالها `attr_reader` و `attr_accessor` 2786 | [[link](#attr)] 2787 | 2788 | ```ruby 2789 | # سئ - بتعرف عنصر واحد (اساسا اهملت من بعد نسخة روبي 1.9) 2790 | attr :something, true 2791 | attr :one, :two, :three # behaves as attr_reader 2792 | 2793 | # جيد 2794 | attr_accessor :something 2795 | attr_reader :one, :two, :three 2796 | ``` 2797 | 2798 | * 2799 | حط في اعتبارك استخدام `Struct.new`, 2800 | هي هتعرفلك trivial accessors و constructor و comparison operators. 2801 | [[link](#struct-new)] 2802 | 2803 | ```ruby 2804 | # جيد 2805 | class Person 2806 | attr_accessor :first_name, :last_name 2807 | 2808 | def initialize(first_name, last_name) 2809 | @first_name = first_name 2810 | @last_name = last_name 2811 | end 2812 | end 2813 | 2814 | # احسن 2815 | Person = Struct.new(:first_name, :last_name) do 2816 | end 2817 | ``` 2818 | 2819 | * 2820 | متمددش حاجة انت عرفتها بال `Struct.new`. 2821 | لانه حاجة ملهاش لازمة و هتجيبلك شوية اخطاء لو الملف اتطلب في اكتر من وقت. 2822 | [[link](#no-extend-struct-new)] 2823 | 2824 | ```ruby 2825 | # سئ 2826 | class Person < Struct.new(:first_name, :last_name) 2827 | end 2828 | 2829 | # جيد 2830 | Person = Struct.new(:first_name, :last_name) 2831 | ``` 2832 | 2833 | * 2834 | حط في اعتبارك تعريف دوال تعريفيه زيادة . 2835 | عشان تسمحلك تعرف نسخ تانيه من الكلاس بشكل اكتر منطقية . 2836 | [[link](#factory-methods)] 2837 | 2838 | ```ruby 2839 | class Person 2840 | def self.create(options_hash) 2841 | # اللي هنا اتشال 2842 | end 2843 | end 2844 | ``` 2845 | 2846 | * 2847 | بيفضل [duck-typing](https://en.wikipedia.org/wiki/Duck_typing) عن 2848 | الوراثة. 2849 | [[link](#duck-typing)] 2850 | 2851 | ```ruby 2852 | # سئ 2853 | class Animal 2854 | # abstract method 2855 | def speak 2856 | end 2857 | end 2858 | 2859 | # extend superclass 2860 | class Duck < Animal 2861 | def speak 2862 | puts 'Quack! Quack' 2863 | end 2864 | end 2865 | 2866 | # extend superclass 2867 | class Dog < Animal 2868 | def speak 2869 | puts 'Bau! Bau!' 2870 | end 2871 | end 2872 | 2873 | # جيد 2874 | class Duck 2875 | def speak 2876 | puts 'Quack! Quack' 2877 | end 2878 | end 2879 | 2880 | class Dog 2881 | def speak 2882 | puts 'Bau! Bau!' 2883 | end 2884 | end 2885 | ``` 2886 | 2887 | * 2888 | تجنب استخدام متغيرات الكلاس (`@@`) عشان التداخل اللي بيحصل في الوراثة. 2889 | [[link](#no-class-vars)] 2890 | 2891 | ```ruby 2892 | class Parent 2893 | @@class_var = 'parent' 2894 | 2895 | def self.print_class_var 2896 | puts @@class_var 2897 | end 2898 | end 2899 | 2900 | class Child < Parent 2901 | @@class_var = 'child' 2902 | end 2903 | 2904 | Parent.print_class_var # => will print 'child' 2905 | ``` 2906 | زي ما انت شايف كل ال classes في الترتيب بتاعم بيتشاركوا في واحد class variable. 2907 | دايما بيفضل استخدام ال Class instance variables عن ال class variables. 2908 | 2909 | * 2910 | عرف المستوي المناسب للدوال (`private`, `protected`) شبه بعض في الاستخدام . 2911 | متسيبش كل حاجة `public` (تقدر تقول هو دا اساسا الوضع الافتراضي). 2912 | علي اي حال احنا بنكتب *روبي* دلوقتي, مش *بايثون*. 2913 | [[link](#visibility)] 2914 | 2915 | * 2916 | المسافة اللي في الاول بتاعت الدوال دي `public`و `protected`و `private` مهمة زيها زي التعريف . 2917 | سيب سطر فاضي قبل الدوال دي قبلها و بعدها . 2918 | عشان توضح ان دا الستوي بتاع كل الدوال اللي تحتها . 2919 | [[link](#indent-public-private-protected)] 2920 | 2921 | ```ruby 2922 | class SomeClass 2923 | def public_method 2924 | # شوية كود هنا 2925 | end 2926 | 2927 | private 2928 | 2929 | def private_method 2930 | # شوية كود هنا 2931 | end 2932 | 2933 | def another_private_method 2934 | # شوية كود هنا 2935 | end 2936 | end 2937 | ``` 2938 | 2939 | * 2940 | استخدم `def self.method` عشان تعرف ال class methods. 2941 | دا بيخلي الكون احسن لو عاوز تحسنه لان اسم الكلاس مش بيتكرر . 2942 | [[link](#def-self-class-methods)] 2943 | 2944 | ```ruby 2945 | class TestClass 2946 | # سئ 2947 | def TestClass.some_method 2948 | # body omitted 2949 | end 2950 | 2951 | # جيد 2952 | def self.some_other_method 2953 | # body omitted 2954 | end 2955 | 2956 | # ممكن جدا و بتبقي كويسة 2957 | # لما تكون مضطر تعرف اكتر من دالة. 2958 | class << self 2959 | def first_method 2960 | # اللي هنا اتشال 2961 | end 2962 | 2963 | def second_method_etc 2964 | # اللي هنا اتشال 2965 | end 2966 | end 2967 | end 2968 | ``` 2969 | 2970 | * 2971 | يفضل `alias` عند استعارة الدوال في حال ال lexical class scope 2972 | حيث ان اخذ قرار ل `self` في حالة زي دي يعتبر برضه lexical, 2973 | و ف حين ان التواصل بتاعها اوضح للمستخدم و برضه مش هيحصل تغير لل aliase 2974 | في الوقت اللي الكود شغال فيه او عن طريق اي subclass الا لو اتعمل بشكل مباشر. 2975 | 2976 | [[link](#alias-method-lexically)] 2977 | 2978 | ```ruby 2979 | class Westerner 2980 | def first_name 2981 | @names.first 2982 | end 2983 | 2984 | alias given_name first_name 2985 | end 2986 | ``` 2987 | و زي ما `alias` شبهة, و هي كلمة مستخدمة 2988 | بيفضل انك تستخدمها كدا `alias foo bar` 2989 | مش كدا `alias :foo :bar`. 2990 | 2991 | برضه خليك عارف ازاي الروبي بتتعامل مع ال aliases و ال inheritance: 2992 | ال alias بيرجع للدالة اللي اتعرفت وقت ما هو بص عليها . 2993 | مبتتغير بعد كدا لوحدها. 2994 | 2995 | ```ruby 2996 | class Fugitive < Westerner 2997 | def first_name 2998 | 'Nobody' 2999 | end 3000 | end 3001 | ``` 3002 | 3003 | في المثال دا, `Fugitive#given_name` هيفضل يستخدم الدالة الاصلية من دي `Westerner#first_name`, 3004 | مش دي `Fugitive#first_name`. 3005 | عشان تعيد كتابة التصرف بتاع `Fugitive#given_name`, انت لازم تعرفها من جديد في ال derived class . 3006 | 3007 | ```ruby 3008 | class Fugitive < Westerner 3009 | def first_name 3010 | 'Nobody' 3011 | end 3012 | 3013 | alias given_name first_name 3014 | end 3015 | ``` 3016 | 3017 | * 3018 | دايما استخدم `alias_method` لما تعمل aliasing من دوال ال modules او classes او singleton classes 3019 | في وقت تشغيل الكود. 3020 | حيث ان تصرف ال `alias` هيعمل حاجة غير متوقعه في الحالات دي. 3021 | [[link](#alias-method)] 3022 | 3023 | ```ruby 3024 | module Mononymous 3025 | def self.included(other) 3026 | other.class_eval { alias_method :full_name, :given_name } 3027 | end 3028 | end 3029 | 3030 | class Sting < Westerner 3031 | include Mononymous 3032 | end 3033 | ``` 3034 | 3035 | * 3036 | لما دوال ال class (او module) يستخدموا دوال تانيين, 3037 | شيل `self` من البداية او اسمها متبوع ب `.` لما تيجي تستخدم زيها من مكان تاني. 3038 | دا حاجة معتادة في ال "service classes" او في الحاجات اللي زيها 3039 | المبدا دا بيقلل الاعادة في ال classes. 3040 | [[link](#class-and-self)] 3041 | 3042 | ```ruby 3043 | class TestClass 3044 | 3045 | # سئ - هتتعب لما تيجي تغير اسم او تشيل الدالة 3046 | def self.call(param1, param2) 3047 | TestClass.new(param1).call(param2) 3048 | end 3049 | 3050 | # سئ - اطول من الازم. 3051 | def self.call(param1, param2) 3052 | self.new(param1).call(param2) 3053 | end 3054 | 3055 | # جيد 3056 | def self.call(param1, param2) 3057 | new(param1).call(param2) 3058 | end 3059 | 3060 | # ...دوال تانية... 3061 | end 3062 | ``` 3063 | 3064 | ## الاستثنائات 3065 | 3066 | * 3067 | بيفضل `raise` عن `fail` في الاستثنائات 3068 | [[link](#prefer-raise-over-fail)] 3069 | 3070 | ```ruby 3071 | # سئ 3072 | fail SomeException, 'message' 3073 | 3074 | # جيد 3075 | raise SomeException, 'message' 3076 | ``` 3077 | 3078 | * 3079 | متحددش نوع الاستثناء `RuntimeError` و تبعته مع نسخة ال `raise`. 3080 | [[link](#no-explicit-runtimeerror)] 3081 | 3082 | ```ruby 3083 | # سئ 3084 | raise RuntimeError, 'message' 3085 | 3086 | # جيد - المفرد بيعتبر RuntimeError منغير ما تكتبه . 3087 | raise 'message' 3088 | ``` 3089 | 3090 | * 3091 | بيفضل فصل الاستثناء و الرسالة بتاعته منفصلين لما تستخدم `raise`, 3092 | بدل ما تعمل نسخة منه . 3093 | [[link](#exception-class-messages)] 3094 | 3095 | ```ruby 3096 | # سئ 3097 | raise SomeException.new('message') 3098 | # خد بالك مفيش طريقة تعرف تعمل بيها كدا `raise SomeException.new('message'), backtrace`. 3099 | 3100 | # جيد 3101 | raise SomeException, 'message' 3102 | # شغاله برضه مع `raise SomeException, 'message', backtrace`. 3103 | ``` 3104 | 3105 | * 3106 | متسخدمش return مع بلوك ال `ensure`. 3107 | لو انت استخدمت return جوا دالة ف بلوك ال `ensure`, الاولويه هتكون ليها عن اي استثناء, 3108 | و الدالة هترجع قيمة كأن مكنش في اي استثناء . الاستثناء ببساطة كانه محصلش. 3109 | [[link](#no-return-ensure)] 3110 | 3111 | ```ruby 3112 | # سئ 3113 | def foo 3114 | raise 3115 | ensure 3116 | return 'very bad idea' 3117 | end 3118 | ``` 3119 | 3120 | * 3121 | Use *implicit begin blocks* where possible. 3122 | [[link](#begin-implicit)] 3123 | 3124 | ```ruby 3125 | # سئ 3126 | def foo 3127 | begin 3128 | # الكود اللي شغال هنا 3129 | rescue 3130 | # الكود اللي بتعامل مع الاخطاء 3131 | end 3132 | end 3133 | 3134 | # جيد 3135 | def foo 3136 | # الكود اللي شغال هنا 3137 | rescue 3138 | # الكود اللي بتعامل مع الاخطاء 3139 | end 3140 | ``` 3141 | 3142 | * 3143 | خفف انتشار بلوكات `begin` عن طريق استخدام *contingency methods* 3144 | 3145 | Mitigate the proliferation of `begin` blocks by using *contingency methods* 3146 | (مصطلح اللي عمله واحد اسمه Avdi Grimm). 3147 | [[link](#contingency-methods)] 3148 | 3149 | ```ruby 3150 | # سئ 3151 | begin 3152 | something_that_might_fail 3153 | rescue IOError 3154 | # handle IOError 3155 | end 3156 | 3157 | begin 3158 | something_else_that_might_fail 3159 | rescue IOError 3160 | # handle IOError 3161 | end 3162 | 3163 | # جيد 3164 | def with_io_error_handling 3165 | yield 3166 | rescue IOError 3167 | # handle IOError 3168 | end 3169 | 3170 | with_io_error_handling { something_that_might_fail } 3171 | 3172 | with_io_error_handling { something_else_that_might_fail } 3173 | ``` 3174 | 3175 | * 3176 | متمنعش استخدام الاستثنائات. 3177 | [[link](#dont-hide-exceptions)] 3178 | 3179 | ```ruby 3180 | # سئ 3181 | begin 3182 | # الاستثنائات بتتحط هنا 3183 | rescue SomeError 3184 | # ال rescue هنا بقي ملهوش لازمة 3185 | end 3186 | 3187 | # سئ 3188 | do_something rescue nil 3189 | ``` 3190 | 3191 | * 3192 | تجنب استخدام `rescue` في شكلة الجديد. 3193 | [[link](#no-rescue-modifiers)] 3194 | 3195 | ```ruby 3196 | # سئ - دي بتمسك الاستثنائات اللي زي StandardError و اللي زيها. 3197 | read_file rescue handle_error($!) 3198 | 3199 | # جيد - دي بتمسك الاستثنائات فقط اللي زي Errno::ENOENT و اللي زيها. 3200 | def foo 3201 | read_file 3202 | rescue Errno::ENOENT => ex 3203 | handle_error(ex) 3204 | end 3205 | ``` 3206 | 3207 | * 3208 | متستخدمش الاستثنائات مع ال flow of control. 3209 | [[link](#no-exceptional-flows)] 3210 | 3211 | ```ruby 3212 | # سئ 3213 | begin 3214 | n / d 3215 | rescue ZeroDivisionError 3216 | puts 'Cannot divide by 0!' 3217 | end 3218 | 3219 | # جيد 3220 | if d.zero? 3221 | puts 'Cannot divide by 0!' 3222 | else 3223 | n / d 3224 | end 3225 | ``` 3226 | 3227 | * 3228 | تجنب استخدام الكلاس دي `Exception`. 3229 | عشان دي هتؤدي انها تقفل البرنامج لانها بتستخدم `exit`. 3230 | بيتطلب منك انك تنفهي العمليه ب `kill -9`. 3231 | [[link](#no-blind-rescues)] 3232 | 3233 | ```ruby 3234 | # سئ 3235 | begin 3236 | # calls to exit and kill signals will be caught (except kill -9) 3237 | exit 3238 | rescue Exception 3239 | puts "you didn't really want to exit, right?" 3240 | # التعامل مع الاستثناء 3241 | end 3242 | 3243 | # جيد 3244 | begin 3245 | # تعامل اعمي مع الاستثنائات بيندرج تحت StandardError. 3246 | # و معظم المبرمجين مبتعتبروش استثناء. 3247 | rescue => e 3248 | # التعامل مع الاستثناء 3249 | end 3250 | 3251 | # برضه جيد 3252 | begin 3253 | # الاستثناء بيبقي هنا 3254 | rescue StandardError => e 3255 | # التعامل مع الاستثناء 3256 | end 3257 | ``` 3258 | 3259 | * 3260 | حط استثناءات محدده أعلى سلسلة ال exceptions ، وإلا مش هتتنفذ. 3261 | [[link](#exception-ordering)] 3262 | 3263 | ```ruby 3264 | # سئ 3265 | begin 3266 | # شوية كود هنا 3267 | rescue StandardError => e 3268 | # التعامل هنا 3269 | rescue IOError => e 3270 | # دي عمرها ما هتشتغل 3271 | end 3272 | 3273 | # جيد 3274 | begin 3275 | # شوية كود هنا 3276 | rescue IOError => e 3277 | # طريقة تعامل 3278 | rescue StandardError => e 3279 | # طريقة تعامل 3280 | end 3281 | ``` 3282 | 3283 | * 3284 | الحاجات اللي الكود بتاعك معتمد عليها و بتيجي من برا حطها جوا `ensure` بلوك. 3285 | [[link](#release-resources)] 3286 | 3287 | ```ruby 3288 | f = File.open('testfile') 3289 | begin 3290 | # .. process 3291 | rescue 3292 | # .. handle error 3293 | ensure 3294 | f.close if f 3295 | end 3296 | ``` 3297 | 3298 | * 3299 | طالما ممكن تستخدم دوال بتنضف بعد ما بتخلص لوحدها و بتتقفل لوحدها استخدمها. 3300 | [[link](#auto-release-resources)] 3301 | 3302 | ```ruby 3303 | # سئ - انت محتاج تقفل الكود بنفسك 3304 | f = File.open('testfile') 3305 | # some action on the file 3306 | f.close 3307 | 3308 | # جيد - الملف بيتقل لوحده بعد ما تخلص. 3309 | File.open('testfile') do |f| 3310 | # some action on the file 3311 | end 3312 | ``` 3313 | 3314 | * 3315 | بيفضل انك تستخدم استثناء من اللي موجودين ف ال standard library 3316 | بدل ما تعمل واحد جديد من الاول. 3317 | [[link](#standard-exceptions)] 3318 | 3319 | ## المجموعات 3320 | 3321 | * 3322 | بيفضل صنع ال array و hash بالعلامات اللي بترمز ليهم ( دا طالما 3323 | انت مش عاوز تبعتلهم بارمتر هيساعد في صنعهم, بس كدا). 3324 | [[link](#literal-array-hash)] 3325 | 3326 | ```ruby 3327 | # سئ 3328 | arr = Array.new 3329 | hash = Hash.new 3330 | 3331 | # جيد 3332 | arr = [] 3333 | arr = Array.new(10) 3334 | hash = {} 3335 | hash = Hash.new(0) 3336 | ``` 3337 | 3338 | * 3339 | بيفضل استخدام `%w` لما تيجي تعرف array متكون من كلمات ( الكلمات الي منغير فواصل 3340 | من جوا مع عدم وجود اي رموز مميزة). طبق القاعدة دي مع ال array اللي بعنصرين او اكتر. 3341 | [[link](#percent-w)] 3342 | 3343 | ```ruby 3344 | # سئ 3345 | STATES = ['draft', 'open', 'closed'] 3346 | 3347 | # جيد 3348 | STATES = %w[draft open closed] 3349 | ``` 3350 | 3351 | * ط 3352 | بيفضل استخدام `%i` لما تيجي تعرف array بيتكون من symbols 3353 | (و انت مش محتاج تصلح في نسخة الروبي 1.9). 3354 | طبق القاعدة دي علي ال arrays اللي بتتكون من عنصر. 3355 | [[link](#percent-i)] 3356 | 3357 | ```ruby 3358 | # سئ 3359 | STATES = [:draft, :open, :closed] 3360 | 3361 | # جيد 3362 | STATES = %i[draft open closed] 3363 | ``` 3364 | 3365 | * 3366 | تجنب انك تحط اخر فاصلة ف ال `Array` او `Hash`, 3367 | خاصة لما يكون متعرف في اكتر من سطر . 3368 | [[link](#no-trailing-array-commas)] 3369 | 3370 | ```ruby 3371 | # سئ - اسهل في انك تشيل/تحط/تحرك عنصر بس برضه مش مفضلة. 3372 | VALUES = [ 3373 | 1001, 3374 | 2020, 3375 | 3333, 3376 | ] 3377 | 3378 | # سئ 3379 | VALUES = [1001, 2020, 3333, ] 3380 | 3381 | # جيد 3382 | VALUES = [1001, 2020, 3333] 3383 | ``` 3384 | 3385 | * 3386 | 3387 | تجنب تسيب مسافات كبيرة جوا فاضية ف ال array. 3388 | [[link](#no-gappy-arrays)] 3389 | 3390 | ```ruby 3391 | arr = [] 3392 | arr[100] = 1 # دلوقتي بقي عندك array كبير من حاجات فاضية 3393 | ``` 3394 | 3395 | * 3396 | لما تيجي تتعامل مع اول و اخر عنصر في ال array بفضل استخدام `first` او `last` 3397 | عن استخدام `[0]` او `[-1]`. 3398 | [[link](#first-and-last)] 3399 | 3400 | * 3401 | استخدم ال `Set` بدلا من ال `Array` لما تكون بتتعامل مع عناصر فريدة مبتتكررش. 3402 | ال `Set` مبنية بحيث انها تشيل مجموعات مش مترتبة بس برضه مش متكررة. 3403 | دا عبارة عن نوع هجين من ال `Array` في علاماته و ال `Hash` في سرعته . 3404 | [[link](#set-vs-array)] 3405 | 3406 | * 3407 | بيفضل استخدام ال symbols بدل ال strings ك hash keys. 3408 | [[link](#symbols-as-keys)] 3409 | 3410 | ```ruby 3411 | # سئ 3412 | hash = { 'one' => 1, 'two' => 2, 'three' => 3 } 3413 | 3414 | # جيد 3415 | hash = { one: 1, two: 2, three: 3 } 3416 | ``` 3417 | 3418 | * 3419 | تجنب استخدام mutable objects ك hash keys. 3420 | [[link](#no-mutable-keys)] 3421 | 3422 | * 3423 | استخدم طريقة نسخة الروبي 1.9 لما تيجي تعرف hash و يكون ال keys بتاعته symbols. 3424 | [[link](#hash-literals)] 3425 | 3426 | ```ruby 3427 | # سئ 3428 | hash = { :one => 1, :two => 2, :three => 3 } 3429 | 3430 | # جيد 3431 | hash = { one: 1, two: 2, three: 3 } 3432 | ``` 3433 | 3434 | * 3435 | متنوعش في الروبي 1.9 لما تيجي تعرف ال hash بين الطريقة العادية و ال hash rockets 3436 | في نفس ال hash لما يكون عندك keys مش symbols و محتاجين hash rockets عشان يتعرفوا . 3437 | [[link](#no-mixed-hash-syntaces)] 3438 | 3439 | ```ruby 3440 | # سئ 3441 | { a: 1, 'b' => 2 } 3442 | 3443 | # جيد 3444 | { :a => 1, 'b' => 2 } 3445 | ``` 3446 | 3447 | * 3448 | استخدم `Hash#key?`بدلا من `Hash#has_key?` و استخدم `Hash#value?` بدلا من `Hash#has_value?`.. 3449 | [[link](#hash-key)] 3450 | 3451 | ```ruby 3452 | # سئ 3453 | hash.has_key?(:test) 3454 | hash.has_value?(value) 3455 | 3456 | # جيد 3457 | hash.key?(:test) 3458 | hash.value?(value) 3459 | ``` 3460 | 3461 | * 3462 | استخدم `Hash#each_key` بدلا من `Hash#keys.each` و `Hash#each_value` بدلا من `Hash#values.each`. 3463 | [[link](#hash-each)] 3464 | 3465 | ```ruby 3466 | # سئ 3467 | hash.keys.each { |k| p k } 3468 | hash.values.each { |v| p v } 3469 | hash.each { |k, _v| p k } 3470 | hash.each { |_k, v| p v } 3471 | 3472 | # جيد 3473 | hash.each_key { |k| p k } 3474 | hash.each_value { |v| p v } 3475 | ``` 3476 | 3477 | * 3478 | استخدم `Hash#fetch` لما تتعامل مع hash keys المفﻻوض تتعرض. 3479 | [[link](#hash-fetch)] 3480 | 3481 | ```ruby 3482 | heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' } 3483 | # سئ - لو في غلط مش هيبان 3484 | heroes[:batman] # => 'Bruce Wayne' 3485 | heroes[:supermann] # => nil 3486 | 3487 | # جيد - fetch هتعمل KeyError ما متلاقي ال key. 3488 | heroes.fetch(:supermann) 3489 | ``` 3490 | 3491 | * 3492 | حط قيمة افتراضيه لل hash keys عن طريق `Hash#fetch` بدل ما تستخدم علامة منطقية . 3493 | [[link](#hash-fetch-defaults)] 3494 | 3495 | ```ruby 3496 | batman = { name: 'Bruce Wayne', is_evil: false } 3497 | 3498 | # سئ - لو احنا استخدمنا علامة ال || مع ال false مش هيجيلنا الناتج اللي متوقعينه. 3499 | batman[:is_evil] || true # => true 3500 | 3501 | # جيد - هتشتغل صح مع القيمة ال false. 3502 | batman.fetch(:is_evil, true) # => false 3503 | ``` 3504 | 3505 | * 3506 | يفضل استخدام البلوك بدل من القيمة الافتراضيه في `Hash#fetch` 3507 | لو الكود بتاعك اللي عدلته ممكن يكون مهم او مؤثر . 3508 | [[link](#use-hash-blocks)] 3509 | 3510 | ```ruby 3511 | batman = { name: 'Bruce Wayne' } 3512 | # سئ - لو استخدمنا القيمة الافتراضية 3513 | # ممكن جدا تبظء البرنامج لو اتعملت كذا مرة . 3514 | batman.fetch(:powers, obtain_batman_powers) # obtain_batman_powers استخدام مكلف 3515 | 3516 | # good - blocks are lazy evaluated, so only triggered in case of KeyError exception 3517 | batman.fetch(:powers) { obtain_batman_powers } 3518 | ``` 3519 | 3520 | * 3521 | استخدم `Hash#values_at` لما تحب ترجع مجموعة من القيم المتتالية. 3522 | [[link](#hash-values-at)] 3523 | 3524 | ```ruby 3525 | # سئ 3526 | email = data['email'] 3527 | username = data['nickname'] 3528 | 3529 | # جيد 3530 | email, username = data.values_at('email', 'nickname') 3531 | ``` 3532 | 3533 | * 3534 | اعتمد علي الحقيقة اللي عملتها روبي نسخة 1.9 ان ال hash مترتب. 3535 | [[link](#ordered-hashes)] 3536 | 3537 | * 3538 | متعدلش في مجموعة و انت بتلف عليها. 3539 | [[link](#no-modifying-collections)] 3540 | 3541 | * 3542 | لما تيجي تستعمل عنصر من عناصر المجموعة, تجنب انك تستخدم دي `[n]`. 3543 | لما بتسخدم حاجة بديلة من دا بيحميك من انك تنادي `[]` عل `nil`. 3544 | [[link](#accessing-elements-directly)] 3545 | 3546 | ```ruby 3547 | # سئ 3548 | Regexp.last_match[1] 3549 | 3550 | # جيد 3551 | Regexp.last_match(1) 3552 | ``` 3553 | 3554 | * 3555 | لما تيجي نوفر accessor ل للمجوعة, احمي المستخدم من انه يناديها علي `nil` 3556 | قبل ما يبدا يتعامل مع العنصر بتاع المجموعة. 3557 | [[link](#provide-alternate-accessor-to-collections)] 3558 | 3559 | ```ruby 3560 | # سئ 3561 | def awesome_things 3562 | @awesome_things 3563 | end 3564 | 3565 | # جيد 3566 | def awesome_things(index = nil) 3567 | if index && @awesome_things 3568 | @awesome_things[index] 3569 | else 3570 | @awesome_things 3571 | end 3572 | end 3573 | ``` 3574 | ## الارقام 3575 | 3576 | * 3577 | استخدم `Integer` لو عاوز تتاكد من انه رقم صحيح او لا. 3578 | عشان `Fixnum` تعتبر platform-dependent و التاكد من خلالها 3579 | هيرجع قيم مختلفة في حالات الاجهزة نوعها 32-bit و 64-bit 3580 | [[link](#integer-type-checking)] 3581 | 3582 | ```ruby 3583 | timestamp = Time.now.to_i 3584 | 3585 | # سئ 3586 | timestamp.is_a? Fixnum 3587 | timestamp.is_a? Bignum 3588 | 3589 | # جيد 3590 | timestamp.is_a? Integer 3591 | ``` 3592 | 3593 | * 3594 | بيفضل استخدام ال ranges لو كنت عاوز تطلع رقم عشوائي 3595 | بدل ما تستخدم فارق الاعداد الصحيحة, عشان هتبقي اوضح 3596 | تخيل اللي ال الزهر بيعمله. 3597 | [[link](#random-numbers)] 3598 | 3599 | ```ruby 3600 | # سئ 3601 | rand(6) + 1 3602 | 3603 | # جيد 3604 | rand(1..6) 3605 | ``` 3606 | 3607 | ## Strings 3608 | 3609 | * 3610 | بيفضل انك تستخدم string interpolation و string formatting بدل من string concatenation: 3611 | [[link](#string-interpolation)] 3612 | 3613 | ```ruby 3614 | # سئ 3615 | email_with_name = user.name + ' <' + user.email + '>' 3616 | 3617 | # جيد 3618 | email_with_name = "#{user.name} <#{user.email}>" 3619 | 3620 | # جيد 3621 | email_with_name = format('%s <%s>', user.name, user.email) 3622 | ``` 3623 | 3624 | * 3625 | اعتمد علي نوع واحد لم تيجي تعرف ال string بالنسبة لل quoting style. 3626 | هو في اتنين مشهورين في مجتمع الروبي, و الاتنين بنعتبرهم كويسين 3627 | و هو single quotes (الاختيار أ) و التاني double quotes (الاختيار ب). 3628 | [[link](#consistent-string-literals)] 3629 | 3630 | * **(الاختيار أ )** بيفضل ال single-quoted لما مبتكنش محتاج تعمل string interpolation 3631 | او الرموز الخاصة زي `\t`, `\n`, `'`, 3632 | وهكذا. 3633 | 3634 | ```ruby 3635 | # سئ 3636 | name = "Bozhidar" 3637 | 3638 | # جيد 3639 | name = 'Bozhidar' 3640 | ``` 3641 | 3642 | * **(الاختيار ب)** يفضل ال double-quotes طالما ال string بتاعك 3643 | مفيهوش `"` او اي رموز مميزة عاوز تظهرها علي اصلها. 3644 | 3645 | ```ruby 3646 | # سئ 3647 | name = 'Bozhidar' 3648 | 3649 | # جيد 3650 | name = "Bozhidar" 3651 | ``` 3652 | 3653 | طريقةالتعامل مع ال string في الدليل دا بتفضل الاختيار الاول. 3654 | 3655 | * 3656 | متستخدمش طريقة تعريف الحروف دي `?x`. 3657 | من ساعة روبي 1.9 و هي مستغني عنها 3658 | بس `?x` هتتحول ك `'x'` (عبارة عن string متعرف ب حرف واحد جواه). 3659 | [[link](#no-character-literals)] 3660 | 3661 | ```ruby 3662 | # سئ 3663 | char = ?c 3664 | 3665 | # جيد 3666 | char = 'c' 3667 | ``` 3668 | 3669 | * 3670 | متسيبش `{}` دي حوالين ال instance و global variables 3671 | عشان يتعمله interpolated جوا string. 3672 | [[link](#curlies-interpolate)] 3673 | 3674 | ```ruby 3675 | class Person 3676 | attr_reader :first_name, :last_name 3677 | 3678 | def initialize(first_name, last_name) 3679 | @first_name = first_name 3680 | @last_name = last_name 3681 | end 3682 | 3683 | # سئ - صح, بس مش واضحة 3684 | def to_s 3685 | "#@first_name #@last_name" 3686 | end 3687 | 3688 | # جيد 3689 | def to_s 3690 | "#{@first_name} #{@last_name}" 3691 | end 3692 | end 3693 | 3694 | $global = 0 3695 | # سئ 3696 | puts "$global = #$global" 3697 | 3698 | # جيد 3699 | puts "$global = #{$global}" 3700 | ``` 3701 | 3702 | * 3703 | متستخدمش Object#to_s` علي ال interpolated objects. 3704 | هي بتتعمل لوحدها كدا. 3705 | [[link](#no-to-s)] 3706 | 3707 | ```ruby 3708 | # سئ 3709 | message = "This is the #{result.to_s}." 3710 | 3711 | # جيد 3712 | message = "This is the #{result}." 3713 | ``` 3714 | 3715 | * 3716 | تجنب استخدام `String#+` لما تكون محتاج تكون داتا كبيرة. 3717 | في حين انك ممكن تستخدم `String#<<` للوصل بينهم في مكان 3718 | هي دايما اسرع من `String#+` اللي بتخليك كل مرة تصنع string object جداد. 3719 | [[link](#concat-strings)] 3720 | 3721 | ```ruby 3722 | # سئ 3723 | html = '' 3724 | html += '

Page title

' 3725 | 3726 | paragraphs.each do |paragraph| 3727 | html += "

#{paragraph}

" 3728 | end 3729 | 3730 | # جيد و اسرع 3731 | html = '' 3732 | html << '

Page title

' 3733 | 3734 | paragraphs.each do |paragraph| 3735 | html << "

#{paragraph}

" 3736 | end 3737 | ``` 3738 | 3739 | * 3740 | متستخدمش `String#gsub` في الحالات اللي ممكن تستخدم فيهاحاجات تانية اسرغ و متخصصه اكتر. 3741 | [[link](#dont-abuse-gsub)] 3742 | 3743 | ```ruby 3744 | url = 'http://example.com' 3745 | str = 'lisp-case-rules' 3746 | 3747 | # سئ 3748 | url.gsub('http://', 'https://') 3749 | str.gsub('-', '_') 3750 | 3751 | # جيد 3752 | url.sub('http://', 'https://') 3753 | str.tr('-', '_') 3754 | ``` 3755 | 3756 | * 3757 | لما تيجي تستخدم heredocs لل strings اللي بتاخد اكتر من سطر, 3758 | حط في اعتبارك انها بتحافظ علي المسافة الزيادة. 3759 | دا تطبيق كويس عشان تبطل تحط مسافات ملهاش لازمة. 3760 | [[link](#heredocs)] 3761 | 3762 | ```ruby 3763 | code = <<-END.gsub(/^\s+\|/, '') 3764 | |def test 3765 | | some_method 3766 | | other_method 3767 | |end 3768 | END 3769 | # => "def test\n some_method\n other_method\nend\n" 3770 | ``` 3771 | 3772 | * 3773 | استخدم طريقة الروبي 2.3 لل squiggly heredocs بشكل الطف ل strings اللي تاخد كذا سطر 3774 | [[link](#squiggly-heredocs)] 3775 | 3776 | ```ruby 3777 | # سئ - بيستخدم Powerpack String#strip_margin 3778 | code = <<-RUBY.strip_margin('|') 3779 | |def test 3780 | | some_method 3781 | | other_method 3782 | |end 3783 | RUBY 3784 | 3785 | # برضه سئ 3786 | code = <<-RUBY 3787 | def test 3788 | some_method 3789 | other_method 3790 | end 3791 | RUBY 3792 | 3793 | # جيد 3794 | code = <<~RUBY 3795 | def test 3796 | some_method 3797 | other_method 3798 | end 3799 | RUBY 3800 | ``` 3801 | 3802 | * 3803 | استخدم محددات تكون معبرة في ال heredocs . 3804 | محددتات تكون بتضيف معلومات قيمة عن المحتوي بتاع ال heredocs, 3805 | و ك حاجة حلوة تانية بعد محررات النصوص تقدر تسيب علامة علي الكود اللي خلال ال heredocs 3806 | لو هو مستخدم المحددات صح . 3807 | [[link](#heredoc-delimiters)] 3808 | 3809 | ```ruby 3810 | # سئ 3811 | code = <<~END 3812 | def foo 3813 | bar 3814 | end 3815 | END 3816 | 3817 | # جيد 3818 | code = <<~RUBY 3819 | def foo 3820 | bar 3821 | end 3822 | RUBY 3823 | 3824 | # good 3825 | code = <<~SUMMARY 3826 | An imposing black structure provides a connection between the past and 3827 | the future in this enigmatic adaptation of a short story by revered 3828 | sci-fi author Arthur C. Clarke. 3829 | SUMMARY 3830 | ``` 3831 | 3832 | ## الوقت و التاريخ 3833 | 3834 | * 3835 | بيفضل `Time.now` عن `Time.new` لما تكون عاوز تاخد الوقت الحالي للنظام. 3836 | [[link](#time-now)] 3837 | 3838 | * 3839 | متسخدمش `DateTime` الا لو كنت عاوز تاخد التقويم التاريخي معاك -- و لو عملت كدا 3840 | حدد بصراحة ال `start` ارجيومنت عشان توضح بالظبط انت عاوز ايه . 3841 | [[link](#no-datetime)] 3842 | 3843 | ```ruby 3844 | # سئ - استخدم DateTime للوقت بتاع دلوقتي 3845 | DateTime.now 3846 | 3847 | # جيد - استخدم Time للوقت دلوقتي 3848 | Time.now 3849 | 3850 | # سئ - استخدم DateTime للتوقيتات العصرية 3851 | DateTime.iso8601('2016-06-29') 3852 | 3853 | # جيد - استخدم Date للتوقيتات العصرية 3854 | Date.iso8601('2016-06-29') 3855 | # جيد - استخدم DateTime و معاها start argument للتاريخ القديم. 3856 | DateTime.iso8601('1751-04-23', Date::ENGLAND) 3857 | ``` 3858 | 3859 | ## التعبيرات العادية 3860 | 3861 | > بعض الناس, لما بتواجهم مشكلة بيفكر, 3862 | > "انا عارف, انا هستخدم التعبيرات العادية" دلوقتي بقي عنده مشكلتين.
3863 | > -- Jamie Zawinski 3864 | 3865 | * 3866 | متستخدمش التعبيرات العادية لو بتدور علي string في نص عادي: `string['text']` 3867 | [[link](#no-regexp-for-plaintext)] 3868 | 3869 | * 3870 | لتكوين بسيط انت ممكن تستخدم regexp مباشرة خلال string index. 3871 | [[link](#regexp-string-index)] 3872 | 3873 | ```ruby 3874 | match = string[/regexp/] # هات المحتوي اللي بيساوي ال regexp 3875 | first_group = string[/text(grp)/, 1] # هات امحتي من المجموعة الي ماسكها 3876 | string[/text (grp)/, 1] = 'replace' # string => 'text replace' 3877 | ``` 3878 | 3879 | * 3880 | استخدم مجموعات ال non-capturing لما متكونش هتستخدم ناتج ال captured. 3881 | [[link](#non-capturing-regexp)] 3882 | 3883 | ```ruby 3884 | # سئ 3885 | /(first|second)/ 3886 | 3887 | # جيد 3888 | /(?:first|second)/ 3889 | ``` 3890 | 3891 | * 3892 | متستخدمش متغيرات ال cryptic Perl-legacy للدلالة علي اخر مجموعة بتطابق ال regexp (`$1`, `$2`, وهكذا). 3893 | استخدم `Regexp.last_match(n)` بدلها. 3894 | [[link](#no-perl-regexp-last-matchers)] 3895 | 3896 | ```ruby 3897 | /(regexp)/ =~ string 3898 | ... 3899 | 3900 | # سئ 3901 | process $1 3902 | 3903 | # جيد 3904 | process Regexp.last_match(1) 3905 | ``` 3906 | 3907 | * 3908 | تجنب استخدام المجموعات المرقمة عشان بيبقي صعب متابعة محتواها. 3909 | ممكن تسمي مجموعات متسمية احسن منها . 3910 | [[link](#no-numbered-regexes)] 3911 | 3912 | ```ruby 3913 | # سئ 3914 | /(regexp)/ =~ string 3915 | # some code 3916 | process Regexp.last_match(1) 3917 | 3918 | # جيد 3919 | /(?regexp)/ =~ string 3920 | # some code 3921 | process meaningful_var 3922 | ``` 3923 | 3924 | * 3925 | ال Character classes عندهم بس قليل من الحروف اللي المفروض تهتم بيهم: 3926 | هم `^`, `-`, `\`, `]`, يبقي متتجنبش `.` او الاقواس في `[]`. 3927 | [[link](#limit-escapes)] 3928 | 3929 | * 3930 | خد بالك من `^` و `$` عشان هم بيعبروا عن بداية/نهاية السطر . مش بتاعت ال string. 3931 | لو عاوز تطتبق ال string كله استخدم `\A` و `\z` (متخليش `\Z` اللي هي بتساوي `/\n?\z/`). 3932 | [[link](#caret-and-dollar-regexp)] 3933 | 3934 | ```ruby 3935 | string = "some injection\nusername" 3936 | string[/^username$/] # متطابقة 3937 | string[/\Ausername\z/] # لا تطابق 3938 | ``` 3939 | 3940 | * 3941 | استخدم `x` في علامات ال regexps المعقدة . 3942 | دا هيخليك تعرف تقري كويس و تقدر تحط شوية تعليقات مفيدة. 3943 | بس خد بالك المسافات مبتتحسبش.ً 3944 | [[link](#comment-regexes)] 3945 | 3946 | ```ruby 3947 | regexp = / 3948 | start # some text 3949 | \s # white space char 3950 | (group) # first group 3951 | (?:alt1|alt2) # some alternation 3952 | end 3953 | /x 3954 | ``` 3955 | 3956 | * 3957 | للتبديل المعقد `sub`/`gsub` ممكن تستخدم مع بلوك او هاش. 3958 | [[link](#gsub-blocks)] 3959 | 3960 | ```ruby 3961 | words = 'foo bar' 3962 | words.sub(/f/, 'f' => 'F') # => 'Foo bar' 3963 | words.gsub(/\w+/) { |word| word.capitalize } # => 'Foo Bar' 3964 | ``` 3965 | 3966 | ## حرف النسبة المئوية 3967 | 3968 | * 3969 | استخدم `%()` (دي اختصار ل `%Q`) اللي بتشتغل علي ال لسطر واحد single-line 3970 | اليي بتبقي محتاجة حاجتين interpolation و انك تحط double-quotes . 3971 | في حالة تعدد السطور بيفضل ال heredocs. 3972 | [[link](#percent-q-shorthand)] 3973 | 3974 | ```ruby 3975 | # سئ (مفيش اي حاجة لل interpolation) 3976 | %(
Some text
) 3977 | # should be '
Some text
' 3978 | 3979 | # سئ (مفي double-quotes) 3980 | %(This is #{quality} style) 3981 | # المفروض تبقي "This is #{quality} style" 3982 | 3983 | # سئ (متعدد السطور) 3984 | %(
\n#{exclamation}\n
) 3985 | # المفروض تبقي heredoc. 3986 | 3987 | # جيد (محتاجة interpolation, عندها quotes,سطر واحد ) 3988 | %(#{name}) 3989 | ``` 3990 | 3991 | * 3992 | تجنب %() او اللي زيها بالظبط %q() طالما مش عندك الاتنيد دول `'` و `"` جوا ال string. 3993 | علامات ال string العادية اسهل للقراية و دايما مفضلة طالما مش عندك رموز كتيرة عاوز تبطل مفعولها 3994 | [[link](#percent-q)] 3995 | 3996 | ```ruby 3997 | # سئ 3998 | name = %q(Bruce Wayne) 3999 | time = %q(8 o'clock) 4000 | question = %q("What did you say?") 4001 | 4002 | # جيد 4003 | name = 'Bruce Wayne' 4004 | time = "8 o'clock" 4005 | question = '"What did you say?"' 4006 | quote = %q(

"What did you say?"

) 4007 | ``` 4008 | 4009 | * 4010 | استخدم `%r` فقط في التعبيرات العادية اللي بتساوي *علي الاقل* واحد من دا '/' . 4011 | [[link](#percent-r)] 4012 | 4013 | ```ruby 4014 | # سئ 4015 | %r{\s+} 4016 | 4017 | # جيد 4018 | %r{^/(.*)$} 4019 | %r{^/blog/2011/(.*)$} 4020 | ``` 4021 | 4022 | * 4023 | تجنب استخدام `%x` طالما مش هتبعت معاها امر معين 4024 | (و هي حاجة مستبعدة ل حد ما). 4025 | [[link](#percent-x)] 4026 | 4027 | ```ruby 4028 | # سئ 4029 | date = %x(date) 4030 | 4031 | # جيد 4032 | date = `date` 4033 | echo = %x(echo `date`) 4034 | ``` 4035 | 4036 | * 4037 | تجنب استخدام `%s`. 4038 | يبدو ان المجتمع قرر `:"some string"` الطريقة المفضلة عشان تعمل symbol 4039 | مع وجود مسافات فاضية جواها . 4040 | [[link](#percent-s)] 4041 | 4042 | * 4043 | استخدم الاقواس الانسب للعلامة المئوية. 4044 | [[link](#percent-literal-braces)] 4045 | - `()` لتعريف ال string (`%q`, `%Q`). 4046 | - `[]` لتعريف ال array (`%w`, `%i`, `%W`, `%I`) دا غير انها بتشتغل مع علامة الاراي العادية. 4047 | - `{}` ل اعريف ال regexp (`%r`) لما بيكون الاقواس موجودة جوا التعبير . 4048 | و لهاذا السبب الحرف الاقل شيوعا مع ال `{` هو دايما افضل delimiter في حالة ال `%r`. 4049 | - `()`لجميع العلامات التانية (زي `%s`, `%x`) 4050 | 4051 | ```ruby 4052 | # سئ 4053 | %q{"Test's king!", John said.} 4054 | 4055 | # جيد 4056 | %q("Test's king!", John said.) 4057 | 4058 | # سئ 4059 | %w(one two three) 4060 | %i(one two three) 4061 | 4062 | # جيد 4063 | %w[one two three] 4064 | %i[one two three] 4065 | 4066 | # سئ 4067 | %r((\w+)-(\d+)) 4068 | %r{\w{1,2}\d{2,5}} 4069 | 4070 | # جيد 4071 | %r{(\w+)-(\d+)} 4072 | %r|\w{1,2}\d{2,5}| 4073 | ``` 4074 | 4075 | ## ميتابروجرامينج 4076 | 4077 | * 4078 | تجنب ال metaprogramming اللي ملهاش لازمة. 4079 | [[link](#no-needless-metaprogramming)] 4080 | 4081 | * 4082 | متلعبش في المكتبات الاساسية في اللغة لما تيجي تعمل حاجة جديدة. 4083 | (متعملش زي ال monkey-patch معاهم.) 4084 | [[link](#no-monkey-patching)] 4085 | 4086 | * 4087 | البلوك اللي بتعمل من `class_eval` بيفضل ل ال string-interpolated . 4088 | [[link](#block-class-eval)] 4089 | 4090 | - لما تيجي تستخدم نموذج ال string-interpolated, دايما وفر `__FILE__` و `__LINE__` 4091 | , عشان اقواسك يبقوا اكتر منطقية: 4092 | 4093 | ```ruby 4094 | class_eval 'def use_relative_model_naming?; true; end', __FILE__, __LINE__ 4095 | ``` 4096 | 4097 | - `define_method` بيفضل ل `class_eval{ def ... }` 4098 | 4099 | * 4100 | لما تيجي تستخدم `class_eval` (او اي `eval` تاني ) و معاه string interpolation, 4101 | حط معاه بلوك من التعليقات يوضح المظهر بتاع ال interpolated (مثال متاخد من كود الرايلز) 4102 | [[link](#eval-comment-docs)] 4103 | 4104 | ```ruby 4105 | # من activesupport/lib/active_support/core_ext/string/output_safety.rb 4106 | UNSAFE_STRING_METHODS.each do |unsafe_method| 4107 | if 'String'.respond_to?(unsafe_method) 4108 | class_eval <<-EOT, __FILE__, __LINE__ + 1 4109 | def #{unsafe_method}(*params, &block) # def capitalize(*params, &block) 4110 | to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block) 4111 | end # end 4112 | 4113 | def #{unsafe_method}!(*params) # def capitalize!(*params) 4114 | @dirty = true # @dirty = true 4115 | super # super 4116 | end # end 4117 | EOT 4118 | end 4119 | end 4120 | ``` 4121 | 4122 | * 4123 | تجنب استخدام ال `method_missing` في ال ميتابروجرايمنج عشان ال backtraces بيبقي فوضوي, 4124 | التصرف مبيبقي مرصود ف ال `#methods` و الخطاء في كتابة اسم دالة هيشغله بهدوء, زي `nukes.launch_state = false`. 4125 | اعتبر استخدام delegation, proxy, او `define_method` كبديل. 4126 | لو لازمك يعني استخدام `method_missing`: 4127 | [[link](#no-method-missing)] 4128 | 4129 | - خليك متأكد ان [و برضه معرف `respond_to_missing?`](http://blog.marc-andre.ca/2010/11/methodmissing-politely.html) 4130 | - اسمك الدوال اللي بدايتها محددة جدا, زي `find_by_*` -- خلي كودك مؤكد قدر المستطاع. 4131 | - كلم `super` في اخر سطر عندك 4132 | - خلي التاكيد علي , الدوال غير سحرية: 4133 | 4134 | ```ruby 4135 | # سئ 4136 | def method_missing?(meth, *params, &block) 4137 | if /^find_by_(?.*)/ =~ meth 4138 | # ... lots of code to do a find_by 4139 | else 4140 | super 4141 | end 4142 | end 4143 | 4144 | # جيد 4145 | def method_missing?(meth, *params, &block) 4146 | if /^find_by_(?.*)/ =~ meth 4147 | find_by(prop, *params, &block) 4148 | else 4149 | super 4150 | end 4151 | end 4152 | 4153 | # افضل الموجودين, علي الرغم , من انك ه define_method مع كل attribute هتلاقيه متعرف 4154 | ``` 4155 | 4156 | * 4157 | بيفضل `public_send` عن `send` عشان متتلغبتش مع ال `private`/`protected` المتاحة . 4158 | [[link](#prefer-public-send)] 4159 | 4160 | ```ruby 4161 | # احنا عندنا منظومة من ال ActiveModel و اللي بتضمن concern Activatable 4162 | module Activatable 4163 | extend ActiveSupport::Concern 4164 | 4165 | included do 4166 | before_create :create_token 4167 | end 4168 | 4169 | private 4170 | 4171 | def reset_token 4172 | # شوية كود هنا 4173 | end 4174 | 4175 | def create_token 4176 | # شوية كود هنا 4177 | end 4178 | 4179 | def activate! 4180 | # شوية كود هنا 4181 | end 4182 | end 4183 | 4184 | class Organization < ActiveRecord::Base 4185 | include Activatable 4186 | end 4187 | 4188 | linux_organization = Organization.find(...) 4189 | # سئ - بيخض علي الخصوصيات 4190 | linux_organization.send(:reset_token) 4191 | # جيد - هيرجع استثناء 4192 | linux_organization.public_send(:reset_token) 4193 | ``` 4194 | 4195 | * 4196 | بيفضل `__send__` عن `send` لانها ممكن تلغبط مع دالة موجودة اصلا. 4197 | [[link](#prefer-__send__)] 4198 | 4199 | ```ruby 4200 | require 'socket' 4201 | 4202 | u1 = UDPSocket.new 4203 | u1.bind('127.0.0.1', 4913) 4204 | u2 = UDPSocket.new 4205 | u2.connect('127.0.0.1', 4913) 4206 | # مش هتبعت حالة للعنصر اللي مفروض يستلم. 4207 | # في المقابل هتبعتها عن طريق ال UDP socket. 4208 | u2.send :sleep, 0 4209 | #كدا فعلا هتبعت للعنصر اللي مفروض يستلم. 4210 | u2.__send__ ... 4211 | ``` 4212 | 4213 | ## متفرقات 4214 | 4215 | * 4216 | اكتب `ruby -w` لكود أمن. 4217 | [[link](#always-warn)] 4218 | 4219 | * 4220 | تجنب ال hashes ك باراميتر اختيارية. الدالة بتاعتك بتعمل حاجات كتير؟ 4221 | (معرف ال Object استثناء للقاعدة دي). 4222 | [[link](#no-optional-hash-params)] 4223 | 4224 | * 4225 | تجنب الدوال اللي حجمها اطول من 10 سطور, لو عاوز تبقي مثالي اوي المفروض تبقي اصغر من 10 سطور. 4226 | السطور الفاضية مش بتساهم في موضوع السطور دا. 4227 | [[link](#short-methods)] 4228 | 4229 | * 4230 | تجنب ال parameter lists اطول من تلاتة او اربعة براميتر. 4231 | [[link](#too-many-params)] 4232 | 4233 | * 4234 | لو انت فعلا محتاج دالة "global"و حطهم ف ال kenral و اعملهم private. 4235 | [[link](#private-global-methods)] 4236 | 4237 | * 4238 | استخدم متغيرات ال module نوع instance بدال ما تستخدم ال global variables. 4239 | [[link](#instance-vars)] 4240 | 4241 | ```ruby 4242 | # سئ 4243 | $foo_bar = 1 4244 | 4245 | # جيد 4246 | module Foo 4247 | class << self 4248 | attr_accessor :bar 4249 | end 4250 | end 4251 | 4252 | Foo.bar = 1 4253 | ``` 4254 | 4255 | * 4256 | استخدم `OptionParser` ل تحليل الاوامر الاختيارية المعقدة و `ruby -s` لل الاوامر التافهة. 4257 | [[link](#optionparser)] 4258 | 4259 | * 4260 | اكت كود بطريقة وظيفية و تجنب ال mutation لما تكون اكثر منطقية. 4261 | [[link](#functional-code)] 4262 | 4263 | * 4264 | متعملش mutate parameters طالما دا هدف الدالة . 4265 | [[link](#no-param-mutations)] 4266 | 4267 | * 4268 | تجنب اكتر من تلت مستوايات من البلوك جوا بعض. 4269 | [[link](#three-is-the-number-thou-shalt-count)] 4270 | 4271 | * 4272 | 4273 | خلي ثابت علي مبداك. في عالم مثالي , خليك ثابت علي الدليل دا. 4274 | [[link](#be-consistent)] 4275 | 4276 | * 4277 | استخدم المنطق. 4278 | [[link](#common-sense)] 4279 | 4280 | ## الادوات 4281 | 4282 | في شوية ادوات تساعد تفحص كود الروبي بتاعك اوتوماتيك كدا بدل الدليل دا. 4283 | 4284 | ### روبوكب 4285 | [RuboCop][] هو بيفحص ل شكل كود الروبي و المرجع بتاعه الدليل دا. 4286 | روبوكب شامل جزء مش قليل من الدليل دا, 4287 | بيدعم الاتنين MRI 1.9 و MRI 2.0 و عنده قابليه للدمج كويس مع Emacs. 4288 | 4289 | ### RubyMine 4290 | 4291 | [RubyMine](http://www.jetbrains.com/ruby/) دا محلل الكود بتاعه 4292 | [جزئيا بيعتمد](http://confluence.jetbrains.com/display/RUBYDEV/RubyMine+Inspections) 4293 | علي الدليل دا. 4294 | 4295 | # المشاركة 4296 | 4297 | الدليل دا لسة شغالين عليه; بعض القواعد ناقصها امثلة, 4298 | و بعض القواعد معندهاش امثلة تفصله بشكل واضح و كافي. 4299 | لتحسين القواعد دي بطريقة عظيمة (و طريقة سهلة) لمساعدة مجتمع الروبي! 4300 | في الوقت الحالي المشاكل دي (نتمني) تتصلح انت بس حطهم في بالك دلوقتي. 4301 | مفيش حاجة في الدليل دا مكتوبة علي حتة حجر, دي رغبتي في الشغل مع كل من الناس المهتمة بوجود طريقة لكتابة الروبي 4302 | عشان كدا احنا نقدر نعمل دليل هيعود بالنفع علي كل مجتمع الروبي. 4303 | 4304 | خد راحتك خالص انك تبلغ بمشكلة او تضيف تغيير في تحسينات. و شكرا مقدما علي تعبك دا 4305 | انت بره تقدر تساعد في البروجكت (و روبوكب) بالفلوس عن طريق [Gratipay](https://gratipay.com/~bbatsov/). 4306 | [![Support via Gratipay](https://cdn.rawgit.com/gratipay/gratipay-badge/2.3.0/dist/gratipay.png)](https://gratipay.com/~bbatsov/) 4307 | 4308 | 4309 | ## ازاي تشارك؟ 4310 | 4311 | بمنتهي السهولة, اتبع الخطوات دي [contribution guidelines](https://github.com/HassanTC/ruby-style-guide/blob/master/CONTRIBUTING.md). 4312 | 4313 | # الرخصة 4314 | 4315 | ![Creative Commons License](http://i.creativecommons.org/l/by/3.0/88x31.png) 4316 | العمل دا بينطبق عليه الرخصة دي [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/deed.en_US) 4317 | 4318 | # انشر الكلمة 4319 | 4320 | الدليل اللي موجود بسبب ال مجتمع قيمته قليلة لمجتمع ميعرفش عن وجوده. 4321 | اكتب عنه ف تويتر، انشره لزمايلك و صحابك. 4322 | كل كومنت و اقتراح و رايي بيخلي الدليل احسن 4323 | واحنا عايزين احسن دليل ممكن، مش كدا؟ 4324 | علي وضعك,
4325 | [Bozhidar](https://twitter.com/bbatsov) 4326 | 4327 | [PEP-8]: https://www.python.org/dev/peps/pep-0008/ 4328 | [rails-style-guide]: https://github.com/bbatsov/rails-style-guide 4329 | [pickaxe]: https://pragprog.com/book/ruby4/programming-ruby-1-9-2-0 4330 | [trpl]: http://www.amazon.com/Ruby-Programming-Language-David-Flanagan/dp/0596516177 4331 | [Pandoc]: http://pandoc.org/ 4332 | [RuboCop]: https://github.com/bbatsov/rubocop 4333 | [rdoc]: http://rdoc.sourceforge.net/doc/ 4334 | --------------------------------------------------------------------------------