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.textile284
1 files changed, 233 insertions, 51 deletions
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 66869b4eeb..ff6c5f967f 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.
@@ -436,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?+.
@@ -512,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+.
@@ -731,12 +719,70 @@ 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+.
+h5. Qualified Constant Names
+
+The standard methods +const_defined?+, +const_get+ , and +const_set+ accept
+bare constant names. Active Support extends this API to be able to pass
+relative qualified constant names.
+
+The new methods are +qualified_const_defined?+, +qualified_const_get+, and
++qualified_const_set+. Their arguments are assumed to be qualified constant
+names relative to their receiver:
+
+<ruby>
+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
+</ruby>
+
+Arguments may be bare constant names:
+
+<ruby>
+Math.qualified_const_get("E") # => 2.718281828459045
+</ruby>
+
+These methods are analogous to their builtin counterparts. In particular,
++qualified_constant_defined?+ accepts an optional second argument in 1.9
+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.
+
+For example, given
+
+<ruby>
+module M
+ X = 1
+end
+
+module N
+ class C
+ include M
+ end
+end
+</ruby>
+
++qualified_const_defined?+ behaves this way:
+
+<ruby>
+N.qualified_const_defined?("C::X", false) # => false (1.9 only)
+N.qualified_const_defined?("C::X", true) # => true (1.9 only)
+N.qualified_const_defined?("C::X") # => false in 1.8, true in 1.9
+</ruby>
+
+As the last example implies, in 1.9 the second argument defaults to true,
+as in +const_defined?+.
+
+For coherence with the builtin methods only relative paths are accepted.
+Absolute qualified constant names like +::Math::PI+ raise +NameError+.
+
+NOTE: Defined in +active_support/core_ext/module/qualified_const.rb+.
+
h4. Synchronization
The +synchronize+ macro declares a method to be synchronized:
@@ -876,13 +922,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
@@ -961,7 +1009,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
@@ -997,7 +1045,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
@@ -1010,7 +1058,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
@@ -1023,8 +1071,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+
@@ -1050,18 +1110,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+.
@@ -1160,8 +1226,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:
@@ -1187,8 +1257,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>
@@ -1229,6 +1297,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:
@@ -1400,6 +1484,14 @@ The method +pluralize+ returns the plural of its receiver:
As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Built-in rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments.
++pluralize+ can also take an optional +count+ parameter. If <tt>count == 1</tt> the singular form will be returned. For any other value of +count+ the plural form will be returned:
+
+<ruby>
+"dude".pluralize(0) # => "dudes"
+"dude".pluralize(1) # => "dude"
+"dude".pluralize(2) # => "dudes"
+</ruby>
+
Active Record uses this method to compute the default table name that corresponds to a model:
<ruby>
@@ -1474,7 +1566,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+.
@@ -1555,7 +1655,7 @@ NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
h5. +demodulize+
-Given a string with a qualified constant reference expression, +demodulize+ returns the very constant name, that is, the rightmost part of it:
+Given a string with a qualified constant name, +demodulize+ returns the very constant name, that is, the rightmost part of it:
<ruby>
"Product".demodulize # => "Product"
@@ -1578,6 +1678,31 @@ end
NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
+h5. +deconstantize+
+
+Given a string with a qualified constant reference expression, +deconstantize+ removes the rightmost segment, generally leaving the name of the constant's container:
+
+<ruby>
+"Product".deconstantize # => ""
+"Backoffice::UsersController".deconstantize # => "Backoffice"
+"Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel"
+</ruby>
+
+Active Support for example uses this method in +Module#qualified_const_set+:
+
+<ruby>
+def qualified_const_set(path, value)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ const_name = path.demodulize
+ mod_name = path.deconstantize
+ mod = mod_name.empty? ? self : qualified_const_get(mod_name)
+ mod.const_set(const_name, value)
+end
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/string/inflections.rb+.
+
h5. +parameterize+
The method +parameterize+ normalizes its receiver in a way that can be used in pretty URLs.
@@ -1726,7 +1851,7 @@ h4(#string-conversions). Conversions
h5. +ord+
-Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encondings like ASCII or ISO-8859-1 in Ruby 1.8:
+Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encodings like ASCII or ISO-8859-1 in Ruby 1.8:
<ruby>
"a".ord # => 97
@@ -1740,7 +1865,7 @@ In Ruby 1.8 +ord+ doesn't work in general in UTF8 strings, use the multibyte sup
"à".mb_chars.ord # => 224, in UTF8
</ruby>
-Note that the 224 is different in both examples. In ISO-8859-1 "à" is represented as a single byte, 224. Its single-character representattion in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à" the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus.
+Note that the 224 is different in both examples. In ISO-8859-1 "à" is represented as a single byte, 224. Its single-character representation in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à" the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus.
INFO: +ord+ is equivalent to +getbyte(0)+.
@@ -2037,6 +2162,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:
@@ -2219,8 +2368,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) # => []
@@ -2296,7 +2445,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)
@@ -2664,6 +2813,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:
@@ -2728,7 +2889,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+.
@@ -3038,7 +3199,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
@@ -3246,7 +3407,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
@@ -3315,7 +3476,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)
@@ -3330,6 +3491,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+:
@@ -3367,7 +3554,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
@@ -3422,8 +3609,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+
@@ -3503,8 +3690,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