文章目录
1.Active Support是什么?
Active Support 是 Ruby on Rails 的一个组件,扩展了 Ruby 语言,提供了一些实用功能。
2 所有对象皆可使用的扩展
2.1 blank? 和 present?
Rails 应用中,下面这些值表示空值:
- nil 和 false;
- 只有空白的字符串(注意下面的说明);
- 空数组和空散列;
- 其他能响应 empty? 方法,而且返回值为 true 的对象;
present? 方法等价于 !blank?,返回一个true或者false
[1] pry(main)> " ".blank?
=> true
[2] pry(main)> "".blank?
=> true
[4] pry(main)> [].blank?
=> true
[5] pry(main)> nil.blank?
=> true
[8] pry(main)> "".present?
=> false
[9] pry(main)> "a".present?
=> true
2.2 presence
presence 方法的返回值为调用对象,否则返回 nil
[21] pry(main)> a
=> ["hello", "world"]
[22] pry(main)> a.presence
=> ["hello", "world"]
[24] pry(main)> "".presence
=> nil
2.3 duplicable?
duplicable? 方法用于查询对象是否可以复制
"foo".duplicable? # => true
"".duplicable? # => true
0.0.duplicable? # => false
false.duplicable? # => false
- 按照定义,除了 nil、false、true、符号、数字、类、模块和方法对象之外,其他对象都可以复制。
- 任何类都可以禁止对象复制,只需删除 dup 和 clone 两个方法,或者在这两个方法中抛出异常。因此只能在 rescue 语句中判断对象是否可复制。
2.3 dup 和 deep_dup
- dup :dup 数组中的字符串是同一个对象
- deep_dup 数组中的字符串不是同一个对象
[12] pry(main)> a=["hello","world"]
=> ["hello", "world"]
[13] pry(main)> b=a.dup
=> ["hello", "world"]
[14] pry(main)> b.first.sub!("hello","xxx")
=> "xxx"
[15] pry(main)> b
=> ["xxx", "world"]
[16] pry(main)> a
=> ["xxx", "world"]
[17] pry(main)> a=["hello","world"]
=> ["hello", "world"]
[18] pry(main)> b=a.deep_dup
=> ["hello", "world"]
[19] pry(main)> b.first.sub!("hello","xxx")
=> "xxx"
[20] pry(main)> b
=> ["xxx", "world"]
[21] pry(main)> a
=> ["hello", "world"]
2.5 try
try可以实现当对象不为 nil 时在其上调用方法
@number.try(:next)
等同于:
unless @number.nil?
@number.next
end
[26] pry(main)> nil.try(:length)
=> nil
[27] pry(main)> "a".try(:length)
=> 1
2.6 to_param
Rails 中的所有对象都能响应 to_param 方法。to_param 方法的返回值表示查询字符串的值,或者 URL 片段。
"Tom & Jerry".to_param # => "Tom & Jerry"
[0, true, String].to_param # => "0/true/String"
2.9 to_query
- to_query 方法把 to_param 方法的返回值赋值给 key,组成查询字符串。
class User
def to_param
"#{id}-#{name.parameterize}"
end
end
current_user.to_query('user') # => user=357-john-smith
- 散列也响应 to_query 方法,但处理方式不一样。如果不传入参数,先在各个元素上调用 to_query(key),得到一系列键值对赋值字符串,然后按照键的顺序排列,再使用 “&” 合并:
{c: 3, b: 2, a: 1}.to_query # => "a=1&b=2&c=3"
2.10 with_options
with_options 方法把一系列方法调用中的通用选项提取出来。
class Account < ApplicationRecord
has_many :customers, dependent: :destroy
has_many :products, dependent: :destroy
has_many :invoices, dependent: :destroy
has_many :expenses, dependent: :destroy
end
# 使用 with_options优化重复的部分
class Account < ApplicationRecord
with_options dependent: :destroy do |assoc|
assoc.has_many :customers
assoc.has_many :products
assoc.has_many :invoices
assoc.has_many :expenses
end
end
2.12.1 instance_values
instance_values 方法返回一个散列,把实例变量的名称(不含前面的 @ 符号)映射到其值上,键是字符串:
class C
def initialize(x, y)
@x, @y = x, y
end
end
C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
2.12.2 instance_variable_names
instance_variable_names 方法返回一个变量名数组,实例变量的名称前面包含 @ 符号。
class C
def initialize(x, y)
@x, @y = x, y
end
end
C.new(0, 1).instance_variable_names # => ["@x", "@y"]
2.14 in?
in? 方法测试某个对象是否在另一个对象中。如果传入的对象不能响应 include? 方法,抛出 ArgumentError 异常。
[30] pry(main)> 1.in? ["hello",1]
=> true
[31] pry(main)> ["hello",1].include? 1
=> true
3 Module 的扩展
3.5 方法委托
delegate 方法提供一种便利的方法转发方式。
假设在一个应用中,用户的登录信息存储在 User 模型中,而名字和其他数据存储在 Profile 模型中,此时,要通过个人资料获取用户的名字,即 user.profile.name。可以通过两种方式实现
class User < ApplicationRecord
has_one :profile
def name
profile.name
end
end
或
class User < ApplicationRecord
has_one :profile
delegate :name, to: :profile
end
显然,使用delegate的方式更加简洁
delegate 方法可接受多个参数,委托多个方法:
delegate :name, :age, :address, :twitter, to: :profile
4 String 的扩展
- remove 方法删除匹配模式的所有内容
- squish 方法把首尾的空白去掉,还会把多个空白压缩成一个
- truncate 方法在指定长度处截断接收者,返回一个副本:
- truncate_words 方法在指定个单词处截断接收者,返回一个副本:
- starts_with? 和 ends_with?开始和结尾进行判断
- indent 按指定量缩进接收者:
- at(position) 返回字符串中 position 位置上的字符:
- from(position) 返回子串,从 position 位置开始:
- to(position) 返回子串,到 position 位置为止:
- pluralize 方法返回接收者的复数形式:
- singularize 方法返回接收者的单数形式:
- camelize 方法把接收者变成驼峰式:
- underscore 方法的作用相反,把驼峰式变成蛇底式:(下划线将单词连接
起来,例如:file_name、 line_number。) - titleize 方法把接收者中的单词首字母变成大写:
"fermat's enigma".titleize # => "Fermat's Enigma"
- dasherize 方法把接收者中的下划线替换成连字符:
"contact_data".dasherize # => "contact-data"
- demodulize 方法返回限定常量名的常量名本身,即最右边那一部分:
- deconstantize 方法去掉限定常量引用表达式的最右侧部分,留下常量的容器:
- parameterize 方法对接收者做整形,以便在精美的 URL 中使用。
"Kurt Gödel".parameterize # => "kurt-godel"
- tableize 方法相当于先调用 underscore,再调用 pluralize。
- classify 方法的作用与 tableize 相反,返回表名对应的类名:
"invoice_lines".classify # => "InvoiceLine"
- foreign_key 方法根据类名计算外键列的名称。为此,它先调用 demodulize,再调用 underscore,最后加上“_id”:
- 5.12.1 to_date、to_time、to_datetime(to_time 有个可选的参数,值为 :utc 或 :local,指明想使用的时区)
"2010-07-27 23:42:00".to_time(:utc) # => 2010-07-27 23:42:00 UTC
"2010-07-27 23:42:00".to_time(:local) # => 2010-07-27 23:42:00 +0200
5 Integer 的扩展
- multiple_of? 方法测试一个整数是不是参数的倍数:
- ordinal 方法返回整数接收者的序数词后缀(字符串):
- ordinalize 方法返回整数接收者的序数词(字符串)。注意,ordinal 方法只返回后缀。
6 Enumerable 的扩展
- sum 方法计算可枚举对象的元素之和:
- many? 方法是 collection.size > 1 的简化:
- exclude? 方法测试指定对象是否不在集合中。这是内置方法 include? 的逆向判断。
- without 从可枚举对象中删除指定的元素,然后返回副本:
- pluck 方法基于指定的键返回一个数组:
7 Array 的扩展
- to 获取到指定索引的子数组
- from 从指定索引一直获取到末尾。如果索引大于数组的长度,返回一个空数组。
- second、third、fourth 和 fifth 分别返回对应的元素
- prepend 从首部开始添加元素
- in_groups_of 方法把数组拆分成特定长度的连续分组,返回由各分组构成的数组:
- in_groups(number, fill_with = nil) 方法把数组分成特定个分组。这个方法返回由分组构成的数组:
- split 方法在指定的分隔符处拆分数组,返回得到的片段。
8 Hash 的扩展
- to_xml 方法返回接收者的 XML 表述(字符串):
- merge 用于合并两个散列
- reverse_merge 和 reverse_merge! 如果键有冲突,merge 方法的参数中的键胜出
[50] pry(main)> {a: 1, b: 1}.merge(a: 0, c: 2)
=> {:a=>0, :b=>1, :c=>2}
[51] pry(main)> {a: 1, b: 1}.reverse_merge(a: 0, c: 2)
=> {:a=>1, :c=>2, :b=>1}
- deep_merge 在深度合并中,如果两个散列中有相同的键,而且它们的值都是散列,那么在得到的散列中,那个键的值是合并后的结果:
[53] pry(main)> {a: {b: 1}}.merge(a: {c: 2})
=> {:a=>{:c=>2}}
[54] pry(main)> {a: {b: 1}}.deep_merge!(a: {c: 2})
=> {:a=>{:b=>1, :c=>2}}
- except 方法返回一个散列,从接收者中把参数中列出的键删除(如果有的话):
- transform_keys 方法接受一个块,使用块中的代码处理接收者的键:
[57] pry(main)> {nil => {}, 1 => 6, a: 'hello'}.transform_keys { |key| key.to_s.upcase }
=> {""=>{}, "1"=>6, "A"=>"hello"}
- stringify_keys 把接收者中的键都变成字符串,然后返回一个散列。为此,它在键上调用 to_s。遇到冲突的键时,只会从中选择一个。选择哪个值并不确定。
- symbolize_keys 方法把接收者中的键尽量变成符号。为此,它在键上调用 to_sym。
- to_options 和 to_options! 分别是 symbolize_keys and symbolize_keys! 的别名。
- transform_values 的参数是一个块,使用块中的代码处理接收者中的各个值。
- compact 和 compact! 方法返回没有 nil 值的散列:
- extract! 方法删除并返回匹配指定键的键值对。
- slice 从字符串和数组中提取切片
{a: 1, b: 2, c: 3}.slice(:a, :c)
# => {:a=>1, :c=>3}
也有 slice!,它就地执行切片,返回被删除的键值对:
14 Date 的扩展
- prev_year 和 next_year 方法返回前一年和下一年中的相同月和日:
- prev_month 和 next_month 方法分别返回前一个月和后一个月中的相同日:
- beginning_of_week 和 end_of_week 方法分别返回某一周的第一天和最后一天的日期。