names-20151201.0/ 0000755 0001752 0001753 00000000000 12627326524 011652 5 ustar elpa elpa names-20151201.0/TheNittyGritty.org 0000644 0001752 0001753 00000012645 12540755212 015340 0 ustar elpa elpa * The Nitty Gritty
In general, =define-namespace= should work as you expect it to. But if you
need to understand why something is or isn't being namespaced, here's
the nitty gritty of how it happens.
** Quoted Lists
Quoted lists (be it with =quote= or =function=) are namespaced *only*
of the list is a =lambda= form (or a =macro= form). Arbitrary lists
are returned untouched (they are way too arbitrary to be handled
sanely). That is:
#+begin_src emacs-lisp
(define-namespace foo-
(defun infinite (y)
(mapcar
'(lambda (x) (infinite x))
'(not a lambda (infinite x))))
)
#+end_src
expands to
#+begin_src emacs-lisp
(defun foo-infinite (y)
(mapcar
'(lambda (x) (foo-infinite x))
'(not a lambda (infinite x))))
#+end_src
Note that = '(lambda ...)= is bad practice in Emacs, you should use
=(lambda ...)= instead (which is also namespaced just fine).
** Symbols Quoted with Quote
A symbol quoted with =quote= (or = ' =) is never namespaced.
#+begin_src emacs-lisp
(define-namespace foo-
(defvar var nil)
(defvaralias 'varalias 'var)
(defun fun nil)
(defalias 'alias 'fun)
(defalias 'otheralias 'var)
)
#+end_src
expands to
#+begin_src emacs-lisp
(defvar foo-var nil)
(defvaralias 'varalias 'var)
(defun foo-fun nil)
(defalias 'alias 'fun)
;;; foo-var is not a function, so:
(defalias 'otheralias 'var)
#+end_src
If you provide the =:assume-var-quote= keyword, quoted symbols will be
namespaced as variables instead.
** Symbols Quoted with Function
A symbol quoted with =function= (or =#' =) is assumed to be the name of a
function, and will be namespaced as such if possible. You may provide
the =:dont-assume-function-quote= keyword to disable this behaviour,
=function= will then be treated like =quote=.
#+begin_src emacs-lisp
(define-namespace foo-
(defun fun (x) x)
(mapcar 'fun somelist)
(mapcar #'fun somelist)
)
#+end_src
expands to
#+begin_src emacs-lisp
(defun foo-fun (x) x)
(mapcar 'fun somelist)
(mapcar #'foo-fun somelist)
#+end_src
** Backticks (quasi-quotes)
Backticks (or =`=) are handled as you would expect. Lists or simbles
quoted with a backtick are treated the same as those quoted with
regular quotes ([[#quoted-lists][see above]]), except anything prefixed by a comma (which
is effectively not quoted) is namespaced as usual.
** Local Variables Take Precedence
Local variables take precedence over namespace variables.
For instance
#+begin_src emacs-lisp
(define-namespace foo-
(defvar bar "2")
(defun funca (bar)
(string-to-int bar))
)
#+end_src
expands to
#+begin_src emacs-lisp
(defvar foo-bar "2")
(defun funca (bar)
(string-to-int bar))
#+end_src
Note how the last =bar= isn't namespaced. That's because it is local
to the =funca= function, and takes precedence over the global
=foo-bar=. The argument list of functions, macros, and lambdas are
all local definitions.
By default, this does not happen with let bindings, they are
namespaced as usual (if the variable name in question has a global
definition). The reason is that let bindings are commonly used to
temporarily override global bindings.
You can customize this behaviour with the =:no-let-vars= keyword.
Then:
#+begin_src emacs-lisp
(define-namespace foo- :no-let-vars
(defvar bar "2")
(let ((bar "1"))
(string-to-int bar))
)
#+end_src
will expand to
#+begin_src emacs-lisp
(defvar foo-bar "2")
(let ((bar "1"))
(string-to-int bar))
#+end_src
** Macros
Macros are handled in a very intelligent manner.
*Names* needs to know which parts of a macro's arguments are
evaluatable forms, and which are just arbitrary symbols. This presents
a challenge because macro arguments could be absolutely anything.
Fortunately, (good) macros already provide that information in their
=debug= declaration.
Thus, *Names* uses the macro's =edebug-spec-list= to find out which
arguments are evaluatable forms, and namespaces only those. Other
arguments are left untouched. Usually, this is not something you'll
need to worry about, it should just do what you expect from it.
This is only relevant if you write your own macros. If you do,
remember to add a debug declaration in them.
*** The theading macros (~->~ and ~-->~)
The threading macros would require special treatment to namespace
correctly. However, you can use the ~:functionlike-macros~ keyword to
tell *Names* to treat them as regular functions.
For example, in the following snippet:
#+BEGIN_SRC emacs-lisp
(require 'dash)
(define-namespace foo-
:functionlike-macros (-> ->>)
(defvar var nil)
(defun fun (x &optional y)
(concat x y))
(-> "some string"
(fun var)
fun)
)
#+END_SRC
the ~(fun var)~ part would be namespaced prefectly fine (~fun~ and
~var~ will be identified as a function and variable respectively),
because it looks like a regular function call. However, the second use
of ~fun~ will not be correctly namespaced, because that ~fun~ looks
like a variable.
In other words, you should use these macros like this instead:
#+BEGIN_SRC emacs-lisp
(-> "some string"
(fun var)
(fun))
#+END_SRC
** Accessing Global Symbols
If one of your definitions shadows a global definition, you can still
access it by prefixing it with =::=.
#+begin_src emacs-lisp
(define-namespace foo-
(defun message ()
(message)
(::message "Hi"))
)
#+end_src
expands to
#+begin_src emacs-lisp
(defun foo-message ()
(foo-message)
(message "Hi"))
#+end_src
When in doubt feel free to use =::=, it will always get removed (as
long as it's not inside a =quote=). You may also change this prefix to
something else with the =:prefix= keyword.
names-20151201.0/Other-Packages.org 0000644 0001752 0001753 00000002556 12432073042 015154 0 ustar elpa elpa * Other Packages
*Names* isn't the first package to try patching up namespaces in
Emacs. Here we link to descriptions and provide short comparisons of
previous packages attempting similar things.
** [[https://github.com/Wilfred/with-namespace.el][with-namespace]]
The closest to *Names* in terms of ideology. It performs simple
namespacing of symbols inside =defun= forms and alike.
The difference is that *Names* performs intelligent namespacing (it
understand which symbols are vars, which are functions, and which are
not fit for namespacing) and applies to any form under the sun.
** [[https://github.com/sigma/codex][Codex]]
A robust and somewhat similar option. Notable differences are that
*Names* does have edebug integration (which greatly facilitates actual
development) and is generally more focused on being practical (write
code as you would, just without the prefix).
** [[https://github.com/skeeto/elisp-fakespace/][Fakespace]]
Focuses on the global obarray clobbering, not on code clobbering. It
uninterns defined symbols, while *Names* actually simplifies the code
that you write.
** [[https://github.com/chrisbarrett/elisp-namespaces][elisp-namespaces]]
Possibly the safest and faciest of the bunch. It's a great way to
avoid clobbering the global obarray if you're willing to use its
syntax. Like above, the difference it that *Names* actually simplifies
that you type.
names-20151201.0/names-pkg.el 0000644 0001752 0001753 00000000414 12627326524 014055 0 ustar elpa elpa ;; Generated package description from names.el
(define-package "names" "20151201.0" "Namespaces for emacs-lisp. Avoid name clobbering without hiding symbols." '((emacs "24.1") (cl-lib "0.5")) :url "https://github.com/Malabarba/names" :keywords '("extensions" "lisp"))
names-20151201.0/names-dev.el 0000644 0001752 0001753 00000022165 12627325723 014061 0 ustar elpa elpa ;;; names-dev.el --- Developer Functions to facilitate use of names.el with your package.
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Prefix: names
;; Separator: -
;;; Commentary:
;;
;; This package has some convenient functions for developers working
;; with names.el.
;; This package is installed along with names.el, but to use its
;; features you must require it explicitly:
;;
;; (require 'names-dev)
;;; License:
;;
;; This file is part of GNU Emacs.
;;
;; GNU Emacs 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.
;;
;; GNU Emacs 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 GNU Emacs. If not, see .
;;; Code:
(require 'names)
(require 'elisp-mode nil t)
(require 'lisp-mode nil t)
;;; ---------------------------------------------------------------
;;; Developer Utility Functions
(defmacro names-compare-forms (name form-a form-b)
"Test if (namespace NAME FORM-A) is the same as FORM-B."
(declare (indent (lambda (&rest x) 0))
(debug (symbolp sexp form)))
`(equal
(macroexpand-all '(define-namespace ,name :global :verbose ,form-a))
(macroexpand-all ',form-b)))
(defmacro names-compare-forms-assert (name form-a form-b)
"Assert if (namespace NAME FORM-A) is the same as FORM-B."
(declare (indent (lambda (&rest x) 0))
(debug (symbolp sexp form)))
(cl-assert
(names-compare-forms name form-a form-b)
t))
(defmacro names-print (name &rest forms)
"Return the expanded results of (namespace NAME :global :verbose FORMS).
Ideal for determining why a specific form isn't being parsed
correctly. You may need to set `eval-expression-print-level' and
`eval-expression-print-length' to nil in order to see your full
expansion."
(declare (indent (lambda (&rest x) 0)) (debug 0))
`(define-namespace ,name :global :verbose ,@forms))
(defvar names-font-lock
'(("^:autoload\\_>" 0 'font-lock-warning-face prepend)
("(\\(\\_\\)[\t \n]+\\([^\t \n]+\\)"
(1 'font-lock-keyword-face)
(2 'font-lock-variable-name-face))))
(when (boundp 'lisp-el-font-lock-keywords-2)
(setq lisp-el-font-lock-keywords-2
(append names-font-lock
lisp-el-font-lock-keywords-2)))
;;; The backbone
(defun names--looking-at-namespace ()
"Non-nil if point is at a `define-namespace' form or an alias to it."
(when (looking-at "(\\_<")
(save-excursion
(forward-char 1)
(ignore-errors
(equal (indirect-function (intern (thing-at-point 'symbol)))
(indirect-function 'define-namespace))))))
(defun names--generate-new-buffer (name &optional form)
"Generate and return a new buffer.
NAME is current namespace name.
If FORM is provided, also try to use it to decide an informative
buffer name."
(get-buffer-create
(concat
" *names "
(format "%s %s"
(or (car-safe form) (random 10000))
(or (car-safe (cdr-safe form)) (random 10000)))
"*")))
(defmacro names--wrapped-in-namespace (command form &optional kill &rest body)
"Call COMMAND, except in a namespace.
In a namespace, expand FORM in a separate buffer then execute
BODY. If BODY is nil, call COMMAND instead.
If KILL is non-nil, kill the temp buffer afterwards."
(declare (indent defun)
(debug (sexp form form body)))
;; Get the namespace, if we're in one.
`(let ((evaled-form ,form)
(invocation
',(if (commandp command t)
`(call-interactively #',command)
command))
(entire-namespace
(save-excursion
(when (names--top-of-namespace)
(cdr (read (current-buffer))))))
b keylist spec name expanded-form)
;; If we're not in a namespace, call the regular `eval-defun'.
(if (null entire-namespace)
(eval invocation)
;; If we are, expand the function in a temp buffer
(setq name (pop entire-namespace))
(while (setq spec (names--next-keyword entire-namespace))
(setq keylist (append keylist spec)))
;; Prepare the (possibly) temporary buffer.
(setq b (names--generate-new-buffer name evaled-form))
(unwind-protect
(with-current-buffer b
(cl-letf (((symbol-function #'message) #'ignore))
(erase-buffer)
(emacs-lisp-mode)
;; Print everything inside the `progn'.
(mapc
(lambda (it) (pp it (current-buffer)))
(cdr
(setq expanded-form
(macroexpand
`(define-namespace ,name :global :clean-output ,@keylist ,evaled-form)))))
(when (fboundp 'font-lock-ensure)
(font-lock-ensure)))
;; Return value
,@(or body '((eval invocation))))
;; Kill the buffer if we won't need it.
(when (and ,kill (buffer-live-p b))
(kill-buffer b))))))
(defun names--top-of-namespace ()
"Move to the top of current namespace, and return non-nil.
If not inside a namespace, return nil and don't move point."
(let ((top (save-excursion
(beginning-of-defun)
(ignore-errors
(backward-up-list))
(when (names--looking-at-namespace)
(point)))))
(when top
(goto-char top)
t)))
(defun names-eval-defun (edebug-it)
"Identical to `eval-defun', except it works for forms inside namespaces.
Argument EDEBUG-IT is the same as `eval-defun', causes the form
to be edebugged."
(interactive "P")
(require 'font-lock) ; just in case
(let ((form
(save-excursion
(end-of-defun)
(beginning-of-defun)
(read (current-buffer)))))
(names--wrapped-in-namespace
eval-defun form (null edebug-it))))
;;; eval-last-sexp
(defalias 'names--preceding-sexp-original
(if (fboundp 'elisp--preceding-sexp)
(symbol-function 'elisp--preceding-sexp)
(symbol-function 'preceding-sexp)))
(defun names--preceding-sexp ()
"Like `elisp--preceding-sexp', but expand namespaces."
(names--wrapped-in-namespace
(names--preceding-sexp-original) (names--preceding-sexp-original) t
expanded-form))
(defun names-eval-last-sexp (eval-last-sexp-arg-internal)
"Identical to `eval-last-sexp', except it works for forms inside namespaces.
Argument EVAL-LAST-SEXP-ARG-INTERNAL is the same as `eval-last-sexp'."
(interactive "P")
(cl-letf (((symbol-function 'elisp--preceding-sexp) #'names--preceding-sexp)
((symbol-function 'preceding-sexp) #'names--preceding-sexp))
(eval-last-sexp eval-last-sexp-arg-internal)))
(defun names-eval-print-last-sexp (eval-last-sexp-arg-internal)
"Identical to `eval-print-last-sexp', except it works for forms inside namespaces.
Argument EVAL-LAST-SEXP-ARG-INTERNAL is the same as `eval-print-last-sexp'."
(interactive "P")
(cl-letf (((symbol-function 'elisp--preceding-sexp) #'names--preceding-sexp)
((symbol-function 'preceding-sexp) #'names--preceding-sexp))
(eval-print-last-sexp eval-last-sexp-arg-internal)))
;; (pp (symbol-function 'names--preceding-sexp-original) (current-buffer))
(defun names-pprint ()
"Pretty-print an expansion of the namespace around point."
(interactive)
(save-excursion
(when (names--top-of-namespace)
(let ((ns (cdr (read (current-buffer)))))
(pp-macroexpand-expression
(macroexpand (cons 'names-print ns)))))))
;;; Find stuff
(require 'find-func nil t)
(defalias 'names--fboundp-original (symbol-function 'fboundp))
(defalias 'names--boundp-original (symbol-function 'boundp))
(defalias 'names--find-function-read-original (symbol-function 'find-function-read))
(defalias 'find-function-read 'names--find-function-read)
(defun names--find-function-read (&optional type)
"Identical to `find-function-read', except it works inside namespaces."
(let ((buf (current-buffer)))
(names--wrapped-in-namespace
(names--find-function-read-original type) nil t
(set-buffer buf)
(let ((names--name name))
(cl-letf (((symbol-function 'fboundp) #'names--dev-fboundp)
((symbol-function 'boundp) #'names--dev-boundp))
(names--find-function-read-original type))))))
(defun names--dev-fboundp (sym)
(or (names--fboundp-original sym)
(names--fboundp-original (names--prepend sym))))
(defun names--dev-boundp (sym)
(or (names--boundp-original sym)
(names--boundp-original (names--prepend sym))))
;;; The keys
(eval-after-load 'lisp-mode
'(let ((map emacs-lisp-mode-map))
(define-key map [remap eval-defun] #'names-eval-defun)
(define-key map [remap eval-last-sexp] #'names-eval-last-sexp)
(define-key map [remap eval-print-last-sexp] #'names-eval-print-last-sexp)))
(provide 'names-dev)
;;; names-dev.el ends here
names-20151201.0/ChangeLog 0000644 0001752 0001753 00000002671 12627326471 013433 0 ustar elpa elpa 2015-12-01 Artur Malabarba
Merge commit '85b3fbe091aba2d9dc581894a02f60acd46f4413'
2015-10-14 Artur Malabarba
Merge commit 'd16c20ffc2197234d4dd631fd66768c3a4b305c9'
2015-07-23 Artur Malabarba
Merge commit 'e2737d0adb7f8d8f79c2ca0fee5b13b6f8ae164b'
2015-06-18 Artur Malabarba
Merge commit 'b1da26d96cbe8308d0988f6b92737819f98f20fd'
2015-04-26 Stefan Monnier
* names/names.el: Use lexical-binding. Silence compiler warnings.
2015-01-14 Artur Malabarba
Merge commit '8b9dd3e5803fd02b03a7f2a8bb6cb51df7f2f7bf'
2015-01-13 Artur Malabarba
Merge commit '68cc63682a66513c0968352f15e9b37fd245e636'
2015-01-12 Artur Malabarba
Merge commit 'dea0ba6347f2eb5be310826e7917effb73e1e600'
2014-12-13 Artur Malabarba
Merge commit 'a11ba779f588af28f93fd4b7a716849695d5d9f3'
2014-11-18 Artur Malabarba
Merge commit 'ed44aa9bcebcc055551a2d018db9080ee0e9866f'
2014-11-15 Artur Malabarba
Add 'packages/names/' from commit
'b7bb062fc3c5de0c5bdb6dcf60da260d2a169783'
git-subtree-dir: packages/names git-subtree-mainline:
4c7d97da50790da208f87ddc6ed8112abe130ea9 git-subtree-split:
b7bb062fc3c5de0c5bdb6dcf60da260d2a169783
names-20151201.0/Readme.org 0000644 0001752 0001753 00000013163 12443007243 013552 0 ustar elpa elpa #+OPTIONS: toc:nil num:nil
* Names [[https://travis-ci.org/Bruce-Connor/names?branch=master][https://secure.travis-ci.org/Bruce-Connor/names.png?branch=master]]
*Names* is designed as a practical, complete, robust, and debuggable
tool which writes your namespaces for you.
It is part of Emacs and is available trough [[https://elpa.gnu.org/packages/names.html][GNU Elpa]], so every
Emacs user running at least 24.1 has access to it.
[[file:package-example.png]]\\
/Example usage of Names to namespace an emacs-lisp function./
*** A Namespace implementation for Emacs-Lisp
The *Names* package aims to provide an implementation of
namespaces in Emacs with four guiding principles:
- Practical :: Actually useful and easy to grasp.
- Complete :: Support any macro, function, or special-form available in
emacs-lisp, /even/ the ones defined by you or a third
party.
- Robust :: No-surprises, well-tested, and with clearly stated
limitations.
- Debuggable :: Support *edebug* and =eval-defun=, and any other
package developing tools.
See [[https://github.com/Bruce-Connor/spaces#why-a-namespace-package][Why a namespace package?]] for a description on why this is
necessary, and see [[https://github.com/Bruce-Connor/emacs-lisp-namespaces/blob/master/Other-Packages.org][Other-Packages.org]] for a description and comparison
of previous packages attempting similar things.
**** Version Compatibility
Currently, *Names* is being supported on the entire Emacs 24 family
(24.1--24.4). Any new changes or pull requests are tested on a
[[https://travis-ci.org/Bruce-Connor/names][Travis-CI machine]]. See the /“tests”/ subdirectory for our test suite,
and see .
** Usage
The [[https://github.com/Bruce-Connor/emacs-lisp-namespaces/blob/master/UsageExample.org][UsageExample]] file clearly displays and explains how to use *Names*
in your package. There are few simple measures to take. Go have a look
if you’re interested, I promise it’s worth it!
If you want deeper descriptions of use-cases, see [[https://github.com/Bruce-Connor/emacs-lisp-namespaces/blob/master/TheNittyGritty.org][TheNittyGritty.org]].
** Developer Tools
*Names* offers a series of tools to make package writing more
convenient inside a namespace. These developer facilities are on this
separate file, so the file isn't loaded on the user's computer when
your package calls =(require 'names)=.
To access them add the following line to your init file.
#+begin_src emacs-lisp
(require 'names-dev)
#+end_src
*** Edebug and eval-defun support
First and foremost, the =edebug-eval-defun= command (bound to =C-u
C-M-x=) is an essential tool for any package developer. *Names*
wouldn't be a very useful utility if it prevented you from using this
asset.
Therefore, it provides the =names-eval-defun= command, which is
identical to =edebug-eval-defun= except it also works inside
namespaces. It will automatically be added to your
=emacs-lisp-mode-map=.
*** Font-locking
Font-lock for =define-namespace= and =:autoload=.
*** Expansion and comparison functions
=names-compare-forms= and =names-print= offer information when
something just doesn't seem to make sense.
** Nomenclature
The name of this package is *Names*, always with a capital “N”.
Despite the word being plural, refer to it in the singular (e.g.,
“Names is an amazing achievement”). If possible consider giving it a
slight emphasis, such as: /Names/.
When there's a risk of confusion or ambiguity, be it due to context or
lack of knowledge by the reader, =names.el= is also acceptable.
** Why a namespace package?
Plain and simple: Emacs doesn't have namespaces, and it needs them.
Nic Ferrier has a [[http://nic.ferrier.me.uk/blog/2013_06/adding-namespaces-to-elisp][great essay on the subject]], and you might want to
read [[https://lists.gnu.org/archive/html/emacs-devel/2014-12/msg00772.html][an opposing opinion]] as well. Note that *Names* is very different
from the solution he proposes, but it does solve the problem he had
with other alternatives which left the debugger unusable.
Emacs takes the approach of prefixing every symbol name with the name
of the package. This successfully avoids name clashes between
packages, but it quickly leads to code that's repetitive and annoying
to write. Below is an example from =package.el=, the word "/package/"
is repeated 7 times in a 10-line function.
*Names* doesn't change this overall approach. It adheres to Emacs
standards and is completely invisible to the end-user. *Names* simply
gives /you/ (the developer) a convenient way of writing code that
adheres to this standard.
[[file:package-example.png]]
/Example usage of Names to namespace an emacs-lisp function./
- At runtime, the right-hand-side will create the same definitions as the left-hand-side.
- At compilation, it will create the exact same compiled file (with no left-over reference to =names.el= functions).
*** Tested On:
Below are the packages on which I've tested *Names*. If you're
interested, try using it on one of your packages and [[https://github.com/Bruce-Connor/names/issues][let me know how
it goes]].
**** elnode
- *Number of ert tests passed:* Same as before namespacing (62).
- *Reduction in code size:* Approx. 2000 characters.
**** s.el
- *Number of ert tests passed:* All.
- *Reduction in code size:* Approx. 1000 characters (8%).
1000 characters is a lot when you consider /s.el/ has the second
shortest namespace possible, =s-=.
**** dash.el
- *Number of ert tests passed:* Same as before namespacing (104).
**** latex-extra
- *Number of ert tests passed:* ALL.
**** aggressive-indent
No actual tests defined, but this package actually uses /Names/ for
real! And it's alive and well.
names-20151201.0/package-example.png 0000644 0001752 0001753 00000243262 12432073042 015401 0 ustar elpa elpa PNG
IHDR sBIT|d IDATxw|,H 6uZ[[ma֪Jq"Nā""dB7B2Hn7{= ܈A`` Ŕ∈`wDDDa ݺ/""-f:(iQKtJEDDDDDDꠤYDDDDDDJEDDo=[DDZ:"BIIdB27c28]2OGqWrz}\ߜåMBקVpP~OSOƗ6PZ/$8u?xE+3hPU4߶t|G^( q f6q:3d3H}nKR7ۃFnt9EZj~*-7%'ʫ}[O?c߉.>yLb/U]VDbCi;`*m\NY;~"""D(%_ɬ+41F3j|/cGq5{ћe7(dQ$,Ö^;I|}ݰE!zDcXzyDDD.,~{ܚ.wKw2)lXQuFs˛ 2Ͽ%34!F@`nG-mqktفb61VL*Ys]oA]~CK_=G{GUXH`j5>ҁq):KayzWD.E%ڀ(Fis