###

alias hbin me

Handle 301 Redirection in Ruby

While I send a GET request to some URI, I got a 301 MOVED PERMANENTLY response returned.

Here is the code:

1
2
require 'net/http'
response = Net::HTTP.get_response(URI(http://***/xyz))

The response’s status code is 301 and body is a empty string.

Solution

  • Use open-uri, open-uri handles redirects automatically.
1
2
require 'open-uri'
response = open('http://***/xyz')
  • Handle redirects with Net::HTTP
1
2
3
4
5
6
7
def get_response_with_redirect(uri)
   r = Net::HTTP.get_response(uri)
   if r.code == "301"
     r = Net::HTTP.get_response(URI.parse(r.header['location']))
   end
   r
end
  • Use the correct URI

The reason that the URI returns a 301 redirection is the trailing slashes are misused. Historically, it’s common for URLs with a trailing slash to indicate a directory, and those without a trailing slash to denote a file:

1
2
http://example.com/foo/ (with trailing slash, conventionally a directory)
http://example.com/foo  (without trailing slash, conventionally a file)

References:

  1. http://stackoverflow.com/questions/7210232/ruby-nethttp-following-301-redirects
  2. http://stackoverflow.com/questions/5948659/trailing-slash-in-urls-which-style-is-preferred

The Ultimate Solution of Emacs Finding Tags in a Rails Project

Emacs is my favorite text editor. I do a lot of Ruby on Rails programming using it. It’s really handy, useful and hacky for me ;)

Sometimes, I want to jump to the definition of a method or a class/module, I will use the ctags tool to build a TAGS file in the root of my project.

1
ctags -e -R --extra=+fq --exclude=db --exclude=doc --exclude=log --exclude=tmp --exclude=.git --exclude=public . $(rvm gemdir)/gems

The appending $(rvm gemdir)/gems will including Rails build-in method(or class/module) definitions, it’s very useful to browse Rails source code.

Formerly, I use the Emacs build-in find-tag command which bounding to M-. to find the tags. It works, but what annoy me is that everytime I find-tag, it prompt to choose a tag, even the first one always what I want. So I write a command to take the place of default find-tag:

1
2
3
4
(defun hbin-find-tag ()
  (interactive)
  (find-tag (find-tag-default)))
(global-set-key (kbd "M-.") 'hbin-find-tag)

It seems that things goes well. But I found that If a method defined in many places. find-tag only jump to one of them, and without any prompt. This misguide me occasionally.

After some google search, I found a package Etags-Select provides a feature to find tag from multiple tag files, and if there are multiple matching tags, it will open a selection window for you to choose the one you want.

Sounds great! eh?

After give it a try, I found it’s not that perfect(not perfect for ruby code at least). It can’t jump to the definition of a method whose name ending with a question mark! e.g. signed_in?. After a wandering around the source code of Etags-Select, I decide to ‘fix’ it by myself. And finally, I made it! Yeah!

It’s showtime ;)

Firstly, git clone my forked Etags-Select version and add it to your Emacs load-path, you may also need to install eproject and s.el first.

1
2
3
;;; Installation of Etags-select
(add-to-list 'load-path "/path/to/my-etags-select")
(require 'etags-select)

Secondly, add following snippets to your emacs dotfile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(require 'thingatpt)

(defun thing-after-point ()
  "Things after point, including current symbol."
  (if (thing-at-point 'symbol)
      (save-excursion
        (let ((from (beginning-of-thing 'symbol))
              (to   (end-of-thing 'line)))
          (and (> to from)
               (buffer-substring-no-properties from to))))))

(defun ruby-thing-at-point ()
  "Get ruby thing at point.
   1. thing at 'current_user'   get current_user;
   2. thing at '!current_user'  get current_user;
   3. thing at 'current_user!'  get current_user!;
   4. thing at 'current_user='  get current_user=;
   5. thing at 'current_user =' get current_user=;
   6. thing at 'current_user ==' get current_user;
   7. thing at 'current_user ||=' get current_user=;
   Otherwise, get `find-tag-default symbol."
  (if (member (symbol-name major-mode)
              '("ruby-mode" "rhtml-mode" "haml-mode" "slim-mode"))
      (let ((symbol (thing-at-point 'symbol))
            (remain (thing-after-point)))
        (if (and symbol remain)
            (let ((sym (s-chop-prefixes '("!!" "!") symbol))
                  (rem (s-chop-prefixes '("!!" "!") remain)))
              (if (s-matches? (concat "^" sym "\\( *\\(||\\)?=[^=]\\)") rem)
                  (concat sym "=")
                sym))
          (find-tag-default)))
    (find-tag-default)))

(defun visit-project-tags ()
  (let ((tags-file (concat (eproject-root) "TAGS")))
    (visit-tags-table tags-file)
    (message (concat "Loaded " tags-file))))

(defun hbin-build-ctags ()
  "Build ctags file at the root of current project."
  (interactive)
  (let ((root (eproject-root)))
    (shell-command
     (concat "ctags -e -R --extra=+fq "
             "--exclude=db --exclude=doc --exclude=log --exclude=tmp --exclude=.git --exclude=public "
             "-f " root "TAGS " root)))
  (visit-project-tags)
  (message "TAGS built successfully"))

(defun hbin-etags-find-tag ()
  "Borrow from http://mattbriggs.net/blog/2012/03/18/awesome-emacs-plugins-ctags/"
  (interactive)
  (if (file-exists-p (concat (eproject-root) "TAGS"))
      (visit-project-tags)
    (hbin-build-ctags))
  (etags-select-find (ruby-thing-at-point)))

(global-set-key (kbd "M-.") 'hbin-etags-find-tag)

Thirdly, The Forgotten snippets

1
2
3
4
5
;; Modify syntax entry
(defun hbin-ruby-mode-init ()
  (modify-syntax-entry ?? "w")
  (modify-syntax-entry ?! "w"))
(add-hook 'ruby-mode-hook 'hbin-ruby-mode-init)

Notice!! According to which template language you prefer, you may need to modify-syntax-entry for that major mode. For example to rhtml

1
2
3
4
(defun hbin-rhtml-mode-init ()
  (modify-syntax-entry ?? "w")
  (modify-syntax-entry ?! "w"))
(add-hook 'rhtml-mode-hook 'hbin-rhtml-mode-init)

DONE and ENJOY IT!

Let me show you some scenes.

1
2
3
4
5
6
7
8
9
current_user              # jump to current_user definition
!current_user.nil?        # jump to current_user definition
current_user == User.find # jump to current_user definition

signed_in?                # jump to signed_in? definition
self.current_user = nil   # jump to current_user= definition
current_user ||= User.new # jump to current_user= definition

current_user!             # jump to current_user! definition

It’s awesome! Cheer up!

At last

I’m not good at writing emacs lisp code, any bug report and bug fix pull request are welcome!

Cleanup the Emacs Mode Line

Look at the bottom of the Emacs frame, there is a distinctive line above the minibuffer, it’s mode-line. This displays various information about what is going on in the buffer, such as whether there are unsaved changes, the editing modes that are in use, the current line number, and so forth.

After installed several add-ons, you may find that the mode-line occupied by the minor-mode indicators. As follow:

Not all of the indicators are useful for me, even more, they (but not the minor mode) pollute the mode-line, so I want to save the limited spaces.

  • DIY

    First, you should add this function to your .emacs.

1
2
3
(defun hbin-remove-mm-lighter (mm)
  "Remove minor lighter from the mode line."
  (setcar (cdr (assq mm minor-mode-alist)) nil))

Then, customize the minor mode as follow:

1
2
3
4
(hbin-remove-mm-lighter 'autopair-mode)
(hbin-remove-mm-lighter 'textmate-mode)
(hbin-remove-mm-lighter 'eproject-mode)
(hbin-remove-mm-lighter 'whole-line-or-region-mode)
  • Diminish plugin

    diminish is a package that diminishes the amount of space taken on the mode line by the names of minor modes. After installed it handy, costomize as follow:

1
2
3
4
(eval-after-load "autopair" '(diminish 'autopair-mode))
(eval-after-load "textmate" '(diminish 'textmate-mode))
(eval-after-load "eproject" '(diminish 'eproject-mode))
(eval-after-load "whole-line-or-region" '(diminish 'whole-line-or-region-mode))

END!

Emacs User Tips for Rails

Emacs is my favorite text editor. I have been used Emacs for 8 months. And recently I’m learning Ruby on Rails following the Ruby on Rails Tutorial written by Michael Hartl.

Here is my Emacs tricks for programming Rails:

  • Shortcut For Inserting Arrows

    There are so many hash rockets. It’s a good practise to bind some key to insert it handy.

1
2
3
4
5
6
7
8
;;;###autoload
(defun insert-arrow ()
  (interactive)
  (delete-horizontal-space t)
  (insert " => "))

(define-key ruby-mode-map (kbd "C-.") 'insert-arrow)
(define-key rinari-minor-mode-map (kbd "C-.") 'insert-arrow)

Ruby 1.9 added a new syntax for hashes.

  • Modify Ruby Syntax

    I use mark-multiple to highlight symbols/variables in the buffer. But I found it can’t distinguish the four types of scoped variable. This can be solved by modify the syntax table.

1
2
3
4
(add-hook 'ruby-mode-hook
          (lambda ()
            (modify-syntax-entry ?$ "w")
            (modify-syntax-entry ?@ "w")))
Before

After

SUPPLEMENT
I also use auto-complete to complete symbols/variables. Some times, I say

1
let!(:newer_micropost) { FactoryGirl.create(:micropost, user: @user, created_at: 1.day.ago)

and

1
@user.microposts = newe

then I want auto-complete the reset of newer_micropost. So I press TAB, oops! nothing completed.

That’s because the punctuation character : had been declared to be a part of a word. It means that the :newer_micropost and the newer_micropost are two independent words. Yes, they are. But what I want is they should be completed by the auto-complete. This can be accomplished by a little hacky fragment:

1
2
3
(add-hook 'ruby-mode-hood
          (lambda ()
            (modify-syntax-entry ?: "."))

Before                       After

  • Fold/unfold code

    I use hs-minor-mode to fold/unfold blocks, add following snippet to support ruby block syntax.

1
2
3
4
(add-to-list 'hs-special-modes-alist
             '(ruby-mode
               "\\(class\\|def\\|do\\|if\\)" "\\(end\\)" "#"
               (lambda (arg) (ruby-end-of-block)) nil))

Outline-mode is a good choice too.

1
2
3
4
(add-hook 'ruby-mode-hook
          (lambda ()
            (outline-minor-mode)
            (setq outline-regexp " *\\(def \\|class\\|module\\)")))

Actually, I don’t use fold/unfold frequently, I have no idea which is a better solution. Any other good folding add-on?

  • YARI

    YARI(Yet Another Ri Interface) provides an Emacs frontend to Ruby’s ri documentation tool. It offers lookup and completion. It’s a good practice to bind a help-command for call YARI handy.

1
(define-key 'help-command "R" 'yari)

Now you can just type C-h R to call yari anywhere. Yari will show ri in Ido-style. It also support Anything-style, but Anything had renamed to Helm, you should add some snippet to support ‘Helm-style’

1
2
3
4
5
6
7
;;;###autoload
(defun yari-helm (&optional rehash)
  (interactive (list current-prefix-arg))
  (when current-prefix-arg (yari-ruby-obarray rehash))
  (helm 'yari-anything-source-ri-pages (yari-symbol-at-point)))

(define-key 'help-command "R" 'yari-helm)
  • Rinari

    Rinari Is Not A Ruby IDE. Must have add-on.

  • The forgotten TextMate

    TextMate is a minor mode to mimick the TextMate’s awesome. It’s quite common used to navigate between project files. The is bound to Meta(Alt) on the Ubuntu.

  • Other useful add-ons

    Ruby-Tools

    Ruby tools is a collection of handy functions for Emacs ruby-mode.

Ruby-Block

Ruby block will show you which block you are in. Since there are too many describe blocks in rspec, this will be helpful.

1
2
3
4
(require 'ruby-block)
  (setq ruby-block-delay 0)
  (setq ruby-block-highlight-toggle t)
  (ruby-block-mode t)

For more tricks, feel free to search my dotfiles for emacs hosted on the Github, bugs and fixes are welcome ;) The Ultimate Collection of Emacs Resources is also a good place for improvement.

PS: More tips are welcome!