-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathactive_support_core_extensions.html
3461 lines (3057 loc) · 188 KB
/
active_support_core_extensions.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Active Support 核心扩展 — Ruby on Rails 指南</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shCore.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shThemeRailsGuides.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/fixes.css" />
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body class="guide">
<div id="topNav">
<div class="wrapper">
<strong class="more-info-label">更多内容 <a href="http://rubyonrails.org/">rubyonrails.org:</a> </strong>
<span class="red-button more-info-button">
更多内容
</span>
<ul class="more-info-links s-hidden">
<li class="more-info"><a href="http://rubyonrails.org/">综览</a></li>
<li class="more-info"><a href="http://rubyonrails.org/download">下载</a></li>
<li class="more-info"><a href="http://rubyonrails.org/deploy">部署</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">源码</a></li>
<li class="more-info"><a href="http://rubyonrails.org/screencasts">视频</a></li>
<li class="more-info"><a href="http://rubyonrails.org/documentation">文件</a></li>
<li class="more-info"><a href="http://rubyonrails.org/community">社群</a></li>
<li class="more-info"><a href="http://weblog.rubyonrails.org/">Blog</a></li>
</ul>
</div>
</div>
<div id="header">
<div class="wrapper clearfix">
<h1><a href="index.html" title="回首页">Guides.rubyonrails.org</a></h1>
<ul class="nav">
<li><a class="nav-item" href="index.html">首页</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">指南目录</a>
<div id="guides" class="clearfix" style="display: none;">
<hr />
<dl class="L">
<dt>入门</dt>
<dd><a href="getting_started.html">Rails 入门</a></dd>
<dt>模型</dt>
<dd><a href="active_record_basics.html">Active Record 基础</a></dd>
<dd><a href="active_record_migrations.html">Active Record 数据库迁移</a></dd>
<dd><a href="active_record_validations.html">Active Record 数据验证</a></dd>
<dd><a href="active_record_callbacks.html">Active Record 回调</a></dd>
<dd><a href="association_basics.html">Active Record 关联</a></dd>
<dd><a href="active_record_querying.html">Active Record 查询</a></dd>
<dt>视图</dt>
<dd><a href="layouts_and_rendering.html">Rails 布局和视图渲染</a></dd>
<dd><a href="form_helpers.html">Action View 表单帮助方法</a></dd>
<dt>控制器</dt>
<dd><a href="action_controller_overview.html">Action Controller 简介</a></dd>
<dd><a href="routing.html">Rails 路由全解</a></dd>
</dl>
<dl class="R">
<dt>深入</dt>
<dd><a href="active_support_core_extensions.html">Active Support 核心扩展</a></dd>
<dd><a href="i18n.html">Rails 国际化 API</a></dd>
<dd><a href="action_mailer_basics.html">Action Mailer 基础</a></dd>
<dd><a href="active_job_basics.html">Active Job 基础</a></dd>
<dd><a href="security.html">Rails 安全指南</a></dd>
<dd><a href="debugging_rails_applications.html">调试 Rails 程序</a></dd>
<dd><a href="configuring.html">设置 Rails 程序</a></dd>
<dd><a href="command_line.html">Rails 命令行</a></dd>
<dd><a href="asset_pipeline.html">Asset Pipeline</a></dd>
<dd><a href="working_with_javascript_in_rails.html">在 Rails 中使用 JavaScript</a></dd>
<dd><a href="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</a></dd>
<dt>扩展 Rails</dt>
<dd><a href="rails_on_rack.html">Rails on Rack</a></dd>
<dd><a href="generators.html">客制与新建 Rails 产生器</a></dd>
<dd><a href="rails_application_templates.html">Rails 应用程式模版</a></dd>
<dt>贡献 Ruby on Rails</dt>
<dd><a href="contributing_to_ruby_on_rails.html">贡献 Ruby on Rails</a></dd>
<dd><a href="api_documentation_guidelines.html">API 文件准则</a></dd>
<dd><a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南准则</a></dd>
<dt>维护方针</dt>
<dd><a href="maintenance_policy.html">维护方针</a></dd>
<dt>发布记</dt>
<dd><a href="upgrading_ruby_on_rails.html">升级 Ruby on Rails</a></dd>
<dd><a href="4_2_release_notes.html">Ruby on Rails 4.2 发布记</a></dd>
<dd><a href="4_1_release_notes.html">Ruby on Rails 4.1 发布记</a></dd>
<dd><a href="4_0_release_notes.html">Ruby on Rails 4.0 发布记</a></dd>
<dd><a href="3_2_release_notes.html">Ruby on Rails 3.2 发布记</a></dd>
<dd><a href="3_1_release_notes.html">Ruby on Rails 3.1 发布记</a></dd>
<dd><a href="3_0_release_notes.html">Ruby on Rails 3.0 发布记</a></dd>
<dd><a href="2_3_release_notes.html">Ruby on Rails 2.3 发布记</a></dd>
<dd><a href="2_2_release_notes.html">Ruby on Rails 2.2 发布记</a></dd>
</dl>
</div>
</li>
<!-- <li><a class="nav-item" href="//github.com/docrails-tw/wiki">参与翻译</a></li> -->
<li><a class="nav-item" href="https://github.com/ruby-china/guides/blob/master/CONTRIBUTING.md">贡献</a></li>
<li><a class="nav-item" href="credits.html">致谢</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">指南目录</option>
<optgroup label="入门">
<option value="getting_started.html">Rails 入门</option>
</optgroup>
<optgroup label="模型">
<option value="active_record_basics.html">Active Record 基础</option>
<option value="active_record_migrations.html">Active Record 数据库迁移</option>
<option value="active_record_validations.html">Active Record 数据验证</option>
<option value="active_record_callbacks.html">Active Record 回调</option>
<option value="association_basics.html">Active Record 关联</option>
<option value="active_record_querying.html">Active Record 查询</option>
</optgroup>
<optgroup label="视图">
<option value="layouts_and_rendering.html">Rails 布局和视图渲染</option>
<option value="form_helpers.html">Action View 表单帮助方法</option>
</optgroup>
<optgroup label="控制器">
<option value="action_controller_overview.html">Action Controller 简介</option>
<option value="routing.html">Rails 路由全解</option>
</optgroup>
<optgroup label="深入">
<option value="active_support_core_extensions.html">Active Support 核心扩展</option>
<option value="i18n.html">Rails 国际化 API</option>
<option value="action_mailer_basics.html">Action Mailer 基础</option>
<option value="active_job_basics.html">Active Job 基础</option>
<option value="security.html">Rails 安全指南</option>
<option value="debugging_rails_applications.html">调试 Rails 程序</option>
<option value="configuring.html">设置 Rails 程序</option>
<option value="command_line.html">Rails 命令行</option>
<option value="asset_pipeline.html">Asset Pipeline</option>
<option value="working_with_javascript_in_rails.html">在 Rails 中使用 JavaScript</option>
<option value="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</option>
</optgroup>
<optgroup label="扩展 Rails">
<option value="rails_on_rack.html">Rails on Rack</option>
<option value="generators.html">客制与新建 Rails 产生器</option>
<option value="rails_application_templates.html">Rails 应用程式模版</option>
</optgroup>
<optgroup label="贡献 Ruby on Rails">
<option value="contributing_to_ruby_on_rails.html">贡献 Ruby on Rails</option>
<option value="api_documentation_guidelines.html">API 文件准则</option>
<option value="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南准则</option>
</optgroup>
<optgroup label="维护方针">
<option value="maintenance_policy.html">维护方针</option>
</optgroup>
<optgroup label="发布记">
<option value="upgrading_ruby_on_rails.html">升级 Ruby on Rails</option>
<option value="4_2_release_notes.html">Ruby on Rails 4.2 发布记</option>
<option value="4_1_release_notes.html">Ruby on Rails 4.1 发布记</option>
<option value="4_0_release_notes.html">Ruby on Rails 4.0 发布记</option>
<option value="3_2_release_notes.html">Ruby on Rails 3.2 发布记</option>
<option value="3_1_release_notes.html">Ruby on Rails 3.1 发布记</option>
<option value="3_0_release_notes.html">Ruby on Rails 3.0 发布记</option>
<option value="2_3_release_notes.html">Ruby on Rails 2.3 发布记</option>
<option value="2_2_release_notes.html">Ruby on Rails 2.2 发布记</option>
</optgroup>
</select>
</li>
</ul>
</div>
</div>
</div>
<hr class="hide" />
<div id="feature">
<div class="wrapper">
<h2>Active Support 核心扩展</h2><p>Active Support 作为 Ruby on Rails 的一个组件,可以用来添加 Ruby 语言扩展、工具集以及其他这类事物。</p><p>它从语言的层面上进行了强化,既可起效于一般 Rails 程序开发,又能增强 Ruby on Rails 框架自身。</p><p>读完本文,你将学到:</p>
<ul>
<li>核心扩展是什么。</li>
<li>如何加载全部扩展。</li>
<li>如何恰如其分的选出你需要的扩展。</li>
<li>Active Support 都提供了哪些功能。</li>
</ul>
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
<li>
<a href="#%E5%A6%82%E4%BD%95%E5%8A%A0%E8%BD%BD%E6%A0%B8%E5%BF%83%E6%89%A9%E5%B1%95">如何加载核心扩展</a>
<ul>
<li><a href="#%E5%8D%95%E7%8B%AC%E7%9A%84-active-support">单独的 Active Support</a></li>
<li><a href="#ruby-on-rails-%E7%A8%8B%E5%BA%8F%E9%87%8C%E7%9A%84-active-support">Ruby on Rails 程序里的 Active Support</a></li>
</ul>
</li>
<li>
<a href="#%E6%89%80%E6%9C%89%E5%AF%B9%E8%B1%A1%E9%83%BD%E5%8F%AF%E7%94%A8%E7%9A%84%E6%89%A9%E5%B1%95">所有对象都可用的扩展</a>
<ul>
<li><a href="#blank-questionmark-and-present-questionmark"><code>blank?</code> and <code>present?</code></a></li>
<li><a href="#presence"><code>presence</code></a></li>
<li><a href="#duplicable-questionmark"><code>duplicable?</code></a></li>
<li><a href="#deep_dup"><code>deep_dup</code></a></li>
<li><a href="#try"><code>try</code></a></li>
<li><a href="#class_eval(*args,-&block)"><code>class_eval(*args, &block)</code></a></li>
<li><a href="#acts_like-questionmark(duck)"><code>acts_like?(duck)</code></a></li>
<li><a href="#to_param"><code>to_param</code></a></li>
<li><a href="#to_query"><code>to_query</code></a></li>
<li><a href="#with_options"><code>with_options</code></a></li>
<li><a href="#json-%E6%94%AF%E6%8C%81">JSON 支持</a></li>
<li><a href="#%E5%AE%9E%E4%BE%8B%E5%8F%98%E9%87%8F">实例变量</a></li>
<li><a href="#silencing-warnings,-streams,-%E5%92%8C-exceptions">Silencing Warnings, Streams, 和 Exceptions</a></li>
<li><a href="#in-questionmark"><code>in?</code></a></li>
</ul>
</li>
<li>
<a href="#%E5%AF%B9module%E7%9A%84%E6%89%A9%E5%B1%95">对<code>Module</code>的扩展</a>
<ul>
<li><a href="#alias_method_chain"><code>alias_method_chain</code></a></li>
<li><a href="#%E5%B1%9E%E6%80%A7">属性</a></li>
<li><a href="#%E5%AF%B9module%E7%9A%84%E6%89%A9%E5%B1%95-parents">Parents</a></li>
<li><a href="#%E5%B8%B8%E9%87%8F">常量</a></li>
<li><a href="#reachable">Reachable</a></li>
<li><a href="#anonymous">Anonymous</a></li>
<li><a href="#method-delegation">Method Delegation</a></li>
<li><a href="#redefining-methods">Redefining Methods</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-class">Extensions to <code>Class</code></a>
<ul>
<li><a href="#class-attributes">Class Attributes</a></li>
<li><a href="#subclasses-&-descendants">Subclasses & Descendants</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-string">Extensions to <code>String</code></a>
<ul>
<li><a href="#output-safety">Output Safety</a></li>
<li><a href="#remove"><code>remove</code></a></li>
<li><a href="#squish"><code>squish</code></a></li>
<li><a href="#truncate"><code>truncate</code></a></li>
<li><a href="#inquiry"><code>inquiry</code></a></li>
<li><a href="#starts_with-questionmark-and-ends_with-questionmark"><code>starts_with?</code> and <code>ends_with?</code></a></li>
<li><a href="#strip_heredoc"><code>strip_heredoc</code></a></li>
<li><a href="#indent"><code>indent</code></a></li>
<li><a href="#access">Access</a></li>
<li><a href="#inflections">Inflections</a></li>
<li><a href="#extensions-to-string-conversions">Conversions</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-numeric">Extensions to <code>Numeric</code></a>
<ul>
<li><a href="#bytes">Bytes</a></li>
<li><a href="#time">Time</a></li>
<li><a href="#formatting">Formatting</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-integer">Extensions to <code>Integer</code></a>
<ul>
<li><a href="#multiple_of-questionmark"><code>multiple_of?</code></a></li>
<li><a href="#ordinal"><code>ordinal</code></a></li>
<li><a href="#ordinalize"><code>ordinalize</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-bigdecimal">Extensions to <code>BigDecimal</code></a>
<ul>
<li><a href="#extensions-to-bigdecimal-to_s"><code>to_s</code></a></li>
<li><a href="#extensions-to-bigdecimal-to_formatted_s"><code>to_formatted_s</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-enumerable">Extensions to <code>Enumerable</code></a>
<ul>
<li><a href="#sum"><code>sum</code></a></li>
<li><a href="#index_by"><code>index_by</code></a></li>
<li><a href="#many-questionmark"><code>many?</code></a></li>
<li><a href="#exclude-questionmark"><code>exclude?</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-array">Extensions to <code>Array</code></a>
<ul>
<li><a href="#accessing">Accessing</a></li>
<li><a href="#adding-elements">Adding Elements</a></li>
<li><a href="#options-extraction">Options Extraction</a></li>
<li><a href="#extensions-to-array-conversions">Conversions</a></li>
<li><a href="#wrapping">Wrapping</a></li>
<li><a href="#duplicating">Duplicating</a></li>
<li><a href="#grouping">Grouping</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-hash">Extensions to <code>Hash</code></a>
<ul>
<li><a href="#extensions-to-hash-conversions">Conversions</a></li>
<li><a href="#merging">Merging</a></li>
<li><a href="#deep-duplicating">Deep duplicating</a></li>
<li><a href="#working-with-keys">Working with Keys</a></li>
<li><a href="#slicing">Slicing</a></li>
<li><a href="#extracting">Extracting</a></li>
<li><a href="#indifferent-access">Indifferent Access</a></li>
<li><a href="#compacting">Compacting</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-regexp">Extensions to <code>Regexp</code></a>
<ul>
<li><a href="#multiline-questionmark"><code>multiline?</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-range">Extensions to <code>Range</code></a>
<ul>
<li><a href="#extensions-to-range-to_s"><code>to_s</code></a></li>
<li><a href="#include-questionmark"><code>include?</code></a></li>
<li><a href="#overlaps-questionmark"><code>overlaps?</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-proc">Extensions to <code>Proc</code></a>
<ul>
<li><a href="#bind"><code>bind</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-date">Extensions to <code>Date</code></a>
<ul>
<li><a href="#extensions-to-date-calculations">Calculations</a></li>
<li><a href="#extensions-to-date-conversions">Conversions</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-datetime">Extensions to <code>DateTime</code></a>
<ul>
<li><a href="#extensions-to-datetime-calculations">Calculations</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-time">Extensions to <code>Time</code></a>
<ul>
<li><a href="#calculations">Calculations</a></li>
<li><a href="#time-constructors">Time Constructors</a></li>
</ul>
</li>
<li>
<a href="#extensions-to-file">Extensions to <code>File</code></a>
<ul>
<li><a href="#atomic_write"><code>atomic_write</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-marshal">Extensions to <code>Marshal</code></a>
<ul>
<li><a href="#load"><code>load</code></a></li>
</ul>
</li>
<li>
<a href="#extensions-to-logger">Extensions to <code>Logger</code></a>
<ul>
<li><a href="#around_%5Blevel%5D"><code>around_[level]</code></a></li>
<li><a href="#silence"><code>silence</code></a></li>
<li><a href="#datetime_format="><code>datetime_format=</code></a></li>
</ul>
</li>
<li><a href="#extensions-to-nameerror">Extensions to <code>NameError</code></a></li>
<li><a href="#extensions-to-loaderror">Extensions to <code>LoadError</code></a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="如何加载核心扩展">1 如何加载核心扩展</h3><h4 id="单独的-active-support">1.1 单独的 Active Support</h4><p>为了使初始空间尽可能干净,默认情况下 Active Support 什么都不加载。它被拆分成许多小组件,这样一来你便可以只加载自己需要的那部分,同时它也提供了一系列便捷入口使你很容易加载相关的扩展,甚至把全部扩展都加载进来。</p><p>因而,像下面这样只简单用一个 require:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
require 'active_support'
</pre>
</div>
<p>对象会连<code>blank?</code>都没法响应。让我们来看下该如何加载它的定义。</p><h5 id="选出合适的定义">1.1.1 选出合适的定义</h5><p>找到<code>blank?</code>最轻便的方法就是直接找出定义它的那个文件。</p><p>对于每一个定义在核心扩展里的方法,本指南都会注明此方法定义于何处。例如这里提到的<code>blank?</code>,会像这样注明:</p><div class="note"><p>定义于 <code>active_support/core_ext/object/blank.rb</code>。</p></div><p>这意味着你可以像下面这样 require 它:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
require 'active_support'
require 'active_support/core_ext/object/blank'
</pre>
</div>
<p>Active Support 经过了严格的修订,确保选定的文件只会加载必要的依赖,若没有则不加载。</p><h5 id="加载一组核心扩展">1.1.2 加载一组核心扩展</h5><p>接下来加载<code>Object</code>下的全部扩展。一般来说,想加载<code>SomeClass</code>下的全部可用扩展,只需加载<code>active_support/core_ext/some_class</code>即可。</p><p>所以,若要加载<code>Object</code>下的全部扩展(包含<code>blank?</code>):</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
require 'active_support'
require 'active_support/core_ext/object'
</pre>
</div>
<h5 id="加载全部核心扩展">1.1.3 加载全部核心扩展</h5><p>你可能更倾向于加载全部核心扩展,有一个文件能办到:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
require 'active_support'
require 'active_support/core_ext'
</pre>
</div>
<h5 id="加载全部-active-support">1.1.4 加载全部 Active Support</h5><p>最后,如果你想要 Active Support 的全部内容,只需:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
require 'active_support/all'
</pre>
</div>
<p>这样做并不会把整个 Active Support 预加载到内存里,鉴于<code>autoload</code>的机制,其只有在真正用到时才会加载。</p><h4 id="ruby-on-rails-程序里的-active-support">1.2 Ruby on Rails 程序里的 Active Support</h4><p>除非把<code>config.active_support.bare</code>设置为 true, 否则 Ruby on Rails 的程序会加载全部的 Active Support。如此一来,程序只会加载框架为自身需要挑选出来的扩展,同时也可像上文所示,可以从任何级别加载特定扩展。</p><h3 id="所有对象都可用的扩展">2 所有对象都可用的扩展</h3><h4 id="blank-questionmark-and-present-questionmark">2.1 <code>blank?</code> and <code>present?</code>
</h4><p>以下各值在 Rails 程序里都看作 blank。</p>
<ul>
<li><p><code>nil</code> 和 <code>false</code>,</p></li>
<li><p>只包含空白的字符串(参照下文注释),</p></li>
<li><p>空的数组和散列表</p></li>
<li><p>任何其他能响应 <code>empty?</code> 方法且为空的对象。</p></li>
</ul>
<div class="info"><p>判断字符串是否为空依据了 Unicode-aware 字符类 <code>[:space:]</code>,所以例如 U+2029(段落分隔符)这种会被当作空白。</p></div><div class="warning"><p>注意这里没有提到数字。通常来说,0和0.0都<strong>不是</strong>blank。</p></div><p>例如,<code>ActionController::HttpAuthentication::Token::ControllerMethods</code>里的一个方法使用了<code>blank?</code>来检验 token 是否存在。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def authenticate(controller, &login_procedure)
token, options = token_and_options(controller.request)
unless token.blank?
login_procedure.call(token, options)
end
end
</pre>
</div>
<p><code>present?</code> 方法等同于 <code>!blank?</code>, 下面的例子出自<code>ActionDispatch::Http::Cache::Response</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def set_conditional_cache_control!
return if self["Cache-Control"].present?
...
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/blank.rb</code>.</p></div><h4 id="presence">2.2 <code>presence</code>
</h4><p><code>presence</code>方法如果满足<code>present?</code>则返回调用者,否则返回<code>nil</code>。它适用于下面这种情况:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
host = config[:host].presence || 'localhost'
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/blank.rb</code>.</p></div><h4 id="duplicable-questionmark">2.3 <code>duplicable?</code>
</h4><p>A few fundamental objects in Ruby are singletons. For example, in the whole life of a program the integer 1 refers always to the same instance:
Ruby 里有些基本对象是单例的。比如,在整个程序的生命周期里,数字1永远指向同一个实例。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
1.object_id # => 3
Math.cos(0).to_i.object_id # => 3
</pre>
</div>
<p>因而,这些对象永远没法用<code>dup</code>或<code>clone</code>复制。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
true.dup # => TypeError: can't dup TrueClass
</pre>
</div>
<p>有些数字虽然不是单例的,但也同样无法复制:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
0.0.clone # => allocator undefined for Float
(2**1024).clone # => allocator undefined for Bignum
</pre>
</div>
<p>Active Support 提供了 <code>duplicable?</code> 方法来判断一个对象是否能够被复制:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
"foo".duplicable? # => true
"".duplicable? # => true
0.0.duplicable? # => false
false.duplicable? # => false
</pre>
</div>
<p>根据定义,所有的对象的<code>duplicated?</code>的,除了:<code>nil</code>、<code>false</code>、 <code>true</code>、 符号、 数字、 类和模块。</p><div class="warning"><p>任何的类都可以通过移除<code>dup</code>和<code>clone</code>方法,或者在其中抛出异常,来禁用其复制功能。虽然<code>duplicable?</code>方法是基于上面的硬编码列表,但是它比用<code>rescue</code>快的多。确保仅在你的情况合乎上面的硬编码列表时候再使用它。</p></div><div class="note"><p>定义于 <code>active_support/core_ext/object/duplicable.rb</code>.</p></div><h4 id="deep_dup">2.4 <code>deep_dup</code>
</h4><p><code>deep_dup</code>方法返回一个对象的深度拷贝。一般来说,当你<code>dup</code>一个包含其他对象的对象时,Ruby 并不会把被包含的对象一同<code>dup</code>,它只会创建一个对象的浅表拷贝。假如你有一个字符串数组,如下例所示:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
array = ['string']
duplicate = array.dup
duplicate.push 'another-string'
# 对象被复制了,所以只有 duplicate 的数组元素有所增加
array # => ['string']
duplicate # => ['string', 'another-string']
duplicate.first.gsub!('string', 'foo')
# 第一个数组元素并未被复制,所以两个数组都发生了变化
array # => ['foo']
duplicate # => ['foo', 'another-string']
</pre>
</div>
<p>如你所见,对<code>Array</code>实例进行复制后,我们得到了另一个对象,因而我们修改它时,原始对象并未跟着有所变化。不过对数组元素而言,情况却有所不同。因为<code>dup</code>不会创建深度拷贝,所以数组里的字符串依然是同一个对象。</p><p>如果你需要一个对象的深度拷贝,就应该使用<code>deep_dup</code>。我们再来看下面这个例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
array = ['string']
duplicate = array.deep_dup
duplicate.first.gsub!('string', 'foo')
array # => ['string']
duplicate # => ['foo']
</pre>
</div>
<p>如果一个对象是不可复制的,<code>deep_dup</code>会返回其自身:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
number = 1
duplicate = number.deep_dup
number.object_id == duplicate.object_id # => true
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/deep_dup.rb</code>.</p></div><h4 id="try">2.5 <code>try</code>
</h4><p>如果你想在一个对象不为<code>nil</code>时,对其调用一个方法,最简单的办法就是使用条件从句,但这么做也会使代码变得乱七八糟。另一个选择就是使用<code>try</code>。<code>try</code>就好比<code>Object#send</code>,只不过如果接收者为<code>nil</code>,那么返回值也会是<code>nil</code>。</p><p>看下这个例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# 不使用 try
unless @number.nil?
@number.next
end
# 使用 try
@number.try(:next)
</pre>
</div>
<p>接下来的这个例子,代码出自<code>ActiveRecord::ConnectionAdapters::AbstractAdapter</code>,这里的<code>@logger</code>有可能为<code>nil</code>。能够看到,代码里使用了<code>try</code>来避免不必要的检查。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def log_info(sql, name, ms)
if @logger.try(:debug?)
name = '%s (%.1fms)' % [name || 'SQL', ms]
@logger.debug(format_log_entry(name, sql.squeeze(' ')))
end
end
</pre>
</div>
<p>调用<code>try</code>时也可以不传参数而是用代码快,其中的代码只有在对象不为<code>nil</code>时才会执行:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
@person.try { |p| "#{p.first_name} #{p.last_name}" }
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/try.rb</code>.</p></div><h4 id="class_eval(*args,-&block)">2.6 <code>class_eval(*args, &block)</code>
</h4><p>You can evaluate code in the context of any object's singleton class using <code>class_eval</code>:
使用<code>class_eval</code>,可以使代码在对象的单件类的上下文里执行:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Proc
def bind(object)
block, time = self, Time.current
object.class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
define_method(method_name, &block)
method = instance_method(method_name)
remove_method(method_name)
method
end.bind(object)
end
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/kernel/singleton_class.rb</code>.</p></div><h4 id="acts_like-questionmark(duck)">2.7 <code>acts_like?(duck)</code>
</h4><p><code>acts_like?</code>方法可以用来判断某个类与另一个类是否有相同的行为,它基于一个简单的惯例:这个类是否提供了与<code>String</code>相同的接口:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def acts_like_string?
end
</pre>
</div>
<p>上述代码只是一个标识,它的方法体或返回值都是不相关的。之后,就可以像下述代码那样判断其代码是否为“鸭子类型安全”的代码了:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
some_klass.acts_like?(:string)
</pre>
</div>
<p>Rails 里的许多类,例如<code>Date</code>和<code>Time</code>,都遵循上述约定。</p><div class="note"><p>定义于 <code>active_support/core_ext/object/acts_like.rb</code>.</p></div><h4 id="to_param">2.8 <code>to_param</code>
</h4><p>所有 Rails 对象都可以响应<code>to_param</code>方法,它会把对象的值转换为查询字符串,或者 URL 片段,并返回该值。</p><p>默认情况下,<code>to_param</code>仅仅调用了<code>to_s</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
7.to_param # => "7"
</pre>
</div>
<p><strong>不要</strong>对<code>to_param</code>方法的返回值进行转义:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
"Tom & Jerry".to_param # => "Tom & Jerry"
</pre>
</div>
<p>Rails 里的许多类重写了这个方法。</p><p>例如<code>nil</code>、<code>true</code>和<code>false</code>会返回其自身。<code>Array#to_param</code>会对数组元素调用<code>to_param</code>并把结果用"/"连接成字符串:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
[0, true, String].to_param # => "0/true/String"
</pre>
</div>
<p>需要注意的是, Rails 的路由系统会在模型上调用<code>to_param</code>并把结果作为<code>:id</code>占位符。<code>ActiveRecord::Base#to_param</code>会返回模型的<code>id</code>,但是你也可以在自己模型里重新定义它。例如:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User
def to_param
"#{id}-#{name.parameterize}"
end
end
</pre>
</div>
<p>会得到:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user_path(@user) # => "/users/357-john-smith"
</pre>
</div>
<div class="warning"><p>控制器里需要注意被重定义过的<code>to_param</code>,因为一个类似上述的请求里,会把"357-john-smith"当作<code>params[:id]</code>的值。</p></div><div class="note"><p>定义于 <code>active_support/core_ext/object/to_param.rb</code>.</p></div><h4 id="to_query">2.9 <code>to_query</code>
</h4><p>除了散列表之外,给定一个未转义的<code>key</code>,这个方法就会基于这个键和<code>to_param</code>的返回值,构造出一个新的查询字符串。例如:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User
def to_param
"#{id}-#{name.parameterize}"
end
end
</pre>
</div>
<p>会得到:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
current_user.to_query('user') # => "user=357-john-smith"
</pre>
</div>
<p>无论对于键还是值,本方法都会根据需要进行转义:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
account.to_query('company[name]')
# => "company%5Bname%5D=Johnson+%26+Johnson"
</pre>
</div>
<p>所以它的输出已经完全适合于用作查询字符串。</p><p>对于数组,会对其中每个元素以<code>_key_[]</code>为键执行<code>to_query</code>方法,并把结果用"&"连接为字符串:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
[3.4, -45.6].to_query('sample')
# => "sample%5B%5D=3.4&sample%5B%5D=-45.6"
</pre>
</div>
<p>哈系表也可以响应<code>to_query</code>方法但是用法有所不同。如果调用时没传参数,会先生成一系列排过序的键值对并在值上调用<code>to_query(键)</code>。然后把所得结果用"&"连接为字符串:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
{c: 3, b: 2, a: 1}.to_query # => "a=1&b=2&c=3"
</pre>
</div>
<p><code>Hash#to_query</code>方法也可接受一个可选的命名空间作为键:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
{id: 89, name: "John Smith"}.to_query('user')
# => "user%5Bid%5D=89&user%5Bname%5D=John+Smith"
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/to_query.rb</code>.</p></div><h4 id="with_options">2.10 <code>with_options</code>
</h4><p><code>with_options</code>方法可以为一组方法调用提取出共有的选项。</p><p>假定有一个默认的散列表选项,<code>with_options</code>方法会引入一个代理对象到代码块。在代码块内部,代理对象上的方法调用,会连同被混入的选项一起,被转发至原方法接收者。例如,若要去除下述代码的重复内容:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Account < ActiveRecord::Base
has_many :customers, dependent: :destroy
has_many :products, dependent: :destroy
has_many :invoices, dependent: :destroy
has_many :expenses, dependent: :destroy
end
</pre>
</div>
<p>可按此法书写:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Account < ActiveRecord::Base
with_options dependent: :destroy do |assoc|
assoc.has_many :customers
assoc.has_many :products
assoc.has_many :invoices
assoc.has_many :expenses
end
end
</pre>
</div>
<h2>TODO: clear this after totally understanding what these statnances means...</h2><p>That idiom may convey <em>grouping</em> to the reader as well. For example, say you want to send a newsletter whose language depends on the user. Somewhere in the mailer you could group locale-dependent bits like this:
上述写法也可用于对读取器进行分组。例如,假设你要发一份新闻通讯,通讯所用语言取决于用户。便可以利用如下例所示代码,对用户按照地区依赖进行分组:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
I18n.with_options locale: user.locale, scope: "newsletter" do |i18n|
subject i18n.t :subject
body i18n.t :body, user_name: user.name
end
</pre>
</div>
<div class="info"><p>由于<code>with_options</code>会把方法调用转发给其自身的接收者,所以可以进行嵌套。每层嵌套都会把继承来的默认值混入到自身的默认值里。</p></div><div class="note"><p>定义于 <code>active_support/core_ext/object/with_options.rb</code>.</p></div><h4 id="json-支持">2.11 JSON 支持</h4><p>相较于 <code>json</code> gem 为 Ruby 对象提供的<code>to_json</code>方法,Active Support 给出了一个更好的实现。因为有许多类,诸如<code>Hash</code>、<code>OrderedHash</code>和<code>Process::Status</code>,都需要做特殊处理才能到适合的 JSON 替换。</p><div class="note"><p>定义于 <code>active_support/core_ext/object/json.rb</code>.</p></div><h4 id="实例变量">2.12 实例变量</h4><p>Active Support 提供了若干方法以简化对实例变量的访问。</p><h5 id="instance_values">2.12.1 <code>instance_values</code>
</h5><p><code>instance_values</code>方法返回一个散列表,其中会把实例变量名去掉"@"作为键,把相应的实例变量值作为值。键全部是字符串:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class C
def initialize(x, y)
@x, @y = x, y
end
end
C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/instance_variables.rb</code>.</p></div><h5 id="instance_variable_names">2.12.2 <code>instance_variable_names</code>
</h5><p><code>instance_variable_names</code>方法返回一个数组。数组中所有的实例变量名都带有"@"标志。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class C
def initialize(x, y)
@x, @y = x, y
end
end
C.new(0, 1).instance_variable_names # => ["@x", "@y"]
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/instance_variables.rb</code>.</p></div><h4 id="silencing-warnings,-streams,-和-exceptions">2.13 Silencing Warnings, Streams, 和 Exceptions</h4><p><code>silence_warnings</code>和<code>enable_warnings</code>方法都可以在其代码块里改变<code>$VERBOSE</code>的值,并在之后把值重置:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
</pre>
</div>
<p>You can silence any stream while a block runs with <code>silence_stream</code>:
在通过<code>silence_stream</code>执行的代码块里,可以使任意流安静的运行:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
silence_stream(STDOUT) do
# 这里的代码不会输出到 STDOUT
end
</pre>
</div>
<p><code>quietly</code>方法可以使 STDOUT 和 STDERR 保持安静,即便在子进程里也如此:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
quietly { system 'bundle install' }
</pre>
</div>
<p>例如,railties 测试组件会用到上述方法,来阻止普通消息与进度状态混到一起。</p><p>也可以用<code>suppress</code>方法来使异常保持安静。方法接收任意数量的异常类。如果代码块的代码执行时报出异常,并且该异常<code>kind_of?</code>满足任一参数,<code>suppress</code>便会将异其捕获并安静的返回。否则会重新抛出该异常:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# If the user is locked the increment is lost, no big deal.
suppress(ActiveRecord::StaleObjectError) do
current_user.increment! :visits
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/kernel/reporting.rb</code>.</p></div><h4 id="in-questionmark">2.14 <code>in?</code>
</h4><p>判断式<code>in?</code>用于测试一个对象是否被包含在另一个对象里。当传入的参数无法响应<code>include?</code>时,会抛出<code>ArgumentError</code>异常。</p><p>使用<code>in?</code>的例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
1.in?([1,2]) # => true
"lo".in?("hello") # => true
25.in?(30..50) # => false
1.in?(1) # => ArgumentError
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/object/inclusion.rb</code>.</p></div><h3 id="对module的扩展">3 对<code>Module</code>的扩展</h3><h4 id="alias_method_chain">3.1 <code>alias_method_chain</code>
</h4><p>使用纯 Ruby 可以用方法环绕其他的方法,这种做法被称为环绕别名。</p><p>例如,我们假设在功能测试里你希望参数都是字符串,就如同真实的请求中那样,但是同时你也希望对于数字和其他类型的值能够很方便的赋值。为了做到这点,你可以把<code>test/test_helper.rb</code>里的<code>ActionController::TestCase#process</code>方法像下面这样环绕:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
ActionController::TestCase.class_eval do
# save a reference to the original process method
alias_method :original_process, :process
# now redefine process and delegate to original_process
def process(action, params=nil, session=nil, flash=nil, http_method='GET')
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
original_process(action, params, session, flash, http_method)
end
end
</pre>
</div>
<p><code>get</code>、<code>post</code>等最终会通过此方法执行。</p><p>这么做有一定风险,<code>:original_process</code>有可能已经被占用了。为了避免方法名发生碰撞,通常会添加标签来表明这是个关于什么的别名:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
ActionController::TestCase.class_eval do
def process_with_stringified_params(...)
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
process_without_stringified_params(action, params, session, flash, http_method)
end
alias_method :process_without_stringified_params, :process
alias_method :process, :process_with_stringified_params
end
</pre>
</div>
<p><code>alias_method_chain</code>为上述技巧提供了一个便捷之法:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
ActionController::TestCase.class_eval do
def process_with_stringified_params(...)
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
process_without_stringified_params(action, params, session, flash, http_method)
end
alias_method_chain :process, :stringified_params
end
</pre>
</div>
<p>Rails 源代码中随处可见<code>alias_method_chain</code>。例如<code>ActiveRecord::Base#save</code>里,就通过这种方式对方法进行环绕,从 validations 下一个专门的模块里为其增加了验证。</p><div class="note"><p>定义于 <code>active_support/core_ext/module/aliasing.rb</code>.</p></div><h4 id="属性">3.2 属性</h4><h5 id="alias_attribute">3.2.1 <code>alias_attribute</code>
</h5><p>模型属性包含读取器、写入器和判断式。只需添加一行代码,就可以为模型属性添加一个包含以上三个方法的别名。与其他别名方法一样,新名称充当第一个参数,原有名称是第二个参数(为了方便记忆,可以类比下赋值时的书写顺序)。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ActiveRecord::Base
# You can refer to the email column as "login".
# This can be meaningful for authentication code.
alias_attribute :login, :email
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/module/aliasing.rb</code>.</p></div><h5 id="内部属性">3.2.2 内部属性</h5><p>当你在一个被继承的类里定义一条属性时,属性名称有可能会发生碰撞。这一点对许多库而言尤为重要。</p><p>Active Support 定义了<code>attr_internal_reader</code>、<code>attr_internal_writer</code>和<code>attr_internal_accessor</code>这些类宏。它们的作用与 Ruby 内建的<code>attr_*</code>相当,只不过实例变量名多了下划线以避免碰撞。</p><p>类宏<code>attr_internal</code>与<code>attr_internal_accessor</code>是同义:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# library
class ThirdPartyLibrary::Crawler
attr_internal :log_level
end
# client code
class MyCrawler < ThirdPartyLibrary::Crawler
attr_accessor :log_level
end
</pre>
</div>
<p>上述例子里的情况可能是,<code>:log_level</code>并不属于库的公共接口,而是只用于开发。而在客户代码里,由于不知道可能出现的冲突,便在子类里又定义了<code>:log_level</code>。多亏了<code>attr_internal</code>才没有出项碰撞。</p><p>默认情况下,内部实例变量名以下划线开头,如上例中即为<code>@_log_level</code>。不过这点可以通过<code>Module.attr_internal_naming_format</code>进行配置,你可以传入任何<code>sprintf</code>这一类的格式化字符串,并在开头加上<code>@</code>,同时还要加上<code>%s</code>表示变量名称的位置。默认值为<code>"@_%s"</code>。</p><p>Rails 在若干地方使用了内部属性,比如在视图层:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module ActionView
class Base
attr_internal :captures
attr_internal :request, :layout
attr_internal :controller, :template
end
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/module/attr_internal.rb</code>.</p></div><h5 id="module-attributes">3.2.3 Module Attributes</h5><p>类宏<code>mattr_reader</code>、<code>mattr_writer</code>和<code>mattr_accessor</code>与为类定义的<code>cattr_*</code>是相同的。实际上,<code>cattr_*</code>系列的类宏只不过是<code>mattr_*</code>这些类宏的别名。详见<a href="#class-attributes">Class Attributes</a>。</p><p>例如,依赖性机制就用到了它们:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module ActiveSupport
module Dependencies
mattr_accessor :warnings_on_first_load
mattr_accessor :history
mattr_accessor :loaded
mattr_accessor :mechanism
mattr_accessor :load_paths
mattr_accessor :load_once_paths
mattr_accessor :autoloaded_constants
mattr_accessor :explicitly_unloadable_constants
mattr_accessor :logger
mattr_accessor :log_activity
mattr_accessor :constant_watch_stack
mattr_accessor :constant_watch_stack_mutex
end
end
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/module/attribute_accessors.rb</code>.</p></div><h4 id="对module的扩展-parents">3.3 Parents</h4><h5 id="parent">3.3.1 <code>parent</code>
</h5><p>对一个嵌套的模块调用<code>parent</code>方法,会返回其相应的常量:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module X
module Y
module Z
end
end
end
M = X::Y::Z
X::Y::Z.parent # => X::Y
M.parent # => X::Y
</pre>
</div>
<p>如果这个模块是匿名的或者属于顶级作用域, <code>parent</code>会返回<code>Object</code>。</p><div class="warning"><p>若有上述情况,则<code>parent_name</code>会返回<code>nil</code>。</p></div><div class="note"><p>定义于 <code>active_support/core_ext/module/introspection.rb</code>.</p></div><h5 id="parent_name">3.3.2 <code>parent_name</code>
</h5><p>对一个嵌套的模块调用<code>parent_name</code>方法,会返回其相应常量的完全限定名:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module X
module Y
module Z
end
end
end
M = X::Y::Z
X::Y::Z.parent_name # => "X::Y"
M.parent_name # => "X::Y"
</pre>
</div>
<p>定义在顶级作用域里的模块或匿名的模块,<code>parent_name</code>会返回<code>nil</code>。</p><div class="warning"><p>若有上述情况,则<code>parent</code>返回<code>Object</code>。</p></div><div class="note"><p>定义于 <code>active_support/core_ext/module/introspection.rb</code>.</p></div><h5 id="对module的扩展-parents-parents">3.3.3 <code>parents</code>
</h5><p><code>parents</code>方法会对接收者调用<code>parent</code>,并向上追溯直至<code>Object</code>。之后所得结果链按由低到高顺序组成一个数组被返回。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module X
module Y
module Z
end
end
end
M = X::Y::Z
X::Y::Z.parents # => [X::Y, X, Object]
M.parents # => [X::Y, X, Object]
</pre>
</div>
<div class="note"><p>定义于 <code>active_support/core_ext/module/introspection.rb</code>.</p></div><h4 id="常量">3.4 常量</h4><p>defined in the receiver module:
<code>local_constants</code>方法返回在接收者模块中定义的常量。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module X
X1 = 1
X2 = 2
module Y
Y1 = :y1
X1 = :overrides_X1_above
end
end
X.local_constants # => [:X1, :X2, :Y]
X::Y.local_constants # => [:Y1, :X1]
</pre>
</div>
<p>常量名会作为符号被返回。</p><div class="note"><p>定义于 <code>active_support/core_ext/module/introspection.rb</code>.</p></div><h5 id="限定常量名">3.4.1 限定常量名</h5><p>标准方法<code>const_defined?</code>、<code>const_get</code>和<code>const_set</code>接受裸常量名。
Active Support 扩展了这些API使其可以接受相对限定常量名。</p><p>新的方法名是<code>qualified_const_defined?</code>,<code>qualified_const_get</code>和<code>qualified_const_set</code>。
它们的参数被假定为相对于其接收者的限定常量名:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Object.qualified_const_defined?("Math::PI") # => true
Object.qualified_const_get("Math::PI") # => 3.141592653589793
Object.qualified_const_set("Math::Phi", 1.618034) # => 1.618034
</pre>
</div>
<p>参数可以使用裸常量名:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Math.qualified_const_get("E") # => 2.718281828459045
</pre>
</div>
<p>These methods are analogous to their built-in counterparts. In particular,
<code>qualified_constant_defined?</code> accepts an optional second argument to be
able to say whether you want the predicate to look in the ancestors.
This flag is taken into account for each constant in the expression while
walking down the path.
这些方法与其内建的对应方法很类似。尤为值得一提的是,<code>qualified_constant_defined?</code>接收一个可选的第二参数,以此来标明你是否要在祖先链中进行查找。</p><p>例如,假定:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module M
X = 1
end
module N
class C
include M
end
end
</pre>
</div>
<p><code>qualified_const_defined?</code>会这样执行:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
N.qualified_const_defined?("C::X", false) # => false
N.qualified_const_defined?("C::X", true) # => true
N.qualified_const_defined?("C::X") # => true
</pre>
</div>
<p>As the last example implies, the second argument defaults to true,
as in <code>const_defined?</code>.</p><p>For coherence with the built-in methods only relative paths are accepted.
Absolute qualified constant names like <code>::Math::PI</code> raise <code>NameError</code>.</p><div class="note"><p>定义于 <code>active_support/core_ext/module/qualified_const.rb</code>.</p></div><h4 id="reachable">3.5 Reachable</h4><p>A named module is reachable if it is stored in its corresponding constant. It means you can reach the module object via the constant.</p><p>That is what ordinarily happens, if a module is called "M", the <code>M</code> constant exists and holds it:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module M
end
M.reachable? # => true
</pre>
</div>
<p>But since constants and modules are indeed kind of decoupled, module objects can become unreachable:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module M
end