rails 指南总结(十三)——深入探索之Active Support 核心扩展

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 方法分别返回某一周的第一天和最后一天的日期。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值