Tag: Ruby on Rails

Global access to Rake DSL methods is deprecated – mały zgrzyt z Rake 0.9.0 i 0.9.1

Przechodząc na rake 0.9.1 możecie napotkać na taki (lub podobny) komunikat podczas odpalania zadań rake'owych na Railsowej aplikacji:

WARNING: Global access to Rake DSL methods is deprecated.  Please Include
    ...  Rake::DSL into classes and modules which use the Rake DSL methods.
WARNING: DSL method Susanoo::Application
#task called at /sciezka/rails/application.rb:215:in `initialize_tasks'

Rozwiązania są dwa. Pierwszym z nich jest powrót do 0.8.7:

sudo gem install rake -v 0.8.7
gem 'rake', '0.8.7'

Drugim jest dołączenie Rake::DSL do naszej aplikacji:

require 'rake'

module MyApp
  class Application < Rails::Application
    include Rake::DSL
    # dalsza część
  end
end

Błąd “Errno::EMFILE: Too many open files” w testach jednostkowych

Dzisiaj pisząc kolejną porcję testów do Senpuu v5, po odpaleniu ich pod RCovem i Rubym 1.8.7 napotkałem na taki oto błąd:

Errno::EMFILE: Too many open files

Błąd ten związany jest z ilością otwartych jednocześnie plików (co ciekawe nie wystąpił podczas odpalania testów pod 1.9.2). Okazuje się, że tego typu wywołania:

file = File.new(File.join(Rails.root, "sciezka/do/pliku"), 'rb')

nie są nigdy zamykane, więc otwierając przykładowo 100 plików, żaden z nich nigdy nie zostanie zamknięty (przy zamykaniu aplikacji zostana). Z czasem ilość otwartych plików narasta i po pewnym czasie następuje zgłoszenie wyżej wspomnianego wyjątku. Rozwiązanie jest nader proste: zamykajmy otwierane pliki :)

W przypadku aplikacji jest to dość proste (robimy coś na pliku, kończymy i zamykamy). Jak jednak zapanować nad otwartymi plikami w testach? Przyznam szczerze, że jestem zbyt dużym leniem aby pamiętać o zamykaniu każdego pliku otworzonego w każdym teście. Z tego względu warto zbudować sobie prosty garbage collector który zajmie się tym za nas. Jak to zrobić pokaże na przykładzie podpięcia takiego kodu pod ActiveSupport::TestCase. Nic nie stoi na przeszkodzie aby tę metodę stosować także dla innych frameworków jak np. RSpec.

W metodze setup deklarujemy zmienną instancyjną, która przechowywać będzie nasze otwarte pliki:

  def setup
    super
    # Jakis inny kod ...
    @opened_files = []
  end

W metodzie teardown zamykamy wszystko:

  def teardown
    super
    # Jakis inny kod
    @opened_files.each { |f| f.close }
  end

I ostatnia z metod - metoda otwierająca pliki i zapamiętująca je w naszej zmiennej:

  def open_file(file = nil)
    return nil if filename.nil?
    file = File.new(File.join(Rails.root, file), 'rb')
    @opened_files << file
    file
  end

Od teraz, korzystając z metody open_file nie musimy się martwić otwartymi plikami. Zostaną automatycznie zamknięte podczas wywołania metody teardown.

Copyright © 2025 Closer to Code

Theme by Anders NorenUp ↑