hamacs/ha-programming-ruby.org
2022-09-02 16:14:10 -07:00

227 lines
6.9 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+TITLE: Programming in Ruby
#+AUTHOR: Howard X. Abrams
#+DATE: 2022-09-01
#+FILETAGS: :emacs:
A literate programming file for configuring Emacs to support the Ruby programming language.
#+begin_src emacs-lisp :exports none
;;; ha-programming-ruby --- Ruby configuration. -*- lexical-binding: t; -*-
;;
;; © 2022 Howard X. Abrams
;; Licensed under a Creative Commons Attribution 4.0 International License.
;; See http://creativecommons.org/licenses/by/4.0/
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
;; Maintainer: Howard X. Abrams
;; Created: September 1, 2022
;;
;; While obvious, GNU Emacs does not include this file or project.
;;
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
;; /Users/howard.abrams/other/hamacs/ha-programming-ruby.org
;; And tangle the file to recreate this one.
;;
;;; Code:
#+end_src
* Getting Started
Ruby is probably already installed on the system, and if not, we certainly can download it from [[https://www.ruby-lang.org/en/downloads/][ruby-lang.org]], but since I need to juggle different versions for each project, I use [[https://direnv.net/docs/ruby.html][direnv]] and [[https://www.ruby-lang.org/en/documentation/installation/#ruby-install][ruby-install]]:
#+begin_src sh
brew install ruby-install
#+end_src
And then install one or more versions:
#+begin_src sh
ruby-install -U
ruby-install ruby 3
#+end_src
** Per Project
While we /could/ use a large project templating system, I keep it simple. For each project, create the following directory structure:
#+begin_example
├── Gemfile
├── Rakefile
├── lib
│   └── hello_world.rb
└── test
└── hello_world_test.rb
#+end_example
For instance:
#+begin_src sh
mkdir ~/other/ruby-xp # Change me
cd ~/other/ruby-xp
mkdir lib test
#+end_src
Now, do the following steps.
1. Create a =.envrc= file with the Ruby you want to use:
#+begin_src sh :tangle ~/other/ruby-xp/.envrc
use ruby 2.6.8
#+end_src
2. Next, get Bundler:
#+begin_src sh
gem install bundle
#+end_src
3. Create a minimal =Gemfile=:
#+begin_src ruby :tangle ~/other/ruby-xp/Gemfile
source 'https://rubygems.org'
gem 'rake', group: :development
gem 'rubocop', group: :development
gem 'solargraph', group: :development
#+end_src
4. Grab all the dependencies:
#+begin_src sh
bundle install
#+end_src
5. Create a minimal =Rakefile=:
#+begin_src ruby :tangle ~/other/ruby-xp/Rakefile
task default: %w[test]
task :run do
ruby 'lib/hello_world.rb'
end
task :test do
ruby 'test/hello_world_test.rb'
end
#+end_src
6. Create the first program:
#+begin_src ruby :tangle ~/other/ruby-xp/lib/hello_world.rb
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
#+end_src
7. Create the first test:
#+begin_src ruby :tangle ~/other/ruby-xp/test/hello_world_test.rb
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
#+end_src
Or something like that.
* Configuration
Ruby-specific commands are attached to the =ha-ruby-leader=, bound to ~SPC m~:
#+begin_src emacs-lisp
(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")
#+end_src
While Emacs supplies a Ruby editing environment, well still use =use-package= to grab the latest:
#+begin_src emacs-lisp
(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))
#+end_src
** Ruby REPL
I am not sure I can learn a new language without a REPL connected to my editor, and for Ruby, this is [[https://github.com/nonsequitur/inf-ruby][inf-ruby]]:
#+BEGIN_SRC elisp
(use-package inf-ruby
:config
(ha-ruby-leader
"R" '("REPL" . inf-ruby)))
#+END_SRC
** Electric Ruby
The [[https://melpa.org/#/ruby-electric][ruby-electric]] project is a minor mode that aims to add the /extra syntax/ when typing Ruby code.
#+begin_src emacs-lisp
(use-package ruby-electric
:hook (ruby-mode . ruby-electric-mode))
#+end_src
** Testing
The [[https://github.com/r0man/ruby-test-mode][ruby-test-mode]] project aims a running Ruby test from Emacs seemless:
#+begin_src emacs-lisp
(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)))
#+end_src
** Rubocop?
The lint-like style checker of choice for Ruby is [[https://github.com/bbatsov/rubocop][Rubocop]]. The [[https://github.com/bbatsov/rubocop-emacs][rubocop.el]] mode should work with [[https://github.com/flycheck/flycheck][Flycheck]]. First install it with:
#+begin_src sh
gem install rubocop
#+end_src
And then we may or may not need to enable the =rubocop-mode=:
#+BEGIN_SRC elisp :tangle no
(use-package rubocop
:hook (ruby-mode . rubocop-mode))
#+END_SRC
* LSP
Need to install [[https://github.com/castwide/solargraph][Solargraph]] for the LSP server experience:
#+begin_src sh
gem install solargraph
#+end_src
Or add it to your =Gemfile=:
#+begin_src ruby
gem 'solargraph', group: :development
#+end_src
* Technical Artifacts :noexport:
Let's =provide= a name so we can =require= this file:
#+begin_src emacs-lisp :exports none
(provide 'ha-programming-ruby)
;;; ha-programming-ruby.el ends here
#+end_src
#+DESCRIPTION: configuring Emacs to support the Ruby programming language.
#+PROPERTY: header-args:sh :tangle no
#+PROPERTY: header-args:emacs-lisp :tangle yes
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js