~subsetpark/fugue

9c5ba786e71ab83aa088b28b11bf31c91f33d129 — Zach Smith 5 months ago 07a06de
Update docs
3 files changed, 82 insertions(+), 63 deletions(-)

M README.md
M fugue.janet
M test/fugue.janet
M README.md => README.md +71 -52
@@ 57,51 57,72 @@ be selected for any descendent prototype instances.

## fugue

[Root](#Root), [Root*?](#Root-1), [Root?](#Root-2), [allocate](#allocate), [declare-open-multi](#declare-open-multi), [defgeneric](#defgeneric), [defmethod](#defmethod), [defmulti](#defmulti), [defproto](#defproto), [extend-multi](#extend-multi), [fields](#fields), [get-type-or-proto](#get-type-or-proto), [multimethod-types-match?](#multimethod-types-match), [new-Root](#new-Root), [prototype?](#prototype), [with-slots](#with-slots), [with-slots-as](#with-slots-as)
[@](#), [Root](#Root), [Root*?](#Root-1), [Root?](#Root-2), [allocate](#allocate), [declare-open-multi](#declare-open-multi), [defgeneric](#defgeneric), [defmethod](#defmethod), [defmulti](#defmulti), [defproto](#defproto), [extend-multi](#extend-multi), [fields](#fields), [get-type-or-proto](#get-type-or-proto), [multimethod-types-match?](#multimethod-types-match), [new-Root](#new-Root), [prototype?](#prototype), [with-slots](#with-slots), [with-slots-as](#with-slots-as)

## @

**macro**  | [source][1]

```janet
(@ proto x &opt y)
```

Compile-time Prototype field checking.

Accepts two forms:

`(@ SomePrototype :some-field)` - Translates into `:some-field`, if
`some-field` is defined on `SomePrototype`.

`(@ SomePrototype some-object :some-field)` - Assets (as above) at
compile time that `some-field` is defined on `SomePrototype`; at
runtime, checks that `some-object` is a descendent of
`SomePrototype` and if so, translates to `(some-object
:some-field)`.

[1]: fugue.janet#L707

## Root

**table**  | [source][1]
**table**  | [source][2]

```janet
@{:_init <function identity> :_meta @{ :prototype-allocations @{} :object-type :prototype :fields () :instance-defaults @{}} :_name "Prototype" :new <function new-from-Root>}
@{:_init <function identity> :_meta @{ :prototype-allocations @{} :getters @{} :object-type :prototype :fields () :instance-defaults @{}} :_name "Prototype" :new <function new-from-Root>}
```

Root of the Fugue object hierarchy.

[1]: fugue.janet#L14
[2]: fugue.janet#L15

## Root*?

**function**  | [source][2]
**function**  | [source][3]

```janet
(Root*? obj)
```

 Proto ancestor predicate: return if `obj` is a
 descendent of Root.
 
Proto ancestor predicate: return if `obj` is a
descendent of Root.

[2]: eval#L-1
[3]: eval#L-1

## Root?

**function**  | [source][3]
**function**  | [source][4]

```janet
(Root? obj)
```

 Proto instance predicate: return if `obj` is an
 instance (that is, a direct child) of Root.
 
Proto instance predicate: return if `obj` is an
instance (that is, a direct child) of Root.

[3]: eval#L-1
[4]: eval#L-1

## allocate

**function**  | [source][4]
**function**  | [source][5]

```janet
(allocate obj key value)


@@ 112,11 133,11 @@ specific prototype for this key, then `fugue/allocate` will put `value`
at `key` in the appropriate prototype, and it will be inherited by
all descendents of that prototype.

[4]: fugue.janet#L293
[5]: fugue.janet#L306

## declare-open-multi

**macro**  | [source][5]
**macro**  | [source][6]

```janet
(declare-open-multi name)


@@ 128,11 149,11 @@ Extending an open multimethod (see `extend-multi`) from any other
environment makes the case extension available wherever the
multimethod has been imported.

[5]: fugue.janet#L606
[6]: fugue.janet#L607

## defgeneric

**macro**  | [source][6]
**macro**  | [source][7]

```janet
(defgeneric name args &opt body)


@@ 143,11 164,11 @@ first argument has a method corresponding to the name of the
function, call that object 's method with the arguments. Otherwise,
evaluate `body`.

[6]: fugue.janet#L329
[7]: fugue.janet#L342

## defmethod

**macro**  | [source][7]
**macro**  | [source][8]

```janet
(defmethod name proto args & body)


@@ 161,11 182,11 @@ Defines a few symbols for reference in the body of the method.
`__parent` - Bound to the parent of `proto`.
`__super` - Bound to the method at `name` within `__parent`.

[7]: fugue.janet#L340
[8]: fugue.janet#L353

## defmulti

**macro**  | [source][8]
**macro**  | [source][9]

```janet
(defmulti name multi-types args & body)


@@ 233,11 254,11 @@ repl:12:> (cat "hello" 100)
"hello #100"
```

[8]: fugue.janet#L530
[9]: fugue.janet#L531

## defproto

**macro**  | [source][9]
**macro**  | [source][10]

```janet
(defproto name parent-name & fields)


@@ 275,11 296,7 @@ field (by default, has the same name as the field). Specify `false`
to prevent a getter from being defined.

`defproto` will define a getter function for each of the defined
fields, unless `:getter` is false. It will also define a "qualified"
getter function, where the getter-name is prepended by the name of
the prototype. This can be used to provide a greater degree of
"type-safety", as the qualified getter won 't be defined if that
prototype doesn 't have that field.
fields, unless `:getter` is false.

`defproto` will also create a `:new` method in the created
prototype. This will take as positional arguments all of the fields


@@ 313,11 330,11 @@ repl:47:> (speak (:new Pekingese))
"My name is Fido and I am Extremely Small"
```

[9]: fugue.janet#L188
[10]: fugue.janet#L205

## extend-multi

**macro**  | [source][10]
**macro**  | [source][11]

```janet
(extend-multi multi multi-types args & body)


@@ 331,11 348,11 @@ See that function's documentation for full usage reference.
Whenever a case is added to `multi`, that case is available
wherever the multimethod is imported.

[10]: fugue.janet#L622
[11]: fugue.janet#L623

## fields

**function**  | [source][11]
**function**  | [source][12]

```janet
(fields obj)


@@ 344,11 361,11 @@ wherever the multimethod is imported.
Return all the defined fields for `obj` and its prototype
hierarchy.

[11]: fugue.janet#L367
[12]: fugue.janet#L21

## get-type-or-proto

**function**  | [source][12]
**function**  | [source][13]

```janet
(get-type-or-proto obj)


@@ 357,11 374,11 @@ hierarchy.
Return the prototype of `obj`, if it has one, otherwise the keyword
output of `type`.

[12]: fugue.janet#L101
[13]: fugue.janet#L119

## multimethod-types-match?

**function**  | [source][13]
**function**  | [source][14]

```janet
(multimethod-types-match? args arg-types)


@@ 371,23 388,23 @@ Check to see if the types `args` match the sequence `arg-types`,
according to multimethod rules (ie, following prototype membership
and using `:_` as a fallback)

[13]: fugue.janet#L455
[14]: fugue.janet#L456

## new-Root

**function**  | [source][14]
**function**  | [source][15]

```janet
(new-Root & rest)
```

Constructor for Root. Return a new object with Root as the prototype.


[14]: eval#L-1
[15]: eval#L-1

## prototype?

**function**  | [source][15]
**function**  | [source][16]

```janet
(prototype? obj)


@@ 395,11 412,11 @@ and using `:_` as a fallback)

Is `obj` the result of a `defproto ` call? 

[15]: fugue.janet#L285
[16]: fugue.janet#L298

## with-slots

**macro**  | [source][16]
**macro**  | [source][17]

```janet
(with-slots proto obj & body)


@@ 409,8 426,10 @@ Anaphoric macro with transformed getter/setters.

Injects `this` into scope as a reference to `obj`.

Any symbols that begin with `@` are transformed into `(this <field name>)`,
so that `@name` or its setter form `(set @name foo)` do the right thing.
The pattern `(@ <field name>)` is transformed into `(this (keyword
<field name>))`, if and only if `<field name>` is defined for
`proto`, so that `(@ name)` or its setter form `(set (@ name) foo)`
do the right thing.

---



@@ 420,19 439,19 @@ Example :
repl:2:> (defproto Foo nil name {:default "Jane Doe"})
repl:3:> (def f (new-Foo))
repl:4:> (with-slots Foo f
           (set @name "Cosmo Kramer")
           (print @name)
           (set (@ name) "Cosmo Kramer")
           (print (@ name))
           (print (Foo? this)))
Cosmo Kramer
true
nil
```

[16]: fugue.janet#L664
[17]: fugue.janet#L663

## with-slots-as

**macro**  | [source][17]
**macro**  | [source][18]

```janet
(with-slots-as proto obj as & body)


@@ 447,5 466,5 @@ so that `@name` or its setter form `(set @name foo)` do the right thing.

See `with-slots` documentation for more details.

[17]: fugue.janet#L692
[18]: fugue.janet#L693


M fugue.janet => fugue.janet +10 -10
@@ 9,7 9,7 @@
             :fields defined-fields
             :prototype-allocations @{}
             :instance-defaults @{}
             :accessors @{}}
             :getters @{}}
    :_name name})

(def Root


@@ 47,7 47,7 @@
        proto-allocated-fields @[]
        proto-allocations @{}
        instance-defaults @{}
        accessors @{}]
        getters @{}]
    (loop [[field-name attrs] :in fields
           :let [key-field (keyword field-name)]]
      # Assemble list of arguments to constructor


@@ 66,20 66,20 @@
      (when-let [getter-name (match attrs
                               {:getter getter} getter
                               _ field-name)]
        (put accessors field-name getter-name)))
    [init-args proto-allocated-fields proto-allocations instance-defaults accessors]))
        (put getters field-name getter-name)))
    [init-args proto-allocated-fields proto-allocations instance-defaults getters]))

(defn- proto-form
  "Generate the def form for a Prototype."
  [name parent fields defined-fields
   _init-args proto-allocated-fields proto-allocations instance-defaults accessors]
   _init-args proto-allocated-fields proto-allocations instance-defaults getters]
  ~(let [object (,bare-proto (,string ',name) ,defined-fields)]
     (,put-in object [:_meta :prototype-allocations]
        (,table/setproto
           (,table ;(,mapcat |[$0 object] ',proto-allocated-fields))
           (,get-in ',parent [:_meta :prototype-allocations])))
     (,put-in object [:_meta :instance-defaults] ',instance-defaults)
     (,put-in object [:_meta :accessors] ',accessors)
     (,put-in object [:_meta :getters] ',getters)
     (,merge-into object ',proto-allocations)
     (,table/setproto object ',parent)))



@@ 186,12 186,12 @@
(eval (new-form 'Root))

(defn- getters
  [name parent [_ _ _ _ accessors]]
  (seq [[field-name accessor-name] :pairs accessors
  [name parent [_ _ _ _ getter-list]]
  (seq [[field-name getter-name] :pairs getter-list
        :let [key-field (keyword field-name)
              docstring (string "Get " field-name " from a " name)]]
    (with-syms [self]
      ~(defn ,accessor-name
      ~(defn ,getter-name
         ,docstring
         [,self]
         (let [current-fields (,fields ,self)]


@@ 729,5 729,5 @@
    (if-not obj
      field
      ~(if-not (,recursive-prototype-check ,proto ,obj)
         (errorf "Expected a %s, got: %q" (,get-type-or-proto ,obj))
         (errorf "Expected a %s, got: %q" ,(string proto) (,get-type-or-proto ,obj))
         ,(tuple obj field)))))

M test/fugue.janet => test/fugue.janet +1 -1
@@ 171,7 171,7 @@
(deftest getter
  (let [a-form (:new Form :unique-field :echo)
        a-dog (:new Dog)]
    (is (== @{'unique-field 'get-unique-field} (get-in Form [:_meta :accessors])))
    (is (== @{'unique-field 'get-unique-field} (get-in Form [:_meta :getters])))
    (is (nil? (dyn 'unique-field)))
    (is (= :echo (get-unique-field a-form)))
    (is (= :echo (a-form (fugue/@ Form :unique-field))))