glyph 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/AUTHORS.textile +1 -1
  2. data/CHANGELOG.textile +119 -222
  3. data/LICENSE.textile +1 -1
  4. data/README.textile +42 -23
  5. data/Rakefile +1 -3
  6. data/VERSION +1 -1
  7. data/benchmark.rb +72 -0
  8. data/book/config.yml +4 -4
  9. data/book/document.glyph +90 -57
  10. data/book/images/document_generation.png +0 -0
  11. data/book/lib/macros/reference.rb +75 -22
  12. data/book/output/html/glyph.html +3183 -2121
  13. data/book/output/html/images/document_generation.png +0 -0
  14. data/book/output/pdf/glyph.pdf +7370 -4913
  15. data/book/resources/document_generation.txt +34 -0
  16. data/book/snippets.yml +6 -0
  17. data/book/text/changelog.glyph +45 -34
  18. data/book/text/compiling/compiling.glyph +23 -0
  19. data/book/text/compiling/lite_mode.glyph +23 -0
  20. data/book/text/compiling/programmatic_usage.glyph +77 -0
  21. data/book/text/extending/bookmarks_headers.glyph +21 -0
  22. data/book/text/extending/further_reading.glyph +13 -0
  23. data/book/text/extending/internals.glyph +79 -0
  24. data/book/text/extending/interpreting.glyph +51 -0
  25. data/book/text/extending/macro_def.glyph +64 -0
  26. data/book/text/extending/params_attrs.glyph +70 -0
  27. data/book/text/extending/placeholders.glyph +34 -0
  28. data/book/text/extending/validators.glyph +16 -0
  29. data/book/text/getting_started/configuration.glyph +49 -0
  30. data/book/text/getting_started/create_project.glyph +41 -0
  31. data/book/text/getting_started/structure.glyph +55 -0
  32. data/book/text/introduction.glyph +49 -26
  33. data/book/text/license.glyph +1 -1
  34. data/book/text/macros/macros_block.glyph +99 -0
  35. data/book/text/macros/macros_core.glyph +208 -0
  36. data/book/text/macros/macros_filters.glyph +40 -0
  37. data/book/text/macros/macros_inline.glyph +50 -0
  38. data/book/text/macros/macros_structure.glyph +100 -0
  39. data/book/text/ref_commands.glyph +94 -73
  40. data/book/text/ref_config.glyph +34 -42
  41. data/book/text/ref_macros.glyph +1 -373
  42. data/book/text/text_editing/code.glyph +51 -0
  43. data/book/text/text_editing/conditionals.glyph +49 -0
  44. data/book/text/text_editing/evaluation.glyph +13 -0
  45. data/book/text/text_editing/glyph_files.glyph +7 -0
  46. data/book/text/text_editing/images.glyph +29 -0
  47. data/book/text/text_editing/inclusions.glyph +44 -0
  48. data/book/text/text_editing/links.glyph +53 -0
  49. data/book/text/text_editing/macro_intro.glyph +111 -0
  50. data/book/text/text_editing/raw_html.glyph +112 -0
  51. data/book/text/text_editing/sections.glyph +63 -0
  52. data/book/text/text_editing/stylesheets.glyph +36 -0
  53. data/book/text/troubleshooting/errors_command.glyph +39 -0
  54. data/book/text/troubleshooting/errors_generic.glyph +29 -0
  55. data/book/text/troubleshooting/errors_intro.glyph +3 -0
  56. data/book/text/troubleshooting/errors_macro.glyph +98 -0
  57. data/book/text/troubleshooting/errors_parser.glyph +29 -0
  58. data/config.yml +77 -58
  59. data/document.glyph +25 -25
  60. data/glyph.gemspec +57 -22
  61. data/lib/glyph.rb +54 -13
  62. data/lib/glyph/commands.rb +84 -17
  63. data/lib/glyph/config.rb +3 -3
  64. data/lib/glyph/document.rb +14 -8
  65. data/lib/glyph/interpreter.rb +18 -58
  66. data/lib/glyph/macro.rb +160 -55
  67. data/lib/glyph/macro_validators.rb +104 -12
  68. data/lib/glyph/node.rb +24 -0
  69. data/lib/glyph/parser.rb +278 -0
  70. data/lib/glyph/syntax_node.rb +225 -0
  71. data/macros/core.rb +212 -0
  72. data/macros/filters.rb +66 -15
  73. data/macros/html/block.rb +43 -105
  74. data/macros/html/inline.rb +11 -12
  75. data/macros/html/structure.rb +123 -58
  76. data/macros/xml.rb +33 -0
  77. data/spec/files/container.textile +2 -2
  78. data/spec/files/document.glyph +2 -2
  79. data/spec/files/document_with_toc.glyph +3 -3
  80. data/spec/files/included.textile +1 -1
  81. data/spec/files/ligature.jpg +0 -0
  82. data/spec/files/markdown.markdown +2 -1
  83. data/spec/lib/commands_spec.rb +46 -3
  84. data/spec/lib/document_spec.rb +4 -4
  85. data/spec/lib/glyph_spec.rb +17 -46
  86. data/spec/lib/interpreter_spec.rb +6 -25
  87. data/spec/lib/macro_spec.rb +141 -43
  88. data/spec/lib/macro_validators_spec.rb +27 -5
  89. data/spec/lib/node_spec.rb +26 -1
  90. data/spec/lib/parser_spec.rb +246 -0
  91. data/spec/lib/syntax_node_spec.rb +111 -0
  92. data/spec/macros/core_spec.rb +195 -0
  93. data/spec/macros/filters_spec.rb +38 -4
  94. data/spec/macros/macros_spec.rb +20 -176
  95. data/spec/macros/textile_spec.rb +13 -71
  96. data/spec/macros/xml_spec.rb +77 -0
  97. data/spec/spec_helper.rb +50 -10
  98. data/spec/tasks/load_spec.rb +13 -2
  99. data/styles/default.css +18 -6
  100. data/styles/pagination.css +1 -19
  101. data/tasks/generate.rake +2 -2
  102. data/tasks/load.rake +27 -17
  103. data/tasks/project.rake +1 -1
  104. metadata +75 -62
  105. data/book/script/compile.rb +0 -8
  106. data/book/script/prof +0 -1
  107. data/book/script/prof_results.htm +0 -21079
  108. data/book/text/authoring.glyph +0 -548
  109. data/book/text/extending.glyph +0 -224
  110. data/book/text/getting_started.glyph +0 -158
  111. data/book/text/troubleshooting.glyph +0 -179
  112. data/lib/glyph/glyph_language.rb +0 -538
  113. data/lib/glyph/glyph_language.treetop +0 -27
  114. data/macros/common.rb +0 -160
data/lib/glyph/config.rb CHANGED
@@ -77,9 +77,9 @@ module Glyph
77
77
  # @raise [ArgumentError] if the setting refers to an invalid namespace
78
78
  # @example
79
79
  # cfg = Glyph::Config.new
80
- # cfg.set "quiet", true # Sets :quiet => true
80
+ # cfg.set "system.quiet", true # Sets "system.quiet" => true
81
81
  # cfg.set "test.test_value", "[1,2,3]" # Sets :test => {:test_value => [1,2,3]}
82
- # cfg.sef :quiet, "false" # Sets :quiet => false
82
+ # cfg.set "system.quiet", "false" # Sets "system.quiet" => false
83
83
  def set(setting, value)
84
84
  raise RuntimeError, "Configuration cannot be changed" unless @options[:mutable]
85
85
  if value.is_a?(String) && value.match(/^(["'].*["']|:.+|\[.*\]|\{.*\}|true|false|nil)$/) then
@@ -122,7 +122,7 @@ module Glyph
122
122
  # @see Glyph::Config#set
123
123
  # @example
124
124
  # cfg = Glyph::Config.new
125
- # cfg.get :quiet # true
125
+ # cfg.get "system.quiet" # true
126
126
  # cfg.get "test.test_value" # [1,2,3]
127
127
  def get(setting)
128
128
  @data.instance_eval "self#{setting.to_s.split(".").map{|key| "[:#{key}]" }.join}" rescue nil
@@ -6,7 +6,7 @@ module Glyph
6
6
  # currently being interpreted.
7
7
  #
8
8
  # It is responsible of analyzing (evaluating) the syntax tree and return the corresponding output
9
- # as well as evaluating placeholders.
9
+ # as well as replacing placeholders.
10
10
  class Document
11
11
 
12
12
  ESCAPES = [
@@ -40,7 +40,7 @@ module Glyph
40
40
  # @raise [RuntimeError] unless the document has been analized
41
41
  def structure
42
42
  raise RuntimeError, "Document has not been analyzed" unless analyzed? || finalized?
43
- @tree.data
43
+ @tree
44
44
  end
45
45
 
46
46
  # Copies bookmarks, headers, todos and placeholders from another Glyph::Document
@@ -99,7 +99,7 @@ module Glyph
99
99
  def analyze
100
100
  raise RuntimeError, "Document is #{@state}" if analyzed? || finalized?
101
101
  @context[:document] = self
102
- @output = @tree.evaluate @context, nil
102
+ @output = @tree.evaluate @context
103
103
  @state = :analyzed
104
104
  end
105
105
 
@@ -114,12 +114,18 @@ module Glyph
114
114
  raise RuntimeError, "Document cannot be finalized due to previous errors" unless @context[:document].errors.blank?
115
115
  # Substitute placeholders
116
116
  ESCAPES.each{|e| @output.gsub! e[0], e[1]}
117
- @placeholders.each_pair do |key, value|
118
- begin
119
- @output.gsub! key.to_s, value.call(self).to_s
120
- rescue Exception => e
121
- Glyph.warning e.message
117
+ begin
118
+ @placeholders.each_pair do |key, value|
119
+ begin
120
+ @output.gsub! key.to_s, value.call(self).to_s
121
+ rescue Glyph::MacroError => e
122
+ e.macro.macro_warning e.message, e
123
+ rescue Exception => e
124
+ puts e.class
125
+ Glyph.warning e.message
126
+ end
122
127
  end
128
+ rescue Exception => e
123
129
  end
124
130
  @state = :finalized
125
131
  end
@@ -1,74 +1,24 @@
1
- # @private
2
- class GlyphSyntaxNode < Treetop::Runtime::SyntaxNode
3
-
4
- attr_reader :data
5
-
6
- def evaluate(context, current=nil)
7
- current ||= context.to_node
8
- @data ||= current.to_node
9
- elements.map { |e| e.evaluate(context, current) if e.respond_to? :evaluate }.join
10
- end
11
-
12
- end
13
-
14
- # @private
15
- class MacroNode < GlyphSyntaxNode
16
-
17
- def evaluate(context, current)
18
- name = macro_name.text_value.to_sym
19
- raise Glyph::SyntaxError, "Undefined macro '#{name}'\n -> source: #{current[:source]}" unless Glyph::MACROS.include? name
20
- @data = {:macro => name, :source => context[:source], :document => context[:document]}.to_node
21
- @data[:escape] = true if is_a? EscapingMacroNode
22
- current << @data
23
- @data[:value] = super(context, @data).strip
24
- Glyph::Macro.new(@data).execute
25
- end
26
-
27
- end
28
-
29
- # @private
30
- class EscapingMacroNode < MacroNode; end
31
-
32
- # @private
33
- class TextNode < GlyphSyntaxNode
34
-
35
- def evaluate(context, current=nil)
36
- text_value
37
- end
38
-
39
- end
40
-
41
-
42
1
  module Glyph
43
-
2
+
44
3
  # A Glyph::Interpreter object perform the following actions:
45
4
  # * Parses a string of text containing Glyph macros
46
5
  # * Creates a document based on the parsed syntax tree
47
6
  # * Analyzes and finalizes the document
48
7
  class Interpreter
49
8
 
50
- PARSER = GlyphLanguageParser.new
51
-
52
9
  # Creates a new Glyph::Interpreter object.
53
10
  # @param [String] text the string to interpret
54
- # @param [Hash] context the context to pass along when evaluating macros
55
- def initialize(text, context=nil)
56
- context ||= {:source => '--'}
57
- @raw = PARSER.parse text
11
+ # @param [Hash] context the context to pass along when expanding macros
12
+ def initialize(text, context={})
58
13
  @context = context
59
- tf = PARSER.terminal_failures
60
- if !@raw.respond_to?(:evaluate) then
61
- reason = "Incorrect macro syntax"
62
- err = "#{reason}\n -> #{@context[:source]} [Line #{PARSER.failure_line}, Column #{PARSER.failure_column}]"
63
- @context[:document].errors << err if @context[:document] && !@context[:embedded]
64
- raise Glyph::SyntaxError, err
65
- end
66
- @document = Glyph::Document.new @raw, @context
67
- @document.inherit_from @context[:document] if @context[:document]
14
+ @context[:source] ||= {:name => "--"}
15
+ @text = text
16
+ @parser = Glyph::Parser.new text, @context[:source][:name]
68
17
  end
69
18
 
70
19
  # @see Glyph::Document#analyze
71
20
  def process
21
+ parse unless @tree
72
22
  @document.analyze
73
23
  end
74
24
 
@@ -80,15 +30,25 @@ module Glyph
80
30
  # Returns the finalized @document (calls self#process and self#postprocess if necessary)
81
31
  # @return [Glyph::Document] the finalized document
82
32
  def document
33
+ parse unless @tree
83
34
  return @document if @document.finalized?
84
35
  process if @document.new?
85
36
  postprocess if @document.analyzed?
86
37
  @document
87
38
  end
88
39
 
40
+ # Parses the string provided during initialization
41
+ # @return [Glyph::SyntaxNode] the Abstract Syntax Tree generated from the string
42
+ # @since 0.3.0
43
+ def parse
44
+ Glyph.info "Parsing: #{@context[:source][:name]}" if Glyph.debug? && @context[:info] && @context[:source][:name]
45
+ @tree = @parser.parse
46
+ @document = Glyph::Document.new @tree, @context
47
+ @document.inherit_from @context[:document] if @context[:document]
48
+ @tree
49
+ end
89
50
 
90
51
  end
91
-
92
52
  end
93
53
 
94
54
 
data/lib/glyph/macro.rb CHANGED
@@ -9,41 +9,153 @@ module Glyph
9
9
 
10
10
  include Validators
11
11
 
12
+ attr_reader :node, :source
13
+
12
14
  # Creates a new macro instance from a Node
13
15
  # @param [Node] node a node populated with macro data
14
16
  def initialize(node)
15
17
  @node = node
16
- @name = @node[:macro]
17
- @value = @node[:value]
18
- @source = @node[:source]
19
- @escaped_pipe = '‡‡‡‡‡ESCAPED¤PIPE‡‡‡‡‡'
18
+ @name = @node[:name]
19
+ @updated_source = nil
20
+ @source = @node[:source][:name] rescue "--"
20
21
  end
21
22
 
22
- # Parses the macro parameters (stripping values)
23
- # @return [Array] the macro parameters
24
- def params
25
- return @params if @params
26
- @params = @value.gsub(/\\\|/, @escaped_pipe).split('|').map{|p| p.strip.gsub @escaped_pipe, "\\|"}
23
+ # Resets the name of the updated source (call before calling
24
+ # Macro#interpret)
25
+ # @param [String] name the source name
26
+ def update_source(name)
27
+ @updated_source = {:node => @node, :name => name}
28
+ end
29
+
30
+ # Returns a Glyph code representation of the specified parameter
31
+ # @param [Fixnum] n the index of the parameter
32
+ # @return [String, nil] the string representation of the parameter
33
+ # @since 0.3.0
34
+ def raw_parameter(n)
35
+ @node.parameter(n).contents.to_s rescue nil
36
+ end
37
+
38
+ # Returns a Glyph code representation of the specified attribute
39
+ # @param [String, Symbol] name the name of the attribute
40
+ # @return [String, nil] the string representation of the attribute
41
+ # @since 0.3.0
42
+ def raw_attribute(name)
43
+ @node.attribute(name).contents.to_s rescue nil
44
+ end
45
+
46
+ # Returns an evaluated macro attribute by name
47
+ # @param [String, Symbol] name the name of the attribute
48
+ # @param [Hash] options a hash of options
49
+ # @option options [Boolean] :strip whether the value is stripped or not
50
+ # @return [String, nil] the value of the attribute
51
+ # @since 0.3.0
52
+ def attribute(name, options={:strip => true})
53
+ return @attributes[name.to_sym] if @attributes && @attributes[name.to_sym]
54
+ return nil unless @node.attribute(name)
55
+ @attributes = {} unless @attributes
56
+ @attributes[name] = @node.attribute(name).evaluate(@node, :attrs => true).to_s
57
+ @attributes[name].strip! if options[:strip]
58
+ @attributes[name]
59
+ end
60
+
61
+ # Returns an evaluated macro parameter by index
62
+ # @param [Fixnum] n the index of the parameter
63
+ # @param [Hash] options a hash of options
64
+ # @option options [Boolean] :strip whether the value is stripped or not
65
+ # @return [String, nil] the value of the parameter
66
+ # @since 0.3.0
67
+ def parameter(n, options={:strip => true})
68
+ return @parameters[n] if @parameters && @parameters[n]
69
+ return nil unless @node.parameter(n)
70
+ @parameters = Array.new(@node.parameters.length) unless @parameters
71
+ @parameters[n] = @node.parameter(n).evaluate(@node, :params => true).to_s
72
+ @parameters[n].strip! if options[:strip]
73
+ @parameters[n]
27
74
  end
28
75
 
29
- # Parses the macro parameters (without stripping values)
76
+ # Returns a hash containing all evaluated macro attributes
77
+ # @param [Hash] options a hash of options
78
+ # @option options [Boolean] :strip whether the value is stripped or not
79
+ # @return [Hash] the macro attributes
80
+ # @since 0.3.0
81
+ def attributes(options={:strip => true})
82
+ return @attributes if @attributes
83
+ @attributes = {}
84
+ @node.attributes.each do |value|
85
+ @attributes[value[:name]] = value.evaluate(@node, :attrs => true)
86
+ @attributes[value[:name]].strip! if options[:strip]
87
+ end
88
+ @attributes
89
+ end
90
+
91
+ # Returns an array containing all evaluated macro parameters
92
+ # @param [Hash] options a hash of options
93
+ # @option options [Boolean] :strip whether the value is stripped or not
30
94
  # @return [Array] the macro parameters
31
- def raw_params
32
- return @raw_params if @raw_params
33
- @params = @value.gsub(/\\\|/, @escaped_pipe).split('|').map{|p| p.gsub @escaped_pipe, "\\|"}
95
+ # @since 0.3.0
96
+ def parameters(options={:strip => true})
97
+ return @parameters if @parameters
98
+ @parameters = []
99
+ @node.parameters.each do |value|
100
+ @parameters << value.evaluate(@node, :params => true)
101
+ @parameters.last.strip! if options[:strip]
102
+ end
103
+ @parameters
104
+ end
105
+
106
+ alias params parameters
107
+ alias param parameter
108
+ alias attrs attributes
109
+ alias attr attribute
110
+ alias raw_param raw_parameter
111
+ alias raw_attr raw_attribute
112
+
113
+ # Equivalent to Glyph::Macro#parameter(0).
114
+ # @since 0.3.0
115
+ def value
116
+ parameter(0)
117
+ end
118
+
119
+ # Equivalent to Glyph::Macro#raw_parameter(0).
120
+ # @since 0.3.0
121
+ def raw_value
122
+ raw_parameter(0)
34
123
  end
35
124
 
36
125
  # Returns the "path" to the macro within the syntax tree.
37
126
  # @return [String] the macro path
127
+ # @since 0.3.0
38
128
  def path
39
129
  macros = []
40
- @node.ascend {|n| macros << n[:macro].to_s if n[:macro] }
41
- macros.reverse.join('/')
130
+ @node.ascend do |n|
131
+ case
132
+ when n.is_a?(Glyph::MacroNode) then
133
+ if n[:name] == :"|xml|" then
134
+ name = "xml[#{n[:element]}]"
135
+ else
136
+ break if n[:name] == :include
137
+ name = n[:name].to_s
138
+ end
139
+ when n.is_a?(Glyph::ParameterNode) then
140
+ if n.parent.parameters.length == 1 then
141
+ name = nil
142
+ else
143
+ name = n[:name].to_s
144
+ end
145
+ when n.is_a?(Glyph::AttributeNode) then
146
+ name = "@#{n[:name]}"
147
+ else
148
+ name = nil
149
+ end
150
+ macros << name
151
+ end
152
+ macros.reverse.compact.join('/')
42
153
  end
43
154
 
44
155
  # Returns a todo message to include in the document in case of errors.
45
156
  # @param [String] message the message to include in the document
46
157
  # @return [String] the resulting todo message
158
+ # @since 0.2.0
47
159
  def macro_todo(message)
48
160
  draft = Glyph['document.draft']
49
161
  Glyph['document.draft'] = true unless draft
@@ -56,57 +168,49 @@ module Glyph
56
168
  # @param [String] msg the message to print
57
169
  # @raise [Glyph::MacroError]
58
170
  def macro_error(msg, klass=Glyph::MacroError)
59
- src = @node[:source_name]
60
- src ||= @node[:source]
61
- src ||= "--"
62
- message = "#{msg}\n -> source: #{src}\n -> path: #{path}"
63
- @node[:document].errors << message
64
- message += "\n -> value:\n#{"-"*54}\n#{@value}\n#{"-"*54}" if Glyph.debug?
65
- raise klass, message
171
+ @node[:document].errors << msg if @node[:document]
172
+ raise klass.new(msg, self)
66
173
  end
67
174
 
68
- # Raises a macro error
175
+ # Prints a macro earning
69
176
  # @param [String] msg the message to print
70
- # @raise [Glyph::MacroError]
71
- def macro_warning(message)
72
- src = @node[:source_name]
73
- src ||= @node[:source]
74
- src ||= "--"
75
- Glyph.warning "#{message}\n -> source: #{src}\n -> path: #{path}"
76
- message += %{\n -> value:\n#{"-"*54}\n#{@value}\n#{"-"*54}} if Glyph.debug?
177
+ # @param [Exception] e the exception raised
178
+ # @since 0.2.0
179
+ def macro_warning(msg, e=nil)
180
+ if e.is_a?(Glyph::MacroError) then
181
+ e.display
182
+ else
183
+ message = "#{msg}\n source: #{@source}\n path: #{path}"
184
+ if Glyph.debug? then
185
+ message << %{\n#{"-"*54}\n#{@node.to_s.gsub(/\t/, ' ')}\n#{"-"*54}}
186
+ if e then
187
+ message << "\n"+"-"*20+"[ Backtrace: ]"+"-"*20
188
+ message << "\n"+e.backtrace.join("\n")
189
+ message << "\n"+"-"*54
190
+ end
191
+ end
192
+ Glyph.warning message
193
+ end
77
194
  end
78
195
 
79
196
  # Instantiates a Glyph::Interpreter and interprets a string
80
197
  # @param [String] string the string to interpret
81
198
  # @return [String] the interpreted output
82
- # @raise [Glyph::MacroError] in case of mutual macro inclusion (snippet, include macros)
83
199
  def interpret(string)
84
- @node[:source] = "#@name[#@value]"
85
- @node[:source_name] = "#{@name}[...]"
86
- macro_error "Mutual inclusion", Glyph::MutualInclusionError if @node.find_parent {|n| n[:source] == @node[:source] }
87
200
  if @node[:escape] then
88
201
  result = string
89
202
  else
90
- @node[:embedded] = true
91
- result = Glyph::Interpreter.new(string, @node).document.output
203
+ context = {}
204
+ context[:source] = @updated_source || @node[:source]
205
+ context[:embedded] = true
206
+ context[:document] = @node[:document]
207
+ interpreter = Glyph::Interpreter.new string, context
208
+ subtree = interpreter.parse
209
+ @node << subtree
210
+ result = interpreter.document.output
92
211
  end
93
212
  result.gsub(/\\*([\[\]])/){"\\#$1"}
94
- end
95
-
96
- # Encodes all macros in a string so that it can be encoded
97
- # (and interpreted) later on
98
- # @param [String] string the string to encode
99
- # @return [String] the encoded string
100
- def encode(string)
101
- string.gsub(/([\[\]\|])/) { "‡‡¤#{$1.bytes.to_a[0]}¤‡‡" }
102
- end
103
-
104
- # Decodes a previously encoded string
105
- # so that it can be interpreted
106
- # @param [String] string the string to decode
107
- # @return [String] the decoded string
108
- def decode(string)
109
- string.gsub(/‡‡¤(91|93|124)¤‡‡/) { $1.to_i.chr }
213
+ result
110
214
  end
111
215
 
112
216
  # @see Glyph::Document#placeholder
@@ -135,12 +239,13 @@ module Glyph
135
239
  end
136
240
 
137
241
  # Executes a macro definition in the context of self
138
- def execute
139
- res = instance_exec(@node, &Glyph::MACROS[@name]).to_s
242
+ def expand
243
+ block = Glyph::MACROS[@name]
244
+ macro_error "Undefined macro '#@name'}" unless block
245
+ res = instance_exec(@node, &block).to_s
140
246
  res.gsub!(/\\*([\[\]\|])/){"\\#$1"}
141
247
  res
142
248
  end
143
249
 
144
250
  end
145
-
146
251
  end