Skip to content

Instantly share code, notes, and snippets.

@bowbow99
Created August 6, 2010 22:44
Show Gist options
  • Save bowbow99/512148 to your computer and use it in GitHub Desktop.
Save bowbow99/512148 to your computer and use it in GitHub Desktop.
symbol が被ってたら、再起動で unintern とか shadow できる use-package
;;; symbol が被ってたら、再起動で unintern とか shadow できる use-package
(defun %use-package-w/restart (used &optional (using *package*))
(tagbody
#1=#:begin
(handler-bind
((simple-package-error
(lambda (e)
(let ((symbol (simple-package-error-datum2 e)))
(restart-case
(error e)
(unintern ()
:report (lambda (s)
(format s "パッケージ ~A からシンボル ~A を unintern する。"
(package-name using)
(symbol-name symbol)))
(unintern (find-symbol (symbol-name symbol) using) using)
(go #1#))
(shadow ()
:report (lambda (s)
(format s "パッケージ ~A のシンボル ~A を shadow する。"
(package-name using) (symbol-name symbol)))
(shadow symbol using)
(go #1#)))))))
(return-from %use-package-w/restart
(use-package used using)))))
(defun %use-package-w/auto-unintern (used &optional (using *package*))
(handler-bind ((simple-package-error
(lambda (c)
(invoke-restart (find-restart 'unintern c)))))
(%use-package-w/restart used using)))
(defun %use-package-w/auto-shadow (used &optional (using *package*))
(handler-bind ((simple-package-error
(lambda (c)
(invoke-restart (find-restart 'shadow c)))))
(%use-package-w/restart used using)))
;;; 使ってみる #1
;; 生贄
(defpackage :test)
=> #<package: test>
;; editor パッケージとぶつかる symbol をいくつか intern しておく
(dolist (x '(lisp-mode with-output-to-buffer string-match))
(intern (symbol-name x) :test))
=> nil
;; 被ってることを確認
(find-all-symbols "lisp-mode")
=> (lisp-mode test::lisp-mode)
(find-all-symbols "with-output-to-buffer")
=> (with-output-to-buffer test::with-output-to-buffer)
(find-all-symbols "string-match")
=> (string-match test::string-match)
;; ノーマルの use-package
(use-package :editor :test)
;; simple-package-error:
;; 名前が衝突するためuseできません: lisp-mode
;;
;; 0 [abort ] やめる。
;;
;; Restart[0-0]: 0
(%use-package-w/restart :editor :test)
;; simple-package-error:
;; 名前が衝突するためuseできません: lisp-mode
;;
;; 0 [unintern] パッケージ test からシンボル lisp-mode を unintern する。
;; 1 [shadow ] パッケージ test のシンボル lisp-mode を shadow する。
;; 2 [abort ] やめる。
;;
;; Restart[0-2]: 0
;; simple-package-error:
;; 名前が衝突するためuseできません: with-output-to-buffer
;;
;; 0 [unintern] パッケージ test からシンボル with-output-to-buffer を unintern する。
;; 1 [shadow ] パッケージ test のシンボル with-output-to-buffer を shadow する。
;; 2 [abort ] やめる。
;;
;; Restart[0-2]: 1
;; simple-package-error:
;; 名前が衝突するためuseできません: string-match
;;
;; 0 [unintern] パッケージ test からシンボル string-match を unintern する。
;; 1 [shadow ] パッケージ test のシンボル string-match を shadow する。
;; 2 [abort ] やめる。
;;
;; Restart[0-2]: 0
=> t
;; test::lisp-mode は unintern された
(find-all-symbols "lisp-mode")
=> (lisp-mode)
;; test::with-output-to-buffer は shadow された
(find-all-symbols "with-output-to-buffer")
=> (with-output-to-buffer test::with-output-to-buffer)
(package-shadowing-symbols :test)
=> (test::with-output-to-buffer)
;; test::string-match は unintern された
(find-all-symbols "string-match")
=> (string-match)
;;; 使ってみる #2: %use-package-w/auto-shadow
;; リセット
(delete-package :test)
=> t
(defpackage :test)
=> #<package: test>
;; めんどくなったので list にしておく
(defvar *symbols* '(lisp-mode with-output-to-buffer string-match))
=> *symbols*
;; パッケージ test にぶつかる symbol を用意
(dolist (x *symbols*)
(intern (symbol-name x) :test))
=> nil
;; 確認
(dolist (x *symbols*)
(format t "~&- ~A in (~{~A~^, ~})"
(symbol-name x)
(mapcar #'package-name
(mapcar #'symbol-package
(find-all-symbols (symbol-name x))))))
- lisp-mode in (editor, test)
- with-output-to-buffer in (editor, test)
- string-match in (editor, test)
=> nil
;; ノーマルの use-package
(use-package :editor :test)
;; simple-package-error:
;; 名前が衝突するためuseできません: lisp-mode
;;
;; 0 [abort ] やめる。
;;
;; Restart[0-0]: 0
(%use-package-w/auto-shadow :editor :test)
=> t
;; みんな shadow された
(package-shadowing-symbols :test)
=> (test::string-match test::with-output-to-buffer test::lisp-mode)
;;; 使ってみる #3: %use-package-w/auto-unintern
;; リセット
(when (find-package :test)
(delete-package :test)
(defpackage :test))
=> #<package: test>
;; ぶつかるシンボルを用意
(dolist (x *symbols*)
(intern (symbol-name x) :test))
=> nil
;; 確認
(dolist (x *symbols*)
(format t "~&- ~A in (~{~A~^, ~})"
(symbol-name x)
(mapcar (lambda (x) (package-name (symbol-package x)))
(find-all-symbols x))))
- lisp-mode in (editor, test)
- with-output-to-buffer in (editor, test)
- string-match in (editor, test)
=> nil
;; ノーマルの use-package
(use-package :editor :test)
;; simple-package-error:
;; 名前が衝突するためuseできません: lisp-mode
;;
;; 0 [abort ] やめる。
;;
;; Restart[0-0]: 0
(%use-package-w/auto-unintern :editor :test)
=> t
;; test 所属の連中は unintern されて消えた
(dolist (x *symbols*)
(format t "~&- ~A in (~{~A~^, ~})"
(symbol-name x)
(mapcar (lambda (x) (package-name (symbol-package x)))
(find-all-symbols (symbol-name x)))))
- lisp-mode in (editor)
- with-output-to-buffer in (editor)
- string-match in (editor)
=> nil
;; パッケージ test 内では editor のシンボルが見える
(dolist (x *symbols*)
(multiple-value-bind (symbol status)
(find-symbol (symbol-name x) :test)
(format t "~&- ~S (~S from ~A)"
symbol status (package-name (symbol-package symbol)))))
- lisp-mode (:inherited from editor)
- with-output-to-buffer (:inherited from editor)
- string-match (:inherited from editor)
=> nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment