aboutsummaryrefslogtreecommitdiffstats
path: root/railties/guides/source/active_support_core_extensions.textile
diff options
context:
space:
mode:
Diffstat (limited to 'railties/guides/source/active_support_core_extensions.textile')
-rw-r--r--railties/guides/source/active_support_core_extensions.textile197
1 files changed, 149 insertions, 48 deletions
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index f2170e120b..addf5f78be 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -78,12 +78,14 @@ The following values are considered to be blank in a Rails application:
* +nil+ and +false+,
-* strings composed only of whitespace, i.e. matching +/\A\s*\z/+,
+* strings composed only of whitespace (see note below),
* empty arrays and hashes, and
* any other object that responds to +empty?+ and it is empty.
+INFO: In Ruby 1.9 the predicate for strings uses the Unicode-aware character class <tt>[:space:]</tt>, so for example U+2029 (paragraph separator) is considered to be whitespace. In Ruby 1.8 whitespace is considered to be <tt>\s</tt> together with the ideographic space U+3000.
+
WARNING: Note that numbers are not mentioned, in particular 0 and 0.0 are *not* blank.
For example, this method from +ActionDispatch::Session::AbstractStore+ uses +blank?+ for checking whether a session key is present:
@@ -294,7 +296,7 @@ This method escapes whatever is needed, both for the key and the value:
<ruby>
account.to_query('company[name]')
-# => "company%5Bname%5D=Johnson+%26+Johnson"
+# => "company%5Bname%5D=Johnson<plus>%26<plus>Johnson"
</ruby>
so its output is ready to be used in a query string.
@@ -417,6 +419,14 @@ silence_stream(STDOUT) do
end
</ruby>
+The +quietly+ method addresses the common use case where you want to silence STDOUT and STDERR, even in subprocesses:
+
+<ruby>
+quietly { system 'bundle install' }
+</ruby>
+
+For example, the railties test suite uses that one in a few places to prevent command messages from being echoed intermixed with the progress status.
+
Silencing exceptions is also possible with +suppress+. This method receives an arbitrary number of exception classes. If an exception is raised during the execution of the block and is +kind_of?+ any of the arguments, +suppress+ captures it and returns silently. Otherwise the exception is reraised:
<ruby>
@@ -428,20 +438,6 @@ end
NOTE: Defined in +active_support/core_ext/kernel/reporting.rb+.
-h4. +require_library_or_gem+
-
-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.
-
-If the first attempt is a failure and +rubygems+ can't be loaded the method raises +LoadError+. A +LoadError+ is also raised if +rubygems+ is available but the argument is not loadable as a gem.
-
-For example, that's the way the MySQL adapter loads the MySQL library:
-
-<ruby>
-require_library_or_gem('mysql')
-</ruby>
-
-NOTE: Defined in +active_support/core_ext/kernel/requires.rb+.
-
h4. +in?+
The predicate +in?+ tests if an object is included in another object. An +ArgumentError+ exception will be raised if the argument passed does not respond to +include?+.
@@ -504,7 +500,7 @@ ActionController::TestCase.class_eval do
end
</ruby>
-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.
+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 specialized in validations.
NOTE: Defined in +active_support/core_ext/module/aliasing.rb+.
@@ -723,9 +719,9 @@ X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8
X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8
</ruby>
-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.
+The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ always returns strings.
-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.
+WARNING: This method returns precise results in Ruby 1.9. In older versions of Ruby, however, it may miss some constants in case the same constant exists in the receiver module as well as in any of its ancestors and both constants point to the same object (objects are compared using +Object#object_id+).
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
@@ -868,13 +864,15 @@ end
It is shorter, and the intention more obvious.
-The macro accepts several methods:
+The method must be public in the target.
+
+The +delegate+ macro accepts several methods:
<ruby>
delegate :name, :age, :address, :twitter, :to => :profile
</ruby>
-When interpolated into a string, the +:to+ option should become an expression that evaluates to the object the method is delegated to. Typically a string or symbol. Such a expression is evaluated in the context of the receiver:
+When interpolated into a string, the +:to+ option should become an expression that evaluates to the object the method is delegated to. Typically a string or symbol. Such an expression is evaluated in the context of the receiver:
<ruby>
# delegates to the Rails constant
@@ -953,7 +951,7 @@ h4. Class Attributes
h5. +class_attribute+
-The method +class_attribute+ declares one or more inheritable class attributes that can be overridden at any level down the hierarchy:
+The method +class_attribute+ declares one or more inheritable class attributes that can be overridden at any level down the hierarchy.
<ruby>
class A
@@ -989,7 +987,7 @@ self.default_params = {
}.freeze
</ruby>
-They can be also accessed and overridden at the instance level:
+They can be also accessed and overridden at the instance level.
<ruby>
A.x = 1
@@ -1002,7 +1000,7 @@ a1.x # => 1, comes from A
a2.x # => 2, overridden in a2
</ruby>
-The generation of the writer instance method can be prevented by setting the option +:instance_writer+ to false, as in
+The generation of the writer instance method can be prevented by setting the option +:instance_writer+ to +false+.
<ruby>
module ActiveRecord
@@ -1015,8 +1013,20 @@ end
A model may find that option useful as a way to prevent mass-assignment from setting the attribute.
+The generation of the reader instance method can be prevented by setting the option +:instance_reader+ to +false+.
+
+<ruby>
+class A
+ class_attribute :x, :instance_reader => false
+end
+
+A.new.x = 1 # NoMethodError
+</ruby>
+
For convenience +class_attribute+ also defines an instance predicate which is the double negation of what the instance reader returns. In the examples above it would be called +x?+.
+When +:instance_reader+ is +false+, the instance predicate returns a +NoMethodError+ just like the reader method.
+
NOTE: Defined in +active_support/core_ext/class/attribute.rb+
h5. +cattr_reader+, +cattr_writer+, and +cattr_accessor+
@@ -1042,18 +1052,24 @@ module ActionView
end
</ruby>
-we can access +field_error_proc+ in views. The generation of the writer instance method can be prevented by setting +:instance_writer+ to +false+ (not any false value, but exactly +false+):
+we can access +field_error_proc+ in views.
+
+The generation of the reader instance method can be prevented by setting +:instance_reader+ to +false+ and the generation of the writer instance method can be prevented by setting +:instance_writer+ to +false+. Generation of both methods can be prevented by setting +:instance_accessor+ to +false+. In all cases, the value must be exactly +false+ and not any false value.
<ruby>
-module ActiveRecord
- class Base
- # No pluralize_table_names= instance writer is generated.
- cattr_accessor :pluralize_table_names, :instance_writer => false
+module A
+ class B
+ # No first_name instance reader is generated.
+ cattr_accessor :first_name, :instance_reader => false
+ # No last_name= instance writer is generated.
+ cattr_accessor :last_name, :instance_writer => false
+ # No surname instance reader or surname= writer is generated.
+ cattr_accessor :surname, :instance_accessor => false
end
end
</ruby>
-A model may find that option useful as a way to prevent mass-assignment from setting the attribute.
+A model may find it useful to set +:instance_accessor+ to +false+ as a way to prevent mass-assignment from setting the attribute.
NOTE: Defined in +active_support/core_ext/class/attribute_accessors.rb+.
@@ -1152,8 +1168,12 @@ h3. Extensions to +String+
h4. Output Safety
+h5. Motivation
+
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;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.
+h5. Safe Strings
+
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.
Strings are considered to be <i>unsafe</i> by default:
@@ -1179,8 +1199,6 @@ s # => "<script>...</script>"
It is your responsibility to ensure calling +html_safe+ on a particular string is fine.
-NOTE: For performance reasons safe strings are implemented in a way that cannot offer an in-place +html_safe!+ variant.
-
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:
<ruby>
@@ -1221,6 +1239,22 @@ end
NOTE: Defined in +active_support/core_ext/string/output_safety.rb+.
+h5. Transformation
+
+As a rule of thumb, except perhaps for concatenation as explained above, any method that may change a string gives you an unsafe string. These are +donwcase+, +gsub+, +strip+, +chomp+, +underscore+, etc.
+
+In the case of in-place transformations like +gsub!+ the receiver itself becomes unsafe.
+
+INFO: The safety bit is lost always, no matter whether the transformation actually changed something.
+
+h5. Conversion and Coercion
+
+Calling +to_s+ on a safe string returns a safe string, but coercion with +to_str+ returns an unsafe string.
+
+h5. Copying
+
+Calling +dup+ or +clone+ on safe strings yields safe strings.
+
h4. +squish+
The method +squish+ strips leading and trailing whitespace, and substitutes runs of whitespace with a single space each:
@@ -1466,7 +1500,15 @@ end
That may be handy to compute method names in a language that follows that convention, for example JavaScript.
-INFO: As a rule of thumb you can think of +camelize+ as the inverse of +underscore+, though there are cases where that does not hold: <tt>"SSLError".underscore.camelize</tt> gives back <tt>"SslError"</tt>.
+INFO: As a rule of thumb you can think of +camelize+ as the inverse of +underscore+, though there are cases where that does not hold: <tt>"SSLError".underscore.camelize</tt> gives back <tt>"SslError"</tt>. To support cases such as this, Active Support allows you to specify acronyms in +config/initializers/inflections.rb+:
+
+<ruby>
+ActiveSupport::Inflector.inflections do |inflect|
+ inflect.acronym 'SSL'
+end
+
+"SSLError".underscore.camelize #=> "SSLError"
+</ruby>
+camelize+ is aliased to +camelcase+.
@@ -1833,6 +1875,8 @@ The method +ordinalize+ returns the ordinal string corresponding to the receiver
2.ordinalize # => "2nd"
53.ordinalize # => "53rd"
2009.ordinalize # => "2009th"
+-21.ordinalize # => "-21st"
+-134.ordinalize # => "-134th"
</ruby>
NOTE: Defined in +active_support/core_ext/integer/inflections.rb+.
@@ -2027,6 +2071,30 @@ shape_types = [Circle, Square, Triangle].sample(2)
NOTE: Defined in +active_support/core_ext/array/random_access.rb+.
+h4. Adding Elements
+
+h5. +prepend+
+
+This method is an alias of <tt>Array#unshift</tt>.
+
+<ruby>
+%w(a b c d).prepend('e') # => %w(e a b c d)
+[].prepend(10) # => [10]
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/array/prepend_and_append.rb+.
+
+h5. +append+
+
+This method is an alias of <tt>Array#<<</tt>.
+
+<ruby>
+%w(a b c d).append('e') # => %w(a b c d e)
+[].append([1,2]) # => [[1,2]]
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/array/prepend_and_append.rb+.
+
h4. Options Extraction
When the last argument in a method call is a hash, except perhaps for a +&block+ argument, Ruby allows you to omit the brackets:
@@ -2209,8 +2277,8 @@ The method +Array.wrap+ wraps its argument in an array unless it is already an a
Specifically:
* If the argument is +nil+ an empty list is returned.
-* Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
-* Otherwise, returns an array with the argument as its single element.
+* Otherwise, if the argument responds to +to_ary+ it is invoked, and if the value of +to_ary+ is not +nil+, it is returned.
+* Otherwise, an array with the argument as its single element is returned.
<ruby>
Array.wrap(nil) # => []
@@ -2286,7 +2354,7 @@ NOTE: Defined in +active_support/core_ext/array/grouping.rb+.
h5. +in_groups(number, fill_with = nil)+
-The method +in_groups+ splits an array into a certain number of groups. The method returns and array with the groups:
+The method +in_groups+ splits an array into a certain number of groups. The method returns an array with the groups:
<ruby>
%w(1 2 3 4 5 6 7).in_groups(3)
@@ -2654,6 +2722,18 @@ hash # => {:a => 1}
NOTE: Defined in +active_support/core_ext/hash/slice.rb+.
+h4. Extracting
+
+The method +extract!+ removes and returns the key/value pairs matching the given keys.
+
+<ruby>
+hash = {:a => 1, :b => 2}
+rest = hash.extract!(:a) # => {:a => 1}
+hash # => {:b => 2}
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/hash/slice.rb+.
+
h4. Indifferent Access
The method +with_indifferent_access+ returns an +ActiveSupport::HashWithIndifferentAccess+ out of its receiver:
@@ -2718,7 +2798,7 @@ Active Support extends the method +Range#step+ so that it can be invoked without
(1..10).step(2) # => [1, 3, 5, 7, 9]
</ruby>
-As the example shows, in that case the method returns and array with the corresponding elements.
+As the example shows, in that case the method returns an array with the corresponding elements.
NOTE: Defined in +active_support/core_ext/range/blockless_step.rb+.
@@ -3028,7 +3108,7 @@ Date.new(2010, 1, 31).change(:month => 2)
h5(#date-durations). Durations
-Durations can be added and substracted to dates:
+Durations can be added to and subtracted from dates:
<ruby>
d = Date.current
@@ -3236,7 +3316,7 @@ DateTime.current.change(:month => 2, :day => 30)
h5(#datetime-durations). Durations
-Durations can be added and substracted to datetimes:
+Durations can be added to and subtracted from datetimes:
<ruby>
now = DateTime.current
@@ -3305,7 +3385,7 @@ They are analogous. Please refer to their documentation above and take into acco
Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
-# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST.
+# In Barcelona, 2010/03/28 02:00 <plus>0100 becomes 2010/03/28 03:00 <plus>0200 due to DST.
t = Time.local_time(2010, 3, 28, 1, 59, 59)
# => Sun Mar 28 01:59:59 +0100 2010
t.advance(:seconds => 1)
@@ -3320,6 +3400,32 @@ Active Support defines +Time.current+ to be today in the current time zone. That
When making Time comparisons using methods which honor the user time zone, make sure to use +Time.current+ and not +Time.now+. There are cases where the user time zone might be in the future compared to the system time zone, which +Time.today+ uses by default. This means +Time.now+ may equal +Time.yesterday+.
+h5. +all_day+, +all_week+, +all_month+, +all_quarter+ and +all_year+
+
+The method +all_day+ returns a range representing the whole day of the current time.
+
+<ruby>
+now = Time.current
+# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
+now.all_day
+# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Mon, 09 Aug 2010 23:59:59 UTC <plus>00:00
+</ruby>
+
+Analogously, +all_week+, +all_month+, +all_quarter+ and +all_year+ all serve the purpose of generating time ranges.
+
+<ruby>
+now = Time.current
+# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
+now.all_week
+# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Sun, 15 Aug 2010 23:59:59 UTC <plus>00:00
+now.all_month
+# => Sat, 01 Aug 2010 00:00:00 UTC <plus>00:00..Tue, 31 Aug 2010 23:59:59 UTC <plus>00:00
+now.all_quarter
+# => Thu, 01 Jul 2010 00:00:00 UTC <plus>00:00..Thu, 30 Sep 2010 23:59:59 UTC <plus>00:00
+now.all_year
+# => Fri, 01 Jan 2010 00:00:00 UTC <plus>00:00..Fri, 31 Dec 2010 23:59:59 UTC <plus>00:00
+</ruby>
+
h4. Time Constructors
Active Support defines +Time.current+ to be +Time.zone.now+ if there's a user time zone defined, with fallback to +Time.now+:
@@ -3357,7 +3463,7 @@ If the time to be constructed lies beyond the range supported by +Time+ in the r
h5(#time-durations). Durations
-Durations can be added and substracted to time objects:
+Durations can be added to and subtracted from time objects:
<ruby>
now = Time.current
@@ -3412,8 +3518,8 @@ h4. +around_[level]+
Takes two arguments, a +before_message+ and +after_message+ and calls the current level method on the +Logger+ instance, passing in the +before_message+, then the specified message, then the +after_message+:
<ruby>
- logger = Logger.new("log/development.log")
- logger.around_info("before", "after") { |logger| logger.info("during") }
+logger = Logger.new("log/development.log")
+logger.around_info("before", "after") { |logger| logger.info("during") }
</ruby>
h4. +silence+
@@ -3493,8 +3599,3 @@ end
</ruby>
NOTE: Defined in +active_support/core_ext/load_error.rb+.
-
-h3. Changelog
-
-* August 10, 2010: Starts to take shape, added to the index.
-* April 18, 2009: Initial version by "Xavier Noria":credits.html#fxn