JRuby Small Memos

1
$ jruby --version
1
2
$ jruby -e "puts 'This is a short program'"
This is a short program
1
2
3
4
5
6
$ jirb
irb(main):001:0> ['Hello', 'world'].join ' '
=> "Hello world"
irb(main):002:0> "ybuRJ morf".reverse
=> ufrom JRuby"
irb(main):003:0>

Ease Life With YASnippet

安装使用package-install,实际上可以写一个简易方法避免重复劳动:

1
2
3
4
5
6
(defun require-package (package)
  "Install given PACKAGE."
  (unless (package-installed-p package)
    (unless (assoc package package-archive-contents)
      (package-refresh-contents))
    (package-install package)))

学习下其中的1个function

assoc is a built-in function in `C source code’.

1
(assoc KEY LIST)

Return non-nil if KEY is `equal’ to the car of an element of LIST. The value is actually the first element of LIST whose car equals KEY.

开始学习如何使用YASnippet。

1 组织你的 Snippets (Organizing Snippets)

Snippet的定义是储存在文件系统的文件中。YASnippet的触发机制会找到这些snippet tables,然后展开。

首先,新建一个目录:my-snippets,用来存放自定义的snippets。

1
2
3
4
5
(require 'yasnippet)

(setq yas-snippet-dirs (concat user-emacs-directory "my-snippets"))

(add-hook 'prog-mode-hook 'yas-minor-mode)

看下是怎么组织snippets的(这是YASnippet自带的):

.yas.parent文件可以共享其他目录下的snippets。

如果有一个空的.yas-make-groups文件,会在 YASnippet Menu按照目录结构组织地更清晰。

2 展开你的 Snippets (Traiggering expansion)

很多中方式能展开snippets,包括:

  • By typing an abbrev, the snippet trigger key, and then pressing the key defined in yas/trigger-key (which defaults to “TAB”). This works in buffers where the minor mode yas/minor-mode is active;

  • By invoking the command yas/insert-snippet (either by typing M-x yas/insert-snippet or its keybinding). This does not require yas/minor-mode to be active.

  • By using hippie-expand

以上是3中最常见的方法(虽然我不知道什么是 hippie-expand)。

Macro & Defmacro in Emacs

学习下Lisp的宏(macro)。

首先,区别:Lisp宏和键盘宏(keyboard macro)是两个不同的概念。

一个LISP宏(Lisp Macro)是一个扩展LISP语言的用户定义的结构. 宏不像函数那样对参数执行表达式. 它们只是在构造一个包括这些参数的表达式.

也就是,宏是一个结构,是在构造。就是Lisp非常牛逼的一点:Code as data。

首先看下语法定义:

defmacro is a Lisp macro in `byte-run.el’.

1
(defmacro NAME ARGLIST &optional DOCSTRING DECL &rest BODY)

Define NAME as a macro. When the macro is called, as in (NAME ARGS…), the function (lambda ARGLIST BODY…) is applied to the list ARGS… as it appears in the expression, and the result should be a form to be evaluated instead of the original. DECL is a declaration, optional, of the form (declare DECLS…) where DECLS is a list of elements of the form (PROP . VALUES). These are interpreted according to `macro-declarations-alist’. The return value is undefined.

好长的解释。

看一个实例:

1
2
(defmacro inc (var)
  (list 'setq var (list '1+ var)))

注意一点:(list '1+ var) 开始时写成(list '1+var),少写了一个空格。

定义了一个Lisp宏:inc (var)。这个macro的BODY是(按照list函数拼出来):

1
(setq var (1+ var))

当然也可以这样展开宏:

1
(macroexpand '(inc x))

现在就可以用宏了:

1
2
(setq x 1)
(inc x)

解释:

list 的用法

1
2
3
4
5
6
list is a built-in function in `C source code'.

(list &rest OBJECTS)

Return a newly created list with specified arguments as elements.
Any number of arguments, even zero arguments, are allowed.

宏还有一种写法,就是使用反引用(Backquote)。

我们可以用 ‘ 引用一个对象并不执行.我们还可以用 反引用 ` 引用一个列表, 但是只是选择性的执行列表的元素.

A Growing Emacser


when: when is a lisp macro

1
(when COND BODY...)

If COND yields non-nil, do BODY, else return nil. When COND yields non-nil, eval BODY forms sequentially and return value of last one, or nil if there are none.


fboundp is a built-in function in `C source code’.

1
(fboundp SYMBOL)

add-to-list is a compiled Lisp function in `subr.el’.

1
(add-to-list LIST-VAR ELEMENT &optional APPEND COMPARE-FN)

Add ELEMENT to the value of LIST-VAR if it isn’t there yet. The test for presence of ELEMENT is done with equal, or with COMPARE-FN if that’s non-nil. If ELEMENT is added, it is added at the beginning of the list, unless the optional argument APPEND is non-nil, in which case ELEMENT is added at the end.

The return value is the new value of LIST-VAR.


provide is a built-in function in `C source code’.

1
(provide FEATURE &optional SUBFEATURES)

Announce that FEATURE is a feature of the current Emacs. The optional argument SUBFEATURES should be a list of symbols listing particular subfeatures supported in this version of FEATURE.


C-x h runs the command mark-whole-buffer

C-w runs the command kill region


use C-x <right>, C-x <left> to cycle around in the buffer ring.

iswitchb-mode replaces the default C-x b behaviour with a very intuitive buffer-switching-with-completion system.

The related commands are C-x b, C-s and C-r.


Dired Mode 非常别扭,很多无用的快捷键。

emacs dired (Directory Editor)mode.

C-x d: enter dired mode(use M-x RET dired RET is quick too)

C-x 4 d: dired-other-window

C-x C-j: (dired-jump to current file)

q: quit

R to rename the file (or ‘dired-do-rename’).

C-x k RET to go back to the (renamed) buffer


A Example of Writing Exception in Java

记录在阅读 Jasig Cas 的源码学习到的 Java 知识。

1
public abstract class AuthenticationException extends Exception {

首先,这是一个 abstract class.

1
2
3
4
5
6
7
8
9
10
11
/** The code to return for resolving to a message description. */
private String code;

/**
 * Method to return the unique identifier for this error type.
 *
 * @return the String identifier for this error type.
 */
public final String getCode() {
    return this.code;
}

使用 code,来解析异常消息的描述。 并且,code 有一个 get 方法,final 不可继承。

1
2
3
4
5
6
7
8
9
10
11
/** The error type that provides additional info about the nature of the exception cause **/
private String type = "error";

/**
 * Method to return the error type of this exception
 *
 * @return the String identifier for the cause of this error.
 */
public final String getType() {
    return this.type;
}

额外的一个 field: type,维护导致异常的本质信息。

下面是 AuthenticationException 的 constructors。

1
2
3
public AuthenticationException(final String code) {
    this.code = code;
}

这是第1个 constructor。

1
2
3
4
5
6
7
8
9
10
public AuthenticationException(final String code, final String msg) {
    super(msg);
    this.code = code;
}

public AuthenticationException(final String code, final String msg, final String type) {
    super(msg);
    this.code = code;
    this.type = type;
}

第2个和第3个 constructor,需要学习的是 super(msg)

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Constructor that takes a code description of the error and the chained
 * exception. These codes normally have a corresponding entries in the
 * messages file for the internationalization of error messages.
 *
 * @param code The short unique identifier for this error.
 * @param throwable The chained exception for this AuthenticationException
 */
public AuthenticationException(final String code, final Throwable throwable) {
    super(throwable);
    this.code = code;
}

最后一个 constructor,需要学习的是 final Throwable throwable,这块不是很懂。按描述是能链式异常。 查看了 Java Exception 文档,它有一个 constructor:

1
public Exception(Throwable cause)

它的作用是:用指定的 cause 和 详细的 message(cause==null ? null : cause.toString())构造新的异常。 它的作用就是一个 “wrapper”。

完整源码见:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jasig.cas.authentication.handler;

/**
 * The most generic type of authentication exception that one can catch if not
 * sure what specific implementation will be thrown. Top of the tree of all
 * other AuthenticationExceptions.
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 3.0
 */
public abstract class AuthenticationException extends Exception {

    /** Serializable ID. */
    private static final long serialVersionUID = 3906648604830611762L;

    /** The code to return for resolving to a message description. */
    private String code;

    /** The error type that provides additional info about the nature of the exception cause **/
    private String type = "error";

    /**
     * Constructor that takes a code description of the error. These codes
     * normally have a corresponding entries in the messages file for the
     * internationalization of error messages.
     *
     * @param code The short unique identifier for this error.
     */
    public AuthenticationException(final String code) {
        this.code = code;
    }

    /**
     * Constructor that takes a <code>code</code> description of the error along with the exception
     * <code>msg</code> generally for logging purposes. These codes normally have a corresponding
     * entries in the messages file for the internationalization of error messages.
     *
     * @param code The short unique identifier for this error.
     * @param msg The error message associated with this exception for additional logging purposes.
     */
    public AuthenticationException(final String code, final String msg) {
        super(msg);
        this.code = code;
    }

    /**
     * Constructor that takes a <code>code</code> description of the error along with the exception
     * <code>msg</code> generally for logging purposes and the <code>type</code> of the error that originally caused the exception.
     * These codes normally have a corresponding entries in the messages file for the internationalization of error messages.
     *
     * @param code The short unique identifier for this error.
     * @param msg The error message associated with this exception for additional logging purposes.
     * @param type The type of the error message that caused the exception to be thrown. By default,
     * all errors are considered of <code>error</code>.
     */
    public AuthenticationException(final String code, final String msg, final String type) {
        super(msg);
        this.code = code;
        this.type = type;
    }

    /**
     * Constructor that takes a code description of the error and the chained
     * exception. These codes normally have a corresponding entries in the
     * messages file for the internationalization of error messages.
     *
     * @param code The short unique identifier for this error.
     * @param throwable The chained exception for this AuthenticationException
     */
    public AuthenticationException(final String code, final Throwable throwable) {
        super(throwable);
        this.code = code;
    }

    /**
     * Method to return the error type of this exception
     *
     * @return the String identifier for the cause of this error.
     */
    public final String getType() {
        return this.type;
    }

    /**
     * Method to return the unique identifier for this error type.
     *
     * @return the String identifier for this error type.
     */
    public final String getCode() {
        return this.code;
    }

    @Override
    public final String toString() {
        String msg = getCode();
        if (getMessage() != null && getMessage().trim().length() > 0)
            msg = ":" + getMessage();
        return msg;
    }

}