2016-07-27 13 views
1
  1. Эйметод рубин с дополнительными опциями и & блок параметров

    Можно ли иметь дополнительные атрибуты и блок в качестве параметров для вызова метода?

    Пример: Я должен позвонить

    method(foo, foo: bar, -> { do_something } 
    

    и попытался его с

    def method(foo, *bar, &block) 
    end 
    

    Что касается моего понимания блок всегда должен быть на последнем месте?

    После небольшого исследования я узнал, что унарный (?) * представляется для массивов. Так как я стараюсь передать Hash я изменил код

    def method(foo, bar={}, &block) 
    end 
    

    Но это не делает трюк либо. Я предполагаю, потому что он наклонялся выяснить, где заканчивается бар и начинается блок.

    Любые идеи или предложения? Заранее спасибо

    Append: Только для любопытных, зачем мне это нужно. У нас есть большая схема json и есть небольшая DSL, которая строит json из определения модели . Не вдаваясь в подробности, мы хотели, чтобы реализовал exportable_scopes.

    class FooBar 
        exportable_scope :some_scope, title: 'Some Scope', -> { rewhere archived: true } 
    end 
    

    На некоторых инициализаторе это, как предполагается, происходит:

    def exportable_scope scope, attributes, &block 
        scope scope block 
        if attributes.any? 
        attributes.each do |attribute| 
         exportable_schema.scopes[scope] = attribute 
        end 
        else 
        exportable_schema.scopes[scope] = {title: scope} 
        end 
    end 
    

    Так что это работает нормально, я просто нужна подсказка для метода параметров.

+0

I ting, вы можете использовать 'exportable_scope (: some_scope, title: 'Some Scope') {rewhere archived: true}'. Вам не нужно посылать блок как параметр. –

+1

Я думаю, вы сбиваете с толку передачу блока с передачей вызываемого объекта (лямбда) в качестве аргумента, который ожидает получить ActiveRecord '.scope'. Тело области видимости требуется, поэтому вы можете изменить свою подпись метода на 'exportable_scope (name, body, attributes = {})' и называть «имя области, тело». Взгляните на определение '.scope' здесь: https://github.com/rails/rails/blob/dc925119a3912ecfe0df400007163f33b99d6385/activerecord/lib/active_record/scoping/named.rb#L143. 'exportable_scope: some_scope, -> {rewhere archived: true}, title: 'Some Scope''. –

ответ

1

Да, это возможно.

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

  1. Позиционные параметры (обязательные и необязательные) и одним параметром знак, в любом порядке;
  2. Параметры ключевого слова (обязательно и необязательно), в любом порядке;
  3. Двойной параметр splat;
  4. Параметр блока (префикс &);

Приведенный выше порядок несколько гибкий. Мы могли бы определить метод и начать список параметров с одним аргументом splat, затем несколькими необязательными позиционными аргументами и т. Д. Несмотря на то, что Ruby позволяет это, это, как правило, очень плохая практика, поскольку код будет трудно читать и даже сложнее отлаживать.Как правило, лучше всего использовать следующий порядок:

  1. Необходимые позиционные параметры;
  2. Дополнительные позиционные параметры (со значениями по умолчанию);
  3. Одиночный параметр splat;
  4. Параметры ключевого слова (обязательно и необязательно, их порядок не имеет значения);
  5. Двойной параметр splat;
  6. Явный параметр блока (с префиксом &).

Пример:

def meditate cushion, meditation="kinhin", *room_items, time: , posture: "kekkafuza", **periods, &b 
    puts "We are practicing #{meditation}, for #{time} minutes, in the #{posture} posture (ouch, my knees!)." 
    puts "Room items: #{room_items}" 
    puts "Periods: #{periods}" 
    b.call # Run the proc received through the &b parameter 
end 

meditate("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon") { puts "Hello from inside the block" } 

# Output: 
We are practicing zazen, for 40 minutes, in the kekkafuza posture (ouch, my knees!). 
Room items: ["zabuton", "incense"] 
Periods: {:period1=>"morning", :period2=>"afternoon"} 
Hello from inside the block 

Обратите внимание, что при вызове метода, мы имеем:

  • При условии, что подушка обязательного позиционную аргумент;
  • Заново занесено значение по умолчанию аргумента позиционного позиционирования медитации;
  • Пропустил пару дополнительных позиционных аргументов (закят и ладан) через параметр * room_items;
  • Предоставлено аргумент обязательного ключевого слова времени;
  • Пропущенный необязательный аргумент ключевого слова;
  • Передано несколько дополнительных аргументов ключевого слова (период1: «утро», период2: «день») через параметр ** периодов;
  • Прошел блок {puts "Hello from inside the block"} через параметр & b;

Обратите внимание на приведенный выше пример серверов, чтобы проиллюстрировать возможность смешивания различных типов параметров. Построение такого метода в реальном коде было бы плохой практикой. Если для этого метода требуется много аргументов, лучше всего разделить его на более мелкие методы. Если необходимо передать столько данных одному методу, мы должны, вероятно, создать класс для хранения данных более организованным образом, а затем передать экземпляр этого класса методу в качестве единственного аргумента.

 Смежные вопросы

  • Нет связанных вопросов^_^