glyph 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/README.textile +80 -0
  2. data/Rakefile +51 -0
  3. data/VERSION +1 -0
  4. data/bin/glyph +7 -0
  5. data/book/config.yml +5 -0
  6. data/book/document.glyph +55 -0
  7. data/book/images/glyph.png +0 -0
  8. data/book/images/glyph.svg +351 -0
  9. data/book/lib/macros/reference.rb +98 -0
  10. data/book/output/html/glyph.html +1809 -0
  11. data/book/output/html/images/glyph.png +0 -0
  12. data/book/output/html/images/glyph.svg +351 -0
  13. data/book/output/pdf/glyph.pdf +4277 -0
  14. data/book/snippets.yml +13 -0
  15. data/book/styles/css3.css +220 -0
  16. data/book/styles/default.css +190 -0
  17. data/book/text/authoring.textile +351 -0
  18. data/book/text/extending.textile +148 -0
  19. data/book/text/getting_started.textile +152 -0
  20. data/book/text/introduction.textile +88 -0
  21. data/book/text/ref_commands.textile +74 -0
  22. data/book/text/ref_config.textile +0 -0
  23. data/book/text/ref_macros.textile +256 -0
  24. data/book/text/troubleshooting.textile +118 -0
  25. data/config.yml +63 -0
  26. data/document.glyph +29 -0
  27. data/glyph.gemspec +138 -0
  28. data/lib/glyph.rb +128 -0
  29. data/lib/glyph/commands.rb +124 -0
  30. data/lib/glyph/config.rb +152 -0
  31. data/lib/glyph/document.rb +145 -0
  32. data/lib/glyph/glyph_language.rb +530 -0
  33. data/lib/glyph/glyph_language.treetop +27 -0
  34. data/lib/glyph/interpreter.rb +84 -0
  35. data/lib/glyph/macro.rb +69 -0
  36. data/lib/glyph/node.rb +126 -0
  37. data/lib/glyph/system_extensions.rb +77 -0
  38. data/macros/common.rb +66 -0
  39. data/macros/filters.rb +69 -0
  40. data/macros/html/block.rb +119 -0
  41. data/macros/html/inline.rb +43 -0
  42. data/macros/html/structure.rb +138 -0
  43. data/spec/files/container.textile +5 -0
  44. data/spec/files/document.glyph +2 -0
  45. data/spec/files/document_with_toc.glyph +3 -0
  46. data/spec/files/included.textile +4 -0
  47. data/spec/files/ligature.jpg +449 -0
  48. data/spec/files/markdown.markdown +8 -0
  49. data/spec/files/test.sass +2 -0
  50. data/spec/lib/commands_spec.rb +83 -0
  51. data/spec/lib/config_spec.rb +79 -0
  52. data/spec/lib/document_spec.rb +100 -0
  53. data/spec/lib/glyph_spec.rb +76 -0
  54. data/spec/lib/interpreter_spec.rb +90 -0
  55. data/spec/lib/macro_spec.rb +60 -0
  56. data/spec/lib/node_spec.rb +76 -0
  57. data/spec/macros/filters_spec.rb +42 -0
  58. data/spec/macros/macros_spec.rb +159 -0
  59. data/spec/spec_helper.rb +92 -0
  60. data/spec/tasks/generate_spec.rb +31 -0
  61. data/spec/tasks/load_spec.rb +37 -0
  62. data/spec/tasks/project_spec.rb +41 -0
  63. data/styles/css3.css +220 -0
  64. data/styles/default.css +190 -0
  65. data/tasks/generate.rake +57 -0
  66. data/tasks/load.rake +55 -0
  67. data/tasks/project.rake +33 -0
  68. metadata +192 -0
@@ -0,0 +1,145 @@
1
+ module Glyph
2
+
3
+ # The Glyph::Document class stores information about a document or a chunk of text
4
+ # currently being interpreted.
5
+ #
6
+ # It is responsible of analyzing (evaluating) the syntax tree and return the corresponding output
7
+ # as well as evaluating placeholders.
8
+ class Document
9
+
10
+ ESCAPES = [
11
+ ['\\]', ']'],
12
+ ['\\[', '['],
13
+ ['\\=', '='],
14
+ ['\\.', ''],
15
+ ['\\\\', '\\'],
16
+ ['\\|', '|']
17
+ ]
18
+
19
+ attr_reader :bookmarks, :placeholders, :headers, :context
20
+
21
+ # Creates a new document
22
+ # @param [GlyphSyntaxNode] tree the syntax tree to be evaluate
23
+ # @param [Glyph::Node] context the context associated with the tree
24
+ # @raise [RuntimeError] unless tree responds to :evaluate
25
+ def initialize(tree, context)
26
+ raise RuntimeError, "Document contains syntax errors." unless tree.respond_to? :evaluate
27
+ @tree = tree
28
+ @context = context
29
+ @bookmarks = {}
30
+ @placeholders = {}
31
+ @headers = []
32
+ @state = :new
33
+ end
34
+
35
+
36
+ # Returns a tree of Glyph::Node objects corresponding to the analyzed document
37
+ # @raise [RuntimeError] unless the document has been analized
38
+ def structure
39
+ raise RuntimeError, "Document has not been analyzed" unless analyzed? || finalized?
40
+ @tree.data
41
+ end
42
+
43
+ # Copies bookmarks, headers and placeholders from another Glyph::Document
44
+ # @param [Glyph::Document] document a valid Glyph::Document
45
+ def inherit_from(document)
46
+ @bookmarks = document.bookmarks
47
+ @headers = document.headers
48
+ @placeholders = document.placeholders
49
+ end
50
+
51
+ # Defines a placeholder block that will be evaluated after the whole document has been analyzed
52
+ # @param [Proc] &block a block taking the document itself as parameter
53
+ # @return [String] the placeholder key string
54
+ def placeholder(&block)
55
+ key = "‡‡‡‡‡PLACEHOLDER¤#{@placeholders.length+1}‡‡‡‡‡".to_sym
56
+ @placeholders[key] = block
57
+ key
58
+ end
59
+
60
+ # Returns a stored bookmark or nil
61
+ # @param [#to_sym] key the bookmark identifier
62
+ # @return [Hash, nil] the bookmark hash or nil if no bookmark is found
63
+ def bookmark?(key)
64
+ @bookmarks[key.to_sym]
65
+ end
66
+
67
+ # Stores a new bookmark
68
+ # @param [Hash] hash the bookmark hash: {:id => "Bookmark ID", :title => "Bookmark Title"}
69
+ # @return [Hash] the stored bookmark (:id is converted to a symbol)
70
+ def bookmark(hash)
71
+ ident = hash[:id].to_sym
72
+ hash[:id] = ident
73
+ @bookmarks[ident] = hash
74
+ hash
75
+ end
76
+
77
+ # Stores a new header
78
+ # @param [Hash] hash the header hash: {:id => "Bookmark ID", :title => "Bookmark Title", :level => 3}
79
+ # @return [Hash] the stored header
80
+ def header(hash)
81
+ @headers << hash
82
+ hash
83
+ end
84
+
85
+ # Returns a stored header or nil
86
+ # @param [String] key the header identifier
87
+ # @return [Hash, nil] the header hash or nil if no header is found
88
+ def header?(key)
89
+ @headers.select{|h| h[:id] == key}[0] rescue nil
90
+ end
91
+
92
+ # Analyzes the document by evaluating its @tree
93
+ # @return [:analyzed]
94
+ # @raise [RuntimeError] if the document is already analyzed or finalized
95
+ def analyze
96
+ raise RuntimeError, "Document is #{@state}" if analyzed? || finalized?
97
+ @context[:document] = self
98
+ @output = @tree.evaluate @context, nil
99
+ @state = :analyzed
100
+ end
101
+
102
+ # Finalizes the document by evaluating its @placeholders
103
+ # @return [:finalized]
104
+ # @raise [RuntimeError] unless the document the document is analyzed or
105
+ # if it is already finalized
106
+ def finalize
107
+ raise RuntimeError, "Document has not been analyzed" unless analyzed?
108
+ raise RuntimeError, "Document has already been finalized" if finalized?
109
+ return (@state = :finalized) if @context[:analyze_only]
110
+ ESCAPES.each{|e| @output.gsub! e[0], e[1]}
111
+ @placeholders.each_pair do |key, value|
112
+ begin
113
+ @output.gsub! key.to_s, value.call(self).to_s
114
+ rescue Exception => e
115
+ warning e.message
116
+ end
117
+ end
118
+ @state = :finalized
119
+ end
120
+
121
+ # Returns the document output
122
+ # @raise [RuntimeError] unless the document is finalized.
123
+ def output
124
+ raise RuntimeError, "Document is not finalized" unless finalized?
125
+ @output
126
+ end
127
+
128
+ # @return [Boolean] Returns true if the document is new, false otherwise
129
+ def new?
130
+ @state == :new
131
+ end
132
+
133
+ # @return [Boolean] Returns true if the document is analyzed, false otherwise
134
+ def analyzed?
135
+ @state == :analyzed
136
+ end
137
+
138
+ # @return [Boolean] Returns true if the document is analyzed, false otherwise
139
+ def finalized?
140
+ @state == :finalized
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,530 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+ # @private
4
+ module GlyphLanguage
5
+ include Treetop::Runtime
6
+
7
+ def root
8
+ @root || :expression
9
+ end
10
+
11
+ def _nt_expression
12
+ start_index = index
13
+ if node_cache[:expression].has_key?(index)
14
+ cached = node_cache[:expression][index]
15
+ @index = cached.interval.end if cached
16
+ return cached
17
+ end
18
+
19
+ s0, i0 = [], index
20
+ loop do
21
+ i1 = index
22
+ r2 = _nt_escaping_macro
23
+ if r2
24
+ r1 = r2
25
+ else
26
+ r3 = _nt_macro
27
+ if r3
28
+ r1 = r3
29
+ else
30
+ r4 = _nt_escaped_text
31
+ if r4
32
+ r1 = r4
33
+ else
34
+ @index = i1
35
+ r1 = nil
36
+ end
37
+ end
38
+ end
39
+ if r1
40
+ s0 << r1
41
+ else
42
+ break
43
+ end
44
+ end
45
+ r0 = instantiate_node(GlyphSyntaxNode,input, i0...index, s0)
46
+
47
+ node_cache[:expression][start_index] = r0
48
+
49
+ r0
50
+ end
51
+
52
+ module EscapingMacro0
53
+ def macro_name
54
+ elements[0]
55
+ end
56
+
57
+ def text
58
+ elements[2]
59
+ end
60
+
61
+ end
62
+
63
+ def _nt_escaping_macro
64
+ start_index = index
65
+ if node_cache[:escaping_macro].has_key?(index)
66
+ cached = node_cache[:escaping_macro][index]
67
+ @index = cached.interval.end if cached
68
+ return cached
69
+ end
70
+
71
+ i0, s0 = index, []
72
+ r1 = _nt_macro_name
73
+ s0 << r1
74
+ if r1
75
+ if has_terminal?('[=', false, index)
76
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 2))
77
+ @index += 2
78
+ else
79
+ terminal_parse_failure('[=')
80
+ r2 = nil
81
+ end
82
+ s0 << r2
83
+ if r2
84
+ r3 = _nt_text
85
+ s0 << r3
86
+ if r3
87
+ if has_terminal?('=]', false, index)
88
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
89
+ @index += 2
90
+ else
91
+ terminal_parse_failure('=]')
92
+ r4 = nil
93
+ end
94
+ s0 << r4
95
+ end
96
+ end
97
+ end
98
+ if s0.last
99
+ r0 = instantiate_node(MacroNode,input, i0...index, s0)
100
+ r0.extend(EscapingMacro0)
101
+ else
102
+ @index = i0
103
+ r0 = nil
104
+ end
105
+
106
+ node_cache[:escaping_macro][start_index] = r0
107
+
108
+ r0
109
+ end
110
+
111
+ module Macro0
112
+ def macro_name
113
+ elements[0]
114
+ end
115
+
116
+ def expression
117
+ elements[2]
118
+ end
119
+
120
+ end
121
+
122
+ def _nt_macro
123
+ start_index = index
124
+ if node_cache[:macro].has_key?(index)
125
+ cached = node_cache[:macro][index]
126
+ @index = cached.interval.end if cached
127
+ return cached
128
+ end
129
+
130
+ i0, s0 = index, []
131
+ r1 = _nt_macro_name
132
+ s0 << r1
133
+ if r1
134
+ if has_terminal?('[', false, index)
135
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
136
+ @index += 1
137
+ else
138
+ terminal_parse_failure('[')
139
+ r2 = nil
140
+ end
141
+ s0 << r2
142
+ if r2
143
+ r3 = _nt_expression
144
+ s0 << r3
145
+ if r3
146
+ if has_terminal?(']', false, index)
147
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
148
+ @index += 1
149
+ else
150
+ terminal_parse_failure(']')
151
+ r4 = nil
152
+ end
153
+ s0 << r4
154
+ end
155
+ end
156
+ end
157
+ if s0.last
158
+ r0 = instantiate_node(MacroNode,input, i0...index, s0)
159
+ r0.extend(Macro0)
160
+ else
161
+ @index = i0
162
+ r0 = nil
163
+ end
164
+
165
+ node_cache[:macro][start_index] = r0
166
+
167
+ r0
168
+ end
169
+
170
+ module EscapedText0
171
+ end
172
+
173
+ module EscapedText1
174
+ def macro_name
175
+ elements[0]
176
+ end
177
+
178
+ end
179
+
180
+ module EscapedText2
181
+ end
182
+
183
+ def _nt_escaped_text
184
+ start_index = index
185
+ if node_cache[:escaped_text].has_key?(index)
186
+ cached = node_cache[:escaped_text][index]
187
+ @index = cached.interval.end if cached
188
+ return cached
189
+ end
190
+
191
+ s0, i0 = [], index
192
+ loop do
193
+ i1 = index
194
+ i2, s2 = index, []
195
+ if has_terminal?('\\', false, index)
196
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
197
+ @index += 1
198
+ else
199
+ terminal_parse_failure('\\')
200
+ r3 = nil
201
+ end
202
+ s2 << r3
203
+ if r3
204
+ if index < input_length
205
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
206
+ @index += 1
207
+ else
208
+ terminal_parse_failure("any character")
209
+ r4 = nil
210
+ end
211
+ s2 << r4
212
+ end
213
+ if s2.last
214
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
215
+ r2.extend(EscapedText0)
216
+ else
217
+ @index = i2
218
+ r2 = nil
219
+ end
220
+ if r2
221
+ r1 = r2
222
+ else
223
+ i5, s5 = index, []
224
+ i6 = index
225
+ i7 = index
226
+ i8, s8 = index, []
227
+ r9 = _nt_macro_name
228
+ s8 << r9
229
+ if r9
230
+ i10 = index
231
+ if has_terminal?('[', false, index)
232
+ r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
233
+ @index += 1
234
+ else
235
+ terminal_parse_failure('[')
236
+ r11 = nil
237
+ end
238
+ if r11
239
+ r10 = r11
240
+ else
241
+ if has_terminal?('[=', false, index)
242
+ r12 = instantiate_node(SyntaxNode,input, index...(index + 2))
243
+ @index += 2
244
+ else
245
+ terminal_parse_failure('[=')
246
+ r12 = nil
247
+ end
248
+ if r12
249
+ r10 = r12
250
+ else
251
+ @index = i10
252
+ r10 = nil
253
+ end
254
+ end
255
+ s8 << r10
256
+ end
257
+ if s8.last
258
+ r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
259
+ r8.extend(EscapedText1)
260
+ else
261
+ @index = i8
262
+ r8 = nil
263
+ end
264
+ if r8
265
+ r7 = r8
266
+ else
267
+ i13 = index
268
+ if has_terminal?(']', false, index)
269
+ r14 = instantiate_node(SyntaxNode,input, index...(index + 1))
270
+ @index += 1
271
+ else
272
+ terminal_parse_failure(']')
273
+ r14 = nil
274
+ end
275
+ if r14
276
+ r13 = r14
277
+ else
278
+ if has_terminal?('=]', false, index)
279
+ r15 = instantiate_node(SyntaxNode,input, index...(index + 2))
280
+ @index += 2
281
+ else
282
+ terminal_parse_failure('=]')
283
+ r15 = nil
284
+ end
285
+ if r15
286
+ r13 = r15
287
+ else
288
+ @index = i13
289
+ r13 = nil
290
+ end
291
+ end
292
+ if r13
293
+ r7 = r13
294
+ else
295
+ @index = i7
296
+ r7 = nil
297
+ end
298
+ end
299
+ if r7
300
+ r6 = nil
301
+ else
302
+ @index = i6
303
+ r6 = instantiate_node(SyntaxNode,input, index...index)
304
+ end
305
+ s5 << r6
306
+ if r6
307
+ if index < input_length
308
+ r16 = instantiate_node(SyntaxNode,input, index...(index + 1))
309
+ @index += 1
310
+ else
311
+ terminal_parse_failure("any character")
312
+ r16 = nil
313
+ end
314
+ s5 << r16
315
+ end
316
+ if s5.last
317
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
318
+ r5.extend(EscapedText2)
319
+ else
320
+ @index = i5
321
+ r5 = nil
322
+ end
323
+ if r5
324
+ r1 = r5
325
+ else
326
+ @index = i1
327
+ r1 = nil
328
+ end
329
+ end
330
+ if r1
331
+ s0 << r1
332
+ else
333
+ break
334
+ end
335
+ end
336
+ if s0.empty?
337
+ @index = i0
338
+ r0 = nil
339
+ else
340
+ r0 = instantiate_node(TextNode,input, i0...index, s0)
341
+ end
342
+
343
+ node_cache[:escaped_text][start_index] = r0
344
+
345
+ r0
346
+ end
347
+
348
+ module Text0
349
+ end
350
+
351
+ module Text1
352
+ def macro_name
353
+ elements[0]
354
+ end
355
+
356
+ end
357
+
358
+ module Text2
359
+ end
360
+
361
+ def _nt_text
362
+ start_index = index
363
+ if node_cache[:text].has_key?(index)
364
+ cached = node_cache[:text][index]
365
+ @index = cached.interval.end if cached
366
+ return cached
367
+ end
368
+
369
+ s0, i0 = [], index
370
+ loop do
371
+ i1 = index
372
+ i2, s2 = index, []
373
+ if has_terminal?('\\', false, index)
374
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
375
+ @index += 1
376
+ else
377
+ terminal_parse_failure('\\')
378
+ r3 = nil
379
+ end
380
+ s2 << r3
381
+ if r3
382
+ if index < input_length
383
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
384
+ @index += 1
385
+ else
386
+ terminal_parse_failure("any character")
387
+ r4 = nil
388
+ end
389
+ s2 << r4
390
+ end
391
+ if s2.last
392
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
393
+ r2.extend(Text0)
394
+ else
395
+ @index = i2
396
+ r2 = nil
397
+ end
398
+ if r2
399
+ r1 = r2
400
+ else
401
+ i5, s5 = index, []
402
+ i6 = index
403
+ i7 = index
404
+ i8, s8 = index, []
405
+ r9 = _nt_macro_name
406
+ s8 << r9
407
+ if r9
408
+ if has_terminal?('[=', false, index)
409
+ r10 = instantiate_node(SyntaxNode,input, index...(index + 2))
410
+ @index += 2
411
+ else
412
+ terminal_parse_failure('[=')
413
+ r10 = nil
414
+ end
415
+ s8 << r10
416
+ end
417
+ if s8.last
418
+ r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
419
+ r8.extend(Text1)
420
+ else
421
+ @index = i8
422
+ r8 = nil
423
+ end
424
+ if r8
425
+ r7 = r8
426
+ else
427
+ if has_terminal?('=]', false, index)
428
+ r11 = instantiate_node(SyntaxNode,input, index...(index + 2))
429
+ @index += 2
430
+ else
431
+ terminal_parse_failure('=]')
432
+ r11 = nil
433
+ end
434
+ if r11
435
+ r7 = r11
436
+ else
437
+ @index = i7
438
+ r7 = nil
439
+ end
440
+ end
441
+ if r7
442
+ r6 = nil
443
+ else
444
+ @index = i6
445
+ r6 = instantiate_node(SyntaxNode,input, index...index)
446
+ end
447
+ s5 << r6
448
+ if r6
449
+ if index < input_length
450
+ r12 = instantiate_node(SyntaxNode,input, index...(index + 1))
451
+ @index += 1
452
+ else
453
+ terminal_parse_failure("any character")
454
+ r12 = nil
455
+ end
456
+ s5 << r12
457
+ end
458
+ if s5.last
459
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
460
+ r5.extend(Text2)
461
+ else
462
+ @index = i5
463
+ r5 = nil
464
+ end
465
+ if r5
466
+ r1 = r5
467
+ else
468
+ @index = i1
469
+ r1 = nil
470
+ end
471
+ end
472
+ if r1
473
+ s0 << r1
474
+ else
475
+ break
476
+ end
477
+ end
478
+ if s0.empty?
479
+ @index = i0
480
+ r0 = nil
481
+ else
482
+ r0 = instantiate_node(TextNode,input, i0...index, s0)
483
+ end
484
+
485
+ node_cache[:text][start_index] = r0
486
+
487
+ r0
488
+ end
489
+
490
+ def _nt_macro_name
491
+ start_index = index
492
+ if node_cache[:macro_name].has_key?(index)
493
+ cached = node_cache[:macro_name][index]
494
+ @index = cached.interval.end if cached
495
+ return cached
496
+ end
497
+
498
+ s0, i0 = [], index
499
+ loop do
500
+ if has_terminal?('\G[^\\[\\]\\|\\\\\\s]', true, index)
501
+ r1 = true
502
+ @index += 1
503
+ else
504
+ r1 = nil
505
+ end
506
+ if r1
507
+ s0 << r1
508
+ else
509
+ break
510
+ end
511
+ end
512
+ if s0.empty?
513
+ @index = i0
514
+ r0 = nil
515
+ else
516
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
517
+ end
518
+
519
+ node_cache[:macro_name][start_index] = r0
520
+
521
+ r0
522
+ end
523
+
524
+ end
525
+
526
+ # @private
527
+ class GlyphLanguageParser < Treetop::Runtime::CompiledParser
528
+ include GlyphLanguage
529
+ end
530
+