glyph 0.1.0

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.
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
+