+(def-edebug-spec luna-define-method
+ (&define name [&optional &or ":before" ":after" ":around"]
+ ((arg symbolp)
+ [&rest arg]
+ [&optional ["&optional" arg &rest arg]]
+ &optional ["&rest" arg]
+ )
+ def-body))
+
+(defun luna-class-find-parents-functions (class service)
+ (let ((parents (luna-class-parents class))
+ ret)
+ (while (and parents
+ (null
+ (setq ret (luna-class-find-functions
+ (luna-find-class (pop parents))
+ service)))))
+ ret))
+
+(defun luna-class-find-functions (class service)
+ (let ((sym (luna-class-find-member class service)))
+ (if (fboundp sym)
+ (cond ((eq (get sym 'luna-method-qualifier) :before)
+ (cons (symbol-function sym)
+ (luna-class-find-parents-functions class service))
+ )
+ ((eq (get sym 'luna-method-qualifier) :after)
+ (nconc (luna-class-find-parents-functions class service)
+ (list (symbol-function sym)))
+ )
+ ((eq (get sym 'luna-method-qualifier) :around)
+ (cons sym (luna-class-find-parents-functions class service))
+ )
+ (t
+ (list (symbol-function sym))
+ ))
+ (luna-class-find-parents-functions class service)
+ )))
+
+(defmacro luna-find-functions (entity service)
+ `(luna-class-find-functions (luna-find-class (luna-class-name ,entity))
+ ,service))
+
+(defsubst luna-send (entity message &rest luna-current-method-arguments)
+ "Send MESSAGE to ENTITY, and return the result.
+LUNA-CURRENT-METHOD-ARGUMENTS is arguments of the MESSAGE."
+ (let ((luna-next-methods (luna-find-functions entity message))
+ luna-current-method
+ luna-previous-return-value)
+ (while (and luna-next-methods
+ (progn
+ (setq luna-current-method (pop luna-next-methods)
+ luna-previous-return-value
+ (apply luna-current-method
+ luna-current-method-arguments))
+ (if (symbolp luna-current-method)
+ (not (eq (get luna-current-method
+ 'luna-method-qualifier) :around))
+ t))))
+ luna-previous-return-value))
+
+(eval-when-compile
+ (defvar luna-next-methods nil)
+ (defvar luna-current-method-arguments nil)
+ )
+
+(defun luna-call-next-method ()
+ "Call the next method in a method with :around qualifier."
+ (let (luna-current-method
+ luna-previous-return-value)
+ (while (and luna-next-methods
+ (progn
+ (setq luna-current-method (pop luna-next-methods)
+ luna-previous-return-value
+ (apply luna-current-method
+ luna-current-method-arguments))
+ (if (symbolp luna-current-method)
+ (not (eq (get luna-current-method
+ 'luna-method-qualifier) :around))
+ t))))
+ luna-previous-return-value))