常见的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应用程序中的一个错误。
既然(而且只有) nil
和false
评估为布尔型假, a ||= b
实际上(几乎*)等价于:
if a == nil || a == false a = b end
或者,用另一个Ruby成语来重写:
a = b unless a
(*因为每个语句都有一个值,所以这些语句在技术上并不等价于a ||= b
,但是如果你不依赖于语句的值,你将不会看到区别。
我维护一个涵盖一些Ruby成语和格式的wiki页面:
你可以用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代码的更多信息,请阅读此处