「...の非表示機能」ミームを続けて、Rubyプログラミング言語のあまり知られていないが便利な機能を共有しましょう。
Ruby on Railsを使わずに、コアRubyでこの議論を制限するようにしてください。
以下も参照してください。
(回答ごとに1 つの非表示機能のみを入力してください。)
ありがとうございました
「...の非表示機能」ミームを続けて、Rubyプログラミング言語のあまり知られていないが便利な機能を共有しましょう。
Ruby on Railsを使わずに、コアRubyでこの議論を制限するようにしてください。
以下も参照してください。
(回答ごとに1 つの非表示機能のみを入力してください。)
ありがとうございました
回答:
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
Peter CooperがRubyトリックの優れたリストを持っています。おそらく私のお気に入りは、単一のアイテムとコレクションの両方を列挙できることです。(つまり、非コレクションオブジェクトを、そのオブジェクトのみを含むコレクションとして扱います。)次のようになります。
[*items].each do |item|
# ...
end
items
文字列の場合は、[*…]で囲む必要はありません。String.eachは、一部のユーザーが期待するように文字を反復しません。自分自身をブロックに戻すだけです。
これがどのように隠されているかはわかりませんが、1次元配列からハッシュを作成する必要があるときに便利です。
fruit = ["apple","red","banana","yellow"]
=> ["apple", "red", "banana", "yellow"]
Hash[*fruit]
=> {"apple"=>"red", "banana"=>"yellow"}
Hash[ [["apple","red"], ["banana","yellow"] ]
同じ結果が生成されることに注意してください。
私が好きなトリックの1つは*
、配列以外のオブジェクトでsplat()エキスパンダーを使用することです。正規表現の一致の例を次に示します。
match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)
その他の例は次のとおりです。
a, b, c = *('A'..'Z')
Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
text, number = *"text 555".match(/regexp/)[1..-1]
。
text, number = "Something 981".scan(/([A-z]*) ([0-9]*)/).flatten.map{|m| Integer(m) rescue m}
うわー、誰もフリップフロップ演算子について言及していません:
1.upto(100) do |i|
puts i if (i == 3)..(i == 15)
end
i == 3
切り替わり、との後 i != 3
でfalse に切り替わりますi == 15
。フリップフロップに似ています:en.wikipedia.org/wiki/Flip-flop_%28electronics%29
Rubyの優れた点の1つは、メソッドやクラスの定義など、他の言語が不快になる場所でメソッドを呼び出してコードを実行できることです。
たとえば、実行時まで不明なスーパークラスを持つ、つまりランダムなクラスを作成するには、次のようにします。
class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
end
RandomSubclass.superclass # could output one of 6 different classes.
これは1.9 Array#sample
メソッドを使用し(1.8.7のみで、を参照Array#choice
)、この例はかなり不自然ですが、ここでそのパワーを確認できます。
もう1つのすばらしい例は、(他の言語がしばしば要求するように)固定されていないデフォルトのパラメーター値を配置する機能です。
def do_something_at(something, at = Time.now)
# ...
end
もちろん、最初の例の問題は、呼び出し時ではなく定義時に評価されることです。したがって、スーパークラスが選択されると、プログラムの残りの部分はそのスーパークラスのままになります。
ただし、2番目の例では、を呼び出すたびdo_something_at
に、at
変数はメソッドが呼び出された時刻になります(まあ、それに非常に近い)
require 'activesupport'
別の小さな機能- 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"
Huw Waltersがコメントしたように、他の方法への変換も同じくらい簡単です:
>> "kf12oi".to_i(36)
=> 1234567890
String#to_s(base)
を期すために、整数に戻すために使用できます。"1001001100101100000001011010010".to_i(2)
、"499602d2".to_i(16)
などはすべてオリジナルを返しますFixnum
。
デフォルト値のハッシュ!この場合の配列。
parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []
parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"
メタプログラミングに非常に役立ちます。
1.9 Proc機能のもう1つの楽しい追加は、Proc#curryです。これにより、n個の引数を受け入れるProcを、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
非ブール値に対するブール演算子。
&&
そして ||
どちらも最後に評価された式の値を返します。
それが理由です ||=
、変数が未定義の場合に、右側の戻り値の式で変数を更新するです。これは明示的に文書化されていませんが、一般的な知識です。
しかし、それ&&=
はそれほど広く知られていません。
string &&= string + "suffix"
に相当
if string
string = string + "suffix"
end
これは、変数が未定義の場合に続行すべきでない破壊的な操作に非常に便利です。
string &&= string + "suffix"
は、 と同等 string = string && string + "suffix"
です。こと&&
とは||
、その第2引数はつるはしで議論されたpを返します。154(パートI-Rubyのファセット、式、条件付き実行)。
Railsが提供するSymbol#to_proc関数は本当にクールです。
の代わりに
Employee.collect { |emp| emp.name }
あなたは書ける:
Employee.collect(&:name)
require 'activesupport'
実際にこれらのヘルパーのほとんどがそこから来ているので、それを使って行うことができます。
最後の1つ-ルビでは、文字列を区切る任意の文字を使用できます。次のコードを見てください。
message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"
文字列内の二重引用符をエスケープしたくない場合は、単に別の区切り文字を使用できます。
contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]
区切り文字をエスケープする必要を回避するだけでなく、これらの区切り文字を使用して、より良い複数行の文字列を作成できます。
sql = %{
SELECT strings
FROM complicated_table
WHERE complicated_condition = '1'
}
define_methodコマンドを使用して動的にメソッドを生成すると、非常に興味深く、あまり知られていません。例えば:
((0..9).each do |n|
define_method "press_#{n}" do
@number = @number.to_i * 10 + n
end
end
上記のコードは、「define_method」コマンドを使用して、「press1」から「press9」までのメソッドを動的に作成します。本質的に同じコードを含む10のメソッドすべてを入力するのではなく、define methodコマンドを使用して、必要に応じてこれらのメソッドを即座に生成します。
module_functionとして宣言されたモジュールメソッドは、モジュールを含むクラスにプライベートインスタンスメソッドとして自身のコピーを作成します。
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>
引数なしで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!'
module_function
(2番目の方法)を使用する代わりに、次のように使用することもできますextend self
(かなり見栄えがよい:D)
require 'backports'
:-)
警告:このアイテムは投票されました#1 2008年の最も恐ろしいハックので、注意して使用してください。実際、疫病のようにそれを避けてください、しかしそれは最も確実に隠されたルビーです。
あなたのコードのユニークな操作のために超秘密のハンドシェイク演算子が必要ですか?コードゴルフをするのが好きですか?-〜+〜-または<---などの演算子を試してください。最後の演算子は、アイテムの順序を逆にする例で使用されています。
私はそれを賞賛する以上に、Superators Projectとは何の関係もありません。
私はパーティーに遅れましたが、
簡単に2つの同じ長さの配列を取得して、1つの配列がキーともう1つの値を提供するハッシュに変換することができます。
a = [:x, :y, :z]
b = [123, 456, 789]
Hash[a.zip(b)]
# => { :x => 123, :y => 456, :z => 789 }
(これは、Array#zipが2つの配列の値を「圧縮」するため機能します。
a.zip(b) # => [[:x, 123], [:y, 456], [:z, 789]]
そして、Hash []はまさにそのような配列を取ることができます。私も人々がこれをするのを見てきました:
Hash[*a.zip(b).flatten] # unnecessary!
同じ結果が得られますが、スプラットとフラット化は完全に不要です-おそらく、それらは過去になかったのでしょうか?)
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 } } }
これはとても便利です。
module InfHash; def self.new; Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}; end; end
Class.new()
実行時に新しいクラスを作成します。引数は派生元のクラスにすることができ、ブロックはクラス本体です。あなたはまた、見たいかもしれないconst_set/const_get/const_defined?
、新しいクラスが正しく登録さ得るためになるようにinspect
名前の代わりに、多数のうちプリント。
毎日必要なものではありませんが、必要なときにとても便利です。
MyClass = Class.new Array do; def hi; 'hi'; end; end
と同等のようclass MyClass < Array; def hi; 'hi'; end; end
です。
連続する数値の配列を作成します。
x = [*0..5]
xを[0、1、2、3、4、5]に設定します
*
)演算子は基本的にto_a
とにかく呼び出します。
Rubylandで見られる魔法の多くは、メタプログラミングに関係しています。メタプログラミングは、コードを記述するコードを記述するだけです。Rubyのattr_accessor
、attr_reader
とattr_writer
彼らは標準パターン、次の1行に2つのメソッドを、作成することで、全てのシンプルなメタプログラミングされています。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"]
メソッドWrapper.forwards
は、メソッド名のシンボルを取り、methods
配列に格納します。次に、与えられたそれぞれについて、define_method
、すべての引数とブロックを含め、メッセージを送信するのが新しいジョブの作成します。
メタプログラミングの問題に関する優れたリソースは、なぜラッキースティフの「メタプログラミングを明確に見ること」です。
===(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
Module
(したがってClass
)Regexp
、Date
および他の多くのクラスがインスタンスメソッドを定義:===(他)、及び全て使用することができます。
Ruby 1.9のようにエイリアスされることを思い出させてくれたFarrelに感謝します。Proc#call
Proc#===
「ルビー」バイナリ(少なくとも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
「ruby one-liners」と「perl one-liners」をググって、もっと便利で実用的な例がたくさんあります。基本的に、Rubyをawkおよびsedのかなり強力な代替として使用できます。
送信()メソッドは、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
この機能については、Blogging Shoes:Simple-Calcアプリケーションで詳しく説明します
一部のクラスまたはモジュールをだまして、本当に必要ではないものを必要としていることを伝えます。
$" << "something"
これは、たとえばAが必要で、次にBが必要であるが、コードでBが必要ない場合に便利です(そして、AはコードでBを使用しません)。
たとえば、Backgroundrb bdrb_test_helper requires
'test/spec'
は使用しますが、まったく使用しないので、コードでは次のようになります。
$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
Fixnum#to_s(base)
場合によっては非常に便利です。このようなケースの1つは、36の基数を使用して乱数を文字列に変換することにより、ランダムな(擬似)一意のトークンを生成することです。
長さ8のトークン:
rand(36**8).to_s(36) => "fmhpjfao"
rand(36**8).to_s(36) => "gcer9ecu"
rand(36**8).to_s(36) => "krpm0h9r"
長さ6のトークン:
rand(36**6).to_s(36) => "bvhl8d"
rand(36**6).to_s(36) => "lb7tis"
rand(36**6).to_s(36) => "ibwgeh"