anatomy 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.md +201 -0
- data/bin/anatomy +5 -0
- data/lib/anatomy/atomy.ay +202 -0
- data/lib/anatomy/base.ay +151 -0
- data/lib/anatomy/cmd.ay +60 -0
- data/lib/anatomy/data.ay +147 -0
- data/lib/anatomy/html.ay +73 -0
- data/lib/anatomy/language/parser.ay +130 -0
- data/lib/anatomy/processor.ay +35 -0
- data/lib/anatomy/renderers/html.ay +306 -0
- data/lib/anatomy/ruby.ay +178 -0
- data/lib/anatomy/server.ay +80 -0
- data/lib/anatomy/slides.ay +48 -0
- data/lib/anatomy/stages/collect.ay +35 -0
- data/lib/anatomy/stages/meta.ay +100 -0
- data/lib/anatomy/stages/resolve.ay +55 -0
- data/lib/anatomy/stages/traverse.ay +34 -0
- data/lib/anatomy.ay +4 -0
- data/public/anatomy.css +427 -0
- data/public/highlight.css +60 -0
- data/public/jquery.hotkeys.js +99 -0
- data/public/jquery.js +16 -0
- data/public/main.js +237 -0
- metadata +110 -0
data/lib/anatomy/ruby.ay
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
use("atomy")
|
2
|
+
|
3
|
+
require("stringio")
|
4
|
+
|
5
|
+
hl = require("hl")
|
6
|
+
token = require("hl/token")
|
7
|
+
ruby = hl load("ruby")
|
8
|
+
|
9
|
+
use("anatomy/html")
|
10
|
+
base = require("anatomy/base")
|
11
|
+
data = require("anatomy/data")
|
12
|
+
|
13
|
+
def = require("define")
|
14
|
+
|
15
|
+
|
16
|
+
fn(format-inline(tokens, link-only = nil)):
|
17
|
+
tokens collect [t]:
|
18
|
+
data Element new(
|
19
|
+
-- constants, identifiers, and operators
|
20
|
+
if((link-only && link-only include?(t contents)) ||
|
21
|
+
(!link-only && ["no", "nf", "n", "o"] include?(t type tag)))
|
22
|
+
then:
|
23
|
+
data ResolveElement new(
|
24
|
+
[part]:
|
25
|
+
tag = part find-tag(t contents)
|
26
|
+
if(tag)
|
27
|
+
then: data Reference new(tag, t contents)
|
28
|
+
else: t contents)
|
29
|
+
else: t contents
|
30
|
+
.class(t type tag))
|
31
|
+
|
32
|
+
|
33
|
+
fn(format-block(tokens, link-only = nil)):
|
34
|
+
data Block new(
|
35
|
+
base verbatim(format-inline(tokens, link-only))
|
36
|
+
.class("highlight"))
|
37
|
+
|
38
|
+
|
39
|
+
fn(with-all-output-to(out, err) &action):
|
40
|
+
before-out = $stdout
|
41
|
+
before-err = $stderr
|
42
|
+
|
43
|
+
{ $stdout = out
|
44
|
+
$stderr = err
|
45
|
+
|
46
|
+
action call
|
47
|
+
} ensuring:
|
48
|
+
$stdout = before-out
|
49
|
+
$stderr = before-err
|
50
|
+
|
51
|
+
|
52
|
+
fn(interactive-line(bnd, input, line, context)):
|
53
|
+
out = StringIO new
|
54
|
+
err = StringIO new
|
55
|
+
|
56
|
+
output-tokens =
|
57
|
+
with-restarts(use-tokens(ts): ts) {
|
58
|
+
res =
|
59
|
+
with-all-output-to(out, err):
|
60
|
+
bnd eval(input)
|
61
|
+
|
62
|
+
-- shorten the long-form inspections that show the ivars
|
63
|
+
ruby lex(res inspect sub(r"#<([^\s]+)\s+@.*$", "#<\\1>"))
|
64
|
+
} bind:
|
65
|
+
(e & Error):
|
66
|
+
restart(
|
67
|
+
.use-tokens
|
68
|
+
[ token Token new(
|
69
|
+
token Tagged new(.gr)
|
70
|
+
i"#{e name}: #{e message}")
|
71
|
+
])
|
72
|
+
|
73
|
+
[ format-inline(
|
74
|
+
token Token new(token Tagged new(.caret), "> ") .
|
75
|
+
ruby lex(input))
|
76
|
+
"\n"
|
77
|
+
out string
|
78
|
+
unless(err string empty?):
|
79
|
+
data Element new(err string, .class("gr"))
|
80
|
+
format-inline(output-tokens)
|
81
|
+
"\n"
|
82
|
+
]
|
83
|
+
|
84
|
+
|
85
|
+
environments = #{}
|
86
|
+
fn(new-interaction-env): binding
|
87
|
+
fn(take-environment(name)):
|
88
|
+
if(name)
|
89
|
+
then:
|
90
|
+
environments[name] ||= new-interaction-env
|
91
|
+
else:
|
92
|
+
new-interaction-env
|
93
|
+
|
94
|
+
|
95
|
+
def(hl(x)): base code(format-inline(ruby new(x) run))
|
96
|
+
|
97
|
+
def(ruby(x)): format-block(ruby new(x) run)
|
98
|
+
|
99
|
+
|
100
|
+
def(evaluate(code, where = nil)):
|
101
|
+
with-restarts(err(msg): data Element new(msg, .class("gr"))) {
|
102
|
+
take-environment(where) eval(code)
|
103
|
+
nil
|
104
|
+
} bind:
|
105
|
+
(e & Error):
|
106
|
+
/restart(.err, i"#{e name}: #{e message}")
|
107
|
+
|
108
|
+
|
109
|
+
def(interaction(x, where = nil)):
|
110
|
+
bnd = take-environment(where)
|
111
|
+
|
112
|
+
data Block new(
|
113
|
+
data Block new(
|
114
|
+
x split("\n") collect with-index [input, line]:
|
115
|
+
interactive-line(bnd, input, line + 1, where)
|
116
|
+
.tt)
|
117
|
+
.class("interaction"))
|
118
|
+
|
119
|
+
|
120
|
+
def(example(x, where = nil)):
|
121
|
+
data Block new(
|
122
|
+
[ data Paragraph new([data Element new("Example:", .italic)])
|
123
|
+
interaction(x, where)
|
124
|
+
]
|
125
|
+
.class("example"))
|
126
|
+
|
127
|
+
|
128
|
+
def(example-segment(x)):
|
129
|
+
data Block new(
|
130
|
+
[ data Paragraph new([data Element new("Example:", .italic)])
|
131
|
+
format-block(ruby new(x) run)
|
132
|
+
]
|
133
|
+
.class("example"))
|
134
|
+
|
135
|
+
|
136
|
+
def(define(what, *rules, returns, body)):
|
137
|
+
thumb = what to-ast
|
138
|
+
|
139
|
+
message-name = thumb name to-s
|
140
|
+
|
141
|
+
display = format-inline(ruby lex(what), [message-name])
|
142
|
+
data Block new(
|
143
|
+
[ base target-element(message-name)
|
144
|
+
data Block new(
|
145
|
+
[ data Block new(
|
146
|
+
[ display
|
147
|
+
data Element new(
|
148
|
+
" => "
|
149
|
+
.class("definition_result_arrow"))
|
150
|
+
format-inline(ruby lex(returns))
|
151
|
+
rules collect [rule]:
|
152
|
+
["\n | ", format-inline(ruby lex(rule))]
|
153
|
+
]
|
154
|
+
.tt)
|
155
|
+
]
|
156
|
+
.class("thumb"))
|
157
|
+
body
|
158
|
+
]
|
159
|
+
.class("definition"))
|
160
|
+
|
161
|
+
def(assign(name, to, body)):
|
162
|
+
display = format-inline(ruby lex(name), [name])
|
163
|
+
data Block new(
|
164
|
+
[ base target-element(name)
|
165
|
+
data Block new(
|
166
|
+
[ data Block new(
|
167
|
+
[ display
|
168
|
+
data Element new(
|
169
|
+
" = "
|
170
|
+
.class("definition_result_arrow"))
|
171
|
+
format-inline(ruby lex(to))
|
172
|
+
]
|
173
|
+
.tt)
|
174
|
+
]
|
175
|
+
.class("thumb"))
|
176
|
+
body
|
177
|
+
]
|
178
|
+
.class("definition", "assign"))
|
@@ -0,0 +1,80 @@
|
|
1
|
+
use(require("atomy"))
|
2
|
+
|
3
|
+
require("webrick")
|
4
|
+
|
5
|
+
-- shim in svg content-type support
|
6
|
+
WEBrick HTTPUtils DefaultMimeTypes["svg"] = "image/svg+xml"
|
7
|
+
|
8
|
+
class(Server):
|
9
|
+
def(initialize(@source, @destination, @processor, @renderer)):
|
10
|
+
@mutex = Mutex new
|
11
|
+
|
12
|
+
def(Server serve(port)):
|
13
|
+
server = WEBrick HTTPServer new(#{.Port -> port})
|
14
|
+
|
15
|
+
server mount-proc("/") [req, res]:
|
16
|
+
relative-path = req path sub(r"^\/", "")
|
17
|
+
local-abs-path = File absolute-path(relative-path, @destination)
|
18
|
+
|
19
|
+
if(relative-path == "favicon.ico")
|
20
|
+
then: respond-to-favicon(res)
|
21
|
+
else: respond-to-path(res, relative-path, local-abs-path)
|
22
|
+
|
23
|
+
trap("INT"): server shutdown
|
24
|
+
|
25
|
+
server start
|
26
|
+
|
27
|
+
def(Server respond-to-favicon(res)):
|
28
|
+
res status = 404
|
29
|
+
|
30
|
+
def(Server respond-to-path(res, relative-path, local-abs-path)):
|
31
|
+
do {
|
32
|
+
rebuild-if-needed
|
33
|
+
|
34
|
+
if(File directory?(local-abs-path))
|
35
|
+
then: respond-to-file(res, File join(local-abs-path, "index.html"))
|
36
|
+
else: respond-to-file(res, local-abs-path)
|
37
|
+
} rescue:
|
38
|
+
e:
|
39
|
+
message = i"#{e to-s}\n#{Rubinius Backtrace backtrace(e locations) show}"
|
40
|
+
puts(message)
|
41
|
+
respond-with-error(res, message)
|
42
|
+
|
43
|
+
def(Server respond-with-error(res, message)):
|
44
|
+
res content-type = "text/html"
|
45
|
+
res body = i"<pre>#{message}</pre>"
|
46
|
+
|
47
|
+
def(Server respond-to-file(res, local-abs-path)):
|
48
|
+
res body = File read(local-abs-path)
|
49
|
+
res content-type = guess-content-type(local-abs-path)
|
50
|
+
|
51
|
+
def(Server guess-content-type(path)):
|
52
|
+
extension = File extname(path) sub(r"^\.", "")
|
53
|
+
WEBrick HTTPUtils DefaultMimeTypes fetch(extension):
|
54
|
+
"application/octet-stream"
|
55
|
+
|
56
|
+
def(Server rebuild-if-needed):
|
57
|
+
-- Webrick is multi-threaded; guard against concurrent builds
|
58
|
+
@mutex synchronize:
|
59
|
+
when(@last-disk-state == disk-state):
|
60
|
+
return
|
61
|
+
|
62
|
+
puts(i"---------------- rebuilding #{@source}")
|
63
|
+
|
64
|
+
-- clear out already-loaded document modules
|
65
|
+
$LOADED_FEATURES reject! &.end-with?(".any")
|
66
|
+
|
67
|
+
@processor process(@source, @renderer, @destination)
|
68
|
+
|
69
|
+
-- Save disk state after rebuilding, to ignore the built artifacts
|
70
|
+
-- themselves
|
71
|
+
@last-disk-state = disk-state
|
72
|
+
|
73
|
+
-- TODO: if this is defined in the class: we get an unknown constant 'Particle'
|
74
|
+
def(Server disk-state):
|
75
|
+
-- collect disk state of files surrounding input file
|
76
|
+
Dir glob(File expand-path("../**/*", @source)) collect &.(
|
77
|
+
File absolute-path(_)
|
78
|
+
) collect [path] {
|
79
|
+
[path, File stat(path) mtime to-s]
|
80
|
+
} sort
|
@@ -0,0 +1,48 @@
|
|
1
|
+
use(require("atomy"))
|
2
|
+
|
3
|
+
data = require("anatomy/data")
|
4
|
+
|
5
|
+
|
6
|
+
def(slides):
|
7
|
+
data MetaBlock new(
|
8
|
+
[part]:
|
9
|
+
part style properties << .slides)
|
10
|
+
|
11
|
+
|
12
|
+
def(title-slide(title)):
|
13
|
+
data Block new(
|
14
|
+
data Block new(title, .header(1))
|
15
|
+
.class("slide title_only"))
|
16
|
+
|
17
|
+
def(title-slide(title, subtitle)):
|
18
|
+
data Block new(
|
19
|
+
data Block new(
|
20
|
+
[ data Block new(title, .header(1))
|
21
|
+
subtitle
|
22
|
+
]
|
23
|
+
.class("body"))
|
24
|
+
.class("slide title"))
|
25
|
+
|
26
|
+
|
27
|
+
def(slide(title, body)):
|
28
|
+
data Block new(
|
29
|
+
data Block new(
|
30
|
+
[ data Block new(title, .header(2))
|
31
|
+
body
|
32
|
+
]
|
33
|
+
.class("body"))
|
34
|
+
.class("slide"))
|
35
|
+
|
36
|
+
def(detail(title, body)):
|
37
|
+
data Block new(
|
38
|
+
data Block new(
|
39
|
+
[ data Block new(
|
40
|
+
[ title
|
41
|
+
" "
|
42
|
+
data Element new("(cont'd)", .class("continue"))
|
43
|
+
]
|
44
|
+
.header(2))
|
45
|
+
body
|
46
|
+
]
|
47
|
+
.class("body"))
|
48
|
+
.class("slide continue"))
|
@@ -0,0 +1,35 @@
|
|
1
|
+
-- scan the Part for any tags it defines, attaching them to a copied Part
|
2
|
+
-- go into sub-parts and do the same
|
3
|
+
|
4
|
+
use(require("atomy"))
|
5
|
+
|
6
|
+
data = require("anatomy/data")
|
7
|
+
|
8
|
+
|
9
|
+
def(pass(a & Array, part)):
|
10
|
+
a collect [x]: pass(x, part)
|
11
|
+
|
12
|
+
def(pass(c & data CollectElement, part)):
|
13
|
+
c action[part]
|
14
|
+
|
15
|
+
def(pass(p & data Paragraph, part)):
|
16
|
+
p dup tap [x]:
|
17
|
+
x content = pass(p content, part)
|
18
|
+
|
19
|
+
def(pass(nil, _)): nil
|
20
|
+
|
21
|
+
def(pass(s & String, _)): s
|
22
|
+
|
23
|
+
def(pass(e & data Element, part)):
|
24
|
+
e dup tap [x]:
|
25
|
+
x content = pass(e content, part)
|
26
|
+
|
27
|
+
def(pass(b & data Block, part)):
|
28
|
+
b dup tap [x]:
|
29
|
+
x content = pass(b content, part)
|
30
|
+
|
31
|
+
|
32
|
+
def(over(part)):
|
33
|
+
part body = pass(part body, part)
|
34
|
+
part parts each [sub]: over(sub)
|
35
|
+
part
|
@@ -0,0 +1,100 @@
|
|
1
|
+
-- build paragraphs, set title info, add sub-parts
|
2
|
+
|
3
|
+
use(require("atomy"))
|
4
|
+
|
5
|
+
data = require("anatomy/data")
|
6
|
+
|
7
|
+
|
8
|
+
fn(close-paragraph(body)):
|
9
|
+
when(body last is-a?(data Paragraph)):
|
10
|
+
body last closed? = true
|
11
|
+
|
12
|
+
fn(ensure-paragraph(body)):
|
13
|
+
unless(body last is-a?(data Paragraph) && !(body last closed?)):
|
14
|
+
body << data Paragraph new([])
|
15
|
+
|
16
|
+
fn(add-content-to(str & String, body)):
|
17
|
+
str split("\n\n", 2) match:
|
18
|
+
[{ chomp empty? }, rest]:
|
19
|
+
close-paragraph(body)
|
20
|
+
add-content-to(rest, body)
|
21
|
+
|
22
|
+
[content, rest]:
|
23
|
+
ensure-paragraph(body)
|
24
|
+
body last content << content
|
25
|
+
close-paragraph(body)
|
26
|
+
add-content-to(rest, body)
|
27
|
+
|
28
|
+
[content]:
|
29
|
+
ensure-paragraph(body)
|
30
|
+
body last content << content
|
31
|
+
|
32
|
+
[]:
|
33
|
+
close-paragraph(body)
|
34
|
+
|
35
|
+
fn(add-content-to(x, body)):
|
36
|
+
ensure-paragraph(body)
|
37
|
+
body last content << x
|
38
|
+
|
39
|
+
|
40
|
+
def(pass(m & data MetaBlock, part, body = part body)):
|
41
|
+
m action[part]
|
42
|
+
nil
|
43
|
+
|
44
|
+
def(pass(a & Array, part, body = part body)):
|
45
|
+
a each [x]:
|
46
|
+
pass(x, part, body)
|
47
|
+
|
48
|
+
nil
|
49
|
+
|
50
|
+
def(pass(p & data Part, part, body = part body)):
|
51
|
+
part parts << p
|
52
|
+
p parent = part
|
53
|
+
part body freeze
|
54
|
+
nil
|
55
|
+
|
56
|
+
def(pass(i & data Itemization, part, body = part body)):
|
57
|
+
unless(body frozen?):
|
58
|
+
body <<
|
59
|
+
i dup tap [x]:
|
60
|
+
x elements collect! [n, b]:
|
61
|
+
body = []
|
62
|
+
pass(b, part, body)
|
63
|
+
[n, body]
|
64
|
+
|
65
|
+
def(pass(l & data List, part, body = part body)):
|
66
|
+
unless(body frozen?):
|
67
|
+
body <<
|
68
|
+
l dup tap [x]:
|
69
|
+
x elements collect! [b]:
|
70
|
+
body = []
|
71
|
+
pass(b, part, body)
|
72
|
+
body
|
73
|
+
|
74
|
+
def(pass(b & data Block, part, body = part body)):
|
75
|
+
unless(body frozen?):
|
76
|
+
body <<
|
77
|
+
b style match:
|
78
|
+
.tt: b
|
79
|
+
|
80
|
+
.verbatim: b
|
81
|
+
|
82
|
+
.header(_): b
|
83
|
+
|
84
|
+
_:
|
85
|
+
b dup tap [x]:
|
86
|
+
x content = []
|
87
|
+
pass(b content, part, x content)
|
88
|
+
|
89
|
+
def(pass(x, part, body = part body)):
|
90
|
+
condition:
|
91
|
+
body frozen?: nil
|
92
|
+
|
93
|
+
data content?(x):
|
94
|
+
add-content-to(x, body)
|
95
|
+
|
96
|
+
otherwise:
|
97
|
+
body << x
|
98
|
+
|
99
|
+
def(over(x, part)):
|
100
|
+
pass(x, part, part body)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
use(require("atomy"))
|
2
|
+
|
3
|
+
data = require("anatomy/data")
|
4
|
+
|
5
|
+
def(pass(a & Array, part)):
|
6
|
+
a collect [x]: pass(x, part)
|
7
|
+
|
8
|
+
def(pass(c & data ResolveElement, part)):
|
9
|
+
pass(c action[part], part)
|
10
|
+
|
11
|
+
def(pass(x & (data Reference | data Target), part)):
|
12
|
+
x
|
13
|
+
|
14
|
+
def(pass(e & data Element, part)):
|
15
|
+
unless(e class == data Element):
|
16
|
+
warning(.did-not-traverse(e class))
|
17
|
+
|
18
|
+
e dup tap [x]:
|
19
|
+
x content = pass(e content, part)
|
20
|
+
|
21
|
+
def(pass(i & data Itemization, part)):
|
22
|
+
i dup tap [x]:
|
23
|
+
x elements = i elements collect [name, body]:
|
24
|
+
[ pass(name, part)
|
25
|
+
pass(body, part)
|
26
|
+
]
|
27
|
+
|
28
|
+
def(pass(l & data List, part)):
|
29
|
+
l dup tap [x]:
|
30
|
+
x elements = l elements collect [body]:
|
31
|
+
pass(body, part)
|
32
|
+
|
33
|
+
def(pass(p & data Paragraph, part)):
|
34
|
+
p dup tap [x]:
|
35
|
+
x content = pass(p content, part)
|
36
|
+
|
37
|
+
def(pass(c & data ResolveBlock, part)):
|
38
|
+
pass(c action[part], part)
|
39
|
+
|
40
|
+
def(pass(b & data Block, part)):
|
41
|
+
unless(b class == data Block):
|
42
|
+
warning(.did-not-traverse(b class))
|
43
|
+
|
44
|
+
b dup tap [x]:
|
45
|
+
x content = pass(b content, part)
|
46
|
+
|
47
|
+
def(pass(s & String, _)): s
|
48
|
+
|
49
|
+
def(pass(nil, _)): nil
|
50
|
+
|
51
|
+
|
52
|
+
def(over(part)):
|
53
|
+
part body = pass(part body, part)
|
54
|
+
part parts each [sub]: over(sub)
|
55
|
+
part
|
@@ -0,0 +1,34 @@
|
|
1
|
+
use(require("atomy"))
|
2
|
+
|
3
|
+
data = require("anatomy/data")
|
4
|
+
|
5
|
+
|
6
|
+
def(pass(a & Array, info)):
|
7
|
+
a collect [x]: pass(x, info)
|
8
|
+
|
9
|
+
def(pass(x & (data TraverseBlock | data TraverseElement), info)):
|
10
|
+
new = x action[info]
|
11
|
+
|
12
|
+
when(new != x):
|
13
|
+
signal(.changed)
|
14
|
+
|
15
|
+
new
|
16
|
+
|
17
|
+
def(pass(x, _)): x
|
18
|
+
|
19
|
+
|
20
|
+
def(over(part)):
|
21
|
+
info = #{}
|
22
|
+
|
23
|
+
changed? = true
|
24
|
+
while(changed?):
|
25
|
+
&changed? = false
|
26
|
+
|
27
|
+
(part body = pass(part body, info)) bind:
|
28
|
+
.changed:
|
29
|
+
&changed? = true
|
30
|
+
|
31
|
+
part parts each [p]:
|
32
|
+
over(p)
|
33
|
+
|
34
|
+
part
|
data/lib/anatomy.ay
ADDED