Here are some hints on best practices to maintain your tasks in larger projects.
Rake Tasks vs. Scripts
- The Rails default is using rake tasks for your application tasks. These live in
lib/tasks/*
. - In case you want to avoid rake for your tasks and just use plain ruby scripts, consider
lib/scripts/*
as folder.
Keeping tasks slim
For readability and testing it's easier to keep your tasks slim. We suggest to use folders inside the tasks
or scripts
folder.
Example for a task:
The slim task lib/tasks/gitlab.rb
:
# bundle exec rake gitlab:user_export
namespace :gitlab do
desc 'Export all users as XSLX'
task user_export: :environment do
Gitlab::UserExport.new.export
end
end
The main code lib/tasks/gitlab/user_export.rb
:
module Gitlab
class UserExport
def export
# Your code of exporting all users e.g. into a XSLX file
end
end
end
Example for a script:
The slim ruby script: lib/scripts/user_export.rb
:
# bundle exec rails runner -e development lib/scripts/user_export.rb
Gitlab::UserExport.new.export
The main code lib/scripts/gitlab/user_export.rb
:
module Gitlab
class UserExport
def export
# Your code of exporting all users e.g. into a XSLX file
end
end
end
Testing should not be optional
Tasks should be tested the same way as other code, even if they are only run once.
Example:
spec/lib/tasks/gitlab/user_export_spec.rb
or spec/lib//scripts/gitlab/user_export_spec.rb
:
describe Gitlab::UserExport do
it 'should export all users as XLSX file' do
# Your code for testing all edge cases in the user export
end
end
As rake task: spec/lib/tasks/gitlab_spec.rb
:
describe 'lib/scripts/gitlab.rb' do
it 'calls the user export' do
Rake::Task['gitlab:user_export'].invoke
# Your code for testing e.g. that a file user_export.xlsx is written to disk (smoke test)
end
end
As plain ruby script: lib/scripts/gitlab_spec.rb
:
describe 'lib/scripts/gitlab.rb' do
let(:script) { Rails.root.join(subject) }
it 'calls the user export' do
load(script)
# Your code for testing e.g. that a file user_export.xlsx is written to disk (smoke test)
end
end
RSpec setup
RSpec setup that avoids rewriting your scripts in a special way to make them testable:
module ScriptSpecHelpers
def run_script(script_path, *args)
stub_const('ARGV', args.map!(&:to_s))
load(script_path, true)
end
end
RSpec.configure do |config|
config.define_derived_metadata(file_path: Regexp.new('/spec/script')) do |metadata|
metadata[:type] = :script
end
config.include ScriptSpecHelpers, type: :script
end
# example usage spec/script/demo_spec.rb
describe 'script/some_script.rb' do
it 'can be tested' do
some_setup
run_script(subject, 42, 'some_arg')
assert_something
end
end