1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge remote-tracking branch 'docrails/master'

Conflicts:
	activesupport/lib/active_support/core_ext/hash/deep_merge.rb
	activesupport/lib/active_support/core_ext/hash/keys.rb
This commit is contained in:
Xavier Noria 2013-11-24 20:00:24 +01:00
commit 17c29a0df0
29 changed files with 203 additions and 183 deletions

View file

@ -74,7 +74,7 @@ Or you can just chain the methods together like:
== Setting defaults
It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed.
It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from <tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed.
Note that every value you set with this method will get overwritten if you use the same key in your mailer method.

View file

@ -389,7 +389,7 @@ module ActionDispatch
# The namespace for :controller.
#
# match 'path', to: 'c#a', module: 'sekret', controller: 'posts'
# #=> Sekret::PostsController
# # => Sekret::PostsController
#
# See <tt>Scoping#namespace</tt> for its scope equivalent.
#

View file

@ -262,10 +262,10 @@ module ActiveModel
# namespaced models regarding whether it's inside isolated engine.
#
# # For isolated engine:
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> "post"
# ActiveModel::Naming.singular_route_key(Blog::Post) # => "post"
#
# # For shared engine:
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> "blog_post"
# ActiveModel::Naming.singular_route_key(Blog::Post) # => "blog_post"
def self.singular_route_key(record_or_class)
model_name_from_record_or_class(record_or_class).singular_route_key
end
@ -274,10 +274,10 @@ module ActiveModel
# namespaced models regarding whether it's inside isolated engine.
#
# # For isolated engine:
# ActiveModel::Naming.route_key(Blog::Post) #=> "posts"
# ActiveModel::Naming.route_key(Blog::Post) # => "posts"
#
# # For shared engine:
# ActiveModel::Naming.route_key(Blog::Post) #=> "blog_posts"
# ActiveModel::Naming.route_key(Blog::Post) # => "blog_posts"
#
# The route key also considers if the noun is uncountable and, in
# such cases, automatically appends _index.
@ -289,10 +289,10 @@ module ActiveModel
# namespaced models regarding whether it's inside isolated engine.
#
# # For isolated engine:
# ActiveModel::Naming.param_key(Blog::Post) #=> "post"
# ActiveModel::Naming.param_key(Blog::Post) # => "post"
#
# # For shared engine:
# ActiveModel::Naming.param_key(Blog::Post) #=> "blog_post"
# ActiveModel::Naming.param_key(Blog::Post) # => "blog_post"
def self.param_key(record_or_class)
model_name_from_record_or_class(record_or_class).param_key
end

View file

@ -787,12 +787,12 @@ module ActiveRecord
# has_many :pets
# end
#
# person.pets.count #=> 1
# person.pets.many? #=> false
# person.pets.count # => 1
# person.pets.many? # => false
#
# person.pets << Pet.new(name: 'Snoopy')
# person.pets.count #=> 2
# person.pets.many? #=> true
# person.pets.count # => 2
# person.pets.many? # => true
#
# You can also pass a block to define criteria. The
# behavior is the same, it returns true if the collection

View file

@ -83,14 +83,14 @@ module ActiveRecord
# end
#
# If I execute `@physician.patients.to_a` then
# base #=> Physician
# associations #=> []
# joins #=> [#<Arel::Nodes::InnerJoin: ...]
# base # => Physician
# associations # => []
# joins # => [#<Arel::Nodes::InnerJoin: ...]
#
# However if I execute `Physician.joins(:appointments).to_a` then
# base #=> Physician
# associations #=> [:appointments]
# joins #=> []
# base # => Physician
# associations # => [:appointments]
# joins # => []
#
def initialize(base, associations, joins)
@alias_tracker = AliasTracker.new(base.connection, joins)

View file

@ -86,11 +86,11 @@ module ActiveRecord
# end
#
# If I execute `Physician.joins(:appointments).to_a` then
# reflection #=> #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...>
# table #=> #<Arel::Table @name="appointments" ...>
# key #=> physician_id
# foreign_table #=> #<Arel::Table @name="physicians" ...>
# foreign_key #=> id
# reflection # => #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...>
# table # => #<Arel::Table @name="appointments" ...>
# key # => physician_id
# foreign_table # => #<Arel::Table @name="physicians" ...>
# foreign_key # => id
#
def build_constraint(klass, table, key, foreign_table, foreign_key)
constraint = table[key].eq(foreign_table[foreign_key])

View file

@ -559,9 +559,9 @@ module ActiveRecord
# Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
#
# Post.where(trashed: true).where(trashed: false) #=> WHERE `trashed` = 1 AND `trashed` = 0
# Post.where(trashed: true).rewhere(trashed: false) #=> WHERE `trashed` = 0
# Post.where(active: true).where(trashed: true).rewhere(trashed: false) #=> WHERE `active` = 1 AND `trashed` = 0
# Post.where(trashed: true).where(trashed: false) # => WHERE `trashed` = 1 AND `trashed` = 0
# Post.where(trashed: true).rewhere(trashed: false) # => WHERE `trashed` = 0
# Post.where(active: true).where(trashed: true).rewhere(trashed: false) # => WHERE `active` = 1 AND `trashed` = 0
#
# This is short-hand for unscope(where: conditions.keys).where(conditions). Note that unlike reorder, we're only unscoping
# the named conditions -- not the entire where statement.
@ -708,7 +708,7 @@ module ActiveRecord
# Specifies table from which the records will be fetched. For example:
#
# Topic.select('title').from('posts')
# #=> SELECT title FROM posts
# # => SELECT title FROM posts
#
# Can accept other relation objects. For example:
#

View file

@ -361,7 +361,7 @@ module ActiveSupport
#
# cache.write("bim", "bam")
# cache.fetch_multi("bim", "boom") {|key| key * 2 }
# #=> ["bam", "boomboom"]
# # => ["bam", "boomboom"]
#
def fetch_multi(*names)
options = names.extract_options!

View file

@ -173,7 +173,7 @@ class Class
# end
# end
#
# Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red]
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
def cattr_accessor(*syms, &blk)
cattr_reader(*syms)
cattr_writer(*syms, &blk)

View file

@ -4,8 +4,8 @@ class Hash
# h1 = { x: { y: [4, 5, 6] }, z: [7, 8, 9] }
# h2 = { x: { y: [7, 8, 9] }, z: 'xyz' }
#
# h1.deep_merge(h2) # => {:x=>{:y=>[7, 8, 9]}, :z=>"xyz"}
# h2.deep_merge(h1) # => {:x=>{:y=>[4, 5, 6]}, :z=>[7, 8, 9]}
# h1.deep_merge(h2) # => {x: {y: [7, 8, 9]}, z: "xyz"}
# h2.deep_merge(h1) # => {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
# h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
# # => {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
def deep_merge(other_hash, &block)

View file

@ -27,7 +27,7 @@ class Hash
# hash = { name: 'Rob', age: '28' }
#
# hash.stringify_keys
# # => {"name"=>"Rob", "age"=>"28"}
# # => { "name" => "Rob", "age" => "28" }
def stringify_keys
transform_keys{ |key| key.to_s }
end
@ -44,7 +44,7 @@ class Hash
# hash = { 'name' => 'Rob', 'age' => '28' }
#
# hash.symbolize_keys
# # => {"name"=>"Rob", "age"=>"28"}
# # => { name: "Rob", age: "28" }
def symbolize_keys
transform_keys{ |key| key.to_sym rescue key }
end

View file

@ -8,8 +8,8 @@ class Object
# dup = object.deep_dup
# dup.instance_variable_set(:@a, 1)
#
# object.instance_variable_defined?(:@a) #=> false
# dup.instance_variable_defined?(:@a) #=> true
# object.instance_variable_defined?(:@a) # => false
# dup.instance_variable_defined?(:@a) # => true
def deep_dup
duplicable? ? dup : self
end
@ -22,8 +22,8 @@ class Array
# dup = array.deep_dup
# dup[1][2] = 4
#
# array[1][2] #=> nil
# dup[1][2] #=> 4
# array[1][2] # => nil
# dup[1][2] # => 4
def deep_dup
map { |it| it.deep_dup }
end
@ -36,8 +36,8 @@ class Hash
# dup = hash.deep_dup
# dup[:a][:c] = 'c'
#
# hash[:a][:c] #=> nil
# dup[:a][:c] #=> "c"
# hash[:a][:c] # => nil
# dup[:a][:c] # => "c"
def deep_dup
each_with_object(dup) do |(key, value), hash|
hash[key.deep_dup] = value.deep_dup

View file

@ -133,7 +133,7 @@ class BigDecimal
# BigDecimal, it still has the chance to post-process the string and get the
# real value.
#
# Use <tt>ActiveSupport.use_standard_json_big_decimal_format = true</tt> to
# Use <tt>ActiveSupport.encode_big_decimal_as_string = true</tt> to
# override this behavior.
def as_json(options = nil) #:nodoc:
if finite?

View file

@ -8,22 +8,22 @@ class String
# the beginning of the range is greater than the end of the string.
#
# str = "hello"
# str.at(0) #=> "h"
# str.at(1..3) #=> "ell"
# str.at(-2) #=> "l"
# str.at(-2..-1) #=> "lo"
# str.at(5) #=> nil
# str.at(5..-1) #=> ""
# str.at(0) # => "h"
# str.at(1..3) # => "ell"
# str.at(-2) # => "l"
# str.at(-2..-1) # => "lo"
# str.at(5) # => nil
# str.at(5..-1) # => ""
#
# If a Regexp is given, the matching portion of the string is returned.
# If a String is given, that given string is returned if it occurs in
# the string. In both cases, nil is returned if there is no match.
#
# str = "hello"
# str.at(/lo/) #=> "lo"
# str.at(/ol/) #=> nil
# str.at("lo") #=> "lo"
# str.at("ol") #=> nil
# str.at(/lo/) # => "lo"
# str.at(/ol/) # => nil
# str.at("lo") # => "lo"
# str.at("ol") # => nil
def at(position)
self[position]
end
@ -32,15 +32,15 @@ class String
# If the position is negative, it is counted from the end of the string.
#
# str = "hello"
# str.from(0) #=> "hello"
# str.from(3) #=> "lo"
# str.from(-2) #=> "lo"
# str.from(0) # => "hello"
# str.from(3) # => "lo"
# str.from(-2) # => "lo"
#
# You can mix it with +to+ method and do fun things like:
#
# str = "hello"
# str.from(0).to(-1) #=> "hello"
# str.from(1).to(-2) #=> "ell"
# str.from(0).to(-1) # => "hello"
# str.from(1).to(-2) # => "ell"
def from(position)
self[position..-1]
end
@ -49,15 +49,15 @@ class String
# If the position is negative, it is counted from the end of the string.
#
# str = "hello"
# str.to(0) #=> "h"
# str.to(3) #=> "hell"
# str.to(-2) #=> "hell"
# str.to(0) # => "h"
# str.to(3) # => "hell"
# str.to(-2) # => "hell"
#
# You can mix it with +from+ method and do fun things like:
#
# str = "hello"
# str.from(0).to(-1) #=> "hello"
# str.from(1).to(-2) #=> "ell"
# str.from(0).to(-1) # => "hello"
# str.from(1).to(-2) # => "ell"
def to(position)
self[0, position + 1]
end
@ -67,11 +67,11 @@ class String
# given limit is greater than or equal to the string length, returns self.
#
# str = "hello"
# str.first #=> "h"
# str.first(1) #=> "h"
# str.first(2) #=> "he"
# str.first(0) #=> ""
# str.first(6) #=> "hello"
# str.first # => "h"
# str.first(1) # => "h"
# str.first(2) # => "he"
# str.first(0) # => ""
# str.first(6) # => "hello"
def first(limit = 1)
if limit == 0
''
@ -87,11 +87,11 @@ class String
# the given limit is greater than or equal to the string length, returns self.
#
# str = "hello"
# str.last #=> "o"
# str.last(1) #=> "o"
# str.last(2) #=> "lo"
# str.last(0) #=> ""
# str.last(6) #=> "hello"
# str.last # => "o"
# str.last(1) # => "o"
# str.last(2) # => "lo"
# str.last(0) # => ""
# str.last(6) # => "hello"
def last(limit = 1)
if limit == 0
''

View file

@ -36,20 +36,20 @@ class String
# Converts a string to a Date value.
#
# "1-1-2012".to_date #=> Sun, 01 Jan 2012
# "01/01/2012".to_date #=> Sun, 01 Jan 2012
# "2012-12-13".to_date #=> Thu, 13 Dec 2012
# "12/13/2012".to_date #=> ArgumentError: invalid date
# "1-1-2012".to_date # => Sun, 01 Jan 2012
# "01/01/2012".to_date # => Sun, 01 Jan 2012
# "2012-12-13".to_date # => Thu, 13 Dec 2012
# "12/13/2012".to_date # => ArgumentError: invalid date
def to_date
::Date.parse(self, false) unless blank?
end
# Converts a string to a DateTime value.
#
# "1-1-2012".to_datetime #=> Sun, 01 Jan 2012 00:00:00 +0000
# "01/01/2012 23:59:59".to_datetime #=> Sun, 01 Jan 2012 23:59:59 +0000
# "2012-12-13 12:50".to_datetime #=> Thu, 13 Dec 2012 12:50:00 +0000
# "12/13/2012".to_datetime #=> ArgumentError: invalid date
# "1-1-2012".to_datetime # => Sun, 01 Jan 2012 00:00:00 +0000
# "01/01/2012 23:59:59".to_datetime # => Sun, 01 Jan 2012 23:59:59 +0000
# "2012-12-13 12:50".to_datetime # => Thu, 13 Dec 2012 12:50:00 +0000
# "12/13/2012".to_datetime # => ArgumentError: invalid date
def to_datetime
::DateTime.parse(self, false) unless blank?
end

View file

@ -2,9 +2,9 @@ class String
# The inverse of <tt>String#include?</tt>. Returns true if the string
# does not include the other string.
#
# "hello".exclude? "lo" #=> false
# "hello".exclude? "ol" #=> true
# "hello".exclude? ?h #=> false
# "hello".exclude? "lo" # => false
# "hello".exclude? "ol" # => true
# "hello".exclude? ?h # => false
def exclude?(string)
!include?(string)
end

View file

@ -39,8 +39,8 @@ class Thread
# Thread.current.thread_variable_set(:cat, 'meow')
# Thread.current.thread_variable_set("dog", 'woof')
# end
# thr.join #=> #<Thread:0x401b3f10 dead>
# thr.thread_variables #=> [:dog, :cat]
# thr.join # => #<Thread:0x401b3f10 dead>
# thr.thread_variables # => [:dog, :cat]
#
# Note that these are not fiber local variables. Please see Thread#thread_variable_get
# for more details.
@ -53,8 +53,8 @@ class Thread
#
# me = Thread.current
# me.thread_variable_set(:oliver, "a")
# me.thread_variable?(:oliver) #=> true
# me.thread_variable?(:stanley) #=> false
# me.thread_variable?(:oliver) # => true
# me.thread_variable?(:stanley) # => false
#
# Note that these are not fiber local variables. Please see Thread#thread_variable_get
# for more details.

View file

@ -207,7 +207,7 @@ module ActiveSupport
# Replaces the contents of this hash with other_hash.
#
# h = { "a" => 100, "b" => 200 }
# h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
# h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
def replace(other_hash)
super(self.class.new_from_hash_copying_default(other_hash))
end

View file

@ -52,21 +52,21 @@ module ActiveSupport
# into a non-delimited single lowercase word when passed to +underscore+.
#
# acronym 'HTML'
# titleize 'html' #=> 'HTML'
# camelize 'html' #=> 'HTML'
# underscore 'MyHTML' #=> 'my_html'
# titleize 'html' # => 'HTML'
# camelize 'html' # => 'HTML'
# underscore 'MyHTML' # => 'my_html'
#
# The acronym, however, must occur as a delimited unit and not be part of
# another word for conversions to recognize it:
#
# acronym 'HTTP'
# camelize 'my_http_delimited' #=> 'MyHTTPDelimited'
# camelize 'https' #=> 'Https', not 'HTTPs'
# underscore 'HTTPS' #=> 'http_s', not 'https'
# camelize 'my_http_delimited' # => 'MyHTTPDelimited'
# camelize 'https' # => 'Https', not 'HTTPs'
# underscore 'HTTPS' # => 'http_s', not 'https'
#
# acronym 'HTTPS'
# camelize 'https' #=> 'HTTPS'
# underscore 'HTTPS' #=> 'https'
# camelize 'https' # => 'HTTPS'
# underscore 'HTTPS' # => 'https'
#
# Note: Acronyms that are passed to +pluralize+ will no longer be
# recognized, since the acronym will not occur as a delimited unit in the
@ -74,25 +74,25 @@ module ActiveSupport
# form as an acronym as well:
#
# acronym 'API'
# camelize(pluralize('api')) #=> 'Apis'
# camelize(pluralize('api')) # => 'Apis'
#
# acronym 'APIs'
# camelize(pluralize('api')) #=> 'APIs'
# camelize(pluralize('api')) # => 'APIs'
#
# +acronym+ may be used to specify any word that contains an acronym or
# otherwise needs to maintain a non-standard capitalization. The only
# restriction is that the word must begin with a capital letter.
#
# acronym 'RESTful'
# underscore 'RESTful' #=> 'restful'
# underscore 'RESTfulController' #=> 'restful_controller'
# titleize 'RESTfulController' #=> 'RESTful Controller'
# camelize 'restful' #=> 'RESTful'
# camelize 'restful_controller' #=> 'RESTfulController'
# underscore 'RESTful' # => 'restful'
# underscore 'RESTfulController' # => 'restful_controller'
# titleize 'RESTfulController' # => 'RESTful Controller'
# camelize 'restful' # => 'RESTful'
# camelize 'restful_controller' # => 'RESTfulController'
#
# acronym 'McDonald'
# underscore 'McDonald' #=> 'mcdonald'
# camelize 'mcdonald' #=> 'McDonald'
# underscore 'McDonald' # => 'mcdonald'
# camelize 'mcdonald' # => 'McDonald'
def acronym(word)
@acronyms[word.downcase] = word
@acronym_regex = /#{@acronyms.values.join("|")}/

View file

@ -327,7 +327,7 @@ Other features of memoization include `unmemoize`, `unmemoize_all`, and `memoize
The `each_with_object` method provides an alternative to `inject`, using a method backported from Ruby 1.9. It iterates over a collection, passing the current element and the memo into the block.
```ruby
%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } #=> {'foo' => 'FOO', 'bar' => 'BAR'}
%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } # => {'foo' => 'FOO', 'bar' => 'BAR'}
```
Lead Contributor: [Adam Keys](http://therealadam.com/)

View file

@ -348,7 +348,7 @@ For most stores, this ID is used to look up the session data on the server, e.g.
The CookieStore can store around 4kB of data - much less than the others - but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error.
If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time.
If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using `ActionDispatch::Session::CacheStore`. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time.
Read more about session storage in the [Security Guide](security.html).

View file

@ -473,7 +473,7 @@ In the case of a belongs_to relationship, an association key can be used to spec
```ruby
Post.where(author: author)
Author.joins(:posts).where(posts: {author: author})
Author.joins(:posts).where(posts: { author: author })
```
NOTE: The values cannot be symbols. For example, you cannot do `Client.where(status: :active)`.
@ -1016,7 +1016,7 @@ Or, in English: "return all posts that have a comment made by a guest."
#### Joining Nested Associations (Multiple Level)
```ruby
Category.joins(posts: [{comments: :guest}, :tags])
Category.joins(posts: [{ comments: :guest }, :tags])
```
This produces:
@ -1042,7 +1042,7 @@ An alternative and cleaner syntax is to nest the hash conditions:
```ruby
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where(orders: {created_at: time_range})
Client.joins(:orders).where(orders: { created_at: time_range })
```
This will find all clients who have orders that were created yesterday, again using a `BETWEEN` SQL expression.
@ -1103,7 +1103,7 @@ This loads all the posts and the associated category and comments for each post.
#### Nested Associations Hash
```ruby
Category.includes(posts: [{comments: :guest}, :tags]).find(1)
Category.includes(posts: [{ comments: :guest }, :tags]).find(1)
```
This will find the category with id 1 and eager load all of the associated posts, the associated posts' tags and comments, and every comment's guest association.
@ -1604,7 +1604,7 @@ Client.where(first_name: 'Ryan').count
You can also use various finder methods on a relation for performing complex calculations:
```ruby
Client.includes("orders").where(first_name: 'Ryan', orders: {status: 'received'}).count
Client.includes("orders").where(first_name: 'Ryan', orders: { status: 'received' }).count
```
Which will execute:

View file

@ -175,28 +175,28 @@ class Person < ActiveRecord::Base
end
>> p = Person.new
#=> #<Person id: nil, name: nil>
# => #<Person id: nil, name: nil>
>> p.errors.messages
#=> {}
# => {}
>> p.valid?
#=> false
# => false
>> p.errors.messages
#=> {name:["can't be blank"]}
# => {name:["can't be blank"]}
>> p = Person.create
#=> #<Person id: nil, name: nil>
# => #<Person id: nil, name: nil>
>> p.errors.messages
#=> {name:["can't be blank"]}
# => {name:["can't be blank"]}
>> p.save
#=> false
# => false
>> p.save!
#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
>> Person.create!
#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
```
`invalid?` is simply the inverse of `valid?`. It triggers your validations,

View file

@ -179,14 +179,14 @@ duplicate = array.dup
duplicate.push 'another-string'
# the object was duplicated, so the element was added only to the duplicate
array #=> ['string']
duplicate #=> ['string', 'another-string']
array # => ['string']
duplicate # => ['string', 'another-string']
duplicate.first.gsub!('string', 'foo')
# first element was not duplicated, it will be changed in both arrays
array #=> ['foo']
duplicate #=> ['foo', 'another-string']
array # => ['foo']
duplicate # => ['foo', 'another-string']
```
As you can see, after duplicating the `Array` instance, we got another object, therefore we can modify it and the original object will stay unchanged. This is not true for array's elements, however. Since `dup` does not make deep copy, the string inside the array is still the same object.
@ -199,8 +199,8 @@ duplicate = array.deep_dup
duplicate.first.gsub!('string', 'foo')
array #=> ['string']
duplicate #=> ['foo']
array # => ['string']
duplicate # => ['foo']
```
If the object is not duplicable, `deep_dup` will just return it:
@ -1554,7 +1554,7 @@ ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym 'SSL'
end
"SSLError".underscore.camelize #=> "SSLError"
"SSLError".underscore.camelize # => "SSLError"
```
`camelize` is aliased to `camelcase`.

View file

@ -1035,7 +1035,7 @@ If you found this guide useful, please consider recommending its authors on [wor
Footnotes
---------
[^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization:) _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
[^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization): _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
[^2]: Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files.

View file

@ -126,7 +126,9 @@ A standard Rails application depends on several gems, specifically:
### `rails/commands.rb`
Once `config/boot.rb` has finished, the next file that is required is `rails/commands` which will execute a command based on the arguments passed in. In this case, the `ARGV` array simply contains `server` which is extracted into the `command` variable using these lines:
Once `config/boot.rb` has finished, the next file that is required is
`rails/commands`, which helps in expanding aliases. In the current case, the
`ARGV` array simply contains `server` which will be passed over:
```ruby
ARGV << '--help' if ARGV.empty?
@ -142,31 +144,64 @@ aliases = {
command = ARGV.shift
command = aliases[command] || command
require 'rails/commands/commands_tasks'
Rails::CommandsTasks.new(ARGV).run_command!(command)
```
TIP: As you can see, an empty ARGV list will make Rails show the help
snippet.
If we used `s` rather than `server`, Rails will use the `aliases` defined in the file and match them to their respective commands. With the `server` command, Rails will run this code:
If we had used `s` rather than `server`, Rails would have used the `aliases`
defined here to find the matching command.
### `rails/commands/command_tasks.rb`
When one types an incorrect rails command, the `run_command` is responsible for
throwing an error message. If the command is valid, a method of the same name
is called.
```ruby
when 'server'
# Change to the application's path if there is no config.ru file in current directory.
# This allows us to run `rails server` from other directories, but still get
# the main config.ru and properly set the tmp directory.
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
def run_command!(command)
if COMMAND_WHITELIST.include?(command)
send(command)
else
write_error_message(command)
end
end
```
With the `server` command, Rails will further run the following code:
```ruby
def set_application_directory!
Dir.chdir(File.expand_path('../../', APP_PATH)) unless
File.exist?(File.expand_path("config.ru"))
end
def server
set_application_directory!
require_command!("server")
require 'rails/commands/server'
Rails::Server.new.tap do |server|
# We need to require application after the server sets environment,
# otherwise the --environment option given to the server won't propagate.
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
end
def require_command!(command)
require "rails/commands/#{command}"
end
```
This file will change into the Rails root directory (a path two directories up from `APP_PATH` which points at `config/application.rb`), but only if the `config.ru` file isn't found. This then requires `rails/commands/server` which sets up the `Rails::Server` class.
This file will change into the Rails root directory (a path two directories up
from `APP_PATH` which points at `config/application.rb`), but only if the
`config.ru` file isn't found. This then requires `rails/commands/server` which
sets up the `Rails::Server` class.
```ruby
require 'fileutils'
@ -294,37 +329,43 @@ and it's free for you to change based on your needs.
### `Rails::Server#start`
After `config/application` is loaded, `server.start` is called. This method is defined like this:
After `config/application` is loaded, `server.start` is called. This method is
defined like this:
```ruby
def start
url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}"
puts "=> Run `rails server -h` for more startup options"
print_boot_information
trap(:INT) { exit }
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
create_tmp_directories
log_to_stdout if options[:log_stdout]
#Create required tmp directories if not found
%w(cache pids sessions sockets).each do |dir_to_make|
FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
super
...
end
private
def print_boot_information
...
puts "=> Run `rails server -h` for more startup options"
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
end
unless options[:daemonize]
def create_tmp_directories
%w(cache pids sessions sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
end
end
def log_to_stdout
wrapped_app # touch the app so the logger is set up
console = ActiveSupport::Logger.new($stdout)
console.formatter = Rails.logger.formatter
console.level = Rails.logger.level
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
end
super
ensure
# The '-h' option calls exit before @options is set.
# If we call 'options' with it unset, we get double help banners.
puts 'Exiting' unless @options && options[:daemonize]
end
```
This is where the first output of the Rails initialization happens. This

View file

@ -182,18 +182,17 @@ You can swap an existing middleware in the middleware stack using `config.middle
config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions
```
#### Middleware Stack is an Enumerable
#### Deleting a Middleware
The middleware stack behaves just like a normal `Enumerable`. You can use any `Enumerable` methods to manipulate or interrogate the stack. The middleware stack also implements some `Array` methods including `[]`, `unshift` and `delete`. Methods described in the section above are just convenience methods.
Append following lines to your application configuration:
Add the following lines to your application configuration:
```ruby
# config/application.rb
config.middleware.delete "Rack::Lock"
```
And now if you inspect the middleware stack, you'll find that `Rack::Lock` will not be part of it.
And now if you inspect the middleware stack, you'll find that `Rack::Lock` is
not a part of it.
```bash
$ rake middleware
@ -319,26 +318,6 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol
TIP: It's possible to use any of the above middlewares in your custom Rack stack.
### Using Rack Builder
The following shows how to replace use `Rack::Builder` instead of the Rails supplied `MiddlewareStack`.
<strong>Clear the existing Rails middleware stack</strong>
```ruby
# config/application.rb
config.middleware.clear
```
<br>
<strong>Add a `config.ru` file to `Rails.root`</strong>
```ruby
# config.ru
use MyOwnStackFromScratch
run Rails.application
```
Resources
---------

View file

@ -51,7 +51,7 @@ Use the same typography as in regular text:
API Documentation Guidelines
----------------------------
The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html:)
The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html):
* [Wording](api_documentation_guidelines.html#wording)
* [Example Code](api_documentation_guidelines.html#example-code)

View file

@ -260,7 +260,7 @@ module Rails
#
# class FooController < ApplicationController
# def index
# my_engine.root_url #=> /my_engine/
# my_engine.root_url # => /my_engine/
# end
# end
#
@ -269,7 +269,7 @@ module Rails
# module MyEngine
# class BarController
# def index
# main_app.foo_path #=> /foo
# main_app.foo_path # => /foo
# end
# end
# end