Configuring Guard to automate Ruby on Rails development

  • Tutorial
Hello! In my opinion, every programmer should strive to automate and optimize everything that moves and is not there. This article will talk about how to automate a Ruby on Rails developer workflow using a Ruby gem called Guard. This article is primarily useful to Ruby developers, but may be useful to others.

image

What is a Guard?



Guard is a tool that allows you to automatically execute any commands when changing a file. For example, when changing the server settings file, the Guard may automatically restart the server. Or you can configure LESS to automatically compile into CSS when saving the file. It all depends on how the Guard is configured by the developer.

Guard has a special Guardfile settings file, which indicates which commands to run when changing which files. You can specify all the settings yourself, or you can use the ones written by the Guard Plugins community, in which the most frequently used settings are written in advance.

Installation and first start


The best way to integrate Guard into a project is to add it to the Gemfile.

group :development do
  gem 'guard'
end

And then install it with the command

$ bundle

Then you need to create a Guardfile command

$ bundle exec guard init

Running Guard is best done using the Bundler command.

$ bundle exec guard

image

Customization for Ruby on Rails application


After installation, consider using Guard for a standard RoR project. Suppose a RoR application has already been created. Let the Guard will automatically install all the necessary gems when changing the Gemfile.

1. Adding to the project


To do this, add the guard-bundler gem to the development group in the Gemfile

group :development do
  # And updates gems when needed
  gem 'guard-bundler', require: false
end

Set gem

$ bundle install

And then initialize the plugin with the command

$ guard init bundler

Pay attention to the Guardfile located at the root of the project. Now there are lines

guard :bundler do
  watch('Gemfile')
end

It says that the Guard will monitor the Gemfile and will execute the command pre-written in the guard-bundler gem. In this case, it is

$ bundle install


2. Verification


Check it out! Enable Guard in the terminal with the command

$ bundle exec guard

Add some gem to the Gemfile. For example, guard-rspec , which will automatically run tests for Rspec.

gem 'guard-rspec', require: false

Let's open the terminal with the guard process and see that it automatically launched bundler there, as a result of which guard-rspec was automatically installed. As you can see, such a setting Guard allows the developer to automate one of the frequently performed tasks.

3. Setup


Initialize the plugin for Rspec after installing it

$ guard init rspec

Now in Guardfile there are new lines. Consider them:

# Note: The cmd option is now required due to the increasing number of ways
#       rspec may be run, below are examples of the most common uses.
#  * bundler: 'bundle exec rspec'
#  * bundler binstubs: 'bin/rspec'
#  * spring: 'bin/rsspec' (This will use spring if running and you have
#                          installed the spring binstubs per the docs)
#  * zeus: 'zeus rspec' (requires the server to be started separetly)
#  * 'just' rspec: 'rspec'
guard :rspec, cmd: 'bundle exec rspec' do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }
  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$})          { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  watch('spec/rails_helper.rb')                       { "spec" }
  # Capybara features specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$})     { |m| "spec/features/#{m[1]}_spec.rb" }
  # Turnip features and steps
  watch(%r{^spec/acceptance/(.+)\.feature$})
  watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$})   { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end

These lines configure Rspec tests to run automatically. Let's consider some of them. For example, the line

ruby watch('spec/spec_helper.rb')  { "spec” }

says that Guard will monitor the spec / spec_helper.rb file (the path relative to the project root is the Guardfile file) and whenever it changes, it will start testing the entire spec folder. Block start

ruby guard :rspec, cmd: 'bundle exec rspec’ do

says that for any rule all Rspec commands will be launched with bundle exec rspec parameters. That is, in the considered case, when changing ruby ​​spec / spec_helper.rb, the command will be launched

$ bundle exec rspec spec

Line

rubywatch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }

says that when changing any .rb file, testing of the test associated with this file will start. That is, when changing app / models / user.rb, the command will automatically run

$ bundle exec spec spec/models/user_spec.rb

Regular expressions are used to create and edit such actions. I recommend using the match command in the Ruby console for debugging, for example

"app/views/units/index.html.slim".match(%r{^app/views/(.+)/(.*)\.(.*)\.(erb|haml|slim)$})


More examples!


For Guard, a large number of plugins have been written for all occasions. Each developer should independently find the right ones for him and configure them for themselves. I will briefly describe the ones that I currently use. I myself have still not found the perfect solutions, so I will be glad to any comments and suggestions!

In gemfile



group :development, :test do
  # Integrates jasmine js testing
  gem 'jasmine-rails'
  # With guard
  gem 'guard-jasmine', git: "git://github.com/guard/guard-jasmine.git", branch: "jasmine-2"
  # Checks ruby code grammar
  gem 'rubocop', require: false
  # With rspec
  gem 'rubocop-rspec'
  # With guard
  gem 'guard-rubocop’
end
group :development do
  # Automagically launches tests for changed files
  gem 'guard'
  gem 'guard-rspec', require: false
  # And updates gems when needed
  gem 'guard-bundler', require: false
  # And auto starts rails server
  gem 'guard-rails'
  # And auto runs migrations
  gem 'guard-migrate'
end


In guardfile



# More info at https://github.com/guard/guard#readme
# https://github.com/guard/guard-bundler
guard :bundler do
  watch('Gemfile')
end
# https://github.com/guard/guard-rspec
guard :rspec, cmd: 'zeus rspec' do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  # Run the model specs related to the changed model
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  # Controller changes
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch('config/routes.rb')                           { "spec/controllers" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('spec/rails_helper.rb')                       { "spec" }
  watch('spec/spec_helper.rb')                        { "spec" }
  # Capybara features specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$})     { |m| "spec/acceptance/#{m[1]}" }
  watch(%r{^app/views/(.+)/(.*)\.(.*)\.(erb|haml|slim)$})     { |m| "spec/acceptance/#{m[1]}" }
  watch(%r{^app/views/(.+)/_.*\.(erb|haml|slim)$})     { |m| "spec/acceptance/#{m[1].partition('/').first}/#{m[1].partition('/').last}_spec.rb" }
end
# Checks any changed ruby file for code grammar
# https://github.com/yujinakayama/guard-rubocop
guard :rubocop, all_on_start: false, cli: ['--out', 'log/rubocop.log'] do
  watch(%r{^(.+)\.rb$}) { |m| "#{m[1]}.rb" }
end
# Restarts server on config changes
# https://github.com/ranmocy/guard-rails
guard :rails, zeus: true, daemon: true do
  watch('Gemfile.lock')
  watch(%r{^(config|lib)/.*})
end
# Restarts all jasmine tests on any js change
# https://github.com/guard/guard-jasmine
guard :jasmine, all_on_start: false, server_mount: '/specs' do
  watch(%r{^app/(.+)\.(js\.coffee|js|coffee)}) { "spec/javascripts" }
  watch(%r{^spec/javascripts/(.+)\.(js\.coffee|js|coffee)}) { "spec/javascripts" }
end
# Runs migrations on migrate files changes
# https://github.com/glanotte/guard-migrate
guard :migrate do
  watch(%r{^db/migrate/(\d+).+\.rb})
  watch('db/seeds.rb')
end

A bit about rubocop


image
Rubocop is a Ruby gem that allows you to check the .rb file for syntax correctness. In this example, it is configured together with the Guard, so every time you change the .rb file of Rubocop, it checks it and displays the result in the console and in the log / rubocop.log file.

Rubocop has a huge number of settings, so it can be adapted to any syntax requirements. You can even make it automatically correct the code. The .rubocop.yml file is used to configure the gem, for example, rubocop usually swears at lines longer than 90 characters, but thanks to the settings file, you can make it point only to lines larger than 140.

To see all the settings, just run the command

$ rubocop --auto-gen-config

which will create a file with all settings disabled. You can thus turn on one by one and get the final desired .rubocop.yml file.

results


What is ultimately configured? In this project, it is enough to run separate processes zeus and guard. Then the following happens:
  1. A server running through zeus Rails is automatically supported, which restarts every time the main project settings files are changed
  2. Every gemfile change installs all gems
  3. When changing any file with a test, this test is run
  4. When changing any file of controllers / models / libs / views, the associated test is launched, if any
  5. Each changed ruby ​​file is checked for literacy using rubocop
  6. When changing any javascript / coffeescript file, all jasmine tests run
  7. When you change any migration file or seeds, all necessary migrations are run

image

Thus, a sufficiently large number of processes were automated. I would like to make it so that for each project it would be enough just to launch the guard and fully focus on the creative process.

Guard example


Now I will describe the current process of working with Guard. Below are the recommendations that I gave to the other developers with whom I am currently working.
  1. Open a terminal and go to the project folder
  2. Run zeus for faster tests / server
    $ zeus start
    
  3. Launch Guard
    $ bundle exec guard
    

    Now Guard will automatically start and keep the Rails server enabled, enabled through Zeus.
  4. Run all tests by pressing Enter in the terminal. After fixing all the tests, you can work!

What you should pay attention to: when changing test files, tests will be run automatically. That is, I recommend keeping the terminal window open at the same time as the IDE window (in Rubymine, for example, you can do this right in the under window), where you can immediately see if the tests have fallen with the changes made.

image

Thanks!


Thank you for reading! I do not claim that I am an expert in Guard, so I will be glad to any comments and suggestions.

Only registered users can participate in the survey. Please come in.

Do you automate?

  • 16% Every day, every process! 24
  • 10% Several times a week, periodically 15
  • 44% Only when itching, in rare cases 66
  • 8.6% Quit! thirteen
  • 21.3% And he didn’t start, doctor! 32

Also popular now: