railties 3.0.0.beta → 3.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +15 -1
- data/README +9 -9
- data/bin/rails +28 -9
- data/guides/images/challenge.png +0 -0
- data/guides/images/edge_badge.png +0 -0
- data/guides/images/posts_index.png +0 -0
- data/guides/images/rails_welcome.png +0 -0
- data/guides/rails_guides.rb +9 -22
- data/guides/rails_guides/generator.rb +79 -50
- data/guides/rails_guides/textile_extensions.rb +3 -3
- data/guides/source/2_2_release_notes.textile +1 -1
- data/guides/source/2_3_release_notes.textile +1 -1
- data/guides/source/3_0_release_notes.textile +46 -38
- data/guides/source/action_controller_overview.textile +2 -2
- data/guides/source/action_mailer_basics.textile +4 -4
- data/guides/source/action_view_overview.textile +2 -2
- data/guides/source/active_record_querying.textile +73 -95
- data/guides/source/active_support_core_extensions.textile +993 -85
- data/guides/source/activerecord_validations_callbacks.textile +3 -3
- data/guides/source/caching_with_rails.textile +1 -1
- data/guides/source/command_line.textile +90 -88
- data/guides/source/configuring.textile +10 -10
- data/guides/source/contribute.textile +2 -2
- data/guides/source/contributing_to_rails.textile +14 -7
- data/guides/source/credits.textile.erb +8 -0
- data/guides/source/debugging_rails_applications.textile +6 -6
- data/guides/source/form_helpers.textile +1 -1
- data/guides/source/generators.textile +14 -14
- data/guides/source/getting_started.textile +634 -500
- data/guides/source/index.textile.erb +16 -1
- data/guides/source/layout.html.erb +7 -1
- data/guides/source/layouts_and_rendering.textile +299 -71
- data/guides/source/migrations.textile +5 -5
- data/guides/source/performance_testing.textile +8 -8
- data/guides/source/plugins.textile +26 -24
- data/guides/source/rails_on_rack.textile +5 -5
- data/guides/source/routing.textile +119 -117
- data/guides/source/security.textile +1 -1
- data/guides/source/testing.textile +4 -4
- data/lib/rails.rb +4 -1
- data/lib/rails/application.rb +44 -7
- data/lib/rails/application/bootstrap.rb +2 -14
- data/lib/rails/application/configuration.rb +69 -5
- data/lib/rails/application/finisher.rb +2 -3
- data/lib/rails/application/metal_loader.rb +1 -1
- data/lib/rails/application/routes_reloader.rb +1 -1
- data/lib/rails/backtrace_cleaner.rb +0 -11
- data/lib/rails/commands.rb +7 -6
- data/lib/rails/commands/application.rb +1 -1
- data/lib/rails/commands/console.rb +1 -1
- data/lib/rails/commands/dbconsole.rb +12 -0
- data/lib/rails/commands/destroy.rb +2 -2
- data/lib/rails/commands/generate.rb +2 -2
- data/lib/rails/commands/performance/benchmarker.rb +2 -2
- data/lib/rails/commands/performance/profiler.rb +2 -2
- data/lib/rails/commands/plugin.rb +6 -6
- data/lib/rails/commands/runner.rb +2 -0
- data/lib/rails/commands/server.rb +23 -8
- data/lib/rails/configuration.rb +2 -84
- data/lib/rails/console/app.rb +4 -3
- data/lib/rails/console/helpers.rb +3 -1
- data/lib/rails/engine.rb +107 -12
- data/lib/rails/engine/configuration.rb +8 -2
- data/lib/rails/generators.rb +22 -7
- data/lib/rails/generators/actions.rb +16 -6
- data/lib/rails/generators/base.rb +15 -8
- data/lib/rails/generators/erb.rb +21 -0
- data/lib/{generators → rails/generators}/erb/controller/controller_generator.rb +4 -5
- data/lib/{generators → rails/generators}/erb/controller/templates/view.html.erb +0 -0
- data/lib/rails/generators/erb/mailer/mailer_generator.rb +13 -0
- data/lib/{generators → rails/generators}/erb/mailer/templates/view.text.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/scaffold_generator.rb +14 -26
- data/lib/{generators → rails/generators}/erb/scaffold/templates/_form.html.erb +1 -1
- data/lib/{generators → rails/generators}/erb/scaffold/templates/edit.html.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/index.html.erb +1 -1
- data/lib/{generators → rails/generators}/erb/scaffold/templates/layout.html.erb +1 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/new.html.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/show.html.erb +0 -0
- data/lib/rails/generators/named_base.rb +4 -0
- data/lib/{generators → rails/generators}/rails/app/USAGE +0 -0
- data/lib/{generators → rails/generators}/rails/app/app_generator.rb +21 -7
- data/lib/rails/generators/rails/app/templates/Gemfile +34 -0
- data/lib/{generators → rails/generators}/rails/app/templates/README +9 -8
- data/lib/{generators → rails/generators}/rails/app/templates/Rakefile +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/controllers/application_controller.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/helpers/application_helper.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/views/layouts/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config.ru +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/application.rb +4 -3
- data/lib/rails/generators/rails/app/templates/config/boot.rb +14 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/frontbase.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/ibm_db.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/mysql.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/oracle.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/postgresql.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/sqlite3.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environment.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/development.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/production.rb.tt +9 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/test.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/backtrace_silencers.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/inflections.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/mime_types.rb +0 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +10 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/locales/en.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/routes.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/db/seeds.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/doc/README_FOR_APP +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/gitignore +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/404.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/422.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/500.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/favicon.ico +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/images/rails.png +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/index.html +17 -17
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/application.js +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/controls.js +5 -3
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/dragdrop.js +7 -6
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/effects.js +8 -13
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/prototype.js +1573 -1019
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/rails.js +1 -2
- data/lib/{generators → rails/generators}/rails/app/templates/public/robots.txt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/script/rails +0 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/performance/browsing_test.rb +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/test_helper.rb +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/controller/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/controller/controller_generator.rb +6 -0
- data/lib/{generators → rails/generators}/rails/controller/templates/controller.rb +0 -0
- data/lib/{generators → rails/generators}/rails/generator/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/generator/generator_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/generator/templates/%file_name%_generator.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/generator/templates/USAGE.tt +1 -1
- data/lib/{generators → rails/generators}/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/helper/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/helper/helper_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/helper/templates/helper.rb +0 -0
- data/lib/{generators → rails/generators}/rails/integration_test/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/integration_test/integration_test_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/mailer/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/mailer/mailer_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/mailer/templates/mailer.rb +0 -0
- data/lib/{generators → rails/generators}/rails/metal/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/metal/metal_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/metal/templates/metal.rb +0 -0
- data/lib/{generators → rails/generators}/rails/migration/USAGE +2 -2
- data/lib/{generators → rails/generators}/rails/migration/migration_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/model/USAGE +2 -2
- data/lib/{generators → rails/generators}/rails/model/model_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/observer/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/observer/observer_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/performance_test/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/performance_test/performance_test_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/plugin/plugin_generator.rb +1 -1
- data/lib/{generators → rails/generators}/rails/plugin/templates/MIT-LICENSE.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/README.tt +0 -0
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +23 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/init.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/install.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/lib/%file_name%.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/uninstall.rb +0 -0
- data/lib/{generators → rails/generators}/rails/resource/USAGE +3 -3
- data/lib/{generators → rails/generators}/rails/resource/resource_generator.rb +3 -1
- data/lib/{generators → rails/generators}/rails/scaffold/USAGE +4 -4
- data/lib/{generators → rails/generators}/rails/scaffold/scaffold_generator.rb +1 -1
- data/lib/{generators → rails/generators}/rails/scaffold_controller/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/scaffold_controller/scaffold_controller_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/scaffold_controller/templates/controller.rb +2 -2
- data/lib/{generators → rails/generators}/rails/session_migration/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/session_migration/session_migration_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/stylesheets/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/stylesheets/stylesheets_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/stylesheets/templates/scaffold.css +4 -0
- data/lib/{generators → rails/generators}/test_unit.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/controller/controller_generator.rb +2 -1
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +18 -0
- data/lib/{generators → rails/generators}/test_unit/helper/helper_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/helper/templates/helper_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/integration/integration_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/integration/templates/integration_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/mailer/mailer_generator.rb +1 -8
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +20 -0
- data/lib/{generators → rails/generators}/test_unit/model/model_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/model/templates/fixtures.yml +0 -0
- data/lib/{generators → rails/generators}/test_unit/model/templates/unit_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/observer/observer_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/observer/templates/unit_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/performance/performance_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/performance/templates/performance_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/plugin/plugin_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/plugin/templates/%file_name%_test.rb.tt +0 -0
- data/lib/{generators → rails/generators}/test_unit/plugin/templates/test_helper.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/scaffold/scaffold_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/scaffold/templates/functional_test.rb +9 -5
- data/{builtin/rails_info → lib}/rails/info.rb +0 -0
- data/{builtin/rails_info → lib}/rails/info_controller.rb +0 -0
- data/{builtin/routes.rb → lib/rails/info_routes.rb} +2 -2
- data/lib/rails/{subscriber.rb → log_subscriber.rb} +27 -27
- data/lib/rails/{subscriber → log_subscriber}/test_helper.rb +15 -16
- data/lib/rails/plugin.rb +31 -8
- data/lib/rails/rack/debugger.rb +3 -1
- data/lib/rails/rack/logger.rb +4 -4
- data/lib/rails/railtie.rb +179 -16
- data/lib/rails/railtie/configuration.rb +56 -1
- data/lib/rails/tasks/documentation.rake +38 -20
- data/lib/rails/tasks/framework.rake +16 -9
- data/lib/rails/tasks/misc.rake +3 -5
- data/lib/rails/tasks/routes.rake +2 -2
- data/lib/rails/test_help.rb +21 -1
- data/lib/rails/test_unit/railtie.rb +1 -3
- data/lib/rails/version.rb +3 -2
- metadata +199 -171
- data/builtin/rails_info/rails/info_helper.rb +0 -2
- data/lib/generators/erb.rb +0 -8
- data/lib/generators/erb/mailer/mailer_generator.rb +0 -20
- data/lib/generators/rails/app/templates/Gemfile +0 -34
- data/lib/generators/rails/app/templates/config/boot.rb +0 -17
- data/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt +0 -15
- data/lib/generators/rails/model_subclass/model_subclass_generator.rb +0 -12
- data/lib/generators/rails/plugin/templates/Rakefile.tt +0 -10
- data/lib/generators/test_unit/controller/templates/functional_test.rb +0 -8
- data/lib/generators/test_unit/mailer/templates/fixture +0 -3
- data/lib/generators/test_unit/mailer/templates/functional_test.rb +0 -22
- data/lib/rails/railties_path.rb +0 -1
@@ -6,6 +6,68 @@ By referring to this guide you will learn the extensions to the Ruby core classe
|
|
6
6
|
|
7
7
|
endprologue.
|
8
8
|
|
9
|
+
h3. How to Load Core Extensions
|
10
|
+
|
11
|
+
h4. Stand-Alone Active Support
|
12
|
+
|
13
|
+
In order to have a near zero default footprint, Active Support does not load anything by default. It is broken in small pieces so that you may load just what you need, and also has some convenience entry points to load related extensions in one shot, even everything.
|
14
|
+
|
15
|
+
Thus, after a simple require like:
|
16
|
+
|
17
|
+
<ruby>
|
18
|
+
require 'active_support'
|
19
|
+
</ruby>
|
20
|
+
|
21
|
+
objects do not even respond to +blank?+, let's see how to load its definition.
|
22
|
+
|
23
|
+
h5. Cherry-picking a Definition
|
24
|
+
|
25
|
+
The most lightweight way to get +blank?+ is to cherry-pick the file that defines it.
|
26
|
+
|
27
|
+
For every single method defined as a core extension this guide has a note that says where is such a method defined. In the case of +blank?+ the note reads:
|
28
|
+
|
29
|
+
NOTE: Defined in +active_support/core_ext/object/blank.rb+.
|
30
|
+
|
31
|
+
That means that this single call is enough:
|
32
|
+
|
33
|
+
<ruby>
|
34
|
+
require 'active_support/core_ext/object/blank'
|
35
|
+
</ruby>
|
36
|
+
|
37
|
+
Active Support has been carefully revised so that cherry-picking a file loads only strictly needed dependencies, if any.
|
38
|
+
|
39
|
+
h5. Loading Grouped Core Extensions
|
40
|
+
|
41
|
+
The next level is to simply load all extensions to +Object+. As a rule of thumb, extensions to +SomeClass+ are available in one shot by loading +active_support/core_ext/some_class+.
|
42
|
+
|
43
|
+
Thus, if that would do, to have +blank?+ available we could just load all extensions to +Object+:
|
44
|
+
|
45
|
+
<ruby>
|
46
|
+
require 'active_support/core_ext/object'
|
47
|
+
</ruby>
|
48
|
+
|
49
|
+
h5. Loading All Core Extensions
|
50
|
+
|
51
|
+
You may prefer just to load all core extensions, there is a file for that:
|
52
|
+
|
53
|
+
<ruby>
|
54
|
+
require 'active_support/core_ext'
|
55
|
+
</ruby>
|
56
|
+
|
57
|
+
h5. Loading All Active Support
|
58
|
+
|
59
|
+
And finally, if you want to have all Active Support available just issue:
|
60
|
+
|
61
|
+
<ruby>
|
62
|
+
require 'active_support/all'
|
63
|
+
</ruby>
|
64
|
+
|
65
|
+
That does not even put the entire Active Support in memory upfront indeed, some stuff is configured via +autoload+, so it is only loaded if used.
|
66
|
+
|
67
|
+
h4. Active Support Within a Ruby on Rails Application
|
68
|
+
|
69
|
+
A Ruby on Rails application loads all Active Support unless +config.active_support.bare+ is true. In that case, the application will only load what the framework itself cherry-picks for its own needs, and can still cherry-pick itself at any granularity level, as explained in the previous section.
|
70
|
+
|
9
71
|
h3. Extensions to All Objects
|
10
72
|
|
11
73
|
h4. +blank?+ and +present?+
|
@@ -138,16 +200,19 @@ end
|
|
138
200
|
|
139
201
|
NOTE: Defined in +active_support/core_ext/object/try.rb+.
|
140
202
|
|
141
|
-
h4. +
|
203
|
+
h4. +singleton_class+
|
142
204
|
|
143
|
-
The method +
|
205
|
+
The method +singleton_class+ returns the singleton class of the receiver:
|
144
206
|
|
145
207
|
<ruby>
|
146
|
-
String.
|
147
|
-
String.new.
|
208
|
+
String.singleton_class # => #<Class:String>
|
209
|
+
String.new.singleton_class # => #<Class:#<String:0x17a1d1c>>
|
148
210
|
</ruby>
|
149
211
|
|
150
|
-
|
212
|
+
WARNING: Fixnums and symbols have no singleton classes, +singleton_class+
|
213
|
+
raises +TypeError+ on them.
|
214
|
+
|
215
|
+
NOTE: Defined in +active_support/core_ext/object/singleton_class.rb+.
|
151
216
|
|
152
217
|
h4. +class_eval(*args, &block)+
|
153
218
|
|
@@ -168,7 +233,7 @@ class Proc
|
|
168
233
|
end
|
169
234
|
</ruby>
|
170
235
|
|
171
|
-
NOTE: Defined in +active_support/core_ext/object/
|
236
|
+
NOTE: Defined in +active_support/core_ext/object/singleton_class.rb+.
|
172
237
|
|
173
238
|
h4. +acts_like?(duck)+
|
174
239
|
|
@@ -323,6 +388,40 @@ TIP: Since +with_options+ forwards calls to its receiver they can be nested. Eac
|
|
323
388
|
|
324
389
|
NOTE: Defined in +active_support/core_ext/object/with_options.rb+.
|
325
390
|
|
391
|
+
h5. +subclasses_of+
|
392
|
+
|
393
|
+
The method +subclasses_of+ receives an arbitrary number of class objects and returns all their anonymous or reachable descendants as a single array:
|
394
|
+
|
395
|
+
<ruby>
|
396
|
+
class C; end
|
397
|
+
subclasses_of(C) # => []
|
398
|
+
|
399
|
+
subclasses_of(Integer) # => [Bignum, Fixnum]
|
400
|
+
|
401
|
+
module M
|
402
|
+
class A; end
|
403
|
+
class B1 < A; end
|
404
|
+
class B2 < A; end
|
405
|
+
end
|
406
|
+
|
407
|
+
module N
|
408
|
+
class C < M::B1; end
|
409
|
+
end
|
410
|
+
|
411
|
+
subclasses_of(M::A) # => [N::C, M::B2, M::B1]
|
412
|
+
</ruby>
|
413
|
+
|
414
|
+
The order in which these classes are returned is unspecified. The returned collection may have duplicates:
|
415
|
+
|
416
|
+
<ruby>
|
417
|
+
subclasses_of(Numeric, Integer)
|
418
|
+
# => [Bignum, Float, Fixnum, Integer, Date::Infinity, Rational, BigDecimal, Bignum, Fixnum]
|
419
|
+
</ruby>
|
420
|
+
|
421
|
+
See also +Class#subclasses+ in "Extensions to +Class+ FIX THIS LINK":FIXME.
|
422
|
+
|
423
|
+
NOTE: Defined in +active_support/core_ext/object/extending.rb+.
|
424
|
+
|
326
425
|
h4. Instance Variables
|
327
426
|
|
328
427
|
Active Support provides several methods to ease access to instance variables.
|
@@ -341,7 +440,7 @@ end
|
|
341
440
|
C.new(0, 1).instance_variable_names # => ["@y", "@x"]
|
342
441
|
</ruby>
|
343
442
|
|
344
|
-
WARNING: The order in which the names are returned is
|
443
|
+
WARNING: The order in which the names are returned is unspecified, and it indeed depends on the version of the interpreter.
|
345
444
|
|
346
445
|
NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+.
|
347
446
|
|
@@ -422,11 +521,23 @@ end
|
|
422
521
|
|
423
522
|
NOTE: Defined in +active_support/core_ext/kernel/reporting.rb+.
|
424
523
|
|
425
|
-
|
524
|
+
h4. +require_library_or_gem+
|
525
|
+
|
526
|
+
The convenience method +require_library_or_gem+ tries to load its argument with a regular +require+ first. If it fails loads +rubygems+ and tries again.
|
527
|
+
|
528
|
+
If the first attempt is a failure and +rubygems+ can't be loaded the method raises +LoadError+. On the other hand, if +rubygems+ is available but the argument is not loadable as a gem, the method gives up and +LoadError+ is also raised.
|
529
|
+
|
530
|
+
For example, that's the way the MySQL adapter loads the MySQL library:
|
531
|
+
|
532
|
+
<ruby>
|
533
|
+
require_library_or_gem('mysql')
|
534
|
+
</ruby>
|
535
|
+
|
536
|
+
NOTE: Defined in +active_support/core_ext/kernel/requires.rb+.
|
426
537
|
|
427
|
-
|
538
|
+
h3. Extensions to +Module+
|
428
539
|
|
429
|
-
|
540
|
+
h4. +alias_method_chain+
|
430
541
|
|
431
542
|
Using plain Ruby you can wrap methods with other methods, that's called _alias chaining_.
|
432
543
|
|
@@ -450,53 +561,495 @@ That's the method +get+, +post+, etc., delegate the work to.
|
|
450
561
|
That technique has a risk, it could be the case that +:original_process+ was taken. To try to avoid collisions people choose some label that characterizes what the chaining is about:
|
451
562
|
|
452
563
|
<ruby>
|
453
|
-
ActionController::TestCase.class_eval do
|
454
|
-
def process_with_stringified_params(...)
|
455
|
-
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
|
456
|
-
process_without_stringified_params(action, params, session, flash, http_method)
|
457
|
-
end
|
458
|
-
alias_method :process_without_stringified_params, :process
|
459
|
-
alias_method :process, :process_with_stringified_params
|
564
|
+
ActionController::TestCase.class_eval do
|
565
|
+
def process_with_stringified_params(...)
|
566
|
+
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
|
567
|
+
process_without_stringified_params(action, params, session, flash, http_method)
|
568
|
+
end
|
569
|
+
alias_method :process_without_stringified_params, :process
|
570
|
+
alias_method :process, :process_with_stringified_params
|
571
|
+
end
|
572
|
+
</ruby>
|
573
|
+
|
574
|
+
The method +alias_method_chain+ provides a shortcut for that pattern:
|
575
|
+
|
576
|
+
<ruby>
|
577
|
+
ActionController::TestCase.class_eval do
|
578
|
+
def process_with_stringified_params(...)
|
579
|
+
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
|
580
|
+
process_without_stringified_params(action, params, session, flash, http_method)
|
581
|
+
end
|
582
|
+
alias_method_chain :process, :stringified_params
|
583
|
+
end
|
584
|
+
</ruby>
|
585
|
+
|
586
|
+
Rails uses +alias_method_chain+ all over the code base. For example validations are added to +ActiveRecord::Base#save+ by wrapping the method that way in a separate module specialised in validations.
|
587
|
+
|
588
|
+
NOTE: Defined in +active_support/core_ext/module/aliasing.rb+.
|
589
|
+
|
590
|
+
h4. Attributes
|
591
|
+
|
592
|
+
h5. +alias_attribute+
|
593
|
+
|
594
|
+
Model attributes have a reader, a writer, and a predicate. You can aliase a model attribute having the corresponding three methods defined for you in one shot. As in other aliasing methods, the new name is the first argument, and the old name is the second (my mnemonic is they go in the same order as if you did an assignment):
|
595
|
+
|
596
|
+
<ruby>
|
597
|
+
class User < ActiveRecord::Base
|
598
|
+
# let me refer to the email column as "login",
|
599
|
+
# much meaningful for authentication code
|
600
|
+
alias_attribute :login, :email
|
601
|
+
end
|
602
|
+
</ruby>
|
603
|
+
|
604
|
+
NOTE: Defined in +active_support/core_ext/module/aliasing.rb+.
|
605
|
+
|
606
|
+
h5. +attr_accessor_with_default+
|
607
|
+
|
608
|
+
The method +attr_accessor_with_default+ serves the same purpose as the Ruby macro +attr_accessor+ but allows you to set a default value for the attribute:
|
609
|
+
|
610
|
+
<ruby>
|
611
|
+
class Url
|
612
|
+
attr_accessor_with_default :port, 80
|
613
|
+
end
|
614
|
+
|
615
|
+
Url.new.port # => 80
|
616
|
+
</ruby>
|
617
|
+
|
618
|
+
The default value can be also specified with a block, which is called in the context of the corresponding object:
|
619
|
+
|
620
|
+
<ruby>
|
621
|
+
class User
|
622
|
+
attr_accessor :name, :surname
|
623
|
+
attr_accessor_with_default(:full_name) {
|
624
|
+
[name, surname].compact.join(" ")
|
625
|
+
}
|
626
|
+
end
|
627
|
+
|
628
|
+
u = User.new
|
629
|
+
u.name = 'Xavier'
|
630
|
+
u.surname = 'Noria'
|
631
|
+
u.full_name # => "Xavier Noria"
|
632
|
+
</ruby>
|
633
|
+
|
634
|
+
The result is not cached, the block is invoked in each call to the reader.
|
635
|
+
|
636
|
+
You can overwrite the default with the writer:
|
637
|
+
|
638
|
+
<ruby>
|
639
|
+
url = Url.new
|
640
|
+
url.host # => 80
|
641
|
+
url.host = 8080
|
642
|
+
url.host # => 8080
|
643
|
+
</ruby>
|
644
|
+
|
645
|
+
The default value is returned as long as the attribute is unset. The reader does not rely on the value of the attribute to know whether it has to return the default. It rather monitors the writer: if there's any assignment the value is no longer considered to be unset.
|
646
|
+
|
647
|
+
Active Resource uses this macro to set a default value for the +:primary_key+ attribute:
|
648
|
+
|
649
|
+
<ruby>
|
650
|
+
attr_accessor_with_default :primary_key, 'id'
|
651
|
+
</ruby>
|
652
|
+
|
653
|
+
NOTE: Defined in +active_support/core_ext/module/attr_accessor_with_default.rb+.
|
654
|
+
|
655
|
+
h5. Internal Attributes
|
656
|
+
|
657
|
+
When you are defining an attribute in a class that is meant to be subclassed name collisions are a risk. That's remarkably important for libraries.
|
658
|
+
|
659
|
+
Active Support defines the macros +attr_internal_reader+, +attr_internal_writer+, and +attr_internal_accessor+. They behave like their Ruby builtin +attr_*+ counterparts, except they name the unerlying instace variable in a way that makes collisions less likely.
|
660
|
+
|
661
|
+
The macro +attr_internal+ is a synonim for +attr_internal_accessor+:
|
662
|
+
|
663
|
+
<ruby>
|
664
|
+
# library
|
665
|
+
class ThirdPartyLibrary::Crawler
|
666
|
+
attr_internal :log_level
|
667
|
+
end
|
668
|
+
|
669
|
+
# client code
|
670
|
+
class MyCrawler < ThirdPartyLibrary::Crawler
|
671
|
+
attr_accessor :log_level
|
672
|
+
end
|
673
|
+
</ruby>
|
674
|
+
|
675
|
+
In the previous example it could be the case that +:log_level+ does not belong to the public interface of the library and it is only used for development. The client code, unaware of the potential conflict, subclasses and defines its own +:log_level+. Thanks to +attr_internal+ there's no collision.
|
676
|
+
|
677
|
+
By default the internal instance variable is named with a leading underscore, +@_log_level+ in the example above. That's configurable via +Module.attr_internal_naming_format+ though, you can pass any +sprintf+-like format string with a leading +@+ and a +%s+ somewhere, which is where the name will be placed. The default is +"@_%s"+.
|
678
|
+
|
679
|
+
Rails uses internal attributes in a few spots, for examples for views:
|
680
|
+
|
681
|
+
<ruby>
|
682
|
+
module ActionView
|
683
|
+
class Base
|
684
|
+
attr_internal :captures
|
685
|
+
attr_internal :request, :layout
|
686
|
+
attr_internal :controller, :template
|
687
|
+
end
|
688
|
+
end
|
689
|
+
</ruby>
|
690
|
+
|
691
|
+
NOTE: Defined in +active_support/core_ext/module/attr_internal.rb+.
|
692
|
+
|
693
|
+
h5. Module Attributes
|
694
|
+
|
695
|
+
The macros +mattr_reader+, +mattr_writer+, and +mattr_accessor+ are analogous to the +cattr_*+ macros defined for class. Check "Class Attributes":#class-attributes.
|
696
|
+
|
697
|
+
For example, the dependencies mechanism uses them:
|
698
|
+
|
699
|
+
<ruby>
|
700
|
+
module ActiveSupport
|
701
|
+
module Dependencies
|
702
|
+
mattr_accessor :warnings_on_first_load
|
703
|
+
mattr_accessor :history
|
704
|
+
mattr_accessor :loaded
|
705
|
+
mattr_accessor :mechanism
|
706
|
+
mattr_accessor :load_paths
|
707
|
+
mattr_accessor :load_once_paths
|
708
|
+
mattr_accessor :autoloaded_constants
|
709
|
+
mattr_accessor :explicitly_unloadable_constants
|
710
|
+
mattr_accessor :logger
|
711
|
+
mattr_accessor :log_activity
|
712
|
+
mattr_accessor :constant_watch_stack
|
713
|
+
mattr_accessor :constant_watch_stack_mutex
|
714
|
+
end
|
715
|
+
end
|
716
|
+
</ruby>
|
717
|
+
|
718
|
+
NOTE: Defined in +active_support/core_ext/module/attribute_accessors.rb+.
|
719
|
+
|
720
|
+
h4. Method Delegation
|
721
|
+
|
722
|
+
The class method +delegate+ offers an easy way to forward methods.
|
723
|
+
|
724
|
+
For example, if +User+ has some details like the age factored out to +Profile+, it could be handy to still be able to acces such attribute directly, <tt>user.age</tt>, instead of having to explicit the chain <tt>user.profile.age</tt>.
|
725
|
+
|
726
|
+
That can be accomplished by hand:
|
727
|
+
|
728
|
+
<ruby>
|
729
|
+
class User
|
730
|
+
has_one :profile
|
731
|
+
|
732
|
+
def age
|
733
|
+
profile.age
|
734
|
+
end
|
735
|
+
end
|
736
|
+
</ruby>
|
737
|
+
|
738
|
+
But with +delegate+ you can make that shorter and the intention even more obvious:
|
739
|
+
|
740
|
+
<ruby>
|
741
|
+
class User
|
742
|
+
has_one :profile
|
743
|
+
|
744
|
+
delegate :age, to => :profile
|
745
|
+
end
|
746
|
+
</ruby>
|
747
|
+
|
748
|
+
The macro accepts more than one method:
|
749
|
+
|
750
|
+
<ruby>
|
751
|
+
class User
|
752
|
+
has_one :profile
|
753
|
+
|
754
|
+
delegate :age, :avatar, :twitter_username, to => :profile
|
755
|
+
end
|
756
|
+
</ruby>
|
757
|
+
|
758
|
+
Methods can be delegated to objects returned by methods, as in the examples above, but also to instance variables, class variables, and constants. Just pass their names as symbols or strings, including the at signs in the last cases.
|
759
|
+
|
760
|
+
For example, +ActionView::Base+ delegates +erb_trim_mode=+:
|
761
|
+
|
762
|
+
<ruby>
|
763
|
+
module ActionView
|
764
|
+
class Base
|
765
|
+
delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
|
766
|
+
end
|
767
|
+
end
|
768
|
+
</ruby>
|
769
|
+
|
770
|
+
In fact, you can delegate to any expression passed as a string. It will be evaluated in the context of the receiver. Controllers for example delegate alerts and notices to the current flash:
|
771
|
+
|
772
|
+
<ruby>
|
773
|
+
delegate :alert, :notice, :to => "request.flash"
|
774
|
+
</ruby>
|
775
|
+
|
776
|
+
If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behavior setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+.
|
777
|
+
|
778
|
+
If the target is a method, the name of delegated methods can also be prefixed. If the +:prefix+ option is set to (exactly) the +true+ object, the value of the +:to+ option is prefixed:
|
779
|
+
|
780
|
+
<ruby>
|
781
|
+
class Invoice
|
782
|
+
belongs_to :customer
|
783
|
+
|
784
|
+
# defines a method called customer_name
|
785
|
+
delegate :name, :to => :customer, :prefix => true
|
786
|
+
end
|
787
|
+
</ruby>
|
788
|
+
|
789
|
+
And a custom prefix can be set as well, in that case it does not matter wheter the target is a method or not:
|
790
|
+
|
791
|
+
<ruby>
|
792
|
+
class Account
|
793
|
+
belongs_to :user
|
794
|
+
|
795
|
+
# defines a method called admin_email
|
796
|
+
delegate :email, :to => :user, :prefix => 'admin'
|
797
|
+
end
|
798
|
+
</ruby>
|
799
|
+
|
800
|
+
NOTE: Defined in +active_support/core_ext/module/delegation.rb+.
|
801
|
+
|
802
|
+
h4. Method Removal
|
803
|
+
|
804
|
+
h5. +remove_possible_method+
|
805
|
+
|
806
|
+
The method +remove_possible_method+ is like the standard +remove_method+, except it silently returns on failure:
|
807
|
+
|
808
|
+
<ruby>
|
809
|
+
class A; end
|
810
|
+
|
811
|
+
A.class_eval do
|
812
|
+
remove_method(:nonexistent) # raises NameError
|
813
|
+
remove_possible_method(:nonexistent) # no problem, continue
|
814
|
+
end
|
815
|
+
</ruby>
|
816
|
+
|
817
|
+
This may come in handy if you need to define a method that may already exist, since redefining a method issues a warning "method redefined; discarding old redefined_method_name".
|
818
|
+
|
819
|
+
NOTE: Defined in +active_support/core_ext/module/remove_method.rb+.
|
820
|
+
|
821
|
+
h4. Parents
|
822
|
+
|
823
|
+
h5. +parent+
|
824
|
+
|
825
|
+
The +parent+ method on a nested named module returns the module that contains its corresponding constant:
|
826
|
+
|
827
|
+
<ruby>
|
828
|
+
module X
|
829
|
+
module Y
|
830
|
+
module Z
|
831
|
+
end
|
832
|
+
end
|
833
|
+
end
|
834
|
+
M = X::Y::Z
|
835
|
+
|
836
|
+
X::Y::Z.parent # => X::Y
|
837
|
+
M.parent # => X::Y
|
838
|
+
</ruby>
|
839
|
+
|
840
|
+
If the module is anonymous or belongs to the top-level, +parent+ returns +Object+.
|
841
|
+
|
842
|
+
WARNING: Note that in that case +parent_name+ returns +nil+.
|
843
|
+
|
844
|
+
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
|
845
|
+
|
846
|
+
h5. +parent_name+
|
847
|
+
|
848
|
+
The +parent_name+ method on a nested named module returns the fully-qualified name of the module that contains its corresponding constant:
|
849
|
+
|
850
|
+
<ruby>
|
851
|
+
module X
|
852
|
+
module Y
|
853
|
+
module Z
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
857
|
+
M = X::Y::Z
|
858
|
+
|
859
|
+
X::Y::Z.parent_name # => "X::Y"
|
860
|
+
M.parent_name # => "X::Y"
|
861
|
+
</ruby>
|
862
|
+
|
863
|
+
For top-level or anonymous modules +parent_name+ returns +nil+.
|
864
|
+
|
865
|
+
WARNING: Note that in that case +parent+ returns +Object+.
|
866
|
+
|
867
|
+
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
|
868
|
+
|
869
|
+
h5. +parents+
|
870
|
+
|
871
|
+
The method +parents+ calls +parent+ on the receiver and upwards until +Object+ is reached. The chain is returned in an array, from bottom to top:
|
872
|
+
|
873
|
+
<ruby>
|
874
|
+
module X
|
875
|
+
module Y
|
876
|
+
module Z
|
877
|
+
end
|
878
|
+
end
|
879
|
+
end
|
880
|
+
M = X::Y::Z
|
881
|
+
|
882
|
+
X::Y::Z.parents # => [X::Y, X, Object]
|
883
|
+
M.parents # => [X::Y, X, Object]
|
884
|
+
</ruby>
|
885
|
+
|
886
|
+
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
|
887
|
+
|
888
|
+
h4. Constants
|
889
|
+
|
890
|
+
The method +local_constants+ returns the names of the constants that have been defined in the receiver module:
|
891
|
+
|
892
|
+
<ruby>
|
893
|
+
module X
|
894
|
+
X1 = 1
|
895
|
+
X2 = 2
|
896
|
+
module Y
|
897
|
+
Y1 = :y1
|
898
|
+
X1 = :overrides_X1_above
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8
|
903
|
+
X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8
|
904
|
+
</ruby>
|
905
|
+
|
906
|
+
The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ returns always strings.
|
907
|
+
|
908
|
+
WARNING: This method is exact if running under Ruby 1.9. In previous versions it may miss some constants if their value in some ancestor stores the exact same object than in the receiver.
|
909
|
+
|
910
|
+
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
|
911
|
+
|
912
|
+
h4. Synchronization
|
913
|
+
|
914
|
+
The +synchronize+ macro declares a method to be synchronized:
|
915
|
+
|
916
|
+
<ruby>
|
917
|
+
class Counter
|
918
|
+
@@mutex = Mutex.new
|
919
|
+
attr_reader :value
|
920
|
+
|
921
|
+
def initialize
|
922
|
+
@value = 0
|
923
|
+
end
|
924
|
+
|
925
|
+
def incr
|
926
|
+
@value += 1 # non-atomic
|
927
|
+
end
|
928
|
+
synchronize :incr, :with => '@@mutex'
|
929
|
+
end
|
930
|
+
</ruby>
|
931
|
+
|
932
|
+
The method receives the name of an action, and a +:with+ option with code. The code is evaluated in the context of the receiver each time the method is invoked, and it should evaluate to a +Mutex+ instance or any other object that responds to +synchronize+ and accepts a block.
|
933
|
+
|
934
|
+
NOTE: Defined in +active_support/core_ext/module/synchronization.rb+.
|
935
|
+
|
936
|
+
h4. Reachable
|
937
|
+
|
938
|
+
A named module is reachable if it is stored in its correspoding constant. It means you can reach the module object via the constant.
|
939
|
+
|
940
|
+
That is what ordinarily happens, if a module is called "M", the +M+ constant exists and holds it:
|
941
|
+
|
942
|
+
<ruby>
|
943
|
+
module M
|
944
|
+
end
|
945
|
+
|
946
|
+
M.reachable? # => true
|
947
|
+
</ruby>
|
948
|
+
|
949
|
+
But since constants and modules are indeed kind of decoupled, module objects can become unreachable:
|
950
|
+
|
951
|
+
<ruby>
|
952
|
+
module M
|
953
|
+
end
|
954
|
+
|
955
|
+
orphan = Object.send(:remove_const, :M)
|
956
|
+
|
957
|
+
# The module object is orphan now but it still has a name.
|
958
|
+
orphan.name # => "M"
|
959
|
+
|
960
|
+
# You cannot reach it via the constant M because it does not even exist.
|
961
|
+
orphan.reachable? # => false
|
962
|
+
|
963
|
+
# Let's define a module called "M" again.
|
964
|
+
module M
|
965
|
+
end
|
966
|
+
|
967
|
+
# The constant M exists now again, and it stores a module
|
968
|
+
# object called "M", but it is a new instance.
|
969
|
+
orphan.reachable? # => false
|
970
|
+
</ruby>
|
971
|
+
|
972
|
+
NOTE: Defined in +active_support/core_ext/module/reachable.rb+.
|
973
|
+
|
974
|
+
h4. Anonymous
|
975
|
+
|
976
|
+
A module may or may not have a name:
|
977
|
+
|
978
|
+
<ruby>
|
979
|
+
module M
|
980
|
+
end
|
981
|
+
M.name # => "M"
|
982
|
+
|
983
|
+
N = Module.new
|
984
|
+
N.name # => "N"
|
985
|
+
|
986
|
+
Module.new.name # => "" in 1.8, nil in 1.9
|
987
|
+
</ruby>
|
988
|
+
|
989
|
+
You can check whether a module has a name with the predicate +anonymous?+:
|
990
|
+
|
991
|
+
<ruby>
|
992
|
+
module M
|
460
993
|
end
|
994
|
+
M.anonymous? # => false
|
995
|
+
|
996
|
+
Module.new.anonymous? # => true
|
461
997
|
</ruby>
|
462
998
|
|
463
|
-
|
999
|
+
Note that being unreachable does not imply being anonymous:
|
464
1000
|
|
465
1001
|
<ruby>
|
466
|
-
|
467
|
-
def process_with_stringified_params(...)
|
468
|
-
params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten]
|
469
|
-
process_without_stringified_params(action, params, session, flash, http_method)
|
470
|
-
end
|
471
|
-
alias_method_chain :process, :stringified_params
|
1002
|
+
module M
|
472
1003
|
end
|
1004
|
+
|
1005
|
+
m = Object.send(:remove_const, :M)
|
1006
|
+
|
1007
|
+
m.reachable? # => false
|
1008
|
+
m.anonymous? # => false
|
473
1009
|
</ruby>
|
474
1010
|
|
475
|
-
|
1011
|
+
though an anonymous module is unreachable by definition.
|
476
1012
|
|
477
|
-
NOTE: Defined in +active_support/core_ext/module/
|
1013
|
+
NOTE: Defined in +active_support/core_ext/module/anonymous.rb+.
|
478
1014
|
|
479
|
-
|
1015
|
+
h3. Extensions to +Class+
|
480
1016
|
|
481
|
-
|
1017
|
+
h4. Class Attributes
|
1018
|
+
|
1019
|
+
The method +Class#class_attribute+ declares one or more inheritable class attributes that can be overriden at any level down the hierarchy:
|
482
1020
|
|
483
1021
|
<ruby>
|
484
|
-
class
|
485
|
-
|
486
|
-
# much meaningful for authentication code
|
487
|
-
alias_attribute :login, :email
|
1022
|
+
class A
|
1023
|
+
class_attribute :x
|
488
1024
|
end
|
489
|
-
</ruby>
|
490
1025
|
|
491
|
-
|
1026
|
+
class B < A; end
|
492
1027
|
|
493
|
-
|
1028
|
+
class C < B; end
|
494
1029
|
|
495
|
-
|
1030
|
+
A.x = :a
|
1031
|
+
B.x # => :a
|
1032
|
+
C.x # => :a
|
496
1033
|
|
497
|
-
|
1034
|
+
B.x = :b
|
1035
|
+
A.x # => :a
|
1036
|
+
C.x # => :b
|
498
1037
|
|
499
|
-
|
1038
|
+
C.x = :c
|
1039
|
+
A.x # => :a
|
1040
|
+
B.x # => :b
|
1041
|
+
</ruby>
|
1042
|
+
|
1043
|
+
For example that's the way the +allow_forgery_protection+ flag is implemented for controllers:
|
1044
|
+
|
1045
|
+
<ruby>
|
1046
|
+
class_attribute :allow_forgery_protection
|
1047
|
+
self.allow_forgery_protection = true
|
1048
|
+
</ruby>
|
1049
|
+
|
1050
|
+
For convenience +class_attribute+ defines also a predicate, so that declaration also generates +allow_forgery_protection?+. Such predicate returns the double boolean negation of the value.
|
1051
|
+
|
1052
|
+
NOTE: Defined in +active_support/core_ext/class/attribute.rb+
|
500
1053
|
|
501
1054
|
The macros +cattr_reader+, +cattr_writer+, and +cattr_accessor+ are analogous to their +attr_*+ counterparts but for classes. They initialize a class variable to +nil+ unless it already exists, and generate the corresponding class methods to access it:
|
502
1055
|
|
@@ -529,6 +1082,8 @@ module ActiveRecord
|
|
529
1082
|
end
|
530
1083
|
</ruby>
|
531
1084
|
|
1085
|
+
A model may find that option useful as a way to prevent mass-assignment from setting the attribute.
|
1086
|
+
|
532
1087
|
NOTE: Defined in +active_support/core_ext/class/attribute_accessors.rb+.
|
533
1088
|
|
534
1089
|
h4. Class Inheritable Attributes
|
@@ -587,9 +1142,11 @@ If for whatever reason an application loads the definition of a mailer class and
|
|
587
1142
|
|
588
1143
|
NOTE: Defined in +active_support/core_ext/class/delegating_attributes.rb+.
|
589
1144
|
|
590
|
-
h4.
|
1145
|
+
h4. Descendants
|
591
1146
|
|
592
|
-
|
1147
|
+
h5. +subclasses+
|
1148
|
+
|
1149
|
+
The +subclasses+ method returns the names of all the anonymous or reachable descendants of its receiver as an array of strings:
|
593
1150
|
|
594
1151
|
<ruby>
|
595
1152
|
class C; end
|
@@ -614,56 +1171,76 @@ The order in which these class names are returned is unspecified.
|
|
614
1171
|
|
615
1172
|
See also +Object#subclasses_of+ in "Extensions to All Objects FIX THIS LINK":FIXME.
|
616
1173
|
|
617
|
-
|
1174
|
+
WARNING: This method is redefined in some Rails core classes.
|
1175
|
+
|
1176
|
+
NOTE: Defined in +active_support/core_ext/class/subclasses.rb+.
|
1177
|
+
|
1178
|
+
h3. Extensions to +String+
|
1179
|
+
|
1180
|
+
h4. Output Safety
|
1181
|
+
|
1182
|
+
Inserting data into HTML templates needs extra care. For example you can't just interpolate +@review.title+ verbatim into an HTML page. On one hand if the review title is "Flanagan & Matz rules!" the output won't be well-formed because an ampersand has to be escaped as "&amp;". On the other hand, depending on the application that may be a big security hole because users can inject malicious HTML setting a hand-crafted review title. Check out the "section about cross-site scripting in the Security guide":security.html#cross-site-scripting-xss for further information about the risks.
|
618
1183
|
|
619
|
-
|
1184
|
+
Active Support has the concept of <i>(html) safe</i> strings since Rails 3. A safe string is one that is marked as being insertable into HTML as is. It is trusted, no matter whether it has been escaped or not.
|
620
1185
|
|
621
|
-
|
1186
|
+
Strings are considered to be <i>unsafe</i> by default:
|
622
1187
|
|
623
1188
|
<ruby>
|
624
|
-
|
625
|
-
Hash # => NameError: uninitialized constant Hash
|
626
|
-
Dir # => NameError: uninitialized constant Dir
|
1189
|
+
"".html_safe? # => false
|
627
1190
|
</ruby>
|
628
1191
|
|
629
|
-
|
1192
|
+
You can obtain a safe string from a given one with the +html_safe+ method:
|
630
1193
|
|
631
1194
|
<ruby>
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
end
|
636
|
-
|
637
|
-
A2 = M::A
|
1195
|
+
s = "".html_safe
|
1196
|
+
s.html_safe? # => true
|
1197
|
+
</ruby>
|
638
1198
|
|
639
|
-
|
640
|
-
Class.remove_class(M::A)
|
1199
|
+
It is important to understand that +html_safe+ performs no escaping whatsoever, it is just an assertion:
|
641
1200
|
|
642
|
-
|
643
|
-
|
1201
|
+
<ruby>
|
1202
|
+
s = "<script>...</script>".html_safe
|
1203
|
+
s.html_safe? # => true
|
1204
|
+
s # => "<script>...</script>"
|
644
1205
|
</ruby>
|
645
1206
|
|
646
|
-
|
1207
|
+
It is your responsability to ensure calling +html_safe+ on a particular string is fine.
|
647
1208
|
|
648
|
-
|
1209
|
+
NOTE: For performance reasons safe strings are implemented in a way that cannot offer an in-place +html_safe!+ variant.
|
1210
|
+
|
1211
|
+
If you append onto a safe string, either in-place with +concat+/<tt><<</tt>, or with <tt>+</tt>, the result is a safe string. Unsafe arguments are escaped:
|
649
1212
|
|
650
1213
|
<ruby>
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
1214
|
+
"".html_safe + "<" # => "<"
|
1215
|
+
</ruby>
|
1216
|
+
|
1217
|
+
Safe arguments are directly appended:
|
655
1218
|
|
656
|
-
|
657
|
-
|
658
|
-
A.subclasses # => []
|
659
|
-
C # => NameError: uninitialized constant C
|
1219
|
+
<ruby>
|
1220
|
+
"".html_safe + "<".html_safe # => "<"
|
660
1221
|
</ruby>
|
661
1222
|
|
662
|
-
|
1223
|
+
These methods should not be used in ordinary views. In Rails 3 unsafe values are automatically escaped:
|
663
1224
|
|
664
|
-
|
1225
|
+
<erb>
|
1226
|
+
<%= @review.title %> <%# fine in Rails 3, escaped if needed %>
|
1227
|
+
</erb>
|
665
1228
|
|
666
|
-
|
1229
|
+
To insert something verbatim use the +raw+ helper rather than calling +html_safe+:
|
1230
|
+
|
1231
|
+
<erb>
|
1232
|
+
<%= raw @cms.current_template %> <%# inserts @cms.current_template as is %>
|
1233
|
+
</erb>
|
1234
|
+
|
1235
|
+
The +raw+ helper calls +html_safe+ for you:
|
1236
|
+
|
1237
|
+
<ruby>
|
1238
|
+
def raw(stringish)
|
1239
|
+
stringish.to_s.html_safe
|
1240
|
+
end
|
1241
|
+
</ruby>
|
1242
|
+
|
1243
|
+
NOTE: Defined in +active_support/core_ext/string/output_safety.rb+.
|
667
1244
|
|
668
1245
|
h4. +squish+
|
669
1246
|
|
@@ -755,6 +1332,338 @@ The call +str.last(n)+ is equivalent to +str.from(-n)+ if +n+ > 0, and returns a
|
|
755
1332
|
|
756
1333
|
NOTE: Defined in +active_support/core_ext/string/access.rb+.
|
757
1334
|
|
1335
|
+
h4. Inflections
|
1336
|
+
|
1337
|
+
h5. +pluralize+
|
1338
|
+
|
1339
|
+
The method +pluralize+ returns the plural of its receiver:
|
1340
|
+
|
1341
|
+
<ruby>
|
1342
|
+
"table".pluralize # => "tables"
|
1343
|
+
"ruby".pluralize # => "rubies"
|
1344
|
+
"equipment".pluralize # => "equipment"
|
1345
|
+
</ruby>
|
1346
|
+
|
1347
|
+
As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Builtin rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments.
|
1348
|
+
|
1349
|
+
Active Record uses this method to compute the default table name that corresponds to a model:
|
1350
|
+
|
1351
|
+
<ruby>
|
1352
|
+
# active_record/base.rb
|
1353
|
+
def undecorated_table_name(class_name = base_class.name)
|
1354
|
+
table_name = class_name.to_s.demodulize.underscore
|
1355
|
+
table_name = table_name.pluralize if pluralize_table_names
|
1356
|
+
table_name
|
1357
|
+
end
|
1358
|
+
</ruby>
|
1359
|
+
|
1360
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1361
|
+
|
1362
|
+
h5. +singularize+
|
1363
|
+
|
1364
|
+
The inverse of +pluralize+:
|
1365
|
+
|
1366
|
+
<ruby>
|
1367
|
+
"tables".singularize # => "table"
|
1368
|
+
"rubies".singularize # => "ruby"
|
1369
|
+
"equipment".singularize # => "equipment"
|
1370
|
+
</ruby>
|
1371
|
+
|
1372
|
+
Associations compute the name of the corresponding default associated class using this method:
|
1373
|
+
|
1374
|
+
<ruby>
|
1375
|
+
# active_record/reflection.rb
|
1376
|
+
def derive_class_name
|
1377
|
+
class_name = name.to_s.camelize
|
1378
|
+
class_name = class_name.singularize if collection?
|
1379
|
+
class_name
|
1380
|
+
end
|
1381
|
+
</ruby>
|
1382
|
+
|
1383
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1384
|
+
|
1385
|
+
h5. +camelize+
|
1386
|
+
|
1387
|
+
The method +camelize+ returns its receiver in camel case:
|
1388
|
+
|
1389
|
+
<ruby>
|
1390
|
+
"product".camelize # => "Product"
|
1391
|
+
"admin_user".camelize # => "AdminUser"
|
1392
|
+
</ruby>
|
1393
|
+
|
1394
|
+
As a rule of thumb you can think of this method as the one that transforms paths into Ruby class or module names, where slashes separate namespaces:
|
1395
|
+
|
1396
|
+
<ruby>
|
1397
|
+
"backoffice/session".camelize # => "Backoffice::Session"
|
1398
|
+
</ruby>
|
1399
|
+
|
1400
|
+
For example, Action Pack uses this method to load the class that provides a certain session store:
|
1401
|
+
|
1402
|
+
<ruby>
|
1403
|
+
# action_controller/metal/session_management.rb
|
1404
|
+
def session_store=(store)
|
1405
|
+
if store == :active_record_store
|
1406
|
+
self.session_store = ActiveRecord::SessionStore
|
1407
|
+
else
|
1408
|
+
@@session_store = store.is_a?(Symbol) ?
|
1409
|
+
ActionDispatch::Session.const_get(store.to_s.camelize) :
|
1410
|
+
store
|
1411
|
+
end
|
1412
|
+
end
|
1413
|
+
</ruby>
|
1414
|
+
|
1415
|
+
+camelize+ accepts an optional argument, it can be +:upper+ (default), or +:lower+. With the latter the first letter becomes lowercase:
|
1416
|
+
|
1417
|
+
<ruby>
|
1418
|
+
"visual_effect".camelize(:lower) # => "visualEffect"
|
1419
|
+
</ruby>
|
1420
|
+
|
1421
|
+
That may be handy to compute method names in a language that follows that convention, for example JavaScript.
|
1422
|
+
|
1423
|
+
+camelize+ is aliased to +camelcase+.
|
1424
|
+
|
1425
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1426
|
+
|
1427
|
+
h5. +underscore+
|
1428
|
+
|
1429
|
+
The method +underscore+ is the inverse of +camelize+, explained above:
|
1430
|
+
|
1431
|
+
<ruby>
|
1432
|
+
"Product".underscore # => "product"
|
1433
|
+
"AdminUser".underscore # => "admin_user"
|
1434
|
+
</ruby>
|
1435
|
+
|
1436
|
+
Also converts "::" back to "/":
|
1437
|
+
|
1438
|
+
<ruby>
|
1439
|
+
"Backoffice::Session".underscore # => "backoffice/session"
|
1440
|
+
</ruby>
|
1441
|
+
|
1442
|
+
and understands strings that start with lowercase:
|
1443
|
+
|
1444
|
+
<ruby>
|
1445
|
+
"visualEffect".underscore # => "visual_effect"
|
1446
|
+
</ruby>
|
1447
|
+
|
1448
|
+
+underscore+ accepts no argument though.
|
1449
|
+
|
1450
|
+
Rails class and module autoloading uses +underscore+ to infer the relative path without extension of a file that would define a given missing constant:
|
1451
|
+
|
1452
|
+
<ruby>
|
1453
|
+
# active_support/dependencies.rb
|
1454
|
+
def load_missing_constant(from_mod, const_name)
|
1455
|
+
...
|
1456
|
+
qualified_name = qualified_name_for from_mod, const_name
|
1457
|
+
path_suffix = qualified_name.underscore
|
1458
|
+
...
|
1459
|
+
end
|
1460
|
+
</ruby>
|
1461
|
+
|
1462
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1463
|
+
|
1464
|
+
h5. +titleize+
|
1465
|
+
|
1466
|
+
The method +titleize+ capitalizes the words in the receiver:
|
1467
|
+
|
1468
|
+
<ruby>
|
1469
|
+
"alice in wonderland".titleize # => "Alice In Wonderland"
|
1470
|
+
"fermat's enigma".titleize # => "Fermat's Enigma"
|
1471
|
+
</ruby>
|
1472
|
+
|
1473
|
+
+titleize+ is aliased to +titlecase+.
|
1474
|
+
|
1475
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1476
|
+
|
1477
|
+
h5. +dasherize+
|
1478
|
+
|
1479
|
+
The method +dasherize+ replaces the underscores in the receiver with dashes:
|
1480
|
+
|
1481
|
+
<ruby>
|
1482
|
+
"name".dasherize # => "name"
|
1483
|
+
"contact_data".dasherize # => "contact-data"
|
1484
|
+
</ruby>
|
1485
|
+
|
1486
|
+
The XML serializer of models uses this method to dasherize node names:
|
1487
|
+
|
1488
|
+
<ruby>
|
1489
|
+
# active_model/serializers/xml.rb
|
1490
|
+
def reformat_name(name)
|
1491
|
+
name = name.camelize if camelize?
|
1492
|
+
dasherize? ? name.dasherize : name
|
1493
|
+
end
|
1494
|
+
</ruby>
|
1495
|
+
|
1496
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1497
|
+
|
1498
|
+
h5. +demodulize+
|
1499
|
+
|
1500
|
+
Given a string with a qualified constant reference expression, +demodulize+ returns the very constant name, that is, the rightmost part of it:
|
1501
|
+
|
1502
|
+
<ruby>
|
1503
|
+
"Product".demodulize # => "Product"
|
1504
|
+
"Backoffice::UsersController".demodulize # => "UsersController"
|
1505
|
+
"Admin::Hotel::ReservationUtils".demodulize # => "ReservationUtils"
|
1506
|
+
</ruby>
|
1507
|
+
|
1508
|
+
Active Record for example uses this method to compute the name of a counter cache column:
|
1509
|
+
|
1510
|
+
<ruby>
|
1511
|
+
# active_record/reflection.rb
|
1512
|
+
def counter_cache_column
|
1513
|
+
if options[:counter_cache] == true
|
1514
|
+
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
1515
|
+
elsif options[:counter_cache]
|
1516
|
+
options[:counter_cache]
|
1517
|
+
end
|
1518
|
+
end
|
1519
|
+
</ruby>
|
1520
|
+
|
1521
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1522
|
+
|
1523
|
+
h5. +parameterize+
|
1524
|
+
|
1525
|
+
The method +parameterize+ normalizes its receiver in a way that can be used in pretty URLs.
|
1526
|
+
|
1527
|
+
<ruby>
|
1528
|
+
"John Smith".parameterize # => "john-smith"
|
1529
|
+
"Kurt Gödel".parameterize # => "kurt-godel"
|
1530
|
+
</ruby>
|
1531
|
+
|
1532
|
+
In fact, the result string is wrapped in an instance of +ActiveSupport::Multibyte::Chars+.
|
1533
|
+
|
1534
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1535
|
+
|
1536
|
+
h5. +tableize+
|
1537
|
+
|
1538
|
+
The method +tableize+ is +underscore+ followed by +pluralize+.
|
1539
|
+
|
1540
|
+
<ruby>
|
1541
|
+
"Person".tableize # => "people"
|
1542
|
+
"Invoice".tableize # => "invoices"
|
1543
|
+
"InvoiceLine".tableize # => "invoice_lines"
|
1544
|
+
</ruby>
|
1545
|
+
|
1546
|
+
As a rule of thumb, +tableize+ returns the table name that corresponds to a given model for simple cases. The actual implementation in Active Record is not straight +tableize+ indeed, because it also demodulizes de class name and checks a few options that may affect the returned string.
|
1547
|
+
|
1548
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1549
|
+
|
1550
|
+
h5. +classify+
|
1551
|
+
|
1552
|
+
The method +classify+ is the inverse of +tableize+. It gives you the class name corresponding to a table name:
|
1553
|
+
|
1554
|
+
<ruby>
|
1555
|
+
"people".classify # => "Person"
|
1556
|
+
"invoices".classify # => "Invoice"
|
1557
|
+
"invoice_lines".classify # => "InvoiceLine"
|
1558
|
+
</ruby>
|
1559
|
+
|
1560
|
+
The method understands qualified table names:
|
1561
|
+
|
1562
|
+
<ruby>
|
1563
|
+
"highrise_production.companies".classify # => "Company"
|
1564
|
+
</ruby>
|
1565
|
+
|
1566
|
+
Note that +classify+ returns a class name as a string. You can get the actual class object invoking +constantize+ on it, explained next.
|
1567
|
+
|
1568
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1569
|
+
|
1570
|
+
h5. +constantize+
|
1571
|
+
|
1572
|
+
The method +constantize+ resolves the constant reference expression in its receiver:
|
1573
|
+
|
1574
|
+
<ruby>
|
1575
|
+
"Fixnum".constantize # => Fixnum
|
1576
|
+
|
1577
|
+
module M
|
1578
|
+
X = 1
|
1579
|
+
end
|
1580
|
+
"M::X".constantize # => 1
|
1581
|
+
</ruby>
|
1582
|
+
|
1583
|
+
If the string evaluates to no known constant, or its content is not even a valid constant name, +constantize+ raises +NameError+.
|
1584
|
+
|
1585
|
+
Constant name resolution by +constantize+ starts always at the top-level +Object+ even if there is no leading "::".
|
1586
|
+
|
1587
|
+
<ruby>
|
1588
|
+
X = :in_Object
|
1589
|
+
module M
|
1590
|
+
X = :in_M
|
1591
|
+
|
1592
|
+
X # => :in_M
|
1593
|
+
"::X".constantize # => :in_Object
|
1594
|
+
"X".constantize # => :in_Object (!)
|
1595
|
+
end
|
1596
|
+
</ruby>
|
1597
|
+
|
1598
|
+
So, it is in general not equivalent to what Ruby would do in the same spot, had a real constant be evaluated.
|
1599
|
+
|
1600
|
+
Mailer test cases obtain the mailer being tested from the name of the test class using +constantize+:
|
1601
|
+
|
1602
|
+
<ruby>
|
1603
|
+
# action_mailer/test_case.rb
|
1604
|
+
def determine_default_mailer(name)
|
1605
|
+
name.sub(/Test$/, '').constantize
|
1606
|
+
rescue NameError => e
|
1607
|
+
raise NonInferrableMailerError.new(name)
|
1608
|
+
end
|
1609
|
+
</ruby>
|
1610
|
+
|
1611
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1612
|
+
|
1613
|
+
h5. +humanize+
|
1614
|
+
|
1615
|
+
The method +humanize+ gives you a sensible name for display out of an attribute name. To do so it replaces underscores with spaces, removes any "_id" suffix, and capitalizes the first word:
|
1616
|
+
|
1617
|
+
<ruby>
|
1618
|
+
"name".humanize # => "Name"
|
1619
|
+
"author_id".humanize # => "Author"
|
1620
|
+
"comments_count".humanize # => "Comments count"
|
1621
|
+
</ruby>
|
1622
|
+
|
1623
|
+
The helper method +full_messages+ uses +humanize+ as a fallback to include attribute names:
|
1624
|
+
|
1625
|
+
<ruby>
|
1626
|
+
def full_messages
|
1627
|
+
full_messages = []
|
1628
|
+
|
1629
|
+
each do |attribute, messages|
|
1630
|
+
...
|
1631
|
+
attr_name = attribute.to_s.gsub('.', '_').humanize
|
1632
|
+
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
|
1633
|
+
...
|
1634
|
+
end
|
1635
|
+
|
1636
|
+
full_messages
|
1637
|
+
end
|
1638
|
+
</ruby>
|
1639
|
+
|
1640
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1641
|
+
|
1642
|
+
h5. +foreign_key+
|
1643
|
+
|
1644
|
+
The method +foreign_key+ gives a foreign key column name from a class name. To do so it demodulizes, underscores, and adds "_id":
|
1645
|
+
|
1646
|
+
<ruby>
|
1647
|
+
"User".foreign_key # => "user_id"
|
1648
|
+
"InvoiceLine".foreign_key # => "invoice_line_id"
|
1649
|
+
"Admin::Session".foreign_key # => "session_id"
|
1650
|
+
</ruby>
|
1651
|
+
|
1652
|
+
Pass a false argument if you do not want the underscore in "_id":
|
1653
|
+
|
1654
|
+
<ruby>
|
1655
|
+
"User".foreign_key(false) # => "userid"
|
1656
|
+
</ruby>
|
1657
|
+
|
1658
|
+
Associations use this method to infer foreign keys, for example +has_one+ and +has_many+ do this:
|
1659
|
+
|
1660
|
+
<ruby>
|
1661
|
+
# active_record/associations.rb
|
1662
|
+
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
|
1663
|
+
</ruby>
|
1664
|
+
|
1665
|
+
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
|
1666
|
+
|
758
1667
|
h3. Extensions to +Numeric+
|
759
1668
|
|
760
1669
|
h4. Bytes
|
@@ -816,7 +1725,15 @@ NOTE: Defined in +active_support/core_ext/integer/inflections.rb+.
|
|
816
1725
|
|
817
1726
|
h3. Extensions to +Float+
|
818
1727
|
|
819
|
-
|
1728
|
+
h4. +round+
|
1729
|
+
|
1730
|
+
The builtin method +Float#round+ rounds a float to the nearest integer. Active Support adds an optional parameter to let you specify a precision:
|
1731
|
+
|
1732
|
+
<ruby>
|
1733
|
+
Math::E.round(4) # => 2.7183
|
1734
|
+
</ruby>
|
1735
|
+
|
1736
|
+
NOTE: Defined in +active_support/core_ext/float/rounding.rb+.
|
820
1737
|
|
821
1738
|
h3. Extensions to +BigDecimal+
|
822
1739
|
|
@@ -1765,7 +2682,7 @@ File.atomic_write(joined_asset_path) do |cache|
|
|
1765
2682
|
end
|
1766
2683
|
</ruby>
|
1767
2684
|
|
1768
|
-
To accomplish this +atomic_write+ creates a temporary file. That's the file the code in the block actually writes to. On completion, the temporary file is renamed. If the target file exists +atomic_write+ overwrites it and keeps owners and permissions.
|
2685
|
+
To accomplish this +atomic_write+ creates a temporary file. That's the file the code in the block actually writes to. On completion, the temporary file is renamed, which is an atomic operation on POSIX systems. If the target file exists +atomic_write+ overwrites it and keeps owners and permissions.
|
1769
2686
|
|
1770
2687
|
WARNING. Note you can't append with +atomic_write+.
|
1771
2688
|
|
@@ -1799,20 +2716,11 @@ NOTE: Defined in +active_support/core_ext/name_error.rb+.
|
|
1799
2716
|
|
1800
2717
|
h3. Extensions to +LoadError+
|
1801
2718
|
|
1802
|
-
|
2719
|
+
Active Support adds +is_missing?+ to +LoadError+, and also assigns that class to the constant +MissingSourceFile+ for backwards compatibility.
|
1803
2720
|
|
1804
|
-
|
1805
|
-
$ ruby -e 'require "nonexistent"'
|
1806
|
-
...: no such file to load -- nonexistent (LoadError)
|
1807
|
-
...
|
1808
|
-
$ script/runner 'require "nonexistent"'
|
1809
|
-
...: no such file to load -- nonexistent (MissingSourceFile)
|
1810
|
-
...
|
1811
|
-
</shell>
|
2721
|
+
Given a path name +is_missing?+ tests whether the exception was raised due to that particular file (except perhaps for the ".rb" extension).
|
1812
2722
|
|
1813
|
-
|
1814
|
-
|
1815
|
-
For example, when an action of +PostsController+ is called Rails tries to load +posts_helper.rb+, but that file may not exist. That's fine, the helper module is not mandatory so Rails silences a load error. But it could be the case that the helper module does exist, but it in turn requires another library that is missing. In that case Rails must reraise the exception. The method +is_missing?+ provides a way to distinguish both cases:
|
2723
|
+
For example, when an action of +PostsController+ is called Rails tries to load +posts_helper.rb+, but that file may not exist. That's fine, the helper module is not mandatory so Rails silences a load error. But it could be the case that the helper module does exist and in turn requires another library that is missing. In that case Rails must reraise the exception. The method +is_missing?+ provides a way to distinguish both cases:
|
1816
2724
|
|
1817
2725
|
<ruby>
|
1818
2726
|
def default_helper_module!
|
@@ -1820,7 +2728,7 @@ def default_helper_module!
|
|
1820
2728
|
module_path = module_name.underscore
|
1821
2729
|
helper module_path
|
1822
2730
|
rescue MissingSourceFile => e
|
1823
|
-
raise e unless e.is_missing? "
|
2731
|
+
raise e unless e.is_missing? "helpers/#{module_path}_helper"
|
1824
2732
|
rescue NameError => e
|
1825
2733
|
raise e unless e.missing_name? "#{module_name}Helper"
|
1826
2734
|
end
|