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


160

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 ngôn ngữ lập trình Ruby.

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ỳ nội dung nào của Ruby on Rails.

Xem thêm:

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

Cảm ơn bạn


nên là wiki cộng đồng
SilentGhost

Câu trả lời:


80

Từ Ruby 1.9 Proc # === là bí danh cho 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

1
Tôi thực sự đã viết một viên đá quý tại một thời điểm để làm điều này, nhưng mã của tôi là (a) một mớ hỗn độn và (b) chậm. Tôi rất vui vì chức năng đã biến nó thành cốt lõi.
James A. Rosen

76

Peter Cooper có một danh sách tốt các thủ thuật Ruby. Có lẽ yêu thích của anh ấy là cho phép liệt kê cả các mục đơn và bộ sưu tập. (Nghĩa là, coi một đối tượng không phải là bộ sưu tập là 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

38
Một hình thức rõ ràng hơn (và do đó đẹp hơn) của điều này là Mảng (vật phẩm) .each
mislav

Nếu itemslà một chuỗi bạn không phải gửi kèm theo [*]]. String.each không lặp lại các ký tự như một số người có thể mong đợi. Nó chỉ trở lại chính nó vào khối.
mxcl

Cái này sẽ dùng cái gì? Chỉ tò mò thôi.
Ed S.

1
@Ed: thật tuyệt nếu bạn đang viết một phương thức và muốn cho phép người dùng phương thức đó vượt qua danh sách varargs hoặc Array.
James A. Rosen

64

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

Lưu ý rằng Hash[ [["apple","red"], ["banana","yellow"] ]tạo ra kết quả tương tự.
Marc-André Lafortune

54

Một mẹo tôi thích là sử dụng bộ *mở rộng splat ( ) 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

13
Ngẫu nhiên, đối với người tò mò, điều này hoạt động bằng cách gọi to_a trên mục tiêu của splat.
Bob Aman

1
Nếu bạn không quan tâm đến trận đấu, bạn có thể có text, number = *"text 555".match(/regexp/)[1..-1].
Andrew Grimm

text, number = "Something 981".scan(/([A-z]*) ([0-9]*)/).flatten.map{|m| Integer(m) rescue m}
Jonas Elfström

7
Cả hai thủ thuật hay, nhưng phải có một điểm mà nó quá nhiều ma thuật, phải không?!
tomafro

1
@Andrew, bạn đã xem xét, trận đấu đó có thể trở về con số không? nil không có phương pháp []
Alexey

52

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

11
Phải ... ai đó sẽ phải giải thích điều này với tôi. Nó hoạt động, nhưng tôi không thể hiểu tại sao.
Bob Aman

12
Toán tử flip flop là một trạng thái nếu. Trạng thái của nó chuyển sang true ngay sau đó i == 3và chuyển sang false sau i != 3i == 15. Tương tự như một flip-flop: en.wikipedia.org/wiki/Flip-flop_%28electronics%29
Konstantin Haase

1
Tôi chính xác sẽ không gọi đây là một tính năng ẩn, rất nhiều phiền toái. Tôi nhớ lần đầu tiên tôi được giới thiệu về nó trong #Ruby trên Freenode, nhiều năm trước; Về cơ bản, tôi đã sử dụng mọi tính năng duy nhất của Ruby ngoại trừ tính năng này.
ELLIOTTCABLE

1
Tôi sẽ không gọi đó là một sự phiền toái, đó chỉ là thứ bạn chưa sử dụng. Tôi sử dụng nó và nó có thể giảm mã độc đáo, đặc biệt là khi tôi lấy các khối dòng từ các tệp dựa trên một số tiêu chí.
Tin Man

49

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ẽ nhăn mặt, chẳng hạn như trong các định nghĩa phương thức hoặc lớp.

Ví dụ, để tạo một lớp có siêu lớp chưa biết 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.

Điều này sử dụng Array#samplephương thức 1.9 (chỉ trong 1.8.7, xem Array#choice) và ví dụ này 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, atbiến sẽ là thời gian mà phương thức được gọi (tốt, rất gần với nó)


2
Lưu ý: Mảng # rand được ActiveSupport cung cấp mà bạn có thể sử dụng bên ngoài Rails dễ dàng nhưrequire 'activesupport'
rfunduk

Lựa chọn mảng # là trong 1.8.7
Josh Lee

24
Lựa chọn mảng # chỉ là 1.8.7 ! Đừng sử dụng nó, nó đã biến mất trong 1.9 và sẽ biến mất trong 1.8.8. Sử dụng #sample
Marc-André Lafortune

python: class DictList ([dict, list] [Random.randint (0,1)]): pass
Anurag Uniyal

def do_s Something_at (Something, at = lambda {Time.now}) at.call #now tự động gán thời gian kết thúc
Jack Kinsella

47

Một tính năng nhỏ khác - chuyển đổi a Fixnumthà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

1
Và để hoàn thiện, String#to_s(base)có thể được sử dụng để chuyển đổi trở lại thành một số nguyên; "1001001100101100000001011010010".to_i(2), "499602d2".to_i(16)vv tất cả trả lại bản gốc Fixnum.
Huw Walters

40

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.


1
Vâng đúng. Ruby băm có thể chấp nhận toán tử '<<' nếu đã có giá trị mặc định được gán với '=' (không quan tâm ngay cả khi đó là gán trống) nếu không thì hàm băm sẽ không chấp nhận '<<'. CMIIW
mhd

39

Tải xuống nguồn Ruby 1.9 và phát hành make golf, sau đó bạn có thể thực hiện những việc như sau:

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để biết những điều gọn gàng hơn ẩn đi.


38

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

35

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, điều &&=này 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.


2
Chính xác hơn, string &&= string + "suffix" tương đương với string = string && string + "suffix". Điều đó &&||trả về đối số thứ hai của chúng được thảo luận trong PickAx, p. 154 (Phần I - Các khía cạnh của Ruby, Biểu hiện, Thi hành có điều kiện).
Richard Michael

29

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)

Rõ ràng, đây là một "thứ tự cường độ chậm hơn" so với sử dụng một khối. igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
Charles Roper

Tôi vừa thử nó, và thấy rằng không có sự khác biệt đáng kể giữa hai. Tôi không chắc thứ "thứ tự cường độ" này đến từ đâu. (Sử dụng Ruby 1.8.7)
Matt Grande

1
Làm điều này bên ngoài Rails cũng tiện dụng và có thể được thực hiện require 'activesupport'vì đó thực sự là nơi mà hầu hết những người trợ giúp này đến từ.
rfunduk

8
điều này từng bị chậm do triển khai của active_support, nghĩa là nó đã chấp nhận nhiều đối số để bạn có thể thực hiện shit mát mẻ như (1..10) .inject &: *, nhưng trường hợp sử dụng chính thường chỉ gọi một phương thức trên mỗi thành viên của một bộ sưu tập, ví dụ% w (con cáo nâu nhanh) .map &: upcase. kể từ 1.8.7, viên ruby ​​cốt lõi của nó và hiệu suất là hợp lý.
Steve Graham

4
@thenduks: Và nó có thể được thực hiện mà không cần sự trợ giúp của hỗ trợ trong ruby ​​1.8.7 và 1.9.
Andrew Grimm

28

Một cái cuối cùng - trong 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:

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 đa dòng đẹp hơn:

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

19
không phải nhân vật nào , nhưng nó vẫn rất tuyệt Nó cũng hoạt động với các nghĩa đen khác:% () /% {} /% [] /% <> /% || % r () /% r {} /% r [] /% r <> /% r | | % w () /% w {} /% w [] /% w <> /% w | |
Bo Jeanes

Ngoài ra còn có cú pháp tài liệu hướng dẫn: << BLOCK ... BLOCK, mà tôi muốn sử dụng cho những thứ như các câu lệnh SQL đa dòng, v.v.
Martin T.

26

Tôi thấy việc sử dụng lệnh notify_method để tự động tạo ra các phương thức khá thú vị và không được biết đến nhiều. 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 đó gõ tất cả 10 phương thức mà thực chất chứa cùng một mã, 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.


4
Vấn đề duy nhất với notify_method là nó không cho phép các khối được truyền dưới dạng tham số trong ruby ​​1.8. Xem bài đăng blog này cho một cách giải quyết.
Andrew Grimm

26

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/


Lazy_select trong bài viết được liên kết là rất gọn gàng.
Joseph Weissman

Điều này thực sự tuyệt vời. Tôi thích cách Infinity là một float, theo cách đó khi tôi thử điều này: (-Inf..Inf) .take (4) nó đưa ra một (phù hợp về mặt logic) không thể lặp lại từ lỗi float. : D
zachaysan

23

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ư các phương thức cá thể riêng 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 xuất hiện 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!'

4
Nếu bạn chỉ muốn khai báo các phương thức riêng tư trong các mô-đun, chỉ cần sử dụng từ khóa riêng. Ngoài việc đặt phương thức riêng tư trong các lớp bao gồm mô-đun, module_feft sao chép phương thức vào thể hiện của mô-đun. Trong hầu hết các trường hợp, đây không phải là điều bạn muốn.
tomafro

Tôi biết bạn chỉ có thể sử dụng riêng tư. Nhưng đây là một câu hỏi về các tính năng ẩn của Ruby. Và, tôi nghĩ rằng hầu hết mọi người chưa bao giờ nghe nói về module_feft (bao gồm cả bản thân tôi) cho đến khi họ nhìn thấy nó trong tài liệu và bắt đầu chơi xung quanh nó.
newtonapple

Một cách khác để sử dụng module_function(cách thứ 2) là chỉ sử dụng extend self(trông khá đẹp: D)
J -_- L


21

Cảnh báo: mục này đã được bình chọn là # 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ó.


19

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ì Array # 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ứ?)


3
Điều này thực sự không có giấy tờ trong một thời gian dài (xem redmine.ruby-lang.org/issues/show/1385 ). Lưu ý rằng hình thức mới này là mới đối với Ruby 1.8.7
Marc-André Lafortune

19

Băm tự động sinh động 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.


1
Tôi sẽ bọc nó trong một mô-đun để có cảm giác giống như init hash gốc:module InfHash; def self.new; Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}; end; end
asaaki

16

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.


15

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 xem xét const_set/const_get/const_defined?để đăng ký lớp mới của mình đúng cách, đểinspect in ra một tên thay vì một 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.


1
MyClass = Class.new Array do; def hi; 'hi'; end; enddường như tương đương với class MyClass < Array; def hi; 'hi'; end; end.
yfeldblum

1
Có lẽ đúng hơn tôi nghĩ. Nó thậm chí có vẻ như bạn có thể kế thừa từ một biến chứ không chỉ là một hằng số. Tuy nhiên, phiên bản có đường (thứ hai) dường như không hoạt động nếu bạn cần xây dựng tên lớp trong thời gian chạy. (Baring eval, tất nhiên.)
Justin Love

Kỹ thuật này được mô tả khá tốt trong cuốn sách Metaprogramming Ruby .
Paul Pladijs

13

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]


Đúng, nhưng nó không ngắn và ngọt ngào;)
Horseyguy

2
căng thẳng là khách quan, dễ đọc là vấn đề của hương vị và kinh nghiệm
Alexey

*Toán tử splat ( ) về cơ bản gọi bằng to_amọi cách.
Matheus Moreira

13

Rất nhiều phép thuật 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 attr_accessor, attr_readerattr_writerđều là những lập trình meta đơn giản, ở chỗ chúng tạo ra hai phương pháp trong một dòng, sau một mô hình chuẩn. Rails thực hiện rất nhiều chương trình siêu dữ liệu 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.forwardslấy các ký hiệu cho tên của các phương thức và lưu trữ chúng trong methodsmảng. Sau đó, đối với mỗi người được đưa ra, chúng tôi sử dụngdefine_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 đề lập trình siêu dữ liệu là Tại sao "Nhìn thấy siêu lập trình rõ ràng" của Lucky Stiff .


Tôi muốn lặn đầu tiên vào metaprogramming trong ruby. Bạn có thể cung cấp một số tài liệu tham khảo để bắt đầu với nó (Khác với liên kết đã cho) không? Sách sẽ làm quá. Cảm ơn.
Chirantan

Serie quay phim của PragProg "Mô hình đối tượng Ruby và lập trình siêu dữ liệu" là một giới thiệu tốt về lập trình meta bằng ruby: pragprog.com/screencasts/v-dtrubyom/ trộm
caffo

@Chirantan, hãy xem Metaprogramming Ruby .
Paul Pladijs

12

sử dụng bất cứ điều gì đáp ứng ===(obj)cho các 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 xác định một phương pháp dụ: === (khác), và tất cả có thể được sử dụng.

Cảm ơn Farrel vì lời nhắc nhở về Proc#callbí danh như Proc#===trong Ruby 1.9.


11

Nhị phân "ruby" (ít nhất là MRI) hỗ trợ rất nhiều công tắc làm 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 một 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.


10

Phương thức send () là một 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 Blog blog: Ứng dụng Simple-Calc


Âm thanh như một cách tuyệt vời để mở một lỗ hổng bảo mật.
mP.

4
Tôi sẽ sử dụng các biểu tượng bất cứ nơi nào có thể.
reto

9

Đá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ụ: Backgroundrb's bdrb_test_helper requires 'test/spec', 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")

Điều này có khắc phục được sự cố khi gem A yêu cầu foo-1.0.0 và gem B yêu cầu foo-1.0.1 không?
Andrew Grimm

Không bởi vì mã của "cái gì đó" sẽ không khả dụng: điều này chỉ mô phỏng rằng "cái gì đó" là bắt buộc, nhưng nó thực sự không yêu cầu nó. $ "là một mảng chứa các tên mô-đun được tải theo yêu cầu (được sử dụng bởi yêu cầu để ngăn chặn tải mô-đun hai lần). Vì vậy, nếu bạn sử dụng điều này để đánh lừa đá quý, điều đó sẽ tạo ra sự cố khi các viên đá quý cố gắng sử dụng" thứ gì đó "thực sự thay vào đó, mã này sẽ không tồn tại. Thay vào đó, bạn có thể muốn mã hóa phiên bản cụ thể của đá quý (ví dụ: foo-1.0.0), thay vì phiên bản mới nhất: docs.rubygems.org/read/ch CHƯƠNG / 4 / page71
olegueret

9

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

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

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

helloPhương thức trên chỉ cần puts "hello"trên màn hình và gọi super- nhưng vì siêu lớp helloxác định các tham số nên nó cũng phải - 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 đặt tên cho chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.