Rubyについて私が気に入っていることの1つは、ほとんどが非常に読みやすい言語であることです(自己文書化コードに最適です)
しかし、この質問に触発されて Rubyコードの説明 と||=
がRubyでどのように機能するかについての説明は、Ruby率直に言って、私はそれらを完全に理解していません。
だから私の質問は、参照された質問の例と同様に、よくあるが明白ではないものですRubyイディオム本当に熟練していることを認識する必要があるRubyプログラマー?
ちなみに、参考になった質問から
a ||= b
に相当
if a == nil || a == false
a = b
end
(訂正してくれたIan Terrellに感謝)
編集:この点は完全に議論の余地がないわけではありません。正しい展開は実際には
(a || (a = (b)))
理由については、次のリンクを参照してください。
これを指摘してくれた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
クラスインスタンス変数
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"
ブロック、プロシージャ、ラムダ。生きて呼吸してください。
# 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' ]
この slideshow は、次のように、メインのRubyイディオムで完全に完了しています。
2つの値を入れ替えます。
_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 }
Caseステートメントでの型の比較
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ステートメントでの===
メソッドの全体的な不正使用
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には自然に見えるはずですが、他の言語から来た人にはそうではないかもしれません:for .. in
を優先してeach
を使用する
some_iterable_object.each{|item| ... }
Ruby 1.9 +、Rails、またはSymbol#to_procメソッドにパッチを適用することで、 this は次第に人気のイディオムになりつつあります。
strings.map(&:upcase)
条件付きメソッド/定数定義
SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)
クエリメソッドと破壊(バン)メソッド
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?
または、少なくとも私がそのようなブロックを置き換えるために使用したものです。
私は、あなたが尊敬し尊敬する人々からの人気のあるよく設計されたプラグインまたは宝石のコードを読むことをお勧めします。
私が遭遇したいくつかの例:
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
ちなみに、参考になった質問から
a ||= b
に相当
if a == nil a = b end
これは微妙に正しくなく、初心者のRubyアプリケーションのバグの原因です。
nil
とfalse
の両方(および唯一)はブール値falseに評価されるため、a ||= b
は実際には(ほぼ*)以下と同等です。
if a == nil || a == false
a = b
end
または、別のRubyイディオムで書き換えます。
a = b unless a
(*すべてのステートメントには値があるため、これらは技術的にa ||= b
と同等ではありません。ただし、ステートメントの値に依存していない場合、違いはわかりません。)
以下は、さまざまなソースから抜粋したものです。
「ない」と「しない」の代わりに「と」と「まで」を使用します。ただし、「else」条件が存在する場合は、「unless」を使用しないようにしてください。
一度に複数の変数を割り当てることができることを覚えておいてください:
a,b,c = 1,2,3
一時なしで変数をスワップすることもできます:
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
いくつかの参照:
私はいくつかのRubyイディオムとフォーマットをカバーするwikiページを維持しています:
私は常に、この省略表現の正確な構文if 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
a = (b && b.attribute) || "default"
おおよそ:
if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b
else a = "default"
これは、bが検出された、または検出されなかったレコードであり、その属性の1つを取得する必要がある場合に使用します。
マーシャリングオブジェクトを使って簡単にディープコピーできます。 -Rubyプログラミング言語から引用
def deepcopy(o)
Marshal.load(Marshal.dump(o))
end
ファイルとI/Oストリーム、およびMethodオブジェクトとBindingオブジェクトは動的すぎるため、マーシャリングできません。それらの状態を復元する信頼できる方法はありません。
マジックが欠落しているメソッド
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を書くような、あなたが知らない;すべてのメソッドとパラメーター名を知っていない
いい質問だ!
直感的で高速なコードであるほど、私たちが構築しているソフトウェアは優れています。 Rubyをコードの小さなスニペットで使用して、私の考えをどのように表現するかを示します。 詳細はこちら
マップ
Mapメソッドはさまざまな方法で使用できます。
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
Double Pipe Equals/Memoization
説明で述べたように、メモを使用できます。
some_variable ||= 10
puts some_variable # => 10
some_variable ||= 99
puts some_variable # => 10
静的メソッド/クラスメソッド
私はクラスメソッドを使用したいのですが、クラスを作成して使用するための本当に慣用的な方法だと思います。
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コード、以下をお読みください こちら
バイナリファイルを操作するためのArray.packおよびString.unpack:
# extracts four binary sint32s to four Integers in an Array
data.unpack("iiii")