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.
@@ -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")