Подтвердить что ты не робот

Переопределение методов Rails

Метод Rails Array#to_sentence допускает следующее:

['a', 'b', 'c'].to_sentence # gives: "a, b, and c"

Я хотел бы расширить этот метод, чтобы он мог взять блок, чтобы вы могли сделать что-то вроде следующего (где люди - это массив объектов Person, которые имеют атрибут name):

people.to_sentence { |person| person.name }
# => "Bill, John, and Mark"

У меня нет проблемы с написанием метода расширения. Но я не могу понять, где это сказать. Расширения ядра Rails загружаются где-то в глубину ActiveSupport. Моя потребность в месте, где пользовательский код всегда загружается и предварительно загружен (перед любым кодом приложения).

4b9b3361

Ответ 1

Создать config/initializers/super_to_sentence.rb. Все файлы в этом каталоге загружаются после загрузки Rails, поэтому у вас будет возможность переопределить определение Rails Array#to_sentence.

Для кода, который вы хотите загрузить до загрузки Rails, добавьте его в config/environment.rb.

Ответ 2

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

# config/initializers/app.rb
Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l }

# lib/core_ext/array.rb
class Array
  def to_sentence_with_block(*args, &block)
    if block_given?
      # do something...
      # to_sentence_without_block(*args) perhaps?
    else
      to_sentence_without_block(*args)
    end
  end
  alias_method_chain :to_sentence, :block
end

Ответ 3

Я думаю, что это уродливая идея. Почему вы просто не пишете

people.collect { |person| person.name }.to_sentence

Это выглядит почти так же и не путает других людей, читающих ваш код (например, себя через 2 года).

Ответ 4

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

поэтому, если вы хотите расширить класс ruby ​​(в моем случае DateTime), просто поместите код в .rb, а затем в config/environment.rb:

  config.after_initialize do
    require "lib/super_datetime.rb"
  end

my super_datetime.rb выглядит так (код из http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/140184):

class DateTime
  def days_in_month
    self::class.civil(year, month, -1).day
  end
  alias dim days_in_month
  def weekdays
    (1..dim).to_a
  end
end

перезагрузите сервер, и у вас будет доступ к новому методу для всех объектов DateTime.