hamacs/ha-programming-ruby.org
Howard Abrams 01a0958e6f Update the copyright year
This really was a lark to see if I could change ALL the files using
woccur and a regular expression. Quite please with how simple that was.
2023-02-23 09:35:36 -08:00

7.2 KiB
Raw Blame History

Programming in Ruby

A literate programming file for configuring Emacs to support the Ruby programming language.

Getting Started

Ruby is probably already installed on the system, and if not, we certainly can download it from ruby-lang.org, but since I need to juggle different versions for each project, I use direnv and ruby-install:

  brew install ruby-install

And then install one or more versions:

  ruby-install -U
  ruby-install ruby 3

Per Project

While we could use a large project templating system, I keep it simple. For each project, create the following directory structure:

├── Gemfile
├── Rakefile
├── lib
│   └── hello_world.rb
└── test
    └── hello_world_test.rb

For instance:

  mkdir ~/other/ruby-xp    # Change me
  cd ~/other/ruby-xp
  mkdir lib test

Now, do the following steps.

  1. Create a .envrc file with the Ruby you want to use:

      use ruby 2.6.8
  2. Next, get Bundler:

      gem install bundle
  3. Create a minimal Gemfile:

      source 'https://rubygems.org'
    
      gem 'rake', group: :development
      gem 'rubocop', group: :development
      gem 'solargraph', group: :development
  4. Grab all the dependencies:

      bundle install
  5. Create a minimal Rakefile:

      task default: %w[test]
    
      task :run do
        ruby 'lib/hello_world.rb'
      end
    
      task :test do
        ruby 'test/hello_world_test.rb'
      end
  6. Create the first program:

      class HelloWorld
        attr_reader :name
    
        def initialize(name = nil)
          @name = name
        end
    
        def greeting
          if @name
            "Hello there, #{@name}"
          else
            'Hello World!'
          end
        end
      end
    
      puts HelloWorld.new.greeting
  7. Create the first test:

      require 'test/unit'
      require_relative '../lib/hello_world'
    
      class TestHelloWorld < Test::Unit::TestCase
        def test_default
          assert_equal 'Hello World!', HelloWorld.new.greeting
        end
    
        def test_name
          assert_equal 'Hello there, Bob', HelloWorld.new('Bob').greeting
        end
      end

Or something like that.

Configuration

Ruby-specific commands are attached to the ha-ruby-leader, bound to SPC m:

  (general-create-definer ha-ruby-leader
      :states '(normal visual motion)
      :keymaps 'ruby-mode-map
      :prefix "SPC m"
      :global-prefix "<f17>"
      :non-normal-prefix "S-SPC")

While Emacs supplies a Ruby editing environment, well still use use-package to grab the latest:

  (use-package ruby-mode
    :after projectile
    :mode (rx ".rb" eos)
    :mode (rx "Rakefile" eos)
    :mode (rx "Gemfile" eos)
    :mode (rx "Berksfile" eos)
    :mode (rx "Vagrantfile" eos)
    :interpreter "ruby"

    :init
    (setq ruby-indent-level 2
          ruby-indent-tabs-mode nil)

    :hook (ruby-mode . superword-mode))

Ruby REPL

I am not sure I can learn a new language without a REPL connected to my editor, and for Ruby, this is inf-ruby:

  (use-package inf-ruby
    :config
    (ha-ruby-leader
      "R" '("REPL" . inf-ruby)))

Electric Ruby

The ruby-electric project is a minor mode that aims to add the extra syntax when typing Ruby code.

  (use-package ruby-electric
    :hook (ruby-mode . ruby-electric-mode))

Testing

The ruby-test-mode project aims a running Ruby test from Emacs seemless:

  (use-package ruby-test-mode
    :hook (ruby-mode . ruby-test-mode)

    :config
    (ha-ruby-leader
      "t"  '(:ignore t :which-key "test")
      "t t" '("test one" . ruby-test-run-at-point)
      "t g" '("toggle code/test" . ruby-test-toggle-implementation-and-specification)
      "t A" '("test all" . ruby-test-run)
      "t a" '("retest" . ruby-test-rerun)))

Rubocop?

The lint-like style checker of choice for Ruby is Rubocop. The rubocop.el mode should work with Flycheck. First install it with:

  gem install rubocop

And then we may or may not need to enable the rubocop-mode:

  (use-package rubocop
    :hook (ruby-mode . rubocop-mode))

Auxiliary Support

Cucumber

Seems that to understand and edit Cucumber feature definitions, you need cucumber.el:

  (use-package feature-mode)

LSP

Need to install Solargraph for the LSP server experience:

  gem install solargraph

Or add it to your Gemfile:

  gem 'solargraph', group: :development