anatomy 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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