1
;;; rails-ruby.el --- provide features for ruby-mode
2
3
;; Copyright (C) 2006 Dmitry Galinsky <dima dot exe at gmail dot com>
4
5
;; Authors: Dmitry Galinsky <dima dot exe at gmail dot com>
6
7
;; Keywords: ruby rails languages oop
8
;; $URL$
9
;; $Id$
10
11
;;; License
12
13
;; This program is free software; you can redistribute it and/or
14
;; modify it under the terms of the GNU General Public License
15
;; as published by the Free Software Foundation; either version 2
16
;; of the License, or (at your option) any later version.
17
18
;; This program is distributed in the hope that it will be useful,
19
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
;; GNU General Public License for more details.
22
23
;; You should have received a copy of the GNU General Public License
24
;; along with this program; if not, write to the Free Software
25
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26
27
;;; Code:
28
29
;; setup align for ruby-mode
30
(require 'align)
31
32
(defconst align-ruby-modes '(ruby-mode)
33
  "align-perl-modes is a variable defined in `align.el'.")
34
35
(defconst ruby-align-rules-list
36
  '((ruby-comma-delimiter
37
     (regexp . ",\\(\\s-*\\)[^/ \t\n]")
38
     (modes  . align-ruby-modes)
39
     (repeat . t))
40
    (ruby-string-after-func
41
     (regexp . "^\\s-*[a-zA-Z0-9.:?_]+\\(\\s-+\\)['\"]\\w+['\"]")
42
     (modes  . align-ruby-modes)
43
     (repeat . t))
44
    (ruby-symbol-after-func
45
     (regexp . "^\\s-*[a-zA-Z0-9.:?_]+\\(\\s-+\\):\\w+")
46
     (modes  . align-ruby-modes)))
47
  "Alignment rules specific to the ruby mode.
48
See the variable `align-rules-list' for more details.")
49
50
(add-to-list 'align-perl-modes 'ruby-mode)
51
(add-to-list 'align-dq-string-modes 'ruby-mode)
52
(add-to-list 'align-sq-string-modes 'ruby-mode)
53
(add-to-list 'align-open-comment-modes 'ruby-mode)
54
(dolist (it ruby-align-rules-list)
55
  (add-to-list 'align-rules-list it))
56
57
;; hideshow ruby support
58
59
(defun display-code-line-counts (ov)
60
  (when (eq 'code (overlay-get ov 'hs))
61
    (overlay-put ov 'face 'font-lock-comment-face)
62
    (overlay-put ov 'display
63
                 (format " ... %d lines"
64
                         (count-lines (overlay-start ov)
65
                                      (overlay-end ov))))))
66
67
(eval-after-load "hideshow"
68
  (unless 'hs-set-up-overlay
69
    (setq hs-set-up-overlay 'display-code-line-counts)))
70
71
(add-hook 'hs-minor-mode-hook
72
          (lambda ()
73
            (unless hs-set-up-overlay
74
              (setq hs-set-up-overlay 'display-code-line-counts))))
75
76
(defun ruby-hs-minor-mode (&optional arg)
77
  (interactive)
78
  (require 'hideshow)
79
  (unless (assoc 'ruby-mode hs-special-modes-alist)
80
    (setq
81
     hs-special-modes-alist
82
     (cons (list 'ruby-mode
83
                 "\\(def\\|do\\)"
84
                 "end"
85
                 "#"
86
                 (lambda (&rest args) (ruby-end-of-block))
87
                 ;(lambda (&rest args) (ruby-beginning-of-defun))
88
                 )
89
           hs-special-modes-alist)))
90
  (hs-minor-mode arg))
91
92
;; flymake ruby support
93
94
(require 'flymake nil t)
95
96
(defconst flymake-allowed-ruby-file-name-masks
97
  '(("\\.rb\\'"      flymake-ruby-init)
98
    ("\\.rxml\\'"    flymake-ruby-init)
99
    ("\\.builder\\'" flymake-ruby-init)
100
    ("\\.rjs\\'"     flymake-ruby-init))
101
  "Filename extensions that switch on flymake-ruby mode syntax checks.")
102
103
(defconst flymake-ruby-error-line-pattern-regexp
104
  '("^\\([^:]+\\):\\([0-9]+\\): *\\([\n]+\\)" 1 2 nil 3)
105
  "Regexp matching ruby error messages.")
106
107
(defun flymake-ruby-init ()
108
  (condition-case er
109
      (let* ((temp-file (flymake-init-create-temp-buffer-copy
110
                         'flymake-create-temp-inplace))
111
             (local-file  (file-relative-name
112
                           temp-file
113
                           (file-name-directory buffer-file-name))))
114
        (list rails-ruby-command (list "-c" local-file)))
115
    ('error ())))
116
117
(defun flymake-ruby-load ()
118
  (when (and (buffer-file-name)
119
             (not (file-remote-p (buffer-file-name))) ; FIX: cabo
120
             (string-match
121
              (format "\\(%s\\)"
122
                      (string-join
123
                       "\\|"
124
                       (mapcar 'car flymake-allowed-ruby-file-name-masks)))
125
              (buffer-file-name)))
126
    (setq flymake-allowed-file-name-masks
127
          (append flymake-allowed-file-name-masks flymake-allowed-ruby-file-name-masks))
128
    (setq flymake-err-line-patterns
129
          (cons flymake-ruby-error-line-pattern-regexp flymake-err-line-patterns))
130
    (flymake-mode t)
131
    (local-set-key (rails-key "d") 'flymake-display-err-menu-for-current-line)))
132
133
(when (featurep 'flymake)
134
  (add-hook 'ruby-mode-hook 'flymake-ruby-load))
135
136
;; other stuff
137
138
(defun ruby-newline-and-indent ()
139
  (interactive)
140
  (newline)
141
  (ruby-indent-line))
142
143
(defun ruby-toggle-string<>simbol ()
144
  "Easy to switch between strings and symbols."
145
  (interactive)
146
  (let ((initial-pos (point)))
147
    (save-excursion
148
      (when (looking-at "[\"']") ;; skip beggining quote
149
        (goto-char (+ (point) 1))
150
        (unless (looking-at "\\w")
151
          (goto-char (- (point) 1))))
152
      (let* ((point (point))
153
             (start (skip-syntax-backward "w"))
154
             (end (skip-syntax-forward "w"))
155
             (end (+ point start end))
156
             (start (+ point start))
157
             (start-quote (- start 1))
158
             (end-quote (+ end 1))
159
             (quoted-str (buffer-substring-no-properties start-quote end-quote))
160
             (symbol-str (buffer-substring-no-properties start end)))
161
        (cond
162
         ((or (string-match "^\"\\w+\"$" quoted-str)
163
              (string-match "^\'\\w+\'$" quoted-str))
164
          (setq quoted-str (substring quoted-str 1 (- (length quoted-str) 1)))
165
          (kill-region start-quote end-quote)
166
          (goto-char start-quote)
167
          (insert (concat ":" quoted-str)))
168
         ((string-match "^\:\\w+$" symbol-str)
169
          (setq symbol-str (substring symbol-str 1))
170
          (kill-region start end)
171
          (goto-char start)
172
          (insert (format "'%s'" symbol-str))))))
173
    (goto-char initial-pos)))
174
175
(require 'inf-ruby)
176
177
(defun run-ruby-in-buffer (buf script &rest params)
178
  "Run CMD as a ruby process in BUF if BUF does not exist."
179
  (message "run-ruby-in-buffer %s" params)
180
  (let ((abuf (concat "*" buf "*")))
181
    (when (not (comint-check-proc abuf))
182
      (set-buffer (apply #'make-comint buf rails-ruby-command nil script params)))
183
    (pop-to-buffer abuf)
184
    (when (fboundp 'inf-ruby-mode)
185
      (inf-ruby-mode)
186
      (when (< (rails-core:current-rails-major-version) 3)
187
        (make-local-variable 'inf-ruby-first-prompt-pattern)
188
        (make-local-variable 'inf-ruby-prompt-pattern)
189
        (setq inf-ruby-first-prompt-pattern "^>> "
190
              inf-ruby-prompt-pattern "^>> "
191
              inf-ruby-buffer (current-buffer))))))
192
193
(defun complete-ruby-method (prefix &optional maxnum)
194
  (if (capital-word-p prefix)
195
      (let* ((cmd "x = []; ObjectSpace.each_object(Class){|i| x << i.to_s}; x.map{|i| i.match(/^%s/) ? i.gsub(/^%s/, '') : nil }.compact.sort{|x,y| x.size <=> y.size}")
196
             (cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd)))
197
        (el4r-ruby-eval (format cmd prefix prefix)))
198
    (save-excursion
199
      (goto-char (- (point) (+ 1 (length prefix))))
200
      (when (and (looking-at "\\.")
201
                 (capital-word-p (word-at-point))
202
                 (el4r-ruby-eval (format "::%s rescue nil" (word-at-point))))
203
        (let* ((cmd "%s.public_methods.map{|i| i.match(/^%s/) ? i.gsub(/^%s/, '') : nil }.compact.sort{|x,y| x.size <=> y.size}")
204
               (cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd)))
205
          (el4r-ruby-eval (format cmd (word-at-point) prefix prefix)))))))
206
207
208
(provide 'rails-ruby)