├── .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 | [](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 | 
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 |
--------------------------------------------------------------------------------