常见的Ruby成语

有一件事我喜欢ruby,主要是它是一个非常可读的语言(这对于自我logging代码来说是很好的)

然而,受到这个问题的启发: Ruby Code解释了和||=如何在Ruby中工作,我想到了我不使用的ruby成语,坦率地说,我没有完全理解它们。

所以我的问题是,类似于引用问题的例子,我需要注意哪些常见但不明显的ruby成语,才能成为一名真正熟练的ruby程序员?

顺便说一句,从引用的问题

 a ||= b 

相当于

 if a == nil || a == false a = b end 

(感谢Ian Terrell的更正)

编辑:事实certificate,这一点不完全没有争议。 其实是正确的扩张

 (a || (a = (b))) 

查看这些链接为什么:

  • http://DABlog.RubyPAL.Com/2008/3/25/a-short-circuit-edge-case/
  • http://DABlog.RubyPAL.Com/2008/3/26/short-circuit-post-correction/
  • http://ProcNew.Com/ruby-short-circuit-edge-case-response.html

感谢JörgW Mittag指出这一点。

允许相同文件充当库或脚本的魔法if子句:

 if __FILE__ == $0 # this library may be run as a standalone script end 

打包和解包数组:

 # put the first two words in a and b and the rest in arr a,b,*arr = *%w{a dog was following me, but then he decided to chase bob} # this holds for method definitions to def catall(first, *rest) rest.map { |word| first + word } end catall( 'franken', 'stein', 'berry', 'sense' ) #=> [ 'frankenstein', 'frankenberry', 'frankensense' ] 

散列的合成糖作为方法参数

 this(:is => :the, :same => :as) this({:is => :the, :same => :as}) 

哈希初始化程序:

 # this animals = Hash.new { [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {} # is not the same as this animals = Hash.new { |_animals, type| _animals[type] = [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]} 

元类语法

 x = Array.new y = Array.new class << x # this acts like a class definition, but only applies to x def custom_method :pow end end x.custom_method #=> :pow y.custom_method # raises NoMethodError 

类实例variables

 class Ticket @remaining = 3 def self.new if @remaining > 0 @remaining -= 1 super else "IOU" end end end Ticket.new #=> Ticket Ticket.new #=> Ticket Ticket.new #=> Ticket Ticket.new #=> "IOU" 

块,特效和lambda。 生活和呼吸他们。

  # know how to pack them into an object block = lambda { |e| puts e } # unpack them for a method %w{ and then what? }.each(&block) # create them as needed %w{ I saw a ghost! }.each { |w| puts w.upcase } # and from the method side, how to call them def ok yield :ok end # or pack them into a block to give to someone else def ok_dokey_ok(&block) ok(&block) block[:dokey] # same as block.call(:dokey) ok(&block) end # know where the parentheses go when a method takes arguments and a block. %w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4 pusher = lambda { |array, word| array.unshift(word) } %w{ eat more fish }.inject([], &pusher) #=> ['fish', 'more', 'eat' ] 

这个幻灯片在主要的Ruby成语上是相当完整的,如:

  • 交换两个值:

    x, y = y, x

  • 如果没有指定,则采用某个默认值的参数

    def somemethod(x, y=nil)

  • 将多余的参数分配到一个数组中

    def substitute(re, str, *rest)

等等…

更多的习语:

使用%w%r%(分隔符

 %w{ An array of strings %} %r{ ^http:// } %{ I don't care if the string has 'single' or "double" strings } 

types比较在案件陈述

 def something(x) case x when Array # Do something with array when String # Do something with string else # You should really teach your objects how to 'quack', don't you? end end 

在案例陈述中整体滥用===方法

 case x when 'something concrete' then ... when SomeClass then ... when /matches this/ then ... when (10...20) then ... when some_condition >= some_value then ... else ... end 

对于Rubyists来说应该看起来很自然,但是对于来自其他语言的人来说也许不是那么简单:使用each都赞成for .. in

 some_iterable_object.each{|item| ... } 

在Ruby 1.9+,Rails中,或者通过修改Symbol#to_proc方法, 这正成为越来越stream行的习惯用法:

 strings.map(&:upcase) 

有条件的方法/常量定义

 SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT) 

查询方法和破坏性(bang)方法

 def is_awesome? # Return some state of the object, usually a boolean end def make_awesome! # Modify the state of the object end 

隐式图示参数

 [[1, 2], [3, 4], [5, 6]].each{ |first, second| puts "(#{first}, #{second})" } 

我喜欢这个:

 str = "Something evil this way comes!" regexp = /(\w[aeiou])/ str[regexp, 1] # <- This 

这(大致)相当于:

 str_match = str.match(regexp) str_match[1] unless str_match.nil? 

或者至less这是我用来取代这样的块。

我build议你阅读一下你喜欢和尊重的人的stream行和精心devise的插件或gem的代码。

我遇到的一些例子:

 if params[:controller] == 'discussions' or params[:controller] == 'account' # do something here end 

对应

 if ['account', 'discussions'].include? params[:controller] # do something here end 

后来将被重构

 if ALLOWED_CONTROLLERS.include? params[:controller] # do something here end 

这里有几个来自不同来源的消息:

使用“除非”和“直到”而不是“如果不是”和“不是”。 尽pipe如此,尽量不要在“else”条件下使用“unless”。

请记住,您可以一次分配多个variables:

 a,b,c = 1,2,3 

甚至没有临时交换variables:

 a,b = b,a 

在适当的地方使用尾随条件,例如

 do_something_interesting unless want_to_be_bored? 

注意一个常用但不是即时显而易见(对我来说)定义类方法的方法:

 class Animal class<<self def class_method puts "call me using Animal.class_method" end end end 

一些参考:

顺便说一句,从引用的问题

 a ||= b 

相当于

 if a == nil a = b end 

这是微妙的错误,是新手Ruby应用程序中的一个错误。

既然(而且只有) nilfalse评估为布尔型假, a ||= b实际上(几乎*)等价于:

 if a == nil || a == false a = b end 

或者,用另一个Ruby成语来重写:

 a = b unless a 

(*因为每个语句都有一个值,所以这些语句在技术上并不等价于a ||= b ,但是如果你不依赖于语句的值,你将不会看到区别。

我维护一个涵盖一些Ruby成语和格式的wiki页面:

https://github.com/tokland/tokland/wiki/RubyIdioms

你可以用Marshaling对象很容易地进行深度拷贝。 – 来自Ruby编程语言

 def deepcopy(o) Marshal.load(Marshal.dump(o)) end 

请注意,文件和I / Ostream以及方法和绑定对象都太dynamic,无法封送。 将没有可靠的方法来恢复他们的状态。

 a = (b && b.attribute) || "default" 

大概是:

 if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b else a = "default" 

我使用这个时,b是一个可能或可能没有find的logging,我需要得到它的一个属性。

我总是忘记这个速记的确切语法,如果else语句(和运算符的名字。评论任何人?)我认为这是广泛使用的ruby之外,但如果别人想要这里的语法是:

 refactor < 3 ? puts("No need to refactor YET") : puts("You need to refactor this into a method") 

扩展到

 if refactor < 3 puts("No need to refactor YET") else puts("You need to refactor this into a method") end 

更新

称为三元运算符:

返回myvar? myvar.size:0

我喜欢If-then-elses或case-when可以缩短,因为他们返回一个值:

 if test>0 result = "positive" elsif test==0 result = "zero" else result = "negative" end 

可以重写

 result = if test>0 "positive" elsif test==0 "zero" else "negative" end 

同样的情况也适用于以下情况:

 result = case test when test>0 ; "positive" when test==0 ; "zero" else "negative" end 

用于处理二进制文件的Array.pack和String.unpack:

 # extracts four binary sint32s to four Integers in an Array data.unpack("iiii") 

方法缺lessmagick

 class Dummy def method_missing(m, *args, &block) "You just called method with name #{m} and arguments- #{args}" end end Dummy.new.anything(10, 20) => "You just called method with name anything and arguments- [10, 20]" 

如果你调用ruby对象中不存在的方法,ruby解释器会调用method_missing方法,如果它定义了的话,你可以使用这个方法来做一些技巧,比如写api包装器或者dsl,不知道所有的方法和参数名

很好的问题!

我认为代码越直观,越快,我们正在构build一个更好的软件。 我将向您展示如何使用Ruby在一小段代码中expression我的想法。 在这里阅读更多

地图

我们可以用不同的方式使用地图方法:

 user_ids = users.map { |user| user.id } 

要么:

 user_ids = users.map(&:id) 

样品

我们可以使用rand方法:

 [1, 2, 3][rand(3)] 

洗牌:

 [1, 2, 3].shuffle.first 

而地道的,简单的和最简单的方法…样本!

 [1, 2, 3].sample 

双pipe齐平/备忘录

正如你在描述中所说的,我们可以使用记忆:

 some_variable ||= 10 puts some_variable # => 10 some_variable ||= 99 puts some_variable # => 10 

静态方法/类方法

我喜欢使用类方法,我觉得这是创build和使用类的一个非常习惯的方法:

 GetSearchResult.call(params) 

简单。 美丽。 直观。 在后台发生了什么?

 class GetSearchResult def self.call(params) new(params).call end def initialize(params) @params = params end def call # ... your code here ... end end 

有关编写惯用Ruby代码的更多信息,请阅读此处