Общие идиомы Ruby

Используйте pathlib . PurePath предлагают абстрактный интерфейс к объектам, подобным путям, которые не имеют отношения к файловой системе. В частности, PurePosixPath - это тот тип, который использует прямую косую черту (/) в качестве разделителей:

>>> from pathlib import PurePosixPath
>>> p = PurePosixPath('/house/dogs/ralph/bone')
>>> str(p.parent)
/house/dogs/ralph
>>> str(p.parent.parent)
/house/dogs

Вы можете сделать это легко:

p = PurePosixPath(...)
while p != p.root:
    # Do stuff to p
    p = p.parent

[1112 ] Достаточно питонным завершающим штрихом было бы сделать его генератором:

def receding_path(p):
    p = PurePosixPath(p)
    while p != p.root:
        yield str(p)
        p = p.parent

for item in receding_path('/house/dogs/ralph/bone'):
    # do stuff to each item

63
задан Community 23 May 2017 в 12:02
поделиться

9 ответов

Волшебное выражение 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"

Блоки, procs, и лямбды. Живите и вдохните их.

 # 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' ]
50
ответ дан Marcus Buffett 24 November 2019 в 16:23
поделиться

Между прочим, от вопроса, на который ссылаются

a ||= b 

эквивалентно [1 110]

if a == nil   
  a = b 
end

, Это тонко неправильно, и является источником ошибок в приложениях Ruby вновь прибывших.

С тех пор и (и только) nil и false оценивают к булевой лжи, a ||= b на самом деле (почти*) эквивалентен:

if a == nil || a == false
  a = b
end

Или, для перезаписи его с другой идиомой Ruby:

a = b unless a

(*Since каждый оператор имеет значение, они не технически эквивалентны a ||= b. Но если Вы не будете полагаться на значение оператора, то Вы не будете видеть различия.)

5
ответ дан Ian Terrell 24 November 2019 в 16:23
поделиться

Вот некоторые, отобранные из различных источников:

использование, "если" и "до" вместо, "если не" и, "в то время как нет". Попытайтесь не использовать "если", когда "еще" условие будет существовать, все же.

Помнят, что можно присвоить несколько переменных сразу:

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

Некоторые ссылки:

5
ответ дан Mike Woodhouse 24 November 2019 в 16:23
поделиться

Я предложил бы прочитать код популярных и хорошо разработанных плагинов или драгоценных камней от людей, которыми Вы восхищаетесь и уважаете.

Некоторые примеры я столкнулся:

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
7
ответ дан ucron 24 November 2019 в 16:23
поделиться

Мне нравится это:

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?

Или по крайней мере это - то, что я раньше заменял такие блоки.

7
ответ дан Daemin 24 November 2019 в 16:23
поделиться

Этот слайд-шоу довольно завершен на основных идиомах Ruby, как в:

  • Подкачка два значения:

    x, y = y, x

  • Параметры, что, если не определенный, берут некоторое значение по умолчанию

    def somemethod(x, y=nil)

  • Пакеты посторонние параметры в массив

    def substitute(re, str, *rest)

И так далее...

11
ответ дан avguchenko 24 November 2019 в 16:23
поделиться

Array.pack и String.unpack для работы с бинарными файлами:

# extracts four binary sint32s to four Integers in an Array
data.unpack("iiii") 
0
ответ дан 24 November 2019 в 16:23
поделиться

Вы можете легко копировать с помощью объекта Marshaling. - взято из языка программирования Ruby

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end

. Обратите внимание, что файлы и потоки ввода-вывода, как а также объекты Method и Binding, слишком динамичны, чтобы их можно было маршалировать; там не было бы надежного способа восстановить их состояние.

1
ответ дан 24 November 2019 в 16:23
поделиться

Еще несколько идиом:

Использование разделителей %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

То, что должно выглядеть естественно для рубистов, но может быть не так для людей, пришедших из других языков: использование each в пользу for ... in

some_iterable_object.each{|item| ... }

В Ruby 1. 9+, Rails или при исправлении метода Symbol#to_proc, this становится все более популярной идиомой:

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})" }
8
ответ дан 24 November 2019 в 16:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: