Emacs & Ruby: Indenting newline after comma [duplicate] - ruby

class Foo
attr_accessor :a,
:time, # ms since epoch
:b,
:c
end
In text mode, the variables listed after 'a' would indent as written above, but in ruby mode they would instead be flush with 'attr_accessor'. How can I get ruby mode to indent like text mode in this situation? Note that I'd like to be able to select the whole file and hit c-m-\ to get the above indentation in addition to all the other ruby-mode.el indentation rules.

This hack should work in the majority of cases.
(defadvice ruby-indent-line (after line-up-args activate)
(let (indent prev-indent arg-indent)
(save-excursion
(back-to-indentation)
(when (zerop (car (syntax-ppss)))
(setq indent (current-column))
(skip-chars-backward " \t\n")
(when (eq ?, (char-before))
(ruby-backward-sexp)
(back-to-indentation)
(setq prev-indent (current-column))
(skip-syntax-forward "w_.")
(skip-chars-forward " ")
(setq arg-indent (current-column)))))
(when prev-indent
(let ((offset (- (current-column) indent)))
(cond ((< indent prev-indent)
(indent-line-to prev-indent))
((= indent prev-indent)
(indent-line-to arg-indent)))
(when (> offset 0) (forward-char offset))))))
Example:
class Comment < ActiveRecord::Base
after_create :send_email_to_author,
:if => :author_wants_emails?,
:unless => Proc.new { |comment| comment.post.ignore_comments? }
end

From Remi (in comments):
Note that Emacs will correctly indent class Foo attr_accessor(:a, :time, # ms since epoch :b, :c) end – Rémi Dec 11 '10 at 8:50
You can add parens and have it indent properly -- I'm adding this here because I'm looking for unanswered questions, and this one comes up (incorrectly, since it has been answered in the comments).

When using Emacs 24.4 or newer, your example will be indented like this by default.

Related

Efficient hash table access with constructed keys

Common Lisp allows any lisp object to serve as a hash table key. But what if you only want to use part of an object as the key. For example, in
(defstruct action
(name nil :type symbol)
(parameters nil :type list)
(time 0 :type fixnum)
(database nil :type hash-table))
the time slot is inappropriate for equalp hashing situations. What is a good strategy for accessing a hash table using a (partial) lisp object as key? One approach might use a key like (list (action-name act1) (action-parameters act1) (action-database act1)), but this seems rather inefficient. Another approach might create a substructure to the action defstruct with just the three appropriate slots, and use that substructure as a key, but this seems somewhat ad-hoc just for the purpose of hash table access. Are there other methods that could work better?
I will use Common Lisp library from here, as for example
cl-custom-hash-table
Then going to your code, first when you create an action like this:
CL-USER> (setq action-1 (make-action
:parameters '(1 2 3)
:time 45))
produce this error:
The value NIL is not of the expected type HASH-TABLE.
[Condition of type TYPE-ERROR]
so you need to change your definition to something like this:
CL-USER> (defstruct action
(name nil :type symbol)
(parameters nil :type list)
(time 0 :type fixnum)
(database (make-hash-table) :type hash-table))
ACTION
CL-USER> (setq action-1 (make-action
:parameters '(1 2 3)
:time 45))
#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 45 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012E708D>)
Then you should define a function for equal time or what ever you need as follow:
accesing to the data
CL-USER> (action-time action-1)
45
create another action
CL-USER> (setq action-2 (make-action
:parameters '(1 2 3)
:time 102))
#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 102 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012FE58D>)
create the function for testing
CL-USER> (defun equal-actions-by-time (a1 a2) (= (action-time a1) (action-time a2)))
EQUAL-ACTIONS-BY-TIME
define the hash-function:
CL-USER> (defun hash-action (a) (action-time a))
HASH-ACTION
create your hash
CL-USER> (define-custom-hash-table-constructor make-action-hash :test equal-actions-by-time :hash-function hash-action)
MAKE-ACTION-HASH
CL-USER> (defparameter *foo-hash* (make-action-hash) "variable for stackoverflow")
*FOO-HASH*
try it:
CL-USER> (setf (gethash action-1 *foo-hash*) 1
(gethash action-2 *foo-hash*) 10)
10
CL-USER> (gethash action-1 *foo-hash*)
1
T
You can avoid using a library if the distribution will work in implementations that support custom TEST/HASH functions natively, if not you can use with-custom-hash-table
In the optimus case you can work as follow:
CL-USER> (defparameter *foo-hash* (make-hash-table :test 'equal-actions-by-time :hash-function 'hash-action))
*FOO-HASH*
CL-USER> (setf (gethash action-1 *foo-hash*) 1
(gethash action-2 *foo-hash*) 10)
10
CL-USER> (gethash action-1 *foo-hash*)
1
T

How to pass font-spec attributes as arguments to set-face-attribute?

Suppose that I have some font-spec in a variable my-font-spec. E.g.
(setq my-font-spec (font-spec :family "XYZ"
:height 120
:weight 'normal
:width 'normal))
I want to pass the attributes in this font-spec as the &rest arguments to set-face-attribute. IOW, I want to, in effect, invoke
(set-face-attribute some-face nil
:family "XYZ"
:height 120
:weight 'normal
:width 'normal)
but do so without spelling out the attributes (as I've done above), but rather indirectly, through some function of my-font-spec.
I'm not sure why, but calling (font-face-attributes my-font-spec) doesn't return the value of the :height attribute you specified:
(:family "XYZ" :weight normal :width normal)
If it did, you could just call:
(apply 'set-face-attribute some-face nil (font-face-attributes my-font-spec))
But to make sure to get the values of all the specified attributes, you can instead get a full list of attributes using the face-attribute-name-alist variable, retrieve the value of each (if present) from my-font-spec, and then apply them to some-face:
(let (props)
(mapcar #'(lambda (attrval)
(let* ((attr (car attrval))
(prop (font-get my-font-spec attr)))
(if prop
(progn (push prop props)
(push attr props))))) face-attribute-name-alist)
(apply 'set-face-attribute some-face nil props))

Which lisp implementations allow me to modify code at runtime?

Lisp is homoiconic, meaning code can be treated as data. Which implementations allow me to do so at runtime? The following is an example of what I mean, in pseudocode:
(defun (my-func)
(display "foo ")
(display "bar ")
(display "baz "))
(defun (main-loop)
(my-func)
(swap (first my-func) (second my-func))
(main-loop))
That should repeatedly output "foo bar baz bar foo baz ".
This is probably not the most elegant approach, but in common Lisp you can do something like this:
> (setq f '(defun foo () (princ "foo ") (princ "bar ") (princ "baz ")))
(DEFUN FOO NIL (PRINC "foo ") (PRINC "bar ") (PRINC "baz "))
> (eval f)
FOO
> (foo)
foo bar baz
NIL
> (defun frot ()
; Call foo (stored in f)
(funcall (eval f))
; Swap the 1st and 2nd statements in foo
(setf tmp (cadddr f))
(setf (cadddr f) (cadr (cdddr f)))
(setf (cadr (cdddr f)) tmp)))
FROT
> (frot)
foo bar baz
(PRINC "foo ")
> (frot)
bar foo baz
(PRINC "bar ")
> (frot)
foo bar baz
(PRINC "foo ")
This stores a Lisp function in f rather than executing it in situ, but it does illustrate the fact that a Lisp program is itself a Lisp data structure than can be dynamically manipulated and executed.
The other answers cover the question well.
From a practical level however if you are using Common Lisp and Slime and want to be able to compile code into your running program from Emacs you will need to tell Swank to update from inside your loop.
Add the following to your code and then add (update-swank) inside your loop.
(defmacro continuable (&body body)
`(restart-case
(progn ,#body)
(continue () :report "Just Continue")))
(defun update-swank ()
"Called from within the main loop, this keep the lisp repl working"
(continuable
(let ((connection (or swank::*emacs-connection*
(swank::default-connection))))
(when connection
(swank::handle-requests connection t)))))
This is one way to use the fact you can recompile live with your editor as in this video (sorry for plugging my own vid).
Another way (again with Slime) is to tell it to use a different thread for the communication. I prefer the former method however as opengl is very unstable when used across threads.
[More Details]
The continuable macro in the code above catches any error and gives you the option to ignore it and continue. I find this really helpful and I often make mistakes in the repl and I don't want to 'abort' from an error as this would abort my main loop.
If you are modifying code as you describe, then you know something about the structure of the code. Since you know the structure of the code, you can parameterize that structure
(define (foo-er foo bar baz)
(lambda ()
(display foo)
(display bar)
(display baz)))
Then you can do the swapping by explicitly passing your arguments as:
(define (main-loop)
(let looping ((foo "foo ") (bar "bar ") (baz "baz "))
((foo-er foo bar baz))
(looping bar foo baz)))
> (main-loop)
foo bar baz bar foo baz foo bar baz ...
The CommonLisp version is analogous.
If you need to keep my-func around:
(define my-func #f)
(define (main-loop)
(let looping ((foo "foo ") (bar "bar ") (baz "baz "))
(set! my-func (foo-er foo bar baz)
(my-func)
(looping bar foo baz)))

Why colons precede variables in Common Lisp

What does the syntax, colons preceding variable in Common Lisp, mean? I've seen programs with such, and I'll present some sample code here, out of a large set of functions.
(defun expand (successorf node)
(mapcar (lambda (action-state-cost)
(let ((action (car action-state-cost))
(state (cadr action-state-cost))
(cost (caddr action-state-cost)))
(make-node :state state :parent node
:action action :path-cost (+ (node-path-cost node) cost)
:depth (1+ (node-depth node)))
))
(funcall successorf (node-state node))
))
Keyword Symbols
:foo is a keyword symbol.
interned in and exported from the KEYWORD package
constantly bound to itself
Usage
Keyword symbols are used when one needs the combination of the following properties:
a symbol is the right data structure
symbols with the same name should be unique (by interning them in a package) -> package KEYWORD
different packages are not needed or wanted -> package KEYWORD
writing the symbol should be easy by not needing to quote them -> :foo better than ':foo
the ability to act as a variable with different values is not needed -> :foo evaluates to :foo itself and only to :foo
In Common Lisp generally symbols can be in a package (kind of a namespace).
An unexported symbol bar in a package foo is written as foo::bar. The double colon is between the package name and the symbol name.
An exported symbol then is written as foo:bar. A single colon is used.
If the symbol is available in the current package then is written as bar without the package.
The package KEYWORD
There is a special package called KEYWORD. A symbol bar in that package is simply and always written as :bar.
Examples
These keyword symbols have also these interesting properties: the symbols are automatically exported from the package KEYWORD (so keyword::bar, keyword:bar, ::bar and :bar are all the same symbol) and they evaluate to themselves:
CL-USER 5 > :bar
:BAR
CL-USER 6 > (describe :bar)
:BAR is a SYMBOL
NAME "BAR"
VALUE :BAR
FUNCTION #<unbound function>
PLIST NIL
PACKAGE #<The KEYWORD package, 0/4 internal, 5830/8192 external>
CL-USER 7 > (eq 'keyword::bar ':bar)
T
CL-USER 8 > (eq :bar ':bar) ; quoted or unquoted, each subform evaluates to :bar
T
Usage
Keyword symbols are used for example as names in named arguments:
(defun foo (&key bar) (+ bar 10))
(foo :bar 7)
Typically they are also used in arguments to instance and structure construction.
(defstruct node state parent action)
DEFSTRUCT is a Common Lisp macro and it generates several functions. One of them is a function MAKE-NODE, which can be used as:
(make-node :state 'open
:parent some-parent
:action an-action)
Note: sometimes the data might also be a keyword. For example in above form, the state might be :open and not open:
(make-node :state :open
:parent some-parent
:action an-action)
They're not variables, actually; those are keywords. They're a special kind of efficient token, similar to “atoms” in other languages. It's a convenient, built-in way to pass named (and, almost always, optional) parameters into a function call.
http://www.gigamonkeys.com/book/functions.html describes the syntax of function calls.

Emacs ruby-mode indentation behavior

class Foo
attr_accessor :a,
:time, # ms since epoch
:b,
:c
end
In text mode, the variables listed after 'a' would indent as written above, but in ruby mode they would instead be flush with 'attr_accessor'. How can I get ruby mode to indent like text mode in this situation? Note that I'd like to be able to select the whole file and hit c-m-\ to get the above indentation in addition to all the other ruby-mode.el indentation rules.
This hack should work in the majority of cases.
(defadvice ruby-indent-line (after line-up-args activate)
(let (indent prev-indent arg-indent)
(save-excursion
(back-to-indentation)
(when (zerop (car (syntax-ppss)))
(setq indent (current-column))
(skip-chars-backward " \t\n")
(when (eq ?, (char-before))
(ruby-backward-sexp)
(back-to-indentation)
(setq prev-indent (current-column))
(skip-syntax-forward "w_.")
(skip-chars-forward " ")
(setq arg-indent (current-column)))))
(when prev-indent
(let ((offset (- (current-column) indent)))
(cond ((< indent prev-indent)
(indent-line-to prev-indent))
((= indent prev-indent)
(indent-line-to arg-indent)))
(when (> offset 0) (forward-char offset))))))
Example:
class Comment < ActiveRecord::Base
after_create :send_email_to_author,
:if => :author_wants_emails?,
:unless => Proc.new { |comment| comment.post.ignore_comments? }
end
From Remi (in comments):
Note that Emacs will correctly indent class Foo attr_accessor(:a, :time, # ms since epoch :b, :c) end – Rémi Dec 11 '10 at 8:50
You can add parens and have it indent properly -- I'm adding this here because I'm looking for unanswered questions, and this one comes up (incorrectly, since it has been answered in the comments).
When using Emacs 24.4 or newer, your example will be indented like this by default.

Resources