squ*_*tte 160 ruby hidden-features
继续"隐藏的......的特征"模因,让我们分享Ruby编程语言鲜为人知但有用的功能.
尝试用核心Ruby限制这个讨论,没有任何Ruby on Rails的东西.
也可以看看:
(请注意,每个答案只有一个隐藏的功能.)
谢谢
Far*_*rel 80
从Ruby 1.9 Proc#===是Proc#call的别名,这意味着Proc对象可以在case语句中使用,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
Jam*_*sen 76
Peter Cooper有很多 Ruby技巧.也许我最喜欢的是允许枚举单个项目和集合.(也就是说,将非集合对象视为仅包含该对象的集合.)它看起来像这样:
[*items].each do |item|
# ...
end
Run Code Online (Sandbox Code Playgroud)
小智 64
不知道这是多么隐蔽,但我发现当需要从一维数组中创建哈希时它很有用:
fruit = ["apple","red","banana","yellow"]
=> ["apple", "red", "banana", "yellow"]
Hash[*fruit]
=> {"apple"=>"red", "banana"=>"yellow"}
Run Code Online (Sandbox Code Playgroud)
tom*_*fro 54
我喜欢的一个技巧是*在Arrays以外的对象上使用splat()扩展器.以下是正则表达式匹配的示例:
match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)
Run Code Online (Sandbox Code Playgroud)
其他例子包括:
a, b, c = *('A'..'Z')
Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
Run Code Online (Sandbox Code Playgroud)
Kon*_*ase 52
哇,没人提到触发器操作员:
1.upto(100) do |i|
puts i if (i == 3)..(i == 15)
end
Run Code Online (Sandbox Code Playgroud)
Bo *_*nes 49
关于ruby的一个很酷的事情是,你可以调用方法并在其他语言不喜欢的地方运行代码,例如在方法或类定义中.
例如,要创建一个具有未知超类的类,直到运行时,即是随机的,您可以执行以下操作:
class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
end
RandomSubclass.superclass # could output one of 6 different classes.
Run Code Online (Sandbox Code Playgroud)
这使用1.9 Array#sample方法(仅在1.8.7中,见Array#choice),这个例子非常人为,但你可以看到这里的力量.
另一个很酷的例子是能够放置非固定的默认参数值(就像其他语言经常要求的那样):
def do_something_at(something, at = Time.now)
# ...
end
Run Code Online (Sandbox Code Playgroud)
当然,第一个例子的问题是它是在定义时而不是通话时间进行评估的.因此,一旦选择了超类,它就会保留该程序其余部分的超类.
但是,在第二个示例中,每次调用时do_something_at,at变量都将是调用方法的时间(嗯,非常接近它)
tom*_*fro 47
另一个微小的功能 - 将一个Fixnum基本转换为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"
Run Code Online (Sandbox Code Playgroud)
正如Huw Walters评论的那样,转换另一种方式同样简单:
>> "kf12oi".to_i(36)
=> 1234567890
Run Code Online (Sandbox Code Playgroud)
Aug*_*aas 40
具有默认值的哈希值!在这种情况下的数组.
parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []
parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"
Run Code Online (Sandbox Code Playgroud)
在元编程中非常有用.
man*_*eru 39
下载Ruby 1.9源代码并发布make golf,然后您可以执行以下操作:
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"
Run Code Online (Sandbox Code Playgroud)
阅读golf_prelude.c更隐蔽的东西.
Far*_*rel 38
1.9 Proc功能中另一个有趣的补充是Proc#curry,它允许你将Proc接受n个参数转换成一个接受n-1的参数.在这里它与我上面提到的Proc#===提示相结合:
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
Run Code Online (Sandbox Code Playgroud)
EmF*_*mFi 35
非布尔值的布尔运算符.
&& 和 ||
两者都返回最后一个表达式的值.
这就是为什么||=如果变量未定义,将使用右侧返回值表达式更新变量.这没有明确记录,但是常识.
然而,&&=并不是那么广为人知.
string &&= string + "suffix"
Run Code Online (Sandbox Code Playgroud)
相当于
if string
string = string + "suffix"
end
Run Code Online (Sandbox Code Playgroud)
如果变量未定义,那么破坏性操作非常方便.
hoy*_*hoy 29
Rails提供的Symbol#to_proc函数非常酷.
代替
Employee.collect { |emp| emp.name }
Run Code Online (Sandbox Code Playgroud)
你可以写:
Employee.collect(&:name)
Run Code Online (Sandbox Code Playgroud)
tom*_*fro 28
最后一个 - 在ruby中,您可以使用任何想要分隔字符串的字符.请使用以下代码:
message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"
Run Code Online (Sandbox Code Playgroud)
如果您不想转义字符串中的双引号,则只需使用不同的分隔符:
contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]
Run Code Online (Sandbox Code Playgroud)
除了避免转义分隔符之外,您还可以使用这些分隔符来获得更好的多行字符串:
sql = %{
SELECT strings
FROM complicated_table
WHERE complicated_condition = '1'
}
Run Code Online (Sandbox Code Playgroud)
Cod*_*nts 26
我发现使用define_method命令动态生成非常有趣的方法,而不是众所周知的.例如:
((0..9).each do |n|
define_method "press_#{n}" do
@number = @number.to_i * 10 + n
end
end
Run Code Online (Sandbox Code Playgroud)
上面的代码使用'define_method'命令动态创建方法"press1"到"press9".而不是键入所有10个特别包含相同代码的方法,define method命令用于根据需要动态生成这些方法.
hor*_*guy 26
使用Range对象作为无限延迟列表:
Inf = 1.0 / 0
(1..Inf).take(5) #=> [1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
更多信息:http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
new*_*ple 23
声明为module_function的模块方法将在包含Module的类中创建自身的副本作为私有实例方法:
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>
Run Code Online (Sandbox Code Playgroud)
如果使用不带任何参数的module_function,那么在module_function语句之后的任何模块方法将自动成为module_functions.
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!'
Run Code Online (Sandbox Code Playgroud)
小智 23
短注射,如下:
(1..10).inject(:+)
=> 55
Run Code Online (Sandbox Code Playgroud)
小智 21
警告:这个项目被评选为2008年最可怕的黑客,所以谨慎使用.实际上,避免它像瘟疫一样,但它肯定是隐藏的红宝石.
有没有想要一个超级秘密握手操作符来代码中的一些独特操作?喜欢打码高尔夫?尝试像 - 〜+〜 - 或<---这样的运算符,在示例中使用最后一个来反转项目的顺序.
除了欣赏它之外,我与Superators项目无关.
Jor*_*ing 19
我迟到了,但是:
您可以轻松地将两个等长数组转换为哈希,其中一个数组提供键,另一个数组提供值:
a = [:x, :y, :z]
b = [123, 456, 789]
Hash[a.zip(b)]
# => { :x => 123, :y => 456, :z => 789 }
Run Code Online (Sandbox Code Playgroud)
(这是因为Array#zip"拉上"两个数组的值:
a.zip(b) # => [[:x, 123], [:y, 456], [:z, 789]]
Run Code Online (Sandbox Code Playgroud)
而Hash []可以采用这样的数组.我见过人们这样做:
Hash[*a.zip(b).flatten] # unnecessary!
Run Code Online (Sandbox Code Playgroud)
这产生了相同的结果,但是完全不需要splat和flatten - 也许它们不是在过去?)
Tre*_*oke 19
在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 } } }
Run Code Online (Sandbox Code Playgroud)
这可能太方便了.
hor*_*guy 16
解构数组
(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]
Run Code Online (Sandbox Code Playgroud)
哪里:
a #=> :a
b #=> :b
c #=> :c
d #=> [:d1, :d2]
Run Code Online (Sandbox Code Playgroud)
使用这种技术,我们可以使用简单的赋值从任何深度的嵌套数组中获取我们想要的精确值.
Jus*_*ove 15
Class.new()
在运行时创建一个新类.参数可以是派生的类,块是类体.您可能还希望查看const_set/const_get/const_defined?正确注册的新类,以便inspect打印出名称而不是数字.
不是你每天都需要的东西,但是当你这样做时非常方便.
TAL*_*ama 13
您在Rubyland中看到的许多魔力与元编程有关,元编程只是编写为您编写代码的代码.Ruby的attr_accessor,attr_reader和attr_writer都是简单元编程,因为它们创造一个线上的两个方法,按照标准模式.Rails用他们的关系管理方法做了很多元编程,比如has_one和belongs_to.
但是使用class_eval动态编写的代码创建自己的元编程技巧非常简单.
以下示例允许包装器对象将某些方法转发到内部对象:
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"]
Run Code Online (Sandbox Code Playgroud)
该方法Wrapper.forwards采用方法名称的符号并将它们存储在methods数组中.然后,对于每个给定的,我们使用define_method创建一个新方法,其作用是发送消息,包括所有参数和块.
元编程问题的一个重要资源是为什么Lucky Stiff的"明确地看到元编程".
hor*_*guy 13
创建一个连续数字的数组:
x = [*0..5]
Run Code Online (Sandbox Code Playgroud)
将x设置为[0,1,2,3,4,5]
Jam*_*sen 12
使用任何响应===(obj)案例比较的东西:
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
Run Code Online (Sandbox Code Playgroud)
Module(因此Class), ,Regexp,Date和许多其他类定义一个实例方法:===(其他),并都可以使用.
感谢Farrel在Ruby 1.9中提醒Proc#call别名Proc#===.
min*_*uib 11
"ruby"二进制文件(至少是MRI)支持许多使perl单行程非常流行的开关.
重要的:
put在每次循环迭代结束时使用自动s一些例子:
# 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
Run Code Online (Sandbox Code Playgroud)
随意谷歌"ruby one-liners"和"perl one-liners"获取更多可用和实用的例子.它基本上允许你使用ruby作为awk和sed的相当强大的替代品.
Cod*_*nts 10
所述的send()方法是可以在任何的Ruby类或对象中使用的通用方法.如果没有重写,send()接受一个字符串并调用传递其字符串的方法的名称.例如,如果用户单击"Clr"按钮,则会将'press_clear'字符串发送到send()方法,并调用'press_clear'方法.send()方法允许以有趣和动态的方式调用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
Run Code Online (Sandbox Code Playgroud)
我在Blogging Shoes中详细介绍了这个功能:Simple-Calc应用程序
愚弄一些类或模块告诉它需要一些它真正不需要的东西:
$" << "something"
Run Code Online (Sandbox Code Playgroud)
这很有用,例如当需要A反过来需要B但我们的代码中不需要B(并且A不会通过我们的代码使用它):
例如,Backgroundrb's bdrb_test_helper requires 'test/spec',但你根本不使用它,所以在你的代码中:
$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
Run Code Online (Sandbox Code Playgroud)
Fixnum#to_s(base)在某些情况下可能非常有用.一种这样的情况是通过使用36的基数将随机数转换为字符串来生成随机(伪)唯一令牌.
长度为8的令牌:
rand(36**8).to_s(36) => "fmhpjfao"
rand(36**8).to_s(36) => "gcer9ecu"
rand(36**8).to_s(36) => "krpm0h9r"
Run Code Online (Sandbox Code Playgroud)
长度为6的令牌:
rand(36**6).to_s(36) => "bvhl8d"
rand(36**6).to_s(36) => "lb7tis"
rand(36**6).to_s(36) => "ibwgeh"
Run Code Online (Sandbox Code Playgroud)
定义一个接受任意数量参数的方法,然后将它们全部丢弃
def hello(*)
super
puts "hello!"
end
Run Code Online (Sandbox Code Playgroud)
上面的hello方法只需要puts "hello"在屏幕上调用super- 但由于超类hello定义了它必须的参数 - 但是因为它实际上不需要使用参数本身 - 它不必给它们一个名字.
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly
Run Code Online (Sandbox Code Playgroud)
看起来像Ruby的酷和(在某些情况下)漂亮/有用的黑客/功能.
如何基于ARGV [0]打开文件?
readfile.rb:
$<.each_line{|l| puts l}
ruby readfile.rb testfile.txt
Run Code Online (Sandbox Code Playgroud)
这是编写一次性脚本的一个很好的捷径.大多数人都不知道有大量预先定义的变量.明智地使用它们(读:不要乱丢你打算用它们维护的代码库,它可能会变得混乱).
我觉得这在一些脚本中很有用.它可以直接使用环境变量,例如shell脚本和Makefile.环境变量用作未定义的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
Run Code Online (Sandbox Code Playgroud)
要将多个正则表达式组合在一起|,您可以使用
Regexp.union /Ruby\d/, /test/i, "cheat"
Run Code Online (Sandbox Code Playgroud)
创建一个类似于的Regexp:
/(Ruby\d|[tT][eE][sS][tT]|cheat)/
Run Code Online (Sandbox Code Playgroud)
我是粉丝:
%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]
Run Code Online (Sandbox Code Playgroud)
这有点太有趣了.
def getCostAndMpg
cost = 30000 # some fancy db calls go here
mpg = 30
return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"
Run Code Online (Sandbox Code Playgroud)
i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
(在大多数语言中,当找不到方法并且抛出错误并且程序停止时.在ruby中,您实际上可以捕获这些错误并且可能在这种情况下做一些聪明的事情)
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)
Run Code Online (Sandbox Code Playgroud)
五
我不知道减法的方法
零
| 归档时间: |
|
| 查看次数: |
41145 次 |
| 最近记录: |