edge
เพิ่มเติมที่ rubyonrails.org: เพิ่มเติมเกี่ยวกับ Ruby on Rails

ส่วนขยายของ Active Support Core

Active Support เป็นส่วนประกอบของ Ruby on Rails ที่รับผิดชอบในการ提供ส่วนขยายและเครื่องมือของภาษา Ruby

มันให้ความสามารถที่เพิ่มขึ้นในระดับภาษาที่เป้าหมายทั้งในการพัฒนาแอปพลิเคชัน Rails และในการพัฒนา Ruby on Rails เอง

หลังจากอ่านเอกสารนี้คุณจะรู้:

Chapters

  1. วิธีโหลดส่วนขยายหลัก
  2. ส่วนขยายสำหรับวัตถุทั้งหมด
  3. ส่วนขยายของ Module
  4. ส่วนขยายให้กับ Class
  5. ขยาย String
  6. ส่วนขยายให้กับ Symbol
  7. ส่วนขยายให้กับ Numeric
  8. ส่วนขยายให้กับ Integer
  9. ส่วนขยายให้กับ BigDecimal
  10. ส่วนขยายให้กับ Enumerable
  11. ส่วนขยายของ Array
  12. ส่วนขยายให้กับ Hash
  13. ส่วนขยายให้กับ Regexp
  14. ส่วนขยายให้กับ Range
  15. ส่วนขยายให้กับ Date
  16. ส่วนขยายให้กับ DateTime
  17. ส่วนขยายใน Time
  18. ส่วนขยายให้กับ File
  19. ไฟล์ช่วยเพิ่มให้กับ NameError
  20. ส่วนขยายให้กับ LoadError
  21. ส่วนขยายให้กับ Pathname

1 วิธีโหลดส่วนขยายหลัก

1.1 Active Support เดี่ยว

เพื่อให้มีขนาดเล็กที่สุดเป็นไปได้ Active Support โหลดความขึ้นต่ำที่สุดโดยค่าเริ่มต้น มันถูกแบ่งออกเป็นชิ้นเล็กๆ เพื่อให้สามารถโหลดส่วนขยายที่ต้องการได้เท่านั้น มันยังมีจุดเริ่มต้นที่สะดวกในการโหลดส่วนขยายที่เกี่ยวข้องในครั้งเดียว แม้ว่าจะเป็นทุกอย่าง

ดังนั้นหลังจาก require ง่ายๆ เช่น:

require "active_support"

เฉพาะส่วนขยายที่ Active Support framework ต้องการจะถูกโหลดเท่านั้น

1.1.1 เลือกเฉพาะการกำหนดค่า

ตัวอย่างนี้แสดงวิธีการโหลด Hash#with_indifferent_access ส่วนขยายนี้ช่วยให้สามารถแปลง Hash เป็น ActiveSupport::HashWithIndifferentAccess ซึ่งอนุญาตให้เข้าถึงคีย์เป็นสตริงหรือสัญลักษณ์ได้

{ a: 1 }.with_indifferent_access["a"] # => 1

สำหรับทุกเมธอดที่กำหนดเป็นส่วนขยายหลัก คู่มือนี้มีหมายเหตุที่ระบุว่าเมธอดดังกล่าวถูกกำหนดที่ไหน ในกรณีของ with_indifferent_access หมายเหตุกล่าวว่า:

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/hash/indifferent_access.rb

ซึ่งหมายความว่าคุณสามารถ require ได้ดังนี้:

require "active_support"
require "active_support/core_ext/hash/indifferent_access"

Active Support ได้รับการตรวจสอบอย่างรอบคอบเพื่อให้การโหลดไฟล์เลือกเฉพาะเฉพาะที่จำเป็นอย่างเคร่งครัด

1.1.2 โหลดส่วนขยายหลักที่จัดกลุ่ม

ระดับถัดไปคือการโหลดส่วนขยายทั้งหมดไปยัง Hash เพียงแค่โหลด active_support/core_ext/hash คือเพียงพอ:

require "active_support"
require "active_support/core_ext/hash"

1.1.3 โหลดส่วนขยายหลักทั้งหมด

คุณอาจต้องการเพียงแค่โหลดส่วนขยายหลักทั้งหมด มีไฟล์สำหรับนั้น:

require "active_support"
require "active_support/core_ext"

1.1.4 โหลด Active Support ทั้งหมด

และสุดท้าย หากคุณต้องการให้ Active Support ทั้งหมดพร้อมใช้งานเพียงแค่เรียกใช้:

require "active_support/all"

ซึ่งไม่ได้เก็บ Active Support ทั้งหมดในหน่วยความจำล่วงหน้าจริงๆ บางส่วนถูกกำหนดค่าผ่าน autoload เพื่อให้โหลดเฉพาะเมื่อใช้งาน

1.2 Active Support ภายในแอปพลิเคชัน Ruby on Rails

แอปพลิเคชัน Ruby on Rails จะโหลด Active Support ทั้งหมด ยกเว้น config.active_support.bare เป็นจริง ในกรณีนั้นแอปพลิเคชันจะโหลดเพียงสิ่งที่เฟรมเวิร์กเองเลือกเฉพาะสำหรับความต้องการของตัวเอง และยังสามารถเลือกเฉพาะตัวเองได้ในระดับที่เหมาะสม ตามที่อธิบายในส่วนก่อนหน้านี้

2 ส่วนขยายสำหรับวัตถุทั้งหมด

2.1 blank? และ present?

ค่าต่อไปนี้ถือว่าเป็นค่าว่างในแอปพลิเคชัน Rails:

  • nil และ false,

  • สตริงที่ประกอบด้วยช่องว่างเท่านั้น (ดูหมายเหตุด้านล่าง),

  • อาร์เรย์และแฮชที่ว่างเปล่า, และ

  • วัตถุอื่น ๆ ที่ตอบสนองกับ empty? และเป็นว่าง

ข้อมูล: ตัวบ่งชี้สำหรับสตริงใช้คลาสอักขระที่ตระหนักถึง Unicode [:space:] ดังนั้นตัวอย่างเช่น U+2029 (ตัวแบ่งย่อหน้า) ถือว่าเป็นช่องว่าง คำเตือน: โปรดทราบว่าไม่ได้กล่าวถึงตัวเลข โดยเฉพาะ 0 และ 0.0 ไม่ใช่ค่าว่าง

ตัวอย่างเช่น เมธอดนี้จาก ActionController::HttpAuthentication::Token::ControllerMethods ใช้ blank? เพื่อตรวจสอบว่ามีโทเค็นอยู่หรือไม่:

def authenticate(controller, &login_procedure)
  token, options = token_and_options(controller.request)
  unless token.blank?
    login_procedure.call(token, options)
  end
end

เมธอด present? เทียบเท่ากับ !blank? ตัวอย่างนี้มาจาก ActionDispatch::Http::Cache::Response:

def set_conditional_cache_control!
  return if self["Cache-Control"].present?
  # ...
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/blank.rb

2.2 presence

เมธอด presence จะคืนค่าตัวเองหาก present? และ nil ในกรณีอื่น ๆ มีประโยชน์สำหรับการใช้งานเช่นนี้:

host = config[:host].presence || 'localhost'

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/blank.rb

2.3 duplicable?

ตั้งแต่ Ruby 2.5 เป็นต้นมา ส่วนใหญ่ของออบเจ็กต์สามารถทำซ้ำได้ผ่าน dup หรือ clone:

"foo".dup           # => "foo"
"".dup              # => ""
Rational(1).dup     # => (1/1)
Complex(0).dup      # => (0+0i)
1.method(:+).dup    # => TypeError (allocator undefined for Method)

Active Support มี duplicable? เพื่อสอบถามออบเจ็กต์เกี่ยวกับนี้:

"foo".duplicable?           # => true
"".duplicable?              # => true
Rational(1).duplicable?     # => true
Complex(1).duplicable?      # => true
1.method(:+).duplicable?    # => false

คำเตือน: คลาสใด ๆ สามารถปฏิเสธการทำซ้ำได้โดยการลบ dup และ clone หรือยกเว้นข้อยกเว้นจากการใช้งาน ดังนั้นเพียงแค่ rescue เท่านั้นที่สามารถบอกได้ว่าวัตถุอะไรก็ตามสามารถทำซ้ำได้หรือไม่ duplicable? ขึ้นอยู่กับรายการที่กำหนดไว้แบบฮาร์ดโค้ดด้านบน แต่มันเร็วกว่า rescue มาก ใช้เฉพาะเมื่อคุณทราบว่ารายการที่กำหนดไว้แบบฮาร์ดโค้ดเพียงพอสำหรับกรณีการใช้งานของคุณ

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/duplicable.rb

2.4 deep_dup

เมธอด deep_dup จะคืนค่าสำเนาลึกของวัตถุที่กำหนด โดยปกติเมื่อคุณทำซ้ำวัตถุที่มีวัตถุอื่น ๆ ภายใน Ruby จะไม่ทำซ้ำวัตถุเหล่านั้น ดังนั้นจะสร้างสำเนาตื้นของวัตถุ ถ้าคุณมีอาร์เรย์ที่มีสตริงเช่น เช่นนี้:

array     = ['string']
duplicate = array.dup

duplicate.push 'another-string'

# วัตถุถูกทำซ้ำดังนั้นองค์ประกอบถูกเพิ่มไปในสำเนาเท่านั้น
array     # => ['string']
duplicate # => ['string', 'another-string']

duplicate.first.gsub!('string', 'foo')

# องค์ประกอบแรกไม่ได้ทำซ้ำ จะเปลี่ยนแปลงในทั้งสองอาร์เรย์
array     # => ['foo']
duplicate # => ['foo', 'another-string']

จากตัวอย่างนี้ หลังจากทำซ้ำอินสแตนซ์ของ Array เราได้วัตถุอื่น ๆ ซึ่งเราสามารถแก้ไขได้และวัตถุต้นฉบับจะไม่เปลี่ยนแปลง แต่สำหรับองค์ประกอบของอาร์เรย์ ไม่เช่นนั้น โดยเนื่องจาก dup ไม่ทำสำเนาลึก สตริงภายในอาร์เรย์ยังคงเป็นวัตถุเดียวกัน

หากคุณต้องการสำเนาลึกของวัตถุ คุณควรใช้ deep_dup ตัวอย่างเช่นนี้:

array     = ['string']
duplicate = array.deep_dup

duplicate.first.gsub!('string', 'foo')

array     # => ['string']
duplicate # => ['foo']

หากวัตถุไม่สามารถทำซ้ำได้ deep_dup จะคืนค่าวัตถุเดิม:

number = 1
duplicate = number.deep_dup
number.object_id == duplicate.object_id   # => true

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/deep_dup.rb

2.5 try

เมื่อคุณต้องการเรียกเมธอดบนวัตถุเฉพาะเมื่อไม่เป็น nil วิธีที่ง่ายที่สุดในการทำได้คือใช้เงื่อนไขเพิ่มเติมซึ่งทำให้เกิดความสับสนโดยไม่จำเป็น ทางเลือกคือการใช้ try try เหมือนกับ Object#public_send ยกเว้นว่าจะคืนค่า nil หากส่งไปยัง nil นี่คือตัวอย่าง:

# โดยไม่ใช้ try
unless @number.nil?
  @number.next
end

# ใช้ try
@number.try(:next)

ตัวอย่างอื่นคือโค้ดนี้จาก ActiveRecord::ConnectionAdapters::AbstractAdapter ที่ @logger อาจเป็น nil คุณสามารถเห็นว่าโค้ดใช้ try และหลีกเลี่ยงการตรวจสอบที่ไม่จำเป็น

def log_info(sql, name, ms)
  if @logger.try(:debug?)
    name = '%s (%.1fms)' % [name || 'SQL', ms]
    @logger.debug(format_log_entry(name, sql.squeeze(' ')))
  end
end

try ยังสามารถเรียกโดยไม่มีอาร์กิวเมนต์แต่มีบล็อก ซึ่งจะถูกดำเนินการเฉพาะเมื่อออบเจ็กต์ไม่ใช่ nil:

@person.try { |p| "#{p.first_name} #{p.last_name}" }

โปรดทราบว่า try จะย่อการเกิดข้อผิดพลาดที่ไม่มีเมธอด และส่งคืน nil แทน หากคุณต้องการป้องกันการพิมพ์ผิดใช้ try! แทน:

@number.try(:nest)  # => nil
@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Integer

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/try.rb.

2.6 class_eval(*args, &block)

คุณสามารถประเมินโค้ดในบริบทของคลาสเดี่ยวของวัตถุใด ๆ โดยใช้ class_eval:

class Proc
  def bind(object)
    block, time = self, Time.current
    object.class_eval do
      method_name = "__bind_#{time.to_i}_#{time.usec}"
      define_method(method_name, &block)
      method = instance_method(method_name)
      remove_method(method_name)
      method
    end.bind(object)
  end
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/kernel/singleton_class.rb.

2.7 acts_like?(duck)

เมธอด acts_like? ให้วิธีการตรวจสอบว่าคลาสใดคลาสหนึ่งทำหน้าที่เหมือนคลาสอื่นๆ โดยอิงตามสัญญาที่เรียบง่าย: คลาสที่ให้ส่วนติดต่อเดียวกับ String กำหนด

def acts_like_string?
end

ซึ่งเป็นเพียงตัวบ่งชี้เท่านั้น ส่วนเนื้อหาหรือค่าที่ส่งกลับไม่สำคัญ จากนั้น โค้ดไคลเอ็นต์สามารถสอบถามความปลอดภัยของ duck-type ได้ดังนี้:

some_klass.acts_like?(:string)

Rails มีคลาสที่ทำหน้าที่เหมือน Date หรือ Time และปฏิบัติตามสัญญานี้

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/acts_like.rb.

2.8 to_param

วัตถุทั้งหมดใน Rails ตอบสนองต่อเมธอด to_param ซึ่งจะส่งคืนสิ่งที่แทนวัตถุนั้นในรูปของค่าในสตริงคิวรี หรือเป็นส่วนของ URL

โดยค่าเริ่มต้น to_param เพียงเรียก to_s เท่านั้น:

7.to_param # => "7"

ค่าที่ส่งคืนจาก to_param ไม่ควรถูกหนีไป:

"Tom & Jerry".to_param # => "Tom & Jerry"

คลาสหลายคลาสใน Rails เขียนทับเมธอดนี้

ตัวอย่างเช่น nil, true, และ false จะส่งคืนตัวเอง Array#to_param เรียก to_param บนสมาชิกและรวมผลลัพธ์ด้วย "/":

[0, true, String].to_param # => "0/true/String"

ความสำคัญคือระบบเส้นทางของ Rails เรียก to_param บนโมเดลเพื่อรับค่าสำหรับตัวแทน :id [ActiveRecord::Base#to_param][ActiveRecord::Base#to_param] ส่งคืน id ของโมเดล แต่คุณสามารถกำหนดเมธอดนี้ในโมเดลของคุณได้ ตัวอย่างเช่น กำหนดให้

class User
  def to_param
    "#{id}-#{name.parameterize}"
  end
end

เราจะได้:

user_path(@user) # => "/users/357-john-smith"

คำเตือน ตัวควบคุมจำเป็นต้องรับทราบการกำหนดเมธอด to_param เพราะเมื่อคำขอเช่นนั้นเข้ามา "357-john-smith" เป็นค่าของ params[:id]

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/object/to_param.rb.

2.9 to_query

เมธอด to_query สร้างสตริงคิวรีที่เชื่อมโยงคีย์ที่กำหนดกับค่าที่ส่งคืนจาก to_param ตัวอย่างเช่น ด้วยการกำหนด to_param ต่อไปนี้:

class User
  def to_param
    "#{id}-#{name.parameterize}"
  end
end

เราจะได้:

current_user.to_query('user') # => "user=357-john-smith"

เมธอดนี้หนีไปทุกอย่างที่จำเป็นทั้งสำหรับคีย์และค่า:

account.to_query('company[name]')
# => "company%5Bname%5D=Johnson+%26+Johnson"

ดังนั้นผลลัพธ์ของมันพร้อมใช้งานในสตริงคิวรี

อาร์เรย์จะส่งผลลัพธ์จากการใช้ to_query กับแต่ละองค์ประกอบโดยใช้ key[] เป็นคีย์ และรวมผลลัพธ์ด้วย "&":

[3.4, -45.6].to_query('sample')
# => "sample%5B%5D=3.4&sample%5B%5D=-45.6"

และแฮชตอนเรียกใช้ to_query ด้วยลายเซ็นต์ที่แตกต่างกัน หากไม่มีอาร์กิวเมนต์ที่ถูกส่งผ่าน การเรียกใช้จะสร้างชุดคีย์/ค่าที่เรียงลำดับและเรียกใช้ to_query(key) กับค่าของมัน จากนั้นรวมผลลัพธ์ด้วย "&":

{ c: 3, b: 2, a: 1 }.to_query # => "a=1&b=2&c=3"

เมธอด Hash#to_query ยอมรับเนมสเปซเวชั่นที่เป็นทางเลือกสำหรับคีย์:

{ id: 89, name: "John Smith" }.to_query('user')
# => "user%5Bid%5D=89&user%5Bname%5D=John+Smith"

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/to_query.rb.

2.10 with_options

เมธอด 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

โดยใช้วิธีนี้:

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

วิธีการนี้อาจสื่อถึงการจัดกลุ่มให้กับผู้อ่านด้วย ตัวอย่างเช่น สมมุติว่าคุณต้องการส่งจดหมายข่าวที่ภาษาขึ้นอยู่กับผู้ใช้ คุณสามารถจัดกลุ่มส่วนที่ขึ้นอยู่กับภาษาได้ดังนี้:

I18n.with_options locale: user.locale, scope: "newsletter" do |i18n|
  subject i18n.t :subject
  body    i18n.t :body, user_name: user.name
end

เคล็ดลับ: เนื่องจาก with_options ส่งการเรียกไปยังผู้รับของมัน คุณสามารถซ้อนกันได้ แต่ละระดับการซ้อนจะผสานค่าเริ่มต้นที่ถูกสืบทอดเพิ่มเติมนอกจากตัวเอง

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/with_options.rb.

2.11 การสนับสนุน JSON

Active Support ให้การสนับสนุน JSON ที่ดีกว่า json gem ที่มักจะให้สำหรับวัตถุ Ruby นี้เพราะบางคลาส เช่น Hash และ Process::Status ต้องการการจัดการพิเศษเพื่อให้ได้รูปแบบ JSON ที่ถูกต้อง

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/json.rb.

2.12 ตัวแปรอินสแตนซ์

Active Support ให้เมธอดหลายตัวเพื่อสะดวกในการเข้าถึงตัวแปรอินสแตนซ์

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}

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/instance_variables.rb.

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"]

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/instance_variables.rb.

2.13 การปิดเสียงคำเตือนและข้อยกเว้น

เมธอด silence_warnings และ enable_warnings เปลี่ยนค่าของ $VERBOSE ตามที่เหมาะสมสำหรับระยะเวลาในบล็อกของพวกเขา และรีเซ็ตค่าเดิมหลังจากนั้น:

silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }

การปิดเสียงข้อยกเว้นก็เป็นไปได้ด้วย suppress เมธอดนี้รับคลาสข้อยกเว้นอย่างไม่จำกัด หากมีข้อยกเว้นถูกเรียกใช้ระหว่างการดำเนินการในบล็อกและเป็น kind_of? ของอาร์กิวเมนต์ใด ๆ suppress จะจับค่านั้นและส่งคืนโดยเงียบ มิฉะนั้นข้อยกเว้นจะไม่ถูกจับ:

# หากผู้ใช้ถูกล็อกไว้ การเพิ่มจำนวนจะหายไปโดยไม่มีผลกระทบใหญ่
suppress(ActiveRecord::StaleObjectError) do
  current_user.increment! :visits
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/kernel/reporting.rb.

2.14 in?

ตัวตรวจสอบ in? ทดสอบว่าวัตถุหนึ่งอยู่ในวัตถุอื่น หากอาร์กิวเมนต์ที่ส่งผ่านไม่ตอบสนองกับ include? จะเกิดข้อยกเว้น ArgumentError.

ตัวอย่างของ in?:

1.in?([1, 2])        # => true
"lo".in?("hello")   # => true
25.in?(30..50)      # => false
1.in?(1)            # => ArgumentError

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/inclusion.rb.

3 ส่วนขยายของ Module

3.1 แอตทริบิวต์

3.1.1 alias_attribute

แอตทริบิวต์ของโมเดลมีตัวอ่าน ตัวเขียน และตัวตรวจสอบ คุณสามารถตั้งชื่อแอตทริบิวต์ของโมเดลให้มีเมธอดสามตัวที่กำหนดไว้ทั้งหมดโดยใช้ alias_attribute คล้ายกับเมธอดการตั้งชื่ออื่น ชื่อใหม่เป็นอาร์กิวเมนต์แรกและชื่อเดิมเป็นอาร์กิวเมนต์ที่สอง (หนึ่งวิธีจำชื่อได้คือใส่ตามลำดับเหมือนกับการกำหนดค่า):

class User < ApplicationRecord
  # คุณสามารถอ้างอิงคอลัมน์อีเมลเป็น "login" ได้
  # สิ่งนี้อาจมีความหมายสำหรับรหัสการตรวจสอบ
  alias_attribute :login, :email
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/aliasing.rb.

3.1.2 แอตทริบิวต์ภายใน

เมื่อคุณกำลังกำหนดแอตทริบิวต์ในคลาสที่ตั้งใจให้เป็นคลาสย่อย การชนกันของชื่อเป็นความเสี่ยง ซึ่งเป็นสิ่งสำคัญอย่างมากสำหรับไลบรารี

Active Support กำหนดแมโคร attr_internal_reader, attr_internal_writer, และ attr_internal_accessor พวกเขามีพฤติกรรมเหมือนกับ attr_* ที่มีอยู่ใน Ruby แต่ชื่อตัวแปรอินสแตนซ์ใต้หลังคาที่ทำให้เกิดชนกันน้อยลง

แมโคร attr_internal เป็นคำเหมือนกับ attr_internal_accessor:

# ไลบรารี
class ThirdPartyLibrary::Crawler
  attr_internal :log_level
end

# โค้ดของไคลเอ็นต์
class MyCrawler < ThirdPartyLibrary::Crawler
  attr_accessor :log_level
end

ในตัวอย่างก่อนหน้านี้อาจเป็นได้ว่า :log_level ไม่ได้อยู่ในอินเทอร์เฟซสาธารณะของไลบรารีและใช้เพียงสำหรับการพัฒนาเท่านั้น โค้ดของไคลเอ็นต์ไม่รู้จักชนกันและกำหนด :log_level ของตัวเอง ด้วย attr_internal ไม่มีการชนกัน

ตามค่าเริ่มต้น ตัวแปรอินสแตนซ์ภายในจะถูกตั้งชื่อด้วยเครื่องหมายขีดล่างนำหน้า @_log_level ในตัวอย่างข้างต้น สามารถกำหนดได้ผ่าน Module.attr_internal_naming_format คุณสามารถส่งสตริงรูปแบบ sprintf ที่มีเครื่องหมาย @ นำหน้าและ %s ที่ใดก็ได้ที่จะใส่ชื่อ ค่าเริ่มต้นคือ "@_%s"

Rails ใช้แอตทริบิวต์ภายในในสถานที่บางแห่ง เช่นสำหรับวิว:

module ActionView
  class Base
    attr_internal :captures
    attr_internal :request, :layout
    attr_internal :controller, :template
  end
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/attr_internal.rb.

3.1.3 แอตทริบิวต์ของโมดูล

แมโคร mattr_reader, mattr_writer, และ mattr_accessor เหมือนกับแมโคร cattr_* ที่กำหนดไว้สำหรับคลาส ในความเป็นจริงแล้ว แมโคร cattr_* เป็นคำย่อสำหรับแมโคร mattr_* ดูที่ แอตทริบิวต์ของคลาส

ตัวอย่างเช่น API สำหรับ logger ของ Active Storage ถูกสร้างขึ้นด้วย mattr_accessor:

module ActiveStorage
  mattr_accessor :logger
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/attribute_accessors.rb.

3.2 พ่อแม่

3.2.1 module_parent

เมธอด module_parent บนโมดูลที่มีชื่อซ้อนกันคืนค่าโมดูลที่มีค่าคงที่ที่สอดคล้องกับค่าคงที่ของมัน:

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parent # => X::Y
M.module_parent       # => X::Y

หากโมดูลเป็นโมดูลที่ไม่มีชื่อหรือเป็นส่วนหนึ่งของระดับบนสุด module_parent จะคืนค่า Object. คำเตือน: โปรดทราบว่าในกรณีนั้น module_parent_name จะส่งคืนค่า nil.

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/introspection.rb.

3.2.2 module_parent_name

เมธอด module_parent_name บนโมดูลที่มีชื่อซ้อนกันจะส่งคืนชื่อที่เต็มรูปแบบของโมดูลที่มีค่าคงที่ที่เกี่ยวข้อง:

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parent_name # => "X::Y"
M.module_parent_name       # => "X::Y"

สำหรับโมดูลระดับบนสุดหรือโมดูลที่ไม่มีชื่อ module_parent_name จะส่งคืนค่า nil.

คำเตือน: โปรดทราบว่าในกรณีนั้น module_parent จะส่งคืนค่า Object.

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/introspection.rb.

3.2.3 module_parents

เมธอด module_parents เรียกใช้ module_parent บนวัตถุต้นฉบับและวัตถุย้อนหลังจนถึง Object เส้นโซ่จะถูกส่งคืนในรูปแบบของอาร์เรย์จากล่างไปบน:

module X
  module Y
    module Z
    end
  end
end
M = X::Y::Z

X::Y::Z.module_parents # => [X::Y, X, Object]
M.module_parents       # => [X::Y, X, Object]

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/introspection.rb.

3.3 โมดูลที่ไม่มีชื่อ

โมดูลอาจมีชื่อหรือไม่มีชื่อ:

module M
end
M.name # => "M"

N = Module.new
N.name # => "N"

Module.new.name # => nil

คุณสามารถตรวจสอบว่าโมดูลมีชื่อหรือไม่ด้วยตัวตรวจสอบ anonymous?:

module M
end
M.anonymous? # => false

Module.new.anonymous? # => true

โปรดทราบว่าการไม่สามารถเข้าถึงได้ไม่ได้หมายความว่าไม่มีชื่อ:

module M
end

m = Object.send(:remove_const, :M)

m.anonymous? # => false

แม้ว่าโมดูลที่ไม่มีชื่อจะไม่สามารถเข้าถึงได้ตามนิยาม

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/module/anonymous.rb.

3.4 การส่งมอบเมธอด

3.4.1 delegate

แมโคร delegate นำเสนอวิธีง่ายในการส่งเมธอดไปยังอื่น ๆ

สมมติว่าผู้ใช้ในแอปพลิเคชันบางอย่างมีข้อมูลการเข้าสู่ระบบในโมเดล User แต่ชื่อและข้อมูลอื่น ๆ อยู่ในโมเดล Profile ที่แยกออกมา:

class User < ApplicationRecord
  has_one :profile
end

ด้วยการกำหนดค่านี้คุณสามารถรับชื่อของผู้ใช้ผ่านโปรไฟล์ของพวกเขาได้ user.profile.name แต่อาจจะเป็นประโยชน์ที่จะยังสามารถเข้าถึงแอตทริบิวต์ดังกล่าวโดยตรงได้:

class User < ApplicationRecord
  has_one :profile

  def name
    profile.name
  end
end

นั่นคือสิ่งที่ delegate ทำให้คุณ:

class User < ApplicationRecord
  has_one :profile

  delegate :name, to: :profile
end

มันสั้นกว่าและเจตนาชัดเจนกว่า

เมธอดต้องเป็นสาธารณะในเป้าหมาย

แมโคร delegate ยอมรับเมธอดหลาย ๆ ตัว:

delegate :name, :age, :address, :twitter, to: :profile

เมื่อถูกตีพิมพ์เป็นสตริง ตัวเลือก :to ควรกลายเป็นนิพจน์ที่ประเมินค่าเป็นวัตถุที่เมธอดถูกส่งมอบไป โดยทั่วไปเป็นสตริงหรือสัญลักษณ์ นิพจน์เช่นนี้จะถูกประเมินในบริบทของผู้รับ:

# ส่งมอบไปยังค่าคงที่ Rails
delegate :logger, to: :Rails

# ส่งมอบไปยังคลาสของผู้รับ
delegate :table_name, to: :class

คำเตือน: หากตัวเลือก :prefix เป็น true นี้จะไม่สามารถใช้ได้ทั่วไป ดูข้างล่าง

ตามค่าเริ่มต้น หากการส่งมอบเกิดข้อผิดพลาด NoMethodError และเป้าหมายเป็น nil ข้อยกเว้นจะถูกส่งต่อ คุณสามารถขอให้ส่งคืน nil แทนด้วยตัวเลือก :allow_nil:

delegate :name, to: :profile, allow_nil: true

ด้วย :allow_nil การเรียก user.name จะส่งคืน nil หากผู้ใช้ไม่มีโปรไฟล์

ตัวเลือก :prefix เพิ่มคำนำหน้าในชื่อของเมธอดที่สร้างขึ้น นี่อาจเป็นประโยชน์ตัวอย่างเช่นในการรับชื่อที่ดีขึ้น: ruby delegate :street, to: :address, prefix: true

ตัวอย่างก่อนหน้านี้สร้าง address_street แทนที่จะเป็น street

คำเตือน: ในกรณีนี้เนื่องจากชื่อของเมธอดที่สร้างขึ้นมาเป็นชื่อของวัตถุเป้าหมายและชื่อเมธอดเป้าหมาย ตัวเลือก :to ต้องเป็นชื่อเมธอด

สามารถกำหนดคำนำหน้าที่กำหนดเองได้เช่นกัน:

delegate :size, to: :attachment, prefix: :avatar

ในตัวอย่างก่อนหน้านี้ แมโครสร้าง avatar_size แทนที่จะเป็น size

ตัวเลือก :private จะเปลี่ยนขอบเขตของเมธอด:

delegate :date_of_birth, to: :profile, private: true

เมธอดที่ถูกมอบหมายจะเป็นสาธารณะตามค่าเริ่มต้น ส่ง private: true เพื่อเปลี่ยนแปลงค่านั้น

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/module/delegation.rb

3.4.2 delegate_missing_to

สมมติว่าคุณต้องการมอบหมายทุกอย่างที่ขาดหายไปจากวัตถุ User ไปยัง Profile โมดูล delegate_missing_to ช่วยให้คุณสามารถทำได้ง่ายๆ:

class User < ApplicationRecord
  has_one :profile

  delegate_missing_to :profile
end

เป้าหมายสามารถเป็นอะไรก็ได้ที่เรียกใช้งานได้ภายในวัตถุ เช่น ตัวแปรอินสแตนซ์ เมธอด ค่าคงที่ เป็นต้น เฉพาะเมธอดสาธารณะของเป้าหมายเท่านั้นที่ถูกมอบหมาย

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/module/delegation.rb.

3.5 การกำหนดเมธอดใหม่

มีกรณีที่คุณต้องการกำหนดเมธอดด้วย define_method แต่ไม่ทราบว่าเมธอดที่มีชื่อนั้นมีอยู่แล้วหรือไม่ หากมี จะมีการเตือนเตือนถ้าเปิดใช้งาน ไม่ใหญ่มาก แต่ไม่สะอาดเท่าไหร่

เมธอด redefine_method ป้องกันการเตือนเตือนเช่นนั้น โดยลบเมธอดที่มีอยู่ก่อนหน้านั้นออกหากจำเป็น

คุณยังสามารถใช้ silence_redefinition_of_method หากคุณต้องการกำหนดเมธอดทดแทนเอง (เนื่องจากคุณกำลังใช้ delegate เป็นต้น)

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/module/redefine_method.rb.

4 ส่วนขยายให้กับ Class

4.1 แอตทริบิวต์ของคลาส

4.1.1 class_attribute

เมธอด class_attribute ประกาศแอตทริบิวต์ของคลาสที่สามารถถูกเขียนทับได้ในระดับใดก็ได้ในลำดับชั้นล่าง

class A
  class_attribute :x
end

class B < A; end

class C < B; end

A.x = :a
B.x # => :a
C.x # => :a

B.x = :b
A.x # => :a
C.x # => :b

C.x = :c
A.x # => :a
B.x # => :b

ตัวอย่างเช่น ActionMailer::Base กำหนด:

class_attribute :default_params
self.default_params = {
  mime_version: "1.0",
  charset: "UTF-8",
  content_type: "text/plain",
  parts_order: [ "text/plain", "text/enriched", "text/html" ]
}.freeze

สามารถเข้าถึงและเขียนทับได้ในระดับอินสแตนซ์เช่นกัน

A.x = 1

a1 = A.new
a2 = A.new
a2.x = 2

a1.x # => 1, มาจาก A
a2.x # => 2, ถูกเขียนทับใน a2

การสร้างเมธอดไอนสแตนซ์ได้ถูกป้องกันโดยการตั้งค่า :instance_writer เป็น false.

module ActiveRecord
  class Base
    class_attribute :table_name_prefix, instance_writer: false, default: "my"
  end
end

โมเดลอาจพบว่าตัวเลือกนั้นเป็นประโยชน์เมื่อต้องการป้องกันการกำหนดค่าจำนวนมากจากการกำหนดค่าแบบมวลชน

การสร้างเมธอดอินสแตนซ์เพื่ออ่านได้ถูกป้องกันโดยการตั้งค่า :instance_reader เป็น false.

class A
  class_attribute :x, instance_reader: false
end

A.new.x = 1
A.new.x # NoMethodError

เพื่อความสะดวก class_attribute ยังกำหนดตัวตรวจสอบอินสแตนซ์ซึ่งเป็นการปฏิเสธค่าที่เมธอดอินสแตนซ์คืนค่า ในตัวอย่างข้างต้นจะเรียกว่า x? เมื่อ :instance_reader เป็น false ตัวตรวจสอบของอินสแตนซ์จะคืนค่า NoMethodError เหมือนกับเมธอดอ่าน

หากคุณไม่ต้องการตัวตรวจสอบของอินสแตนซ์ ให้ส่ง instance_predicate: false และมันจะไม่ถูกกำหนด

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/class/attribute.rb

4.1.2 cattr_reader, cattr_writer, และ cattr_accessor

แมโคร cattr_reader, cattr_writer, และ cattr_accessor เป็นคู่คำสั่งที่คล้ายกับ attr_* แต่สำหรับคลาส พวกเขาจะกำหนดค่าตัวแปรคลาสเป็น nil ยกเว้นถ้ามันมีอยู่แล้ว และสร้างเมธอดคลาสที่เกี่ยวข้องในการเข้าถึง:

class MysqlAdapter < AbstractAdapter
  # สร้างเมธอดคลาสเพื่อเข้าถึง @@emulate_booleans
  cattr_accessor :emulate_booleans
end

นอกจากนี้คุณยังสามารถส่งบล็อกไปยัง cattr_* เพื่อกำหนดค่าเริ่มต้นของแอตทริบิวต์:

class MysqlAdapter < AbstractAdapter
  # สร้างเมธอดคลาสเพื่อเข้าถึง @@emulate_booleans โดยมีค่าเริ่มต้นเป็น true
  cattr_accessor :emulate_booleans, default: true
end

เมธอดอินสแตนซ์จะถูกสร้างขึ้นเพื่อความสะดวกด้วย แต่พวกเขาเป็นพร็อกซีไปยังแอตทริบิวต์คลาส ดังนั้นอินสแตนซ์สามารถเปลี่ยนแปลงแอตทริบิวต์คลาสได้ แต่ไม่สามารถแทนที่ได้เหมือนกับ class_attribute (ดูข้างต้น) ตัวอย่างเช่น

module ActionView
  class Base
    cattr_accessor :field_error_proc, default: Proc.new { ... }
  end
end

เราสามารถเข้าถึง field_error_proc ในวิวได้

การสร้างเมธอดอินสแตนซ์อ่านสามารถป้องกันได้โดยตั้งค่า :instance_reader เป็น false และการสร้างเมธอดอินสแตนซ์เขียนสามารถป้องกันได้โดยตั้งค่า :instance_writer เป็น false การสร้างทั้งสองเมธอดสามารถป้องกันได้โดยตั้งค่า :instance_accessor เป็น false ในทุกกรณีค่าจะต้องเป็น false เท่านั้นและไม่ใช่ค่าเท็จใดๆ

module A
  class B
    # ไม่มีตัวอ่าน first_name สำหรับอินสแตนซ์ที่ถูกสร้างขึ้น
    cattr_accessor :first_name, instance_reader: false
    # ไม่มีตัวเขียน last_name= สำหรับอินสแตนซ์ที่ถูกสร้างขึ้น
    cattr_accessor :last_name, instance_writer: false
    # ไม่มีตัวอ่าน surname หรือตัวเขียน surname= สำหรับอินสแตนซ์ที่ถูกสร้างขึ้น
    cattr_accessor :surname, instance_accessor: false
  end
end

โมเดลอาจพบว่ามันเป็นประโยชน์ที่จะตั้งค่า :instance_accessor เป็น false เพื่อป้องกันการกำหนดค่าจำนวนมากจากการกำหนดค่าแบบมวลชน

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/module/attribute_accessors.rb

4.2 คลาสย่อยและลูกหลาน

4.2.1 subclasses

เมธอด subclasses จะคืนค่าคลาสย่อยของอ็อบเจกต์:

class C; end
C.subclasses # => []

class B < C; end
C.subclasses # => [B]

class A < B; end
C.subclasses # => [B]

class D < C; end
C.subclasses # => [B, D]

ลำดับที่คลาสเหล่านี้ถูกคืนค่าไม่ได้ระบุ

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/class/subclasses.rb

4.2.2 descendants

เมธอด descendants จะคืนค่าคลาสทั้งหมดที่เป็น < กว่าอ็อบเจกต์:

class C; end
C.descendants # => []

class B < C; end
C.descendants # => [B]

class A < B; end
C.descendants # => [B, A]

class D < C; end
C.descendants # => [B, A, D]

ลำดับที่คลาสเหล่านี้ถูกคืนค่าไม่ได้ระบุ

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/class/subclasses.rb

5 ขยาย String

5.1 ความปลอดภัยของผลลัพธ์

5.1.1 แรงจูงใจ

การแทรกข้อมูลลงในเทมเพลต HTML ต้องการความระมัดระวังเพิ่มเติม ตัวอย่างเช่นคุณไม่สามารถแทรก @review.title โดยตรงลงในหน้า HTML ได้ อย่างหนึ่งเพราะถ้าชื่อเรื่องรีวิวคือ "Flanagan & Matz rules!" ผลลัพธ์จะไม่ถูกต้องเพราะต้องหนีเครื่องหมายแอมเปอร์แทนด้วย "&amp;" อีกอย่างนั้น ขึ้นอยู่กับแอปพลิเคชัน มันอาจเป็นช่องโหว่ความปลอดภัยที่ใหญ่เพราะผู้ใช้สามารถฉายโค้ด HTML ที่ไม่ดีเข้าไปได้โดยการตั้งค่าชื่อเรื่องรีวิวเอง ดูส่วนเกี่ยวกับการโจมตีแบบ Cross-Site Scripting ในคู่มือความปลอดภัย เพื่อข้อมูลเพิ่มเติมเกี่ยวกับความเสี่ยง

5.1.2 สตริงที่ปลอดภัย

Active Support มีแนวคิดของสตริงที่เป็น (html) safe สตริงที่ปลอดภัยคือสตริงที่ถูกทำเครื่องหมายว่าสามารถแทรกใส่ HTML ได้อย่างเดียว มันถูกเชื่อถือไม่ว่าจะถูกหลีกเลี่ยงหรือไม่

สตริงถือว่า ไม่ปลอดภัย โดยค่าเริ่มต้น:

"".html_safe? # => false

คุณสามารถรับสตริงที่ปลอดภัยจากสตริงที่กำหนดได้ด้วยเมธอด html_safe:

s = "".html_safe
s.html_safe? # => true

สิ่งสำคัญที่ต้องเข้าใจคือ html_safe ไม่ได้ทำการหลีกเลี่ยงใดๆเลย มันเป็นการยืนยันเท่านั้น:

s = "<script>...</script>".html_safe
s.html_safe? # => true
s            # => "<script>...</script>"

คุณต้องรับผิดชอบในการตรวจสอบว่าการเรียกใช้ html_safe กับสตริงที่เฉพาะเจาะจงนั้นเป็นเรื่องปลอดภัยหรือไม่

หากคุณต่อสตริงที่ปลอดภัย ไม่ว่าจะโดยใช้ concat/<< หรือ + ผลลัพธ์ที่ได้คือสตริงที่ปลอดภัย อาร์กิวเมนต์ที่ไม่ปลอดภัยจะถูกหลีกเลี่ยง:

"".html_safe + "<" # => "&lt;"

อาร์กิวเมนต์ที่ปลอดภัยจะถูกต่อเติมโดยตรง:

"".html_safe + "<".html_safe # => "<"

เมธอดเหล่านี้ไม่ควรใช้ในมุมมองทั่วไป ค่าที่ไม่ปลอดภัยจะถูกหลีกเลี่ยงโดยอัตโนมัติ:

<%= @review.title %> <%# ปลอดภัยถ้าจำเป็น %>

ในการแทรกสิ่งที่ตรงกันข้ามใช้ตัวช่วย raw แทนการเรียกใช้ html_safe:

<%= raw @cms.current_template %> <%# แทรก @cms.current_template ตามที่กำหนดไว้อย่างเดียว %>

หรือใช้ <%== ในทางเทียบเท่า:

<%== @cms.current_template %> <%# แทรก @cms.current_template ตามที่กำหนดไว้อย่างเดียว %>

ตัวช่วย raw เรียกใช้ html_safe ให้คุณ:

def raw(stringish)
  stringish.to_s.html_safe
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/output_safety.rb.

5.1.3 การแปลง

ตามหลักทั่วไป ยกเว้นการต่อสตริงเช่นที่อธิบายไว้ข้างต้น วิธีการใดๆที่อาจเปลี่ยนแปลงสตริงจะให้คุณได้สตริงที่ไม่ปลอดภัย ตัวอย่างเช่น downcase, gsub, strip, chomp, underscore, เป็นต้น

ในกรณีของการเปลี่ยนแปลงในตำแหน่งเดียวกันเช่น gsub! ตัวรับเองก็จะกลายเป็นสตริงที่ไม่ปลอดภัย

ข้อมูล: สตริงที่ปลอดภัยจะสูญหายเสมอไม่ว่าการเปลี่ยนแปลงจะเป็นอย่างไร

5.1.4 การแปลงและการบังคับ

การเรียกใช้ to_s กับสตริงที่ปลอดภัยจะคืนค่าเป็นสตริงที่ปลอดภัย แต่การบังคับด้วย to_str จะคืนค่าเป็นสตริงที่ไม่ปลอดภัย

5.1.5 การคัดลอก

การเรียกใช้ dup หรือ clone กับสตริงที่ปลอดภัยจะคืนค่าเป็นสตริงที่ปลอดภัย

5.2 remove

เมธอด remove จะลบทุกครั้งที่พบรูปแบบ:

"Hello World".remove(/Hello /) # => "World"

ยังมีเวอร์ชันที่ทำลาย String#remove! เช่นกัน

ข้อมูล: ถูกกำหนดไว้ใน active_support/core_ext/string/filters.rb.

5.3 squish

เมธอด squish จะลบช่องว่างด้านหน้าและด้านหลัง และแทนที่ช่วงช่องว่างด้วยช่องว่างเดียว:

" \n  foo\n\r \t bar \n".squish # => "foo bar"

ยังมีเวอร์ชันที่ทำลาย String#squish! เช่นกัน

โปรดทราบว่ามันจัดการกับช่องว่างทั้ง ASCII และ Unicode

ข้อมูล: ถูกกำหนดไว้ใน active_support/core_ext/string/filters.rb.

5.4 truncate

เมธอด truncate จะคืนค่าสำเนาของสตริงตัดท้ายหลังจากความยาวที่กำหนด:

"Oh dear! Oh dear! I shall be late!".truncate(20)
# => "Oh dear! Oh dear!..."

สามารถกำหนดลักษณะของ ellipsis ด้วยตัวเลือก :omission:

"Oh dear! Oh dear! I shall be late!".truncate(20, omission: '&hellip;')
# => "Oh dear! Oh &hellip;"

โปรดทราบโดยเฉพาะว่าการตัดท้ายนี้คำนึงถึงความยาวของสตริงที่ใช้แทน

ส่ง :separator เพื่อตัดสตริงที่จุดพักธรรมชาติ: ```ruby "Oh dear! Oh dear! I shall be late!".truncate(18)

=> "Oh dear! Oh dea..."

"Oh dear! Oh dear! I shall be late!".truncate(18, separator: ' ')

=> "Oh dear! Oh..."


ตัวเลือก `:separator` สามารถเป็น regexp ได้:

```ruby
"Oh dear! Oh dear! I shall be late!".truncate(18, separator: /\s/)
# => "Oh dear! Oh..."

ในตัวอย่างข้างต้น "dear" ถูกตัดก่อน แต่ตัวเลือก :separator ป้องกันการตัด

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/filters.rb.

5.5 truncate_bytes

เมธอด truncate_bytes คืนค่าสำเนาของตัวอักษรตัดแต่ละตัวอักษรให้มีขนาดไม่เกิน bytesize ไบต์:

"👍👍👍👍".truncate_bytes(15)
# => "👍👍👍…"

สามารถกำหนด ellipsis ด้วยตัวเลือก :omission:

"👍👍👍👍".truncate_bytes(15, omission: "🖖")
# => "👍👍🖖"

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/filters.rb.

5.6 truncate_words

เมธอด truncate_words คืนค่าสำเนาของตัวอักษรตัดหลังจากจำนวนคำที่กำหนด:

"Oh dear! Oh dear! I shall be late!".truncate_words(4)
# => "Oh dear! Oh dear!..."

สามารถกำหนด ellipsis ด้วยตัวเลือก :omission:

"Oh dear! Oh dear! I shall be late!".truncate_words(4, omission: '&hellip;')
# => "Oh dear! Oh dear!&hellip;"

ส่ง :separator เพื่อตัดตัวอักษรที่จุดพักธรรมชาติ:

"Oh dear! Oh dear! I shall be late!".truncate_words(3, separator: '!')
# => "Oh dear! Oh dear! I shall be late..."

ตัวเลือก :separator สามารถเป็น regexp ได้:

"Oh dear! Oh dear! I shall be late!".truncate_words(4, separator: /\s/)
# => "Oh dear! Oh dear!..."

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/filters.rb.

5.7 inquiry

เมธอด inquiry แปลงสตริงเป็นออบเจ็กต์ StringInquirer เพื่อทำให้การเปรียบเทียบเป็นรูปแบบที่สวยงามขึ้น

"production".inquiry.production? # => true
"active".inquiry.inactive?       # => false

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inquiry.rb.

5.8 starts_with? และ ends_with?

Active Support กำหนดตัวย่อของ String#start_with? และ String#end_with? ในบุคคลที่สาม:

"foo".starts_with?("f") # => true
"foo".ends_with?("o")   # => true

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/starts_ends_with.rb.

5.9 strip_heredoc

เมธอด strip_heredoc ลบการเยื้องใน heredocs

ตัวอย่างเช่นใน

if options[:usage]
  puts <<-USAGE.strip_heredoc
    This command does such and such.

    Supported options are:
      -h         This message
      ...
  USAGE
end

ผู้ใช้จะเห็นข้อความการใช้งานที่จัดชิดกับขอบซ้าย

เทคนิคนี้จะค้นหาบรรทัดที่ย่อยที่สุดในสตริงทั้งหมดและลบ จำนวนช่องว่างด้านหน้านั้น

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/strip.rb.

5.10 indent

เมธอด indent ย่อหน้าบรรทัดในสตริง:

<<EOS.indent(2)
def some_method
  some_code
end
EOS
# =>
  def some_method
    some_code
  end

อาร์กิวเมนต์ที่สอง indent_string ระบุว่าจะใช้สตริงย่อหน้าใด ค่าเริ่มต้นคือ nil ซึ่งบอกให้เมธอดทำการเดาโดยมองไปที่บรรทัดแรกที่ย่อหน้าแล้วใช้ช่องว่างหากไม่มี

"  foo".indent(2)        # => "    foo"
"foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
"foo".indent(2, "\t")    # => "\t\tfoo"

ในขณะที่ indent_string มักจะเป็นช่องว่างหรือแท็บ แต่ก็สามารถเป็นสตริงอื่นได้

อาร์กิวเมนต์ที่สาม indent_empty_lines เป็นตัวกำหนดว่าจะย่อหน้าบรรทัดว่างหรือไม่ ค่าเริ่มต้นคือเท็จ

"foo\n\nbar".indent(2)            # => "  foo\n\n  bar"
"foo\n\nbar".indent(2, nil, true) # => "  foo\n  \n  bar"

เมธอด indent! ทำการย่อหน้าในตำแหน่งเดิม

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/indent.rb.

5.11 การเข้าถึง

5.11.1 at(position)

เมธอด at จะคืนค่าตัวอักษรของสตริงที่ตำแหน่ง position:

"hello".at(0)  # => "h"
"hello".at(4)  # => "o"
"hello".at(-1) # => "o"
"hello".at(10) # => nil

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/access.rb.

5.11.2 from(position)

เมธอด from จะคืนค่าสตริงย่อยของสตริงที่เริ่มต้นที่ตำแหน่ง position:

"hello".from(0)  # => "hello"
"hello".from(2)  # => "llo"
"hello".from(-2) # => "lo"
"hello".from(10) # => nil

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/access.rb.

5.11.3 to(position)

เมธอด to จะคืนค่าสตริงย่อยของสตริงจนถึงตำแหน่ง position:

"hello".to(0)  # => "h"
"hello".to(2)  # => "hel"
"hello".to(-2) # => "hell"
"hello".to(10) # => "hello"

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/access.rb.

5.11.4 first(limit = 1)

เมธอด first จะคืนค่าสตริงย่อยที่ประกอบด้วยตัวอักษรแรก limit ตัวของสตริง

การเรียกใช้ str.first(n) เทียบเท่ากับ str.to(n-1) ถ้า n > 0 และจะคืนสตริงว่างสำหรับ n == 0.

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/access.rb.

5.11.5 last(limit = 1)

เมธอด last จะคืนค่าสตริงย่อยที่ประกอบด้วยตัวอักษรสุดท้าย limit ตัวของสตริง

การเรียกใช้ str.last(n) เทียบเท่ากับ str.from(-n) ถ้า n > 0 และจะคืนสตริงว่างสำหรับ n == 0.

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/access.rb.

5.12 การผันคำ

5.12.1 pluralize

เมธอด pluralize จะคืนค่ารูปพหูพจน์ของสตริงที่รับเข้ามา:

"table".pluralize     # => "tables"
"ruby".pluralize      # => "rubies"
"equipment".pluralize # => "equipment"

เช่นตัวอย่างก่อนหน้านี้แสดงให้เห็นว่า Active Support รู้จักบางรูปพหูพจน์ที่ไม่เป็นไปตามกฎและคำนามที่ไม่นับได้ กฎที่มีอยู่สามารถขยายได้ใน config/initializers/inflections.rb ไฟล์นี้ถูกสร้างขึ้นโดยค่าเริ่มต้นโดยคำสั่ง rails new และมีคำแนะนำในคอมเมนต์

pluralize ยังสามารถรับพารามิเตอร์ count ได้ ถ้า count == 1 จะคืนรูปเอกพจน์ สำหรับค่าอื่น ๆ ของ count จะคืนรูปพหูพจน์:

"dude".pluralize(0) # => "dudes"
"dude".pluralize(1) # => "dude"
"dude".pluralize(2) # => "dudes"

Active Record ใช้เมธอดนี้เพื่อคำนวณชื่อตารางเริ่มต้นที่สอดคล้องกับโมเดล:

# active_record/model_schema.rb
def undecorated_table_name(model_name)
  table_name = model_name.to_s.demodulize.underscore
  pluralize_table_names ? table_name.pluralize : table_name
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.2 singularize

เมธอด singularize เป็นการกลับค่าของ pluralize:

"tables".singularize    # => "table"
"rubies".singularize    # => "ruby"
"equipment".singularize # => "equipment"

การสร้างคลาสที่เกี่ยวข้องกันโดยค่าเริ่มต้นใช้เมธอดนี้:

# active_record/reflection.rb
def derive_class_name
  class_name = name.to_s.camelize
  class_name = class_name.singularize if collection?
  class_name
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.3 camelize

เมธอด camelize จะคืนค่ารับเป็นตัวอักษรในรูปแบบแคเมิลเคส:

"product".camelize    # => "Product"
"admin_user".camelize # => "AdminUser"

เป็นกฎทั่วไปที่คุณสามารถคิดว่าเมธอดนี้เป็นเมธอดที่แปลงเส้นทางเป็นชื่อคลาสหรือโมดูลใน Ruby โดยที่เครื่องหมายสแลชแยกเนมสเปซ:

"backoffice/session".camelize # => "Backoffice::Session"

เช่น เอ็กชันแพ็คใช้เมธอดนี้เพื่อโหลดคลาสที่ให้บริการเก็บเซสชันที่แน่นอน:

# action_controller/metal/session_management.rb
def session_store=(store)
  @@session_store = store.is_a?(Symbol) ?
    ActionDispatch::Session.const_get(store.to_s.camelize) :
    store
end

camelize ยอมรับอาร์กิวเมนต์ที่เป็นตัวเลือก สามารถเป็น :upper (ค่าเริ่มต้น) หรือ :lower โดยที่ตัวอักษรแรกจะกลายเป็นตัวพิมพ์เล็ก: ruby "visual_effect".camelize(:lower) # => "visualEffect"

นั่นอาจเป็นสิ่งที่มีประโยชน์ในการคำนวณชื่อเมธอดในภาษาที่ปฏิบัติตามกฎเดียวกันนั่นคือ JavaScript

ข้อมูล: เป็นกฎเกณฑ์ทั่วไปที่คุณสามารถคิดว่า camelize เป็นการกลับของ underscore แต่มีกรณีที่ไม่เป็นเช่นนั้น: "SSLError".underscore.camelize จะให้ผลลัพธ์เป็น "SslError" ในการรองรับกรณีเช่นนี้ Active Support ช่วยให้คุณระบุคำย่อใน config/initializers/inflections.rb:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.acronym 'SSL'
end

"SSLError".underscore.camelize # => "SSLError"

camelize ถูกตั้งชื่อให้เป็น camelcase

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.4 underscore

เมธอด underscore ทำการแปลงจากแบบ Camel case เป็นรูปแบบของพาธ:

"Product".underscore   # => "product"
"AdminUser".underscore # => "admin_user"

และแปลง "::" กลับเป็น "/":

"Backoffice::Session".underscore # => "backoffice/session"

และเข้าใจสตริงที่ขึ้นต้นด้วยตัวพิมพ์เล็ก:

"visualEffect".underscore # => "visual_effect"

underscore ไม่รับอาร์กิวเมนต์

Rails ใช้ underscore เพื่อให้ได้ชื่อที่เป็นตัวพิมพ์เล็กสำหรับคลาสคอนโทรลเลอร์:

# actionpack/lib/abstract_controller/base.rb
def controller_path
  @controller_path ||= name.delete_suffix("Controller").underscore
end

ตัวอย่างเช่นค่านั้นคือค่าที่คุณได้รับใน params[:controller]

ข้อมูล: เป็นกฎเกณฑ์ทั่วไปที่คุณสามารถคิดว่า underscore เป็นการกลับของ camelize แต่มีกรณีที่ไม่เป็นเช่นนั้น เช่น "SSLError".underscore.camelize จะให้ผลลัพธ์เป็น "SslError"

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.5 titleize

เมธอด titleize ทำการเปลี่ยนตัวอักษรตัวแรกของคำในสตริงให้เป็นตัวพิมพ์ใหญ่:

"alice in wonderland".titleize # => "Alice In Wonderland"
"fermat's enigma".titleize     # => "Fermat's Enigma"

titleize ถูกตั้งชื่อให้เป็น titlecase

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.6 dasherize

เมธอด dasherize ทำการแทนที่เครื่องหมาย underscore ในสตริงด้วยเครื่องหมาย dash:

"name".dasherize         # => "name"
"contact_data".dasherize # => "contact-data"

ตัวแปลง XML ของโมเดลใช้เมธอดนี้เพื่อแทนที่เครื่องหมายของโหนดด้วย dash:

# active_model/serializers/xml.rb
def reformat_name(name)
  name = name.camelize if camelize?
  dasherize? ? name.dasherize : name
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.7 demodulize

ให้สตริงที่มีชื่อคงที่ที่มีคุณสมบัติที่กำหนด, demodulize คืนค่าชื่อคงที่เดียวกัน นั่นคือส่วนที่อยู่ทางขวาสุด:

"Product".demodulize                        # => "Product"
"Backoffice::UsersController".demodulize    # => "UsersController"
"Admin::Hotel::ReservationUtils".demodulize # => "ReservationUtils"
"::Inflections".demodulize                  # => "Inflections"
"".demodulize                               # => ""

Active Record เช่นใช้เมธอดนี้ในการคำนวณชื่อคอลัมน์ของการนับจำนวน:

# active_record/reflection.rb
def counter_cache_column
  if options[:counter_cache] == true
    "#{active_record.name.demodulize.underscore.pluralize}_count"
  elsif options[:counter_cache]
    options[:counter_cache]
  end
end

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.8 deconstantize

ให้สตริงที่มีการอ้างอิงค่าคงที่ที่มีคุณสมบัติที่กำหนด, deconstantize ลบส่วนสุดท้ายออก โดยทั่วไปจะเหลือชื่อของคอนสแตนต์ที่เก็บ:

"Product".deconstantize                        # => ""
"Backoffice::UsersController".deconstantize    # => "Backoffice"
"Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel"

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/string/inflections.rb.

5.12.9 parameterize

เมธอด parameterize ทำการปรับปรุงสตริงให้เป็นรูปแบบที่ใช้ใน URL ที่สวยงาม

"John Smith".parameterize # => "john-smith"
"Kurt Gödel".parameterize # => "kurt-godel"

เพื่อรักษาตัวอักษรในสตริง ให้ตั้งค่าอาร์กิวเมนต์ preserve_case เป็น true โดยค่าเริ่มต้น preserve_case ถูกตั้งค่าเป็น false

"John Smith".parameterize(preserve_case: true) # => "John-Smith"
"Kurt Gödel".parameterize(preserve_case: true) # => "Kurt-Godel"

ในการใช้ตัวคั่นแบบกำหนดเอง ให้แทนที่อาร์กิวเมนต์ separator

"John Smith".parameterize(separator: "_") # => "john_smith"
"Kurt Gödel".parameterize(separator: "_") # => "kurt_godel"

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/inflections.rb

5.12.10 tableize

เมธอด tableize คือ underscore ตามด้วย pluralize.

"Person".tableize      # => "people"
"Invoice".tableize     # => "invoices"
"InvoiceLine".tableize # => "invoice_lines"

เป็นกฎทั่วไปว่า tableize จะคืนชื่อตารางที่สอดคล้องกับโมเดลที่กำหนดให้ ในกรณีที่เป็นกรณีง่าย การประมวลผลจริงใน Active Record ไม่ได้เป็นแบบ tableize โดยตรง แต่ยังทำการ demodulize ชื่อคลาสและตรวจสอบตัวเลือกบางอย่างที่อาจมีผลต่อสตริงที่คืนกลับ

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/inflections.rb

5.12.11 classify

เมธอด classify เป็นการกลับค่าของ tableize โดยคืนชื่อคลาสที่สอดคล้องกับชื่อตาราง:

"people".classify        # => "Person"
"invoices".classify      # => "Invoice"
"invoice_lines".classify # => "InvoiceLine"

เมธอดเข้าใจชื่อตารางที่มีคุณสมบัติ:

"highrise_production.companies".classify # => "Company"

โปรดทราบว่า classify คืนชื่อคลาสเป็นสตริง คุณสามารถรับออบเจกต์คลาสจริงๆได้โดยเรียกใช้ constantize บนสตริงนั้น ซึ่งจะอธิบายต่อไป

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/inflections.rb

5.12.12 constantize

เมธอด constantize แก้ไขนิพจน์การอ้างอิงค่าคงที่ในตัวรับของมัน:

"Integer".constantize # => Integer

module M
  X = 1
end
"M::X".constantize # => 1

หากสตริงประเมินไม่ได้เป็นค่าคงที่ที่รู้จักหรือเนื้อหาของมันไม่ใช่ชื่อค่าคงที่ที่ถูกต้อง constantize จะเรียก NameError

การแก้ไขชื่อค่าคงที่ด้วย constantize เริ่มต้นที่ Object ระดับสูงสุดเสมอ แม้ว่าจะไม่มี "::" นำหน้า

X = :in_Object
module M
  X = :in_M

  X                 # => :in_M
  "::X".constantize # => :in_Object
  "X".constantize   # => :in_Object (!)
end

ดังนั้น โดยทั่วไปแล้ว มันไม่เทียบเท่ากับสิ่งที่ Ruby จะทำในจุดเดียวกัน หากค่าคงที่จริงๆถูกประเมิน

ทดสอบเมลเลอร์ได้รับเมลเลอร์ที่กำลังทดสอบจากชื่อคลาสทดสอบโดยใช้ constantize:

# action_mailer/test_case.rb
def determine_default_mailer(name)
  name.delete_suffix("Test").constantize
rescue NameError => e
  raise NonInferrableMailerError.new(name)
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/inflections.rb

5.12.13 humanize

เมธอด humanize ปรับแต่งชื่อแอตทริบิวต์สำหรับการแสดงผลให้กับผู้ใช้งาน

โดยเฉพาะอย่างยิ่ง มันทำการดำเนินการต่อไปนี้:

  • ใช้กฎการเอาชื่อมนุษย์กับอาร์กิวเมนต์
  • ลบขีดล่างนำหน้าหากมี
  • ลบ "_id" ท้ายสุดหากมี
  • แทนที่ขีดล่างด้วยช่องว่างหากมี
  • ทำให้ตัวพิมพ์เล็กทั้งหมดยกเว้นคำย่อ
  • ทำให้ตัวพิมพ์ใหญ่ตัวแรก

การทำให้ตัวพิมพ์ใหญ่ตัวแรกสามารถปิดการใช้งานได้โดยตั้งค่าตัวเลือก :capitalize เป็น false (ค่าเริ่มต้นคือ true)

"name".humanize                         # => "Name"
"author_id".humanize                    # => "Author"
"author_id".humanize(capitalize: false) # => "author"
"comments_count".humanize               # => "Comments count"
"_id".humanize                          # => "Id"

หาก "SSL" ถูกกำหนดให้เป็นคำย่อ:

'ssl_error'.humanize # => "SSL error"

เมธอดช่วย full_messages ใช้ humanize เป็นค่าเริ่มต้นเพื่อรวมชื่อแอตทริบิวต์:

def full_messages
  map { |attribute, message| full_message(attribute, message) }
end

def full_message
  # ...
  attr_name = attribute.to_s.tr('.', '_').humanize
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
  # ...
end

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/string/inflections.rb

5.12.14 foreign_key

เมธอด foreign_key ให้ชื่อคอลัมน์คีย์ต่างประเทศจากชื่อคลาส โดยการ demodulize, underscores, และเพิ่ม "_id":

"User".foreign_key           # => "user_id"
"InvoiceLine".foreign_key    # => "invoice_line_id"
"Admin::Session".foreign_key # => "session_id"

ส่งอาร์กิวเมนต์เท็จหากคุณไม่ต้องการขีดล่างใน "_id":

"User".foreign_key(false) # => "userid"

การเชื่อมโยงใช้เมธอดนี้เพื่อสร้างคีย์ต่างประเทศโดยอัตโนมัติ เช่น has_one และ has_many ทำดังนี้:

# active_record/associations.rb
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/string/inflections.rb.

5.12.15 upcase_first

เมธอด upcase_first จะทำให้ตัวอักษรแรกของวัตถุเป็นตัวพิมพ์ใหญ่:

"employee salary".upcase_first # => "Employee salary"
"".upcase_first                # => ""

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/string/inflections.rb.

5.12.16 downcase_first

เมธอด downcase_first จะแปลงตัวอักษรแรกของวัตถุเป็นตัวพิมพ์เล็ก:

"If I had read Alice in Wonderland".downcase_first # => "if I had read Alice in Wonderland"
"".downcase_first                                  # => ""

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/string/inflections.rb.

5.13 การแปลง

5.13.1 to_date, to_time, to_datetime

เมธอด to_date, to_time, และ to_datetime เป็นเมธอดที่ใช้สะดวกในการแปลงข้อมูลเป็นวันที่และเวลา:

"2010-07-27".to_date              # => Tue, 27 Jul 2010
"2010-07-27 23:37:00".to_time     # => 2010-07-27 23:37:00 +0200
"2010-07-27 23:37:00".to_datetime # => Tue, 27 Jul 2010 23:37:00 +0000

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

ค่าเริ่มต้นคือ :local.

โปรดอ้างอิงเอกสารของ Date._parse เพื่อดูรายละเอียดเพิ่มเติม

ข้อมูล: เมื่อวัตถุว่างเปล่า เมธอดเหล่านี้จะส่งคืน nil.

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/string/conversions.rb.

6 ส่วนขยายให้กับ Symbol

6.1 starts_with? และ ends_with?

Active Support กำหนดตัวย่อของ Symbol#start_with? และ Symbol#end_with? ในบุคคลที่ 3:

:foo.starts_with?("f") # => true
:foo.ends_with?("o")   # => true

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/symbol/starts_ends_with.rb.

7 ส่วนขยายให้กับ Numeric

7.1 Bytes

ตัวเลขทุกตัวสามารถใช้เมธอดเหล่านี้ได้:

เมธอดเหล่านี้จะส่งคืนจำนวนไบต์ที่เกี่ยวข้องโดยใช้อัตราการแปลงเป็น 1024:

2.kilobytes   # => 2048
3.megabytes   # => 3145728
3.5.gigabytes # => 3758096384.0
-4.exabytes   # => -4611686018427387904

รูปพจน์เอกพจน์ถูกตั้งชื่อใหม่เพื่อให้คุณสามารถใช้ได้เช่น:

1.megabyte # => 1048576

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/numeric/bytes.rb.

7.2 เวลา

เมธอดต่อไปนี้:

ช่วยให้คุณประกาศและคำนวณเวลา เช่น 45.minutes + 2.hours + 4.weeks ค่าที่ส่งคืนยังสามารถเพิ่มหรือลบจากวัตถุเวลาได้

เมธอดเหล่านี้สามารถผสมกับ from_now, ago, เป็นต้น เพื่อคำนวณวันที่อย่างแม่นยำ เช่น:

# เทียบเท่ากับ Time.current.advance(days: 1)
1.day.from_now

# เทียบเท่ากับ Time.current.advance(weeks: 2)
2.weeks.from_now

# เทียบเท่ากับ Time.current.advance(days: 4, weeks: 5)
(4.days + 5.weeks).from_now

คำเตือน: สำหรับระยะเวลาอื่น ๆ โปรดอ้างอิงส่วนขยายเวลาให้กับ Integer.

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/numeric/time.rb.

7.3 การจัดรูปแบบ

ช่วยให้คุณจัดรูปแบบตัวเลขในหลายรูปแบบ

สร้างสตริงที่แสดงตัวเลขเป็นหมายเลขโทรศัพท์:

5551234.to_fs(:phone)
# => 555-1234
1235551234.to_fs(:phone)
# => 123-555-1234
1235551234.to_fs(:phone, area_code: true)
# => (123) 555-1234
1235551234.to_fs(:phone, delimiter: " ")
# => 123 555 1234
1235551234.to_fs(:phone, area_code: true, extension: 555)
# => (123) 555-1234 x 555
1235551234.to_fs(:phone, country_code: 1)
# => +1-123-555-1234

สร้างสตริงที่แสดงตัวเลขเป็นสกุลเงิน:

1234567890.50.to_fs(:currency)                 # => $1,234,567,890.50
1234567890.506.to_fs(:currency)                # => $1,234,567,890.51
1234567890.506.to_fs(:currency, precision: 3)  # => $1,234,567,890.506

สร้างสตริงที่แสดงตัวเลขเป็นเปอร์เซ็นต์:

100.to_fs(:percentage)
# => 100.000%
100.to_fs(:percentage, precision: 0)
# => 100%
1000.to_fs(:percentage, delimiter: '.', separator: ',')
# => 1.000,000%
302.24398923423.to_fs(:percentage, precision: 5)
# => 302.24399%

สร้างสตริงที่แสดงตัวเลขในรูปแบบที่มีตัวคั่น:

12345678.to_fs(:delimited)                     # => 12,345,678
12345678.05.to_fs(:delimited)                  # => 12,345,678.05
12345678.to_fs(:delimited, delimiter: ".")     # => 12.345.678
12345678.to_fs(:delimited, delimiter: ",")     # => 12,345,678
12345678.05.to_fs(:delimited, separator: " ")  # => 12,345,678 05

สร้างสตริงที่แสดงตัวเลขที่ถูกปัดเศษ:

111.2345.to_fs(:rounded)                     # => 111.235
111.2345.to_fs(:rounded, precision: 2)       # => 111.23
13.to_fs(:rounded, precision: 5)             # => 13.00000
389.32314.to_fs(:rounded, precision: 0)      # => 389
111.2345.to_fs(:rounded, significant: true)  # => 111

สร้างสตริงที่แสดงตัวเลขในรูปแบบขนานกับขนาดไบต์:

123.to_fs(:human_size)                  # => 123 Bytes
1234.to_fs(:human_size)                 # => 1.21 KB
12345.to_fs(:human_size)                # => 12.1 KB
1234567.to_fs(:human_size)              # => 1.18 MB
1234567890.to_fs(:human_size)           # => 1.15 GB
1234567890123.to_fs(:human_size)        # => 1.12 TB
1234567890123456.to_fs(:human_size)     # => 1.1 PB
1234567890123456789.to_fs(:human_size)  # => 1.07 EB

สร้างสตริงที่แสดงตัวเลขในรูปแบบข้อความที่อ่านง่าย:

123.to_fs(:human)               # => "123"
1234.to_fs(:human)              # => "1.23 Thousand"
12345.to_fs(:human)             # => "12.3 Thousand"
1234567.to_fs(:human)           # => "1.23 Million"
1234567890.to_fs(:human)        # => "1.23 Billion"
1234567890123.to_fs(:human)     # => "1.23 Trillion"
1234567890123456.to_fs(:human)  # => "1.23 Quadrillion"

หมายเหตุ: นิยามใน active_support/core_ext/numeric/conversions.rb.

8 ส่วนขยายให้กับ Integer

8.1 multiple_of?

เมธอด multiple_of? ทดสอบว่าจำนวนเต็มเป็นเท่ากับอาร์กิวเมนต์หรือไม่:

2.multiple_of?(1) # => true
1.multiple_of?(2) # => false

หมายเหตุ: นิยามใน active_support/core_ext/integer/multiple.rb.

8.2 ordinal

เมธอด ordinal คืนคำต่อท้ายที่เป็นลำดับของจำนวนเต็ม:

1.ordinal    # => "st"
2.ordinal    # => "nd"
53.ordinal   # => "rd"
2009.ordinal # => "th"
-21.ordinal  # => "st"
-134.ordinal # => "th"

หมายเหตุ: นิยามใน active_support/core_ext/integer/inflections.rb.

8.3 ordinalize

เมธอด ordinalize คืนคำที่เป็นลำดับของจำนวนเต็ม ในการเปรียบเทียบ โปรดทราบว่าเมธอด ordinal คืนค่าเฉพาะสตริงต่อท้ายเท่านั้น.

1.ordinalize    # => "1st"
2.ordinalize    # => "2nd"
53.ordinalize   # => "53rd"
2009.ordinalize # => "2009th"
-21.ordinalize  # => "-21st"
-134.ordinalize # => "-134th"

หมายเหตุ: นิยามใน active_support/core_ext/integer/inflections.rb.

8.4 Time

เมธอดต่อไปนี้:

ช่วยให้สามารถประกาศและคำนวณเวลา เช่น 4.months + 5.years ค่าที่คืนค่าสามารถเพิ่มหรือลบจากออบเจ็กต์เวลาได้เช่นกัน.

เมธอดเหล่านี้สามารถใช้ร่วมกับ from_now, ago, เป็นต้น เพื่อคำนวณวันที่อย่างแม่นยำ เช่น:

# เทียบเท่ากับ Time.current.advance(months: 1)
1.month.from_now

# เทียบเท่ากับ Time.current.advance(years: 2)
2.years.from_now

# เทียบเท่ากับ Time.current.advance(months: 4, years: 5)
(4.months + 5.years).from_now

คำเตือน: สำหรับระยะเวลาอื่นๆ โปรดอ้างอิงส่วนขยายเวลาไปยัง Numeric.

หมายเหตุ: นิยามใน active_support/core_ext/integer/time.rb.

9 ส่วนขยายให้กับ BigDecimal

9.1 to_s

เมธอด to_s ให้ตัวกำหนดเริ่มต้นเป็น "F" ซึ่งหมายความว่าการเรียกใช้งาน to_s จะได้ผลลัพธ์เป็นตัวเลขทศนิยมแทนการแสดงเลขวิศวกรรม:

BigDecimal(5.00, 6).to_s       # => "5.0"

การแสดงเลขวิศวกรรมยังคงรองรับ:

BigDecimal(5.00, 6).to_s("e")  # => "0.5E1"

10 ส่วนขยายให้กับ Enumerable

10.1 sum

เมธอด sum บวกสมาชิกของอินเทอร์เอเบิล: ruby [1, 2, 3].sum # => 6 (1..100).sum # => 5050

การบวกเพิ่มเติมเฉพาะสมาชิกที่ตอบสนองกับ +:

[[1, 2], [2, 3], [3, 4]].sum    # => [1, 2, 2, 3, 3, 4]
%w(foo bar baz).sum             # => "foobarbaz"
{ a: 1, b: 2, c: 3 }.sum          # => [:a, 1, :b, 2, :c, 3]

ผลรวมของคอลเลกชันที่ว่างเปล่าเป็นศูนย์ตามค่าเริ่มต้น แต่สามารถกำหนดค่าเริ่มต้นได้:

[].sum    # => 0
[].sum(1) # => 1

หากมีบล็อกที่กำหนดให้ sum เป็นตัววนซ้ำที่ส่งคืนค่าของสมาชิกในคอลเลกชันและรวมผลลัพธ์ที่ส่งกลับ:

(1..5).sum { |n| n * 2 } # => 30
[2, 4, 6, 8, 10].sum    # => 30

ผลรวมของตัวรับที่ว่างเปล่าสามารถกำหนดเองได้ในรูปแบบนี้เช่นกัน:

[].sum(1) { |n| n**3 } # => 1

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.2 index_by

เมธอด index_by สร้างแฮชที่มีสมาชิกของคอลเลกชันที่มีดัชนีโดยใช้คีย์ที่กำหนด

มันวนซ้ำผ่านคอลเลกชันและส่งผ่านแต่ละสมาชิกให้กับบล็อก สมาชิกจะถูกจัดกุญแจโดยค่าที่ส่งกลับจากบล็อก:

invoices.index_by(&:number)
# => {'2009-032' => <Invoice ...>, '2009-008' => <Invoice ...>, ...}

คำเตือน คีย์ควรเป็นค่าที่ไม่ซ้ำกันตามปกติ หากบล็อกส่งค่าเดียวกันสำหรับสมาชิกที่แตกต่างกัน จะไม่สร้างคอลเลกชันสำหรับคีย์นั้น รายการสุดท้ายจะชนะ

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.3 index_with

เมธอด index_with สร้างแฮชที่มีสมาชิกของคอลเลกชันเป็นคีย์ ค่า เป็นค่าเริ่มต้นที่ผ่านหรือส่งกลับในบล็อก

post = Post.new(title: "hey there", body: "what's up?")

%i( title body ).index_with { |attr_name| post.public_send(attr_name) }
# => { title: "hey there", body: "what's up?" }

WEEKDAYS.index_with(Interval.all_day)
# => { monday: [ 0, 1440 ], … }

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.4 many?

เมธอด many? เป็นตัวย่อสำหรับ collection.size > 1:

<% if pages.many? %>
  <%= pagination_links %>
<% end %>

หากมีบล็อกที่กำหนดเพิ่มเติม many? จะพิจารณาเฉพาะสมาชิกที่ส่งคืนค่าเป็นจริง:

@see_more = videos.many? { |video| video.category == params[:category] }

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.5 exclude?

พรีดิเคต exclude? ทดสอบว่าวัตถุที่กำหนดไม่เป็นส่วนหนึ่งของคอลเลกชัน นี่คือการปฏิเสธของ include? ที่มีอยู่:

to_visit << node if visited.exclude?(node)

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.6 including

เมธอด including ส่งคืนคอลเลกชันใหม่ที่รวมสมาชิกที่ผ่านมา:

[ 1, 2, 3 ].including(4, 5)                    # => [ 1, 2, 3, 4, 5 ]
["David", "Rafael"].including %w[ Aaron Todd ] # => ["David", "Rafael", "Aaron", "Todd"]

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.7 excluding

เมธอด excluding ส่งคืนสำเนาของคอลเลกชันที่กำหนดสมาชิกที่ระบุ ถูกลบออก:

["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]

excluding เป็นนามแฝงของ without.

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb.

10.8 pluck

เมธอด pluck แยกคีย์ที่กำหนดจากแต่ละสมาชิก:

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name) # => ["David", "Rafael", "Aaron"]
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name) # => [[1, "David"], [2, "Rafael"]]

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb

10.9 pick

เมธอด pick สกัดคีย์ที่กำหนดมาจากองค์ประกอบแรก:

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name) # => "David"
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name) # => [1, "David"]

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/enumerable.rb

11 ส่วนขยายของ Array

11.1 การเข้าถึง

Active Support ขยาย API ของอาร์เรย์เพื่อสะดวกในการเข้าถึงบางวิธี ตัวอย่างเช่น to จะคืนค่าอาร์เรย์ย่อยขององค์ประกอบจนถึงองค์ประกอบที่มีดัชนีที่ระบุ:

%w(a b c d).to(2) # => ["a", "b", "c"]
[].to(7)          # => []

อย่างเดียวกัน from จะคืนค่าส่วนท้ายของอาร์เรย์ตั้งแต่องค์ประกอบที่มีดัชนีที่ระบุไปจนถึงสุดท้าย หากดัชนีมากกว่าความยาวของอาร์เรย์ จะคืนค่าอาร์เรย์ว่าง

%w(a b c d).from(2)  # => ["c", "d"]
%w(a b c d).from(10) # => []
[].from(0)           # => []

เมธอด including จะคืนค่าอาร์เรย์ใหม่ที่รวมองค์ประกอบที่ระบุ:

[ 1, 2, 3 ].including(4, 5)          # => [ 1, 2, 3, 4, 5 ]
[ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]

เมธอด excluding จะคืนค่าสำเนาของอาร์เรย์โดยไม่รวมองค์ประกอบที่ระบุ นี่เป็นการปรับปรุงของ Enumerable#excluding ที่ใช้ Array#- แทน Array#reject เพื่อเพิ่มประสิทธิภาพ

["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
[ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ])                  # => [ [ 0, 1 ] ]

เมธอด second, third, fourth, และ fifth จะคืนค่าองค์ประกอบที่สอง, ที่สาม, ที่สี่, และที่ห้าตามลำดับ องค์ประกอบที่สองจากท้ายและองค์ประกอบที่สามจากท้ายก็คืนค่าเช่นกัน (first และ last เป็นฟังก์ชันที่มีอยู่แล้ว) ด้วยความรู้สึกทางสังคมและการสร้างสรรค์ที่เชิดชูกันทั่วไป จึงมี forty_two ให้ใช้งานเช่นกัน

%w(a b c d).third # => "c"
%w(a b c d).fifth # => nil

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/access.rb

11.2 การสกัด

เมธอด extract! จะลบและคืนค่าองค์ประกอบที่ฟังก์ชันคืนค่าเป็นจริง หากไม่มีฟังก์ชันคืนค่า จะคืนค่า Enumerator แทน

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
numbers # => [0, 2, 4, 6, 8]

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/extract.rb

11.3 การสกัดตัวเลือก

เมื่ออาร์กิวเมนต์สุดท้ายในการเรียกเมธอดเป็นแฮช เว้นแต่จะมีอาร์กิวเมนต์ &block Ruby อนุญาตให้คุณละเว้นวงเล็บได้:

User.exists?(email: params[:email])

การใช้ไวยากรณ์นี้มีความสะดวกมากใน Rails เพื่อหลีกเลี่ยงอาร์กิวเมนต์ตำแหน่งที่มีจำนวนมาก และให้แทนที่ด้วยอินเทอร์เฟซที่จำลองพารามิเตอร์ที่มีชื่อ โดยเฉพาะอย่างยิ่งการใช้แฮชที่ตามมา

หากเมธอดคาดหวังอาร์กิวเมนต์จำนวนตัวแปรและใช้ * ในการประกาศ แต่แฮชตัวเลือกนั้นจะเป็นส่วนหนึ่งของอาร์เรย์ของอาร์กิวเมนต์ แล้วแฮชตัวเลือกจะสูญเสียบทบาทของตน

ในกรณีเช่นนั้น คุณสามารถให้แฮชตัวเลือกได้รับการจัดการที่แตกต่างด้วย extract_options! เมธอดนี้จะตรวจสอบประเภทของรายการสุดท้ายในอาร์เรย์ หากเป็นแฮชจะดึงออกและคืนค่า มิฉะนั้นจะคืนค่าแฮชว่าง

เรามาดูตัวอย่างการกำหนด caches_action controller macro:

def caches_action(*actions)
  return unless cache_configured?
  options = actions.extract_options!
  # ...
end

เมธอดนี้รับชื่อแอ็กชันได้เป็นจำนวนไม่จำกัด และมีตัวเลือกแบบแฮชเป็นอาร์กิวเมนต์สุดท้าย ด้วยการเรียกใช้ extract_options! คุณจะได้รับแบบแฮชตัวเลือกและลบออกจาก actions อย่างง่ายและชัดเจน

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/extract_options.rb.

11.4 การแปลง

11.4.1 to_sentence

เมธอด to_sentence แปลงอาร์เรย์ให้เป็นสตริงที่ประกอบด้วยประโยคที่ระบุรายการ:

%w().to_sentence                # => ""
%w(Earth).to_sentence           # => "Earth"
%w(Earth Wind).to_sentence      # => "Earth and Wind"
%w(Earth Wind Fire).to_sentence # => "Earth, Wind, and Fire"

เมธอดนี้รับตัวเลือกสามตัว:

  • :two_words_connector: ใช้อะไรสำหรับอาร์เรย์ที่มีความยาว 2 ค่า ค่าเริ่มต้นคือ " and "
  • :words_connector: ใช้เชื่อมต่อองค์ประกอบของอาร์เรย์ที่มี 3 หรือมากกว่า ค่าเริ่มต้นคือ ", "
  • :last_word_connector: ใช้เชื่อมต่อรายการสุดท้ายของอาร์เรย์ที่มี 3 หรือมากกว่า ค่าเริ่มต้นคือ ", and "

ค่าเริ่มต้นสำหรับตัวเลือกเหล่านี้สามารถแปลงเป็นภาษาท้องถิ่นได้ โดยใช้คีย์ต่างๆ ดังนี้:

ตัวเลือก คีย์ I18n
:two_words_connector support.array.two_words_connector
:words_connector support.array.words_connector
:last_word_connector support.array.last_word_connector

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/conversions.rb.

11.4.2 to_fs

เมธอด to_fs ทำงานเหมือน to_s เป็นค่าเริ่มต้น

แต่ถ้าอาร์เรย์มีรายการที่ตอบสนองต่อ id สัญลักษณ์ :db สามารถถูกส่งเป็นอาร์กิวเมนต์ได้ ซึ่งใช้งานได้โดยปกติกับคอลเลกชันของออบเจกต์ Active Record สตริงที่คืนค่าคือ:

[].to_fs(:db)            # => "null"
[user].to_fs(:db)        # => "8456"
invoice.lines.to_fs(:db) # => "23,567,556,12"

จำนวนเต็มในตัวอย่างข้างต้นควรมาจากการเรียก id ที่เกี่ยวข้อง

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/conversions.rb.

11.4.3 to_xml

เมธอด to_xml คืนค่าสตริงที่ประกอบด้วยรายการ XML ของอ็อบเจกต์ที่รับเป็นอาร์กิวเมนต์:

Contributor.limit(2).order(:rank).to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <contributors type="array">
#   <contributor>
#     <id type="integer">4356</id>
#     <name>Jeremy Kemper</name>
#     <rank type="integer">1</rank>
#     <url-id>jeremy-kemper</url-id>
#   </contributor>
#   <contributor>
#     <id type="integer">4404</id>
#     <name>David Heinemeier Hansson</name>
#     <rank type="integer">2</rank>
#     <url-id>david-heinemeier-hansson</url-id>
#   </contributor>
# </contributors>

เพื่อทำเช่นนี้ มันจะส่ง to_xml ไปยังทุกออบเจกต์ตามลำดับ และรวบรวมผลลัพธ์ภายใต้โหนดราก รายการทั้งหมดต้องตอบสนองต่อ to_xml มิฉะนั้นจะเกิดข้อยกเว้น

ตามค่าเริ่มต้น ชื่อขององค์ประกอบรากคือชื่อคลาสของรายการแรกที่มีเส้นใต้และเครื่องหมายขีดกลาง หากส่วนที่เหลือขององค์ประกอบเป็นชนิดเดียวกัน (ตรวจสอบด้วย is_a?) และไม่ใช่แฮช ในตัวอย่างข้างต้นคือ "contributors"

หากมีองค์ประกอบใดๆ ที่ไม่เป็นชนิดขององค์ประกอบแรก โหนดรากก็จะกลายเป็น "objects":

[Contributor.first, Commit.first].to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <id type="integer">4583</id>
#     <name>Aaron Batalion</name>
#     <rank type="integer">53</rank>
#     <url-id>aaron-batalion</url-id>
#   </object>
#   <object>
#     <author>Joshua Peek</author>
#     <authored-timestamp type="datetime">2009-09-02T16:44:36Z</authored-timestamp>
#     <branch>origin/master</branch>
#     <committed-timestamp type="datetime">2009-09-02T16:44:36Z</committed-timestamp>
#     <committer>Joshua Peek</committer>
#     <git-show nil="true"></git-show>
#     <id type="integer">190316</id>
#     <imported-from-svn type="boolean">false</imported-from-svn>
#     <message>Kill AMo observing wrap_with_notifications since ARes was only using it</message>
#     <sha1>723a47bfb3708f968821bc969a9a3fc873a3ed58</sha1>
#   </object>
# </objects>

หากผู้รับเป็นอาร์เรย์ของแฮช องค์ประกอบรากจะเป็น "ออบเจ็กต์" โดยค่าเริ่มต้น:

[{ a: 1, b: 2 }, { c: 3 }].to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <b type="integer">2</b>
#     <a type="integer">1</a>
#   </object>
#   <object>
#     <c type="integer">3</c>
#   </object>
# </objects>

คำเตือน. หากคอลเลกชันเป็นว่างเปล่า องค์ประกอบรากจะเป็น "nil-classes" โดยค่าเริ่มต้น นั่นคือสิ่งที่คุณต้องระวัง เช่น องค์ประกอบรากของรายการผู้มีส่วนร่วมด้านบนจะไม่ใช่ "ผู้มีส่วนร่วม" หากคอลเลกชันเป็นว่างเปล่า แต่เป็น "nil-classes" คุณสามารถใช้ตัวเลือก :root เพื่อให้มีองค์ประกอบรากที่สม่ำเสมอ

ชื่อของโหนดลูกๆ คือชื่อของโหนดรากที่ถูกกำหนดให้เป็นรูปพจนานุกรม ในตัวอย่างด้านบนเราเห็น "ผู้มีส่วนร่วม" และ "ออบเจ็กต์" ตัวเลือก :children ช่วยให้คุณตั้งชื่อโหนดเหล่านี้

XML builder เริ่มต้นค่าเป็นตัวอย่างใหม่ของ Builder::XmlMarkup คุณสามารถกำหนดค่า builder เองผ่านตัวเลือก :builder วิธีนี้ยังรองรับตัวเลือกอื่น ๆ เช่น :dasherize และอื่น ๆ ซึ่งถูกส่งต่อไปยัง builder:

Contributor.limit(2).order(:rank).to_xml(skip_types: true)
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <contributors>
#   <contributor>
#     <id>4356</id>
#     <name>Jeremy Kemper</name>
#     <rank>1</rank>
#     <url-id>jeremy-kemper</url-id>
#   </contributor>
#   <contributor>
#     <id>4404</id>
#     <name>David Heinemeier Hansson</name>
#     <rank>2</rank>
#     <url-id>david-heinemeier-hansson</url-id>
#   </contributor>
# </contributors>

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/conversions.rb.

11.5 การห่อหุ้ม

เมธอด Array.wrap ห่อหุ้มอาร์กิวเมนต์ของมันในอาร์เรย์ ยกเว้นถ้ามันเป็นอาร์เรย์ (หรืออาร์เรย์เหมือน)

โดยเฉพาะอย่างยิ่ง:

  • หากอาร์กิวเมนต์เป็น nil จะคืนอาร์เรย์ว่างเปล่า
  • มิฉะนั้น หากอาร์กิวเมนต์ตอบสนองกับ to_ary จะเรียกใช้ และหากค่าของ to_ary ไม่ใช่ nil จะคืนค่านั้น
  • มิฉะนั้น จะคืนอาร์เรย์ที่มีอาร์กิวเมนต์เป็นสมาชิกเดียว
Array.wrap(nil)       # => []
Array.wrap([1, 2, 3]) # => [1, 2, 3]
Array.wrap(0)         # => [0]

เมธอดนี้คล้ายกับ Kernel#Array แต่มีความแตกต่างบางอย่าง:

  • หากอาร์กิวเมนต์ตอบสนองกับ to_ary จะเรียกใช้เมธอด แต่ Kernel#Array จะลองเรียกใช้ to_a หากค่าที่คืนมาเป็น nil แต่ Array.wrap จะคืนอาร์เรย์ที่มีอาร์กิวเมนต์เป็นสมาชิกเดียวทันที
  • หากค่าที่คืนมาจาก to_ary ไม่ใช่ nil หรือออบเจ็กต์ของอาร์เรย์ Kernel#Array จะเรียกใช้ raise exception ในขณะที่ Array.wrap ไม่ได้ทำเช่นนั้น มันแค่คืนค่า
  • มันไม่เรียกใช้ to_a กับอาร์กิวเมนต์ หากอาร์กิวเมนต์ไม่ตอบสนองกับ to_ary มันจะคืนอาร์เรย์ที่มีอาร์กิวเมนต์เป็นสมาชิกเดียว

จุดสุดท้ายนี้เป็นสิ่งที่ควรเปรียบเทียบกับบางอย่างใน enumerables บางอย่าง:

Array.wrap(foo: :bar) # => [{:foo=>:bar}]
Array(foo: :bar)      # => [[:foo, :bar]]

ยังมีรูปแบบที่เกี่ยวข้องที่ใช้ตัวดอกจัน:

[*object]

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/array/wrap.rb.

11.6 การทำซ้ำ

เมธอด Array#deep_dup ทำซ้ำตัวเองและวัตถุทั้งหมดภายใน โดยใช้เมธอด Object#deep_dup ใน Active Support มันทำงานเหมือนกับ Array#map โดยส่งเมธอด deep_dup ไปยังแต่ละวัตถุภายใน

array = [1, [2, 3]]
dup = array.deep_dup
dup[1][2] = 4
array[1][2] == nil   # => true

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/object/deep_dup.rb

11.7 การจัดกลุ่ม

11.7.1 in_groups_of(number, fill_with = nil)

เมธอด in_groups_of แบ่งอาร์เรย์เป็นกลุ่มติดต่อกันของขนาดที่กำหนด และคืนค่าอาร์เรย์ที่มีกลุ่ม:

[1, 2, 3].in_groups_of(2) # => [[1, 2], [3, nil]]

หรือส่งค่าต่อไปในลำดับถ้ามีบล็อกที่ถูกส่ง:

<% sample.in_groups_of(3) do |a, b, c| %>
  <tr>
    <td><%= a %></td>
    <td><%= b %></td>
    <td><%= c %></td>
  </tr>
<% end %>

ตัวอย่างแรกแสดงวิธี in_groups_of เติมกลุ่มสุดท้ายด้วยสมาชิก nil ตามที่ต้องการ คุณสามารถเปลี่ยนค่าเติมนี้ได้โดยใช้อาร์กิวเมนต์ที่สอง:

[1, 2, 3].in_groups_of(2, 0) # => [[1, 2], [3, 0]]

และคุณสามารถบอกเมธอดให้ไม่เติมกลุ่มสุดท้ายโดยส่ง false:

[1, 2, 3].in_groups_of(2, false) # => [[1, 2], [3]]

เนื่องจากนั้น false ไม่สามารถใช้เป็นค่าเติมได้

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/array/grouping.rb.

11.7.2 in_groups(number, fill_with = nil)

เมธอด in_groups แบ่งอาร์เรย์เป็นจำนวนกลุ่มที่กำหนด และคืนค่าอาร์เรย์ที่มีกลุ่ม:

%w(1 2 3 4 5 6 7).in_groups(3)
# => [["1", "2", "3"], ["4", "5", nil], ["6", "7", nil]]

หรือส่งค่าต่อไปในลำดับถ้ามีบล็อกที่ถูกส่ง:

%w(1 2 3 4 5 6 7).in_groups(3) { |group| p group }
["1", "2", "3"]
["4", "5", nil]
["6", "7", nil]

ตัวอย่างข้างต้นแสดงว่า in_groups เติมกลุ่มบางกลุ่มด้วยสมาชิก nil ตามที่ต้องการ กลุ่มสามารถได้รับสมาชิกเพิ่มเติมได้สูงสุดหนึ่งตัว ตัวที่อยู่ทางขวาสุดถ้ามี และกลุ่มที่มีสมาชิกเพิ่มเติมเป็นกลุ่มสุดท้ายเสมอ

คุณสามารถเปลี่ยนค่าเติมนี้ได้โดยใช้อาร์กิวเมนต์ที่สอง:

%w(1 2 3 4 5 6 7).in_groups(3, "0")
# => [["1", "2", "3"], ["4", "5", "0"], ["6", "7", "0"]]

และคุณสามารถบอกเมธอดให้ไม่เติมกลุ่มที่เล็กกว่าโดยส่ง false:

%w(1 2 3 4 5 6 7).in_groups(3, false)
# => [["1", "2", "3"], ["4", "5"], ["6", "7"]]

เนื่องจากนั้น false ไม่สามารถใช้เป็นค่าเติมได้

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/array/grouping.rb.

11.7.3 split(value = nil)

เมธอด split แบ่งอาร์เรย์ด้วยตัวคั่นและคืนค่าชิ้นส่วนที่ได้

ถ้าส่งบล็อกไป ตัวคั่นคือสมาชิกของอาร์เรย์ที่บล็อกส่งคืนค่า true:

(-5..5).to_a.split { |i| i.multiple_of?(4) }
# => [[-5], [-3, -2, -1], [1, 2, 3], [5]]

มิฉะนั้น ค่าที่ได้รับเป็นอาร์กิวเมนต์ ซึ่งมีค่าเริ่มต้นเป็น nil, เป็นตัวคั่น:

[0, 1, -5, 1, 1, "foo", "bar"].split(1)
# => [[0], [-5], [], ["foo", "bar"]]

เคล็ดลับ: สังเกตในตัวอย่างก่อนหน้านี้ว่าตัวคั่นต่อเนื่องจะทำให้ได้อาร์เรย์เปล่า

หมายเหตุ: ถูกกำหนดใน active_support/core_ext/array/grouping.rb.

12 ส่วนขยายให้กับ Hash

12.1 การแปลง

12.1.1 to_xml

เมธอด to_xml คืนค่าสตริงที่มีการแสดงผล XML ของวัตถุที่ได้รับ:

{ foo: 1, bar: 2 }.to_xml
# =>
# <?xml version="1.0" encoding="UTF-8"?>
# <hash>
#   <foo type="integer">1</foo>
#   <bar type="integer">2</bar>
# </hash>

เพื่อทำเช่นนั้น วิธีการจะวนลูปผ่านคู่และสร้างโหนดที่ขึ้นอยู่กับ values ที่กำหนด โดยให้คู่ key, value:

  • หาก value เป็นแฮช จะมีการเรียกใช้งานแบบเรียกตัวเองกับ key เป็น :root ในลูปซ้ำ

  • หาก value เป็นอาร์เรย์ จะมีการเรียกใช้งานแบบเรียกตัวเองกับ key เป็น :root และ key ที่ถูกแยกเป็นรูปเดี่ยวเป็น :children ในลูปซ้ำ

  • หาก value เป็นวัตถุที่เรียกใช้งานได้ จะต้องคาดหวังอาร์กิวเมนต์หนึ่งหรือสองตัว ขึ้นอยู่กับความยาวของอาร์กิวเมนต์ วิธีการเรียกใช้งานคือเรียกใช้งานวัตถุที่เรียกใช้งานได้ด้วยแฮช options เป็นอาร์กิวเมนต์แรกด้วย key เป็น :root และ key ที่ถูกแยกเป็นรูปเดี่ยวเป็นอาร์กิวเมนต์ที่สอง ค่าที่ส่งกลับจะกลายเป็นโหนดใหม่

  • หาก value ตอบสนองกับ to_xml วิธีการจะเรียกใช้งานคือเรียกใช้งานวิธีด้วย key เป็น :root

  • มิฉะนั้น จะสร้างโหนดด้วย key เป็นแท็กพร้อมกับการแสดงตัวอย่างของ value เป็นโหนดข้อความ หาก value เป็น nil จะเพิ่มแอตทริบิวต์ "nil" ที่ตั้งค่าเป็น "true" นอกจากนั้น หากตัวเลือก :skip_types มีอยู่และเป็นจริง จะเพิ่มแอตทริบิวต์ "type" ตามการแมปต่อไปนี้:

XML_TYPE_NAMES = {
  "Symbol"     => "symbol",
  "Integer"    => "integer",
  "BigDecimal" => "decimal",
  "Float"      => "float",
  "TrueClass"  => "boolean",
  "FalseClass" => "boolean",
  "Date"       => "date",
  "DateTime"   => "datetime",
  "Time"       => "datetime"
}

โดยค่าเริ่มต้นของโหนดรูทคือ "hash" แต่สามารถกำหนดค่าได้ผ่านตัวเลือก :root

XML builder เริ่มต้นคือตัวอย่างใหม่ของ Builder::XmlMarkup คุณสามารถกำหนดค่า builder เองได้ด้วยตัวเลือก :builder วิธีการยังยอมรับตัวเลือกเช่น :dasherize และเพื่อนๆ ซึ่งจะถูกส่งต่อไปยัง builder

หมายเหตุ: ได้กำหนดไว้ใน active_support/core_ext/hash/conversions.rb

12.2 การผสาน

Ruby มีเมธอด Hash#merge ที่ผสานสองแฮชอย่างมีอยู่แล้ว:

{ a: 1, b: 1 }.merge(a: 0, c: 2)
# => {:a=>0, :b=>1, :c=>2}

Active Support กำหนดวิธีการผสานแฮชเพิ่มเติมที่อาจจะสะดวก

12.2.1 reverse_merge และ reverse_merge!

ในกรณีที่มีการชนกัน คีย์ในแฮชของอาร์กิวเมนต์จะชนะในการผสาน คุณสามารถรองรับแฮชตัวเลือกที่มีค่าเริ่มต้นได้อย่างสะดวกด้วยวิธีนี้:

options = { length: 30, omission: "..." }.merge(options)

Active Support กำหนด reverse_merge ในกรณีที่คุณชอบรูปแบบทางเลือกที่แตกต่างนี้:

options = options.reverse_merge(length: 30, omission: "...")

และเวอร์ชันแบบแบง reverse_merge! ที่ดำเนินการผสานในที่เดียว:

options.reverse_merge!(length: 30, omission: "...")

คำเตือน. โปรดทราบว่า reverse_merge! อาจเปลี่ยนแปลงแฮชในตัวเรียก ซึ่งอาจเป็นได้หรือไม่เป็นได้ตามที่ต้องการ

หมายเหตุ: ได้กำหนดไว้ใน active_support/core_ext/hash/reverse_merge.rb

12.2.2 reverse_update

เมธอด reverse_update เป็นชื่อย่อสำหรับ reverse_merge! ที่อธิบายไว้ข้างต้น

คำเตือน. โปรดทราบว่า reverse_update ไม่มีเครื่องหมายแบง

หมายเหตุ: ได้กำหนดไว้ใน active_support/core_ext/hash/reverse_merge.rb

12.2.3 deep_merge และ deep_merge!

ตามที่คุณเห็นในตัวอย่างก่อนหน้านี้ หากพบคีย์ในทั้งสองแฮช ค่าในแอร์กิวเมนต์จะชนะ

Active Support กำหนด Hash#deep_merge ในการผสานลึก หากพบคีย์ในทั้งสองแฮชและค่าของพวกเขาเป็นแฮชต่อไป ค่าผสานของพวกเขาจะกลายเป็นค่าในแฮชที่ได้:

{ a: { b: 1 } }.deep_merge(a: { c: 2 })
# => {:a=>{:b=>1, :c=>2}}

เมธอด deep_merge! ทำการผสานรวมค่าในแบบลึกในตำแหน่งเดิม

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/hash/deep_merge.rb

12.3 การทำสำเนาแบบลึก

เมธอด Hash#deep_dup ทำการทำสำเนาของตัวเองและคีย์และค่าทั้งหมดภายในโดยใช้เมธอด Object#deep_dup ใน Active Support มันทำงานเหมือน Enumerator#each_with_object โดยส่งเมธอด deep_dup ไปยังคู่แต่ละคู่ภายใน

hash = { a: 1, b: { c: 2, d: [3, 4] } }

dup = hash.deep_dup
dup[:b][:e] = 5
dup[:b][:d] << 5

hash[:b][:e] == nil      # => true
hash[:b][:d] == [3, 4]   # => true

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/object/deep_dup.rb

12.4 การทำงานกับคีย์

12.4.1 except และ except!

เมธอด except คืนค่าเป็นแฮชที่มีคีย์ในรายการอาร์กิวเมนต์ถูกลบออกหากมีอยู่:

{ a: 1, b: 2 }.except(:a) # => {:b=>2}

หากผู้รับตอบสนองกับ convert_key เมธอดจะถูกเรียกใช้กับแต่ละอาร์กิวเมนต์ ซึ่งทำให้ except สามารถทำงานร่วมกับแฮชที่มีการเข้าถึงได้โดยไม่สนใจตัวอักษรตัวพิมพ์ใหญ่หรือเล็ก เช่น:

{ a: 1 }.with_indifferent_access.except(:a)  # => {}
{ a: 1 }.with_indifferent_access.except("a") # => {}

ยังมีรูปแบบแบง except! ที่ลบคีย์ในตำแหน่งเดิม

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/hash/except.rb

12.4.2 stringify_keys และ stringify_keys!

เมธอด stringify_keys คืนค่าเป็นแฮชที่มีรุ่นที่ถูกแปลงเป็นสตริงของคีย์ในแฮชต้นฉบับ โดยส่ง to_s ไปยังคีย์:

{ nil => nil, 1 => 1, a: :a }.stringify_keys
# => {"" => nil, "1" => 1, "a" => :a}

ในกรณีที่มีการชนกันของคีย์ ค่าจะเป็นค่าที่ถูกแทรกล่าสุดในแฮช:

{ "a" => 1, a: 2 }.stringify_keys
# ผลลัพธ์จะเป็น
# => {"a"=>2}

เมธอดนี้อาจมีประโยชน์ตัวอย่างเช่นในการยอมรับตัวเลือกทั้งสัญลักษณ์และสตริงได้อย่างง่ายดาย เช่น ActionView::Helpers::FormHelper กำหนด:

def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
  options = options.stringify_keys
  options["type"] = "checkbox"
  # ...
end

บรรทัดที่สองสามารถเข้าถึงคีย์ "type" ได้อย่างปลอดภัย และให้ผู้ใช้สามารถส่ง :type หรือ "type" ได้

ยังมีรูปแบบแบง stringify_keys! ที่แปลงคีย์เป็นสตริงในตำแหน่งเดิม

นอกจากนี้ยังสามารถใช้ deep_stringify_keys และ deep_stringify_keys! เพื่อแปลงเป็นสตริงทั้งหมดในแฮชที่กำหนดและแฮชที่ซ้อนอยู่ภายใน ตัวอย่างผลลัพธ์คือ:

{ nil => nil, 1 => 1, nested: { a: 3, 5 => 5 } }.deep_stringify_keys
# => {""=>nil, "1"=>1, "nested"=>{"a"=>3, "5"=>5}}

หมายเหตุ: ถูกกำหนดไว้ใน active_support/core_ext/hash/keys.rb

12.4.3 symbolize_keys และ symbolize_keys!

เมธอด symbolize_keys คืนค่าเป็นแฮชที่มีรุ่นที่ถูกแปลงเป็นสัญลักษณ์ของคีย์ในแฮชต้นฉบับ โดยส่ง to_sym ไปยังคีย์:

{ nil => nil, 1 => 1, "a" => "a" }.symbolize_keys
# => {nil=>nil, 1=>1, :a=>"a"}

คำเตือน โปรดทราบในตัวอย่างก่อนหน้านี้มีเพียงคีย์เดียวที่ถูกแปลงเป็นสัญลักษณ์

ในกรณีที่มีการชนกันของคีย์ ค่าจะเป็นค่าที่ถูกแทรกล่าสุดในแฮช:

{ "a" => 1, a: 2 }.symbolize_keys
# => {:a=>2}

เมธอดนี้อาจมีประโยชน์ตัวอย่างเช่นในการยอมรับตัวเลือกทั้งสัญลักษณ์และสตริงได้อย่างง่ายดาย เช่น ActionText::TagHelper กำหนด ```ruby def rich_text_area_tag(name, value = nil, options = {}) options = options.symbolize_keys

options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}" # ... end ```

บรรทัดที่สามสามารถเข้าถึงคีย์ :input ได้อย่างปลอดภัย และอนุญาตให้ผู้ใช้ส่ง :input หรือ "input" เข้ามาได้

ยังมีตัวแปรแบบ bang symbolize_keys! ที่จะแปลงคีย์ให้เป็นสัญลักษณ์ในตำแหน่งเดียวกัน

นอกจากนี้ยังสามารถใช้ deep_symbolize_keys และ deep_symbolize_keys! เพื่อแปลงคีย์ทั้งหมดในแฮชที่กำหนดและแฮชที่ซ้อนอยู่ในนั้นให้เป็นสัญลักษณ์ ตัวอย่างของผลลัพธ์คือ:

{ nil => nil, 1 => 1, "nested" => { "a" => 3, 5 => 5 } }.deep_symbolize_keys
# => {nil=>nil, 1=>1, nested:{a:3, 5=>5}}

หมายเหตุ: นิยามใน active_support/core_ext/hash/keys.rb

12.4.4 to_options และ to_options!

เมธอด to_options และ to_options! เป็นตัวย่อของ symbolize_keys และ symbolize_keys! ตามลำดับ

หมายเหตุ: นิยามใน active_support/core_ext/hash/keys.rb

12.4.5 assert_valid_keys

เมธอด assert_valid_keys รับอาร์กิวเมนต์จำนวนไม่จำกัด และตรวจสอบว่าแฮชที่รับมีคีย์นอกเหนือจากนั้นหรือไม่ ถ้ามีจะเกิด ArgumentError

{ a: 1 }.assert_valid_keys(:a)  # ผ่าน
{ a: 1 }.assert_valid_keys("a") # ArgumentError

Active Record ไม่ยอมรับตัวเลือกที่ไม่รู้จักเมื่อสร้างความสัมพันธ์ เช่น มันนำมาใช้ควบคู่กับ assert_valid_keys เพื่อควบคุม

หมายเหตุ: นิยามใน active_support/core_ext/hash/keys.rb

12.5 การทำงานกับค่า

12.5.1 deep_transform_values และ deep_transform_values!

เมธอด deep_transform_values จะคืนแฮชใหม่ที่มีค่าทั้งหมดถูกแปลงด้วยการดำเนินการบล็อก รวมถึงค่าจากแฮชรูทและแฮชซ้อนอยู่ภายใน

hash = { person: { name: 'Rob', age: '28' } }

hash.deep_transform_values { |value| value.to_s.upcase }
# => {person: {name: "ROB", age: "28"}}

ยังมีตัวแปรแบบ bang deep_transform_values! ที่แปลงค่าทั้งหมดโดยทำการใช้งานบล็อก

หมายเหตุ: นิยามใน active_support/core_ext/hash/deep_transform_values.rb

12.6 การแบ่ง

เมธอด slice! จะแทนที่แฮชด้วยเฉพาะคีย์ที่กำหนดและคืนแฮชที่มีคีย์/ค่าที่ถูกลบ

hash = { a: 1, b: 2 }
rest = hash.slice!(:a) # => {:b=>2}
hash                   # => {:a=>1}

หมายเหตุ: นิยามใน active_support/core_ext/hash/slice.rb

12.7 การแยก

เมธอด extract! จะลบและคืนคีย์/ค่าที่ตรงกับคีย์ที่กำหนด

hash = { a: 1, b: 2 }
rest = hash.extract!(:a) # => {:a=>1}
hash                     # => {:b=>2}

เมธอด extract! จะคืนคลาสแฮชเดียวกับแฮชต้นฉบับ

hash = { a: 1, b: 2 }.with_indifferent_access
rest = hash.extract!(:a).class
# => ActiveSupport::HashWithIndifferentAccess

หมายเหตุ: นิยามใน active_support/core_ext/hash/slice.rb

12.8 การเข้าถึงโดยไม่สนใจตัวอักษรตัวพิมพ์ใหญ่หรือเล็ก

เมธอด with_indifferent_access จะคืน ActiveSupport::HashWithIndifferentAccess จากแฮชต้นฉบับ:

{ a: 1 }.with_indifferent_access["a"] # => 1

หมายเหตุ: นิยามใน active_support/core_ext/hash/indifferent_access.rb

13 ส่วนขยายให้กับ Regexp

13.1 multiline?

เมธอด multiline? บอกว่ารูปแบบเรกเอ็กซ์มีตัวสองเส้น /m ที่ตั้งไว้หรือไม่ กล่าวคือ ว่าจุดจับตรงกับบรรทัดใหม่หรือไม่

%r{.}.multiline?  # => false
%r{.}m.multiline? # => true

Regexp.new('.').multiline?                    # => false
Regexp.new('.', Regexp::MULTILINE).multiline? # => true

Rails ใช้เมธอดนี้ในที่เดียวเท่านั้น ในรหัสการเชื่อมต่อเส้นทาง รูปแบบเรกเอ็กซ์ที่มีหลายบรรทัดถูกห้ามสำหรับความต้องการของเส้นทางและตรงนี้จะทำให้การบังคับข้อจำกัดนั้นง่ายขึ้น

def verify_regexp_requirements(requirements)
  # ...
  if requirement.multiline?
    raise ArgumentError, "Regexp multiline option is not allowed in routing requirements: #{requirement.inspect}"
  end
  # ...
end

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/regexp.rb

14 ส่วนขยายให้กับ Range

14.1 to_fs

Active Support กำหนด Range#to_fs เป็นตัวเลือกทางเลือกสำหรับ to_s ที่เข้าใจอารมณ์ทางเลือกได้ โดยในขณะที่เขียนข้อความนี้รูปแบบที่รองรับที่ไม่ใช่ค่าเริ่มต้นเดียวคือ :db:

(Date.today..Date.tomorrow).to_fs
# => "2009-10-25..2009-10-26"

(Date.today..Date.tomorrow).to_fs(:db)
# => "BETWEEN '2009-10-25' AND '2009-10-26'"

เช่นที่แสดงในตัวอย่าง รูปแบบ :db สร้างคำสั่ง SQL BETWEEN ซึ่งใช้โดย Active Record เพื่อรองรับค่าช่วงในเงื่อนไข

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/range/conversions.rb

14.2 === และ include?

เมธอด Range#=== และ Range#include? บอกว่าค่าใดค่าหนึ่งอยู่ระหว่างสิ้นสุดของอินสแตนซ์ที่กำหนด:

(2..3).include?(Math::E) # => true

Active Support ขยายเมธอดเหล่านี้เพื่อให้สามารถใช้อาร์กิวเมนต์เป็นช่วงอื่นได้อีกด้วย ในกรณีนั้นเราจะทดสอบว่าสิ้นสุดของช่วงอาร์กิวเมนต์เป็นส่วนของตัวรับเองหรือไม่:

(1..10) === (3..7)  # => true
(1..10) === (0..7)  # => false
(1..10) === (3..11) # => false
(1...9) === (3..9)  # => false

(1..10).include?(3..7)  # => true
(1..10).include?(0..7)  # => false
(1..10).include?(3..11) # => false
(1...9).include?(3..9)  # => false

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/range/compare_range.rb

14.3 overlap?

เมธอด Range#overlap? บอกว่าช่วงสองช่วงที่กำหนดมีการตัดกันที่ไม่เป็นค่าว่าง:

(1..10).overlap?(7..11)  # => true
(1..10).overlap?(0..7)   # => true
(1..10).overlap?(11..27) # => false

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/range/overlap.rb

15 ส่วนขยายให้กับ Date

15.1 การคำนวณ

ข้อมูล: เมธอดการคำนวณต่อไปนี้มีกรณีพิเศษในเดือนตุลาคม ค.ศ. 1582 เนื่องจากวันที่ 5-14 ไม่มีอยู่จริง คู่มือนี้ไม่ได้ระบุพฤติกรรมของพวกเขารอบวันเหล่านั้นเพื่อความกระชับ แต่สามารถบอกได้ว่าพวกเขาทำตามที่คุณคาดหวัง กล่าวคือ Date.new(1582, 10, 4).tomorrow จะคืนค่า Date.new(1582, 10, 15) และอื่น ๆ โปรดตรวจสอบ test/core_ext/date_ext_test.rb ในชุดทดสอบ Active Support เพื่อดูพฤติกรรมที่คาดหวัง

15.1.1 Date.current

Active Support กำหนด Date.current ให้เป็นวันนี้ในเขตเวลาปัจจุบัน คล้ายกับ Date.today แต่มันยอมรับเขตเวลาของผู้ใช้ถ้าถูกกำหนดไว้ นอกจากนี้ยังกำหนด Date.yesterday และ Date.tomorrow และตัวบ่งชี้ของอินสแตนซ์ past?, today?, tomorrow?, next_day?, yesterday?, prev_day?, future?, on_weekday? และ on_weekend? ทั้งหมดเกี่ยวข้องกับ Date.current

เมื่อทำการเปรียบเทียบวันที่โดยใช้เมธอดที่ยอมรับเขตเวลาของผู้ใช้ โปรดใช้ Date.current และไม่ใช้ Date.today มีกรณีที่เขตเวลาของผู้ใช้อาจอยู่ในอนาคตเมื่อเปรียบเทียบกับเขตเวลาของระบบ ซึ่ง Date.today ใช้ค่าเริ่มต้น นั่นหมายความว่า Date.today อาจเท่ากับ Date.yesterday

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/date/calculations.rb

15.1.2 ชื่อวันที่

15.1.2.1 beginning_of_week, end_of_week

เมธอด beginning_of_week และ end_of_week คืนค่าวันที่สำหรับเริ่มต้นและสิ้นสุดของสัปดาห์ตามลำดับ สัปดาห์ถือว่าเริ่มต้นในวันจันทร์ แต่สามารถเปลี่ยนได้โดยส่งอาร์กิวเมนต์ ตั้งค่า Date.beginning_of_week ที่เก็บในเธรดหรือ config.beginning_of_week

d = Date.new(2010, 5, 8)     # => Sat, 08 May 2010
d.beginning_of_week          # => Mon, 03 May 2010
d.beginning_of_week(:sunday) # => Sun, 02 May 2010
d.end_of_week                # => Sun, 09 May 2010
d.end_of_week(:sunday)       # => Sat, 08 May 2010

beginning_of_week เป็นนามแฝงของ at_beginning_of_week และ end_of_week เป็นนามแฝงของ at_end_of_week

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/date_and_time/calculations.rb

15.1.2.2 monday, sunday

เมธอด monday และ sunday คืนค่าวันที่จันทร์ก่อนหน้าและวันอาทิตย์ถัดไปตามลำดับ ruby date = Date.new(2010, 6, 7) date.months_ago(3) # => Mon, 07 Mar 2010 date.months_since(3) # => Thu, 07 Sep 2010

If such a day does not exist, the last day of the corresponding month is returned:

Date.new(2012, 3, 31).months_ago(1)     # => Thu, 29 Feb 2012
Date.new(2012, 1, 31).months_since(1)   # => Thu, 29 Feb 2012

last_month is short-hand for #months_ago(1).

15.1.2.3 weeks_ago, weeks_since

The methods weeks_ago and [weeks_since][DateAndTime::Calculations#weeks_since] work analogously for weeks:

date = Date.new(2010, 6, 7)
date.weeks_ago(2)   # => Mon, 24 May 2010
date.weeks_since(2) # => Mon, 21 Jun 2010

If such a day does not exist, the last day of the corresponding month is returned:

Date.new(2012, 3, 31).weeks_ago(4)     # => Sat, 03 Mar 2012
Date.new(2012, 1, 31).weeks_since(4)   # => Sat, 03 Mar 2012

last_week is short-hand for #weeks_ago(1).

15.1.2.4 days_ago, days_since

The methods [days_ago][DateAndTime::Calculations#days_ago] and [days_since][DateAndTime::Calculations#days_since] work analogously for days:

date = Date.new(2010, 6, 7)
date.days_ago(5)   # => Wed, 02 Jun 2010
date.days_since(5) # => Sat, 12 Jun 2010

[yesterday][DateAndTime::Calculations#yesterday] is short-hand for #days_ago(1), and [tomorrow][DateAndTime::Calculations#tomorrow] is short-hand for #days_since(1).

The method end_of_minute returns a timestamp at the end of the minute (hh:mm:59):

date = DateTime.new(2010, 6, 7, 19, 55, 25)
date.end_of_minute # => Mon Jun 07 19:55:59 +0200 2010

beginning_of_minute is aliased to at_beginning_of_minute.

เมธอด end_of_minute จะคืนค่า timestamp ที่สิ้นสุดของนาที (hh:mm:59):

date = DateTime.new(2010, 6, 7, 19, 55, 25)
date.end_of_minute # => จันทร์ 7 มิถุนายน 19:55:59 +0200 2010

beginning_of_minute มีการตั้งชื่อให้เป็น at_beginning_of_minute.

ข้อมูล: beginning_of_hour, end_of_hour, beginning_of_minute, และ end_of_minute ถูกนำมาใช้สำหรับ Time และ DateTime แต่ไม่สำหรับ Date เนื่องจากไม่มีความหมายที่จะขอข้อมูลเริ่มต้นหรือสิ้นสุดของชั่วโมงหรือนาทีใน Date instance

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date_time/calculations.rb.

15.1.2.5 ago, since

เมธอด ago รับอาร์กิวเมนต์เป็นจำนวนวินาทีและคืนค่า timestamp กี่วินาทีก่อนเที่ยงคืน:

date = Date.current # => วันศุกร์ 11 มิถุนายน 2010
date.ago(1)         # => วันพฤหัสบดี 10 มิถุนายน 2010 23:59:59 EDT -04:00

อย่างเดียวกัน since จะเลื่อนไปข้างหน้า:

date = Date.current # => วันศุกร์ 11 มิถุนายน 2010
date.since(1)       # => วันศุกร์ 11 มิถุนายน 2010 00:00:01 EDT -04:00

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date/calculations.rb.

16 ส่วนขยายให้กับ DateTime

คำเตือน: DateTime ไม่รู้จักกฎ DST ดังนั้นเมธอดบางส่วนอาจมีกรณีพิเศษเมื่อมีการเปลี่ยน DST ตัวอย่างเช่น seconds_since_midnight อาจไม่คืนค่าจริงในวันที่มีการเปลี่ยน DST

16.1 การคำนวณ

คลาส DateTime เป็นคลาสลูกของ Date ดังนั้นโดยการโหลด active_support/core_ext/date/calculations.rb คุณจะสืบทอดเมธอดเหล่านี้และนามแฝงของพวกเขา แต่จะคืนค่าเป็น datetimes เสมอ

เมธอดต่อไปนี้ถูกนำมาสร้างใหม่เพื่อให้คุณไม่จำเป็นต้องโหลด active_support/core_ext/date/calculations.rb สำหรับเหล่านี้:

อย่างไรก็ตาม advance และ change ก็ถูกนิยามและรองรับตัวเลือกเพิ่มเติม และได้รับการเอกสารด้านล่าง

เมธอดต่อไปนี้มีการนำมาใช้เฉพาะใน active_support/core_ext/date_time/calculations.rb เนื่องจากมีความหมายเฉพาะเมื่อใช้กับ DateTime instance เท่านั้น:

16.1.1 วันที่ที่ตั้งชื่อ

16.1.1.1 DateTime.current

Active Support กำหนด DateTime.current ให้เป็นเหมือน Time.now.to_datetime แต่จะใช้ time zone ของผู้ใช้งานถ้าได้กำหนดไว้ ตัวตรวจสอบของ instance past? และ future? ถูกกำหนดให้เป็นสัมพันธ์กับ DateTime.current

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date_time/calculations.rb.

16.1.2 ส่วนขยายอื่น ๆ

16.1.2.1 seconds_since_midnight

เมธอด seconds_since_midnight คืนค่าจำนวนวินาทีตั้งแต่เที่ยงคืน:

now = DateTime.current     # => จันทร์ 7 มิถุนายน 2010 20:26:36 +0000
now.seconds_since_midnight # => 73596

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date_time/calculations.rb.

16.1.2.2 utc

เมธอด utc จะให้คุณได้ datetime เดียวกันใน receiver ที่แสดงออกเป็น UTC

now = DateTime.current # => จันทร์ 7 มิถุนายน 2010 19:27:52 -0400
now.utc                # => จันทร์ 7 มิถุนายน 2010 23:27:52 +0000

เมธอดนี้ยังมีการตั้งชื่อให้เป็น getutc.

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date_time/calculations.rb.

16.1.2.3 utc?

ตัวตรวจสอบ utc? บอกว่า receiver มีเขตเวลาเป็น UTC หรือไม่:

now = DateTime.now # => จันทร์ 7 มิถุนายน 2010 19:30:47 -0400
now.utc?           # => เท็จ
now.utc.utc?       # => จริง

หมายเหตุ: ถูกนิยามใน active_support/core_ext/date_time/calculations.rb.

16.1.2.4 advance

วิธีที่สามารถกระโดดไปยัง datetime อื่น ๆ ได้ที่สุด advance เมธอดนี้รับ hash ที่มีคีย์ :years, :months, :weeks, :days, :hours, :minutes, และ :seconds และคืนค่า datetime ที่ได้รับการเลื่อนไปตามคีย์ที่ระบุในปัจจุบัน ```ruby d = DateTime.current

=> พฤหัสบดี, 05 สิงหาคม 2010 11:33:31 +0000

d.advance(years: 1, months: 1, days: 1, hours: 1, minutes: 1, seconds: 1)

=> อังคาร, 06 กันยายน 2011 12:34:32 +0000


เมธอดนี้จะคำนวณวันที่ปลายทางโดยส่ง `:years`, `:months`, `:weeks`, และ `:days` ไปยัง `Date#advance` ที่ได้ระบุไว้ข้างต้น หลังจากนั้น จะปรับเวลาโดยเรียกใช้ [`since`][DateTime#since] ด้วยจำนวนวินาทีที่ต้องการเลื่อนขึ้น การเรียงลำดับนี้มีความสำคัญ การเรียงลำดับที่แตกต่างกันอาจทำให้ได้วันที่และเวลาที่แตกต่างกันในบางกรณีที่เป็นกรณีพิเศษ ตัวอย่างใน `Date#advance` ยังใช้ได้ และเราสามารถขยายไปเพื่อแสดงความสำคัญของการเรียงลำดับที่เกี่ยวข้องกับชิ้นส่วนเวลา

หากเราย้ายชิ้นส่วนวันที่ (ซึ่งยังมีการเรียงลำดับที่สัมพันธ์กันอีกด้วยตามที่ได้ระบุไว้ข้างต้น) แล้วค่อยย้ายชิ้นส่วนเวลา เราจะได้ผลลัพธ์ดังต่อไปนี้:

```ruby
d = DateTime.new(2010, 2, 28, 23, 59, 59)
# => อาทิตย์, 28 กุมภาพันธ์ 2010 23:59:59 +0000
d.advance(months: 1, seconds: 1)
# => จันทร์, 29 มีนาคม 2010 00:00:00 +0000

แต่หากเราคำนวณในทิศทางตรงกันข้าม ผลลัพธ์จะแตกต่าง:

d.advance(seconds: 1).advance(months: 1)
# => พฤหัสบดี, 01 เมษายน 2010 00:00:00 +0000

คำเตือน: เนื่องจาก DateTime ไม่รองรับการจัดเก็บข้อมูลเกี่ยวกับการปรับเวลาตามฤดูกาล คุณอาจได้เวลาที่ไม่มีอยู่จริงโดยไม่มีการเตือนหรือข้อผิดพลาดที่บอกให้คุณทราบ

หมายเหตุ: ได้กำหนดไว้ใน active_support/core_ext/date_time/calculations.rb

16.1.3 เปลี่ยนแปลงส่วนประกอบ

เมธอด change ช่วยให้คุณได้วันที่และเวลาใหม่ที่เหมือนกับวัตถุรับข้อมูลยกเว้นส่วนประกอบที่กำหนด ซึ่งอาจรวมถึง :year, :month, :day, :hour, :min, :sec, :offset, :start:

now = DateTime.current
# => อังคาร, 08 มิถุนายน 2010 01:56:22 +0000
now.change(year: 2011, offset: Rational(-6, 24))
# => พุธ, 08 มิถุนายน 2011 01:56:22 -0600

หากชั่วโมงถูกตั้งเป็นศูนย์ นาทีและวินาทีก็จะเป็นศูนย์ด้วย (ยกเว้นถ้ามีค่าที่กำหนด):

now.change(hour: 0)
# => อังคาร, 08 มิถุนายน 2010 00:00:00 +0000

ในทางเดียวกัน หากนาทีถูกตั้งเป็นศูนย์ วินาทีก็จะเป็นศูนย์ด้วย (ยกเว้นถ้ามีค่าที่กำหนด):

now.change(min: 0)
# => อังคาร, 08 มิถุนายน 2010 01:00:00 +0000

เมธอดนี้ไม่ยอมรับวันที่ที่ไม่มีอยู่ หากการเปลี่ยนแปลงไม่ถูกต้อง จะเกิดข้อผิดพลาด ArgumentError:

DateTime.current.change(month: 2, day: 30)
# => ArgumentError: invalid date

หมายเหตุ: ได้กำหนดไว้ใน active_support/core_ext/date_time/calculations.rb

16.1.4 ระยะเวลา

วัตถุ Duration สามารถเพิ่มหรือลดจากวันที่และเวลาได้:

now = DateTime.current
# => จันทร์, 09 สิงหาคม 2010 23:15:17 +0000
now + 1.year
# => อังคาร, 09 สิงหาคม 2011 23:15:17 +0000
now - 1.week
# => จันทร์, 02 สิงหาคม 2010 23:15:17 +0000

การเพิ่มหรือลดจะแปลงเป็นการเรียกใช้ since หรือ advance ตัวอย่างเช่นที่นี่เราได้รับการเลื่อนที่ถูกต้องในการปฏิทิน:

DateTime.new(1582, 10, 4, 23) + 1.hour
# => ศุกร์, 15 ตุลาคม 1582 00:00:00 +0000

17 ส่วนขยายใน Time

17.1 การคำนวณ

มันคล้ายกัน โปรดอ้างอิงคู่มือของพวกเขาด้านบนและพิจารณาความแตกต่างต่อไปนี้:

  • change ยอมรับตัวเลือกเพิ่มเติม :usec อีกตัวหนึ่ง
  • Time เข้าใจ DST ดังนั้นคุณจะได้การคำนวณ DST ที่ถูกต้องเช่นเดียวกับ
Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>

# ในบาร์เซโลนา เวลา 2010/03/28 02:00 +0100 กลายเป็น 2010/03/28 03:00 +0200 เนื่องจาก DST
t = Time.local(2010, 3, 28, 1, 59, 59)
# => อาทิตย์ มีนาคม 28 01:59:59 +0100 2010
t.advance(seconds: 1)
# => อาทิตย์ มีนาคม 28 03:00:00 +0200 2010
  • หาก since หรือ ago กระโดดไปยังเวลาที่ไม่สามารถแสดงได้ด้วย Time จะส่งกลับเป็นอ็อบเจกต์ DateTime แทน

17.1.1 Time.current

Active Support กำหนด Time.current ให้เป็นวันนี้ในโซนเวลาปัจจุบัน คล้ายกับ Time.now แต่มันจะให้ความสำคัญกับโซนเวลาของผู้ใช้ หากได้กำหนดไว้ มันยังกำหนดตัวพิสัย past?, today?, tomorrow?, next_day?, yesterday?, prev_day? และ future? ทั้งหมดเทียบกับ Time.current

เมื่อทำการเปรียบเทียบเวลาโดยใช้เมธอดที่ให้ความสำคัญกับโซนเวลาของผู้ใช้ ตรวจสอบให้แน่ใจว่าใช้ Time.current แทน Time.now มีกรณีที่โซนเวลาของผู้ใช้อาจอยู่ในอนาคตเมื่อเทียบกับโซนเวลาของระบบซึ่ง Time.now ใช้โดยค่าเริ่มต้น นี่หมายความว่า Time.now.to_date อาจเท่ากับ Date.yesterday

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/time/calculations.rb

17.1.2 all_day, all_week, all_month, all_quarter, และ all_year

เมธอด all_day จะส่งกลับช่วงเวลาที่แทนวันทั้งหมดของเวลาปัจจุบัน

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_day
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Mon, 09 Aug 2010 23:59:59 UTC +00:00

ในทางเดียวกัน all_week, all_month, all_quarter และ all_year ใช้สำหรับสร้างช่วงเวลา

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_week
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Sun, 15 Aug 2010 23:59:59 UTC +00:00
now.all_week(:sunday)
# => Sun, 16 Sep 2012 00:00:00 UTC +00:00..Sat, 22 Sep 2012 23:59:59 UTC +00:00
now.all_month
# => Sat, 01 Aug 2010 00:00:00 UTC +00:00..Tue, 31 Aug 2010 23:59:59 UTC +00:00
now.all_quarter
# => Thu, 01 Jul 2010 00:00:00 UTC +00:00..Thu, 30 Sep 2010 23:59:59 UTC +00:00
now.all_year
# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/date_and_time/calculations.rb

17.1.3 prev_day, next_day

prev_day และ next_day จะส่งกลับเวลาในวันก่อนหน้าหรือวันถัดไป:

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_day               # => 2010-05-07 00:00:00 +0900
t.next_day               # => 2010-05-09 00:00:00 +0900

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/time/calculations.rb

17.1.4 prev_month, next_month

prev_month และ next_month จะส่งกลับเวลาในเดือนก่อนหน้าหรือเดือนถัดไปที่มีวันเดียวกัน:

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_month             # => 2010-04-08 00:00:00 +0900
t.next_month             # => 2010-06-08 00:00:00 +0900

หากวันดังกล่าวไม่มีอยู่ จะส่งกลับวันสุดท้ายของเดือนที่เกี่ยวข้อง:

Time.new(2000, 5, 31).prev_month # => 2000-04-30 00:00:00 +0900
Time.new(2000, 3, 31).prev_month # => 2000-02-29 00:00:00 +0900
Time.new(2000, 5, 31).next_month # => 2000-06-30 00:00:00 +0900
Time.new(2000, 1, 31).next_month # => 2000-02-29 00:00:00 +0900

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/time/calculations.rb

17.1.5 prev_year, next_year

prev_year และ next_year จะส่งกลับเวลาในปีก่อนหน้าหรือปีถัดไปที่มีวัน/เดือนเดียวกัน:

t = Time.new(2010, 5, 8) # => 2010-05-08 00:00:00 +0900
t.prev_year              # => 2009-05-08 00:00:00 +0900
t.next_year              # => 2011-05-08 00:00:00 +0900

หากวันที่เป็นวันที่ 29 กุมภาพันธ์ของปีอธิปไตย จะได้วันที่ 28:

t = Time.new(2000, 2, 29) # => 2000-02-29 00:00:00 +0900
t.prev_year               # => 1999-02-28 00:00:00 +0900
t.next_year               # => 2001-02-28 00:00:00 +0900

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/time/calculations.rb

17.1.6 prev_quarter, next_quarter

prev_quarter และ next_quarter จะคืนค่าวันที่เดียวกันในไตรมาสก่อนหน้าหรือไตรมาสถัดไป:

t = Time.local(2010, 5, 8) # => 2010-05-08 00:00:00 +0300
t.prev_quarter             # => 2010-02-08 00:00:00 +0200
t.next_quarter             # => 2010-08-08 00:00:00 +0300

หากไม่มีวันดังกล่าวอยู่ จะคืนค่าวันสุดท้ายของเดือนที่เกี่ยวข้อง:

Time.local(2000, 7, 31).prev_quarter  # => 2000-04-30 00:00:00 +0300
Time.local(2000, 5, 31).prev_quarter  # => 2000-02-29 00:00:00 +0200
Time.local(2000, 10, 31).prev_quarter # => 2000-07-31 00:00:00 +0300
Time.local(2000, 11, 31).next_quarter # => 2001-03-01 00:00:00 +0200

prev_quarter มีชื่อย่อเป็น last_quarter.

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/date_and_time/calculations.rb.

17.2 ตัวสร้างเวลา

Active Support กำหนด Time.current ให้เป็น Time.zone.now หากมีการกำหนดโซนเวลาของผู้ใช้ มีการย้อนกลับไปที่ Time.now หากไม่มี:

Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
Time.current
# => Fri, 06 Aug 2010 17:11:58 CEST +02:00

เหมือนกับ DateTime, ตัวบ่งชี้ past? และ future? เป็นสัมพันธ์กับ Time.current.

หากเวลาที่จะสร้างอยู่นอกขอบเขตที่รองรับโดย Time ในแพลตฟอร์มการทำงาน จะละทิ้งไมโครวินาทีและคืนค่าออบเจ็กต์ DateTime แทน.

17.2.1 ระยะเวลา

ออบเจ็กต์ Duration สามารถเพิ่มหรือลบจากออบเจ็กต์เวลาได้:

now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now + 1.year
# => Tue, 09 Aug 2011 23:21:11 UTC +00:00
now - 1.week
# => Mon, 02 Aug 2010 23:21:11 UTC +00:00

การแปลงเป็นการเรียกใช้ since หรือ advance ตัวอย่างเช่นที่นี่เราได้รับการกระโดดที่ถูกต้องในการปฏิทิน:

Time.utc(1582, 10, 3) + 5.days
# => Mon Oct 18 00:00:00 UTC 1582

18 ส่วนขยายให้กับ File

18.1 atomic_write

ด้วยเมธอดคลาส File.atomic_write คุณสามารถเขียนไปยังไฟล์ในวิธีที่จะป้องกันผู้อ่านใดๆ จากการเห็นเนื้อหาที่เขียนครึ่งหนึ่ง

ชื่อของไฟล์ถูกส่งผ่านเป็นอาร์กิวเมนต์ และเมธอดจะเรียกใช้ไฟล์แฮนเดิลที่เปิดเพื่อเขียน หลังจากที่บล็อกเสร็จสิ้น atomic_write จะปิดไฟล์แฮนเดิลและทำงานเสร็จ

ตัวอย่างเช่น Action Pack ใช้เมธอดนี้ในการเขียนไฟล์แคชสินทรัพย์เช่น all.css:

File.atomic_write(joined_asset_path) do |cache|
  cache.write(join_asset_file_contents(asset_paths))
end

เพื่อทำให้สำเร็จ atomic_write สร้างไฟล์ชั่วคราว นั่นคือไฟล์ที่โค้ดในบล็อกจริงๆ เขียนไป หลังจากเสร็จสิ้น ไฟล์ชั่วคราวจะถูกเปลี่ยนชื่อ ซึ่งเป็นการดำเนินการแอตอมิกบนระบบ POSIX หากไฟล์เป้าหมายมีอยู่ atomic_write จะเขียนทับและเก็บเจ้าของและสิทธิ์ อย่างไรก็ตามมีกรณีบางกรณีที่ atomic_write ไม่สามารถเปลี่ยนเจ้าของหรือสิทธิ์ของไฟล์ได้ ข้อผิดพลาดนี้ถูกจับและข้ามไปเชื่อมใจในผู้ใช้/ระบบไฟล์เพื่อให้ไฟล์สามารถเข้าถึงได้โดยกระบวนการที่ต้องการ

หมายเหตุ. เนื่องจากการดำเนินการ chmod atomic_write ทำ หากไฟล์เป้าหมายมี ACL ที่ตั้งค่าไว้ ACL นี้จะถูกคำนวณ/แก้ไขใหม่

คำเตือน. โปรดทราบว่าคุณไม่สามารถเพิ่มเข้าไปด้วย atomic_write ได้

19 ไฟล์ช่วยเพิ่มให้กับ NameError

Active Support เพิ่ม missing_name? ใน NameError เพื่อทดสอบว่าข้อยกเว้นถูกเกิดขึ้นเพราะชื่อที่ถูกส่งเป็นอาร์กิวเมนต์

ชื่ออาจถูกกำหนดให้เป็นสัญลักษณ์หรือสตริง สัญลักษณ์จะถูกทดสอบกับชื่อค่าคงที่เปล่าเปลี่ยน สตริงจะถูกทดสอบกับชื่อค่าคงที่ที่เต็มรูปแบบ

เคล็ดลับ: สัญลักษณ์สามารถแทนชื่อค่าคงที่ที่เต็มรูปแบบได้เช่น :"ActiveRecord::Base" ดังนั้นพฤติกรรมสำหรับสัญลักษณ์ถูกกำหนดเพื่อความสะดวก ไม่ใช่เพราะว่าจำเป็นตามเทคนิค

ตัวอย่างเช่น เมื่อเรียกใช้การกระทำของ ArticlesController Rails พยายามที่จะใช้ ArticlesHelper ในทางทฤษฎี ไม่มีปัญหาที่โมดูลช่วยเหลือไม่มีอยู่ ดังนั้นหากมีข้อยกเว้นสำหรับชื่อค่าคงที่นั้นถูกเกิดขึ้น ควรปิดเสียง แต่อาจเป็นได้ว่า articles_helper.rb กำลังเกิดข้อผิดพลาด NameError เนื่องจากค่าคงที่ที่ไม่รู้จักจริง ในกรณีนั้นควรเกิดขึ้นอีกครั้ง วิธี missing_name? ให้วิธีที่จะแยกแยะทั้งสองกรณี:

def default_helper_module!
  module_name = name.delete_suffix("Controller")
  module_path = module_name.underscore
  helper module_path
rescue LoadError => e
  raise e unless e.is_missing? "helpers/#{module_path}_helper"
rescue NameError => e
  raise e unless e.missing_name? "#{module_name}Helper"
end

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/name_error.rb

20 ส่วนขยายให้กับ LoadError

Active Support เพิ่ม is_missing? ใน LoadError

โดยกำหนดให้ is_missing? ทดสอบว่าข้อยกเว้นถูกเกิดขึ้นเนื่องจากไฟล์ที่เฉพาะเจาะจงนั้น (ยกเว้นบางครั้งสำหรับส่วนขยาย ".rb")

ตัวอย่างเช่น เมื่อเรียกใช้การกระทำของ ArticlesController Rails พยายามโหลด articles_helper.rb แต่ไฟล์นั้นอาจไม่มีอยู่ นั่นไม่เป็นไร โมดูลช่วยเหลือไม่บังคับให้ Rails ปิดเสียงข้อผิดพลาดในการโหลด แต่อาจเป็นได้ว่าโมดูลช่วยเหลือนั้นมีอยู่และต้องการไลบรารีอื่นที่หายไป ในกรณีนั้น Rails ต้องเกิดข้อผิดพลาดอีกครั้ง วิธี is_missing? ให้วิธีที่จะแยกแยะทั้งสองกรณี:

def default_helper_module!
  module_name = name.delete_suffix("Controller")
  module_path = module_name.underscore
  helper module_path
rescue LoadError => e
  raise e unless e.is_missing? "helpers/#{module_path}_helper"
rescue NameError => e
  raise e unless e.missing_name? "#{module_name}Helper"
end

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/load_error.rb

21 ส่วนขยายให้กับ Pathname

21.1 existence

เมธอด existence จะส่งคืนตัวรับถ้ามีไฟล์ที่ระบุอยู่ มิฉะนั้นจะส่งคืน nil เป็นประโยชน์สำหรับไอดีอิโดมเช่นนี้:

content = Pathname.new("file").existence&.read

หมายเหตุ: กำหนดไว้ใน active_support/core_ext/pathname/existence.rb

ข้อเสนอแนะ

คุณสามารถช่วยปรับปรุงคุณภาพของคู่มือนี้ได้

กรุณาช่วยเพิ่มเติมหากพบข้อผิดพลาดหรือข้อผิดพลาดทางความจริง เพื่อเริ่มต้นคุณสามารถอ่านส่วน การสนับสนุนเอกสาร ของเราได้

คุณอาจพบเนื้อหาที่ไม่สมบูรณ์หรือเนื้อหาที่ไม่ได้อัปเดต กรุณาเพิ่มเอกสารที่ขาดหายไปสำหรับเนื้อหาหลัก โปรดตรวจสอบ Edge Guides ก่อนเพื่อตรวจสอบ ว่าปัญหาได้รับการแก้ไขหรือไม่ในสาขาหลัก ตรวจสอบ คู่มือแนวทาง Ruby on Rails เพื่อดูรูปแบบและกฎเกณฑ์

หากคุณพบข้อผิดพลาดแต่ไม่สามารถแก้ไขได้เอง กรุณา เปิดปัญหา.

และสุดท้าย การสนทนาใด ๆ เกี่ยวกับ Ruby on Rails เอกสารยินดีต้อนรับที่สุดใน เว็บบอร์ดอย่างเป็นทางการของ Ruby on Rails.