Add ruby stuff
authorJoerg Jaspert <joerg@ganneff.de>
Tue, 28 Jan 2014 11:09:07 +0000 (12:09 +0100)
committerJoerg Jaspert <joerg@ganneff.de>
Tue, 28 Jan 2014 11:09:07 +0000 (12:09 +0100)
.emacs.d/elisp/local/inf-ruby.el [new file with mode: 0644]
.emacs.d/elisp/local/ruby-hash-syntax.el [new file with mode: 0644]

diff --git a/.emacs.d/elisp/local/inf-ruby.el b/.emacs.d/elisp/local/inf-ruby.el
new file mode 100644 (file)
index 0000000..d26c768
--- /dev/null
@@ -0,0 +1,636 @@
+;;; inf-ruby.el --- Run a Ruby process in a buffer
+
+;; Copyright (C) 1999-2008 Yukihiro Matsumoto, Nobuyoshi Nakada
+
+;; Author: Yukihiro Matsumoto
+;;         Nobuyoshi Nakada
+;;         Cornelius Mika <cornelius.mika@gmail.com>
+;;         Dmitry Gutov <dgutov@yandex.ru>
+;;         Kyle Hargraves <pd@krh.me>
+;; URL: http://github.com/nonsequitur/inf-ruby
+;; Created: 8 April 1998
+;; Keywords: languages ruby
+;; Version: 2.3.2
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;; This file is not part of GNU Emacs.
+
+;;; Commentary:
+;;
+;; inf-ruby provides a REPL buffer connected to a Ruby subprocess.
+;;
+;; If you're installing manually, you'll need to:
+;; * drop the file somewhere on your load path (perhaps ~/.emacs.d)
+;; * Add the following lines to your .emacs file:
+;;
+;;    (autoload 'inf-ruby "inf-ruby" "Run an inferior Ruby process" t)
+;;    (add-hook 'ruby-mode-hook 'inf-ruby-minor-mode)
+;;
+;; Or, for enh-ruby-mode:
+;;
+;;    (add-hook 'enh-ruby-mode-hook 'inf-ruby-minor-mode)
+;;
+;; Installation via ELPA interface does the above for you
+;; automatically.
+;;
+;; Additionally, consider adding
+;;
+;;    (add-hook 'after-init-hook 'inf-ruby-switch-setup)
+;;
+;; to your init file to easily switch from common Ruby compilation
+;; modes to interact with a debugger.
+
+;;; Code:
+
+(require 'comint)
+(require 'compile)
+(require 'ruby-mode)
+(require 'thingatpt)
+
+(defgroup inf-ruby nil
+  "Run Ruby process in a buffer"
+  :group 'languages)
+
+(defcustom inf-ruby-prompt-read-only t
+  "If non-nil, the prompt will be read-only.
+
+Also see the description of `ielm-prompt-read-only'.")
+
+(defvar inf-ruby-default-implementation "ruby"
+  "Which Ruby implementation to use if none is specified.")
+
+(defconst inf-ruby-prompt-format
+  (concat
+   (mapconcat
+    #'identity
+    '("\\(^%s> *\\)"                      ; Simple
+      "\\(^(rdb:1) *\\)"                  ; Debugger
+      "\\(^\\(irb([^)]+)"                 ; IRB default
+      "\\([[0-9]+] \\)?[Pp]ry ?([^)]+)"   ; Pry
+      "\\(jruby-\\|JRUBY-\\)?[1-9]\\.[0-9]\\.[0-9]+\\(-?p?[0-9]+\\)?" ; RVM
+      "^rbx-head\\)")                     ; RVM continued
+    "\\|")
+   ;; Statement and nesting counters, common to the last four.
+   " ?[0-9:]* ?%s *\\)")
+  "Format string for the prompt regexp pattern.
+Two placeholders: first char in the Simple prompt, and the last
+graphical char in all other prompts.")
+
+(defvar inf-ruby-first-prompt-pattern (format inf-ruby-prompt-format ">" ">")
+  "First prompt regex pattern of Ruby interpreter.")
+
+(defvar inf-ruby-prompt-pattern (format inf-ruby-prompt-format "[?>]" "[\]>*\"'/`]")
+  "Prompt regex pattern of Ruby interpreter.")
+
+(defvar inf-ruby-mode-hook nil
+  "Hook for customizing `inf-ruby-mode'.")
+
+(defvar inf-ruby-mode-map
+  (let ((map (copy-keymap comint-mode-map)))
+    (define-key map (kbd "C-c C-l") 'ruby-load-file)
+    (define-key map (kbd "C-x C-e") 'ruby-send-last-sexp)
+    (define-key map (kbd "TAB") 'inf-ruby-complete)
+    (define-key map (kbd "C-x C-q") 'inf-ruby-maybe-switch-to-compilation)
+    map)
+  "Mode map for `inf-ruby-mode'.")
+
+(defvar inf-ruby-implementations
+  '(("ruby"     . "irb --prompt default -r irb/completion")
+    ("jruby"    . "jruby -S irb --prompt default -r irb/completion")
+    ("rubinius" . "rbx -r irb/completion")
+    ("yarv"     . "irb1.9 -r irb/completion")
+    ("macruby"  . "macirb -r irb/completion")
+    ("pry"      . "pry"))
+  "An alist of ruby implementations to irb executable names.")
+
+;;;###autoload
+(defvar ruby-source-modes '(ruby-mode enh-ruby-mode)
+  "Used to determine if a buffer contains Ruby source code.
+If it's loaded into a buffer that is in one of these major modes, it's
+considered a ruby source file by `ruby-load-file'.
+Used by these commands to determine defaults.")
+
+(defvar ruby-prev-l/c-dir/file nil
+  "Caches the last (directory . file) pair.
+Caches the last pair used in the last `ruby-load-file' command.
+Used for determining the default in the
+next one.")
+
+(defvar inf-ruby-at-top-level-prompt-p t)
+
+(defconst inf-ruby-error-regexp-alist
+  '(("SyntaxError: \\(?:compile error\n\\)?\\([^\(].*\\):\\([1-9][0-9]*\\):" 1 2)
+    ("^\tfrom \\([^\(].*\\):\\([1-9][0-9]*\\)\\(:in `.*'\\)?$" 1 2)))
+
+;;;###autoload
+(defun inf-ruby-setup-keybindings ()
+  "Hook up `inf-ruby-minor-mode' to each of `ruby-source-modes'."
+  (warn "`inf-ruby-setup-keybindings' is deprecated, please don't use it anymore.")
+  (warn "If you're using `inf-ruby' from Git, please look up the new usage instructions."))
+
+(make-obsolete 'inf-ruby-setup-keybindings 'add-hook "2.3.1")
+
+(defvar inf-ruby-minor-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-M-x") 'ruby-send-definition)
+    (define-key map (kbd "C-x C-e") 'ruby-send-last-sexp)
+    (define-key map (kbd "C-c C-b") 'ruby-send-block)
+    (define-key map (kbd "C-c M-b") 'ruby-send-block-and-go)
+    (define-key map (kbd "C-c C-x") 'ruby-send-definition)
+    (define-key map (kbd "C-c M-x") 'ruby-send-definition-and-go)
+    (define-key map (kbd "C-c C-r") 'ruby-send-region)
+    (define-key map (kbd "C-c M-r") 'ruby-send-region-and-go)
+    (define-key map (kbd "C-c C-z") 'ruby-switch-to-inf)
+    (define-key map (kbd "C-c C-l") 'ruby-load-file)
+    (define-key map (kbd "C-c C-s") 'inf-ruby)
+    map))
+
+;;;###autoload
+(define-minor-mode inf-ruby-minor-mode
+  "Minor mode for interacting with the inferior process buffer.
+
+The following commands are available:
+
+\\{inf-ruby-minor-mode-map}"
+  :lighter "" :keymap inf-ruby-minor-mode-map)
+
+(defvar inf-ruby-buffer nil "Current Ruby process buffer.")
+
+(defun inf-ruby-mode ()
+  "Major mode for interacting with an inferior Ruby REPL process.
+
+A simple IRB process can be fired up with \\[inf-ruby].
+
+To launch a REPL with project-specific console instead, type
+\\[inf-ruby-console-auto].  It recognizes several
+project types, including Rails, gems and anything with `racksh'
+in their Gemfile.
+
+Customization: When entered, this mode runs `comint-mode-hook' and
+`inf-ruby-mode-hook' (in that order).
+
+You can send text to the inferior Ruby process from other buffers containing
+Ruby source.
+
+    `ruby-switch-to-inf' switches the current buffer to the ruby process buffer.
+    `ruby-send-definition' sends the current definition to the ruby process.
+    `ruby-send-region' sends the current region to the ruby process.
+    `ruby-send-definition-and-go' and `ruby-send-region-and-go'
+        switch to the ruby process buffer after sending their text.
+
+Commands:
+`RET' after the end of the process' output sends the text from the
+    end of process to point.
+`RET' before the end of the process' output copies the sexp ending at point
+    to the end of the process' output, and sends it.
+`DEL' converts tabs to spaces as it moves back.
+`TAB' completes the input at point. IRB, Pry and Bond completion is supported.
+`C-M-q' does `TAB' on each line starting within following expression.
+Paragraphs are separated only by blank lines.  # start comments.
+If you accidentally suspend your process, use \\[comint-continue-subjob]
+to continue it.
+
+The following commands are available:
+
+\\{inf-ruby-mode-map}"
+  (interactive)
+  (let ((orig-mode-line-process mode-line-process))
+    (comint-mode)
+    (when orig-mode-line-process
+      (setq mode-line-process orig-mode-line-process)))
+  (setq comint-prompt-regexp inf-ruby-prompt-pattern)
+  (ruby-mode-variables)
+  (setq major-mode 'inf-ruby-mode)
+  (setq mode-name "Inf-Ruby")
+  (use-local-map inf-ruby-mode-map)
+  (add-hook 'comint-output-filter-functions 'inf-ruby-output-filter nil t)
+  (setq comint-get-old-input 'inf-ruby-get-old-input)
+  (set (make-local-variable 'compilation-error-regexp-alist)
+       inf-ruby-error-regexp-alist)
+  (set (make-local-variable 'comint-prompt-read-only) inf-ruby-prompt-read-only)
+  (when (eq system-type 'windows-nt)
+    (setq comint-process-echoes t))
+  (compilation-shell-minor-mode t)
+  (run-hooks 'inf-ruby-mode-hook))
+
+(defun inf-ruby-output-filter (output)
+  "Check if the current prompt is a top-level prompt."
+  (unless (zerop (length output))
+    (setq inf-ruby-at-top-level-prompt-p
+          (string-match inf-ruby-first-prompt-pattern
+                        (car (last (split-string output "\n")))))))
+
+;; adapted from replace-in-string in XEmacs (subr.el)
+(defun inf-ruby-remove-in-string (str regexp)
+  "Remove all matches in STR for REGEXP and returns the new string."
+  (let ((rtn-str "") (start 0) match prev-start)
+    (while (setq match (string-match regexp str start))
+      (setq prev-start start
+            start (match-end 0)
+            rtn-str (concat rtn-str (substring str prev-start match))))
+    (concat rtn-str (substring str start))))
+
+(defun inf-ruby-get-old-input ()
+  "Snarf the sexp ending at point."
+  (save-excursion
+    (let ((end (point)))
+      (re-search-backward inf-ruby-first-prompt-pattern)
+      (inf-ruby-remove-in-string (buffer-substring (point) end)
+                                 inf-ruby-prompt-pattern))))
+
+;;;###autoload
+(defun inf-ruby (&optional impl)
+  "Run an inferior Ruby process in a buffer.
+With prefix argument, prompts for which Ruby implementation
+\(from the list `inf-ruby-implementations') to use.  Runs the
+hooks `inf-ruby-mode-hook' \(after the `comint-mode-hook' is
+run)."
+
+  (interactive (list (if current-prefix-arg
+                         (completing-read "Ruby Implementation: "
+                                          (mapc #'car inf-ruby-implementations))
+                       inf-ruby-default-implementation)))
+  (setq impl (or impl "ruby"))
+
+  (let ((command (cdr (assoc impl inf-ruby-implementations))))
+    (run-ruby command impl)))
+
+;;;###autoload
+(defun run-ruby (&optional command name)
+  "Run an inferior Ruby process, input and output via buffer `*NAME*'.
+If there is a process already running in `*NAME*', switch to that buffer.
+
+NAME defaults to \"ruby\". COMMAND defaults to the default entry
+in `inf-ruby-implementations'.
+
+\(Type \\[describe-mode] in the process buffer for the list of commands.)"
+
+  (interactive)
+  (setq command (or command (cdr (assoc inf-ruby-default-implementation
+                                        inf-ruby-implementations))))
+  (setq name (or name "ruby"))
+
+  (if (not (comint-check-proc inf-ruby-buffer))
+      (let ((commandlist (split-string-and-unquote command))
+            (process-environment process-environment))
+        ;; http://debbugs.gnu.org/15775
+        (setenv "PAGER" (executable-find "cat"))
+        (set-buffer (apply 'make-comint name (car commandlist)
+                           nil (cdr commandlist)))
+        (inf-ruby-mode)))
+  (pop-to-buffer (setq inf-ruby-buffer (format "*%s*" name))))
+
+(defun inf-ruby-proc ()
+  "Return the current inferior Ruby process.
+
+See variable `inf-ruby-buffer'."
+  (or (get-buffer-process (if (eq major-mode 'inf-ruby-mode)
+                              (current-buffer)
+                            inf-ruby-buffer))
+      (error "No current process. See variable inf-ruby-buffer")))
+
+;; These commands are added to the ruby-mode keymap:
+
+(defconst ruby-send-terminator "--inf-ruby-%x-%d-%d-%d--"
+  "Template for irb here document terminator.
+Must not contain ruby meta characters.")
+
+(defconst inf-ruby-eval-binding
+  (concat "(IRB.conf[:MAIN_CONTEXT] && IRB.conf[:MAIN_CONTEXT].workspace.binding) || "
+          "(defined?(Pry) && Pry.toplevel_binding)"))
+
+(defconst ruby-eval-separator "")
+
+(defun ruby-send-region (start end)
+  "Send the current region to the inferior Ruby process."
+  (interactive "r")
+  (let (term (file (or buffer-file-name (buffer-name))) line)
+    (save-excursion
+      (save-restriction
+        (widen)
+        (goto-char start)
+        (setq line (+ start (forward-line (- start)) 1))
+        (goto-char start)
+        (while (progn
+                 (setq term (apply 'format ruby-send-terminator (random) (current-time)))
+                 (re-search-forward (concat "^" (regexp-quote term) "$") end t)))))
+    ;; compilation-parse-errors parses from second line.
+    (save-excursion
+      (let ((m (process-mark (inf-ruby-proc))))
+        (set-buffer (marker-buffer m))
+        (goto-char m)
+        (insert ruby-eval-separator "\n")
+        (set-marker m (point))))
+    (comint-send-string (inf-ruby-proc) (format "eval <<'%s', %s, %S, %d\n"
+                                                term inf-ruby-eval-binding
+                                                file line))
+    (comint-send-region (inf-ruby-proc) start end)
+    (comint-send-string (inf-ruby-proc) (concat "\n" term "\n"))))
+
+(defun ruby-send-definition ()
+  "Send the current definition to the inferior Ruby process."
+  (interactive)
+  (save-excursion
+    (ruby-end-of-defun)
+    (let ((end (point)))
+      (ruby-beginning-of-defun)
+      (ruby-send-region (point) end))))
+
+(defun ruby-send-last-sexp ()
+  "Send the previous sexp to the inferior Ruby process."
+  (interactive)
+  (ruby-send-region (save-excursion (ruby-backward-sexp) (point)) (point)))
+
+(defun ruby-send-block ()
+  "Send the current block to the inferior Ruby process."
+  (interactive)
+  (save-excursion
+    (ruby-end-of-block)
+    (end-of-line)
+    (let ((end (point)))
+      (ruby-beginning-of-block)
+      (ruby-send-region (point) end))))
+
+(defun ruby-switch-to-inf (eob-p)
+  "Switch to the ruby process buffer.
+With argument, positions cursor at end of buffer."
+  (interactive "P")
+  (if (and inf-ruby-buffer (get-buffer inf-ruby-buffer))
+      (pop-to-buffer inf-ruby-buffer)
+    (error "No current process buffer, see variable inf-ruby-buffer"))
+  (cond (eob-p
+         (push-mark)
+         (goto-char (point-max)))))
+
+(defun ruby-send-region-and-go (start end)
+  "Send the current region to the inferior Ruby process.
+Then switch to the process buffer."
+  (interactive "r")
+  (ruby-send-region start end)
+  (ruby-switch-to-inf t))
+
+(defun ruby-send-definition-and-go ()
+  "Send the current definition to the inferior Ruby.
+Then switch to the process buffer."
+  (interactive)
+  (ruby-send-definition)
+  (ruby-switch-to-inf t))
+
+(defun ruby-send-block-and-go ()
+  "Send the current block to the inferior Ruby.
+Then switch to the process buffer."
+  (interactive)
+  (ruby-send-block)
+  (ruby-switch-to-inf t))
+
+(defun ruby-load-file (file-name)
+  "Load a Ruby file into the inferior Ruby process."
+  (interactive (comint-get-source "Load Ruby file: " ruby-prev-l/c-dir/file
+                                  ruby-source-modes t)) ;; T because LOAD needs an exact name
+  (comint-check-source file-name) ; Check to see if buffer needs saved.
+  (setq ruby-prev-l/c-dir/file (cons (file-name-directory    file-name)
+                                     (file-name-nondirectory file-name)))
+  (comint-send-string (inf-ruby-proc) (concat "(load \""
+                                              file-name
+                                              "\"\)\n")))
+
+(defun ruby-escape-single-quoted (str)
+  "Escape single quotes, double quotes and newlines in STR."
+  (replace-regexp-in-string "'" "\\\\'"
+    (replace-regexp-in-string "\n" "\\\\n"
+      (replace-regexp-in-string "\\\\" "\\\\\\\\" str))))
+
+(defun inf-ruby-completions (expr)
+  "Return a list of completions for the Ruby expression starting with EXPR."
+  (let* ((proc (inf-ruby-proc))
+         (line (buffer-substring (save-excursion (beginning-of-thing 'line))
+                                 (point)))
+         (comint-filt (process-filter proc))
+         (kept "") completions
+         ;; Guard against running completions in parallel:
+         inf-ruby-at-top-level-prompt-p)
+    (set-process-filter proc (lambda (proc string) (setq kept (concat kept string))))
+    (unwind-protect
+        (let ((completion-snippet
+               (format (concat "proc { |expr, line| "
+                           "if defined?(Pry.config) then "
+                           "completor = Pry.config.completer"
+                           ".build_completion_proc(binding, defined?(_pry_) ? _pry_ : Pry.new)"
+                           " elsif defined?(Bond.agent) && Bond.started? then "
+                           "completor = Bond.agent"
+                           " end ? (puts completor.call(expr, line).compact) : "
+                           "if defined?(IRB::InputCompletor::CompletionProc) then "
+                           "puts IRB::InputCompletor::CompletionProc.call(expr).compact "
+                           "end }.call('%s', '%s')\n")
+                   (ruby-escape-single-quoted expr)
+                   (ruby-escape-single-quoted line))))
+          (process-send-string proc completion-snippet)
+          (while (and (not (string-match inf-ruby-prompt-pattern kept))
+                      (accept-process-output proc 2)))
+          (setq completions (butlast (split-string kept "\r?\n") 2))
+          ;; Subprocess echoes output on Windows and OS X.
+          (when (and completions (string= (concat (car completions) "\n") completion-snippet))
+            (setq completions (cdr completions))))
+      (set-process-filter proc comint-filt))
+    completions))
+
+(defconst inf-ruby-ruby-expr-break-chars " \t\n\"\'`><,;|&{(")
+
+(defun inf-ruby-completion-bounds-of-expr-at-point ()
+  "Return bounds of expression at point to complete."
+  (save-excursion
+    (let ((end (point)))
+      (skip-chars-backward (concat "^" inf-ruby-ruby-expr-break-chars))
+      (cons (point) end))))
+
+(defun inf-ruby-completion-expr-at-point ()
+  "Return expression at point to complete."
+  (let ((bounds (inf-ruby-completion-bounds-of-expr-at-point)))
+    (buffer-substring (car bounds) (cdr bounds))))
+
+(defun inf-ruby-completion-at-point ()
+  "Retrieve the list of completions and prompt the user.
+Returns the selected completion or nil."
+  (if inf-ruby-at-top-level-prompt-p
+      (let* ((expr (inf-ruby-completion-expr-at-point))
+             (completions (inf-ruby-completions expr)))
+        (if completions
+            (if (= (length completions) 1)
+                (car completions)
+              (completing-read "possible completions: "
+                               completions nil t expr))))
+    (message "Completion aborted: Not at a top-level prompt")
+    nil))
+
+(defun inf-ruby-complete ()
+  "Complete the Ruby code at point.
+Uses the first one available of Pry, Bond and the default IRB
+completion."
+  (interactive)
+  (let ((replacement (inf-ruby-completion-at-point)))
+    (when replacement
+      (inf-ruby-complete-replace-expr replacement))))
+
+(defun inf-ruby-complete-replace-expr (str)
+  "Replace expression at point with STR."
+  (let ((bounds (inf-ruby-completion-bounds-of-expr-at-point)))
+    (delete-region (car bounds) (cdr bounds)))
+  (insert str))
+
+(defun inf-ruby-complete-or-tab ()
+  "Complete the Ruby code at point or call `indent-for-tab-command'."
+  (interactive)
+  (let ((replacement (inf-ruby-completion-at-point)))
+    (if (not replacement)
+        (call-interactively 'indent-for-tab-command)
+      (inf-ruby-complete-replace-expr replacement))))
+
+(defvar inf-ruby-orig-compilation-mode nil
+  "Original compilation mode before switching to `inf-ruby-mode'.")
+
+(defvar inf-ruby-orig-process-filter nil
+  "Original process filter before switching to `inf-ruby-mode`.")
+
+(defun inf-ruby-switch-from-compilation ()
+  "Make the buffer writable and switch to `inf-ruby-mode'.
+Recommended for use when the program being executed enters
+interactive mode, i.e. hits a debugger breakpoint."
+  (interactive)
+  (setq buffer-read-only nil)
+  (buffer-enable-undo)
+  (let ((mode major-mode))
+    (inf-ruby-mode)
+    (make-local-variable 'inf-ruby-orig-compilation-mode)
+    (setq inf-ruby-orig-compilation-mode mode))
+  (let ((proc (get-buffer-process (current-buffer))))
+    (when proc
+      (make-local-variable 'inf-ruby-orig-process-filter)
+      (setq inf-ruby-orig-process-filter (process-filter proc))
+      (set-process-filter proc 'comint-output-filter))
+    (when (looking-back inf-ruby-prompt-pattern (line-beginning-position))
+      (let ((line (match-string 0)))
+        (delete-region (match-beginning 0) (point))
+        (comint-output-filter proc line)))))
+
+(defun inf-ruby-maybe-switch-to-compilation ()
+  "Switch to compilation mode this buffer was in before
+`inf-ruby-switch-from-compilation' was called, if it was.
+Otherwise, just toggle read-only status."
+  (interactive)
+  (if inf-ruby-orig-compilation-mode
+      (let ((orig-mode-line-process mode-line-process)
+            (proc (get-buffer-process (current-buffer)))
+            (filter inf-ruby-orig-process-filter))
+        (funcall inf-ruby-orig-compilation-mode)
+        (setq mode-line-process orig-mode-line-process)
+        (when proc
+          (set-process-filter proc filter)))
+    (toggle-read-only)))
+
+;;;###autoload
+(defun inf-ruby-switch-setup ()
+  "Modify `rspec-compilation-mode' and `ruby-compilation-mode'
+keymaps to bind `inf-ruby-switch-from-compilation' to `ะก-x C-q'."
+  (eval-after-load 'rspec-mode
+    '(define-key rspec-compilation-mode-map (kbd "C-x C-q")
+       'inf-ruby-switch-from-compilation))
+  (eval-after-load 'ruby-compilation
+    '(define-key ruby-compilation-mode-map (kbd "C-x C-q")
+       'inf-ruby-switch-from-compilation)))
+
+(defvar inf-ruby-console-patterns-alist
+  '(("config/application.rb" . rails)
+    ("*.gemspec" . gem)
+    ("Gemfile" . default))
+  "Mapping from file name patterns to name symbols.
+`inf-ruby-console-auto' walks up from the current directory until
+one of the patterns matches, then calls `inf-ruby-console-NAME',
+passing it the found directory.")
+
+(defun inf-ruby-console-match (dir)
+  "Find matching console command for DIR, if any."
+  (catch 'type
+    (dolist (pair inf-ruby-console-patterns-alist)
+      (let ((default-directory dir))
+        (when (file-expand-wildcards (car pair))
+          (throw 'type (cdr pair)))))))
+
+;;;###autoload
+(defun inf-ruby-console-auto ()
+  "Run the appropriate Ruby console command.
+The command and and the directory to run it from are detected
+automatically."
+  (interactive)
+  (let* ((dir (locate-dominating-file default-directory
+                                      #'inf-ruby-console-match))
+         (type (inf-ruby-console-match dir))
+         (fun (intern (format "inf-ruby-console-%s" type))))
+    (unless type (error "No matching directory found"))
+    (funcall fun dir)))
+
+;;;###autoload
+(defun inf-ruby-console-rails (dir)
+  "Run Rails console in DIR."
+  (interactive "D")
+  (let ((default-directory dir))
+    (run-ruby "rails console" "rails")))
+
+;;;###autoload
+(defun inf-ruby-console-gem (dir)
+  "Run IRB console for the gem in DIR.
+The main module should be loaded automatically.  If DIR contains a
+Gemfile, it should use the `gemspec' instruction."
+  (interactive "D")
+  (let* ((default-directory dir)
+         (base-command (if (file-exists-p "Gemfile")
+                           "bundle exec irb"
+                         "irb -I lib"))
+         files)
+    (unless (file-exists-p "lib")
+      (error "The directory must contain a 'lib' subdirectory"))
+    (dolist (item (directory-files "lib"))
+      (unless (file-directory-p item)
+        (setq files (cons item files))))
+    (run-ruby (concat base-command " "
+                      ;; If there are several files under 'lib'
+                      ;; (unlikely), load them all.
+                      (mapconcat
+                       (lambda (file)
+                         (concat " -r " (file-name-sans-extension file)))
+                       files
+                       ""))
+              "gem")))
+
+;;;###autoload
+(defun inf-ruby-console-default (dir)
+  "Run racksh, custom console.rb, or just IRB, in DIR."
+  (interactive "D")
+  (let ((default-directory dir))
+    (unless (file-exists-p "Gemfile")
+      (error "The directory must contain a Gemfile"))
+    (cond
+     ((with-temp-buffer
+        (insert-file-contents "Gemfile")
+        (re-search-forward "[\"']racksh[\"']" nil t))
+      (run-ruby "bundle exec racksh" "racksh"))
+     ((file-exists-p "console.rb")
+      (run-ruby "ruby console.rb" "console.rb"))
+     (t
+      (run-ruby "bundle console")))))
+
+;;;###autoload (dolist (mode ruby-source-modes) (add-hook (intern (format "%s-hook" mode)) 'inf-ruby-minor-mode))
+
+(provide 'inf-ruby)
+;;; inf-ruby.el ends here
diff --git a/.emacs.d/elisp/local/ruby-hash-syntax.el b/.emacs.d/elisp/local/ruby-hash-syntax.el
new file mode 100644 (file)
index 0000000..315cbdf
--- /dev/null
@@ -0,0 +1,65 @@
+;;; ruby-hash-syntax.el --- Toggle ruby hash syntax between classic and 1.9 styles
+
+;; Copyright (C) 2013  Steve Purcell
+
+;; Author: Steve Purcell <steve@sanityinc.com>
+;; Version: DEV
+;; URL: https://github.com/purcell/ruby-hash-syntax
+;; Keywords: languages
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Adapted from the method used by TextMate, this library provides
+;; a command `ruby-hash-syntax-toggle' which attempts to automatically
+;; convert the selected region of ruby code between 1.8 and 1.9 hash styles.
+
+;;; Code:
+
+;; Borrowed from https://github.com/textmate/ruby.tmbundle/blob/master/Commands/Convert%20Ruby%20hash%20to%201_9%20syntax.tmCommand
+
+;;;###autoload
+(defun ruby-toggle-hash-syntax (beg end)
+  "Toggle syntax of ruby hash literal in region from BEG to END between ruby 1.8 and 1.9 styles."
+  (interactive "r")
+  (save-excursion
+    (let ((limit (copy-marker (max beg end))))
+      (goto-char (min beg end))
+      (cond
+       ((ruby-hash-syntax--code-has-pattern "=>" limit)
+        (ruby-hash-syntax--replace ":\\([a-zA-Z0-9_]+\\) *=> *" "\\1: " limit))
+       ((ruby-hash-syntax--code-has-pattern "\\w+:" limit)
+        (ruby-hash-syntax--replace "\\([a-zA-Z0-9_]+\\):\\( *\\(?:\"\\(?:\\\"\\|[^\"]\\)*\"\\|'\\(?:\\'\\|[^']\\)*'\\|[a-zA-Z0-9_]+([^)]*)\\|[^,]+\\)\\)" ":\\1 =>\\2" limit))))))
+
+(defun ruby-hash-syntax--code-has-pattern (pat limit)
+  "A version of `search-forward' which skips over string literals.
+Argument PAT is the search patter, while LIMIT is the maximum
+search extent."
+  (let (found)
+    (save-excursion
+      (while (and (not found) (re-search-forward pat limit t))
+        (unless (elt (syntax-ppss) 3)
+          ;; If this isn't inside a string...
+          (setq found t))))
+    found))
+
+(defun ruby-hash-syntax--replace (from to end)
+  "Replace FROM with TO up to END."
+  (while (re-search-forward from end t)
+    (replace-match to nil nil)))
+
+
+(provide 'ruby-hash-syntax)
+;;; ruby-hash-syntax.el ends here