Общие Рубин Фразеологизмы
одна вещь, которую я люблю в ruby, заключается в том, что в основном это очень читаемый язык (который отлично подходит для самодокументированного кода)
однако, вдохновленный этим вопросом: Ruby Code explained
и описание как ||= работает в ruby, я думал о Ruby идиомы я не использую, как честно говоря, я не полностью Грок их.
Итак, мой вопрос похож на пример из упомянутого вопроса, Какие общие, но не очевидные идиомы ruby мне нужно знать, чтобы быть действительно опытным программистом ruby?
кстати, из упомянутого вопроса
a ||= b
эквивалентно
if a == nil || a == false
a = b
end
(спасибо Яну Терреллу за исправление)
Edit: оказывается, этот момент не совсем бесспорен. Правильное расширение на самом деле
(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
спасибо Йоргу W Mittag за указание на это.
15 ответов:
волшебное предложение if, которое позволяет одному и тому же файлу служить библиотекой или скриптом:
if __FILE__ == # 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' ]
этой слайдшоу довольно полно на основных идиомах 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 }сравнение типов в операторах 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... и в целом злоупотребление
===метод в операторах casecase x when 'something concrete' then ... when SomeClass then ... when /matches this/ then ... when (10...20) then ... when some_condition >= some_value then ... else ... endчто-то, что должно выглядеть естественно для рубистов, но, возможно, не так для людей, происходящих из других языков: использование
eachв пользуfor .. insome_iterable_object.each{|item| ... }в Ruby 1.9+, рельсы, или исправление символа#to_proc метод,этой становится все более популярной идиомой:
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неявные параметры splat
[[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
вот несколько, отобранных из различных источников:
используйте "если " и" пока "вместо" Если нет "и"пока нет". Однако старайтесь не использовать "если", когда существует условие "else".
помните, что вы можете назначить несколько переменных сразу:
a,b,c = 1,2,3и даже поменять переменную без temp:
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вычислить логическое значение false,a ||= bфактически (почти*) эквивалентно:if a == nil || a == false a = b endили, чтобы переписать его с другой идиомой Ruby:
a = b unless a(*так как каждое утверждение имеет значение, они технически не эквивалентны
a ||= b. Но если вы не полагаетесь на значение утверждения, вы не увидите разницы.)
вы можете deepcopy с маршалинг объекта легко. - взято из языка программирования Ruby
def deepcopy(o) Marshal.load(Marshal.dump(o)) endобратите внимание, что файлы и потоки ввода-вывода, Как а также способ и объекты привязки, слишком динамичны для маршалинга; там не было бы надежного способа восстановить свое государство.
a = (b && b.attribute) || "default"грубо:
if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b else a = "default"Я использую это, когда b-это запись, которая может быть или не быть найдена, и мне нужно получить один из ее атрибутов.
Я всегда забываю точный синтаксис этого сокращенного оператора 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.размер : 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то же самое может быть применено к case-when:
result = case test when test>0 ; "positive" when test==0 ; "zero" else "negative" end
массив.пакет и веревка.распаковать для работы с двоичными файлами:
# extracts four binary sint32s to four Integers in an Array data.unpack("iiii")
метод отсутствует магия
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)пример
мы можем использовать функцию слчис метод:
[1, 2, 3][rand(3)]Shuffle:
[1, 2, 3].shuffle.firstи идиоматический, простой и легкий способ... образец!
[1, 2, 3].sampleДвойная Труба Равна / 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, прочитайте здесь
Comments