anatomy 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,4 @@
1
+ use("atomy")
2
+
3
+ traverse = require("anatomy/stages/traverse")
4
+ collect = require("anatomy/stages/collect")