glyph 0.4.2 → 0.5.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 (132) hide show
  1. data/Rakefile +19 -40
  2. data/benchmark.rb +1 -2
  3. data/book/config.yml +8 -8
  4. data/book/document.glyph +18 -19
  5. data/book/images/glyph/commands_tasks.png +0 -0
  6. data/book/lib/layouts/bookindex.glyph +113 -111
  7. data/book/lib/layouts/bookpage.glyph +112 -108
  8. data/book/lib/macros/reference.rb +2 -2
  9. data/book/lib/tasks/tasks.rake +1 -1
  10. data/book/text/acknowledgements.glyph +1 -0
  11. data/book/text/changelog.glyph +140 -112
  12. data/book/text/compiling/compiling.glyph +36 -24
  13. data/book/text/compiling/lite_mode.glyph +11 -11
  14. data/book/text/compiling/programmatic_usage.glyph +57 -57
  15. data/book/text/config/document.glyph +7 -1
  16. data/book/text/config/options.glyph +5 -3
  17. data/book/text/config/output.glyph +41 -8
  18. data/book/text/extending/bookmarks_headers.glyph +13 -11
  19. data/book/text/extending/command.glyph +1 -1
  20. data/book/text/extending/commands_tasks.glyph +2 -2
  21. data/book/text/extending/internals.glyph +29 -29
  22. data/book/text/extending/interpreting.glyph +48 -9
  23. data/book/text/extending/macro_def.glyph +80 -32
  24. data/book/text/extending/output_format.glyph +2 -2
  25. data/book/text/extending/placeholders.glyph +27 -15
  26. data/book/text/extending/validators.glyph +1 -1
  27. data/book/text/getting_started/configuration.glyph +1 -1
  28. data/book/text/getting_started/create_project.glyph +4 -5
  29. data/book/text/getting_started/structure.glyph +2 -2
  30. data/book/text/macros/macros_core.glyph +341 -199
  31. data/book/text/macros/macros_filters.glyph +1 -1
  32. data/book/text/macros/macros_inline.glyph +3 -3
  33. data/book/text/macros/macros_structure.glyph +1 -1
  34. data/book/text/ref_commands.glyph +98 -93
  35. data/book/text/snippets.glyph +18 -0
  36. data/book/text/stats/bookmarks.glyph +16 -16
  37. data/book/text/stats/links.glyph +23 -23
  38. data/book/text/stats/macros.glyph +14 -14
  39. data/book/text/stats/snippets.glyph +26 -26
  40. data/book/text/stats/stats.glyph +14 -15
  41. data/book/text/text_editing/attribute_intro.glyph +8 -8
  42. data/book/text/text_editing/code.glyph +16 -16
  43. data/book/text/text_editing/conditionals.glyph +12 -13
  44. data/book/text/text_editing/esc_quot.glyph +3 -3
  45. data/book/text/text_editing/evaluation.glyph +57 -3
  46. data/book/text/text_editing/inclusions.glyph +34 -25
  47. data/book/text/text_editing/macro_composition.glyph +28 -0
  48. data/book/text/text_editing/macro_intro.glyph +4 -4
  49. data/book/text/text_editing/section_aliases.glyph +23 -23
  50. data/book/text/text_editing/sections.glyph +22 -22
  51. data/book/text/text_editing/stylesheets.glyph +33 -33
  52. data/book/text/text_editing/topics.glyph +6 -6
  53. data/book/text/text_editing/xml_fallback.glyph +1 -1
  54. data/book/text/troubleshooting/errors_command.glyph +4 -4
  55. data/book/text/troubleshooting/errors_generic.glyph +16 -10
  56. data/book/text/troubleshooting/errors_macro.glyph +18 -21
  57. data/book/text/troubleshooting/errors_parser.glyph +7 -7
  58. data/config.yml +51 -29
  59. data/document.glyph +18 -18
  60. data/glyph.gemspec +39 -287
  61. data/layouts/web5/topic.glyph +1 -1
  62. data/lib/glyph.rb +42 -10
  63. data/lib/glyph/analyzer.rb +5 -2
  64. data/lib/glyph/bookmark.rb +3 -1
  65. data/lib/glyph/commands.rb +11 -9
  66. data/lib/glyph/commands/add.rb +3 -1
  67. data/lib/glyph/commands/compile.rb +10 -7
  68. data/lib/glyph/commands/config.rb +7 -5
  69. data/lib/glyph/commands/init.rb +2 -0
  70. data/lib/glyph/commands/outline.rb +2 -0
  71. data/lib/glyph/commands/stats.rb +3 -0
  72. data/lib/glyph/commands/todo.rb +2 -0
  73. data/lib/glyph/config.rb +2 -0
  74. data/lib/glyph/document.rb +34 -9
  75. data/lib/glyph/interpreter.rb +2 -0
  76. data/lib/glyph/macro.rb +97 -25
  77. data/lib/glyph/macro_validators.rb +9 -6
  78. data/lib/glyph/node.rb +3 -1
  79. data/lib/glyph/parser.rb +68 -33
  80. data/lib/glyph/reporter.rb +3 -1
  81. data/lib/glyph/syntax_node.rb +23 -28
  82. data/lib/glyph/system_extensions.rb +21 -0
  83. data/lib/glyph/utils.rb +24 -4
  84. data/macros/block.rb +111 -0
  85. data/macros/core.rb +163 -33
  86. data/macros/filters.rb +3 -2
  87. data/macros/inline.rb +97 -0
  88. data/macros/reps/html.rb +180 -0
  89. data/macros/reps/html5.rb +100 -0
  90. data/macros/reps/web.rb +4 -0
  91. data/macros/reps/web5.rb +4 -0
  92. data/macros/structure.rb +229 -0
  93. data/macros/xml.rb +29 -24
  94. data/spec/config.yml +7 -0
  95. data/spec/files/article.glyph +2 -2
  96. data/spec/files/web_doc.glyph +9 -5
  97. data/spec/lib/commands_spec.rb +13 -9
  98. data/spec/lib/config_spec.rb +2 -2
  99. data/spec/lib/document_spec.rb +10 -0
  100. data/spec/lib/glyph_spec.rb +30 -8
  101. data/spec/lib/macro_spec.rb +39 -4
  102. data/spec/lib/macro_validators_spec.rb +3 -4
  103. data/spec/lib/parser_spec.rb +7 -0
  104. data/spec/lib/reporter_spec.rb +1 -0
  105. data/spec/lib/syntax_node_spec.rb +40 -6
  106. data/spec/macros/core_spec.rb +154 -21
  107. data/spec/macros/filters_spec.rb +1 -1
  108. data/spec/macros/html5_spec.rb +4 -5
  109. data/spec/macros/macros_spec.rb +6 -7
  110. data/spec/macros/web5_spec.rb +3 -3
  111. data/spec/macros/web_spec.rb +10 -7
  112. data/spec/macros/xml_spec.rb +11 -2
  113. data/spec/spec_helper.rb +11 -5
  114. data/spec/tasks/generate_spec.rb +40 -5
  115. data/spec/tasks/load_spec.rb +1 -13
  116. data/styles/coderay.css +147 -38
  117. data/styles/default.css +19 -22
  118. data/styles/pagination.css +30 -30
  119. data/tasks/generate.rake +54 -18
  120. data/tasks/load.rake +9 -24
  121. data/tasks/project.rake +0 -2
  122. metadata +208 -207
  123. data/.gitignore +0 -7
  124. data/VERSION +0 -1
  125. data/book/snippets.yml +0 -18
  126. data/lib/glyph/macro_helpers.rb +0 -282
  127. data/macros/html/block.rb +0 -124
  128. data/macros/html/inline.rb +0 -42
  129. data/macros/html/structure.rb +0 -191
  130. data/macros/html5/block.rb +0 -69
  131. data/macros/html5/inline.rb +0 -24
  132. data/macros/html5/structure.rb +0 -140
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Glyph
2
4
 
3
5
  # A Glyph::Interpreter object perform the following actions:
data/lib/glyph/macro.rb CHANGED
@@ -8,14 +8,14 @@ module Glyph
8
8
  class Macro
9
9
 
10
10
  include Validators
11
- include Helpers
12
11
  include Utils
13
12
 
14
- attr_reader :node, :source_name, :source_file, :source_topic
13
+ attr_reader :node, :source_name, :source_file, :source_topic, :name
15
14
 
16
15
  # Creates a new macro instance from a Node
17
16
  # @param [Node] node a node populated with macro data
18
17
  def initialize(node)
18
+ @data = {}
19
19
  @node = node
20
20
  @name = @node[:name]
21
21
  @updated_source = nil
@@ -34,7 +34,7 @@ module Glyph
34
34
  file ||= @node[:source][:file] rescue nil
35
35
  @updated_source = {:name => name, :file => file, :topic => topic}
36
36
  end
37
-
37
+
38
38
  # Returns a Glyph code representation of the specified parameter
39
39
  # @param [Fixnum] n the index of the parameter
40
40
  # @return [String, nil] the string representation of the parameter
@@ -109,8 +109,8 @@ module Glyph
109
109
  @parameters = []
110
110
  @node.parameters.each do |value|
111
111
  @parameters << value.evaluate(@node, :params => true)
112
- @parameters.last.strip! if options[:strip]
113
- @parameters.last = nil if @parameters.last.blank? && options[:null_if_blank]
112
+ @parameters[@parameters.length-1].strip! if options[:strip]
113
+ @parameters[@parameters.length-1] = nil if @parameters.last.blank? && options[:null_if_blank]
114
114
  end
115
115
  @parameters
116
116
  end
@@ -163,7 +163,7 @@ module Glyph
163
163
  end
164
164
  macros.reverse.compact.join('/')
165
165
  end
166
-
166
+
167
167
  # Returns a todo message to include in the document in case of errors.
168
168
  # @param [String] message the message to include in the document
169
169
  # @return [String] the resulting todo message
@@ -209,23 +209,10 @@ module Glyph
209
209
  # @param [String] string the string to interpret
210
210
  # @return [String] the interpreted output
211
211
  def interpret(string)
212
- if @node[:escape] then
213
- result = string
214
- else
215
- context = {}
216
- context[:source] = @updated_source || @node[:source]
217
- context[:embedded] = true
218
- context[:document] = @node[:document]
219
- interpreter = Glyph::Interpreter.new string, context
220
- subtree = interpreter.parse
221
- subtree[:source] = context[:source]
222
- @node << subtree
223
- result = interpreter.document.output
224
- end
225
- result
212
+ @node[:escape] ? string : inject(string).document.output
226
213
  end
227
214
 
228
- # @see Glyph::Document#placeholder
215
+ # @see Glyph::Document#placeholder
229
216
  def placeholder(&block)
230
217
  @node[:document].placeholder &block
231
218
  end
@@ -250,14 +237,99 @@ module Glyph
250
237
  @node[:document].header hash
251
238
  end
252
239
 
240
+ # @see Glyph::Document#snippet
241
+ def snippet(key, value)
242
+ @node[:document].snippet key, value
243
+ end
244
+
245
+ # @see Glyph::Document#snippet?
246
+ def snippet?(ident)
247
+ @node[:document].snippet? ident
248
+ end
249
+
250
+ # @since 0.5.0
251
+ # Renders a macro representation
252
+ # @param [Symbol, String] rep the representation to render
253
+ # @param [Hash] data the data to pass to the representation
254
+ def render(rep=nil, data=nil)
255
+ rep ||= @name
256
+ data ||= @data
257
+ block = Glyph::REPS[rep.to_sym]
258
+ macro_error "No macro representation for '#{rep}'", e unless block
259
+ instance_exec(data, &block).to_s
260
+ end
261
+
262
+ # Stores a block of code to be "dispatched" via macro composition
263
+ # @since 0.5.0
264
+ # @example
265
+ # # Macro definition (Ruby)
266
+ # macro :greet do
267
+ # dispatch do |node|
268
+ # "#{node[:name]}, #{node.param 0}!"
269
+ # end
270
+ # end
271
+ #
272
+ # # macro usage (Glyph)
273
+ # greet/Hello[World] --[Outputs: Hello, World!]
274
+ # greet/GoodBye[John] --[Outputs: Goodbye, John!]
275
+ def dispatch(&block)
276
+ @node[:dispatch] = block
277
+ value
278
+ end
279
+
280
+ # Performs parameter/attribute substitution and interprets text
281
+ # @since 0.5.0
282
+ # @param [String] text the text to interpret
283
+ # @return [String] the interpreted output
284
+ def apply(text)
285
+ body = text.dup
286
+ # Parameters
287
+ body.gsub!(/\{\{(\d+)\}\}/) do
288
+ raw_param($1.to_i).to_s.strip
289
+ end
290
+ # Attributes
291
+ body.gsub!(/\{\{([^\[\]\|\\\s]+)\}\}/) do
292
+ raw_attr($1.to_sym).to_s.strip
293
+ end
294
+ interpret body
295
+ end
296
+
297
+ # Parses text and injects the syntax tree into the current node
298
+ # @since 0.5.0
299
+ # @param [String] text the text to parse
300
+ # @return [Glyph::Interpreter] the interpreter instance used to parse text
301
+ def inject(text)
302
+ context = create_context
303
+ interpreter = Glyph::Interpreter.new text, context
304
+ subtree = interpreter.parse
305
+ subtree[:source] = context[:source]
306
+ @node << subtree
307
+ interpreter
308
+ end
309
+
310
+ # Parses text
311
+ # @since 0.5.0
312
+ # @param [String] text the text to parse
313
+ # @return [Glyph::Node] the syntax tree generated by parsing
314
+ def parse(text)
315
+ Glyph::Interpreter.new(text, create_context).parse
316
+ end
317
+
253
318
  # Executes a macro definition in the context of self
254
319
  def expand
255
320
  block = Glyph::MACROS[@name]
256
- macro_error "Undefined macro '#@name'}" unless block
257
- res = instance_exec(@node, &block).to_s
258
- res.gsub!(/\\?([\[\]\|])/){"\\#$1"}
259
- res
321
+ macro_error "Undefined macro '#@name'" unless block
322
+ instance_exec(@node, &block).to_s.gsub(/\\?([\[\]\|])/){"\\#$1"}
260
323
  end
261
324
 
325
+ private
326
+
327
+ def create_context
328
+ context = {}
329
+ context[:source] = @updated_source || @node[:source]
330
+ context[:embedded] = true
331
+ context[:document] = @node[:document]
332
+ context
333
+ end
262
334
  end
263
335
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Glyph
2
4
  class Macro
3
5
 
@@ -20,12 +22,13 @@ module Glyph
20
22
  result
21
23
  end
22
24
 
23
- # Ensures that the macro element attributes is a valid XML element name.
25
+ # Ensures that the provided name is a valid XML element name.
26
+ # @param [String, Symbol] name the element name to validate
24
27
  # @param [Hash] options a hash containing validation options (for now the only option is :level)
25
28
  # @return [Boolean] whether the validation passed or not
26
29
  # @since 0.3.0
27
- def valid_xml_element(options={:level => :error})
28
- validate("Invalid XML element '#{@node[:element]}'", options) { @node[:element].to_s.match(/^([^[:punct:]0-9<>]|_)[^<>"']*/) }
30
+ def valid_xml_element(name, options={:level => :error})
31
+ validate("Invalid XML element '#{name}'", options) { name.to_s.match(/^([^[:punct:]0-9<>]|_)[^<>"']*/) }
29
32
  end
30
33
 
31
34
  # Ensures that a macro attribute name is a valid XML attribute name.
@@ -118,7 +121,7 @@ module Glyph
118
121
  macro_error "Macro '#@name' cannot be used in safe mode" if Glyph.safe?
119
122
  end
120
123
 
121
- # Ensure that no mutual inclusion occurs within the specified parameter or attribute
124
+ # Ensures that no mutual inclusion occurs within the specified parameter or attribute
122
125
  # @param [Fixnum, Symbol] the parameter index or attribute name to check
123
126
  # @raise [Glyph::MacroError] mutual inclusion was detected
124
127
  # @since 0.3.0
@@ -146,7 +149,7 @@ module Glyph
146
149
  end
147
150
  end
148
151
 
149
- # Ensure that the macros is within another
152
+ # Ensures that the macros is within another
150
153
  # @param [String, Symbol] arg the name of the container macro
151
154
  # @param [Hash] options a hash containing validation options
152
155
  # @option options :level the error level (:error, :warning)
@@ -158,7 +161,7 @@ module Glyph
158
161
  end
159
162
  end
160
163
 
161
- # Ensure that the macros is _not_ within another
164
+ # Ensures that the macros is _not_ within another
162
165
  # @param [String, Symbol] arg the name of the container macro
163
166
  # @param [Hash] options a hash containing validation options
164
167
  # @option options :level the error level (:error, :warning)
data/lib/glyph/node.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ # Core Hash class.
1
4
  class Hash
2
5
 
3
6
  # Converts self to a Node
@@ -85,7 +88,6 @@ class Node < Hash
85
88
 
86
89
  # Iterates through children recursively (including self)
87
90
  # @param [Node, nil] element the node to process
88
- # @yieldparam [Integer] level the initial tree depth
89
91
  # @yieldparam [Node] element the current node
90
92
  # @yieldparam [Integer] level the current tree depth
91
93
  def descend(element=nil, level=0, &block)
data/lib/glyph/parser.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+
2
3
  require 'strscan'
3
4
 
4
5
  module Glyph
@@ -13,6 +14,7 @@ module Glyph
13
14
  # @param [String] source_name the name of the source file (stored in the root node)
14
15
  # @since 0.3.0
15
16
  def initialize(text, source_name="--")
17
+ @ruby19 = RUBY_VERSION >= '1.9' ? true : false
16
18
  @source_name = source_name || "--"
17
19
  @input = StringScanner.new text
18
20
  @output = create_node DocumentNode, :name => @source_name.to_sym
@@ -29,8 +31,8 @@ module Glyph
29
31
  @output << result
30
32
  count +=1
31
33
  end
32
- if @input.pos < @input.string.length then
33
- current_char = @input.string[@input.pos].chr
34
+ if @input.pos < @input.string.bytesize then
35
+ current_char = @input.string[@input.pos].chr rescue nil
34
36
  illegal_delimiter = current_char.match(/\]|\[/) rescue nil
35
37
  error "Macro delimiter '#{current_char}' not escaped" if illegal_delimiter
36
38
  end
@@ -58,18 +60,15 @@ module Glyph
58
60
  name = @input.matched
59
61
  name.chop!
60
62
  name.chop!
61
- error "#{name}[...] - A macro cannot start with '@' or a digit." if name.match(/^[0-1@]/)
62
- node = create_node(MacroNode, {
63
- :name => name.to_sym,
64
- :escape => true,
65
- :attributes => [],
66
- :parameters => []
67
- })
68
- while contents = parse_escaped_contents(node) do
69
- node << contents unless contents.is_a?(AttributeNode)
63
+ error "#{name}[=...=] - A macro cannot start with a digit or contain '@'" if (name.match(/^[0-1]/) || name.match(/@/)) && !name.match(/^@:?$/)
64
+ node = macro_node_for name, true
65
+ leaf = node
66
+ node.descend { |n, level| leaf = n }
67
+ while contents = parse_escaped_contents(leaf) do
68
+ leaf << contents unless contents.is_a?(AttributeNode)
70
69
  end
71
70
  @input.scan(/\=\]/) or error "Escaping macro '#{name}' not closed"
72
- organize_children_for node
71
+ organize_children_for leaf
73
72
  node
74
73
  else
75
74
  nil
@@ -77,9 +76,9 @@ module Glyph
77
76
  end
78
77
 
79
78
  def escaping_attribute(current)
80
- if @input.scan(/@[^\[\]\|\\\s]+\[\=/) then
79
+ if @input.scan(/@[^:\[\]\|\\\s]+\[\=/) then
81
80
  error "Attributes cannot be nested" if @current_attribute
82
- name = @input.matched[1..@input.matched.length-3]
81
+ name = @input.matched[1..@input.matched.bytesize-3]
83
82
  node = create_node(AttributeNode, {
84
83
  :escape => true,
85
84
  :name => name.to_sym
@@ -99,18 +98,15 @@ module Glyph
99
98
  if @input.scan(/[^\[\]\|\\\s]+\[/) then
100
99
  name = @input.matched
101
100
  name.chop!
102
- error "#{name}[...] - A macro cannot start with '@' or a digit." if name.match(/^[0-1@]/)
103
- node = create_node(MacroNode, {
104
- :escape => false,
105
- :name => name.to_sym,
106
- :attributes => [],
107
- :parameters => []
108
- })
109
- while contents = parse_contents(node) do
110
- node << contents unless contents.is_a?(AttributeNode)
101
+ error "#{name}[...] - A macro cannot start with a digit or contain '@'" if (name.match(/^[0-1]/) || name.match(/@/)) && !name.match(/^@:?$/)
102
+ node = macro_node_for name
103
+ leaf = node
104
+ node.descend { |n, level| leaf = n }
105
+ while contents = parse_contents(leaf) do
106
+ leaf << contents unless contents.is_a?(AttributeNode)
111
107
  end
112
108
  @input.scan(/\]/) or error "Macro '#{name}' not closed"
113
- organize_children_for node
109
+ organize_children_for leaf
114
110
  node
115
111
  else
116
112
  nil
@@ -118,9 +114,9 @@ module Glyph
118
114
  end
119
115
 
120
116
  def attribute(current)
121
- if @input.scan(/@[^\[\]\|\\\s]+\[/) then
117
+ if @input.scan(/@[^:\[\]\|\\\s]+\[/) then
122
118
  error "Attributes cannot be nested" if current.is_a?(AttributeNode)
123
- name = @input.matched[1..@input.matched.length-2]
119
+ name = @input.matched[1..@input.matched.bytesize-2]
124
120
  node = create_node(AttributeNode, {
125
121
  :escape => false,
126
122
  :name => name.to_sym
@@ -139,12 +135,12 @@ module Glyph
139
135
  def text(current)
140
136
  start_p = @input.pos
141
137
  res = @input.scan_until /(\\.)|(\A(\]|\|)|[^\\](\]|\|)|[^\[\]\|\\\s]+\[|\Z)/
142
- offset = @input.matched.match(/^[^\\](\]|\|)$/) ? 1 : @input.matched.length
138
+ offset = @input.matched.match(/^[^\\](\]|\|)$/) ? 1 : @input.matched.bytesize
143
139
  @input.pos = @input.pos - offset rescue @input.pos
144
140
  return nil if @input.pos == start_p
145
- match = @input.string[start_p..@input.pos-1]
141
+ match = extract_string(start_p..@input.pos-1)
146
142
  illegal_macro_delimiter? start_p, match
147
- if match.length > 0 then
143
+ if match.bytesize > 0 then
148
144
  create_node TextNode, :value => match
149
145
  else
150
146
  nil
@@ -160,16 +156,16 @@ module Glyph
160
156
  when @input.matched.match(/^[^\\]\|$/) then
161
157
  offset = 1
162
158
  else
163
- offset = @input.matched.length
159
+ offset = @input.matched.bytesize
164
160
  end
165
161
  @input.pos = @input.pos - offset rescue @input.pos
166
162
  return nil if @input.pos == start_p
167
- match = @input.string[start_p..@input.pos-1]
163
+ match = extract_string(start_p..@input.pos-1)
168
164
  illegal_nesting = match.match(/([^\[\]\|\\\s]+)\[\=/)[1] rescue nil
169
165
  if illegal_nesting then
170
166
  error "Cannot nest escaping macro '#{illegal_nesting}' within escaping macro '#{current[:name]}'"
171
167
  end
172
- if match.length > 0 then
168
+ if match.bytesize > 0 then
173
169
  create_node TextNode, :value => match, :escaped => true
174
170
  else
175
171
  nil
@@ -197,6 +193,45 @@ module Glyph
197
193
 
198
194
  private
199
195
 
196
+ def macro_node_for(ident, escape=false)
197
+ macro_names = ident.split(/\//).select{|e| !e.blank?}
198
+ nest_node = lambda do |parent, count|
199
+ node = create_node(MacroNode, {
200
+ :escape => false,
201
+ :name => macro_names[count].to_sym
202
+ })
203
+ parent ? (parent&0) << node : parent = node
204
+ if macro_names[count+1] then
205
+ node << create_node(ParameterNode, :name => :"0")
206
+ nest_node.call(node, count+1)
207
+ else
208
+ node[:parameters] = []
209
+ node[:attributes] = []
210
+ node[:escape] = escape
211
+ end
212
+ node
213
+ end
214
+ nest_node.call(nil, 0)
215
+ end
216
+
217
+ # Thanks Thomas Leitner
218
+ # http://redmine.ruby-lang.org/issues/show/2645
219
+ def extract_string(range)
220
+ result = nil
221
+ if @ruby19 then
222
+ begin
223
+ enc = @input.string.encoding
224
+ @input.string.force_encoding('ASCII-8BIT')
225
+ result = @input.string[range].force_encoding(enc)
226
+ ensure
227
+ @input.string.force_encoding(enc)
228
+ end
229
+ else
230
+ result = @input.string[range]
231
+ end
232
+ result
233
+ end
234
+
200
235
  def aggregate_parameters_for(node)
201
236
  indices = []
202
237
  count = 0
@@ -216,7 +251,7 @@ module Glyph
216
251
  total_parameters = 0
217
252
  save_parameter = lambda do |max_index|
218
253
  parameter = create_node ParameterNode, :name => "#{total_parameters}".to_sym
219
- total_parameters +=1
254
+ total_parameters +=1
220
255
  current_index.upto(max_index) do |index|
221
256
  parameter << (node & index)
222
257
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Glyph
2
4
 
3
5
  # This class is used to display statistics collected by a Glyph::Analyzer.
@@ -92,7 +94,7 @@ module Glyph
92
94
  section "Snippet '#{s[:param]}'"
93
95
  info "Definition:"
94
96
  puts "-------------------"
95
- puts SNIPPETS[s[:param]]
97
+ puts @stats[:snippets][:values][s[:param]]
96
98
  puts "-------------------"
97
99
  total :used_instances, s[:stats][:total]
98
100
  occurrences s[:stats][:files], "Usage Details:" if @detailed
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Glyph
2
4
 
3
5
  # A subclass of Glyph::SyntaxNode is instantiated by Glyph::Parser whenever a known
@@ -59,7 +61,13 @@ module Glyph
59
61
  # @since 0.3.0
60
62
  def to_s
61
63
  e = self[:escape] ? "=" : ""
62
- "#{self[:name]}["+e+attributes.join+parameters.join("|")+e+"]"
64
+ "#{self[:name]}["+e+contents+e+"]"
65
+ end
66
+
67
+ # @return [String] a textual representation of the macro parameters.
68
+ # @since 0.3.0
69
+ def contents
70
+ attributes.join+parameters.join("|")
63
71
  end
64
72
 
65
73
  # Expands the macro
@@ -123,11 +131,18 @@ module Glyph
123
131
  # @return [String] the value of the macro
124
132
  # @since 0.3.0
125
133
  def expand(context)
126
- xml_element(context)
127
134
  self[:source] = context[:source]
128
135
  self[:document] = context[:document]
129
136
  self[:info] = context[:info]
130
137
  self[:value] = ""
138
+ dispatched = parent_macro.dispatch(self) if parent_macro
139
+ return dispatched if dispatched
140
+ if Glyph['options.macro_set'] == "xml" || Glyph::MACROS[self[:name]].blank? && Glyph['options.xml_fallback'] then
141
+ m = Glyph::MacroNode.new
142
+ m[:name] = :xml
143
+ Glyph::Macro.new(m).expand
144
+ return m[:dispatch].call self
145
+ end
131
146
  Glyph::Macro.new(self).expand
132
147
  end
133
148
 
@@ -139,33 +154,13 @@ module Glyph
139
154
  s
140
155
  end
141
156
 
142
- protected
143
-
144
- def xml_element(context)
145
- known_macro = Glyph::MACROS.include? self[:name]
146
- name = self[:name].to_s
147
- if !known_macro && name.match(/^=(.+)/) then
148
- # Force tag name override if macro starts with a '='
149
- name.gsub! /^=(.+)/, '\1'
150
- end
151
- case
152
- # Use XML syntax
153
- when Glyph['options.macro_set'] == 'xml' then
154
- self[:element] = name
155
- self[:name] = :"|xml|"
156
- # Fallback to XML syntax
157
- when Glyph["options.xml_fallback"] then
158
- unless known_macro then
159
- self[:element] = name
160
- self[:fallback] = true
161
- self[:name] = :"|xml|"
162
- end
163
- else
164
- # Unknown macro
165
- raise RuntimeError, "Undefined macro '#{name}'\n -> source: #{context[:source][:name]}" unless known_macro
166
- end
157
+ # @since 0.5.0
158
+ # Calls the ruby block stored in the :dispatch key, if present,
159
+ # in the context of node
160
+ def dispatch(node)
161
+ return self[:dispatch].call node if self[:dispatch]
162
+ false
167
163
  end
168
-
169
164
  end
170
165
 
171
166
  # A piece of text in Glyph Abstract Syntax Tree