Browse code
feat(docs): update README, generate doc site and tests from it
Edward Langley authored on 16/03/2022 08:24:33
Showing 76 changed files
Showing 76 changed files
- README.org
- docs/colors.css
- docs/fonts/Lato-Black.eot
- docs/fonts/Lato-Black.ttf
- docs/fonts/Lato-Black.woff
- docs/fonts/Lato-Black.woff2
- docs/fonts/Lato-BlackItalic.eot
- docs/fonts/Lato-BlackItalic.ttf
- docs/fonts/Lato-BlackItalic.woff
- docs/fonts/Lato-BlackItalic.woff2
- docs/fonts/Lato-Bold.eot
- docs/fonts/Lato-Bold.ttf
- docs/fonts/Lato-Bold.woff
- docs/fonts/Lato-Bold.woff2
- docs/fonts/Lato-BoldItalic.eot
- docs/fonts/Lato-BoldItalic.ttf
- docs/fonts/Lato-BoldItalic.woff
- docs/fonts/Lato-BoldItalic.woff2
- docs/fonts/Lato-Hairline.eot
- docs/fonts/Lato-Hairline.ttf
- docs/fonts/Lato-Hairline.woff
- docs/fonts/Lato-Hairline.woff2
- docs/fonts/Lato-HairlineItalic.eot
- docs/fonts/Lato-HairlineItalic.ttf
- docs/fonts/Lato-HairlineItalic.woff
- docs/fonts/Lato-HairlineItalic.woff2
- docs/fonts/Lato-Heavy.eot
- docs/fonts/Lato-Heavy.ttf
- docs/fonts/Lato-Heavy.woff
- docs/fonts/Lato-Heavy.woff2
- docs/fonts/Lato-HeavyItalic.eot
- docs/fonts/Lato-HeavyItalic.ttf
- docs/fonts/Lato-HeavyItalic.woff
- docs/fonts/Lato-HeavyItalic.woff2
- docs/fonts/Lato-Italic.eot
- docs/fonts/Lato-Italic.ttf
- docs/fonts/Lato-Italic.woff
- docs/fonts/Lato-Italic.woff2
- docs/fonts/Lato-Light.eot
- docs/fonts/Lato-Light.ttf
- docs/fonts/Lato-Light.woff
- docs/fonts/Lato-Light.woff2
- docs/fonts/Lato-LightItalic.eot
- docs/fonts/Lato-LightItalic.ttf
- docs/fonts/Lato-LightItalic.woff
- docs/fonts/Lato-LightItalic.woff2
- docs/fonts/Lato-Medium.eot
- docs/fonts/Lato-Medium.ttf
- docs/fonts/Lato-Medium.woff
- docs/fonts/Lato-Medium.woff2
- docs/fonts/Lato-MediumItalic.eot
- docs/fonts/Lato-MediumItalic.ttf
- docs/fonts/Lato-MediumItalic.woff
- docs/fonts/Lato-MediumItalic.woff2
- docs/fonts/Lato-Regular.eot
- docs/fonts/Lato-Regular.ttf
- docs/fonts/Lato-Regular.woff
- docs/fonts/Lato-Regular.woff2
- docs/fonts/Lato-Semibold.eot
- docs/fonts/Lato-Semibold.ttf
- docs/fonts/Lato-Semibold.woff
- docs/fonts/Lato-Semibold.woff2
- docs/fonts/Lato-SemiboldItalic.eot
- docs/fonts/Lato-SemiboldItalic.ttf
- docs/fonts/Lato-SemiboldItalic.woff
- docs/fonts/Lato-SemiboldItalic.woff2
- docs/fonts/Lato-Thin.eot
- docs/fonts/Lato-Thin.ttf
- docs/fonts/Lato-Thin.woff
- docs/fonts/Lato-Thin.woff2
- docs/fonts/Lato-ThinItalic.eot
- docs/fonts/Lato-ThinItalic.ttf
- docs/fonts/Lato-ThinItalic.woff
- docs/fonts/Lato-ThinItalic.woff2
- docs/index.html
- src/doc.test.js
... | ... |
@@ -1,3 +1,8 @@ |
1 |
+#+TITLE: README for js-generic-functions |
|
2 |
+#+AUTHOR: Ed L |
|
3 |
+#+HTML_HEAD: <link rel="stylesheet" href="./colors.css"></link> |
|
4 |
+#+EXPORT_FILE_NAME: docs/index.html |
|
5 |
+ |
|
1 | 6 |
* What is this? |
2 | 7 |
|
3 | 8 |
An implementation of generic functions based on CLOS and the protocols |
... | ... |
@@ -13,18 +18,18 @@ between such specializers and subtyping are an open question. |
13 | 18 |
** Basic Usage |
14 | 19 |
|
15 | 20 |
#+NAME: imports |
16 |
-#+BEGIN_SRC js2 |
|
21 |
+#+BEGIN_SRC js |
|
17 | 22 |
import { defgeneric } from "./genfuns.js"; |
18 | 23 |
#+END_SRC |
19 | 24 |
|
20 |
-Defining a function works by calling src_js2{defgeneric} with some |
|
25 |
+Defining a function works by calling src_js{defgeneric} with some |
|
21 | 26 |
information about the function name and arguments. Methods are then |
22 | 27 |
added by calling the appropriate methods with a pair of arguments: a |
23 | 28 |
list of specializers (prototypes in the simple case, although there |
24 | 29 |
are other options) and a function to run if those specializers match. |
25 | 30 |
|
26 | 31 |
#+NAME: basic-definition |
27 |
-#+BEGIN_SRC js2 |
|
32 |
+#+BEGIN_SRC js |
|
28 | 33 |
const example1generic = defgeneric("example1", "a", "b") |
29 | 34 |
.primary([Number, Object], (n, __) => [1, n]) |
30 | 35 |
.primary([Object, Number], (_, n) => [2, n]) |
... | ... |
@@ -32,10 +37,10 @@ are other options) and a function to run if those specializers match. |
32 | 37 |
#+END_SRC |
33 | 38 |
|
34 | 39 |
After a generic function has been defined, you can get the function to |
35 |
-call it by accessing its src_js2{.fn} attribute. |
|
40 |
+call it by accessing its src_js{.fn} attribute. |
|
36 | 41 |
|
37 | 42 |
#+NAME: call-the-function |
38 |
-#+BEGIN_SRC js2 |
|
43 |
+#+BEGIN_SRC js |
|
39 | 44 |
const example1 = example1generic.fn; |
40 | 45 |
|
41 | 46 |
expect(example1(5, {})).toEqual([1, 5]); |
... | ... |
@@ -49,7 +54,7 @@ If a separate reference to the generic function object is maintained, |
49 | 54 |
you can add methods like so: |
50 | 55 |
|
51 | 56 |
#+NAME: add-methods |
52 |
-#+BEGIN_SRC js2 |
|
57 |
+#+BEGIN_SRC js |
|
53 | 58 |
example1generic |
54 | 59 |
.primary([String, Object], (s, __) => [3, s]) |
55 | 60 |
.primary([Object, String], (_, s) => [4, s]); |
... | ... |
@@ -58,8 +63,33 @@ you can add methods like so: |
58 | 63 |
expect(example1({}, "world")).toEqual([4, "world"]); |
59 | 64 |
#+END_SRC |
60 | 65 |
|
66 |
+** Other sorts of specializers |
|
67 |
+#+NAME: specializer-import |
|
68 |
+#+BEGIN_SRC js |
|
69 |
+ import { Shape, Eql } from "./genfuns.js"; |
|
70 |
+#+END_SRC |
|
71 |
+ |
|
72 |
+ |
|
73 |
+ |
|
74 |
+#+NAME: specializer-examples |
|
75 |
+#+BEGIN_SRC js |
|
76 |
+ const example2 = defgeneric("example2", "inp") |
|
77 |
+ .primary([Shape("a", "b")], inp => `a: ${inp.a} b: ${inp.b}`) |
|
78 |
+ .primary([Shape("a")], inp => `a: ${inp.a} b: <missing>`) |
|
79 |
+ .primary([Shape(["c", 1])], inp => `c: one`) |
|
80 |
+ .primary([Shape(["c", 2])], inp => `c: two`) |
|
81 |
+ .primary([Eql(1)], inp => "one").fn; |
|
82 |
+ |
|
83 |
+ expect(example2({ a: 3, q: "whatever" })).toEqual("a: 3 b: <missing>"); |
|
84 |
+ expect(example2({ a: 3, b: 4, q: "whatever" })).toEqual("a: 3 b: 4"); |
|
85 |
+ expect(example2({ c: 1, q: "whatever" })).toEqual("c: one"); |
|
86 |
+ expect(example2({ c: 2, q: "whatever" })).toEqual("c: two"); |
|
87 |
+ expect(example2(1)).toEqual("one"); |
|
88 |
+#+END_SRC |
|
89 |
+ |
|
61 | 90 |
#+BEGIN_SRC js :tangle src/doc.test.js :comments noweb :noweb tangle :exports none |
62 | 91 |
<<imports>> |
92 |
+ <<specializer-import>> |
|
63 | 93 |
|
64 | 94 |
describe("defgeneric", () => { |
65 | 95 |
test("methods get called appropriately", () => { |
... | ... |
@@ -71,5 +101,8 @@ you can add methods like so: |
71 | 101 |
|
72 | 102 |
<<sample1>> |
73 | 103 |
}); |
104 |
+ test ('specializers work as expected', () => { |
|
105 |
+ <<specializer-examples>> |
|
106 |
+ }) |
|
74 | 107 |
}); |
75 | 108 |
#+END_SRC |
76 | 109 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,88 @@ |
1 |
+@import url(./latofonts.css); |
|
2 |
+ |
|
3 |
+:root { |
|
4 |
+ --zenburn-fg-plus-2: #ffffef; |
|
5 |
+ --zenburn-fg-plus-1: #f5f5d6; |
|
6 |
+ --zenburn-fg: #dcdccc; |
|
7 |
+ --zenburn-fg-1: #a6a689; |
|
8 |
+ --zenburn-fg-2: #656555; |
|
9 |
+ --zenburn-black: #000000; |
|
10 |
+ --zenburn-bg-2: #000000; |
|
11 |
+ --zenburn-bg-1: #111112; |
|
12 |
+ --zenburn-bg-05: #383838; |
|
13 |
+ --zenburn-bg: #2a2b2e; |
|
14 |
+ --zenburn-bg-plus-05: #494949; |
|
15 |
+ --zenburn-bg-plus-1: #4f4f4f; |
|
16 |
+ --zenburn-bg-plus-2: #5f5f5f; |
|
17 |
+ --zenburn-bg-plus-3: #6f6f6f; |
|
18 |
+ --zenburn-red-plus-2: #ecb3b3; |
|
19 |
+ --zenburn-red-plus-1: #dca3a3; |
|
20 |
+ --zenburn-red: #cc9393; |
|
21 |
+ --zenburn-red-1: #bc8383; |
|
22 |
+ --zenburn-red-2: #ac7373; |
|
23 |
+ --zenburn-red-3: #9c6363; |
|
24 |
+ --zenburn-red-4: #8c5353; |
|
25 |
+ --zenburn-red-5: #7c4343; |
|
26 |
+ --zenburn-red-6: #6c3333; |
|
27 |
+ --zenburn-orange: #dfaf8f; |
|
28 |
+ --zenburn-yellow: #f0dfaf; |
|
29 |
+ --zenburn-yellow-1: #e0cf9f; |
|
30 |
+ --zenburn-yellow-2: #d0bf8f; |
|
31 |
+ --zenburn-green-5: #2f4f2f; |
|
32 |
+ --zenburn-green-4: #3f5f3f; |
|
33 |
+ --zenburn-green-3: #4f6f4f; |
|
34 |
+ --zenburn-green-2: #5f7f5f; |
|
35 |
+ --zenburn-green-1: #6f8f6f; |
|
36 |
+ --zenburn-green: #7f9f7f; |
|
37 |
+ --zenburn-green-plus-1: #8fb28f; |
|
38 |
+ --zenburn-green-plus-2: #9fc59f; |
|
39 |
+ --zenburn-green-plus-3: #afd8af; |
|
40 |
+ --zenburn-green-plus-4: #bfebbf; |
|
41 |
+ --zenburn-cyan: #93e0e3; |
|
42 |
+ --zenburn-blue-plus-3: #bde0f3; |
|
43 |
+ --zenburn-blue-plus-2: #ace0e3; |
|
44 |
+ --zenburn-blue-plus-1: #94bff3; |
|
45 |
+ --zenburn-blue: #8cd0d3; |
|
46 |
+ --zenburn-blue-1: #7cb8bb; |
|
47 |
+ --zenburn-blue-2: #6ca0a3; |
|
48 |
+ --zenburn-blue-3: #5c888b; |
|
49 |
+ --zenburn-blue-4: #4c7073; |
|
50 |
+ --zenburn-blue-5: #366060; |
|
51 |
+ --zenburn-magenta: #dc8cc3; |
|
52 |
+} |
|
53 |
+ |
|
54 |
+html { |
|
55 |
+ --background: var(--zenburn-bg); |
|
56 |
+ --foreground: var(--zenburn-fg); |
|
57 |
+ --background-hl: var(--zenburn-bg-plus-1); |
|
58 |
+ --foreground-hl: var(--zenburn-fg-plus-1); |
|
59 |
+ --accent: var(--zenburn-green); |
|
60 |
+ --link: var(--zenburn-blue); |
|
61 |
+} |
|
62 |
+ |
|
63 |
+body { |
|
64 |
+ background: var(--background); |
|
65 |
+ color: var(--foreground); |
|
66 |
+} |
|
67 |
+ |
|
68 |
+pre { |
|
69 |
+ background: var(--background-hl); |
|
70 |
+ color: var(--foreground-hl); |
|
71 |
+} |
|
72 |
+ |
|
73 |
+h1, |
|
74 |
+h2, |
|
75 |
+h3, |
|
76 |
+h4, |
|
77 |
+h5, |
|
78 |
+h6 { |
|
79 |
+ color: var(--accent); |
|
80 |
+} |
|
81 |
+ |
|
82 |
+body { |
|
83 |
+ font-family: "LatoWeb", sans-serif; |
|
84 |
+} |
|
85 |
+ |
|
86 |
+a { |
|
87 |
+ color: var(--link); |
|
88 |
+} |
144 | 233 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,327 @@ |
1 |
+<?xml version="1.0" encoding="utf-8"?> |
|
2 |
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
|
3 |
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
|
4 |
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> |
|
5 |
+<head> |
|
6 |
+<!-- 2022-03-16 Wed 01:22 --> |
|
7 |
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> |
|
8 |
+<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|
9 |
+<title>README for js-generic-functions</title> |
|
10 |
+<meta name="author" content="Ed L" /> |
|
11 |
+<meta name="generator" content="Org Mode" /> |
|
12 |
+<style> |
|
13 |
+ #content { max-width: 60em; margin: auto; } |
|
14 |
+ .title { text-align: center; |
|
15 |
+ margin-bottom: .2em; } |
|
16 |
+ .subtitle { text-align: center; |
|
17 |
+ font-size: medium; |
|
18 |
+ font-weight: bold; |
|
19 |
+ margin-top:0; } |
|
20 |
+ .todo { font-family: monospace; color: red; } |
|
21 |
+ .done { font-family: monospace; color: green; } |
|
22 |
+ .priority { font-family: monospace; color: orange; } |
|
23 |
+ .tag { background-color: #eee; font-family: monospace; |
|
24 |
+ padding: 2px; font-size: 80%; font-weight: normal; } |
|
25 |
+ .timestamp { color: #bebebe; } |
|
26 |
+ .timestamp-kwd { color: #5f9ea0; } |
|
27 |
+ .org-right { margin-left: auto; margin-right: 0px; text-align: right; } |
|
28 |
+ .org-left { margin-left: 0px; margin-right: auto; text-align: left; } |
|
29 |
+ .org-center { margin-left: auto; margin-right: auto; text-align: center; } |
|
30 |
+ .underline { text-decoration: underline; } |
|
31 |
+ #postamble p, #preamble p { font-size: 90%; margin: .2em; } |
|
32 |
+ p.verse { margin-left: 3%; } |
|
33 |
+ pre { |
|
34 |
+ border: 1px solid #e6e6e6; |
|
35 |
+ border-radius: 3px; |
|
36 |
+ background-color: #f2f2f2; |
|
37 |
+ padding: 8pt; |
|
38 |
+ font-family: monospace; |
|
39 |
+ overflow: auto; |
|
40 |
+ margin: 1.2em; |
|
41 |
+ } |
|
42 |
+ pre.src { |
|
43 |
+ position: relative; |
|
44 |
+ overflow: auto; |
|
45 |
+ } |
|
46 |
+ pre.src:before { |
|
47 |
+ display: none; |
|
48 |
+ position: absolute; |
|
49 |
+ top: -8px; |
|
50 |
+ right: 12px; |
|
51 |
+ padding: 3px; |
|
52 |
+ color: #555; |
|
53 |
+ background-color: #f2f2f299; |
|
54 |
+ } |
|
55 |
+ pre.src:hover:before { display: inline; margin-top: 14px;} |
|
56 |
+ /* Languages per Org manual */ |
|
57 |
+ pre.src-asymptote:before { content: 'Asymptote'; } |
|
58 |
+ pre.src-awk:before { content: 'Awk'; } |
|
59 |
+ pre.src-authinfo::before { content: 'Authinfo'; } |
|
60 |
+ pre.src-C:before { content: 'C'; } |
|
61 |
+ /* pre.src-C++ doesn't work in CSS */ |
|
62 |
+ pre.src-clojure:before { content: 'Clojure'; } |
|
63 |
+ pre.src-css:before { content: 'CSS'; } |
|
64 |
+ pre.src-D:before { content: 'D'; } |
|
65 |
+ pre.src-ditaa:before { content: 'ditaa'; } |
|
66 |
+ pre.src-dot:before { content: 'Graphviz'; } |
|
67 |
+ pre.src-calc:before { content: 'Emacs Calc'; } |
|
68 |
+ pre.src-emacs-lisp:before { content: 'Emacs Lisp'; } |
|
69 |
+ pre.src-fortran:before { content: 'Fortran'; } |
|
70 |
+ pre.src-gnuplot:before { content: 'gnuplot'; } |
|
71 |
+ pre.src-haskell:before { content: 'Haskell'; } |
|
72 |
+ pre.src-hledger:before { content: 'hledger'; } |
|
73 |
+ pre.src-java:before { content: 'Java'; } |
|
74 |
+ pre.src-js:before { content: 'Javascript'; } |
|
75 |
+ pre.src-latex:before { content: 'LaTeX'; } |
|
76 |
+ pre.src-ledger:before { content: 'Ledger'; } |
|
77 |
+ pre.src-lisp:before { content: 'Lisp'; } |
|
78 |
+ pre.src-lilypond:before { content: 'Lilypond'; } |
|
79 |
+ pre.src-lua:before { content: 'Lua'; } |
|
80 |
+ pre.src-matlab:before { content: 'MATLAB'; } |
|
81 |
+ pre.src-mscgen:before { content: 'Mscgen'; } |
|
82 |
+ pre.src-ocaml:before { content: 'Objective Caml'; } |
|
83 |
+ pre.src-octave:before { content: 'Octave'; } |
|
84 |
+ pre.src-org:before { content: 'Org mode'; } |
|
85 |
+ pre.src-oz:before { content: 'OZ'; } |
|
86 |
+ pre.src-plantuml:before { content: 'Plantuml'; } |
|
87 |
+ pre.src-processing:before { content: 'Processing.js'; } |
|
88 |
+ pre.src-python:before { content: 'Python'; } |
|
89 |
+ pre.src-R:before { content: 'R'; } |
|
90 |
+ pre.src-ruby:before { content: 'Ruby'; } |
|
91 |
+ pre.src-sass:before { content: 'Sass'; } |
|
92 |
+ pre.src-scheme:before { content: 'Scheme'; } |
|
93 |
+ pre.src-screen:before { content: 'Gnu Screen'; } |
|
94 |
+ pre.src-sed:before { content: 'Sed'; } |
|
95 |
+ pre.src-sh:before { content: 'shell'; } |
|
96 |
+ pre.src-sql:before { content: 'SQL'; } |
|
97 |
+ pre.src-sqlite:before { content: 'SQLite'; } |
|
98 |
+ /* additional languages in org.el's org-babel-load-languages alist */ |
|
99 |
+ pre.src-forth:before { content: 'Forth'; } |
|
100 |
+ pre.src-io:before { content: 'IO'; } |
|
101 |
+ pre.src-J:before { content: 'J'; } |
|
102 |
+ pre.src-makefile:before { content: 'Makefile'; } |
|
103 |
+ pre.src-maxima:before { content: 'Maxima'; } |
|
104 |
+ pre.src-perl:before { content: 'Perl'; } |
|
105 |
+ pre.src-picolisp:before { content: 'Pico Lisp'; } |
|
106 |
+ pre.src-scala:before { content: 'Scala'; } |
|
107 |
+ pre.src-shell:before { content: 'Shell Script'; } |
|
108 |
+ pre.src-ebnf2ps:before { content: 'ebfn2ps'; } |
|
109 |
+ /* additional language identifiers per "defun org-babel-execute" |
|
110 |
+ in ob-*.el */ |
|
111 |
+ pre.src-cpp:before { content: 'C++'; } |
|
112 |
+ pre.src-abc:before { content: 'ABC'; } |
|
113 |
+ pre.src-coq:before { content: 'Coq'; } |
|
114 |
+ pre.src-groovy:before { content: 'Groovy'; } |
|
115 |
+ /* additional language identifiers from org-babel-shell-names in |
|
116 |
+ ob-shell.el: ob-shell is the only babel language using a lambda to put |
|
117 |
+ the execution function name together. */ |
|
118 |
+ pre.src-bash:before { content: 'bash'; } |
|
119 |
+ pre.src-csh:before { content: 'csh'; } |
|
120 |
+ pre.src-ash:before { content: 'ash'; } |
|
121 |
+ pre.src-dash:before { content: 'dash'; } |
|
122 |
+ pre.src-ksh:before { content: 'ksh'; } |
|
123 |
+ pre.src-mksh:before { content: 'mksh'; } |
|
124 |
+ pre.src-posh:before { content: 'posh'; } |
|
125 |
+ /* Additional Emacs modes also supported by the LaTeX listings package */ |
|
126 |
+ pre.src-ada:before { content: 'Ada'; } |
|
127 |
+ pre.src-asm:before { content: 'Assembler'; } |
|
128 |
+ pre.src-caml:before { content: 'Caml'; } |
|
129 |
+ pre.src-delphi:before { content: 'Delphi'; } |
|
130 |
+ pre.src-html:before { content: 'HTML'; } |
|
131 |
+ pre.src-idl:before { content: 'IDL'; } |
|
132 |
+ pre.src-mercury:before { content: 'Mercury'; } |
|
133 |
+ pre.src-metapost:before { content: 'MetaPost'; } |
|
134 |
+ pre.src-modula-2:before { content: 'Modula-2'; } |
|
135 |
+ pre.src-pascal:before { content: 'Pascal'; } |
|
136 |
+ pre.src-ps:before { content: 'PostScript'; } |
|
137 |
+ pre.src-prolog:before { content: 'Prolog'; } |
|
138 |
+ pre.src-simula:before { content: 'Simula'; } |
|
139 |
+ pre.src-tcl:before { content: 'tcl'; } |
|
140 |
+ pre.src-tex:before { content: 'TeX'; } |
|
141 |
+ pre.src-plain-tex:before { content: 'Plain TeX'; } |
|
142 |
+ pre.src-verilog:before { content: 'Verilog'; } |
|
143 |
+ pre.src-vhdl:before { content: 'VHDL'; } |
|
144 |
+ pre.src-xml:before { content: 'XML'; } |
|
145 |
+ pre.src-nxml:before { content: 'XML'; } |
|
146 |
+ /* add a generic configuration mode; LaTeX export needs an additional |
|
147 |
+ (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */ |
|
148 |
+ pre.src-conf:before { content: 'Configuration File'; } |
|
149 |
+ |
|
150 |
+ table { border-collapse:collapse; } |
|
151 |
+ caption.t-above { caption-side: top; } |
|
152 |
+ caption.t-bottom { caption-side: bottom; } |
|
153 |
+ td, th { vertical-align:top; } |
|
154 |
+ th.org-right { text-align: center; } |
|
155 |
+ th.org-left { text-align: center; } |
|
156 |
+ th.org-center { text-align: center; } |
|
157 |
+ td.org-right { text-align: right; } |
|
158 |
+ td.org-left { text-align: left; } |
|
159 |
+ td.org-center { text-align: center; } |
|
160 |
+ dt { font-weight: bold; } |
|
161 |
+ .footpara { display: inline; } |
|
162 |
+ .footdef { margin-bottom: 1em; } |
|
163 |
+ .figure { padding: 1em; } |
|
164 |
+ .figure p { text-align: center; } |
|
165 |
+ .equation-container { |
|
166 |
+ display: table; |
|
167 |
+ text-align: center; |
|
168 |
+ width: 100%; |
|
169 |
+ } |
|
170 |
+ .equation { |
|
171 |
+ vertical-align: middle; |
|
172 |
+ } |
|
173 |
+ .equation-label { |
|
174 |
+ display: table-cell; |
|
175 |
+ text-align: right; |
|
176 |
+ vertical-align: middle; |
|
177 |
+ } |
|
178 |
+ .inlinetask { |
|
179 |
+ padding: 10px; |
|
180 |
+ border: 2px solid gray; |
|
181 |
+ margin: 10px; |
|
182 |
+ background: #ffffcc; |
|
183 |
+ } |
|
184 |
+ #org-div-home-and-up |
|
185 |
+ { text-align: right; font-size: 70%; white-space: nowrap; } |
|
186 |
+ textarea { overflow-x: auto; } |
|
187 |
+ .linenr { font-size: smaller } |
|
188 |
+ .code-highlighted { background-color: #ffff00; } |
|
189 |
+ .org-info-js_info-navigation { border-style: none; } |
|
190 |
+ #org-info-js_console-label |
|
191 |
+ { font-size: 10px; font-weight: bold; white-space: nowrap; } |
|
192 |
+ .org-info-js_search-highlight |
|
193 |
+ { background-color: #ffff00; color: #000000; font-weight: bold; } |
|
194 |
+ .org-svg { width: 90%; } |
|
195 |
+</style> |
|
196 |
+<link rel="stylesheet" href="./colors.css"></link> |
|
197 |
+</head> |
|
198 |
+<body> |
|
199 |
+<div id="content" class="content"> |
|
200 |
+<h1 class="title">README for js-generic-functions</h1> |
|
201 |
+<div id="table-of-contents" role="doc-toc"> |
|
202 |
+<h2>Table of Contents</h2> |
|
203 |
+<div id="text-table-of-contents" role="doc-toc"> |
|
204 |
+<ul> |
|
205 |
+<li><a href="#orgfafc37c">1. What is this?</a></li> |
|
206 |
+<li><a href="#org9f23f39">2. Docs</a> |
|
207 |
+<ul> |
|
208 |
+<li><a href="#orgd157493">2.1. Basic Usage</a></li> |
|
209 |
+<li><a href="#orgfff236b">2.2. Other sorts of specializers</a></li> |
|
210 |
+</ul> |
|
211 |
+</li> |
|
212 |
+</ul> |
|
213 |
+</div> |
|
214 |
+</div> |
|
215 |
+ |
|
216 |
+<div id="outline-container-orgfafc37c" class="outline-2"> |
|
217 |
+<h2 id="orgfafc37c"><span class="section-number-2">1.</span> What is this?</h2> |
|
218 |
+<div class="outline-text-2" id="text-1"> |
|
219 |
+<p> |
|
220 |
+An implementation of generic functions based on CLOS and the protocols |
|
221 |
+defined in the Art of the Metaobject protocol, adapted for JS. These |
|
222 |
+adaptations include using the prototype chain instead of classes and |
|
223 |
+additionally providing extensible specializers (as in |
|
224 |
+<a href="https://github.com/sbcl/specializable">https://github.com/sbcl/specializable</a>). For the moment, this is only |
|
225 |
+used to provide a Shape specializer, as the details of the interaction |
|
226 |
+between such specializers and subtyping are an open question. |
|
227 |
+</p> |
|
228 |
+</div> |
|
229 |
+</div> |
|
230 |
+ |
|
231 |
+<div id="outline-container-org9f23f39" class="outline-2"> |
|
232 |
+<h2 id="org9f23f39"><span class="section-number-2">2.</span> Docs</h2> |
|
233 |
+<div class="outline-text-2" id="text-2"> |
|
234 |
+</div> |
|
235 |
+<div id="outline-container-orgd157493" class="outline-3"> |
|
236 |
+<h3 id="orgd157493"><span class="section-number-3">2.1.</span> Basic Usage</h3> |
|
237 |
+<div class="outline-text-3" id="text-2-1"> |
|
238 |
+<div class="org-src-container"> |
|
239 |
+<pre class="src src-js" id="org5053093"><span style="color: #F0DFAF;">import</span> { defgeneric } from <span style="color: #D0BF8F;">"./genfuns.js"</span>; |
|
240 |
+</pre> |
|
241 |
+</div> |
|
242 |
+ |
|
243 |
+<p> |
|
244 |
+Defining a function works by calling with some |
|
245 |
+information about the function name and arguments. Methods are then |
|
246 |
+added by calling the appropriate methods with a pair of arguments: a |
|
247 |
+list of specializers (prototypes in the simple case, although there |
|
248 |
+are other options) and a function to run if those specializers match. |
|
249 |
+</p> |
|
250 |
+ |
|
251 |
+<div class="org-src-container"> |
|
252 |
+<pre class="src src-js" id="orgbfcefb2"><span style="color: #F0DFAF;">const</span> <span style="color: #DC8CC3;">example1generic</span> = defgeneric(<span style="color: #D0BF8F;">"example1"</span>, <span style="color: #D0BF8F;">"a"</span>, <span style="color: #D0BF8F;">"b"</span>) |
|
253 |
+ .primary([Number, Object], (n, __) => [1, n]) |
|
254 |
+ .primary([Object, Number], (_, n) => [2, n]) |
|
255 |
+ .primary([Object, Object], (_, __) => [5, <span style="font-weight: bold;">null</span>]); |
|
256 |
+</pre> |
|
257 |
+</div> |
|
258 |
+ |
|
259 |
+<p> |
|
260 |
+After a generic function has been defined, you can get the function to |
|
261 |
+call it by accessing its attribute. |
|
262 |
+</p> |
|
263 |
+ |
|
264 |
+<div class="org-src-container"> |
|
265 |
+<pre class="src src-js" id="orgcb5dfea"><span style="color: #F0DFAF;">const</span> <span style="color: #DC8CC3;">example1</span> = example1generic.fn; |
|
266 |
+ |
|
267 |
+expect(example1(5, {})).toEqual([1, 5]); |
|
268 |
+expect(example1({}, 6)).toEqual([2, 6]); |
|
269 |
+expect(example1(<span style="color: #D0BF8F;">"hello"</span>, {})).toEqual([5, <span style="font-weight: bold;">null</span>]); |
|
270 |
+expect(example1({}, <span style="color: #D0BF8F;">"world"</span>)).toEqual([5, <span style="font-weight: bold;">null</span>]); |
|
271 |
+expect(example1({}, {})).toEqual([5, <span style="font-weight: bold;">null</span>]); |
|
272 |
+</pre> |
|
273 |
+</div> |
|
274 |
+ |
|
275 |
+<p> |
|
276 |
+If a separate reference to the generic function object is maintained, |
|
277 |
+you can add methods like so: |
|
278 |
+</p> |
|
279 |
+ |
|
280 |
+<div class="org-src-container"> |
|
281 |
+<pre class="src src-js" id="orgda77441">example1generic |
|
282 |
+ .primary([String, Object], (s, __) => [3, s]) |
|
283 |
+ .primary([Object, String], (_, s) => [4, s]); |
|
284 |
+ |
|
285 |
+expect(example1(<span style="color: #D0BF8F;">"hello"</span>, {})).toEqual([3, <span style="color: #D0BF8F;">"hello"</span>]); |
|
286 |
+expect(example1({}, <span style="color: #D0BF8F;">"world"</span>)).toEqual([4, <span style="color: #D0BF8F;">"world"</span>]); |
|
287 |
+</pre> |
|
288 |
+</div> |
|
289 |
+</div> |
|
290 |
+</div> |
|
291 |
+ |
|
292 |
+<div id="outline-container-orgfff236b" class="outline-3"> |
|
293 |
+<h3 id="orgfff236b"><span class="section-number-3">2.2.</span> Other sorts of specializers</h3> |
|
294 |
+<div class="outline-text-3" id="text-2-2"> |
|
295 |
+<div class="org-src-container"> |
|
296 |
+<pre class="src src-js" id="org0346038"><span style="color: #F0DFAF;">import</span> { Shape, Eql } from <span style="color: #D0BF8F;">"./genfuns.js"</span>; |
|
297 |
+</pre> |
|
298 |
+</div> |
|
299 |
+ |
|
300 |
+ |
|
301 |
+ |
|
302 |
+<div class="org-src-container"> |
|
303 |
+<pre class="src src-js" id="org89b4645"><span style="color: #F0DFAF;">const</span> <span style="color: #DC8CC3;">example2</span> = defgeneric(<span style="color: #D0BF8F;">"example2"</span>, <span style="color: #D0BF8F;">"inp"</span>) |
|
304 |
+ .primary([Shape(<span style="color: #D0BF8F;">"a"</span>, <span style="color: #D0BF8F;">"b"</span>)], inp => <span style="color: #D0BF8F;">`a: ${inp.a} b: ${inp.b}`</span>) |
|
305 |
+ .primary([Shape(<span style="color: #D0BF8F;">"a"</span>)], inp => <span style="color: #D0BF8F;">`a: ${inp.a} b: <missing>`</span>) |
|
306 |
+ .primary([Shape([<span style="color: #D0BF8F;">"c"</span>, 1])], inp => <span style="color: #D0BF8F;">`c: one`</span>) |
|
307 |
+ .primary([Shape([<span style="color: #D0BF8F;">"c"</span>, 2])], inp => <span style="color: #D0BF8F;">`c: two`</span>) |
|
308 |
+ .primary([Eql(1)], inp => <span style="color: #D0BF8F;">"one"</span>).fn; |
|
309 |
+ |
|
310 |
+expect(example2({ a: 3, q: <span style="color: #D0BF8F;">"whatever"</span> })).toEqual(<span style="color: #D0BF8F;">"a: 3 b: <missing>"</span>); |
|
311 |
+expect(example2({ a: 3, b: 4, q: <span style="color: #D0BF8F;">"whatever"</span> })).toEqual(<span style="color: #D0BF8F;">"a: 3 b: 4"</span>); |
|
312 |
+expect(example2({ c: 1, q: <span style="color: #D0BF8F;">"whatever"</span> })).toEqual(<span style="color: #D0BF8F;">"c: one"</span>); |
|
313 |
+expect(example2({ c: 2, q: <span style="color: #D0BF8F;">"whatever"</span> })).toEqual(<span style="color: #D0BF8F;">"c: two"</span>); |
|
314 |
+expect(example2(1)).toEqual(<span style="color: #D0BF8F;">"one"</span>); |
|
315 |
+</pre> |
|
316 |
+</div> |
|
317 |
+</div> |
|
318 |
+</div> |
|
319 |
+</div> |
|
320 |
+</div> |
|
321 |
+<div id="postamble" class="status"> |
|
322 |
+<p class="author">Author: Ed L</p> |
|
323 |
+<p class="date">Created: 2022-03-16 Wed 01:22</p> |
|
324 |
+<p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p> |
|
325 |
+</div> |
|
326 |
+</body> |
|
327 |
+</html> |
0 | 328 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,56 @@ |
1 |
+// [[file:../README.org::*Other sorts of specializers][Other sorts of specializers:3]] |
|
2 |
+// [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::imports][imports]]][imports]] |
|
3 |
+import { defgeneric } from "./genfuns.js"; |
|
4 |
+// imports ends here |
|
5 |
+// [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::specializer-import][specializer-import]]][specializer-import]] |
|
6 |
+import { Shape, Eql } from "./genfuns.js"; |
|
7 |
+// specializer-import ends here |
|
8 |
+ |
|
9 |
+describe("defgeneric", () => { |
|
10 |
+ test("methods get called appropriately", () => { |
|
11 |
+ // [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::basic-definition][basic-definition]]][basic-definition]] |
|
12 |
+ const example1generic = defgeneric("example1", "a", "b") |
|
13 |
+ .primary([Number, Object], (n, __) => [1, n]) |
|
14 |
+ .primary([Object, Number], (_, n) => [2, n]) |
|
15 |
+ .primary([Object, Object], (_, __) => [5, null]); |
|
16 |
+ // basic-definition ends here |
|
17 |
+ |
|
18 |
+ // [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::call-the-function][call-the-function]]][call-the-function]] |
|
19 |
+ const example1 = example1generic.fn; |
|
20 |
+ |
|
21 |
+ expect(example1(5, {})).toEqual([1, 5]); |
|
22 |
+ expect(example1({}, 6)).toEqual([2, 6]); |
|
23 |
+ expect(example1("hello", {})).toEqual([5, null]); |
|
24 |
+ expect(example1({}, "world")).toEqual([5, null]); |
|
25 |
+ expect(example1({}, {})).toEqual([5, null]); |
|
26 |
+ // call-the-function ends here |
|
27 |
+ |
|
28 |
+ // [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::add-methods][add-methods]]][add-methods]] |
|
29 |
+ example1generic |
|
30 |
+ .primary([String, Object], (s, __) => [3, s]) |
|
31 |
+ .primary([Object, String], (_, s) => [4, s]); |
|
32 |
+ |
|
33 |
+ expect(example1("hello", {})).toEqual([3, "hello"]); |
|
34 |
+ expect(example1({}, "world")).toEqual([4, "world"]); |
|
35 |
+ // add-methods ends here |
|
36 |
+ |
|
37 |
+ |
|
38 |
+ }); |
|
39 |
+ test ('specializers work as expected', () => { |
|
40 |
+ // [[[[file:~/git_repos/git.fiddlerwoaroof.com/js-generic-functions/README.org::specializer-examples][specializer-examples]]][specializer-examples]] |
|
41 |
+ const example2 = defgeneric("example2", "inp") |
|
42 |
+ .primary([Shape("a", "b")], inp => `a: ${inp.a} b: ${inp.b}`) |
|
43 |
+ .primary([Shape("a")], inp => `a: ${inp.a} b: <missing>`) |
|
44 |
+ .primary([Shape(["c", 1])], inp => `c: one`) |
|
45 |
+ .primary([Shape(["c", 2])], inp => `c: two`) |
|
46 |
+ .primary([Eql(1)], inp => "one").fn; |
|
47 |
+ |
|
48 |
+ expect(example2({ a: 3, q: "whatever" })).toEqual("a: 3 b: <missing>"); |
|
49 |
+ expect(example2({ a: 3, b: 4, q: "whatever" })).toEqual("a: 3 b: 4"); |
|
50 |
+ expect(example2({ c: 1, q: "whatever" })).toEqual("c: one"); |
|
51 |
+ expect(example2({ c: 2, q: "whatever" })).toEqual("c: two"); |
|
52 |
+ expect(example2(1)).toEqual("one"); |
|
53 |
+ // specializer-examples ends here |
|
54 |
+ }) |
|
55 |
+}); |
|
56 |
+// Other sorts of specializers:3 ends here |