it-swarm-vi.tech

Các tính năng ẩn của Ruby

Tiếp tục meme "Các tính năng ẩn của ...", hãy chia sẻ các tính năng ít được biết đến nhưng hữu ích của Ruby ngôn ngữ lập trình.

Cố gắng hạn chế cuộc thảo luận này với Ruby cốt lõi, không có bất kỳ Ruby trên Rails thứ.

Xem thêm:

(Xin vui lòng, chỉ một tính năng cho mỗi câu trả lời.)

Cảm ơn bạn

160
squadette

Từ Ruby 1.9 Proc # === là bí danh của cuộc gọi Proc #, có nghĩa là các đối tượng Proc có thể được sử dụng trong các câu lệnh tình huống như vậy:

def multiple_of(factor)
  Proc.new{|product| product.modulo(factor).zero?}
end

case number
  when multiple_of(3)
    puts "Multiple of 3"
  when multiple_of(7)
    puts "Multiple of 7"
end
80
Farrel

Peter Cooper có danh sách tốt of Ruby. Có lẽ sở thích của tôi là cho phép cả hai mục và bộ sưu tập được liệt kê. (Nghĩa là đối xử với một người không- đối tượng bộ sưu tập như một bộ sưu tập chỉ chứa đối tượng đó.) Nó trông như thế này:

[*items].each do |item|
  # ...
end
76
James A. Rosen

Không biết nó ẩn như thế nào, nhưng tôi thấy nó hữu ích khi cần tạo Hash từ mảng một chiều:

fruit = ["Apple","red","banana","yellow"]
=> ["Apple", "red", "banana", "yellow"]

Hash[*fruit]    
=> {"Apple"=>"red", "banana"=>"yellow"}
64
astronautism

Một mẹo tôi thích là sử dụng splat (*) mở rộng trên các đối tượng khác ngoài Mảng. Đây là một ví dụ về kết hợp biểu thức chính quy:

match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)

Các ví dụ khác bao gồm:

a, b, c = *('A'..'Z')

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
54
tomafro

Wow, không ai đề cập đến toán tử flip flop:

1.upto(100) do |i|
  puts i if (i == 3)..(i == 15)
end
52
Konstantin Haase

Một trong những điều thú vị về Ruby là bạn có thể gọi các phương thức và chạy mã ở những nơi mà các ngôn ngữ khác sẽ cau mày, chẳng hạn như trong định nghĩa phương thức hoặc lớp.

Chẳng hạn, để tạo một lớp có siêu lớp không xác định cho đến khi chạy, tức là ngẫu nhiên, bạn có thể làm như sau:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample

end

RandomSubclass.superclass # could output one of 6 different classes.

Cái này sử dụng 1.9 Array#sample phương thức (chỉ trong 1.8.7, xem Array#choice), và ví dụ khá giả tạo nhưng bạn có thể thấy sức mạnh ở đây.

Một ví dụ thú vị khác là khả năng đặt các giá trị tham số mặc định không cố định (như các ngôn ngữ khác thường yêu cầu):

def do_something_at(something, at = Time.now)
   # ...
end

Tất nhiên vấn đề với ví dụ đầu tiên là nó được đánh giá ở thời gian xác định, không phải thời gian gọi. Vì vậy, một khi siêu lớp đã được chọn, nó sẽ giữ nguyên siêu lớp đó trong phần còn lại của chương trình.

Tuy nhiên, trong ví dụ thứ hai, mỗi lần bạn gọi do_something_at, biến at sẽ là thời gian mà phương thức được gọi (tốt, rất gần với nó)

49
Bo Jeanes

Một tính năng nhỏ khác - chuyển đổi một Fixnum thành bất kỳ cơ sở nào lên tới 36:

>> 1234567890.to_s(2)
=> "1001001100101100000001011010010"

>> 1234567890.to_s(8)
=> "11145401322"

>> 1234567890.to_s(16)
=> "499602d2"

>> 1234567890.to_s(24)
=> "6b1230i"

>> 1234567890.to_s(36)
=> "kf12oi"

Và như Huw Walters đã nhận xét, chuyển đổi theo cách khác cũng đơn giản như sau:

>> "kf12oi".to_i(36)
=> 1234567890
47
tomafro

Băm với giá trị mặc định! Một mảng trong trường hợp này.

parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []

parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"

Rất hữu ích trong siêu lập trình.

40
August Lilleaas

Tải xuống Ruby 1.9 nguồn và vấn đề make golf, sau đó bạn có thể làm những việc như thế này:

make golf

./goruby -e 'h'
# => Hello, world!

./goruby -e 'p St'
# => StandardError

./goruby -e 'p 1.tf'
# => 1.0

./goruby19 -e 'p Fil.exp(".")'
"/home/manveru/pkgbuilds/Ruby-svn/src/trunk"

Đọc golf_prelude.c cho những thứ gọn gàng hơn trốn đi.

39
manveru

Một bổ sung thú vị khác trong chức năng 1.9 Proc là Proc # curry cho phép bạn biến một Proc chấp nhận n đối số thành một chấp nhận n-1. Ở đây, nó được kết hợp với mẹo Proc # === tôi đã đề cập ở trên:

it_is_day_of_week = lambda{ |day_of_week, date| date.wday == day_of_week }
it_is_saturday = it_is_day_of_week.curry[6]
it_is_sunday = it_is_day_of_week.curry[0]

case Time.now
when it_is_saturday
  puts "Saturday!"
when it_is_sunday
  puts "Sunday!"
else
  puts "Not the weekend"
end
38
Farrel

Toán tử Boolean trên các giá trị không boolean.

&&||

Cả hai trả về giá trị của biểu thức cuối cùng được đánh giá.

Đó là lý do tại sao ||= sẽ cập nhật biến với biểu thức trả về giá trị ở phía bên phải nếu biến không được xác định. Đây không phải là tài liệu rõ ràng, nhưng kiến ​​thức phổ biến.

Tuy nhiên, &&= không được biết đến rộng rãi.

string &&= string + "suffix"

tương đương với

if string
  string = string + "suffix"
end

Nó rất thuận tiện cho các hoạt động phá hoại không nên tiến hành nếu biến không được xác định.

35
EmFi

Hàm Symbol # to_proc mà Rails cung cấp thực sự rất tuyệt.

Thay vì

Employee.collect { |emp| emp.name }

Bạn có thể viết:

Employee.collect(&:name)
29
hoyhoy

Một cái cuối cùng - in Ruby bạn có thể sử dụng bất kỳ ký tự nào bạn muốn phân định chuỗi. Lấy mã sau đây:

message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"

Nếu bạn không muốn thoát dấu ngoặc kép trong chuỗi, bạn chỉ cần sử dụng một dấu phân cách khác:

contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]

Ngoài việc tránh phải thoát các dấu phân cách, bạn có thể sử dụng các dấu phân cách này cho các chuỗi nhiều dòng đẹp hơn:

sql = %{
    SELECT strings 
    FROM complicated_table
    WHERE complicated_condition = '1'
}
28
tomafro

Tôi tìm thấy bằng cách sử dụng lệnh notify_method để tự động tạo các phương thức khá thú vị và không được nhiều người biết đến. Ví dụ:

((0..9).each do |n|
    define_method "press_#{n}" do
      @number = @number.to_i * 10 + n
    end
  end

Đoạn mã trên sử dụng lệnh 'notify_method' để tự động tạo các phương thức "nhấn1" đến "nhấn9". Thay vào đó, sau đó nhập tất cả 10 phương thức chứa mã giống nhau, lệnh phương thức xác định được sử dụng để tạo các phương thức này một cách nhanh chóng khi cần thiết.

26
CodingWithoutComments

Sử dụng một đối tượng Phạm vi như một danh sách lười biếng vô hạn:

Inf = 1.0 / 0

(1..Inf).take(5) #=> [1, 2, 3, 4, 5]

Thêm thông tin tại đây: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-Ruby/

26
horseyguy

mô-đun

Các phương thức mô-đun được khai báo là module_function sẽ tạo các bản sao của chính chúng như private phương thức cá thể trong lớp bao gồm Mô-đun:

module M
  def not!
    'not!'
  end
  module_function :not!
end

class C
  include M

  def fun
    not!
  end
end

M.not!     # => 'not!
C.new.fun  # => 'not!'
C.new.not! # => NoMethodError: private method `not!' called for #<C:0x1261a00>

Nếu bạn sử dụng module_function mà không có bất kỳ đối số nào, thì bất kỳ phương thức mô-đun nào đi sau câu lệnh module_feft sẽ tự động trở thành module_fifts.

module M
  module_function

  def not!
    'not!'
  end

  def yea!
    'yea!'
  end
end


class C
  include M

  def fun
    not! + ' ' + yea!
  end
end
M.not!     # => 'not!'
M.yea!     # => 'yea!'
C.new.fun  # => 'not! yea!'
23
newtonapple

Tiêm ngắn, như vậy:

Tổng phạm vi :

(1..10).inject(:+)
=> 55
23
user130730

Cảnh báo: mục này đã được bình chọn # 1 Hack khủng khiếp nhất năm 2008, vì vậy hãy cẩn thận khi sử dụng. Trên thực tế, tránh nó như bệnh dịch, nhưng nó chắc chắn là Hidden Ruby.

Superators Thêm toán tử mới vào Ruby

Bạn đã bao giờ muốn một toán tử bắt tay siêu bí mật cho một số hoạt động độc đáo trong mã của bạn chưa? Thích chơi golf mã? Hãy thử các toán tử như - ~ + ~ - hoặc <--- Cái cuối cùng được sử dụng trong các ví dụ để đảo ngược thứ tự của một mặt hàng.

Tôi không có gì để làm với Dự án Superators ngoài việc ngưỡng mộ nó.

21
Captain Hammer

Tôi đến bữa tiệc muộn, nhưng:

Bạn có thể dễ dàng lấy hai mảng có độ dài bằng nhau và biến chúng thành một hàm băm với một mảng cung cấp các khóa và các giá trị khác:

a = [:x, :y, :z]
b = [123, 456, 789]

Hash[a.Zip(b)]
# => { :x => 123, :y => 456, :z => 789 }

(Điều này hoạt động vì Mảng # Zip "nén" các giá trị từ hai mảng:

a.Zip(b)  # => [[:x, 123], [:y, 456], [:z, 789]]

Và Hash [] có thể chỉ cần một mảng như vậy. Tôi đã thấy mọi người cũng làm điều này:

Hash[*a.Zip(b).flatten]  # unnecessary!

Điều này mang lại kết quả tương tự, nhưng splat và flatten hoàn toàn không cần thiết - có lẽ chúng không có trong quá khứ?)

19
Jordan Running

Tự động băm băm trong Ruby

def cnh # silly name "create nested hash"
  Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
end
my_hash = cnh
my_hash[1][2][3] = 4
my_hash # => { 1 => { 2 => { 3 =>4 } } }

Điều này chỉ có thể là tiện dụng chết tiệt.

19
Trevoke

Phá hủy một mảng

(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]

Ở đâu:

a #=> :a
b #=> :b
c #=> :c
d #=> [:d1, :d2]

Sử dụng kỹ thuật này, chúng ta có thể sử dụng phép gán đơn giản để có được các giá trị chính xác mà chúng ta muốn từ mảng lồng nhau ở bất kỳ độ sâu nào.

16
horseyguy

Class.new()

Tạo một lớp mới trong thời gian chạy. Đối số có thể là một lớp để xuất phát và khối là phần thân của lớp. Bạn cũng có thể muốn nhìn vào const_set/const_get/const_defined? để đăng ký lớp mới của bạn đúng cách, sao cho inspect in ra một tên thay vì số.

Không phải thứ bạn cần mỗi ngày, nhưng khá tiện dụng khi bạn làm.

15
Justin Love

tạo một dãy các số liên tiếp:

x = [*0..5]

đặt x thành [0, 1, 2, 3, 4, 5]

13
horseyguy

Rất nhiều điều kỳ diệu bạn thấy trong Rubyland có liên quan đến siêu lập trình, đơn giản là viết mã viết mã cho bạn. Ruby là attr_accessor, attr_readerattr_writer đều là các siêu lập trình đơn giản, trong đó chúng tạo ra hai phương thức trong một dòng, theo một mẫu chuẩn. Rails thực hiện toàn bộ quá trình siêu lập trình với các phương thức quản lý mối quan hệ của họ như has_onebelongs_to.

Nhưng thật đơn giản để tạo các thủ thuật siêu lập trình của riêng bạn bằng cách sử dụng class_eval để thực thi mã được viết động.

Ví dụ sau đây cho phép một đối tượng trình bao bọc chuyển tiếp các phương thức nhất định cùng với một đối tượng bên trong:

class Wrapper
  attr_accessor :internal

  def self.forwards(*methods)
    methods.each do |method|
      define_method method do |*arguments, &block|
        internal.send method, *arguments, &block
      end
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
w.to_i        # => 12
w.length      # => 8
w.split('1')  # => ["", "2 ", "3 ", "4"]

Phương thức Wrapper.forwards lấy các ký hiệu cho tên của các phương thức và lưu trữ chúng trong mảng methods. Sau đó, đối với mỗi người được cung cấp, chúng tôi sử dụng define_method để tạo một phương thức mới có nhiệm vụ gửi tin nhắn theo, bao gồm tất cả các đối số và khối.

Một nguồn tài nguyên tuyệt vời cho các vấn đề siêu lập trình là Tại sao "Nhìn thấy siêu lập trình rõ ràng" của Lucky Stiff .

13
TALlama

sử dụng bất cứ điều gì đáp ứng với ===(obj) để so sánh trường hợp:

case foo
when /baz/
  do_something_with_the_string_matching_baz
when 12..15
  do_something_with_the_integer_between_12_and_15
when lambda { |x| x % 5 == 0 }
  # only works in Ruby 1.9 or if you alias Proc#call as Proc#===
  do_something_with_the_integer_that_is_a_multiple_of_5
when Bar
  do_something_with_the_instance_of_Bar
when some_object
  do_something_with_the_thing_that_matches_some_object
end

Module (và do đó Class), Regexp, Date và nhiều lớp khác định nghĩa một phương thức cá thể: === (khác) và tất cả có thể được dùng.

Cảm ơn Farrel vì lời nhắc của Proc#call được đặt bí danh là Proc#=== in Ruby 1.9.

12
James A. Rosen

Nhị phân "Ruby" (ít nhất là MRI) hỗ trợ rất nhiều công tắc khiến cho Perl one-liners trở nên khá phổ biến.

Những người quan trọng:

  • -n Thiết lập một vòng lặp bên ngoài chỉ bằng "got" - hoạt động kỳ diệu với tên tệp hoặc STDIN đã cho, đặt từng dòng đọc thành $ _
  • -p Tương tự như -n nhưng với puts tự động ở cuối mỗi lần lặp
  • -a Tự động gọi đến .split trên mỗi dòng đầu vào, được lưu trữ trong $ F
  • -i Chỉnh sửa tập tin đầu vào tại chỗ
  • -l Tự động gọi đến .chomp trên đầu vào
  • -e Thực thi một đoạn mã
  • -c Kiểm tra mã nguồn
  • -w Với cảnh báo

Vài ví dụ:

# Print each line with its number:
Ruby -ne 'print($., ": ", $_)' < /etc/irbrc

# Print each line reversed:
Ruby -lne 'puts $_.reverse' < /etc/irbrc

# Print the second column from an input CSV (dumb - no balanced quote support etc):
Ruby -F, -ane 'puts $F[1]' < /etc/irbrc

# Print lines that contain "eat"
Ruby -ne 'puts $_ if /eat/i' < /etc/irbrc

# Same as above:
Ruby -pe 'next unless /eat/i' < /etc/irbrc

# Pass-through (like cat, but with possible line-end munging):
Ruby -p -e '' < /etc/irbrc

# Uppercase all input:
Ruby -p -e '$_.upcase!' < /etc/irbrc

# Same as above, but actually write to the input file, and make a backup first with extension .bak - Notice that inplace edit REQUIRES input files, not an input STDIN:
Ruby -i.bak -p -e '$_.upcase!' /etc/irbrc

Vui lòng google "Ruby one-liners" và "Perl one-liners" để biết thêm nhiều ví dụ thực tế và hữu dụng. Về cơ bản, nó cho phép bạn sử dụng Ruby như một sự thay thế khá mạnh mẽ cho awk và sed.

11
minaguib

Phương thức send () là phương thức có mục đích chung có thể được sử dụng trên bất kỳ Class hoặc Object nào trong Ruby. Nếu không bị ghi đè, send () chấp nhận một chuỗi và gọi tên của phương thức có chuỗi được truyền. Ví dụ: nếu người dùng nhấp vào nút Cl Cl Cl, thì, chuỗi ‘press_clear, sẽ được gửi đến phương thức send () và phương thức‘ press_clear, sẽ được gọi. Phương thức send () cho phép một cách thú vị và năng động để gọi các hàm trong Ruby.

 %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn|
    button btn, :width => 46, :height => 46 do
      method = case btn
        when /[0-9]/: 'press_'+btn
        when 'Clr': 'press_clear'
        when '=': 'press_equals'
        when '+': 'press_add'
        when '-': 'press_sub'
        when '*': 'press_times'
        when '/': 'press_div'
      end

      number.send(method)
      number_field.replace strong(number)
    end
  end

Tôi nói thêm về tính năng này trong Giày blog: Ứng dụng đơn giản-Calc

10
CodingWithoutComments
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly

Trông giống như một trò chơi thú vị và (trong một số trường hợp) Nice/hữu ích của Ruby.

9
Szymon Jeż

Fixnum#to_s(base) có thể thực sự hữu ích trong một số trường hợp. Một trường hợp như vậy là tạo ra các mã thông báo duy nhất ngẫu nhiên (giả) bằng cách chuyển đổi số ngẫu nhiên thành chuỗi bằng cơ sở 36.

Mã thông báo có độ dài 8:

Rand(36**8).to_s(36) => "fmhpjfao"
Rand(36**8).to_s(36) => "gcer9ecu"
Rand(36**8).to_s(36) => "krpm0h9r"

Mã thông báo có độ dài 6:

Rand(36**6).to_s(36) => "bvhl8d"
Rand(36**6).to_s(36) => "lb7tis"
Rand(36**6).to_s(36) => "ibwgeh"
9
sickill

Đánh lừa một số lớp hoặc mô-đun nói rằng nó đã yêu cầu một cái gì đó mà nó thực sự không yêu cầu:

$" << "something"

Ví dụ, điều này hữu ích khi yêu cầu A mà lần lượt yêu cầu B nhưng chúng tôi không cần B trong mã của chúng tôi (và A sẽ không sử dụng nó thông qua mã của chúng tôi):

Ví dụ: bdrb_test_helper requires'test/spec' Của Backgroundrb, nhưng bạn hoàn toàn không sử dụng nó, vì vậy trong mã của bạn:

$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
9
olegueret

Xác định phương thức chấp nhận bất kỳ số lượng tham số nào và chỉ loại bỏ tất cả chúng

def hello(*)
    super
    puts "hello!"
end

Phương thức hello ở trên chỉ cần puts"hello" trên màn hình và gọi super - nhưng vì siêu lớp hello cũng xác định các tham số nên nó cũng vậy - tuy nhiên vì nó không thực sự cần sử dụng chính các tham số - nên nó không phải cho họ một cái tên.

9
horseyguy

Để kết hợp nhiều biểu thức với |, bạn có thể dùng

Regexp.union /Ruby\d/, /test/i, "cheat"

để tạo một Regapi tương tự như:

/(Ruby\d|[tT][eE][sS][tT]|cheat)/
8
J-_-L

Tôi thấy điều này hữu ích trong một số kịch bản. Nó cho phép sử dụng trực tiếp các biến môi trường, như trong tập lệnh Shell và Makefiles. Các biến môi trường được sử dụng làm dự phòng cho các hằng số không xác định Ruby.

>> class <<Object
>>  alias :old_const_missing :const_missing
>>  def const_missing(sym)
>>   ENV[sym.to_s] || old_const_missing(sym)
>>  end
>> end
=> nil

>> puts Shell
/bin/zsh
=> nil
>> TERM == 'xterm'
=> true
8
Ropez

Làm thế nào về việc mở một tệp dựa trên ARGV [0]?

readfile.rb:

$<.each_line{|l| puts l}

Ruby readfile.rb testfile.txt

Đó là một phím tắt tuyệt vời để viết các kịch bản một lần. Có một mớ hỗn độn các biến được xác định trước mà hầu hết mọi người không biết. Sử dụng chúng một cách khôn ngoan (đọc: không xả rác một cơ sở mã mà bạn dự định duy trì với chúng, nó có thể trở nên lộn xộn).

8
Scott Holden

Tôi là fan của:

%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]

Thật là buồn cười khi nó thường hữu ích.

5
Judson

Nhiều giá trị trả về

def getCostAndMpg
    cost = 30000  # some fancy db calls go here
    mpg = 30
    return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"

Chuyển nhượng song song

i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"

Thuộc tính ảo

class Employee < Person
  def initialize(fname, lname, position)
    super(fname,lname)
    @position = position
  end
  def to_s
     super + ", #@position"
  end
  attr_writer :position
  def etype
     if @position == "CEO" || @position == "CFO"
         "executive"
     else
         "staff"
     end
  end
end
employee = Employee.new("Augustus","Bondi","CFO")
employee.position = "CEO"
puts employee.etype    =>  executive
employee.position = "Engineer"
puts employee.etype    =>  staff

method_missing - một ý tưởng tuyệt vời

(Trong hầu hết các ngôn ngữ khi không thể tìm thấy phương thức và lỗi được ném và chương trình của bạn dừng lại. Trong Ruby bạn thực sự có thể bắt những lỗi đó và có thể làm điều gì đó thông minh với tình huống)

class MathWiz
  def add(a,b) 
    return a+b
  end
  def method_missing(name, *args)
    puts "I don't know the method #{name}"
  end
end
mathwiz = MathWiz.new
puts mathwiz.add(1,4)
puts mathwiz.subtract(4,2)

5

Tôi không biết phương pháp trừ

không

5
Ramiz Uddin

Mẹo của James A. Rosen rất tuyệt ([* mục] .each), nhưng tôi thấy rằng nó phá hủy băm:

irb(main):001:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):002:0> [*h]
=> [[:name, "Bob"]]

Tôi thích cách xử lý vụ việc này khi tôi chấp nhận một danh sách những việc cần xử lý nhưng lại khoan dung và cho phép người gọi cung cấp một:

irb(main):003:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):004:0> [h].flatten
=> [{:name=>"Bob"}]

Điều này có thể được kết hợp với một chữ ký phương thức rất độc đáo:

def process(*entries)
  [entries].flatten.each do |e|
    # do something with e
  end
end
4
minaguib

Tôi chỉ yêu từ khóa nội tuyến cứ như thế này:
[.__.] VÍ DỤ EDITED :

@user #=> nil (but I did't know)
@user.name rescue "Unknown"
link_to( d.user.name, url_user( d.user.id, d.user.name)) rescue 'Account removed'

Điều này tránh phá vỡ Ứng dụng của tôi và tốt hơn nhiều so với tính năng được phát hành tại Rails . Try ()

4
Fabiano Soriani

Gọi một phương thức được xác định ở bất cứ đâu trong chuỗi thừa kế, ngay cả khi bị ghi đè

Các đối tượng của ActiveSupport đôi khi giả trang thành các đối tượng tích hợp.

[.__.] yêu cầu 'active_support' [.__.] ngày = 5. ngày [.__.] ngày. class # => Fixnum [.__.] days.is_a? (Fixnum) # => true [.___ .] Fixnum === ngày # => false (huh? Bạn thực sự là gì?) [.__.] Object.instance_method (: class) .bind (ngày) .call # => ActiveSupport :: Thời gian (aha!) [.__.] ActiveSupport :: Thời lượng === ngày # => đúng [.__.]

Tất nhiên, ở trên, phụ thuộc vào thực tế là active_support không xác định lại Object # instance_method, trong trường hợp đó chúng tôi thực sự sẽ lên một con lạch. Sau đó, một lần nữa, chúng ta luôn có thể lưu giá trị trả về của Object.instance_method (: class) trước khi bất kỳ thư viện bên thứ 3 nào được tải.

Object.instance_method (...) trả về một UnboundMethod mà sau đó bạn có thể liên kết với một thể hiện của lớp đó. Trong trường hợp này, bạn có thể liên kết nó với bất kỳ trường hợp nào của Object (bao gồm các lớp con).

Nếu lớp của một đối tượng bao gồm các mô-đun, bạn cũng có thể sử dụng UnboundMethod từ các mô-đun đó.

[.__.] mô-đun Mod [.__.] def var_add (thêm); @ var + nhiều hơn; end [.__.] end [.__.] class Cla [.__.] bao gồm Mod [.__.] def khởi tạo (var); @ var = var; end [.___.] # ghi đè [.__.] def var_add (thêm); @ var + nhiều hơn + nhiều hơn; end [.__.] end [.__.] Stew = Cla.new ('abcdef') [.__.] Stew.var_add ('ghi') # => "abcdefghighi" [.__.] Mod.instance_method ( : var_add) .bind (ngột ngạt) .call ('ghi') # => "abcdefghi" [.__.]

Điều này thậm chí hoạt động cho các phương thức singleton ghi đè lên một phương thức cá thể của lớp mà đối tượng thuộc về.

[.__.] lớp Foo [.__.] def mymethod; 'nguyên'; end [.__.] end [.__.] foo = Foo.new [.__.] foo.mymethod # => 'gốc' [.__.] def foo.mymethod; 'đơn lẻ'; end [.__.] foo.mymethod # => 'singleton' [.__.] Foo.instance_method (: mymethod) .bind (foo) .call # => 'gốc' [.__.] [.__.] # Bạn cũng có thể gọi phương thức #instance trên các lớp singleton: [.__.] Lớp << foo; tự; end.instance_method (: mymethod) .bind (foo) .call # => 'singleton' [.__.]
4
Kelvin

Có một số khía cạnh của văn học biểu tượng mà mọi người nên biết. Một trường hợp được giải quyết bằng chữ ký hiệu đặc biệt là khi bạn cần tạo một ký hiệu có tên gây ra lỗi cú pháp vì một số lý do với cú pháp ký hiệu ký tự bình thường:

:'class'

Bạn cũng có thể thực hiện phép nội suy ký hiệu. Trong ngữ cảnh của một người truy cập, ví dụ:

define_method :"#{name}=" do |value|
  instance_variable_set :"@#{name}", value
end
3
Tom

Each_with_index phương thức cho bất kỳ đối tượng có thể đếm được (mảng, hàm băm, v.v.) có lẽ?

myarray = ["la", "li", "lu"]
myarray.each_with_index{|v,idx| puts "#{idx} -> #{v}"}

#result:
#0 -> la
#1 -> li
#2 -> lu

Có thể nó được biết đến nhiều hơn các câu trả lời khác nhưng không phải ai cũng biết đến tất cả Ruby lập trình viên :)

3
mhd
class A

  private

  def my_private_method
    puts 'private method called'
  end
end

a = A.new
a.my_private_method # Raises exception saying private method was called
a.send :my_private_method # Calls my_private_method and prints private method called'
2
Chirantan

Ruby có cơ chế gọi/cc cho phép một người tự do nhảy lên và xuống ngăn xếp.

Ví dụ đơn giản sau đây. Đây chắc chắn không phải là cách người ta sẽ nhân một chuỗi trong Ruby, nhưng nó cho thấy cách người ta có thể sử dụng lệnh gọi/cc để tiếp cận ngăn xếp để làm ngắn mạch thuật toán. Trong trường hợp này, chúng tôi nhân lên một cách đệ quy một danh sách các số cho đến khi chúng tôi thấy mọi số hoặc chúng tôi thấy số không (hai trường hợp chúng tôi biết câu trả lời). Trong trường hợp không, chúng ta có thể tùy ý vào sâu trong danh sách và chấm dứt.

#!/usr/bin/env Ruby

def rprod(k, rv, current, *nums)
  puts "#{rv} * #{current}"
  k.call(0) if current == 0 || rv == 0
  nums.empty? ? (rv * current) : rprod(k, rv * current, *nums)
end

def prod(first, *rest)
  callcc { |k| rprod(k, first, *rest) }
end

puts "Seq 1:  #{prod(1, 2, 3, 4, 5, 6)}"
puts ""
puts "Seq 2:  #{prod(1, 2, 0, 3, 4, 5, 6)}"

Bạn có thể thấy đầu ra ở đây:

http://codepad.org/Oh8ddh9e

Đối với một ví dụ phức tạp hơn có tính năng tiếp tục di chuyển theo hướng khác trên ngăn xếp, hãy đọc nguồn tới Trình tạo .

2
Dustin

Tôi vừa đọc tất cả các câu trả lời ... một thiếu sót đáng chú ý là phá hủy bài tập:

> (a,b),c = [[1,2],3]
=> [[1,2],3]
> a
=> 1

Nó cũng hoạt động cho các tham số khối. Điều này rất hữu ích khi bạn có các mảng lồng nhau, mỗi phần tử đại diện cho một cái gì đó khác biệt. Thay vì viết mã như "mảng [0] [1]", bạn có thể phá vỡ mảng lồng nhau đó và đặt tên mô tả cho từng thành phần, trong một dòng mã.

2
Alex D
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
2
haoqi

Phím tắt chạy nước rút

Yêu thích của tôi Ruby. Cú pháp là format_string % argument

"%04d"  % 1         # => "0001"
"%0.2f" % Math::PI  # => "3.14"

Hoạt động tốt cho mảng (format_string % array_of_arguments)

"%.2f %.3f %.4f" % ([Math::PI]*3) 
# => "3.14 3.142 3.1416"
1
iblue