├── .gitignore ├── ChangeLog ├── History ├── README ├── behave-rails.el ├── inflections.el ├── predictive-prog-mode.el ├── rails-bytecompile.el ├── rails-cmd-proxy.el ├── rails-compat.el ├── rails-controller-layout.el ├── rails-controller-minor-mode.el ├── rails-core.el ├── rails-features.el ├── rails-find.el ├── rails-fixture-minor-mode.el ├── rails-functional-test-minor-mode.el ├── rails-helper-minor-mode.el ├── rails-layout-minor-mode.el ├── rails-lib.el ├── rails-log.el ├── rails-mailer-minor-mode.el ├── rails-migration-minor-mode.el ├── rails-model-layout.el ├── rails-model-minor-mode.el ├── rails-navigation.el ├── rails-plugin-minor-mode.el ├── rails-project.el ├── rails-rake.el ├── rails-ruby.el ├── rails-scripts.el ├── rails-shoulda.el ├── rails-snippets-feature.el ├── rails-spec.el ├── rails-speedbar-feature.el ├── rails-test.el ├── rails-ui.el ├── rails-unit-test-minor-mode.el ├── rails-view-minor-mode.el ├── rails-ws.el └── rails.el /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.cache 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /History: -------------------------------------------------------------------------------- 1 | SVN 2 | * Feature [#1853]: added support of thin (http://code.macournoyer.com/thin/) 3 | * Fixed [#16742]: pass rails environment to script/console 4 | 5 | 0.5.99.6 6 | * Removed file 'untabify-file.el' from package emacs-rails 7 | * Updated highlight of compilation output 8 | * Added ruby-mode support in hs-minor-mode (aka folding). 9 | * Added migrations and configuration files to speedbar. 10 | * More shortcuts for tests. 11 | 12 | 0.5.99.5 13 | * Improved `align` support in `ruby-mode`. 14 | * Fixed bug [#10613]: Wrong comparison of emacs-major-version. 15 | * Apply patch [#10532]: allows '-' to occur in the errror filepath (thanks Peter Williams). 16 | * Fixed bug [#10417]: ruby-flymake had applying only if flymake is 17 | available. 18 | * Raise a error if emacs-rails run on old version of Emacs (less 22). 19 | * Updated view mode of "views". 20 | * Fixed bug [#10357]: code expansion shouldn't occur in comment lines. 21 | 22 | 0.5.99.4 23 | * Added the test/test_helper in list of helpers. 24 | * Added list of templates in speedbar. 25 | * Fixed bug [#10056]: when one open file in a read only directory, 26 | flymake try to open a new file and failed (thanks Rémi Vanicat). 27 | * Fixed bug [#9991]: allow setup key prefix for rails-minor-mode. 28 | * Fixed bug [#10053]: don't match rhtml/rxml/rjs files in test output (thanks Rémi Vanicat). 29 | 30 | 0.5.99.3 31 | * Added speedbar integration, type [F11] to toogle speedbar. 32 | * Fixed bug #9880: the hotkey "C-c ." conflicted with ECB, changed to "C-c C-c ,". 33 | * New hotkeys, to easy switch without a popup menu between a 34 | controller or a model related files. 35 | In model layout: 36 | - "C-c m" go to model 37 | - "C-c u" go to unit test 38 | - "C-c g" go to migration 39 | - "C-c c" go to controller 40 | - "C-c x" go to fixture 41 | - "C-c n" go to mailer 42 | In controller layout: 43 | - "C-c g" go to migration 44 | - "C-c m" go to model 45 | - "C-c h" go to helper 46 | - "C-c f" go to functional test 47 | - "C-c c" go to controller 48 | - "C-c u" go to unit test 49 | * Fixed bug #9783 (remove-postfix: Wrong type argument: arrayp, nil). 50 | * Updated the compilation output, for better highlight of error and warnings. 51 | * Added the flymake support to on the fly syntax checked in the ruby-mode. 52 | 53 | 0.5.99.2 54 | * Added new dynamic snippets for RESTful, 55 | for instance: in controller UsersController type "rshow" 56 | will be expand to "user_url(@user)" and display tooltip "GET /users/1". 57 | * Added migration support - migrate, migrate to previous version, 58 | migrate to version. 59 | * Created separate menubar entries named "Navigate", "Database", "Tests". 60 | * Fixed bug #9721: Emacs 21.4.x can't load rails-core.el with error "Wrong 61 | number of arguments: #". 62 | * Added support pcompletion in ruby-mode (if possible). 63 | * Added new "Go to unit tests" and "Go to functional tests" hotkeys 64 | and menu entries. 65 | * Added tests integration with the compile library. 66 | * New [C-c /] hotkey to toggle output window. 67 | 68 | 0.5.99.1 69 | * Fixed bug #9619, script/server fails to start with [C-c C-c w s]. 70 | * Added hotkeys for tests: 71 | - [C-c C-c .] running a test for current model/controller (global) 72 | - [C-c .] running a test for current method (in a functional/unit test) 73 | * Prints total of tests, asertions, failures, errors after end of 74 | tests running. 75 | * Fixed recursive "require" error after compilation #9547. 76 | 77 | 0.5.99 78 | * Improvement of tests and rails scripts output; run asynchronous, 79 | colorize output, etc. 80 | * New [C-:] hotkey to easy switch between strings and symbols at point 81 | in ruby-mode. 82 | * New [C-c f] hotkey to popup a menu with list of functions in 83 | ruby-mode. 84 | 85 | 0.5.4 86 | * Added mailers support. 87 | * Added fixtures support. 88 | * Fixed incorrect indentation in snippets [#9460]. 89 | * Added support template types in layouts menu. 90 | * Added support haml template engine. 91 | * Use `compile` to run `rake tests`. 92 | * Ask to save modified buffers before run rake. 93 | * Added "quick switch" to support models and unit tests. 94 | 95 | 0.5.3 96 | * Create separate menubar entry "Snippets". 97 | * Allow web server selection auto-save. 98 | * Corrected errors at work with sql. 99 | * Fixed byte-compile warnings. 100 | 101 | 0.5.2 102 | * Fixed bugs: #8221, #8223. 103 | * Using system `tail` program for display log files. 104 | 105 | 0.5.1 at 27.01.2007 106 | * Support plugin: quick menu "Go to plugins" and navigate inside 107 | plugin. 108 | * Update Web Server support, add Lighttd to list of supported servers. 109 | * Automatic apply ruby-mode to *.rake files and setup utf-8 encoding. 110 | * Add more targets to generate/destroy. 111 | * Add autocomplete in generate/destroy/rake/test commands. 112 | * Small fixes indentation in snippets. 113 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomtt/emacs-rails/f2c4f8f4c0f728d7b37e2d1e2e15c9a6164428f1/README -------------------------------------------------------------------------------- /behave-rails.el: -------------------------------------------------------------------------------- 1 | (require 'behave) 2 | 3 | (context "Testing if string is camelized" 4 | (tag rails rails-lib camelized-p) 5 | (specify "should be nil if there are no capital characters" 6 | (expect (camelized-p "horse") equal nil)) 7 | (specify "should be 0 for a word with first character being a capital" 8 | (expect (camelized-p "Horse") equal 0)) 9 | (specify "should be nil if the first character is not a capital" 10 | (expect (camelized-p "dragonFly") equal nil)) 11 | (specify "should be 0 if there are multiple capitals" 12 | (expect (camelized-p "DragonFly") equal 0)) 13 | (specify "should be 0 if it has numbers" 14 | (expect (camelized-p "DragonFly69") equal 0)) 15 | (specify "should be nil if all its characters are capital" 16 | (expect (camelized-p "DONKEY") equal nil))) 17 | 18 | (context "Testing if string is underscored" 19 | (tag rails rails-lib underscored-p) 20 | (specify "should be nil if there is a capital character" 21 | (expect (underscored-p "horSe") equal nil)) 22 | (specify "should be 0 if all characters are lowercase" 23 | (expect (underscored-p "horse") equal 0)) 24 | (specify "should be 0 if some characters are numbers" 25 | (expect (underscored-p "horse12") equal 0)) 26 | (specify "should be 0 if some characters are underscores" 27 | (expect (underscored-p "dragon_fly") equal 0)) 28 | (specify "should be nil if the first character is not a letter" 29 | (expect (underscored-p "5_gold_rings") equal nil)) 30 | ) 31 | 32 | (context "Decamelizing" 33 | (tag rails rails-lib decamelize) 34 | (specify "should return a string of all lower case characters unchanged" 35 | (expect (decamelize "horse") equal "horse")) 36 | (specify "should replace an initial capital with a lower case character" 37 | (expect (decamelize "Horse") equal "horse")) 38 | (specify "should insert underscores before capital letters" 39 | (expect (decamelize "AntEaterTongue") equal "ant_eater_tongue")) 40 | (specify "should insert one underscore after last character of serie of capitals" 41 | (expect (decamelize "SMSMessage") equal "sms_message")) 42 | (specify "should insert an underscore between a digit and a capital" 43 | (expect (decamelize "Dalmatien101Movie") equal "dalmatien101_movie")) 44 | ) 45 | -------------------------------------------------------------------------------- /inflections.el: -------------------------------------------------------------------------------- 1 | ;;; inflections.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Howard Yeh 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | ;;; Code: 29 | 30 | (defvar inflection-singulars nil) 31 | (defvar inflection-plurals nil) 32 | (defvar inflection-irregulars nil) 33 | (defvar inflection-uncountables nil) 34 | 35 | (defmacro define-inflectors (&rest specs) 36 | (loop for (type . rest) in specs do 37 | (case type 38 | (:singular (push rest inflection-singulars)) 39 | (:plural (push rest inflection-plurals)) 40 | (:irregular (push rest inflection-irregulars)) 41 | (:uncountable (setf inflection-uncountables 42 | (append rest inflection-uncountables)))))) 43 | 44 | (define-inflectors 45 | (:plural "$" "s") 46 | (:plural "s$" "s") 47 | (:plural "\\(ax\\|test\\)is$" "\\1es") 48 | (:plural "\\(octop\\|vir\\)us$" "\\1i") 49 | (:plural "\\(alias\\|status\\)$" "\\1es") 50 | (:plural "\\(bu\\)s$" "\\1ses") 51 | (:plural "\\(buffal\\|tomat\\)o$" "\\1oes") 52 | (:plural "\\([ti]\\)um$" "\\1a") 53 | (:plural "sis$" "ses") 54 | (:plural "\\(?:\\([^f]\\)fe\\|\\([lr]\\)f\\)$" "\\1\\2ves") 55 | (:plural "\\(hive\\)$" "\\1s") 56 | (:plural "\\([^aeiouy]\\|qu\\)y$" "\\1ies") 57 | (:plural "\\(x\\|ch\\|ss\\|sh\\)$" "\\1es") 58 | (:plural "\\(matr\\|vert\\|ind\\)ix\\|ex$" "\\1ices") 59 | (:plural "\\([m\\|l]\\)ouse$" "\\1ice") 60 | (:plural "^\\(ox\\)$" "\\1en") 61 | (:plural "\\(quiz\\)$" "\\1zes") 62 | 63 | (:singular "s$" "") 64 | (:singular "\\(n\\)ews$" "\\1ews") 65 | (:singular "\\([ti]\\)a$" "\\1um") 66 | (:singular "\\(\\(a\\)naly\\|\\(b\\)a\\|\\(d\\)iagno\\|\\(p\\)arenthe\\|\\(p\\)rogno\\|\\(s\\)ynop\\|\\(t\\)he\\)ses$" "\\1\\2sis") 67 | (:singular "\\(^analy\\)ses$" "\\1sis") 68 | (:singular "\\([^f]\\)ves$" "\\1fe") 69 | (:singular "\\(hive\\)s$" "\\1") 70 | (:singular "\\(tive\\)s$" "\\1") 71 | (:singular "\\([lr]\\)ves$" "\\1f") 72 | (:singular "\\([^aeiouy]\\|qu\\)ies$" "\\1y") 73 | (:singular "\\(s\\)eries$" "\\1eries") 74 | (:singular "\\(m\\)ovies$" "\\1ovie") 75 | (:singular "\\(x\\|ch\\|ss\\|sh\\)es$" "\\1") 76 | (:singular "\\([m\\|l]\\)ice$" "\\1ouse") 77 | (:singular "\\(bus\\)es$" "\\1") 78 | (:singular "\\(o\\)es$" "\\1") 79 | (:singular "\\(shoe\\)s$" "\\1") 80 | (:singular "\\(cris\\|ax\\|test\\)es$" "\\1is") 81 | (:singular "\\(octop\\|vir\\)i$" "\\1us") 82 | (:singular "\\(alias\\|status\\)es$" "\\1") 83 | (:singular "^\\(ox\\)en" "\\1") 84 | (:singular "\\(vert\\|ind\\)ices$" "\\1ex") 85 | (:singular "\\(matr\\)ices$" "\\1ix") 86 | (:singular "\\(quiz\\)zes$" "\\1") 87 | 88 | (:irregular "stratum" "strate") 89 | (:irregular "syllabus" "syllabi") 90 | (:irregular "radius" "radii") 91 | (:irregular "addendum" "addenda") 92 | (:irregular "cactus" "cacti") 93 | (:irregular "child" "children") 94 | (:irregular "corpus" "corpora") 95 | (:irregular "criterion" "criteria") 96 | (:irregular "datum" "data") 97 | (:irregular "genus" "genera") 98 | (:irregular "man" "men") 99 | (:irregular "medium" "media") 100 | (:irregular "move" "moves") 101 | (:irregular "person" "people") 102 | (:irregular "man" "men") 103 | (:irregular "child" "children") 104 | (:irregular "sex" "sexes") 105 | (:irregular "move" "moves") 106 | 107 | (:uncountable "equipment" "information" "rice" "money" "species" "series" "fish" "sheep" "news")) 108 | 109 | (defun singularize-string (str) 110 | (when (stringp str) 111 | (or (car (member str inflection-uncountables)) 112 | (caar (member* (downcase str) inflection-irregulars :key 'cadr :test 'equal)) 113 | (loop for (from to) in inflection-singulars 114 | for singular = (string=~ from str (sub to)) 115 | when singular do (return singular)) 116 | str))) 117 | 118 | (defun pluralize-string (str) 119 | (when (stringp str) 120 | (or (car (member str inflection-uncountables)) 121 | (cadar (member* (downcase str) inflection-irregulars :key 'car :test 'equal)) 122 | (loop for (from to) in inflection-plurals 123 | for plurals = (string=~ from str (sub to)) 124 | when plurals do (return plurals)) 125 | str))) 126 | 127 | (provide 'inflections) 128 | -------------------------------------------------------------------------------- /predictive-prog-mode.el: -------------------------------------------------------------------------------- 1 | ;;; predictive-prog-mode.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails.el $ 9 | ;; $Id: rails.el 149 2007-03-29 15:07:49Z dimaexe $ 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 | (eval-when-compile 30 | (require 'predictive nil t) 31 | (require 'completion-ui nil t)) 32 | 33 | (require 'flyspell) 34 | 35 | (defconst predictive-prog-text-faces 36 | '(font-lock-comment-face font-lock-doc-face) 37 | "Faces corresponding to text in programming-mode buffers.") 38 | 39 | (defvar predictive-prog-mode-main-dict nil) 40 | 41 | (defun activate-predictive-inside-comments (start end len) 42 | "Looking at symbol at point and activate the `predictive-mode' 43 | if there a string or a comment." 44 | (save-excursion 45 | (let ((p (get-text-property (- (point) 1) 'face)) 46 | (f (get-text-property (point) 'face))) 47 | (if (or (memq f predictive-prog-text-faces) 48 | (memq p predictive-prog-text-faces)) 49 | (setq predictive-main-dict predictive-prog-mode-main-dict) 50 | (setq predictive-main-dict nil))))) 51 | 52 | (defun predictive-prog-mode () 53 | "Enable the `predictive-mode' inside strings and comments 54 | only, like `flyspell-prog-mode'." 55 | (interactive) 56 | (when (fboundp 'predictive-mode) 57 | (set (make-local-variable 'predictive-main-dict) nil) 58 | (set (make-local-variable 'predictive-prog-mode-main-dict) predictive-main-dict) 59 | (if (find 'activate-predictive-inside-comments after-change-functions) 60 | (progn 61 | (remove-hook 'after-change-functions 'activate-predictive-inside-comments t) 62 | (predictive-mode -1)) 63 | (progn 64 | ; (set (make-local-variable 'predictive-use-auto-learn-cache) nil) 65 | (set (make-local-variable 'predictive-dict-autosave-on-kill-buffer) nil) 66 | (predictive-mode 1) 67 | (add-hook 'after-change-functions 'activate-predictive-inside-comments nil t))))) 68 | 69 | (provide 'predictive-prog-mode) 70 | -------------------------------------------------------------------------------- /rails-bytecompile.el: -------------------------------------------------------------------------------- 1 | (require 'rails) 2 | 3 | (mapcar 4 | #'byte-compile-file 5 | (directory-files "./" t "\\.el$")) -------------------------------------------------------------------------------- /rails-cmd-proxy.el: -------------------------------------------------------------------------------- 1 | ;;; rails-cmd-proxy.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defstruct rails-cmd-proxy:struct local remote args) 30 | 31 | (defvar rails-cmd-proxy:directories-list 32 | '(("y:" "/mnt/www" "-t @server-cmd"))) 33 | 34 | (defvar rails-cmd-proxy:remote-cmd 35 | "plink") 36 | 37 | (defun rails-cmd-proxy:lookup (root &optional lookup-local) 38 | "Lookup ROOT using `rails-cmd-proxy:directories-list' and 39 | return the `rails-cmd-proxy:struct'. If not found ROOT return 40 | nil." 41 | (loop for (local remote args) in rails-cmd-proxy:directories-list 42 | when (string-match (concat "^" (if lookup-local remote local)) root) 43 | do (return 44 | (make-rails-cmd-proxy:struct 45 | :local local 46 | :remote remote 47 | :args args)))) 48 | 49 | (defun rails-cmd-proxy:convert (proxy-struct path &optional reverse) 50 | "Convert PATH from local to remote using PROXY-STRUCT, 51 | otherwise if set REVERSE convert from remote to local." 52 | (let* ((local (rails-cmd-proxy:struct-local proxy-struct)) 53 | (remote (rails-cmd-proxy:struct-remote proxy-struct)) 54 | (regexp (concat "^" (if reverse remote local))) 55 | (replacement (if reverse local remote))) 56 | (when (string-match regexp path) 57 | (replace-regexp-in-string regexp replacement path)))) 58 | 59 | (defun rails-cmd-proxy:construct-remote-cmd (proxy-struct root command &optional command-args) 60 | (let ((root (rails-cmd-proxy:convert proxy-struct root)) 61 | (args (rails-cmd-proxy:struct-args proxy-struct))) 62 | (if command-args 63 | (format "%s \"cd %s && %s %s\"" args root command command-args) 64 | (format "%s \"cd %s && %s\"" args root command)))) 65 | 66 | ;; remote wrappers 67 | 68 | (defun rails-cmd-proxy:start-process (name buffer command command-args) 69 | "" 70 | (rails-project:with-root 71 | (root) 72 | (let ((proxy-struct (rails-cmd-proxy:lookup root)) 73 | (command command) 74 | (command-args command-args)) 75 | (when proxy-struct 76 | (setq command-args 77 | (rails-cmd-proxy:construct-remote-cmd proxy-struct 78 | root 79 | command 80 | command-args)) 81 | (setq command rails-cmd-proxy:remote-cmd)) 82 | (start-process-shell-command name 83 | buffer 84 | command 85 | command-args)))) 86 | 87 | (defun rails-cmd-proxy:shell-command-to-string (command) 88 | (rails-project:with-root 89 | (root) 90 | (let ((proxy-struct (rails-cmd-proxy:lookup root)) 91 | (command command)) 92 | (when proxy-struct 93 | (setq command 94 | (format "%s %s" 95 | rails-cmd-proxy:remote-cmd 96 | (rails-cmd-proxy:construct-remote-cmd proxy-struct 97 | root 98 | command)))) 99 | (shell-command-to-string command)))) 100 | 101 | ;; helper functions 102 | 103 | (defun rails-cmd-proxy:convert-buffer-from-remote (start end len) 104 | (when-bind 105 | (struct (rails-cmd-proxy:lookup default-directory)) 106 | (save-excursion 107 | (goto-char start) 108 | (let* ((local (rails-cmd-proxy:struct-local struct)) 109 | (remote (rails-cmd-proxy:struct-remote struct)) 110 | (root default-directory) 111 | (remote-with-root (concat remote (substring root (length local)))) 112 | (buffer-read-only nil) 113 | point) 114 | (while (setq point (re-search-forward (format "^\\s-*\\(%s\\)" 115 | remote-with-root) end t)) 116 | (replace-match (format "%s " 117 | (string-repeat " " (- (length (match-string 1)) 1))) 118 | nil t nil 1)))))) 119 | 120 | (provide 'rails-cmd-proxy) 121 | -------------------------------------------------------------------------------- /rails-compat.el: -------------------------------------------------------------------------------- 1 | ;;; rails-compat.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails.el $ 9 | ;; $Id: rails.el 149 2007-03-29 15:07:49Z dimaexe $ 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 | (eval-when-compile 30 | (require 'snippet nil t) 31 | (require 'completion-ui nil t)) 32 | 33 | (when (fboundp 'indent-and-complete) 34 | (message "WARNNING: the `indent-and-complete' already defined.")) 35 | 36 | (defun indent-and-complete () 37 | "Indent line and Complete if point is at end of left a leave word." 38 | (interactive) 39 | 40 | (cond 41 | ;; snippet 42 | ((and (boundp 'snippet) 43 | snippet) 44 | (snippet-next-field)) 45 | 46 | ;; completion-ui 47 | ((and (fboundp 'completion-overlay-at-point) 48 | (completion-overlay-at-point)) 49 | (let* ((ov (completion-overlay-at-point)) 50 | (end (overlay-end ov)) 51 | ;; setup as last command 52 | (last-input-event 32) 53 | (last-command-event 32)) 54 | ;; skip message output 55 | (flet ((message (format-string &rest args) nil)) 56 | (completion-self-insert)))) 57 | 58 | ;; hippie-expand 59 | ((looking-at "\\_>") 60 | ;; skip message output 61 | (flet ((message (format-string &rest args) nil)) 62 | (hippie-expand nil)))) 63 | 64 | ;; always indent line 65 | (indent-for-tab-command)) 66 | 67 | 68 | (when (fboundp 'try-complete-abbrev) 69 | (message "WARRNING: the function `try-complete-abbrev' already defined")) 70 | 71 | (defun try-complete-abbrev (old) 72 | (if (abbrev-expansion-point-p) 73 | (if (expand-abbrev) 74 | t nil) 75 | nil)) 76 | 77 | (defun abbrev-expansion-point-p () 78 | "returns true if point is a place that might be expanded" 79 | (if (memq (get-text-property (- (point) 1) 'face) 80 | '(font-lock-string-face font-lock-comment-face font-lock-doc-face)) 81 | (return nil) ;; we never expand inside of string literals or comments 82 | (string-not-empty (syntax-word-before-point)))) 83 | 84 | (defun syntax-word-before-point () 85 | "Yields the word immediately preceding point" 86 | (buffer-substring-no-properties 87 | (+ (point) (save-excursion (skip-syntax-backward "w"))) 88 | (point))) 89 | 90 | 91 | (unless (find 'try-complete-abbrev hippie-expand-try-functions-list) 92 | (add-to-list 'hippie-expand-try-functions-list 'try-complete-abbrev)) 93 | (provide 'rails-compat) 94 | -------------------------------------------------------------------------------- /rails-controller-layout.el: -------------------------------------------------------------------------------- 1 | ;;; rails-controller-layout.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defvar rails-controller-layout:recent-template-type nil) 30 | 31 | (defun rails-controller-layout:switch-to-action-in-controller (controller-name action-name) 32 | "Open CONTROLLER-NAME and go to ACTION-NAME." 33 | (if (or (rails-core:find-file-if-exist (rails-core:controller-file controller-name)) 34 | (rails-core:find-file-if-exist (rails-core:mailer-file controller-name))) 35 | (progn 36 | (goto-char (point-min)) 37 | (when action-name 38 | (if (search-forward-regexp (concat "^[ ]*def[ ]*" action-name) nil t) 39 | (recenter)) 40 | (message (format "%s: %s" (substring (symbol-name (rails-core:buffer-type)) 1) controller-name)))))) 41 | 42 | (defun rails-controller-layout:switch-to-view (controller-name action-name) 43 | "Open the ACTION-NAME file for CONTROLLER-NAME in the views directory." 44 | (when action-name 45 | (let ((views (rails-controller-layout:view-files controller-name action-name)) 46 | (title (substring (symbol-name (rails-core:buffer-type)) 1))) 47 | (cond 48 | ((= (length views) 1) 49 | (find-file (first views)) 50 | (message "%s: %s#%s" title controller-name action-name)) 51 | ((= (length views) 0) 52 | (rails-controller-layout:create-view-for-action controller-name action-name)))))) 53 | 54 | (defun rails-controller-layout:toggle-action-view () 55 | (interactive) 56 | (let ((controller-name (rails-core:current-controller)) 57 | (action-name (rails-core:current-action))) 58 | (case (rails-core:buffer-type) 59 | (:view 60 | (rails-controller-layout:switch-to-action-in-controller controller-name action-name)) 61 | (:mailer 62 | (rails-controller-layout:switch-to-view controller-name action-name)) 63 | (:controller 64 | (if action-name 65 | (rails-controller-layout:switch-to-view controller-name action-name) 66 | (rails-controller-layout:switch-to :functional-test)))))) 67 | 68 | (defun rails-controller-layout:create-view-for-action (controller-name action-name) 69 | (let ((type 70 | (if rails-controller-layout:recent-template-type 71 | rails-controller-layout:recent-template-type 72 | (car rails-templates-list)))) 73 | (setq type 74 | (completing-read (format "View for %s#%s not found, create %s.[%s]? " 75 | controller-name action-name action-name type) 76 | rails-templates-list 77 | nil t type)) 78 | (setq rails-controller-layout:recent-template-type type) 79 | (let ((file (rails-core:file (concat "app/views/" 80 | (replace-regexp-in-string "_controller" "" 81 | (rails-core:file-by-class controller-name t)))))) 82 | (make-directory file t) 83 | (find-file (format "%s/%s.%s" file action-name type))))) 84 | 85 | (defun rails-controller-layout:view-files (controller-name &optional action) 86 | "Retun a list containing the view file for CONTROLLER-NAME#ACTION. 87 | If the action is nil, return all views for the controller." 88 | (rails-project:with-root 89 | (root) 90 | (directory-files 91 | (rails-core:file 92 | (rails-core:views-dir 93 | (rails-core:short-controller-name controller-name))) t 94 | (if action 95 | (concat "^" action (rails-core:regex-for-match-view)) 96 | (rails-core:regex-for-match-view))))) 97 | 98 | (defun rails-controller-layout:views-menu (controller-name) 99 | "Make menu of view for CONTROLLER-NAME." 100 | (let (menu) 101 | (setq menu 102 | (mapcar (lambda(i) 103 | (list (concat (if (string-match "^_" (file-name-nondirectory i)) "Partial" "View") 104 | ": " 105 | (file-name-nondirectory i)) 106 | i)) 107 | (rails-controller-layout:view-files controller-name nil))) 108 | (when (zerop (length menu)) 109 | (setq menu (list))) 110 | menu)) 111 | 112 | (defun rails-controller-layout:keymap (type) 113 | (let* ((name (capitalize (substring (symbol-name type) 1))) 114 | (map (make-sparse-keymap)) 115 | (menu (make-sparse-keymap))) 116 | (when type 117 | (define-keys menu 118 | ([goto-migration] '(menu-item "Go to Migration" 119 | rails-controller-layout:switch-to-migration 120 | :enable (and (not (rails-core:current-mailer)) 121 | (rails-core:migration-file-by-model 122 | (singularize-string (rails-core:current-controller)))))) 123 | ([goto-model] '(menu-item "Go to Model" 124 | rails-controller-layout:switch-to-model 125 | :enable (and (not (rails-core:current-mailer)) 126 | (rails-core:model-exist-p 127 | (singularize-string (rails-core:current-controller)))))) 128 | ([goto-helper] '(menu-item "Go to Helper" 129 | rails-controller-layout:switch-to-helper 130 | :enable (and (not (rails-core:current-mailer)) 131 | (not (eq (rails-core:buffer-type) :helper))))) 132 | ([goto-ftest] '(menu-item "Go to Functional Test" 133 | rails-controller-layout:switch-to-functional-test 134 | :enable (and (not (rails-core:current-mailer)) 135 | (not (eq (rails-core:buffer-type) :functional-test))))) 136 | ([goto-controller] '(menu-item "Go to Controller" 137 | rails-controller-layout:switch-to-controller 138 | :enable (and (not (rails-core:current-mailer)) 139 | (not (eq (rails-core:buffer-type) :controller))))) 140 | ([goto-utest] '(menu-item "Go to Unit Test" 141 | rails-controller-layout:switch-to-unit-test 142 | :enable (rails-core:current-mailer)))) 143 | (define-keys map 144 | ((rails-key "g") 'rails-controller-layout:switch-to-migration) 145 | ((rails-key "m") 'rails-controller-layout:switch-to-model) 146 | ((rails-key "h") 'rails-controller-layout:switch-to-helper) 147 | ((rails-key "f") 'rails-controller-layout:switch-to-functional-test) 148 | ((rails-key "c") 'rails-controller-layout:switch-to-controller) 149 | ((rails-key "u") 'rails-controller-layout:switch-to-unit-test) 150 | ([menu-bar rails-controller-layout] (cons name menu)))) 151 | map)) 152 | 153 | (defun rails-controller-layout:switch-to (type) 154 | (let* ((name (capitalize (substring (symbol-name type) 1))) 155 | (controller (rails-core:current-controller)) 156 | (model (singularize-string controller)) 157 | (mailer (rails-core:current-mailer)) 158 | (item (case type 159 | (:helper (rails-core:helper-file controller)) 160 | (:functional-test (rails-core:functional-test-file controller)) 161 | (:controller (rails-core:controller-file controller)) 162 | (:model (rails-core:model-file model)) 163 | (:unit-test (rails-core:unit-test-file mailer)) 164 | (:migration (rails-core:migration-file-by-model model))))) 165 | (if item 166 | (let ((file (rails-core:file item))) 167 | (if (file-exists-p file) 168 | (progn 169 | (find-file file) 170 | (message (format "%s: %s" (substring (symbol-name type) 1) item))) 171 | (message "File %s not exists" file))) 172 | (message "%s not found" name)))) 173 | 174 | (defun rails-controller-layout:switch-to-helper () (interactive) (rails-controller-layout:switch-to :helper)) 175 | (defun rails-controller-layout:switch-to-functional-test () (interactive) (rails-controller-layout:switch-to :functional-test)) 176 | (defun rails-controller-layout:switch-to-controller () (interactive) (rails-controller-layout:switch-to :controller)) 177 | (defun rails-controller-layout:switch-to-model () (interactive) (rails-controller-layout:switch-to :model)) 178 | (defun rails-controller-layout:switch-to-migration () (interactive) (rails-controller-layout:switch-to :migration)) 179 | (defun rails-controller-layout:switch-to-unit-test () (interactive) (rails-controller-layout:switch-to :unit-test)) 180 | 181 | (defun rails-controller-layout:menu () 182 | (interactive) 183 | (let* ((type (rails-core:buffer-type)) 184 | (title (capitalize (substring (symbol-name type) 1))) 185 | (controller (rails-core:current-controller)) 186 | (action (rails-core:current-action)) 187 | (model (singularize-string controller)) 188 | (mailer (rails-core:current-mailer)) 189 | (item (rails-controller-layout:views-menu (or controller mailer)))) 190 | (add-to-list 'item (rails-core:menu-separator)) 191 | (when controller 192 | (when (rails-core:model-exist-p model) 193 | (when (rails-core:migration-file-by-model model) 194 | (add-to-list 'item (cons "Migration" :migration))) 195 | (add-to-list 'item (cons "Model" :model))) 196 | (unless (eq type :helper) 197 | (add-to-list 'item (cons "Helper" :helper))) 198 | (unless (eq type :functional-test) 199 | (add-to-list 'item (cons "Functional Test" :functional-test))) 200 | (unless (eq type :controller) 201 | (add-to-list 'item (cons "Controller" :controller)))) 202 | (when mailer 203 | (add-to-list 'item (cons "Unit Test" (rails-core:unit-test-file mailer))) 204 | (when (eq type :view) 205 | (add-to-list 'item (cons "Mailer" (rails-core:mailer-file mailer))))) 206 | (setq item 207 | (rails-core:menu 208 | (list (concat title " " controller 209 | (when action (format " (%s)" action))) 210 | (cons "Please select.." 211 | item)))) 212 | (typecase item 213 | (symbol (rails-controller-layout:switch-to item)) 214 | (string (rails-core:find-file-if-exist item))))) 215 | 216 | (provide 'rails-controller-layout) 217 | -------------------------------------------------------------------------------- /rails-controller-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-controller-minor-mode.el --- minor mode for RubyOnRails controllers 2 | 3 | ;; Copyright (C) 2006-2007 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | ;;; Code: 29 | 30 | (define-minor-mode rails-controller-minor-mode 31 | "Minor mode for RubyOnRails controllers." 32 | :lighter " Controller" 33 | :keymap (rails-controller-layout:keymap :controller) 34 | (setq rails-secondary-switch-func 'rails-controller-layout:menu) 35 | (setq rails-primary-switch-func 'rails-controller-layout:toggle-action-view)) 36 | 37 | (provide 'rails-controller-minor-mode) 38 | -------------------------------------------------------------------------------- /rails-core.el: -------------------------------------------------------------------------------- 1 | ;;; rails-core.el --- core helper functions and macros for emacs-rails 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | (eval-when-compile 29 | (require 'rails-lib)) 30 | 31 | (defvar rails-core:class-dirs 32 | '("app/controllers" 33 | "app/views" 34 | "app/models" 35 | "app/helpers" 36 | "test/unit" 37 | "test/functional" 38 | "test/fixtures") 39 | "Directories with Rails classes") 40 | 41 | (defun rails-core:class-by-file (filename) 42 | "Return the class associated with FILENAME. 43 | /(app/models|app/controllers|app/helpers|test/unit|test/functional)/foo/bar_baz 44 | --> Foo::BarBaz" 45 | (let* ((case-fold-search nil) 46 | (path (replace-regexp-in-string 47 | (format 48 | "\\(.*\\(%s\\)/\\)?\\([^\.]+\\)\\(.*\\)?" 49 | (strings-join "\\|" rails-core:class-dirs)) "\\3" filename)) 50 | (path (replace-regexp-in-string "/" " " path)) 51 | (path (replace-regexp-in-string "_" " " path))) 52 | (replace-regexp-in-string 53 | " " "" 54 | (replace-regexp-in-string 55 | " " "::" 56 | (if (string-match "^ *\\([0-9]+ *\\)?[A-Z]" path) 57 | path 58 | (capitalize path)))))) 59 | 60 | (defun rails-core:file-by-class (classname &optional do-not-append-ext) 61 | "Return the filename associated with CLASSNAME. 62 | If the optional parameter DO-NOT-APPEND-EXT is set this function 63 | will not append \".rb\" to result." 64 | (concat (decamelize (replace-regexp-in-string "::" "/" classname)) 65 | (unless do-not-append-ext ".rb"))) 66 | 67 | ;;;;;;;;;; Files ;;;;;;;;;; 68 | 69 | (defun rails-core:file (file-name) 70 | "Return the full path for FILE-NAME in a Rails directory." 71 | (when file-name 72 | (if (file-name-absolute-p file-name) 73 | file-name 74 | (rails-project:with-root 75 | (root) 76 | (concat root file-name))))) 77 | 78 | (defun rails-core:quoted-file (file-name) 79 | "Return the quoted full path for FILE-NAME in a Rails directory." 80 | (concat "\"" (rails-core:file file-name) "\"")) 81 | 82 | (defun rails-core:find-file (file-name) 83 | "Open the file named FILE_NAME in a Rails directory." 84 | (when-bind (file (rails-core:file file-name)) 85 | (find-file file))) 86 | 87 | (defun rails-core:find-file-if-exist (file-name) 88 | "Open the file named FILE-NAME in a Rails directory only if the file exists." 89 | (let ((file-name (rails-core:file file-name))) 90 | (when (file-exists-p file-name) 91 | (find-file file-name)))) 92 | 93 | (defun rails-core:find-or-ask-to-create (question file) 94 | "Open the file named FILE in a Rails directory if it exists. If 95 | it does not exist, ask to create it using QUESTION as a prompt." 96 | (find-or-ask-to-create question (rails-core:file file))) 97 | 98 | (defun rails-core:strip-namespace (class-name) 99 | "Strip namespace of CLASS-NAME, eg Foo::Bar -> Bar." 100 | (let ((name-list (split-string class-name "::"))) 101 | (car (last name-list)))) 102 | 103 | ;; Funtions, that retrun Rails objects full pathes 104 | 105 | (defun rails-core:model-file (model-name) 106 | "Return the model file from the model name." 107 | (when model-name 108 | (let* ((stripped-model-file 109 | (rails-core:file-by-class 110 | (rails-core:strip-namespace model-name))) 111 | (model-file 112 | (rails-core:file-by-class model-name))) 113 | (cond 114 | ((file-exists-p 115 | (rails-core:file (concat "app/models/" model-file))) 116 | (concat "app/models/" model-file)) 117 | ((file-exists-p 118 | (rails-core:file (concat "app/models/" stripped-model-file))) 119 | (concat "app/models/" stripped-model-file)) 120 | (t nil))))) 121 | 122 | (defun rails-core:model-exist-p (model-name) 123 | "Return t if model MODEL-NAME exist." 124 | (let ((model-file (rails-core:model-file model-name))) 125 | (when model-file 126 | (and (file-exists-p (rails-core:file model-file)) 127 | (not (rails-core:observer-p model-name)) 128 | (not (rails-core:mailer-p model-name)))))) 129 | 130 | (defun rails-core:controller-file (controller-name) 131 | "Return the path to the controller CONTROLLER-NAME." 132 | (when controller-name 133 | (concat "app/controllers/" 134 | (rails-core:file-by-class 135 | (rails-core:short-controller-name controller-name) t) 136 | (unless (string-equal controller-name "Application") "_controller") 137 | ".rb"))) 138 | 139 | (defun rails-core:controller-exist-p (controller-name) 140 | "Return t if controller CONTROLLER-NAME exist." 141 | (when controller-name 142 | (file-exists-p 143 | (rails-core:file 144 | (rails-core:controller-file controller-name))))) 145 | 146 | (defun rails-core:controller-file-by-model (model) 147 | (when model 148 | (let* ((controller (pluralize-string model))) 149 | ;(controller (when controller (capitalize controller)))) 150 | (setq controller 151 | (cond 152 | ((rails-core:controller-exist-p controller) controller) ;; pluralized 153 | ((rails-core:controller-exist-p model) model) ;; singularized 154 | (t (let ((controllers (rails-core:controllers t))) 155 | (cond 156 | ;; with namespace 157 | ((find 158 | (list controller model) 159 | controllers 160 | :test #'(lambda(x y) 161 | (or 162 | (string= (car x) (rails-core:strip-namespace y)) 163 | (string= (cadr x) (rails-core:strip-namespace y))))))))))) 164 | (when controller 165 | (rails-core:controller-file controller))))) 166 | 167 | (defun rails-core:observer-file (observer-name) 168 | "Return the path to the observer OBSERVER-NAME." 169 | (when observer-name 170 | (rails-core:model-file (concat observer-name "Observer")))) 171 | 172 | (defun rails-core:mailer-file (mailer) 173 | (when (and mailer 174 | (rails-core:mailer-p mailer)) 175 | (rails-core:model-file mailer))) 176 | 177 | (defun rails-core:mailer-exist-p (mailer) 178 | (when mailer 179 | (file-exists-p (rails-core:file (rails-core:mailer-file mailer))))) 180 | 181 | (defun rails-core:migration-file (migration-name) 182 | "Return the model file from the MIGRATION-NAME." 183 | (when migration-name 184 | (let ((dir "db/migrate/") 185 | (name (replace-regexp-in-string 186 | " " "_" 187 | (rails-core:file-by-class migration-name)))) 188 | (when (string-match "^[^0-9]+[^_]" name) ; try search when the name without migration number 189 | (let ((files (directory-files (rails-core:file dir) 190 | nil 191 | (concat "[0-9]+_" name "$")))) 192 | (setq name (if files 193 | (car files) 194 | nil)))) 195 | (when name 196 | (concat dir name))))) 197 | 198 | (defun rails-core:migration-file-by-model (model) 199 | (when model 200 | (rails-core:migration-file 201 | (concat "Create" (rails-core:class-by-file (pluralize-string model)))))) 202 | 203 | (defun rails-core:model-by-migration-filename (migration-filename) 204 | (when migration-filename 205 | (let ((model-name (singularize-string 206 | (string=~ "[0-9]+_create_\\(\\w+\\)\.rb" (buffer-name) $1)))) 207 | (when (and model-name 208 | (rails-core:model-exist-p model-name)) 209 | model-name)))) 210 | 211 | (defun rails-core:configuration-file (file) 212 | "Return the path to the configuration FILE." 213 | (when file 214 | (concat "config/" file))) 215 | 216 | (defun rails-core:plugin-file (plugin file) 217 | "Return the path to the FILE in Rails PLUGIN." 218 | (concat "vendor/plugins/" plugin "/" file)) 219 | 220 | (defun rails-core:layout-file (layout) 221 | "Return the path to the layout file named LAYOUT." 222 | (let ((its rails-templates-list) 223 | filename) 224 | (while (and (car its) 225 | (not filename)) 226 | (when (file-exists-p (format "%sapp/views/layouts/%s.%s" (rails-project:root) layout (car its))) 227 | (setq filename (format "app/views/layouts/%s.%s" layout (car its)))) 228 | (setq its (cdr its))) 229 | filename)) 230 | 231 | (defun rails-core:js-file (js) 232 | "Return the path to the JavaScript file named JS." 233 | (concat "public/javascripts/" js ".js")) 234 | 235 | (defun rails-core:partial-name (name) 236 | "Return the file name of partial NAME." 237 | (if (string-match "/" name) 238 | (concat "app/views/" 239 | (replace-regexp-in-string "\\([^/]*\\)$" "_\\1.rhtml" name)) 240 | (concat (rails-core:views-dir (rails-core:current-controller)) 241 | "_" name ".rhtml"))) 242 | 243 | (defun rails-core:view-name (name) 244 | "Return the file name of view NAME." 245 | (concat (rails-core:views-dir (rails-core:current-controller)) 246 | name ".rhtml")) ;; BUG: will fix it 247 | 248 | (defun rails-core:helper-file (controller) 249 | "Return the helper file name for the controller named 250 | CONTROLLER." 251 | (if (string= "Test/TestHelper" controller) 252 | (rails-core:file (rails-core:file-by-class "Test/TestHelper")) 253 | (when controller 254 | (format "app/helpers/%s_helper.rb" 255 | (replace-regexp-in-string "_controller" "" 256 | (rails-core:file-by-class controller t)))))) 257 | 258 | (defun rails-core:functional-test-file (controller) 259 | "Return the functional test file name for the controller named 260 | CONTROLLER." 261 | (when controller 262 | (format "test/functional/%s_test.rb" 263 | (rails-core:file-by-class (rails-core:long-controller-name controller) t)))) 264 | 265 | (defun rails-core:unit-test-file (model) 266 | "Return the unit test file name for the model named MODEL." 267 | (when model 268 | (format "test/unit/%s_test.rb" (rails-core:file-by-class model t)))) 269 | 270 | (defun rails-core:unit-test-exist-p (model) 271 | "Return the unit test file name for the model named MODEL." 272 | (let ((test (rails-core:unit-test-file model))) 273 | (when test 274 | (file-exists-p (rails-core:file test))))) 275 | 276 | (defun rails-core:fixture-file (model) 277 | "Return the fixtures file name for the model named MODEL." 278 | (when model 279 | (format "test/fixtures/%s.yml" (pluralize-string (rails-core:file-by-class model t))))) 280 | 281 | (defun rails-core:fixture-exist-p (model) 282 | (when model 283 | (file-exists-p 284 | (rails-core:file (rails-core:fixture-file model))))) 285 | 286 | (defun rails-core:views-dir (controller) 287 | "Return the view directory name for the controller named CONTROLLER." 288 | (format "app/views/%s/" (replace-regexp-in-string "_controller" "" (rails-core:file-by-class controller t)))) 289 | 290 | (defun rails-core:stylesheet-name (name) 291 | "Return the file name of the stylesheet named NAME." 292 | (concat "public/stylesheets/" name ".css")) 293 | 294 | (defun rails-core:controller-name (controller-file) 295 | "Return the class name of the controller named CONTROLLER. 296 | Bar in Foo dir -> Foo::Bar" 297 | (rails-core:class-by-file 298 | (if (eq (elt controller-file 0) 47) ;;; 47 == '/' 299 | (subseq controller-file 1) 300 | (let ((current-controller (rails-core:current-controller))) 301 | (if (string-match ":" current-controller) 302 | (concat (replace-regexp-in-string "[^:]*$" "" current-controller) 303 | controller-file) 304 | controller-file))))) 305 | 306 | (defun rails-core:short-controller-name (controller) 307 | "Convert FooController -> Foo." 308 | (remove-postfix controller "Controller" )) 309 | 310 | (defun rails-core:long-controller-name (controller) 311 | "Convert Foo/FooController -> FooController." 312 | (if (string-match "Controller$" controller) 313 | controller 314 | (concat controller "Controller"))) 315 | 316 | ;;;;;;;;;; Functions that return collection of Rails objects ;;;;;;;;;; 317 | (defun rails-core:observer-p (name) 318 | (when name 319 | (if (string-match "\\(Observer\\|_observer\\)\\(\\.rb\\)?$" name) 320 | t nil))) 321 | 322 | (defun rails-core:mailer-p (name) 323 | (when name 324 | (if (string-match "\\(Mailer\\|Notifier\\|_mailer\\|_notifier\\)\\(\\.rb\\)?$" name) 325 | t nil))) 326 | 327 | 328 | (defun rails-core:controllers (&optional cut-contoller-suffix) 329 | "Return a list of Rails controllers. Remove the '_controller' 330 | suffix if CUT-CONTOLLER-SUFFIX is non nil." 331 | (mapcar 332 | #'(lambda (controller) 333 | (rails-core:class-by-file 334 | (if cut-contoller-suffix 335 | (replace-regexp-in-string "_controller\\." "." controller) 336 | controller))) 337 | (delete-if-not 338 | #'(lambda (controller) 339 | (string-match "\\(application\\|[a-z0-9_]+_controller\\)\\.rb$" 340 | controller)) 341 | (find-recursive-files "\\.rb$" (rails-core:file "app/controllers/"))))) 342 | 343 | (defun rails-core:functional-tests () 344 | "Return a list of Rails functional tests." 345 | (mapcar 346 | #'(lambda(it) 347 | (remove-postfix (rails-core:class-by-file it) 348 | "ControllerTest")) 349 | (find-recursive-files "\\.rb$" (rails-core:file "test/functional/")))) 350 | 351 | (defun rails-core:models () 352 | "Return a list of Rails models." 353 | (mapcar 354 | #'rails-core:class-by-file 355 | (delete-if 356 | #'(lambda (file) (or (rails-core:observer-p file) 357 | (rails-core:mailer-p file))) 358 | (find-recursive-files "\\.rb$" (rails-core:file "app/models/"))))) 359 | 360 | (defun rails-core:unit-tests () 361 | "Return a list of Rails functional tests." 362 | (mapcar 363 | #'(lambda(it) 364 | (remove-postfix (rails-core:class-by-file it) 365 | "Test")) 366 | (find-recursive-files "\\.rb$" (rails-core:file "test/unit/")))) 367 | 368 | (defun rails-core:observers () 369 | "Return a list of Rails observers." 370 | (mapcar 371 | #'(lambda (observer) (replace-regexp-in-string "Observer$" "" observer)) 372 | (mapcar 373 | #'rails-core:class-by-file 374 | (find-recursive-files "\\(_observer\\)\\.rb$" (rails-core:file "app/models/"))))) 375 | 376 | (defun rails-core:mailers () 377 | "Return a list of Rails mailers." 378 | (mapcar 379 | #'rails-core:class-by-file 380 | (find-recursive-files "\\(_mailer\\|_notifier\\)\\.rb$" (rails-core:file "app/models/")))) 381 | 382 | (defun rails-core:helpers () 383 | "Return a list of Rails helpers." 384 | (append 385 | (mapcar 386 | #'(lambda (helper) (replace-regexp-in-string "Helper$" "" helper)) 387 | (mapcar 388 | #'rails-core:class-by-file 389 | (find-recursive-files "_helper\\.rb$" (rails-core:file "app/helpers/")))) 390 | (list "Test/TestHelper"))) 391 | 392 | (defun rails-core:migrations (&optional strip-numbers) 393 | "Return a list of Rails migrations." 394 | (let (migrations) 395 | (setq 396 | migrations 397 | (reverse 398 | (mapcar 399 | #'(lambda (migration) 400 | (replace-regexp-in-string "^\\([0-9]+\\)" "\\1 " migration)) 401 | (mapcar 402 | #'rails-core:class-by-file 403 | (find-recursive-files "^[0-9]+_.*\\.rb$" (rails-core:file "db/migrate/")))))) 404 | (if strip-numbers 405 | (mapcar #'(lambda(i) (car (last (split-string i " ")))) 406 | migrations) 407 | migrations))) 408 | 409 | (defun rails-core:migration-versions (&optional with-zero) 410 | "Return a list of migtaion versions as the list of strings. If 411 | second argument WITH-ZERO is present, append the \"000\" version 412 | of migration." 413 | (let ((ver (mapcar 414 | #'(lambda(it) (car (split-string it " "))) 415 | (rails-core:migrations)))) 416 | (if with-zero 417 | (append ver '("000")) 418 | ver))) 419 | 420 | (defun rails-core:plugins () 421 | "Return a list of Rails plugins." 422 | (mapcar 423 | #'file-name-nondirectory 424 | (delete-if-not 425 | #'file-directory-p 426 | (directory-files (rails-core:file "vendor/plugins") t "^[^\\.]")))) 427 | 428 | (defun rails-core:plugin-files (plugin) 429 | "Return a list of files in specific Rails plugin." 430 | (find-recursive-files "^[^.]" (rails-core:file (concat "vendor/plugins/" plugin)))) 431 | 432 | (defun rails-core:layouts () 433 | "Return a list of Rails layouts." 434 | (mapcar 435 | #'(lambda (l) 436 | (replace-regexp-in-string "\\.[^.]+$" "" l)) 437 | (find-recursive-files (rails-core:regex-for-match-view) (rails-core:file "app/views/layouts")))) 438 | 439 | (defun rails-core:fixtures () 440 | "Return a list of Rails fixtures." 441 | (mapcar 442 | #'(lambda (l) 443 | (replace-regexp-in-string "\\.[^.]+$" "" l)) 444 | (find-recursive-files "\\.yml$" (rails-core:file "test/fixtures/")))) 445 | 446 | (defun rails-core:configuration-files () 447 | "Return a files of files from config folder." 448 | (find-recursive-files nil (rails-core:file "config/"))) 449 | 450 | (defun rails-core:regex-for-match-view () 451 | "Return a regex to match Rails view templates. 452 | The file extensions used for views are defined in `rails-templates-list'." 453 | (format "\\.\\(%s\\)$" (strings-join "\\|" rails-templates-list))) 454 | 455 | (defun rails-core:get-view-files (controller-class &optional action) 456 | "Retun a list containing the view file for CONTROLLER-CLASS#ACTION. 457 | If the action is nil, return all views for the controller." 458 | (rails-project:with-root 459 | (root) 460 | (directory-files 461 | (rails-core:file 462 | (rails-core:views-dir 463 | (rails-core:short-controller-name controller-class))) t 464 | (if action 465 | (concat "^" action (rails-core:regex-for-match-view)) 466 | (rails-core:regex-for-match-view))))) 467 | 468 | (defun rails-core:extract-ancestors (classes) 469 | "Return the parent classes from a list of classes named CLASSES." 470 | (delete "" 471 | (uniq-list 472 | (mapcar (lambda (class) 473 | (replace-regexp-in-string 474 | "::[^:]*$" "::" 475 | (replace-regexp-in-string "^[^:]*$" "" class))) 476 | classes)))) 477 | 478 | (defun rails-core:models-ancestors () 479 | "Return the parent classes of models." 480 | (rails-core:extract-ancestors (rails-core:models))) 481 | 482 | (defun rails-core:controllers-ancestors () 483 | "Return the parent classes of controllers." 484 | (rails-core:extract-ancestors (rails-core:controllers))) 485 | 486 | ;;;;;;;;;; Getting Controllers/Model/Action from current buffer ;;;;;;;;;; 487 | 488 | (defun rails-core:current-controller () 489 | "Return the current Rails controller." 490 | (let* ((file-class (rails-core:class-by-file (buffer-file-name)))) 491 | (unless (rails-core:mailer-p file-class) 492 | (case (rails-core:buffer-type) 493 | (:controller (rails-core:short-controller-name file-class)) 494 | (:view (rails-core:class-by-file 495 | (directory-file-name (directory-of-file (buffer-file-name))))) 496 | (:helper (remove-postfix file-class "Helper")) 497 | (:functional-test (remove-postfix file-class "ControllerTest")))))) 498 | 499 | (defun rails-core:current-model () 500 | "Return the current Rails model." 501 | (let* ((file-class (rails-core:class-by-file (buffer-file-name)))) 502 | (unless (rails-core:mailer-p file-class) 503 | (case (rails-core:buffer-type) 504 | (:migration (rails-core:model-by-migration-filename (buffer-name))) 505 | (:model file-class) 506 | (:unit-test (remove-postfix file-class "Test")) 507 | (:fixture (singularize-string file-class)))))) 508 | 509 | (defun rails-core:current-mailer () 510 | "Return the current Rails Mailer, else return nil." 511 | (let* ((file-class (rails-core:class-by-file (buffer-file-name))) 512 | (test (remove-postfix file-class "Test"))) 513 | (when (or (rails-core:mailer-p file-class) 514 | (rails-core:mailer-p test)) 515 | (case (rails-core:buffer-type) 516 | (:mailer file-class) 517 | (:unit-test test) 518 | (:view (rails-core:class-by-file 519 | (directory-file-name (directory-of-file (buffer-file-name))))))))) 520 | 521 | (defun rails-core:current-action () 522 | "Return the current action in the current Rails controller." 523 | (case (rails-core:buffer-type) 524 | (:controller (rails-core:current-method-name)) 525 | (:mailer (rails-core:current-method-name)) 526 | (:view (string-match "/\\([a-z0-9_]+\\)\.[a-z]+$" (buffer-file-name)) 527 | (match-string 1 (buffer-file-name))))) 528 | 529 | (defun rails-core:current-helper () 530 | "Return the current helper" 531 | (rails-core:current-controller)) 532 | 533 | (defun rails-core:current-plugin () 534 | "Return the current plugin name." 535 | (let ((name (buffer-file-name))) 536 | (when (string-match "vendor\\/plugins\\/\\([^\\/]+\\)" name) 537 | (match-string 1 name)))) 538 | 539 | (defun rails-core:current-method-name () 540 | (save-excursion 541 | (when (search-backward-regexp "^[ ]*def \\([a-z0-9_]+\\)" nil t) 542 | (match-string-no-properties 1)))) 543 | 544 | ;;;;;;;;;; Determination of buffer type ;;;;;;;;;; 545 | 546 | (defun rails-core:buffer-file-match (regexp) 547 | "Match the current buffer file name to RAILS_ROOT + REGEXP." 548 | (when-bind (file (rails-core:file regexp)) 549 | (string-match file 550 | (buffer-file-name (current-buffer))))) 551 | 552 | (defun rails-core:buffer-type () 553 | "Return the type of the current Rails file or nil if the type 554 | cannot be determinated." 555 | (loop for (type dir func) in rails-directory<-->types 556 | when (and (rails-core:buffer-file-match dir) 557 | (if func 558 | (apply func (list (buffer-file-name (current-buffer)))) 559 | t)) 560 | do (return type))) 561 | 562 | 563 | ;;;;;;;;;; Rails minor mode Buttons ;;;;;;;;;; 564 | 565 | (define-button-type 'rails-button 566 | 'follow-link t 567 | 'action #'rails-core:button-action) 568 | 569 | (defun rails-core:button-action (button) 570 | (let* ((file-name (button-get button :rails:file-name)) 571 | (line-number (button-get button :rails:line-number)) 572 | (file (rails-core:file file-name))) 573 | (when (and file 574 | (file-exists-p file)) 575 | (find-file-other-window file) 576 | (when line-number 577 | (goto-line line-number))))) 578 | 579 | ;;;;;;;;;; Rails minor mode logs ;;;;;;;;;; 580 | 581 | (defun rails-log-add (message) 582 | "Add MESSAGE to the Rails minor mode log in RAILS_ROOT." 583 | (rails-project:with-root 584 | (root) 585 | (append-string-to-file (rails-core:file "log/rails-minor-mode.log") 586 | (format "%s: %s\n" 587 | (format-time-string "%Y/%m/%d %H:%M:%S") message)))) 588 | 589 | (defun rails-logged-shell-command (command buffer) 590 | "Execute a shell command in the buffer and write the results to 591 | the Rails minor mode log." 592 | (shell-command (format "%s %s" rails-ruby-command command) buffer) 593 | (rails-log-add 594 | (format "\n%s> %s\n%s" (rails-project:name) 595 | command (buffer-string-by-name buffer)))) 596 | 597 | ;;;;;;;;;; Rails menu ;;;;;;;;;; 598 | 599 | (defun rails-core:menu-separator () 600 | (unless (rails-use-text-menu) 'menu (list "--" "--"))) 601 | 602 | (if (fboundp 'completion-posn-at-point-as-event) 603 | (defun rails-core:menu-position () 604 | (completion-posn-at-point-as-event nil nil nil (+ (frame-char-height) 2))) 605 | (defun rails-core:menu-position () 606 | (list '(300 50) (get-buffer-window (current-buffer))))) 607 | 608 | (defun rails-core:menu (menu) 609 | "Show a menu." 610 | (let ((result 611 | (if (rails-use-text-menu) 612 | (tmm-prompt menu) 613 | (x-popup-menu (rails-core:menu-position) 614 | (rails-core:prepare-menu menu))))) 615 | (if (listp result) 616 | (first result) 617 | result))) 618 | 619 | (defvar rails-core:menu-letters-list 620 | (let ((res '())) 621 | (loop for i from (string-to-char "1") upto (string-to-char "9") 622 | do (add-to-list 'res (char-to-string i) t)) 623 | (loop for i from (string-to-char "a") upto (string-to-char "z") 624 | do (add-to-list 'res (char-to-string i) t)) 625 | res) 626 | "List contains 0-9a-z letter") 627 | 628 | (defun rails-core:prepare-menu (menu) 629 | "Append a prefix to each label of menu-item from MENU." 630 | (let ((title (car menu)) 631 | (menu (cdr menu)) 632 | (result '()) 633 | (result-line '()) 634 | (letter 0)) 635 | (dolist (line menu) 636 | (setq result-line '()) 637 | (dolist (it line) 638 | (typecase it 639 | (cons 640 | (if (and (string= (car (rails-core:menu-separator)) (car it)) 641 | (string= (cadr (rails-core:menu-separator)) (cadr it))) 642 | (add-to-list 'result-line it t) 643 | (progn 644 | (add-to-list 'result-line (cons 645 | (format "%s) %s" 646 | (nth letter rails-core:menu-letters-list) 647 | (car it)) 648 | (cdr it)) 649 | t) 650 | (setq letter (+ 1 letter))))) 651 | (t 652 | (add-to-list 'result-line it t)))) 653 | (add-to-list 'result result-line t)) 654 | (cons title result))) 655 | 656 | ;;;;;;;;;; Misc ;;;;;;;;;; 657 | 658 | (defun rails-core:erb-block-string () 659 | "Return the contents of the current ERb block." 660 | (save-excursion 661 | (save-match-data 662 | (let ((start (point))) 663 | (search-backward-regexp "<%[=]?") 664 | (let ((from (match-end 0))) 665 | (search-forward "%>") 666 | (let ((to (match-beginning 0))) 667 | (when (>= to start) 668 | (buffer-substring-no-properties from to)))))))) 669 | 670 | (defun rails-core:rhtml-buffer-p () 671 | "Return non nil if the current buffer is rhtml file." 672 | (string-match "\\.rhtml$" (buffer-file-name))) 673 | 674 | (provide 'rails-core) 675 | -------------------------------------------------------------------------------- /rails-features.el: -------------------------------------------------------------------------------- 1 | ;;; rails-features.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-ruby.el $ 9 | ;; $Id: rails-ruby.el 166 2007-04-05 17:44:57Z dimaexe $ 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 | (defvar rails-features:list 30 | '(rails-snippets-feature 31 | rails-speedbar-feature 32 | rails-rspec-feature) 33 | "List of features") 34 | 35 | (defvar rails-features:installed-p nil) 36 | 37 | (defun rails-features:install () 38 | (unless rails-features:installed-p 39 | (dolist (feature rails-features:list) 40 | (when (require feature nil t) 41 | (apply 42 | (intern (concat (symbol-name feature) ":install")) 43 | (list)))) 44 | (setq rails-features:installed-p t))) 45 | 46 | (provide 'rails-features) -------------------------------------------------------------------------------- /rails-find.el: -------------------------------------------------------------------------------- 1 | ;;; rails-find.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-navigation.el $ 10 | ;; $Id: rails-navigation.el 111 2007-03-24 22:28:12Z dimaexe $ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | (defmacro rails-find:gen (name dir) 29 | "Define new rails-find function" 30 | (let ((dir (concat dir "/"))) 31 | `(defun ,(intern (concat "rails-find:" name)) () 32 | ,(format "Run find-file in Rails \"%s\" dir" dir) 33 | (interactive) 34 | (let ((default-directory (rails-core:file ,dir))) 35 | (call-interactively ',(if (fboundp 'ido-find-file) 36 | 'ido-find-file 37 | 'find-file)))))) 38 | 39 | (rails-find:gen "controller" "app/controllers") 40 | (rails-find:gen "view" "app/views") 41 | (rails-find:gen "layout" "app/views/layouts") 42 | (rails-find:gen "db" "db") 43 | (rails-find:gen "public" "public") 44 | (rails-find:gen "helpers" "app/helpers") 45 | (rails-find:gen "models" "app/models") 46 | (rails-find:gen "config" "config") 47 | (rails-find:gen "lib" "lib") 48 | (rails-find:gen "tasks" "lib/tasks") 49 | (rails-find:gen "stylesheets" "public/stylesheets") 50 | (rails-find:gen "javascripts" "public/javascripts") 51 | (rails-find:gen "migrate" "db/migrate") 52 | (rails-find:gen "fixtures" "test/fixtures") 53 | 54 | ;; Rspec 55 | (rails-find:gen "spec" "spec/") 56 | (rails-find:gen "spec-controllers" "spec/controllers/") 57 | (rails-find:gen "spec-models" "spec/models/") 58 | (rails-find:gen "spec-helpers" "spec/helpers/") 59 | (rails-find:gen "spec-fixtures" "spec/fixtures/") 60 | 61 | (provide 'rails-find) -------------------------------------------------------------------------------- /rails-fixture-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-fixture-minor-mode.el --- minor mode for RubyOnRails fixtures 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-fixture-minor-mode 30 | "Minor mode for RubyOnRails fixtures." 31 | :lighter " Fixture" 32 | :keymap (rails-model-layout:keymap :fixture) 33 | (setq rails-primary-switch-func 'rails-model-layout:switch-to-unit-test) 34 | (setq rails-secondary-switch-func 'rails-model-layout:menu)) 35 | 36 | (provide 'rails-fixture-minor-mode) -------------------------------------------------------------------------------- /rails-functional-test-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-functional-test-minor-mode.el --- minor mode for RubyOnRails functional tests 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-functional-test-minor-mode 30 | "Minor mode for RubyOnRails functional tests." 31 | :lighter " FTest" 32 | :keymap (let ((map (rails-controller-layout:keymap :functional-test))) 33 | (define-key map rails-minor-mode-test-current-method-key 'rails-test:run-current-method) 34 | (define-key map [menu-bar rails-controller-layout run] '("Test current method" . rails-test:run-current-method)) 35 | map) 36 | (setq rails-primary-switch-func 'rails-controller-layout:switch-to-controller) 37 | (setq rails-secondary-switch-func 'rails-controller-layout:menu)) 38 | 39 | (provide 'rails-functional-test-minor-mode) -------------------------------------------------------------------------------- /rails-helper-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-helper-minor-mode.el --- minor mode for RubyOnRails helpers 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-helper-minor-mode 30 | "Minor mode for RubyOnRails helpers." 31 | :lighter " Helper" 32 | :keymap (rails-controller-layout:keymap :helper) 33 | (setq rails-primary-switch-func 'rails-controller-layout:switch-to-controller) 34 | (setq rails-secondary-switch-func 'rails-controller-layout:menu)) 35 | 36 | (provide 'rails-helper-minor-mode) -------------------------------------------------------------------------------- /rails-layout-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-layout-minor-mode.el --- minor mode for RubyOnRails layouts 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-layout-minor-mode 30 | "Minor mode for RubyOnRails layouts." 31 | nil 32 | " layout" 33 | nil) 34 | 35 | (provide 'rails-layout-minor-mode) 36 | -------------------------------------------------------------------------------- /rails-lib.el: -------------------------------------------------------------------------------- 1 | ;;; rails-lib.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | ;; Howard Yeh 8 | 9 | ;; Keywords: ruby rails languages oop 10 | ;; $URL$ 11 | ;; $Id$ 12 | 13 | ;;; License 14 | 15 | ;; This program is free software; you can redistribute it and/or 16 | ;; modify it under the terms of the GNU General Public License 17 | ;; as published by the Free Software Foundation; either version 2 18 | ;; of the License, or (at your option) any later version. 19 | 20 | ;; This program is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with this program; if not, write to the Free Software 27 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 28 | 29 | ;;; Code: 30 | 31 | (defun rails-lib:run-primary-switch () 32 | "Run the primary switch function." 33 | (interactive) 34 | (if rails-primary-switch-func 35 | (apply rails-primary-switch-func nil))) 36 | 37 | (defun rails-lib:run-secondary-switch () 38 | "Run the secondary switch function." 39 | (interactive) 40 | (if rails-secondary-switch-func 41 | (apply rails-secondary-switch-func nil))) 42 | 43 | ;;;;; Non Rails realted helper functions ;;;;; 44 | 45 | ;; Syntax macro 46 | 47 | (defmacro* when-bind ((var expr) &rest body) 48 | "Binds VAR to the result of EXPR. 49 | If EXPR is not nil exeutes BODY. 50 | 51 | (when-bind (var (func foo)) 52 | (do-somth (with var)))." 53 | `(let ((,var ,expr)) 54 | (when ,var 55 | ,@body))) 56 | 57 | ;; Lists 58 | 59 | (defun list->alist (list) 60 | "Convert ((a . b) c d) to ((a . b) (c . c) (d . d))." 61 | (mapcar 62 | #'(lambda (el) 63 | (if (listp el) el(cons el el))) 64 | list)) 65 | 66 | (defun uniq-list (list) 67 | "Return a list of unique elements." 68 | (let ((result '())) 69 | (dolist (elem list) 70 | (when (not (member elem result)) 71 | (push elem result))) 72 | (nreverse result))) 73 | 74 | ;; Strings 75 | 76 | (defun string-repeat (char num) 77 | (let ((len num) 78 | (str "")) 79 | (while (not (zerop len)) 80 | (setq len (- len 1)) 81 | (setq str (concat char str))) 82 | str)) 83 | 84 | 85 | (defmacro string=~ (regex string &rest body) 86 | "regex matching similar to the =~ operator found in other languages." 87 | (let ((str (gensym))) 88 | `(lexical-let ((,str ,string)) 89 | ;; Use lexical-let to make closures (in flet). 90 | (when (string-match ,regex ,str) 91 | (symbol-macrolet ,(loop for i to 9 collect 92 | (let ((sym (intern (concat "$" (number-to-string i))))) 93 | `(,sym (match-string ,i ,str)))) 94 | (flet (($ (i) (match-string i ,str)) 95 | (sub (replacement &optional (i 0) &key fixedcase literal-string) 96 | (replace-match replacement fixedcase literal-string ,str i))) 97 | (symbol-macrolet ( ;;before 98 | ($b (substring ,str 0 (match-beginning 0))) 99 | ;;match 100 | ($m (match-string 0 ,str)) 101 | ;;after 102 | ($a (substring ,str (match-end 0) (length ,str)))) 103 | ,@body))))))) 104 | 105 | (defun decamelize (string) 106 | "Convert from CamelCaseString to camel_case_string." 107 | (let ((case-fold-search nil)) 108 | (downcase 109 | (replace-regexp-in-string 110 | "\\([A-Z]+\\)\\([A-Z][a-z]\\)" "\\1_\\2" 111 | (replace-regexp-in-string 112 | "\\([a-z0-9]\\)\\([A-Z]\\)" "\\1_\\2" 113 | string))))) 114 | 115 | (defun string-not-empty (str) ;(+) 116 | "Return t if string STR is not empty." 117 | (and (stringp str) (not (or (string-equal "" str) 118 | (string-match "^ +$" str))))) 119 | 120 | (defun yml-value (name) 121 | "Return the value of the parameter named NAME in the current 122 | buffer or an empty string." 123 | (save-excursion 124 | (goto-char (point-min)) 125 | (if (search-forward-regexp (format "%s:[ ]*\\(.*\\)[ ]*$" name) nil t) 126 | (match-string 1) 127 | ""))) 128 | 129 | (defun current-line-string () 130 | "Return the string value of the current line." 131 | (buffer-substring-no-properties 132 | (progn (beginning-of-line) (point)) 133 | (progn (end-of-line) (point)))) 134 | 135 | (defun remove-prefix (word prefix) 136 | "Remove the PREFIX string in WORD if it exists. 137 | PrefixBla -> Bla." 138 | (replace-regexp-in-string (format "^%s" prefix) "" word)) 139 | 140 | (defun remove-postfix (word postfix) 141 | "Remove the POSTFIX string in WORD if it exists. 142 | BlaPostfix -> Bla." 143 | (replace-regexp-in-string (format "%s$" postfix) "" word)) 144 | 145 | (defun strings-join (separator strings) 146 | "Join all STRINGS using a SEPARATOR." 147 | (mapconcat 'identity strings separator)) 148 | 149 | (defalias 'string-join 'strings-join) 150 | 151 | (defun capital-word-p (word) 152 | "Return t if first letter of WORD is uppercased." 153 | (= (elt word 0) 154 | (elt (capitalize word) 0))) 155 | 156 | ;;;;;;;; def-snips stuff ;;;; 157 | 158 | (defun snippet-abbrev-function-name (abbrev-table abbrev-name) 159 | "Return the name of the snippet abbreviation function in the 160 | ABBREV-TABLE for the abbreviation ABBREV-NAME." 161 | (intern (concat "snippet-abbrev-" 162 | (snippet-strip-abbrev-table-suffix 163 | (symbol-name abbrev-table)) 164 | "-" 165 | abbrev-name))) 166 | 167 | (defun snippet-menu-description-variable (table name) 168 | "Return a variable for the menu description of the snippet ABBREV-NAME in ABBREV-TABLE." 169 | (intern 170 | (concat 171 | (symbol-name (snippet-abbrev-function-name table name)) 172 | "-menu-description"))) 173 | 174 | (defmacro* def-snips ((&rest abbrev-tables) &rest snips) 175 | "Generate snippets with menu documentaion in several ABBREV-TABLES. 176 | 177 | (def-snip (some-mode-abbrev-table other-mode-abbrev-table) 178 | (\"abbr\" \"some snip $${foo}\" \"menu documentation\") 179 | (\"anabr\" \"other snip $${bar}\" \"menu documentation\") 180 | " 181 | `(progn 182 | ,@(loop for table in abbrev-tables 183 | collect 184 | `(snippet-with-abbrev-table ',table 185 | ,@(loop for (name template desc) in snips collect 186 | `(,name . ,template))) 187 | append 188 | (loop for (name template desc) in snips collect 189 | `(setf ,(snippet-menu-description-variable table name) 190 | ,desc))))) 191 | 192 | (defun snippet-menu-description (abbrev-table name) 193 | "Return the menu descripton for the snippet named NAME in 194 | ABBREV-TABLE." 195 | (symbol-value (snippet-menu-description-variable abbrev-table name))) 196 | 197 | (defun snippet-menu-line (abbrev-table name) 198 | "Generate a menu line for the snippet NAME in ABBREV-TABLE." 199 | (cons 200 | (concat name "\t" (snippet-menu-description abbrev-table name)) 201 | (lexical-let ((func-name (snippet-abbrev-function-name abbrev-table name))) 202 | (lambda () (interactive) (funcall func-name))))) 203 | 204 | ;;; Define keys 205 | 206 | (defmacro define-keys (key-map &rest key-funcs) 207 | "Define key bindings for KEY-MAP (create KEY-MAP, if it does 208 | not exist." 209 | `(progn 210 | (unless (boundp ',key-map) 211 | (setf ,key-map (make-keymap))) 212 | ,@(mapcar 213 | #'(lambda (key-func) 214 | `(define-key ,key-map ,(first key-func) ,(second key-func))) 215 | key-funcs))) 216 | 217 | ;; Files 218 | 219 | (defun append-string-to-file (file string) 220 | "Append a string to end of a file." 221 | (write-region string nil file t)) 222 | 223 | (defun write-string-to-file (file string) 224 | "Write a string to a file (erasing the previous content)." 225 | (write-region string nil file)) 226 | 227 | (defun read-from-file (file-name) 228 | "Read sexpr from a file named FILE-NAME." 229 | (with-temp-buffer 230 | (insert-file-contents file-name) 231 | (read (current-buffer)))) 232 | 233 | ;; File hierarchy functions 234 | 235 | (defun find-recursive-files (file-regexp directory) 236 | "Return a list of files, found in DIRECTORY and match them to FILE-REGEXP." 237 | (find-recursive-filter-out 238 | find-recursive-exclude-files 239 | (find-recursive-directory-relative-files directory "" file-regexp))) 240 | 241 | (defun directory-name (path) 242 | "Return the name of a directory with a given path. 243 | For example, (path \"/foo/bar/baz/../\") returns bar." 244 | ;; Rewrite me 245 | (let ((old-path default-directory)) 246 | (cd path) 247 | (let ((dir (pwd))) 248 | (cd old-path) 249 | (replace-regexp-in-string "^Directory[ ]*" "" dir)))) 250 | 251 | (defun find-or-ask-to-create (question file) 252 | "Open file if it exists. If it does not exist, ask to create 253 | it." 254 | (if (file-exists-p file) 255 | (find-file file) 256 | (when (y-or-n-p question) 257 | (when (string-match "\\(.*\\)/[^/]+$" file) 258 | (make-directory (match-string 1 file) t)) 259 | (find-file file)))) 260 | 261 | (defun directory-of-file (file-name) 262 | "Return the parent directory of a file named FILE-NAME." 263 | (replace-regexp-in-string "[^/]*$" "" file-name)) 264 | 265 | (defmacro* in-directory ((directory) &rest body) 266 | (let ((before-directory (gensym))) 267 | `(let ((,before-directory default-directory) 268 | (default-directory ,directory)) 269 | (cd ,directory) 270 | ,@body 271 | (cd ,before-directory)))) 272 | 273 | 274 | ;; Buffers 275 | 276 | (defun buffer-string-by-name (buffer-name) 277 | "Return the content of buffer named BUFFER-NAME as a string." 278 | (interactive) 279 | (save-excursion 280 | (set-buffer buffer-name) 281 | (buffer-string))) 282 | 283 | (defun buffer-visible-p (buffer-name) 284 | (if (get-buffer-window buffer-name) t nil)) 285 | 286 | ;; Misc 287 | 288 | (defun rails-browse-api-url (url) 289 | "Browse preferentially with Emacs w3m browser." 290 | (if rails-browse-api-with-w3m 291 | (when (fboundp 'w3m-find-file) 292 | (w3m-find-file (remove-prefix url "file://"))) 293 | (rails-alternative-browse-url url))) 294 | 295 | (defun rails-alternative-browse-url (url &rest args) 296 | "Fix a problem with Internet Explorer not being able to load 297 | URLs with anchors via ShellExecute. It will only be invoked it 298 | the user explicit sets `rails-use-alternative-browse-url'." 299 | (if (and (eq system-type 'windows-nt) rails-use-alternative-browse-url) 300 | (w32-shell-execute "open" "iexplore" url) 301 | (browse-url url args))) 302 | 303 | ;; abbrev 304 | ;; from http://www.opensource.apple.com/darwinsource/Current/emacs-59/emacs/lisp/derived.el 305 | (defun merge-abbrev-tables (old new) 306 | "Merge an old abbrev table into a new one. 307 | This function requires internal knowledge of how abbrev tables work, 308 | presuming that they are obarrays with the abbrev as the symbol, the expansion 309 | as the value of the symbol, and the hook as the function definition." 310 | (when old 311 | (mapatoms 312 | (lambda(it) 313 | (or (intern-soft (symbol-name it) new) 314 | (define-abbrev new 315 | (symbol-name it) 316 | (symbol-value it) 317 | (symbol-function it) 318 | nil 319 | t))) 320 | old))) 321 | 322 | ;; Colorize 323 | 324 | (defun apply-colorize-to-buffer (name) 325 | (let ((buffer (current-buffer))) 326 | (set-buffer name) 327 | (make-local-variable 'after-change-functions) 328 | (add-hook 'after-change-functions 329 | '(lambda (start end len) 330 | (ansi-color-apply-on-region start end))) 331 | (set-buffer buffer))) 332 | 333 | ;; completion-read 334 | (defun rails-completing-read (prompt table history require-match) 335 | (let ((history-value (symbol-value history))) 336 | (list (completing-read 337 | (format "%s?%s: " 338 | prompt 339 | (if (car history-value) 340 | (format " (%s)" (car history-value)) 341 | "")) 342 | (list->alist table) ; table 343 | nil ; predicate 344 | require-match ; require-match 345 | nil ; initial input 346 | history ; hist 347 | (car history-value))))) ;def 348 | 349 | ;; railsy-replace 350 | (defun camelized-p (string) 351 | "Return nil unless string is in camelized format (first character is capital, there is at least on lower capital and all characters are letters of numbers" 352 | (let ((case-fold-search nil)) 353 | (string-match "^[A-Z][A-Za-z0-9]*[a-z]+[A-Za-z0-9]*$" string))) 354 | 355 | (defun underscored-p (string) 356 | "Return nil unless string is in underscored format (containing only lower case characters, numbers or underscores)" 357 | (let ((case-fold-search nil)) 358 | (string-match "^[a-z][a-z0-9_]*$" string))) 359 | 360 | (defun replace-rails-variable () 361 | (interactive) 362 | ) 363 | 364 | ;; MMM 365 | 366 | ;; (defvar mmm-indent-sandbox-finish-position nil) 367 | 368 | ;; (defun mmm-run-indent-with-sandbox (indent-func) 369 | ;; (interactive) 370 | ;; (let* ((fragment-name "*mmm-indent-sandbox*") 371 | ;; (ovl (mmm-overlay-at (point))) 372 | ;; (current (when ovl (overlay-buffer ovl))) 373 | ;; (start (when ovl (overlay-start ovl))) 374 | ;; (end (when ovl (overlay-end ovl))) 375 | ;; (current-pos (when ovl (point))) 376 | ;; (ovl-line-start (when start 377 | ;; (progn (goto-char start) 378 | ;; (line-beginning-position)))) 379 | ;; (current-line-start (when current-pos 380 | ;; (progn (goto-char current-pos) 381 | ;; (line-beginning-position)))) 382 | ;; (fragment-pos (when (and start end) (- (point) (- start 1)))) 383 | ;; (ovl-offset (when ovl (- (progn 384 | ;; (goto-char start) 385 | ;; (while (not (looking-at "<")) 386 | ;; (goto-char (- (point) 1))) 387 | ;; (point)) 388 | ;; ovl-line-start))) 389 | ;; (content (when (and start end) (buffer-substring-no-properties start end))) 390 | ;; (fragment (when content (get-buffer-create fragment-name)))) 391 | ;; (when fragment 392 | ;; (setq mmm-indent-sandbox-finish-position nil) 393 | ;; (save-excursion 394 | ;; (set-buffer fragment-name) 395 | ;; (beginning-of-buffer) 396 | ;; (insert content) 397 | ;; (goto-char fragment-pos) 398 | ;; (funcall indent-func t) 399 | ;; (let ((start-line) 400 | ;; (end-line) 401 | ;; (kill-after-start) 402 | ;; (finish-pos (- (+ start (point)) 1)) 403 | ;; (indented (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) 404 | ;; (set-buffer current) 405 | ;; (kill-buffer fragment-name) 406 | ;; (princ ovl-offset) 407 | ;; (goto-char current-pos) 408 | ;; (setq start-line (line-beginning-position)) 409 | ;; (setq end-line (line-end-position)) 410 | ;; (when (> start start-line) 411 | ;; (setq start-line (+ start 1)) 412 | ;; (setq kill-after-start t)) 413 | ;; (when (> end-line end) 414 | ;; (setq end-line end)) 415 | ;; (kill-region start-line end-line) 416 | ;; (goto-char start-line) 417 | ;; (unless (= ovl-line-start current-line-start) 418 | ;; (dotimes (i ovl-offset) 419 | ;; (setq indented (concat " " indented)))) 420 | ;; ;; (insert-char (string-to-char " ") ovl-offset)) 421 | ;; (insert indented) 422 | ;; (when kill-after-start 423 | ;; (goto-char (+ start 1)) 424 | ;; (backward-delete-char 1)) 425 | ;; ;; (setq mmm-indent-sandbox-finish-position finish-pos))) 426 | ;; (if (= ovl-line-start current-line-start) 427 | ;; (setq mmm-indent-sandbox-finish-position finish-pos) 428 | ;; (setq mmm-indent-sandbox-finish-position (+ finish-pos ovl-offset))))) 429 | ;; (goto-char mmm-indent-sandbox-finish-position)))) 430 | 431 | ;; (defadvice ruby-indent-line (around mmm-sandbox-ruby-indent-line) 432 | ;; (if (and (fboundp 'mmm-overlay-at) 433 | ;; (mmm-overlay-at (point))) 434 | ;; (mmm-run-indent-with-sandbox 'ruby-indent-line) 435 | ;; ad-do-it)) 436 | ;; (ad-activate 'ruby-indent-line) 437 | 438 | 439 | ;; Cross define functions from my rc files 440 | 441 | (provide 'rails-lib) -------------------------------------------------------------------------------- /rails-log.el: -------------------------------------------------------------------------------- 1 | ;;; rails-log.el --- provide features for Rails log files 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defvar rails-log:last-log nil) 30 | 31 | (defun rails-log:files () 32 | (directory-files (rails-core:file "log") nil "\\.log$")) 33 | 34 | (defun rails-log:buffer-name (log-file) 35 | (concat "*" log-file "*")) 36 | 37 | (defun rails-log:open-file (log-file) 38 | (let ((buffer (rails-log:buffer-name log-file)) 39 | (current (buffer-name))) 40 | (unless (get-buffer buffer) 41 | (get-buffer-create buffer) 42 | (set-buffer buffer) 43 | (setq auto-window-vscroll t) 44 | (rails-minor-mode t) 45 | (setq buffer-read-only t) 46 | (set-buffer current) 47 | (apply-colorize-to-buffer buffer)) 48 | (start-process "tail" 49 | buffer 50 | "tail" 51 | "-n" (message "%d" rails-number-of-lines-shown-when-opening-log-file) 52 | "-f" (rails-core:file (concat "log/" log-file))))) 53 | 54 | (defun rails-log:open (log-file) 55 | (interactive 56 | (list (completing-read "Select log (with autocomplete): " 57 | (list->alist (rails-log:files)) 58 | nil 59 | t 60 | rails-log:last-log))) 61 | (setq rails-log:last-log log-file) 62 | (let ((name (rails-log:buffer-name log-file))) 63 | (unless (get-buffer name) 64 | (rails-log:open-file log-file)) 65 | (switch-to-buffer name) 66 | (recenter t))) 67 | 68 | (defun rails-log:open-production () 69 | (interactive) 70 | (rails-log:open "production.log")) 71 | 72 | (defun rails-log:open-development () 73 | (interactive) 74 | (rails-log:open "development.log")) 75 | 76 | (defun rails-log:open-test () 77 | (interactive) 78 | (rails-log:open "test.log")) 79 | 80 | (provide 'rails-log) -------------------------------------------------------------------------------- /rails-mailer-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-mailer-minor-mode.el --- minor mode for RubyOnRails mailers 2 | 3 | ;; Copyright (C) 2006-2007 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | ;;; Code: 29 | 30 | (define-minor-mode rails-mailer-minor-mode 31 | "Minor mode for RubyOnRails mailers." 32 | :lighter " Mailer" 33 | :keymap (rails-controller-layout:keymap :mailer) 34 | (setq rails-secondary-switch-func 'rails-controller-layout:menu) 35 | (setq rails-primary-switch-func 'rails-controller-layout:toggle-action-view)) 36 | 37 | (provide 'rails-mailer-minor-mode) 38 | -------------------------------------------------------------------------------- /rails-migration-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-migration-minor-mode.el --- minor mode for RubyOnRails migration 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-migration-minor-mode 30 | "Minor mode for RubyOnRails migrations." 31 | :lighter " Migration" 32 | :keymap (rails-model-layout:keymap :migration) 33 | (setq rails-primary-switch-func nil) 34 | (setq rails-secondary-switch-func 'rails-model-layout:menu)) 35 | 36 | (provide 'rails-migration-minor-mode) -------------------------------------------------------------------------------- /rails-model-layout.el: -------------------------------------------------------------------------------- 1 | ;;; rails-model-layout.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defun rails-model-layout:keymap (type) 30 | (let* ((name (capitalize (substring (symbol-name type) 1))) 31 | (map (make-sparse-keymap)) 32 | (menu (make-sparse-keymap))) 33 | (when type 34 | (define-keys menu 35 | ([goto-model] '(menu-item "Go to Model" 36 | rails-model-layout:switch-to-model 37 | :enable (and (not (eq (rails-core:buffer-type) :model)) 38 | (rails-core:model-exist-p (rails-core:current-model))))) 39 | ([goto-utest] '(menu-item "Go to Unit Test" 40 | rails-model-layout:switch-to-unit-test 41 | :enable (and (not (eq (rails-core:buffer-type) :unit-test)) 42 | (rails-core:unit-test-exist-p (or (rails-core:current-model) 43 | (rails-core:current-mailer)))))) 44 | ([goto-migration] '(menu-item "Go to Migration" 45 | rails-model-layout:switch-to-migration 46 | :enable (and (not (eq (rails-core:buffer-type) :migration)) 47 | (rails-core:migration-file-by-model (rails-core:current-model))))) 48 | ([goto-controller] '(menu-item "Go to Controller" 49 | rails-model-layout:switch-to-controller 50 | :enable (rails-core:controller-file-by-model (rails-core:current-model)))) 51 | ([goto-fixture] '(menu-item "Go to Fixture" 52 | rails-model-layout:switch-to-fixture 53 | :enable (and (not (eq (rails-core:buffer-type) :fixture)) 54 | (rails-core:fixture-exist-p (rails-core:current-model))))) 55 | ([goto-mailer] '(menu-item "Go to Mailer" 56 | rails-model-layout:switch-to-mailer 57 | :enable (rails-core:mailer-exist-p (rails-core:current-mailer))))) 58 | (define-keys map 59 | ((rails-key "m") 'rails-model-layout:switch-to-model) 60 | ((rails-key "u") 'rails-model-layout:switch-to-unit-test) 61 | ((rails-key "g") 'rails-model-layout:switch-to-migration) 62 | ((rails-key "c") 'rails-model-layout:switch-to-controller) 63 | ((rails-key "x") 'rails-model-layout:switch-to-fixture) 64 | ((rails-key "n") 'rails-model-layout:switch-to-mailer) 65 | ([menu-bar rails-model-layout] (cons name menu)))) 66 | map)) 67 | 68 | (defun rails-model-layout:switch-to (type) 69 | (let* ((name (capitalize (substring (symbol-name type) 1))) 70 | (model (rails-core:current-model)) 71 | (controller (rails-core:current-controller)) 72 | (mailer (rails-core:current-mailer)) 73 | (item (if controller controller model)) 74 | (item (case type 75 | (:mailer (rails-core:mailer-file mailer)) 76 | (:controller (rails-core:controller-file-by-model model)) 77 | (:fixture (rails-core:fixture-file model)) 78 | (:unit-test (rails-core:unit-test-file item)) 79 | (:model (rails-core:model-file model)) 80 | (:migration (rails-core:migration-file-by-model model))))) 81 | (if item 82 | (let ((file (rails-core:file item))) 83 | (if (file-exists-p file) 84 | (progn 85 | (find-file file) 86 | (message (format "%s: %s" (substring (symbol-name type) 1) item))) 87 | (message "File %s not exists" file))) 88 | (message "%s not found" name)))) 89 | 90 | (defun rails-model-layout:switch-to-mailer () (interactive) (rails-model-layout:switch-to :mailer)) 91 | (defun rails-model-layout:switch-to-controller () (interactive) (rails-model-layout:switch-to :controller)) 92 | (defun rails-model-layout:switch-to-fixture () (interactive) (rails-model-layout:switch-to :fixture)) 93 | (defun rails-model-layout:switch-to-unit-test () (interactive) (rails-model-layout:switch-to :unit-test)) 94 | (defun rails-model-layout:switch-to-model () (interactive) (rails-model-layout:switch-to :model)) 95 | (defun rails-model-layout:switch-to-migration () (interactive) (rails-model-layout:switch-to :migration)) 96 | 97 | (defun rails-model-layout:menu () 98 | (interactive) 99 | (let* ((item (list)) 100 | (type (rails-core:buffer-type)) 101 | (title (capitalize (substring (symbol-name type) 1))) 102 | (model (rails-core:current-model)) 103 | (controller (pluralize-string model)) 104 | (mailer (rails-core:current-mailer))) 105 | (when model 106 | (when (and (not (eq type :migration)) 107 | (rails-core:migration-file-by-model model)) 108 | (add-to-list 'item (cons "Migration" :migration))) 109 | (unless (eq type :fixture) 110 | (add-to-list 'item (cons "Fixture" :fixture))) 111 | (when (rails-core:controller-exist-p controller) 112 | (add-to-list 'item (cons "Controller" :controller))) 113 | (unless (eq type :unit-test) 114 | (add-to-list 'item (cons "Unit Test" :unit-test))) 115 | (unless (eq type :model) 116 | (add-to-list 'item (cons "Model" :model)))) 117 | (when mailer 118 | (setq item (rails-controller-layout:views-menu model)) 119 | (add-to-list 'item (rails-core:menu-separator)) 120 | (add-to-list 'item (cons "Mailer" :mailer))) 121 | (when item 122 | (setq item 123 | (rails-core:menu 124 | (list (concat title " " model) 125 | (cons "Please select.." 126 | item)))) 127 | (typecase item 128 | (symbol (rails-model-layout:switch-to item)) 129 | (string (rails-core:find-file-if-exist item)))))) 130 | 131 | (provide 'rails-model-layout) -------------------------------------------------------------------------------- /rails-model-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-model-minor-mode.el --- minor mode for RubyOnRails models 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-model-minor-mode 30 | "Minor mode for RubyOnRails models." 31 | :lighter " Model" 32 | :keymap (rails-model-layout:keymap :model) 33 | (setq rails-primary-switch-func 'rails-model-layout:switch-to-unit-test) 34 | (setq rails-secondary-switch-func 'rails-model-layout:menu)) 35 | 36 | (provide 'rails-model-minor-mode) -------------------------------------------------------------------------------- /rails-navigation.el: -------------------------------------------------------------------------------- 1 | ;;; rails-navigation.el --- emacs-rails navigation functions 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | (defun rails-nav:create-goto-menu (items title &optional append-to-menu) 29 | (when append-to-menu 30 | (dolist (l append-to-menu items) 31 | (add-to-list 'items l t))) 32 | (let ((selected 33 | (when items 34 | (rails-core:menu 35 | (list title (cons title items)))))) 36 | (if selected selected (message "No files found")))) 37 | 38 | (defun rails-nav:goto-file-with-menu (dir title &optional ext no-inflector append-to-menu) 39 | "Make a menu to choose files from and find-file it." 40 | (let* (file 41 | files 42 | (ext (if ext ext "rb")) 43 | (ext (concat "\\." ext "$")) 44 | (dir (rails-core:file dir))) 45 | (setq files (find-recursive-directory-relative-files dir "" ext)) 46 | (setq files (sort files 'string<)) 47 | (setq files (mapcar 48 | #'(lambda(f) 49 | (list 50 | (if no-inflector f (rails-core:class-by-file f)) 51 | f)) 52 | files)) 53 | (when-bind 54 | (selected (rails-nav:create-goto-menu files title append-to-menu)) 55 | (if (symbolp selected) 56 | (apply selected (list)) 57 | (rails-core:find-file-if-exist (concat dir selected)))))) 58 | 59 | (defun rails-nav:goto-file-with-menu-from-list (items title func &optional append-to-menu) 60 | (when-bind 61 | (selected (rails-nav:create-goto-menu (list->alist items) title append-to-menu)) 62 | (when-bind 63 | (file (apply func (list selected))) 64 | (rails-core:find-file-if-exist file)))) 65 | 66 | (defun rails-nav:goto-controllers () 67 | "Go to controllers." 68 | (interactive) 69 | (rails-nav:goto-file-with-menu-from-list 70 | (rails-core:controllers t) 71 | "Go to controller" 72 | 'rails-core:controller-file)) 73 | 74 | (defun rails-nav:goto-models () 75 | "Go to models." 76 | (interactive) 77 | (rails-nav:goto-file-with-menu-from-list 78 | (rails-core:models) 79 | "Go to model.." 80 | 'rails-core:model-file)) 81 | 82 | (defun rails-nav:goto-functional-tests () 83 | "Go to functional tests." 84 | (interactive) 85 | (rails-nav:goto-file-with-menu-from-list 86 | (rails-core:functional-tests) 87 | "Go to functional test." 88 | 'rails-core:functional-test-file)) 89 | 90 | (defun rails-nav:goto-unit-tests () 91 | "Go to functional tests." 92 | (interactive) 93 | (rails-nav:goto-file-with-menu-from-list 94 | (rails-core:unit-tests) 95 | "Go to unit test." 96 | 'rails-core:unit-test-file)) 97 | 98 | (defun rails-nav:goto-observers () 99 | "Go to observers." 100 | (interactive) 101 | (rails-nav:goto-file-with-menu-from-list 102 | (rails-core:observers) 103 | "Go to observer.." 104 | 'rails-core:observer-file)) 105 | 106 | (defun rails-nav:goto-mailers () 107 | "Go to mailers." 108 | (interactive) 109 | (rails-nav:goto-file-with-menu-from-list 110 | (rails-core:mailers) 111 | "Go to mailers.." 112 | 'rails-core:mailer-file)) 113 | 114 | (defun rails-nav:goto-migrate () 115 | "Go to migrations." 116 | (interactive) 117 | (rails-nav:goto-file-with-menu-from-list 118 | (rails-core:migrations) 119 | "Go to migrate.." 120 | 'rails-core:migration-file)) 121 | 122 | (defun rails-nav:goto-helpers () 123 | "Go to helpers." 124 | (interactive) 125 | (rails-nav:goto-file-with-menu-from-list 126 | (rails-core:helpers) 127 | "Go to helper.." 128 | 'rails-core:helper-file)) 129 | 130 | (defun rails-nav:goto-plugins () 131 | "Go to plugins." 132 | (interactive) 133 | (rails-nav:goto-file-with-menu-from-list 134 | (rails-core:plugins) 135 | "Go to plugin.." 136 | (lambda (plugin) 137 | (concat "vendor/plugins/" plugin "/init.rb")))) 138 | 139 | (defun rails-nav:create-new-layout (&optional name) 140 | "Create a new layout." 141 | (let ((name (or name (read-string "Layout name? ")))) 142 | (when name 143 | (rails-core:find-file (rails-core:layout-file name)) 144 | (if (y-or-n-p "Insert initial template? ") 145 | (insert rails-layout-template))))) 146 | 147 | (defun rails-nav:goto-layouts () 148 | "Go to layouts." 149 | (interactive) 150 | (let ((items (list (rails-core:menu-separator) 151 | (cons "Create new layout" 'rails-nav:create-new-layout)))) 152 | (rails-nav:goto-file-with-menu-from-list 153 | (rails-core:layouts) 154 | "Go to layout.." 155 | (lambda (l) 156 | (if (stringp l) 157 | (rails-core:layout-file l) 158 | (apply l (list)))) 159 | items))) 160 | 161 | (defun rails-nav:goto-fixtures () 162 | "Go to fixtures." 163 | (interactive) 164 | (rails-nav:goto-file-with-menu-from-list 165 | (rails-core:fixtures) 166 | "Go to fixture.." 167 | 'rails-core:fixture-file)) 168 | 169 | (defun rails-nav:goto-stylesheets () 170 | "Go to stylesheets." 171 | (interactive) 172 | (rails-nav:goto-file-with-menu "public/stylesheets/" "Go to stylesheet.." "css" t)) 173 | 174 | (defun rails-nav:goto-javascripts () 175 | "Go to JavaScripts." 176 | (interactive) 177 | (rails-nav:goto-file-with-menu "public/javascripts/" "Go to stylesheet.." "js" t)) 178 | 179 | ;;;;;;;;;; Goto file on current line ;;;;;;;;;; 180 | 181 | (defmacro* def-goto-line (name (&rest conditions) &rest body) 182 | "Go to the file specified by the current line. Parses the 183 | current line for a series of patterns." 184 | (let ((line (gensym)) 185 | (field (gensym)) 186 | (prefix (gensym))) 187 | `(progn 188 | (defun ,name (,line ,prefix) 189 | (block ,name 190 | ,@(loop for (sexpr . map) in conditions 191 | collect 192 | `(when (string-match ,sexpr ,line) 193 | (let ,(loop for var-acc in map collect 194 | (if (listp var-acc) 195 | `(,(first var-acc) (match-string ,(second var-acc) ,line)) 196 | var-acc)) 197 | (return-from ,name (progn ,@body)))))))))) 198 | 199 | (defun rails-goto-file-on-current-line (prefix) 200 | "Analyze a string (or ERb block) and open some file related with it. 201 | For example, on a line with \"render :partial\" runing this 202 | function will open the partial file. The function works with 203 | \"layout 'name'\", \"render/redirect-to [:action => 'name',] [controller => 'n']\", 204 | stylesheet_link_tag and other common 205 | patterns. 206 | 207 | Rules for actions/controllers: 208 | If you are in a controller, the cursor will be placed on the controller action. 209 | If you in view, the view file related to the action will be opened. 210 | Use prefix before the command to change this navigation direction." 211 | (interactive "P") 212 | (rails-project:with-root 213 | (root) 214 | (save-match-data 215 | (unless 216 | (when-bind 217 | (line (save-excursion 218 | (if (rails-core:rhtml-buffer-p) 219 | (rails-core:erb-block-string) 220 | (current-line-string)))) 221 | (loop for func in rails-on-current-line-gotos 222 | until (when (funcall func line prefix) (return t)))) 223 | (message "Can't switch to some file from this line."))))) 224 | 225 | (defvar rails-on-current-line-gotos 226 | '(rails-line-->partial 227 | rails-line-->action 228 | rails-line-->controller+action 229 | rails-line-->layout 230 | rails-line-->stylesheet 231 | rails-line-->js) 232 | "Functions that will ne called to analyze the line when 233 | rails-goto-file-on-current-line is run.") 234 | 235 | (def-goto-line rails-line-->stylesheet (("[ ]*stylesheet_link_tag[ ][\"']\\([^\"']*\\)[\"']" 236 | (name 1))) 237 | (rails-core:find-or-ask-to-create 238 | (format "Stylesheet \"%s\" does not exist do you whant to create it? " name) 239 | (rails-core:stylesheet-name name))) 240 | 241 | (def-goto-line rails-line-->partial (("\\([ ]*render\\|replace_html\\|insert_html\\).*:partial[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']" 242 | (name 2))) 243 | (rails-core:find-or-ask-to-create 244 | (format "Partial \"%s\" does not exist do you whant to create it? " name) 245 | (rails-core:partial-name name))) 246 | 247 | (def-goto-line rails-line-->action (("\\([ ]*render\\|replace_html\\|insert_html\\).*:action[ ]*=>[ ]*[\"'\:]\\([^\"']*\\)" 248 | (name 2))) 249 | (rails-core:find-or-ask-to-create 250 | (format "View \"%s\" does not exist do you whant to create it? " name) 251 | (rails-core:view-name name))) 252 | 253 | (def-goto-line rails-line-->layout (("^[ ]*layout[ ]*[\"']\\(.*\\)[\"']" (name 1))) 254 | (let ((file-name (rails-core:layout-file name))) 255 | (if (file-exists-p (rails-core:file file-name)) 256 | (rails-core:find-file file-name) 257 | (rails-nav:create-new-layout name)))) 258 | 259 | (def-goto-line rails-line-->js (("^[ ]*javascript_include_tag[ ]*[\"']\\(.*\\)[\"']" 260 | (name 1))) 261 | (rails-core:find-or-ask-to-create 262 | (format "JavaScript file \"%s\" does not exist do you whant to create it? " name) 263 | (rails-core:js-file name))) 264 | 265 | (defvar rails-line-to-controller/action-keywords 266 | '("render" "redirect_to" "link_to" "form_tag" "start_form_tag" "render_component" 267 | "form_remote_tag" "link_to_remote")) 268 | 269 | (defun rails-line-->controller+action (line prefix) 270 | (when (loop for keyword in rails-line-to-controller/action-keywords 271 | when (string-match (format "^[ ]*%s " keyword) line) do (return t)) 272 | (let (action controller) 273 | (when (string-match ":action[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']" line) 274 | (setf action (match-string 1 line))) 275 | (when (string-match ":controller[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']" line) 276 | (setf controller (match-string 1 line))) 277 | (rails-controller-layout:switch-to-action-in-controller 278 | (if controller controller 279 | (rails-core:current-controller)) 280 | action)))) 281 | 282 | (provide 'rails-navigation) 283 | -------------------------------------------------------------------------------- /rails-plugin-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-plugin-minor-mode.el --- minor mode for RubyOnRails plugins 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defun rails-plugin-minor-mode:switch-to-init () 30 | (interactive) 31 | (rails-core:find-file-if-exist 32 | (rails-core:plugin-file (rails-core:current-plugin) "init.rb"))) 33 | 34 | (defun rails-plugin-minor-mode:switch-with-menu () 35 | (interactive) 36 | (let* ((item) 37 | (plugin (rails-core:current-plugin)) 38 | (menu (rails-core:plugin-files plugin))) 39 | (setq item 40 | (rails-core:menu 41 | (list (concat "Plugin " plugin) 42 | (cons "Please select.." (list->alist menu))))) 43 | (when item 44 | (rails-core:find-file-if-exist 45 | (rails-core:plugin-file plugin item))))) 46 | 47 | (define-minor-mode rails-plugin-minor-mode 48 | "Minor mode for RubyOnRails plugins." 49 | nil 50 | " plugin" 51 | nil 52 | (setq rails-primary-switch-func 'rails-plugin-minor-mode:switch-to-init) 53 | (setq rails-secondary-switch-func 'rails-plugin-minor-mode:switch-with-menu)) 54 | 55 | (provide 'rails-plugin-minor-mode) -------------------------------------------------------------------------------- /rails-project.el: -------------------------------------------------------------------------------- 1 | ;;; rails-project.el --- 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails.el $ 9 | ;; $Id: rails.el 149 2007-03-29 15:07:49Z dimaexe $ 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 | (defun rails-project:root () 30 | "Return RAILS_ROOT if this file is a part of a Rails application, 31 | else return nil" 32 | (let ((curdir default-directory) 33 | (max 10) 34 | (found nil)) 35 | (while (and (not found) (> max 0)) 36 | (progn 37 | (if (file-exists-p (concat curdir "config/environment.rb")) 38 | (progn 39 | (setq found t)) 40 | (progn 41 | (setq curdir (concat curdir "../")) 42 | (setq max (- max 1)))))) 43 | (if found (expand-file-name curdir)))) 44 | 45 | (defmacro* rails-project:with-root ((root) &body body) 46 | "If you use `rails-project:root' or functions related on it 47 | several times in a block of code, you can optimize your code by 48 | using this macro. Also, blocks of code will be executed only if 49 | rails-root exist. 50 | (rails-project:with-root (root) 51 | (foo root) 52 | (bar (rails-core:file \"some/path\"))) 53 | " 54 | `(let ((,root (rails-project:root))) 55 | (when ,root 56 | (flet ((rails-project:root () ,root)) 57 | ,@body)))) 58 | 59 | (defmacro rails-project:in-root (&rest body) 60 | "Set the default directory to the Rails root directory while 61 | BODY is executed." 62 | (let ((root (gensym))) 63 | `(rails-project:with-root 64 | (,root) 65 | (let ((default-dir ,root)) 66 | ,@body)))) 67 | 68 | (defmacro* rails-project:in-root-with-cd (&rest body) 69 | (let ((root (gensym))) 70 | `(rails-project:with-root (,root) 71 | (in-directory (,root) ,@body)))) 72 | 73 | (defun rails-project:compile-in-root (command) 74 | (rails-project:in-root-with-cd 75 | (compile command))) 76 | 77 | (defun rails-project:name () 78 | "Return the name of current Rails project." 79 | (replace-regexp-in-string "^.*/\\(.*\\)/$" "\\1" 80 | (directory-name (rails-project:root)))) 81 | 82 | (provide 'rails-project) -------------------------------------------------------------------------------- /rails-rake.el: -------------------------------------------------------------------------------- 1 | ;;; rails-rake.el --- emacs-rails integraions with rake tasks. 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-scripts.el $ 9 | ;; $Id: rails-scripts.el 117 2007-03-25 23:37:37Z dimaexe $ 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 | (eval-when-compile 28 | (require 'rails-scripts)) 29 | 30 | (defvar rails-rake:history (list)) 31 | 32 | (defvar rails-rake:tasks-regexp "^rake \\([^ ]*\\).*# \\(.*\\)" 33 | "Regexp to match tasks list in `rake --tasks` output.") 34 | 35 | (defun rails-rake:create-tasks-cache (file-name) 36 | "Create a cache file from rake --tasks output." 37 | (let ((tasks (loop for str in (split-string (rails-cmd-proxy:shell-command-to-string "rake --tasks") "\n") 38 | for task = (when (string-not-empty str) 39 | (string=~ rails-rake:tasks-regexp str $1)) 40 | when task collect task))) 41 | (write-string-to-file file-name (prin1-to-string tasks)) 42 | tasks)) 43 | 44 | (defun rails-rake:list-of-tasks () 45 | "Return all available tasks and create tasks cache file." 46 | (rails-project:in-root 47 | (let* ((cache-file (rails-core:file "tmp/.tasks-cache"))) 48 | (if (file-exists-p cache-file) 49 | (read-from-file cache-file) 50 | (rails-rake:create-tasks-cache cache-file))))) 51 | 52 | (defun rails-rake:list-of-tasks-without-tests () 53 | "Return available tasks without test actions." 54 | (when-bind 55 | (tasks (rails-rake:list-of-tasks)) 56 | (sort (delete* nil 57 | (mapcar 58 | #'(lambda (it) (if (string=~ "^test\\($\\|:\\)" it t) nil it)) 59 | (rails-rake:list-of-tasks)) 60 | :if 'null) 61 | 'string<))) 62 | 63 | (defun rails-rake:task (task &optional major-mode) 64 | "Run a Rake task in RAILS_ROOT with MAJOR-MODE." 65 | (interactive (rails-completing-read "What task run" (rails-rake:list-of-tasks-without-tests) 66 | 'rails-rake:history nil)) 67 | (when task 68 | (rails-script:run "rake" (list task) major-mode))) 69 | 70 | (defun rails-rake:migrate (&optional version) 71 | "Run the db:migrate task" 72 | (interactive) 73 | (rails-rake:task 74 | (concat 75 | "db:migrate" 76 | (typecase version 77 | (integer (format " VERSION=%.3i" version)) 78 | (string (format " VERSION=%s" version)))))) 79 | 80 | (defun rails-rake:migrate-to-version (version) 81 | "Run migrate with VERSION." 82 | (interactive (rails-completing-read "Version of migration" 83 | (rails-core:migration-versions t) 84 | nil 85 | t)) 86 | (when version 87 | (rails-rake:migrate version))) 88 | 89 | (defun rails-rake:migrate-to-prev-version () 90 | "Migrate to a previous version." 91 | (interactive) 92 | (let ((versions (rails-core:migration-versions t))) 93 | (rails-rake:migrate 94 | (when (< 2 (length versions)) 95 | (nth 1 versions))))) 96 | 97 | ;; This function was originally defined anonymously in ui. It was defined here so keys 98 | ;; can be added to it dryly 99 | (defun rails-rake:clone-development-db-to-test-db () 100 | "Clone development DB to test DB." 101 | (interactive) (rails-rake:task "db:test:clone")) 102 | 103 | (provide 'rails-rake) 104 | -------------------------------------------------------------------------------- /rails-ruby.el: -------------------------------------------------------------------------------- 1 | ;;; rails-ruby.el --- provide features for ruby-mode 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (string-match 120 | (format "\\(%s\\)" 121 | (string-join 122 | "\\|" 123 | (mapcar 'car flymake-allowed-ruby-file-name-masks))) 124 | (buffer-file-name))) 125 | (setq flymake-allowed-file-name-masks 126 | (append flymake-allowed-file-name-masks flymake-allowed-ruby-file-name-masks)) 127 | (setq flymake-err-line-patterns 128 | (cons flymake-ruby-error-line-pattern-regexp flymake-err-line-patterns)) 129 | (flymake-mode t) 130 | (local-set-key (rails-key "d") 'flymake-display-err-menu-for-current-line))) 131 | 132 | (when (featurep 'flymake) 133 | (add-hook 'ruby-mode-hook 'flymake-ruby-load)) 134 | 135 | ;; other stuff 136 | 137 | (defun ruby-newline-and-indent () 138 | (interactive) 139 | (newline) 140 | (ruby-indent-command)) 141 | 142 | (defun ruby-toggle-string<>simbol () 143 | "Easy to switch between strings and symbols." 144 | (interactive) 145 | (let ((initial-pos (point))) 146 | (save-excursion 147 | (when (looking-at "[\"']") ;; skip beggining quote 148 | (goto-char (+ (point) 1)) 149 | (unless (looking-at "\\w") 150 | (goto-char (- (point) 1)))) 151 | (let* ((point (point)) 152 | (start (skip-syntax-backward "w")) 153 | (end (skip-syntax-forward "w")) 154 | (end (+ point start end)) 155 | (start (+ point start)) 156 | (start-quote (- start 1)) 157 | (end-quote (+ end 1)) 158 | (quoted-str (buffer-substring-no-properties start-quote end-quote)) 159 | (symbol-str (buffer-substring-no-properties start end))) 160 | (cond 161 | ((or (string-match "^\"\\w+\"$" quoted-str) 162 | (string-match "^\'\\w+\'$" quoted-str)) 163 | (setq quoted-str (substring quoted-str 1 (- (length quoted-str) 1))) 164 | (kill-region start-quote end-quote) 165 | (goto-char start-quote) 166 | (insert (concat ":" quoted-str))) 167 | ((string-match "^\:\\w+$" symbol-str) 168 | (setq symbol-str (substring symbol-str 1)) 169 | (kill-region start end) 170 | (goto-char start) 171 | (insert (format "'%s'" symbol-str)))))) 172 | (goto-char initial-pos))) 173 | 174 | (require 'inf-ruby) 175 | 176 | (defun run-ruby-in-buffer (buf script &optional params) 177 | "Run CMD as a ruby process in BUF if BUF does not exist." 178 | (let ((abuf (concat "*" buf "*"))) 179 | (when (not (comint-check-proc abuf)) 180 | (set-buffer (make-comint buf rails-ruby-command nil script params))) 181 | (inferior-ruby-mode) 182 | (make-local-variable 'inferior-ruby-first-prompt-pattern) 183 | (make-local-variable 'inferior-ruby-prompt-pattern) 184 | (setq inferior-ruby-first-prompt-pattern "^>> " 185 | inferior-ruby-prompt-pattern "^>> ") 186 | (pop-to-buffer abuf))) 187 | 188 | (defun complete-ruby-method (prefix &optional maxnum) 189 | (if (capital-word-p prefix) 190 | (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}") 191 | (cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd))) 192 | (el4r-ruby-eval (format cmd prefix prefix))) 193 | (save-excursion 194 | (goto-char (- (point) (+ 1 (length prefix)))) 195 | (when (and (looking-at "\\.") 196 | (capital-word-p (word-at-point)) 197 | (el4r-ruby-eval (format "::%s rescue nil" (word-at-point)))) 198 | (let* ((cmd "%s.public_methods.map{|i| i.match(/^%s/) ? i.gsub(/^%s/, '') : nil }.compact.sort{|x,y| x.size <=> y.size}") 199 | (cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd))) 200 | (el4r-ruby-eval (format cmd (word-at-point) prefix prefix))))))) 201 | 202 | 203 | (provide 'rails-ruby) -------------------------------------------------------------------------------- /rails-scripts.el: -------------------------------------------------------------------------------- 1 | ;;; rails-scripts.el --- emacs-rails integraions with rails script/* scripts 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | (eval-when-compile 29 | (require 'inf-ruby) 30 | (require 'ruby-mode)) 31 | 32 | (defvar rails-script:generators-list 33 | '("controller" "model" "scaffold" "migration" "plugin" "mailer" "observer" "resource")) 34 | 35 | (defvar rails-script:destroy-list rails-script:generators-list) 36 | 37 | (defvar rails-script:generate-params-list 38 | '("-f") 39 | "Add parameters to script/generate. 40 | For example -s to keep existing files and -c to add new files into svn.") 41 | 42 | (defvar rails-script:destroy-params-list 43 | '("-f") 44 | "Add parameters to script/destroy. 45 | For example -c to remove files from svn.") 46 | 47 | (defvar rails-script:buffer-name "*ROutput*") 48 | 49 | (defvar rails-script:running-script-name nil 50 | "Curently running the script name") 51 | 52 | (defvar rails-script:history (list)) 53 | (defvar rails-script:history-of-generate (list)) 54 | (defvar rails-script:history-of-destroy (list)) 55 | 56 | ;; output-mode 57 | 58 | (defconst rails-script:font-lock-ketwords 59 | (list 60 | '("^\\(\(in [^\)]+\)\\)$" 1 font-lock-builtin-face) 61 | '(" \\(rm\\|rmdir\\) " 1 font-lock-warning-face) 62 | '(" \\(missing\\|notempty\\|exists\\) " 1 font-lock-warning-face) 63 | '(" \\(create\\|dependency\\) " 1 font-lock-function-name-face))) 64 | 65 | (defconst rails-script:button-regexp 66 | " \\(create\\) + \\([^ ]+\\.\\w+\\)") 67 | 68 | (defvar rails-script:output-mode-ret-value nil) 69 | (defvar rails-script:run-after-stop-hook nil) 70 | (defvar rails-script:show-buffer-hook nil) 71 | 72 | (defun rails-script:make-buttons (start end len) 73 | (save-excursion 74 | (let ((buffer-read-only nil)) 75 | (goto-char start) 76 | (while (re-search-forward rails-script:button-regexp end t) 77 | (make-button (match-beginning 2) (match-end 2) 78 | :type 'rails-button 79 | :rails:file-name (match-string 2)))))) 80 | 81 | (defun rails-script:popup-buffer (&optional do-not-scroll-to-top) 82 | "Popup output buffer." 83 | (unless (buffer-visible-p rails-script:buffer-name) 84 | (display-buffer rails-script:buffer-name t)) 85 | (let ((win (get-buffer-window-list rails-script:buffer-name))) 86 | (when win 87 | (unless do-not-scroll-to-top 88 | (mapcar #'(lambda(w) (set-window-point w 0)) win)) 89 | (shrink-window-if-larger-than-buffer 90 | (get-buffer-window rails-script:buffer-name)) 91 | (run-hooks 'rails-script:show-buffer-hook)))) 92 | 93 | (defun rails-script:push-first-button () 94 | (let (file-name) 95 | (with-current-buffer (get-buffer rails-script:buffer-name) 96 | (let ((button (next-button 1))) 97 | (when button 98 | (setq file-name (button-get button :rails:file-name))))) 99 | (when file-name 100 | (rails-core:find-file-if-exist file-name)))) 101 | 102 | (defun rails-script:toggle-output-window () 103 | (interactive) 104 | (let ((current (current-buffer)) 105 | (buf (get-buffer rails-script:buffer-name))) 106 | (if buf 107 | (if (buffer-visible-p rails-script:buffer-name) 108 | (delete-windows-on buf) 109 | (progn 110 | (pop-to-buffer rails-script:buffer-name t t) 111 | (pop-to-buffer current t t) 112 | (shrink-window-if-larger-than-buffer 113 | (get-buffer-window rails-script:buffer-name)) 114 | (run-hooks 'rails-script:show-buffer-hook))) 115 | (message "No output window found. Try running a script or a rake task before.")))) 116 | 117 | (defun rails-script:setup-output-buffer () 118 | "Setup default variables and values for the output buffer." 119 | (set (make-local-variable 'font-lock-keywords-only) t) 120 | (make-local-variable 'font-lock-defaults) 121 | (set (make-local-variable 'scroll-margin) 0) 122 | (set (make-local-variable 'scroll-preserve-screen-position) nil) 123 | (make-local-variable 'after-change-functions) 124 | (rails-minor-mode t)) 125 | 126 | (define-derived-mode rails-script:output-mode fundamental-mode "ROutput" 127 | "Major mode to Rails Script Output." 128 | (rails-script:setup-output-buffer) 129 | (setq font-lock-defaults '((rails-script:font-lock-ketwords) nil t)) 130 | (buffer-disable-undo) 131 | (setq buffer-read-only t) 132 | (rails-script:make-buttons (point-min) (point-max) (point-max)) 133 | (add-hook 'rails-script:run-after-stop-hook 'rails-script:popup-buffer t t) 134 | (add-hook 'rails-script:run-after-stop-hook 'rails-script:push-first-button t t) 135 | (add-hook 'after-change-functions 'rails-script:make-buttons nil t) 136 | (run-hooks 'rails-script:output-mode-hook)) 137 | 138 | (defun rails-script:running-p () 139 | (get-buffer-process rails-script:buffer-name)) 140 | 141 | (defun rails-script:sentinel-proc (proc msg) 142 | (let* ((name rails-script:running-script-name) 143 | (ret-val (process-exit-status proc)) 144 | (buf (get-buffer rails-script:buffer-name)) 145 | (ret-message (if (zerop ret-val) "successful" "failure"))) 146 | (with-current-buffer buf 147 | (set (make-local-variable 'rails-script:output-mode-ret-value) ret-val)) 148 | (when (memq (process-status proc) '(exit signal)) 149 | (setq rails-script:running-script-name nil 150 | msg (format "%s was stopped (%s)." name ret-message))) 151 | (message (replace-regexp-in-string "\n" "" msg)) 152 | (with-current-buffer buf 153 | (run-hooks 'rails-script:run-after-stop-hook)))) 154 | 155 | (defun rails-script:run (command parameters &optional buffer-major-mode) 156 | "Run a Rails script COMMAND with PARAMETERS with 157 | BUFFER-MAJOR-MODE and process-sentinel SENTINEL." 158 | (unless (listp parameters) 159 | (error "rails-script:run PARAMETERS must be the list")) 160 | (rails-project:with-root 161 | (root) 162 | (save-some-buffers) 163 | (let ((proc (rails-script:running-p))) 164 | (if proc 165 | (message "Only one instance rails-script allowed") 166 | (let* ((default-directory root) 167 | (proc (rails-cmd-proxy:start-process rails-script:buffer-name 168 | rails-script:buffer-name 169 | command 170 | (strings-join " " parameters)))) 171 | (with-current-buffer (get-buffer rails-script:buffer-name) 172 | (let ((buffer-read-only nil) 173 | (win (get-buffer-window-list rails-script:buffer-name))) 174 | (kill-region (point-min) (point-max))) 175 | (if buffer-major-mode 176 | (apply buffer-major-mode (list)) 177 | (rails-script:output-mode)) 178 | (add-hook 'after-change-functions 'rails-cmd-proxy:convert-buffer-from-remote nil t)) 179 | (set-process-coding-system proc 'utf-8-dos 'utf-8-dos) 180 | (set-process-sentinel proc 'rails-script:sentinel-proc) 181 | (setq rails-script:running-script-name 182 | (if (= 1 (length parameters)) 183 | (format "%s %s" command (first parameters)) 184 | (format "%s %s" (first parameters) (first (cdr parameters))))) 185 | (message "Starting %s." rails-script:running-script-name)))))) 186 | 187 | ;;;;;;;;;; Destroy stuff ;;;;;;;;;; 188 | 189 | (defun rails-script:run-destroy (what &rest parameters) 190 | "Run the destroy script using WHAT and PARAMETERS." 191 | (rails-script:run rails-ruby-command 192 | (append (list (format "script/destroy %s" what)) 193 | parameters 194 | rails-script:destroy-params-list))) 195 | 196 | (defun rails-script:destroy (what) 197 | "Run destroy WHAT" 198 | (interactive (rails-completing-read "What destroy" rails-script:destroy-list 199 | 'rails-script:history-of-destroy nil)) 200 | (let ((name (intern (concat "rails-script:destroy-" 201 | (replace-regexp-in-string "_" "-" what))))) 202 | (when (fboundp name) 203 | (call-interactively name)))) 204 | 205 | (defmacro rails-script:gen-destroy-function (name &optional completion completion-arg) 206 | (let ((func (intern (format "rails-script:destroy-%s" name))) 207 | (param (intern (concat name "-name")))) 208 | `(defun ,func (&optional ,param) 209 | (interactive 210 | (list (completing-read ,(concat "Destroy " 211 | (replace-regexp-in-string "[^a-z0-9]" " " name) 212 | ": ") 213 | ,(if completion 214 | `(list->alist 215 | ,(if completion-arg 216 | `(,completion ,completion-arg) 217 | `(,completion))) 218 | nil)))) 219 | (when (string-not-empty ,param) 220 | (rails-script:run-destroy ,(replace-regexp-in-string "-" "_" name) ,param))))) 221 | 222 | (rails-script:gen-destroy-function "controller" rails-core:controllers t) 223 | (rails-script:gen-destroy-function "model" rails-core:models) 224 | (rails-script:gen-destroy-function "scaffold") 225 | (rails-script:gen-destroy-function "migration" rails-core:migrations t) 226 | (rails-script:gen-destroy-function "mailer" rails-core:mailers) 227 | (rails-script:gen-destroy-function "plugin" rails-core:plugins) 228 | (rails-script:gen-destroy-function "observer" rails-core:observers) 229 | (rails-script:gen-destroy-function "resource") 230 | 231 | ;;;;;;;;;; Generators stuff ;;;;;;;;;; 232 | 233 | (defun rails-script:run-generate (what &rest parameters) 234 | "Run the generate script using WHAT and PARAMETERS." 235 | (rails-script:run rails-ruby-command 236 | (append (list (format "script/generate %s" what)) 237 | parameters 238 | rails-script:generate-params-list))) 239 | 240 | (defun rails-script:generate (what) 241 | "Run generate WHAT" 242 | (interactive (rails-completing-read "What generate" rails-script:generators-list 243 | 'rails-script:history-of-generate nil)) 244 | (let ((name (intern (concat "rails-script:generate-" 245 | (replace-regexp-in-string "_" "-" what))))) 246 | (when (fboundp name) 247 | (call-interactively name)))) 248 | 249 | (defmacro rails-script:gen-generate-function (name &optional completion completion-arg) 250 | (let ((func (intern (format "rails-script:generate-%s" name))) 251 | (param (intern (concat name "-name")))) 252 | `(defun ,func (&optional ,param) 253 | (interactive 254 | (list (completing-read ,(concat "Generate " 255 | (replace-regexp-in-string "[^a-z0-9]" " " name) 256 | ": ") 257 | ,(if completion 258 | `(list->alist 259 | ,(if completion-arg 260 | `(,completion ,completion-arg) 261 | `(,completion))) 262 | nil)))) 263 | (when (string-not-empty ,param) 264 | (rails-script:run-generate ,(replace-regexp-in-string "-" "_" name) ,param))))) 265 | 266 | (defun rails-script:generate-controller (&optional controller-name actions) 267 | "Generate a controller and open the controller file." 268 | (interactive (list 269 | (completing-read "Controller name (use autocomplete) : " 270 | (list->alist (rails-core:controllers-ancestors))) 271 | (read-string "Actions (or return to skip): "))) 272 | (when (string-not-empty controller-name) 273 | (rails-script:run-generate "controller" controller-name actions))) 274 | 275 | (defun rails-script:generate-scaffold (&optional model-name controller-name actions) 276 | "Generate a scaffold and open the controller file." 277 | (interactive 278 | "MModel name: \nMController (or return to skip): \nMActions (or return to skip): ") 279 | (when (string-not-empty model-name) 280 | (if (string-not-empty controller-name) 281 | (rails-script:run-generate "scaffold" model-name controller-name actions) 282 | (rails-script:run-generate "scaffold" model-name)))) 283 | 284 | (rails-script:gen-generate-function "model" rails-core:models-ancestors) 285 | (rails-script:gen-generate-function "migration") 286 | (rails-script:gen-generate-function "plugin") 287 | (rails-script:gen-generate-function "mailer") 288 | (rails-script:gen-generate-function "observer") 289 | (rails-script:gen-generate-function "resource") 290 | 291 | ;;;;;;;;;; Rails create project ;;;;;;;;;; 292 | 293 | (defun rails-script:create-project (dir) 294 | "Create a new project in a directory named DIR." 295 | (interactive "FNew Rails project directory: ") 296 | (make-directory dir t) 297 | (let ((default-directory (concat (expand-file-name dir) "/"))) 298 | (flet ((rails-project:root () default-directory)) 299 | (rails-script:run "rails" (list "--skip" (rails-project:root)))))) 300 | 301 | ;;;;;;;;;; Shells ;;;;;;;;;; 302 | 303 | (defun rails-script:run-interactive (name script &optional params) 304 | "Run an interactive shell with SCRIPT in a buffer named 305 | *rails--*." 306 | (rails-project:with-root 307 | (root) 308 | (let ((buffer-name (format "rails-%s-%s" (rails-project:name) name)) 309 | (script (rails-core:file script))) 310 | (run-ruby-in-buffer buffer-name 311 | script 312 | params) 313 | (setq ruby-buffer buffer-name)) 314 | (rails-minor-mode t))) 315 | 316 | (defun rails-script:console () 317 | "Run script/console." 318 | (interactive) 319 | (rails-script:run-interactive (format "console at (%s)" rails-default-environment) 320 | "script/console" 321 | rails-default-environment)) 322 | 323 | (defun rails-script:breakpointer () 324 | "Run script/breakpointer." 325 | (interactive) 326 | (rails-script:run-interactive "breakpointer" "script/breakpointer")) 327 | 328 | (provide 'rails-scripts) 329 | -------------------------------------------------------------------------------- /rails-shoulda.el: -------------------------------------------------------------------------------- 1 | ;;; rails-shoulda.el --- emacs-rails integraions with should plugin. 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | ;; Authors: Rob Christie , 5 | ;; Keywords: ruby rails languages oop 6 | 7 | ;;; License 8 | 9 | ;; This program is free software; you can redistribute it and/or 10 | ;; modify it under the terms of the GNU General Public License 11 | ;; as published by the Free Software Foundation; either version 2 12 | ;; of the License, or (at your option) any later version. 13 | 14 | ;; This program is distributed in the hope that it will be useful, 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ;; GNU General Public License for more details. 18 | 19 | ;; You should have received a copy of the GNU General Public License 20 | ;; along with this program; if not, write to the Free Software 21 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 | 23 | (defun rails-shoulda:current-test () 24 | "Return the test name based on point" 25 | (save-excursion 26 | (ruby-end-of-block) 27 | (let ((should (when (search-backward-regexp "^[ ]*should \"\\([a-z0-9_ ]+\\)\"[ ]*do" nil t) 28 | (match-string-no-properties 1))) 29 | (context (when (search-backward-regexp "^[ ]*context \"\\([a-z0-9_ ]+\\)\"[ ]*do" nil t) 30 | (match-string-no-properties 1)))) 31 | (when (and should context) 32 | (concat context " should " should))))) 33 | 34 | (defun rails-shoulda:current-context () 35 | "Return the shoulda context name based on point" 36 | (save-excursion 37 | (ruby-end-of-block) 38 | (when (search-backward-regexp "^[ ]*context \"\\([a-z0-9_ ]+\\)\"[ ]*do" nil t) 39 | (match-string-no-properties 1)))) 40 | 41 | (defun rails-shoulda:run-current-should () 42 | "Run should assertion based on the location of point." 43 | (interactive) 44 | (let ((file (substring (buffer-file-name) (length (rails-project:root)))) 45 | (method (replace-regexp-in-string "[\+\. \'\"\(\)]" "." (rails-shoulda:current-test)))) 46 | (when method 47 | (rails-test:run-single-file file (format "--name=/%s/" method))))) 48 | 49 | (defun rails-shoulda:run-current-context () 50 | "Run tests associated with the context based on the location of point." 51 | (interactive) 52 | (let ((file (substring (buffer-file-name) (length (rails-project:root)))) 53 | (method (replace-regexp-in-string "[\+\. \'\"\(\)]" "." (rails-shoulda:current-context)))) 54 | (when method 55 | (rails-test:run-single-file file (format "--name=/%s/" method))))) 56 | 57 | (provide 'rails-shoulda) 58 | -------------------------------------------------------------------------------- /rails-spec.el: -------------------------------------------------------------------------------- 1 | ;;; rails-rake.el --- emacs-rails integraions with rake tasks. 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Peter Rezikov 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-spec.el $ 9 | ;; $Id: rails-spec.el 117 2007-03-25 23:37:37Z dimaexe $ 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 | (defvar rails-spec:all-files "./spec" 28 | "All spec files/directories in project") 29 | 30 | (defvar rails-spec:last-files rails-spec:all-files 31 | "Last files that run with spec. In this variable memorized each spec coommand.") 32 | 33 | (defvar rails-spec:runner "./script/spec" 34 | "Command, that run specs.") 35 | 36 | (defvar rails-spec:runner-options "" 37 | "Options to spec command.") 38 | 39 | (defun rails-spec:run-files (files) 40 | "Run spec for files" 41 | (interactive "Mspec files: ") 42 | (setf rails-spec:last-files files) 43 | (let ((default-process-coding-system '(utf-8 . utf-8))) 44 | (rails-project:compile-in-root 45 | (concat rails-spec:runner " " 46 | rails-spec:runner-options " " 47 | files)))) 48 | 49 | (defun rails-spec:run-this-file () 50 | "Run spec for current file" 51 | (interactive) 52 | (rails-spec:run-files (buffer-file-name (current-buffer)))) 53 | 54 | (defun rails-spec:run-all () 55 | "Run spec for all files in project (rails-spec:all-files variable)" 56 | (interactive) 57 | (rails-spec:run-files rails-spec:all-files)) 58 | 59 | (defun rails-spec:run-last () 60 | "Run last runned spec command" 61 | (interactive) 62 | (rails-spec:run-files rails-spec:last-files)) 63 | 64 | (defun rails-spec:run-this-spec () 65 | "Run spec where the point is" 66 | (interactive) 67 | (let ((default-process-coding-system '(utf-8 . utf-8))) 68 | (rails-project:compile-in-root 69 | (concat rails-spec:runner " " 70 | rails-spec:runner-options (concat " --line " (substring (what-line) 5) " ") 71 | (buffer-file-name (current-buffer)))))) 72 | 73 | (provide 'rails-spec) 74 | -------------------------------------------------------------------------------- /rails-speedbar-feature.el: -------------------------------------------------------------------------------- 1 | (defvar rails-speedbar:roots 2 | '(("Controllers" rails-core:controllers rails-core:controller-file) 3 | ("Helpers" rails-core:helpers rails-core:helper-file) 4 | ("Models" rails-core:models rails-core:model-file) 5 | ("Observers" rails-core:observers rails-core:observer-file) 6 | ("Mailers" rails-core:mailers rails-core:mailer-file) 7 | ("Migrations" rails-core:migrations rails-core:migration-file) 8 | ("Functional Tests" rails-core:functional-tests rails-core:functional-test-file) 9 | ("Unit Tests" rails-core:unit-tests rails-core:unit-test-file) 10 | ("Fixtures" rails-core:fixtures rails-core:fixture-file) 11 | ("Configuration" rails-core:configuration-files rails-core:configuration-file))) 12 | 13 | (defvar rails-speedbar:menu-items nil) 14 | (defvar rails-speedbar:key-map 15 | (let ((map (speedbar-make-specialized-keymap))) 16 | (define-key map " " 'speedbar-toggle-line-expansion) 17 | (define-key map "+" 'speedbar-expand-line) 18 | (define-key map "=" 'speedbar-expand-line) 19 | (define-key map "-" 'speedbar-contract-line) 20 | (define-key map "e" 'speedbar-edit-line) 21 | (define-key map "\C-m" 'speedbar-edit-line) 22 | map)) 23 | 24 | (defun rails-speedbar:display (directory depth) 25 | (setq speedbar-update-flag nil) 26 | (speedbar-with-writable 27 | (insert (rails-project:root) "\n")) 28 | (dolist (i rails-speedbar:roots) 29 | (speedbar-make-tag-line 'angle 30 | ?+ 31 | 'rails-speedbar:expand-group 32 | (car i) 33 | (car i) 34 | nil 35 | nil 36 | nil 37 | depth)) 38 | (speedbar-make-tag-line 'angle 39 | ?+ 40 | 'rails-speedbar:expand-directory 41 | (concat (rails-speedbar:root) "app/views") 42 | "Views" 43 | nil 44 | nil 45 | nil 46 | depth)) 47 | 48 | (defun rails-speedbar:expand-directory (text token indent) 49 | (cond 50 | ((string-match "+" text) 51 | (speedbar-change-expand-button-char ?-) 52 | (let ((files (directory-files token nil "^[^.]"))) 53 | (save-excursion 54 | (end-of-line) (forward-char 1) 55 | (speedbar-with-writable 56 | (dolist (i files) 57 | (if (file-directory-p (format "%s/%s" token i)) 58 | (speedbar-make-tag-line 'curly 59 | ?+ 60 | 'rails-speedbar:expand-directory 61 | (format "%s/%s" token i) 62 | i 63 | nil nil nil 64 | (+ 1 indent)) 65 | (speedbar-make-tag-line 'statictag 66 | ?? 67 | nil 68 | nil 69 | i 70 | 'rails-speedbar:find-file 71 | (format "%s/%s" token i) 72 | nil 73 | (+ 1 indent)))))))) 74 | ((string-match "-" text) 75 | (speedbar-change-expand-button-char ?+) 76 | (speedbar-delete-subblock indent)))) 77 | 78 | (defun rails-speedbar:expand-group (text token indent) 79 | (cond 80 | ((string-match "+" text) 81 | (speedbar-change-expand-button-char ?-) 82 | (let* ((fn (find-if #'(lambda(i) (string= token (car i))) 83 | rails-speedbar:roots)) 84 | (lst (apply (nth 1 fn) (list))) 85 | (find (nth 2 fn))) 86 | (speedbar-with-writable 87 | (save-excursion 88 | (end-of-line) (forward-char 1) 89 | (dolist (i lst) 90 | (speedbar-make-tag-line 'bracket 91 | ?+ 92 | 'rails-speedbar:expand-tags 93 | (rails-speedbar:in-root (rails-core:file (apply find (list i)))) 94 | i 95 | 'rails-speedbar:find-file 96 | (rails-speedbar:in-root (rails-core:file (apply find (list i)))) 97 | nil 98 | (+ indent 1))))))) 99 | ((string-match "-" text) 100 | (speedbar-change-expand-button-char ?+) 101 | (speedbar-delete-subblock indent)))) 102 | 103 | (defun rails-speedbar:expand-tags (text token indent) 104 | (cond 105 | ((string-match "+" text) 106 | (let ((lst (speedbar-fetch-dynamic-tags token))) 107 | (if (not lst) 108 | (speedbar-change-expand-button-char ??) 109 | (progn 110 | (speedbar-change-expand-button-char ?-) 111 | (speedbar-with-writable 112 | (save-excursion 113 | (end-of-line) (forward-char 1) 114 | (speedbar-insert-generic-list indent 115 | (cdr lst) 116 | 'speedbar-tag-expand 117 | 'speedbar-tag-find))))))) 118 | ((string-match "-" text) 119 | (speedbar-change-expand-button-char ?+) 120 | (speedbar-delete-subblock indent)))) 121 | 122 | (defun rails-speedbar:line-directory (&optional depth) 123 | (save-excursion 124 | (end-of-line) 125 | (let ((start (point))) 126 | (when (search-backward "[-]" nil t) 127 | (end-of-line) 128 | (skip-syntax-backward "w") 129 | (get-text-property (point) 'speedbar-token))))) 130 | 131 | (defun rails-speedbar:find-file (text token indent) 132 | (typecase token 133 | (string (speedbar-find-file-in-frame token)))) 134 | 135 | (defun rails-speedbar:root () 136 | (save-excursion 137 | (goto-char (point-min)) 138 | (let* ((root (current-line-string)) 139 | (root (if (file-directory-p root) 140 | root 141 | (rails-project:root)))) 142 | root))) 143 | 144 | (defmacro rails-speedbar:in-root (&rest body) 145 | `(flet ((rails-project:root () ,(rails-speedbar:root))) 146 | ,@body)) 147 | 148 | (defun rails-speedbar:get-focus () 149 | (interactive) 150 | (speedbar-change-initial-expansion-list "Ruby On Rails") 151 | (let ((default-directory (rails-project:root))) 152 | (speedbar-get-focus))) 153 | 154 | (defun rails-speedbar-feature:install () 155 | (speedbar-add-expansion-list 156 | '("Ruby On Rails" 157 | rails-speedbar:menu-items 158 | rails-speedbar:key-map 159 | rails-speedbar:display)) 160 | (speedbar-add-mode-functions-list 161 | '("Ruby On Rails" 162 | (speedbar-line-directory . rails-speedbar:line-directory))) 163 | 164 | (define-key rails-minor-mode-map (kbd "") 'rails-speedbar:get-focus) 165 | (define-key-after 166 | (lookup-key rails-minor-mode-map [menu-bar rails]) 167 | [speedbar] '("Toggle Speedbar" . rails-speedbar:get-focus) 168 | 'svn-status)) 169 | 170 | (provide 'rails-speedbar-feature) -------------------------------------------------------------------------------- /rails-test.el: -------------------------------------------------------------------------------- 1 | ;;; rails-test.el --- tests integration with the compile library 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | 7 | ;; Keywords: ruby rails languages oop 8 | ;; $URL: svn+ssh://rubyforge/var/svn/emacs-rails/trunk/rails-ws.el $ 9 | ;; $Id: rails-ws.el 140 2007-03-27 23:33:36Z dimaexe $ 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 | (defvar rails-test:history nil) 30 | 31 | (defconst rails-test:result-regexp 32 | "\\([0-9]+ tests, [0-9]+ assertions, \\([0-9]+\\) failures, \\([0-9]+\\) errors\\)") 33 | 34 | (defconst rails-test:progress-regexp 35 | "^[.EF]+$") 36 | 37 | (defvar rails-test:font-lock-keywords 38 | '(("\\([0-9]+ tests, [0-9]+ assertions, 0 failures, 0 errors\\)" 39 | 1 compilation-info-face) 40 | ("\\([0-9]+ tests, [0-9]+ assertions, [0-9]+ failures, [0-9]+ errors\\)" 41 | 1 compilation-line-face) 42 | ("`\\([a-z0-9_]+\\)'" 43 | 1 font-lock-function-name-face t) 44 | ("^\s+\\([0-9]+)\s+\\(Error\\|Failure\\):\\)" 45 | 1 compilation-line-face) 46 | ("^\\(test_[a-z0-9_]+\\)(\\([a-zA-Z0-9:]+\\)):?$" 47 | (1 font-lock-function-name-face) 48 | (2 font-lock-type-face)) 49 | ("^[.EF]+$" . compilation-info-face))) 50 | 51 | (defun rails-test:line-regexp (&optional append prepend) 52 | (concat 53 | append 54 | "\\[?\\([^ \f\n\r\t\v]+?\\):\\([0-9]+\\)\\(?::in\s*`\\(.*?\\)'\\)?" 55 | prepend)) 56 | 57 | (defun rails-test:error-regexp-alist () 58 | (list 59 | (list 'rails-test-trace 60 | (rails-test:line-regexp) 1 2 nil 1) 61 | (list 'rails-test-error 62 | (rails-test:line-regexp nil "\\(?:\]:\\|\n$\\)") 1 2 nil 2))) ; ending of "]:" or next line is blank 63 | 64 | (defun rails-test:print-result () 65 | "Determine if the output buffer needs to be shown" 66 | (with-current-buffer (get-buffer rails-script:buffer-name) 67 | (let ((msg (list)) 68 | (failures 0) 69 | (errors 0)) 70 | (save-excursion 71 | (goto-char (point-min)) 72 | (while (re-search-forward rails-test:result-regexp (point-max) t) 73 | (setq failures (+ failures (string-to-number (match-string 2)))) 74 | (setq errors (+ errors (string-to-number (match-string 3)))) 75 | (add-to-list 'msg (match-string-no-properties 1)))) 76 | (unless (zerop (length msg)) 77 | (message (strings-join " || " (reverse msg)))) 78 | (when (and (or (not (zerop rails-script:output-mode-ret-value)) 79 | (not (zerop errors)) 80 | (not (zerop failures))) 81 | (not (buffer-visible-p (current-buffer)))) 82 | (rails-script:popup-buffer))))) 83 | 84 | (defun rails-test:print-progress (start end len) 85 | (let (content) 86 | (save-excursion 87 | (goto-char (point-min)) 88 | (while (re-search-forward "^Started" end t) 89 | (line-move 1) 90 | (save-match-data 91 | (let ((progress (string=~ rails-test:progress-regexp 92 | (current-line-string) $m))) 93 | (when progress 94 | (setq content (concat content progress))))))) 95 | (when content 96 | (message "Progress of %s: %s" rails-script:running-script-name content)))) 97 | 98 | (define-derived-mode rails-test:compilation-mode compilation-mode "RTest" 99 | "Major mode for RoR tests." 100 | (rails-script:setup-output-buffer) 101 | ; replace compilation font-lock-keywords 102 | (set (make-local-variable 'compilation-mode-font-lock-keywords) rails-test:font-lock-keywords) 103 | ; skip anythins less that error 104 | (set (make-local-variable 'compilation-skip-threshold) 2) 105 | (set (make-local-variable 'compilation-error-regexp-alist-alist) 106 | (rails-test:error-regexp-alist)) 107 | (set (make-local-variable 'compilation-error-regexp-alist) 108 | '(rails-test-error 109 | rails-test-trace)) 110 | (add-hook 'after-change-functions 'rails-test:print-progress nil t) 111 | (add-hook 'rails-script:run-after-stop-hook 'rails-test:hide-rails-project-root t t) 112 | ;; (add-hook 'rails-script:run-after-stop-hook 'rails-test:scroll-of-buffer t t) 113 | (add-hook 'rails-script:run-after-stop-hook 'rails-test:print-result t t) 114 | (add-hook 'rails-script:show-buffer-hook 'rails-test:reset-point-and-height t t)) 115 | 116 | ;; (defun rails-test:scroll-of-buffer () 117 | ;; (with-current-buffer "ROutput" 118 | ;; (buffer "ROutput") 119 | ;; (goto-char (point-min)) 120 | ;; (scroll-down-nomark (count-lines (point-min) (point-max))))) 121 | 122 | (defun rails-test:hide-rails-project-root () 123 | "Show files that are relative to the project root as relative filenames 124 | As the buffer is read-only this is merely a change in appearance" 125 | (rails-project:with-root (root) 126 | (save-excursion 127 | (beginning-of-buffer) 128 | (let ((file-regex (concat (regexp-quote root) "[^:]+"))) 129 | (while (re-search-forward file-regex nil t) 130 | (let* ((orig-filename (match-string 0)) 131 | (rel-filename (file-relative-name orig-filename root))) 132 | (overlay-put (make-overlay (match-beginning 0) (match-end 0)) 133 | 'display rel-filename))))))) 134 | 135 | (defun rails-test:reset-point-and-height () 136 | "Resets the point and resizes the window for the output buffer. 137 | Used when it's determined that the output buffer needs to be shown." 138 | (let ((win (get-buffer-window (current-buffer)))) 139 | (when (window-live-p win) 140 | (set-window-point win 0) 141 | (unless (buffer-visible-p (current-buffer)) 142 | (compilation-set-window-height win))))) 143 | 144 | (defun rails-test:list-of-tasks () 145 | "Return a list contains test tasks." 146 | (append (list "all") 147 | (delete* nil 148 | (mapcar 149 | #'(lambda (task) (string=~ "^test\\:\\([^ ]+\\)" task $1)) 150 | (rails-rake:list-of-tasks)) 151 | :if 'null))) 152 | 153 | (defun rails-test:run (task) 154 | "Run rake tests in RAILS_ROOT." 155 | (interactive (rails-completing-read "What test run" 156 | (rails-test:list-of-tasks) 157 | 'rails-test:history t)) 158 | (unless task 159 | (setq task "all") 160 | (add-to-list rails-test:history task)) 161 | (let ((task-name 162 | (if (string= "all" task) 163 | "test" 164 | (concat "test:" task)))) 165 | (rails-rake:task task-name 'rails-test:compilation-mode))) 166 | 167 | (defun rails-test:run-single-file (file &optional param) 168 | "Run test for single file FILE." 169 | (when (not (or file param)) 170 | "Refuse to run ruby without an argument: it would never return") 171 | (let ((param (if param 172 | (list file param) 173 | (list file)))) 174 | (rails-script:run "ruby" param 'rails-test:compilation-mode))) 175 | 176 | (defun rails-test:run-current () 177 | "Run a test for the current controller/model/mailer." 178 | (interactive) 179 | (let* ((model (rails-core:current-model)) 180 | (controller (rails-core:current-controller)) 181 | (func-test (rails-core:functional-test-file controller)) 182 | (unit-test (rails-core:unit-test-file model)) 183 | (mailer-test (rails-core:unit-test-file controller))) 184 | (rails-test:run-single-file 185 | (cond 186 | ;; model 187 | ((and model unit-test) unit-test) 188 | ;; controller 189 | ((and controller (not (rails-core:mailer-p controller)) func-test) 190 | func-test) 191 | ;; mailer 192 | ((and controller (rails-core:mailer-p controller) unit-test) 193 | unit-test) 194 | ;; otherwise... 195 | (t (if (string-match "test.*\\.rb" (buffer-file-name)) 196 | (buffer-file-name) 197 | (error "Cannot determine whiche test file to run."))))))) 198 | 199 | (defun rails-test:run-current-method () 200 | "Run a test for the current method." 201 | (interactive) 202 | (let ((file (substring (buffer-file-name) (length (rails-project:root)))) 203 | (method (rails-core:current-method-name)) 204 | (shoulda-method (rails-shoulda:current-test))) 205 | (when method 206 | (rails-test:run-single-file file (format "--name=%s" method))) 207 | (when shoulda-method 208 | (rails-test:run-single-file file (format "--name=/%s/" (replace-regexp-in-string "[\+\. \'\"\(\)]" "." shoulda-method)))))) 209 | 210 | ;; These functions were originally defined anonymously in ui. They are defined here so keys 211 | ;; can be added to them dryly 212 | (defun rails-test:run-integration () 213 | "Run Integration Tests." 214 | (interactive) 215 | (rails-test:run "integration")) 216 | (defun rails-test:run-units () 217 | "Run Unit Tests." 218 | (interactive) 219 | (rails-test:run "units")) 220 | (defun rails-test:run-functionals () 221 | "Run Functional Tests." 222 | (interactive) 223 | (rails-test:run "functionals")) 224 | (defun rails-test:run-recent () 225 | "Run Recent Tests." 226 | (interactive) 227 | (rails-test:run "recent")) 228 | (defun rails-test:run-all () 229 | "Run All Tests." 230 | (interactive) 231 | (rails-test:run "all")) 232 | 233 | (provide 'rails-test) 234 | -------------------------------------------------------------------------------- /rails-ui.el: -------------------------------------------------------------------------------- 1 | ;;; rails-ui.el --- emacs-rails user interface 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | 29 | ;;;;;;;;;; Some init code ;;;;;;;;;; 30 | 31 | (defconst rails-minor-mode-log-menu-bar-map 32 | (let ((map (make-sparse-keymap))) 33 | (define-keys map 34 | ([test] '("test.log" . rails-log:open-test)) 35 | ([pro] '("production.log" . rails-log:open-production)) 36 | ([dev] '("development.log" . rails-log:open-development)) 37 | ([separator] '("---")) 38 | ([open] '("Open Log File..." . rails-log:open))) 39 | map)) 40 | 41 | (defconst rails-minor-mode-config-menu-bar-map 42 | (let ((map (make-sparse-keymap))) 43 | (define-keys map 44 | ([routes] '("routes.rb" . 45 | (lambda () (interactive) 46 | (rails-core:find-file "config/routes.rb")))) 47 | ([environment] '("environment.rb" . 48 | (lambda() (interactive) 49 | (rails-core:find-file "config/environment.rb")))) 50 | ([database] '("database.yml" . 51 | (lambda() (interactive) 52 | (rails-core:find-file "config/database.yml")))) 53 | ([boot] '("boot.rb" . 54 | (lambda() (interactive) 55 | (rails-core:find-file "config/boot.rb")))) 56 | ([env] (cons "environments" (make-sparse-keymap "environments"))) 57 | ([env test] '("test.rb" . 58 | (lambda() (interactive) 59 | (rails-core:find-file "config/environments/test.rb")))) 60 | ([env production] '("production.rb" . 61 | (lambda() (interactive) 62 | (rails-core:find-file "config/environments/production.rb")))) 63 | ([env development] '("development.rb" . 64 | (lambda()(interactive) 65 | (rails-core:find-file "config/environments/development.rb"))))) 66 | map)) 67 | 68 | (defconst rails-minor-mode-nav-menu-bar-map 69 | (let ((map (make-sparse-keymap))) 70 | (define-keys map 71 | ([goto-fixtures] '("Go to Fixtures" . rails-nav:goto-fixtures)) 72 | ([goto-plugins] '("Go to Plugins" . rails-nav:goto-plugins)) 73 | ([goto-migrate] '("Go to Migrations" . rails-nav:goto-migrate)) 74 | ([goto-layouts] '("Go to Layouts" . rails-nav:goto-layouts)) 75 | ([goto-stylesheets] '("Go to Stylesheets" . rails-nav:goto-stylesheets)) 76 | ([goto-javascripts] '("Go to Javascripts" . rails-nav:goto-javascripts)) 77 | ([goto-helpers] '("Go to Helpers" . rails-nav:goto-helpers)) 78 | ([goto-mailers] '("Go to Mailers" . rails-nav:goto-mailers)) 79 | ([goto-observers] '("Go to Observers" . rails-nav:goto-observers)) 80 | ([goto-unit-tests] '("Go to Unit Tests" . rails-nav:goto-unit-tests)) 81 | ([goto-func-tests] '("Go to Functional Tests" . rails-nav:goto-functional-tests)) 82 | ([goto-models] '("Go to Models" . rails-nav:goto-models)) 83 | ([goto-controllers] '("Go to Controllers" . rails-nav:goto-controllers))) 84 | map)) 85 | 86 | (defconst rails-minor-mode-tests-menu-bar-map 87 | (let ((map (make-sparse-keymap))) 88 | (define-keys map 89 | ([integration] '("Integration Tests" . rails-test:run-integration)) 90 | ([unit] '("Unit Tests" . rails-test:run-units)) 91 | ([functional] '("Functional Tests" . rails-test:run-functionals)) 92 | ([recent] '("Recent Tests" . rails-test:run-recent)) 93 | ([tests] '("All" . rails-test:run-all)) 94 | ([separator] '("--")) 95 | ([toggle] '(menu-item "Toggle Output Window" rails-script:toggle-output-window 96 | :enable (get-buffer rails-script:buffer-name))) 97 | ([run-current] '("Test Current Model/Controller/Mailer" . rails-test:run-current)) 98 | ([run] '("Run Tests ..." . rails-test:run))) 99 | map)) 100 | 101 | (defconst rails-minor-mode-db-menu-bar-map 102 | (let ((map (make-sparse-keymap))) 103 | (define-keys map 104 | ([clone-db] '("Clone Development DB to Test DB" . rails-rake:clone-development-db-to-test-db)) 105 | ([load-schema] '("Load schema.rb to DB" . (lambda() (interactive) (rails-rake:task "db:schema:load")))) 106 | ([dump-schema] '("Dump DB to schema.rb" . (lambda() (interactive) (rails-rake:task "db:schema:dump")))) 107 | ([sep] '("--")) 108 | ([prev] '("Migrate to Previous Version" . rails-rake:migrate-to-prev-version)) 109 | ([version] '("Migrate to Version ..." . rails-rake:migrate-to-version)) 110 | ([migrate] '("Migrate" . rails-rake:migrate))) 111 | map)) 112 | 113 | (define-keys rails-minor-mode-menu-bar-map 114 | 115 | ([rails] (cons "RoR" (make-sparse-keymap "RubyOnRails"))) 116 | 117 | ([rails rails-customize] '("Customize" . (lambda () (interactive) (customize-group 'rails)))) 118 | ([rails separator0] '("--")) 119 | ([rails svn-status] '("SVN Status" . rails-svn-status-into-root)) 120 | ([rails api-doc] '("Rails API Doc at Point" . rails-browse-api-at-point)) 121 | ([rails sql] '("SQL Rails Buffer" . rails-run-sql)) 122 | ([rails tag] '("Update TAGS File" . rails-create-tags)) 123 | ([rails ri] '("Search Documentation" . rails-search-doc)) 124 | ([rails goto-file-by-line] '("Go to File by Line" . rails-goto-file-on-current-line)) 125 | ([rails switch-file-menu] '("Switch file Menu..." . rails-lib:run-secondary-switch)) 126 | ([rails switch-file] '("Switch File" . rails-lib:run-primary-switch)) 127 | ([rails separator1] '("--")) 128 | 129 | ([rails scr] (cons "Scripts" (make-sparse-keymap "Scripts"))) 130 | 131 | ([rails scr gen] (cons "Generate" (make-sparse-keymap "Generate"))) 132 | ([rails scr destr] (cons "Destroy" (make-sparse-keymap "Generators"))) 133 | 134 | ([rails scr destr resource] '("Resource" . rails-script:destroy-resource)) 135 | ([rails scr destr observer] '("Observer" . rails-script:destroy-observer)) 136 | ([rails scr destr mailer] '("Mailer" . rails-script:destroy-mailer)) 137 | ([rails scr destr plugin] '("Plugin" . rails-script:destroy-plugin)) 138 | ([rails scr destr migration] '("Migration" . rails-script:destroy-migration)) 139 | ([rails scr destr scaffold] '("Scaffold" . rails-script:destroy-scaffold)) 140 | ([rails scr destr model] '("Model" . rails-script:destroy-model)) 141 | ([rails scr destr controller] '("Controller" . rails-script:destroy-controller)) 142 | ([rails scr destr separator] '("--")) 143 | ([rails scr destr run] '("Run Destroy ..." . rails-script:destroy)) 144 | 145 | ([rails scr gen resource] '("Resource" . rails-script:generate-resource)) 146 | ([rails scr gen observer] '("Observer" . rails-script:generate-observer)) 147 | ([rails scr gen mailer] '("Mailer" . rails-script:generate-mailer)) 148 | ([rails scr gen plugin] '("Plugin" . rails-script:generate-plugin)) 149 | ([rails scr gen migration] '("Migration" . rails-script:generate-migration)) 150 | ([rails scr gen scaffold] '("Scaffold" . rails-script:generate-scaffold)) 151 | ([rails scr gen model] '("Model" . rails-script:generate-model)) 152 | ([rails scr gen controller] '("Controller" . rails-script:generate-controller)) 153 | ([rails scr gen separator] '("--")) 154 | ([rails scr gen run] '("Run Generate ..." . rails-script:generate)) 155 | 156 | ([rails scr break] '("Breakpointer" . rails-script:breakpointer)) 157 | ([rails scr console] '("Console" . rails-script:console)) 158 | ([rails scr rake] '("Rake..." . rails-rake:task)) 159 | 160 | ([rails nav] (cons "Navigation" rails-minor-mode-nav-menu-bar-map)) 161 | ([rails config] (cons "Configuration" rails-minor-mode-config-menu-bar-map)) 162 | ([rails log] (cons "Log Files" rails-minor-mode-log-menu-bar-map)) 163 | 164 | ([rails ws] (cons "WebServer" (make-sparse-keymap "WebServer"))) 165 | 166 | ([rails ws use-webrick] '(menu-item "Use WEBrick" (lambda() (interactive) 167 | (rails-ws:switch-default-server-type "webrick")) 168 | :button (:toggle . (rails-ws:default-server-type-p "webrick")))) 169 | ([rails ws use-lighttpd] '(menu-item "Use Lighty" (lambda() (interactive) 170 | (rails-ws:switch-default-server-type "lighttpd")) 171 | :button (:toggle . (rails-ws:default-server-type-p "lighttpd")))) 172 | ([rails ws use-mongrel] '(menu-item "Use Mongrel" (lambda() (interactive) 173 | (rails-ws:switch-default-server-type "mongrel")) 174 | :button (:toggle . (rails-ws:default-server-type-p "mongrel")))) 175 | ([rails ws use-thin] '(menu-item "Use Thin" (lambda() (interactive) 176 | (rails-ws:switch-default-server-type "thin")) 177 | :button (:toggle . (rails-ws:default-server-type-p "thin")))) 178 | ([rails ws separator] '("--")) 179 | 180 | ([rails ws brows] '(menu-item "Open Browser..." rails-ws:open-browser-on-controller 181 | :enable (rails-ws:running-p))) 182 | ([rails ws auto-brows] '(menu-item "Open Browser on Current Action" rails-ws:auto-open-browser 183 | :enable (rails-ws:running-p))) 184 | ([rails ws url] '(menu-item "Open Browser" rails-ws:open-browser 185 | :enable (rails-ws:running-p))) 186 | ([rails ws separator2] '("--")) 187 | 188 | ([rails ws test] '(menu-item "Start Test" rails-ws:start-test 189 | :enable (not (rails-ws:running-p)))) 190 | ([rails ws production] '(menu-item "Start Production" rails-ws:start-production 191 | :enable (not (rails-ws:running-p)))) 192 | ([rails ws development] '(menu-item "Start Development" rails-ws:start-development 193 | :enable (not (rails-ws:running-p)))) 194 | ([rails ws separator3] '("--")) 195 | 196 | ([rails ws status] '(menu-item "Print Status" rails-ws:print-status)) 197 | ([rails ws default] '(menu-item "Start/Stop Web Server (With Default Environment)" rails-ws:toggle-start-stop)) 198 | ) 199 | 200 | (defcustom rails-minor-mode-prefix-key "\C-c" 201 | "Key prefix for rails minor mode." 202 | :group 'rails) 203 | 204 | (defmacro rails-key (key) 205 | `(kbd ,(concat rails-minor-mode-prefix-key " " key))) 206 | 207 | (defconst rails-minor-mode-test-current-method-key (rails-key "\C-c ,")) 208 | 209 | (defvar rails-minor-mode-map 210 | (let ((map (make-keymap))) 211 | map)) 212 | 213 | (define-keys rails-minor-mode-map 214 | ([menu-bar] rails-minor-mode-menu-bar-map) 215 | ([menu-bar rails-tests] (cons "Tests" rails-minor-mode-tests-menu-bar-map)) 216 | ([menu-bar rails-db] (cons "Database" rails-minor-mode-db-menu-bar-map)) 217 | 218 | ;; Goto 219 | ((rails-key "\C-c g m") 'rails-nav:goto-models) 220 | ((rails-key "\C-c g c") 'rails-nav:goto-controllers) 221 | ((rails-key "\C-c g o") 'rails-nav:goto-observers) 222 | ((rails-key "\C-c g n") 'rails-nav:goto-mailers) 223 | ((rails-key "\C-c g h") 'rails-nav:goto-helpers) 224 | ((rails-key "\C-c g l") 'rails-nav:goto-layouts) 225 | ((rails-key "\C-c g s") 'rails-nav:goto-stylesheets) 226 | ((rails-key "\C-c g j") 'rails-nav:goto-javascripts) 227 | ((rails-key "\C-c g g") 'rails-nav:goto-migrate) 228 | ((rails-key "\C-c g p") 'rails-nav:goto-plugins) 229 | ((rails-key "\C-c g x") 'rails-nav:goto-fixtures) 230 | ((rails-key "\C-c g f") 'rails-nav:goto-functional-tests) 231 | ((rails-key "\C-c g u") 'rails-nav:goto-unit-tests) 232 | 233 | ;; Switch 234 | ((kbd "") 'rails-lib:run-primary-switch) 235 | ((kbd "") 'rails-lib:run-secondary-switch) 236 | ((rails-key "") 'rails-lib:run-primary-switch) 237 | ((rails-key "") 'rails-lib:run-secondary-switch) 238 | ((kbd "") 'rails-goto-file-on-current-line) 239 | 240 | ;; Scripts & SQL 241 | ((rails-key "\C-c e") 'rails-script:generate) 242 | ((rails-key "\C-c x") 'rails-script:destroy) 243 | ((rails-key "\C-c s c") 'rails-script:console) 244 | ((rails-key "\C-c s b") 'rails-script:breakpointer) 245 | ((rails-key "\C-c s s") 'rails-run-sql) 246 | ((rails-key "\C-c w s") 'rails-ws:toggle-start-stop) 247 | ((rails-key "\C-c w d") 'rails-ws:start-development) 248 | ((rails-key "\C-c w p") 'rails-ws:start-production) 249 | ((rails-key "\C-c w t") 'rails-ws:start-test) 250 | ((rails-key "\C-c w i") 'rails-ws:print-status) 251 | ((rails-key "\C-c w a") 'rails-ws:auto-open-browser) 252 | 253 | ;; Rails finds 254 | ((rails-key "\C-c f m") 'rails-find:models) 255 | ((rails-key "\C-c f c") 'rails-find:controller) 256 | ((rails-key "\C-c f h") 'rails-find:helpers) 257 | ((rails-key "\C-c f l") 'rails-find:layout) 258 | ((rails-key "\C-c f s") 'rails-find:stylesheets) 259 | ((rails-key "\C-c f j") 'rails-find:javascripts) 260 | ((rails-key "\C-c f g") 'rails-find:migrate) 261 | ((rails-key "\C-c f b") 'rails-find:lib) 262 | ((rails-key "\C-c f t") 'rails-find:tasks) 263 | ((rails-key "\C-c f v") 'rails-find:view) 264 | ((rails-key "\C-c f d") 'rails-find:db) 265 | ((rails-key "\C-c f p") 'rails-find:public) 266 | ((rails-key "\C-c f f") 'rails-find:fixtures) 267 | ((rails-key "\C-c f o") 'rails-find:config) 268 | ;; Spec finds 269 | ((rails-key "\C-c f r s") 'rails-find:spec) 270 | ((rails-key "\C-c f r c") 'rails-find:spec-controllers) 271 | ((rails-key "\C-c f r m") 'rails-find:spec-models) 272 | ((rails-key "\C-c f r h") 'rails-find:spec-helpers) 273 | ((rails-key "\C-c f r v") 'rails-find:spec-views) 274 | ((rails-key "\C-c f r f") 'rails-find:spec-fixtures) 275 | 276 | ((rails-key "\C-c d m") 'rails-rake:migrate) 277 | ((rails-key "\C-c d v") 'rails-rake:migrate-to-version) 278 | ((rails-key "\C-c d p") 'rails-rake:migrate-to-prev-version) 279 | ((rails-key "\C-c d t") 'rails-rake:clone-development-db-to-test-db) 280 | 281 | 282 | 283 | ;; Tests 284 | ((rails-key "\C-c r") 'rails-rake:task) 285 | ((rails-key "\C-c t") 'rails-test:run) 286 | ((rails-key "\C-c .") 'rails-test:run-current) 287 | ((rails-key "\C-c y i") 'rails-test:run-integration) 288 | ((rails-key "\C-c y u") 'rails-test:run-units) 289 | ((rails-key "\C-c y f") 'rails-test:run-functionals) 290 | ((rails-key "\C-c #") 'rails-test:run-recent) 291 | ((rails-key "\C-c y a") 'rails-test:run-all) 292 | 293 | ;; Log files 294 | ((rails-key "\C-c l") 'rails-log:open) 295 | ((rails-key "\C-c o t") 'rails-log:open-test) 296 | ((rails-key "\C-c o p") 'rails-log:open-production) 297 | ((rails-key "\C-c o d") 'rails-log:open-development) 298 | 299 | ;; Tags 300 | ((rails-key "\C-c \C-t") 'rails-create-tags) 301 | 302 | ;; Documentation 303 | ([f1] 'rails-search-doc) 304 | ((kbd "") 'rails-browse-api-at-point) 305 | ((rails-key "") 'rails-browse-api) 306 | ((rails-key "/") 'rails-script:toggle-output-window) 307 | 308 | ([f9] 'rails-svn-status-into-root)) 309 | 310 | ;; Global keys and menubar 311 | 312 | (global-set-key (rails-key "\C-c j") 'rails-script:create-project) 313 | 314 | (when-bind (map (lookup-key global-map [menu-bar file])) 315 | (define-key-after 316 | map 317 | [create-rails-project] 318 | '("Create Rails Project" . rails-script:create-project) 'insert-file)) 319 | 320 | (provide 'rails-ui) 321 | -------------------------------------------------------------------------------- /rails-unit-test-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-unit-test-minor-mode.el --- minor mode for RubyOnRails unit tests 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (define-minor-mode rails-unit-test-minor-mode 30 | "Minor mode for RubyOnRails unit tests." 31 | :lighter " UTest" 32 | :keymap (let ((map (rails-model-layout:keymap :unit-test))) 33 | (define-key map rails-minor-mode-test-current-method-key 'rails-test:run-current-method) 34 | (define-key map [menu-bar rails-model-layout run] '("Test current method" . rails-test:run-current-method)) 35 | map) 36 | (setq rails-primary-switch-func (lambda() 37 | (interactive) 38 | (if (rails-core:mailer-p (rails-core:current-model)) 39 | (rails-model-layout:switch-to-mailer) 40 | (rails-model-layout:switch-to-model)))) 41 | (setq rails-secondary-switch-func 'rails-model-layout:menu)) 42 | 43 | (provide 'rails-unit-test-minor-mode) -------------------------------------------------------------------------------- /rails-view-minor-mode.el: -------------------------------------------------------------------------------- 1 | ;;; rails-view-minor-mode.el --- minor mode for RubyOnRails views 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky 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 | (defun rails-view-minor-mode:create-partial-from-selection () 30 | "Create a partial from current buffer selection." 31 | (interactive) 32 | (if mark-active 33 | (save-excursion 34 | (let ((name (read-string "Partial name (without _ and extension)? ")) 35 | (content (buffer-substring-no-properties (region-beginning) (region-end))) 36 | (modified (buffer-modified-p))) 37 | (unless (string-not-empty name) 38 | (progn 39 | (message "Empty partial name") (return))) 40 | (kill-region (region-beginning) (region-end)) 41 | (insert (concat "<%= render :partial => \"" name "\" %>")) 42 | (mmm-parse-region (line-beginning-position) (line-end-position)) 43 | (insert "\n") 44 | (split-window-vertically) 45 | (other-window 1) 46 | (find-file (concat "_" name ".rhtml")) 47 | (goto-char (point-min)) 48 | (erase-buffer) 49 | (insert content) 50 | (save-buffer) 51 | (fit-window-to-buffer) 52 | (other-window -1) 53 | (unless modified (save-buffer)) 54 | (message "type `C-x +` to balance windows"))))) 55 | 56 | (defun rails-view-minor-mode:create-helper-from-block (&optional helper-name) 57 | "Create a helper function from current ERb block (<% .. %>)." 58 | (interactive) 59 | (let ((current-pos (point)) 60 | (file buffer-file-name) 61 | begin-pos 62 | end-pos) 63 | (save-excursion 64 | (setq begin-pos (search-backward "<%" nil t)) 65 | (setq end-pos (search-forward "%>" nil t))) 66 | (if (and begin-pos 67 | end-pos 68 | (> current-pos begin-pos) 69 | (< current-pos end-pos)) 70 | (let* ((helper-file (concat (rails-project:root) (rails-core:helper-file (rails-core:current-controller)))) 71 | (content (replace-regexp-in-string "\\(<%=?\\|-?%>\\)" "" 72 | (buffer-substring-no-properties begin-pos end-pos))) 73 | (helper-defination (if helper-name helper-name 74 | (read-string "Type helper function defination (without `def` keyword): ")))) 75 | (if (file-exists-p helper-file) 76 | (let ((modified (buffer-modified-p)) 77 | (helper-func-def (concat "def " helper-defination))) 78 | (kill-region begin-pos end-pos) 79 | (insert (concat "<%= " helper-defination " -%>" )) 80 | (mmm-parse-region (line-beginning-position) (line-end-position)) 81 | (insert "\n") 82 | (split-window-vertically) 83 | (other-window 1) 84 | (find-file helper-file) 85 | (goto-char (point-min)) 86 | (search-forward-regexp "module +[a-zA-Z0-9:]+") 87 | (end-of-line) 88 | (newline) 89 | (ruby-indent-command) 90 | (save-excursion 91 | (insert (concat helper-func-def "\n" content "\nend\n"))) 92 | (ruby-indent-exp) 93 | (fit-window-to-buffer) 94 | (save-buffer) 95 | (other-window -1) 96 | (unless modified (save-buffer)) 97 | (message "Type `C-x +` to balance windows")) 98 | (message "helper not found"))) 99 | (message "block not found")))) 100 | 101 | (define-minor-mode rails-view-minor-mode 102 | "Minor mode for RubyOnRails views." 103 | :lighter " View" 104 | :keymap (rails-controller-layout:keymap :view) 105 | (setq rails-primary-switch-func 'rails-controller-layout:toggle-action-view) 106 | (setq rails-secondary-switch-func 'rails-controller-layout:menu) 107 | (if (boundp 'mmm-mode-map) 108 | (progn 109 | (define-key mmm-mode-map (rails-key "p") 'rails-view-minor-mode:create-partial-from-selection) 110 | (define-key mmm-mode-map (rails-key "b") 'rails-view-minor-mode:create-helper-from-block)) 111 | (progn 112 | (local-set-key (rails-key "p") 'rails-view-minor-mode:create-partial-from-selection) 113 | (local-set-key (rails-key "b") 'rails-view-minor-mode:create-helper-from-block)))) 114 | 115 | (provide 'rails-view-minor-mode) -------------------------------------------------------------------------------- /rails-ws.el: -------------------------------------------------------------------------------- 1 | ;;; rails-ws.el --- functions for manadge application server 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | ;;; Code: 29 | 30 | (defcustom rails-ws:port "3000" 31 | "Default web server port" 32 | :group 'rails 33 | :type 'string 34 | :tag "Rails Server Port") 35 | 36 | (defcustom rails-ws:server-name "http://localhost" 37 | "Protocol and the hostname for web server or other rails server" 38 | :group 'rails 39 | :type 'string 40 | :tag "Rails Server Default") 41 | 42 | (defcustom rails-ws:default-server-type "mongrel" 43 | "Web server to run Rails application." 44 | :group 'rails 45 | :type 'string 46 | :tag "Rails Server Type") 47 | 48 | (defvar rails-ws:available-servers-list (list "mongrel" "lighttpd" "webrick" "thin")) 49 | (defvar rails-ws:buffer-name "*RWebServer*") 50 | (defvar rails-ws:process-environment nil) 51 | 52 | (defun rails-ws:default-server-type-p (type) 53 | (string= type rails-ws:default-server-type)) 54 | 55 | (defun rails-ws:switch-default-server-type (type) 56 | "Switch default server type to run." 57 | (interactive (list (completing-read "Server type (use autocomplete): " 58 | rails-ws:available-servers-list 59 | nil t 60 | rails-ws:default-server-type))) 61 | (setq rails-ws:default-server-type type) 62 | (customize-save-variable 'rails-ws:default-server-type rails-ws:default-server-type) 63 | (message (concat "Switching to " (upcase type) " as default server type"))) 64 | 65 | (defun rails-ws:running-p () 66 | "Return t if a WebServer process is running." 67 | (if (get-buffer-process rails-ws:buffer-name) t nil)) 68 | 69 | (defun rails-ws:sentinel-proc (proc msg) 70 | (let ((env rails-ws:process-environment)) 71 | (when (memq (process-status proc) '(exit signal)) 72 | (setq rails-ws:process-environment nil) 73 | (setq msg (format "stopped (%s)" msg))) 74 | (message 75 | (replace-regexp-in-string "\n" "" 76 | (format "%s - %s" 77 | (capitalize rails-ws:default-server-type) 78 | msg))))) 79 | 80 | (defun rails-ws:start(&optional env) 81 | "Start a server process with ENV environment if ENV is not set 82 | using `rails-default-environment'." 83 | (interactive (list (rails-read-enviroment-name))) 84 | (rails-project:with-root 85 | (root) 86 | (let ((proc (get-buffer-process rails-ws:buffer-name))) 87 | (if proc 88 | (message "Only one instance rails-ws allowed") 89 | (let* ((default-directory root) 90 | (env (if env env rails-default-environment)) 91 | (command (rails-ws:compute-server-conmmand rails-ws:default-server-type rails-ws:port env)) 92 | (proc 93 | (rails-cmd-proxy:start-process rails-ruby-command 94 | rails-ws:buffer-name 95 | (car command) 96 | (cadr command)))) 97 | (set-process-sentinel proc 'rails-ws:sentinel-proc) 98 | (setq rails-ws:process-environment env) 99 | (message (format "%s (%s) starting with port %s" 100 | (capitalize rails-ws:default-server-type) 101 | env 102 | rails-ws:port))))))) 103 | 104 | (defun rails-ws:compute-server-conmmand (server-type port env) 105 | (cond 106 | ((string= "thin" server-type) 107 | (list server-type 108 | (format "-p %s -e %s start" 109 | port 110 | env))) 111 | (t 112 | (list rails-ruby-command 113 | (format "script/server %s -p %s -e %s" 114 | server-type 115 | port 116 | env))))) 117 | 118 | (defun rails-ws:stop () 119 | "Stop the WebServer process." 120 | (interactive) 121 | (let ((proc (get-buffer-process rails-ws:buffer-name))) 122 | (when proc (kill-process proc t)))) 123 | 124 | 125 | (defun rails-ws:start-default () 126 | "Start WebServer using the default environment defined in 127 | `rails-default-environment'." 128 | (interactive) 129 | (rails-ws:start rails-default-environment)) 130 | 131 | (defun rails-ws:start-development () 132 | (interactive) 133 | (rails-ws:start "development")) 134 | 135 | (defun rails-ws:start-production () 136 | (interactive) 137 | (rails-ws:start "production")) 138 | 139 | (defun rails-ws:start-test () 140 | (interactive) 141 | (rails-ws:start "test")) 142 | 143 | (defun rails-ws:toggle-start-stop () 144 | "Toggle Rails WebServer start/stop with default environment." 145 | (interactive) 146 | (if (rails-ws:running-p) 147 | (rails-ws:stop) 148 | (rails-ws:start-default))) 149 | 150 | (defun rails-ws:print-status () 151 | (interactive) 152 | (message 153 | (concat rails-ws:default-server-type 154 | " (" (if rails-ws:process-environment 155 | rails-ws:process-environment 156 | rails-default-environment) ")" 157 | " is " 158 | (if (rails-ws:running-p) 159 | (concat "running on port " rails-ws:port) 160 | "stopped")))) 161 | 162 | ;;;;;;;;;; Open browser ;;;;;;;;;; 163 | 164 | (defun rails-ws:open-browser (&optional address) 165 | "Open a browser on the main page of the current Rails project 166 | server." 167 | (interactive) 168 | (let ((url (concat (concat rails-ws:server-name 169 | ":" 170 | rails-ws:port 171 | "/" 172 | address )))) 173 | (message "Opening browser: %s" url) 174 | (browse-url url))) 175 | 176 | (defun rails-ws:open-browser-on-controller (&optional controller action params) 177 | "Open browser on the controller/action/id for the current 178 | file." 179 | (interactive 180 | (list 181 | (completing-read "Controller name: " 182 | (list->alist (rails-core:controllers t))) 183 | (read-from-minibuffer "Action name: ") 184 | (read-from-minibuffer "Params: "))) 185 | (when (string-not-empty controller) 186 | (rails-ws:open-browser 187 | (concat (rails-core:file-by-class controller t) "/" 188 | (if (string-not-empty action) (concat action "/")) params)))) 189 | 190 | (defun rails-ws:auto-open-browser (ask-parameters?) 191 | "Autodetect the current action and open browser on it with. 192 | Prefix the command to ask parameters for action." 193 | (interactive "P") 194 | (rails-project:with-root 195 | (root) 196 | (if (find (rails-core:buffer-type) '(:view :controller)) 197 | (when-bind (controller (rails-core:current-controller)) 198 | (rails-ws:open-browser-on-controller 199 | controller (rails-core:current-action) 200 | (when ask-parameters? 201 | (read-from-minibuffer "Parameters: ")))) 202 | (message "You can auto-open browser only in view or controller")))) 203 | 204 | (provide 'rails-ws) -------------------------------------------------------------------------------- /rails.el: -------------------------------------------------------------------------------- 1 | ;;; rails.el --- minor mode for editing RubyOnRails code 2 | 3 | ;; Copyright (C) 2006 Dmitry Galinsky 4 | 5 | ;; Authors: Dmitry Galinsky , 6 | ;; Rezikov Peter 7 | 8 | ;; Keywords: ruby rails languages oop 9 | ;; $URL$ 10 | ;; $Id$ 11 | 12 | ;;; License 13 | 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License 16 | ;; as published by the Free Software Foundation; either version 2 17 | ;; of the License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | ;;; Code: 29 | 30 | (unless (<= 22 emacs-major-version) 31 | (error 32 | (format "emacs-rails require CVS version of Emacs (future Emacs 22), and not be running on your Emacs %s.%s" 33 | emacs-major-version 34 | emacs-minor-version))) 35 | 36 | (eval-when-compile 37 | (require 'speedbar) 38 | (require 'inf-ruby) 39 | (require 'ruby-mode) 40 | (require 'ruby-electric)) 41 | 42 | (require 'sql) 43 | (require 'ansi-color) 44 | (require 'etags) 45 | (require 'find-recursive) 46 | 47 | (require 'predictive-prog-mode) 48 | 49 | (require 'inflections) 50 | 51 | (require 'rails-compat) 52 | (require 'rails-project) 53 | 54 | (require 'rails-core) 55 | (require 'rails-ruby) 56 | (require 'rails-lib) 57 | 58 | (require 'rails-cmd-proxy) 59 | (require 'rails-navigation) 60 | (require 'rails-find) 61 | (require 'rails-scripts) 62 | (require 'rails-rake) 63 | (require 'rails-test) 64 | (require 'rails-ws) 65 | (require 'rails-log) 66 | (require 'rails-ui) 67 | (require 'rails-model-layout) 68 | (require 'rails-controller-layout) 69 | (require 'rails-features) 70 | (require 'rails-spec) 71 | (require 'rails-shoulda) 72 | 73 | 74 | ;;;;;;;;;; Variable definition ;;;;;;;;;; 75 | 76 | (defgroup rails nil 77 | "Edit Rails projet with Emacs." 78 | :group 'programming 79 | :prefix "rails-") 80 | 81 | (defcustom rails-api-root nil 82 | "*Root of Rails API html documentation. Must be a local directory." 83 | :group 'rails 84 | :type 'string) 85 | 86 | (defcustom rails-use-alternative-browse-url nil 87 | "Indicates an alternative way of loading URLs on Windows. 88 | Try using the normal method before. If URLs invoked by the 89 | program don't end up in the right place, set this option to 90 | true." 91 | :group 'rails 92 | :type 'boolean) 93 | 94 | (defcustom rails-browse-api-with-w3m nil 95 | "Indicates that the user wants to browse the Rails API using 96 | Emacs w3m browser." 97 | :group 'rails 98 | :type 'boolean) 99 | 100 | (defcustom rails-tags-command "ctags -e -a --Ruby-kinds=-f -o %s -R %s" 101 | "Command used to generate TAGS in Rails root" 102 | :group 'rails 103 | :type 'string) 104 | 105 | (defcustom rails-ri-command "ri" 106 | "Command used to invoke the ri utility." 107 | :group 'rails 108 | :type 'string) 109 | 110 | (defcustom rails-always-use-text-menus nil 111 | "Force the use of text menus by default." 112 | :group 'rails 113 | :type 'boolean) 114 | 115 | (defcustom rails-ask-when-reload-tags nil 116 | "Indicates whether the user should confirm reload a TAGS table or not." 117 | :group 'rails 118 | :type 'boolean) 119 | 120 | (defcustom rails-chm-file nil 121 | "Path to CHM documentation file on Windows, or nil." 122 | :group 'rails 123 | :type 'string) 124 | 125 | (defcustom rails-ruby-command "ruby" 126 | "Ruby preferred command line invocation." 127 | :group 'rails 128 | :type 'string) 129 | 130 | (defcustom rails-layout-template 131 | " 133 | 135 | 136 | 137 | 138 | <%= stylesheet_link_tag \"default\" %> 139 | 140 | 141 | 142 | <%= yield %> 143 | 144 | " 145 | "Default html template for new rails layout" 146 | :group 'rails 147 | :type 'string) 148 | 149 | (defcustom rails-enable-ruby-electric t 150 | "Indicates whether ruby electric minor mode should be enabled by default for ruby files" 151 | :group 'rails 152 | :type 'boolean) 153 | 154 | (defcustom rails-number-of-lines-shown-when-opening-log-file 130 155 | "Specifies how many lines to show initially when opening a log file" 156 | :group 'rails 157 | :type 'integer) 158 | 159 | (defvar rails-version "0.5.99.6") 160 | (defvar rails-templates-list '("html.erb" "erb" "js.rjs" "builder" "rhtml" "rxml" "rjs" "haml" "liquid" "mab")) 161 | (defvar rails-use-another-define-key nil) 162 | (defvar rails-primary-switch-func nil) 163 | (defvar rails-secondary-switch-func nil) 164 | (defvar rails-required-lisp-eval-depth 1000) ; Specifies the minimum required value of max-lisp-eval-depth for rails mode to work 165 | 166 | (defvar rails-directory<-->types 167 | '((:controller "app/controllers/") 168 | (:layout "app/layouts/") 169 | (:view "app/views/") 170 | (:observer "app/models/" (lambda (file) (rails-core:observer-p file))) 171 | (:mailer "app/models/" (lambda (file) (rails-core:mailer-p file))) 172 | (:model "app/models/" (lambda (file) (and (not (rails-core:mailer-p file)) 173 | (not (rails-core:observer-p file))))) 174 | (:helper "app/helpers/") 175 | (:plugin "vendor/plugins/") 176 | (:unit-test "test/unit/") 177 | (:functional-test "test/functional/") 178 | (:fixture "test/fixtures/") 179 | (:migration "db/migrate")) 180 | "Rails file types -- rails directories map") 181 | 182 | (defvar rails-enviroments '("development" "production" "test")) 183 | (defvar rails-default-environment (first rails-enviroments)) 184 | 185 | (defvar rails-adapters-alist 186 | '(("mysql" . sql-mysql) 187 | ("postgresql" . sql-postgres) 188 | ("sqlite3" . sql-sqlite)) 189 | "Sets emacs sql function for rails adapter names.") 190 | 191 | (defvar rails-tags-dirs '("app" "lib" "test" "db") 192 | "List of directories from RAILS_ROOT where ctags works.") 193 | 194 | (defun rails-use-text-menu () 195 | "If t use text menu, popup menu otherwise" 196 | (or (null window-system) rails-always-use-text-menus)) 197 | 198 | ;;;;;;;; hack ;;;; 199 | (defun rails-svn-status-into-root () 200 | (interactive) 201 | (rails-project:with-root (root) 202 | (svn-status root))) 203 | 204 | ;; helper functions/macros 205 | (defun rails-search-doc (&optional item) 206 | (interactive) 207 | (setq item (if item item (thing-at-point 'sexp))) 208 | (unless item 209 | (setq item (read-string "Search symbol: "))) 210 | (if item 211 | (if (and rails-chm-file 212 | (file-exists-p rails-chm-file)) 213 | (start-process "keyhh" "*keyhh*" "keyhh.exe" "-#klink" 214 | (format "'%s'" item) rails-chm-file) 215 | (let ((buf (buffer-name))) 216 | (unless (string= buf "*ri*") 217 | (switch-to-buffer-other-window "*ri*")) 218 | (setq buffer-read-only nil) 219 | (kill-region (point-min) (point-max)) 220 | (message (concat "Please wait...")) 221 | (call-process rails-ri-command nil "*ri*" t item) 222 | (local-set-key [return] 'rails-search-doc) 223 | (ansi-color-apply-on-region (point-min) (point-max)) 224 | (setq buffer-read-only t) 225 | (goto-char (point-min)))))) 226 | 227 | (defun rails-create-tags() 228 | "Create tags file" 229 | (interactive) 230 | (rails-project:in-root 231 | (message "Creating TAGS, please wait...") 232 | (let ((tags-file-name (rails-core:file "TAGS"))) 233 | (shell-command 234 | (format rails-tags-command tags-file-name 235 | (strings-join " " (mapcar #'rails-core:file rails-tags-dirs)))) 236 | (flet ((yes-or-no-p (p) (if rails-ask-when-reload-tags 237 | (y-or-n-p p) 238 | t))) 239 | (visit-tags-table tags-file-name))))) 240 | 241 | (defun rails-apply-for-buffer-type () 242 | (let* ((type (rails-core:buffer-type)) 243 | (name (substring (symbol-name type) 1)) 244 | (minor-mode-name (format "rails-%s-minor-mode" name)) 245 | (minor-mode-abbrev (concat minor-mode-name "-abbrev-table"))) 246 | (when (require (intern minor-mode-name) nil t) ;; load new style minor mode rails-*-minor-mode 247 | (when (fboundp (intern minor-mode-name)) 248 | (apply (intern minor-mode-name) (list t)) 249 | (when (boundp (intern minor-mode-abbrev)) 250 | (merge-abbrev-tables 251 | (symbol-value (intern minor-mode-abbrev)) 252 | local-abbrev-table)))))) 253 | 254 | ;;;;;;;;;; Database integration ;;;;;;;;;; 255 | 256 | (defstruct rails-db-conf adapter host database username password) 257 | 258 | (defun rails-db-parameters (env) 259 | "Return database parameters for enviroment ENV" 260 | (with-temp-buffer 261 | (shell-command 262 | (format "ruby -r yaml -r erb -e 'YAML.load(ERB.new(ARGF.read).result)[\"%s\"].to_yaml.display' %s" 263 | env 264 | (rails-core:file "config/database.yml")) 265 | (current-buffer)) 266 | (let ((answer 267 | (make-rails-db-conf 268 | :adapter (yml-value "adapter") 269 | :host (yml-value "host") 270 | :database (yml-value "database") 271 | :username (yml-value "username") 272 | :password (yml-value "password")))) 273 | answer))) 274 | 275 | (defun rails-database-emacs-func (adapter) 276 | "Return the Emacs function for ADAPTER that, when run, will 277 | +invoke the appropriate database server console." 278 | (cdr (assoc adapter rails-adapters-alist))) 279 | 280 | (defun rails-read-enviroment-name (&optional default) 281 | "Read Rails enviroment with auto-completion." 282 | (completing-read "Environment name: " (list->alist rails-enviroments) nil nil default)) 283 | 284 | (defun* rails-run-sql (&optional env) 285 | "Run a SQL process for the current Rails project." 286 | (interactive (list (rails-read-enviroment-name "development"))) 287 | (rails-project:with-root (root) 288 | (cd root) 289 | (if (bufferp (sql-find-sqli-buffer)) 290 | (switch-to-buffer-other-window (sql-find-sqli-buffer)) 291 | (let ((conf (rails-db-parameters env))) 292 | (let ((sql-database (rails-db-conf-database conf)) 293 | (default-process-coding-system '(utf-8 . utf-8)) 294 | (sql-server (rails-db-conf-host conf)) 295 | (sql-user (rails-db-conf-username conf)) 296 | (sql-password (rails-db-conf-password conf))) 297 | ;; Reload localy sql-get-login to avoid asking of confirmation of DB login parameters 298 | (flet ((sql-get-login (&rest pars) () t)) 299 | (funcall (rails-database-emacs-func (rails-db-conf-adapter conf))))))))) 300 | 301 | (defun rails-has-api-root () 302 | "Test whether `rails-api-root' is configured or not, and offer to configure 303 | it in case it's still empty for the project." 304 | (rails-project:with-root 305 | (root) 306 | (unless (or (file-exists-p (rails-core:file "doc/api/index.html")) 307 | (not (yes-or-no-p (concat "This project has no API documentation. " 308 | "Would you like to configure it now? ")))) 309 | (let (clobber-gems) 310 | (message "This may take a while. Please wait...") 311 | (unless (file-exists-p (rails-core:file "vendor/rails")) 312 | (setq clobber-gems t) 313 | (message "Freezing gems...") 314 | (shell-command-to-string "rake rails:freeze:gems")) 315 | ;; Hack to allow generation of the documentation for Rails 1.0 and 1.1 316 | ;; See http://dev.rubyonrails.org/ticket/4459 317 | (unless (file-exists-p (rails-core:file "vendor/rails/activesupport/README")) 318 | (write-string-to-file (rails-core:file "vendor/rails/activesupport/README") 319 | "Placeholder")) 320 | (message "Generating documentation...") 321 | (shell-command-to-string "rake doc:rails") 322 | (if clobber-gems 323 | (progn 324 | (message "Unfreezing gems...") 325 | (shell-command-to-string "rake rails:unfreeze"))) 326 | (message "Done..."))) 327 | (if (file-exists-p (rails-core:file "doc/api/index.html")) 328 | (setq rails-api-root (rails-core:file "doc/api"))))) 329 | 330 | (defun rails-browse-api () 331 | "Browse Rails API on RAILS-API-ROOT." 332 | (interactive) 333 | (if (rails-has-api-root) 334 | (rails-browse-api-url (concat rails-api-root "/index.html")) 335 | (message "Please configure variable rails-api-root."))) 336 | 337 | (defun rails-get-api-entries (name file sexp get-file-func) 338 | "Return all API entries named NAME in file FILE using SEXP to 339 | find matches, and GET-FILE-FUNC to process the matches found." 340 | (if (file-exists-p (concat rails-api-root "/" file)) 341 | (save-current-buffer 342 | (save-match-data 343 | (find-file (concat rails-api-root "/" file)) 344 | (let* ((result 345 | (loop for line in (split-string (buffer-string) "\n") 346 | when (string-match (format sexp (regexp-quote name)) line) 347 | collect (cons (match-string-no-properties 2 line) 348 | (match-string-no-properties 1 line))))) 349 | (kill-buffer (current-buffer)) 350 | (when-bind (api-file (funcall get-file-func result)) 351 | (rails-browse-api-url (concat "file://" rails-api-root "/" api-file)))))) 352 | (message "There are no API docs."))) 353 | 354 | (defun rails-browse-api-class (class) 355 | "Browse the Rails API documentation for CLASS." 356 | (rails-get-api-entries 357 | class "fr_class_index.html" "%s<" 358 | (lambda (entries) 359 | (cond ((= 0 (length entries)) (progn (message "No API Rails doc for class %s." class) nil)) 360 | ((= 1 (length entries)) (cdar entries)))))) 361 | 362 | (defun rails-browse-api-method (method) 363 | "Browse the Rails API documentation for METHOD." 364 | (rails-get-api-entries 365 | method "fr_method_index.html" "%s[ ]+(\\(.*\\))" 366 | (lambda (entries) 367 | (cond ((= 0 (length entries)) (progn (message "No API Rails doc for %s" method) nil)) 368 | ((= 1 (length entries)) (cdar entries)) 369 | (t (cdr (assoc (completing-read (format "Method %s from what class? " method) entries) 370 | entries))))))) 371 | 372 | (defun rails-browse-api-at-point () 373 | "Open the Rails API documentation on the class or method at the current point. 374 | The variable `rails-api-root' must be pointing to a local path 375 | either in your project or elsewhere in the filesystem. The 376 | function will also offer to build the documentation locally if 377 | necessary." 378 | (interactive) 379 | (if (rails-has-api-root) 380 | (let ((current-symbol (prog2 381 | (modify-syntax-entry ?: "w") 382 | (thing-at-point 'sexp) 383 | (modify-syntax-entry ?: ".")))) 384 | (if current-symbol 385 | (if (capital-word-p current-symbol) 386 | (rails-browse-api-class current-symbol) 387 | (rails-browse-api-method current-symbol)))) 388 | (message "Please configure \"rails-api-root\"."))) 389 | 390 | ;;; Rails minor mode 391 | 392 | (define-minor-mode rails-minor-mode 393 | "RubyOnRails" 394 | nil 395 | " RoR" 396 | rails-minor-mode-map 397 | (abbrev-mode -1) 398 | (make-local-variable 'tags-file-name) 399 | (make-local-variable 'rails-primary-switch-func) 400 | (make-local-variable 'rails-secondary-switch-func) 401 | (rails-features:install)) 402 | 403 | ;; hooks 404 | 405 | (add-hook 'ruby-mode-hook 406 | (lambda() 407 | (require 'rails-ruby) 408 | (require 'ruby-electric) 409 | (ruby-electric-mode (or rails-enable-ruby-electric -1)) 410 | (ruby-hs-minor-mode t) 411 | (imenu-add-to-menubar "IMENU") 412 | (modify-syntax-entry ?! "w" (syntax-table)) 413 | (modify-syntax-entry ?: "w" (syntax-table)) 414 | (modify-syntax-entry ?_ "w" (syntax-table)) 415 | (local-set-key (kbd "C-.") 'complete-tag) 416 | (local-set-key (if rails-use-another-define-key 417 | (kbd "TAB") (kbd "")) 418 | 'indent-and-complete) 419 | (local-set-key (rails-key "f") '(lambda() 420 | (interactive) 421 | (mouse-major-mode-menu (rails-core:menu-position)))) 422 | (local-set-key (kbd "C-:") 'ruby-toggle-string<>simbol) 423 | (local-set-key (if rails-use-another-define-key 424 | (kbd "RET") (kbd "")) 425 | 'ruby-newline-and-indent))) 426 | 427 | (add-hook 'speedbar-mode-hook 428 | (lambda() 429 | (speedbar-add-supported-extension "\\.rb"))) 430 | 431 | (add-hook 'find-file-hooks 432 | (lambda() 433 | (rails-project:with-root 434 | (root) 435 | (progn 436 | (local-set-key (if rails-use-another-define-key 437 | (kbd "TAB") (kbd "")) 438 | 'indent-and-complete) 439 | (rails-minor-mode t) 440 | (rails-apply-for-buffer-type))))) 441 | 442 | ;; Run rails-minor-mode in dired 443 | 444 | (add-hook 'dired-mode-hook 445 | (lambda () 446 | (if (rails-project:root) 447 | (rails-minor-mode t)))) 448 | 449 | 450 | (autoload 'haml-mode "haml-mode" "" t) 451 | 452 | (setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist)) 453 | (setq auto-mode-alist (cons '("\\.rake$" . ruby-mode) auto-mode-alist)) 454 | (setq auto-mode-alist (cons '("\\.mab$" . ruby-mode) auto-mode-alist)) 455 | (setq auto-mode-alist (cons '("Rakefile$" . ruby-mode) auto-mode-alist)) 456 | (setq auto-mode-alist (cons '("\\.haml$" . haml-mode) auto-mode-alist)) 457 | (setq auto-mode-alist (cons '("\\.rjs$" . ruby-mode) auto-mode-alist)) 458 | (setq auto-mode-alist (cons '("\\.rxml$" . ruby-mode) auto-mode-alist)) 459 | (setq auto-mode-alist (cons '("\\.builder$" . ruby-mode) auto-mode-alist)) 460 | (setq auto-mode-alist (cons '("\\.rjs$" . ruby-mode) auto-mode-alist)) 461 | (setq auto-mode-alist (cons '("\\.rhtml$" . html-mode) auto-mode-alist)) 462 | (setq auto-mode-alist (cons '("\\.erb$" . html-mode) auto-mode-alist)) 463 | 464 | (modify-coding-system-alist 'file "\\.rb$" 'utf-8) 465 | (modify-coding-system-alist 'file "\\.rake$" 'utf-8) 466 | (modify-coding-system-alist 'file "Rakefile$" 'utf-8) 467 | (modify-coding-system-alist 'file (rails-core:regex-for-match-view) 'utf-8) 468 | 469 | ;; Some navigation breaks if max-lisp-eval-depth is not high enough, up it if too low 470 | (setq max-lisp-eval-depth (max max-lisp-eval-depth rails-required-lisp-eval-depth)) 471 | 472 | (provide 'rails) 473 | --------------------------------------------------------------------------------