Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metaclass extensibility #68

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ Now consider the following scenarios:
```lisp
(jzon:stringify (make-instance 'person :name "Anya" :job nil
:married nil :children nil)
:pretty t :stream t)`
:pretty t :stream t)
```
``` json
{
Expand Down Expand Up @@ -808,7 +808,7 @@ now
```lisp
(jzon:stringify (make-instance 'person :name "Anya" :job nil
:married nil :children nil)
:pretty t :stream t)`
:pretty t :stream t)
```
``` json
{
Expand Down
54 changes: 31 additions & 23 deletions src/jzon.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,22 +1121,30 @@ see `close-parser'"
(with-open-file (in in :direction :input :external-format :utf-8 :element-type 'character)
(parse in :max-depth max-depth :allow-comments allow-comments :allow-trailing-comma allow-trailing-comma :allow-multiple-content allow-multiple-content :max-string-length max-string-length :key-fn key-fn)))
(t
(multiple-value-bind (%step %read-string %pos) (%make-fns in max-string-length)
(declare (dynamic-extent %step %read-string %pos))
(%parse %step %read-string %pos key-fn max-depth (and allow-comments t) (and allow-trailing-comma t) (and allow-multiple-content t)))))))

(macrolet ((%coerced-fields-slots (element)
`(let ((class (class-of ,element)))
(c2mop:ensure-finalized class)
(mapcar (lambda (s)
(let ((slot-name (c2mop:slot-definition-name s)))
(list slot-name
(slot-value ,element slot-name)
(c2mop:slot-definition-type s))))
(remove-if-not (lambda (s) (slot-boundp ,element (c2mop:slot-definition-name s)))
(c2mop:class-slots class))))))
(defgeneric coerced-fields (element)
(:documentation "Return a list of key definitions for `element'.
(multiple-value-bind (%step %read-string %pos) (%make-fns in max-string-length)
(declare (dynamic-extent %step %read-string %pos))
(%parse %step %read-string %pos key-fn max-depth (and allow-comments t) (and allow-trailing-comma t) (and allow-multiple-content t)))))))

(defgeneric %coerced-fields-slots (element))
(defmethod %coerced-fields-slots (element)
(let ((class (class-of element)))
(c2mop:ensure-finalized class)
(mapcar (lambda (s)
(let ((slot-name (c2mop:slot-definition-name s)))
(list slot-name
(slot-value element slot-name)
(c2mop:slot-definition-type s))))
(get-slots-to-encode class element))))

(defgeneric get-slots-to-encode (class element)
(:documentation "This function is used to get the slots to be json encoded. The class is the first parameter in order to allow for extending the dispatch based on the metaclass of the object."))

(defmethod get-slots-to-encode (class element)
(remove-if-not (lambda (s) (slot-boundp element (c2mop:slot-definition-name s)))
(c2mop:class-slots class)))

(defgeneric coerced-fields (element)
(:documentation "Return a list of key definitions for `element'.
A key definition is a three-element list of the form
(name value &optional type)
name is the key name and will be coerced if not already a string
Expand All @@ -1147,13 +1155,13 @@ Example return value:
((name :zulu)
(hobbies nil list))
")
(:method (element)
nil)
#+(or ccl clisp sbcl lispworks8)
(:method ((element structure-object))
(%coerced-fields-slots element))
(:method ((element standard-object))
(%coerced-fields-slots element))))
(:method (element)
nil)
#+(or ccl clisp sbcl lispworks8)
(:method ((element structure-object))
(%coerced-fields-slots element))
(:method ((element standard-object))
(%coerced-fields-slots element)))

(eval-when (:compile-toplevel :load-toplevel :execute)
(declaim (inline %type=))
Expand Down