glyph 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. data/.gitignore +7 -0
  2. data/AUTHORS.textile +8 -7
  3. data/CHANGELOG.textile +89 -8
  4. data/LICENSE.textile +1 -2
  5. data/README.textile +89 -61
  6. data/Rakefile +12 -10
  7. data/VERSION +1 -1
  8. data/benchmark.rb +1 -1
  9. data/book/config.yml +18 -4
  10. data/book/document.glyph +269 -45
  11. data/book/images/glyph/commands_tasks.png +0 -0
  12. data/book/images/{document_generation.png → glyph/document_generation.png} +0 -0
  13. data/book/images/glyph/glyph.eps +123 -0
  14. data/book/images/glyph/glyph.png +0 -0
  15. data/book/images/glyph/glyph.svg +29 -0
  16. data/book/lib/commands/commands.rb +11 -0
  17. data/book/lib/layouts/bookindex.glyph +127 -0
  18. data/book/lib/layouts/bookpage.glyph +129 -0
  19. data/book/lib/layouts/project.glyph +26 -0
  20. data/book/lib/macros/reference.rb +27 -7
  21. data/book/lib/tasks/tasks.rake +52 -0
  22. data/book/snippets.yml +1 -1
  23. data/book/text/{acknowledgement.glyph → acknowledgements.glyph} +4 -2
  24. data/book/text/changelog.glyph +29 -3
  25. data/book/text/compiling/compiling.glyph +44 -20
  26. data/book/text/compiling/lite_mode.glyph +0 -4
  27. data/book/text/compiling/programmatic_usage.glyph +1 -5
  28. data/book/text/config/document.glyph +35 -0
  29. data/book/text/config/filters.glyph +28 -0
  30. data/book/text/config/options.glyph +25 -0
  31. data/book/text/config/output.glyph +83 -0
  32. data/book/text/extending/bookmarks_headers.glyph +0 -5
  33. data/book/text/extending/command.glyph +56 -0
  34. data/book/text/extending/commands_tasks.glyph +39 -0
  35. data/book/text/extending/further_reading.glyph +0 -3
  36. data/book/text/extending/internals.glyph +3 -5
  37. data/book/text/extending/interpreting.glyph +0 -4
  38. data/book/text/extending/layouts.glyph +68 -0
  39. data/book/text/extending/macro_def.glyph +0 -5
  40. data/book/text/extending/output_format.glyph +78 -0
  41. data/book/text/extending/params_attrs.glyph +0 -3
  42. data/book/text/extending/placeholders.glyph +0 -4
  43. data/book/text/extending/task.glyph +46 -0
  44. data/book/text/extending/validators.glyph +5 -6
  45. data/book/text/getting_started/configuration.glyph +1 -5
  46. data/book/text/getting_started/create_project.glyph +1 -5
  47. data/book/text/getting_started/structure.glyph +0 -4
  48. data/book/text/introduction.glyph +100 -75
  49. data/book/text/license.glyph +1 -2
  50. data/book/text/macros/macros_block.glyph +8 -4
  51. data/book/text/macros/macros_core.glyph +0 -3
  52. data/book/text/macros/macros_filters.glyph +2 -7
  53. data/book/text/macros/macros_inline.glyph +0 -4
  54. data/book/text/macros/macros_structure.glyph +0 -4
  55. data/book/text/ref_commands.glyph +29 -7
  56. data/book/text/stats/bookmarks.glyph +49 -0
  57. data/book/text/stats/links.glyph +90 -0
  58. data/book/text/stats/macros.glyph +73 -0
  59. data/book/text/stats/snippets.glyph +50 -0
  60. data/book/text/stats/stats.glyph +79 -0
  61. data/book/text/text_editing/attribute_intro.glyph +22 -0
  62. data/book/text/text_editing/code.glyph +0 -5
  63. data/book/text/text_editing/conditionals.glyph +0 -4
  64. data/book/text/text_editing/esc_quot.glyph +64 -0
  65. data/book/text/text_editing/evaluation.glyph +0 -3
  66. data/book/text/text_editing/glyph_files.glyph +0 -3
  67. data/book/text/text_editing/images.glyph +0 -5
  68. data/book/text/text_editing/inclusions.glyph +0 -4
  69. data/book/text/text_editing/links.glyph +2 -7
  70. data/book/text/text_editing/macro_intro.glyph +1 -98
  71. data/book/text/text_editing/raw_html.glyph +0 -87
  72. data/book/text/text_editing/section_aliases.glyph +28 -0
  73. data/book/text/text_editing/sections.glyph +1 -32
  74. data/book/text/text_editing/stylesheets.glyph +3 -5
  75. data/book/text/text_editing/topics.glyph +33 -0
  76. data/book/text/text_editing/xml_fallback.glyph +73 -0
  77. data/book/text/troubleshooting/errors_command.glyph +0 -3
  78. data/book/text/troubleshooting/errors_generic.glyph +21 -6
  79. data/book/text/troubleshooting/errors_macro.glyph +11 -8
  80. data/book/text/troubleshooting/errors_parser.glyph +0 -3
  81. data/config.yml +60 -25
  82. data/glyph.gemspec +90 -36
  83. data/layouts/web/index.glyph +16 -0
  84. data/layouts/web/topic.glyph +15 -0
  85. data/layouts/web5/index.glyph +16 -0
  86. data/layouts/web5/topic.glyph +17 -0
  87. data/lib/glyph.rb +36 -49
  88. data/lib/glyph/analyzer.rb +253 -0
  89. data/lib/glyph/bookmark.rb +92 -0
  90. data/lib/glyph/commands.rb +9 -221
  91. data/lib/glyph/commands/add.rb +8 -0
  92. data/lib/glyph/commands/compile.rb +93 -0
  93. data/lib/glyph/commands/config.rb +38 -0
  94. data/lib/glyph/commands/init.rb +6 -0
  95. data/lib/glyph/commands/outline.rb +45 -0
  96. data/lib/glyph/commands/stats.rb +48 -0
  97. data/lib/glyph/commands/todo.rb +29 -0
  98. data/lib/glyph/config.rb +2 -0
  99. data/lib/glyph/document.rb +61 -30
  100. data/lib/glyph/interpreter.rb +2 -2
  101. data/lib/glyph/macro.rb +14 -5
  102. data/lib/glyph/macro_helpers.rb +280 -0
  103. data/lib/glyph/macro_validators.rb +37 -2
  104. data/lib/glyph/reporter.rb +182 -0
  105. data/lib/glyph/syntax_node.rb +37 -10
  106. data/lib/glyph/system_extensions.rb +8 -45
  107. data/lib/glyph/utils.rb +148 -0
  108. data/macros/core.rb +10 -15
  109. data/macros/filters.rb +4 -5
  110. data/macros/html/block.rb +46 -30
  111. data/macros/html/inline.rb +9 -35
  112. data/macros/html/structure.rb +59 -72
  113. data/macros/html5/block.rb +69 -0
  114. data/macros/html5/inline.rb +24 -0
  115. data/macros/html5/structure.rb +139 -0
  116. data/macros/xml.rb +1 -1
  117. data/spec/files/custom_command.rb +6 -0
  118. data/spec/files/custom_tasks.rake +6 -0
  119. data/spec/files/document_for_stats.glyph +12 -0
  120. data/spec/files/references.glyph +4 -0
  121. data/spec/files/web1.glyph +11 -0
  122. data/spec/files/web2.glyph +10 -0
  123. data/spec/files/web_doc.glyph +23 -0
  124. data/spec/lib/analyzer_spec.rb +137 -0
  125. data/spec/lib/bookmark_spec.rb +64 -0
  126. data/spec/lib/commands_spec.rb +30 -5
  127. data/spec/lib/document_spec.rb +49 -9
  128. data/spec/lib/glyph_spec.rb +21 -1
  129. data/spec/lib/macro_spec.rb +6 -6
  130. data/spec/lib/macro_validators_spec.rb +24 -0
  131. data/spec/lib/reporter_spec.rb +132 -0
  132. data/spec/macros/core_spec.rb +2 -3
  133. data/spec/macros/filters_spec.rb +2 -2
  134. data/spec/macros/html5_spec.rb +101 -0
  135. data/spec/macros/macros_spec.rb +16 -6
  136. data/spec/macros/web5_spec.rb +32 -0
  137. data/spec/macros/web_spec.rb +59 -0
  138. data/spec/macros/xml_spec.rb +1 -1
  139. data/spec/spec_helper.rb +24 -4
  140. data/spec/tasks/generate_spec.rb +54 -0
  141. data/spec/tasks/load_spec.rb +29 -3
  142. data/spec/tasks/project_spec.rb +21 -3
  143. data/styles/default.css +40 -4
  144. data/styles/pagination.css +59 -41
  145. data/tasks/generate.rake +110 -31
  146. data/tasks/load.rake +39 -7
  147. data/tasks/project.rake +9 -7
  148. metadata +115 -34
  149. data/book/images/glyph.png +0 -0
  150. data/book/images/glyph.svg +0 -351
  151. data/book/output/html/glyph.html +0 -4482
  152. data/book/output/html/images/document_generation.png +0 -0
  153. data/book/output/html/images/glyph.png +0 -0
  154. data/book/output/html/images/glyph.svg +0 -351
  155. data/book/output/pdf/glyph.pdf +4 -10254
  156. data/book/script/authors +0 -1
  157. data/book/script/changelog +0 -1
  158. data/book/script/license +0 -1
  159. data/book/script/readme +0 -1
  160. data/book/text/ref_config.glyph +0 -100
  161. data/book/text/ref_macros.glyph +0 -6
  162. data/book/text/troubleshooting/errors_intro.glyph +0 -3
@@ -0,0 +1,16 @@
1
+ document[
2
+ head[
3
+ style[default.css]
4
+ ]
5
+ body[
6
+ @class[topic]
7
+ halftitlepage[
8
+ title[]
9
+ subtitle[]
10
+ author[]
11
+ ]
12
+ frontmatter[
13
+ toc[]
14
+ ]
15
+ ]
16
+ ]
@@ -0,0 +1,15 @@
1
+ document[
2
+ head[
3
+ style[default.css]
4
+ ]
5
+ body[
6
+ @class[topic]
7
+ section[
8
+ @title[{{title}}]
9
+ @id[{{id}}]
10
+ navigation[{{id}}]
11
+ {{contents}}
12
+ navigation[{{id}}]
13
+ ]
14
+ ]
15
+ ]
@@ -0,0 +1,16 @@
1
+ document[
2
+ head[
3
+ style[default.css]
4
+ ]
5
+ body[
6
+ @class[topic]
7
+ halftitlepage[
8
+ title[]
9
+ subtitle[]
10
+ author[]
11
+ ]
12
+ frontmatter[
13
+ toc[]
14
+ ]
15
+ ]
16
+ ]
@@ -0,0 +1,17 @@
1
+ document[
2
+ head[
3
+ style[default.css]
4
+ ]
5
+ body[
6
+ @class[topic]
7
+ =article[
8
+ section[
9
+ @title[{{title}}]
10
+ @id[{{id}}]
11
+ navigation[{{id}}]
12
+ {{contents}}
13
+ navigation[{{id}}]
14
+ ]
15
+ ]
16
+ ]
17
+ ]
data/lib/glyph.rb CHANGED
@@ -25,18 +25,25 @@ module Glyph
25
25
  TASKS_DIR = Pathname(__FILE__).dirname.expand_path/'../tasks'
26
26
 
27
27
  require LIB/'system_extensions'
28
+ require LIB/'utils'
28
29
  require LIB/'config'
29
30
  require LIB/'node'
31
+ require LIB/'bookmark'
30
32
  require LIB/'document'
31
33
  require LIB/'macro_validators'
34
+ require LIB/'macro_helpers'
32
35
  require LIB/'macro'
33
36
  require LIB/'syntax_node'
34
37
  require LIB/'parser'
35
38
  require LIB/'interpreter'
39
+ require LIB/'analyzer'
40
+ require LIB/'reporter'
41
+ extend Glyph::Utils
36
42
 
37
43
  class Error < RuntimeError; end
38
44
  class SyntaxError < Error; end
39
45
  class MacroError < Error
46
+ include Glyph::Utils
40
47
  attr_reader :macro
41
48
 
42
49
  # Initializes a new Glyph::MacroError
@@ -49,9 +56,10 @@ module Glyph
49
56
 
50
57
  # Displays the error message, source, path and node value (if debugging)
51
58
  def display
52
- Glyph.warning exception.message
53
- Glyph.msg " source: #{@macro.source}\n path: #{@macro.path}"
54
- Glyph.msg "#{"-"*54}\n#{@macro.node.to_s.gsub(/\t/, ' ')}\n#{"-"*54}" if Glyph.debug?
59
+ warning exception.message
60
+ path = @macro.path.blank? ? "" : "\n path: #{@macro.path}"
61
+ msg " source: #{@macro.source_name}#{path}"
62
+ msg "#{"-"*54}\n#{@macro.node.to_s.gsub(/\t/, ' ')}\n#{"-"*54}" if Glyph.debug?
55
63
  end
56
64
  end
57
65
  class MutualInclusionError < MacroError; end
@@ -65,6 +73,9 @@ module Glyph
65
73
  # All the currently-loaded macros
66
74
  MACROS = {}
67
75
 
76
+ # All macro aliases
77
+ ALIASES = {:by_alias => {}, :by_def => {}}
78
+
68
79
  begin
69
80
  unless const_defined? :MODE then
70
81
  MODE = {
@@ -139,6 +150,7 @@ module Glyph
139
150
  # Restores Glyph configuration (keeping all overrides and project settings)
140
151
  def self.config_refresh
141
152
  CONFIG.merge!(SYSTEM_CONFIG.merge(GLOBAL_CONFIG.merge(PROJECT_CONFIG)))
153
+ Glyph.safe_mode = Glyph['options.safe_mode']
142
154
  end
143
155
 
144
156
  # Resets Glyph configuration (removing all overrides and project settings)
@@ -148,13 +160,6 @@ module Glyph
148
160
  self.config_refresh
149
161
  end
150
162
 
151
- # Returns true if the PROJECT constant is set to a valid Glyph project directory
152
- def self.project?
153
- children = ["text", "output", "snippets.yml", "config.yml", "document.glyph"].sort
154
- actual_children = PROJECT.children.map{|c| c.basename.to_s}.sort
155
- (actual_children & children) == children
156
- end
157
-
158
163
  # Resets Glyph completely, i.e.:
159
164
  # * Re-enables all Glyph Rake tasks
160
165
  # * Resets the configuration to system defaults
@@ -198,9 +203,22 @@ module Glyph
198
203
  MACROS[name.to_sym] = block
199
204
  end
200
205
 
201
- def self.rewrite(name, &block)
202
- MACROS[name.to_sym] = lambda do
203
- rewrite &block
206
+ #@since 0.4.0
207
+ # Creates a new macro by rewriting.
208
+ # @param [Symbol, String] name the name of the macro
209
+ # @param [String] text the Glyph code used to define the macro
210
+ def self.rewrite(name, text)
211
+ macro name do
212
+ body = text.dup
213
+ # Parameters
214
+ body.gsub!(/\{\{(\d+)\}\}/) do
215
+ raw_param($1.to_i).strip
216
+ end
217
+ # Attributes
218
+ body.gsub!(/\{\{([^\[\]\|\\\s]+)\}\}/) do
219
+ raw_attr($1.to_sym).strip
220
+ end
221
+ interpret body
204
222
  end
205
223
  end
206
224
 
@@ -210,12 +228,11 @@ module Glyph
210
228
  # {:old_name => :new_name}
211
229
  def self.macro_alias(pair)
212
230
  name = pair.keys[0].to_sym
213
- found = MACROS[name]
214
- if found then
215
- self.warning "Invalid alias: macro '#{name}' already exists."
216
- return
217
- end
218
- MACROS[name] = MACROS[pair.values[0].to_sym]
231
+ orig = pair.values[0].to_sym
232
+ ALIASES[:by_def][orig] = [] unless ALIASES[:by_def][orig]
233
+ ALIASES[:by_def][orig] << name unless ALIASES[:by_def][orig].include? name
234
+ ALIASES[:by_alias][name] = orig
235
+ MACROS[name] = MACROS[orig]
219
236
  end
220
237
 
221
238
  # Compiles a single Glyph file
@@ -267,36 +284,6 @@ module Glyph
267
284
  end
268
285
 
269
286
 
270
- # Prints a message
271
- # @param [String] message the message to print
272
- def self.msg(message)
273
- puts message unless Glyph['system.quiet']
274
- end
275
-
276
- # Prints an informational message
277
- # @param [String] message the message to print
278
- def self.info(message)
279
- puts "-- #{message}" unless Glyph['system.quiet']
280
- end
281
-
282
- # Prints a warning
283
- # @param [String] message the message to print
284
- def self.warning(message)
285
- puts "-> warning: #{message}" unless Glyph['system.quiet']
286
- end
287
-
288
- # Prints an error
289
- # @param [String] message the message to print
290
- def self.error(message)
291
- puts "=> error: #{message}" unless Glyph['system.quiet']
292
- end
293
-
294
- # Prints a message if running in debug mode
295
- # @param [String] message the message to print
296
- def self.debug(message)
297
- puts message if Glyph.debug?
298
- end
299
-
300
287
  end
301
288
 
302
289
  Glyph.setup
@@ -0,0 +1,253 @@
1
+ module Glyph
2
+
3
+ # @since 0.4.0
4
+ # This class is used to collect statistics about a Glyph document.
5
+ class Analyzer
6
+
7
+ include Glyph::Utils
8
+
9
+ attr_reader :stats
10
+
11
+ # Initializes a new Analyzer
12
+ # @param [Glyph::Document] doc the document to analyze
13
+ def initialize(doc=Glyph.document)
14
+ @doc = doc
15
+ @stats = {}
16
+ @macros = []
17
+ @macros_by_def = {}
18
+ end
19
+
20
+ # Helper method used to return an array of specific macro instances
21
+ # @param [String, Symbol] name the name of the macro definition
22
+ def macro_array_for(name)
23
+ return @macros_by_def[name.to_sym] if @macros_by_def[name.to_sym]
24
+ key = @macros_by_def.keys.select{|k| macro_eq?(k, name.to_sym) }[0] || name.to_sym
25
+ @macros_by_def[key] = [] unless @macros_by_def[key]
26
+ @macros_by_def[key]
27
+ end
28
+
29
+ # Iterator over specific macro instances
30
+ # @param [String, Symbol] name the name of the macro definition (if left blank, iterates over all macro instances)
31
+ # @yieldparam [Glyph::MacroNode] n the macro node
32
+ def with_macros(name=nil, &block)
33
+ raise ArgumentError, "No block given" unless block_given?
34
+ name = name.to_sym if name
35
+ if !name then
36
+ unless @macros.blank? then
37
+ @macros.each(&block)
38
+ else
39
+ @doc.structure.descend do |n, level|
40
+ if n.is_a?(Glyph::MacroNode) && n.source
41
+ @macros << n
42
+ macro_array_for(n[:name]) << n
43
+ block.call n
44
+ end
45
+ end
46
+ end
47
+ else
48
+ existing = @macros_by_def[name]
49
+ if existing then
50
+ existing.each(&block)
51
+ else
52
+ macros = []
53
+ @doc.structure.descend do |n, level|
54
+ if n.is_a?(Glyph::MacroNode) && macro_eq?(name, n[:name]) && n.source
55
+ macros << n
56
+ block.call n
57
+ end
58
+ end
59
+ @macros_by_def[name] = macros
60
+ end
61
+ end
62
+ end
63
+
64
+ # Retrieves statistics of a given type
65
+ # @param [String, Symbol] stats_type the type of stats to retrieve
66
+ # (:macros, :bookmarks, :links, :snippets, :files, :global, :macro, :bookmark, :snippet, :link)
67
+ # @param [String, Symbol] *args Stats parameter(s) (e.g. a macro name, bookmark ID, etc.)
68
+ def stats_for(stats_type, *args)
69
+ begin
70
+ send :"stats_#{stats_type}", *args
71
+ rescue NoMethodError => e
72
+ raise RuntimeError, "Unable to calculate #{stats_type} stats"
73
+ end
74
+ end
75
+
76
+ protected
77
+
78
+ def stats_global
79
+ stats_macros
80
+ stats_bookmarks
81
+ stats_links
82
+ stats_snippets
83
+ stats_files
84
+ end
85
+
86
+ def stats_macros
87
+ c = @stats[:macros] = {}
88
+ c[:aliases] = Glyph::ALIASES[:by_alias].keys.sort
89
+ c[:definitions] = (Glyph::MACROS.keys - c[:aliases]).uniq.sort
90
+ c[:instances] = []
91
+ with_macros {|n| c[:instances] << n[:name]}
92
+ c[:used_definitions] = c[:instances].map{|m| macro_definition_for(m) || m}.uniq.sort
93
+ end
94
+
95
+ def stats_macro(name)
96
+ name = name.to_sym
97
+ raise ArgumentError, "Unknown macro '#{name}'" unless Glyph::MACROS.include? name
98
+ c = @stats[:macro] = {}
99
+ c[:param] = name
100
+ c[:instances] = []
101
+ c[:alias_for] = macro_definition_for name
102
+ files = {}
103
+ with_macros(name) do |n|
104
+ unless n.source.blank? then
105
+ c[:instances] << n[:name]
106
+ files[n.source] ||= 0
107
+ files[n.source] += 1
108
+ end
109
+ end
110
+ raise ArgumentError, "Macro '#{name}' is not used in this document" if c[:instances].blank?
111
+ if c[:alias_for] && !name.in?(c[:instances]) then
112
+ raise ArgumentError, "Macro '#{name}' is not used in this document, did you mean '#{c[:alias_for]}'?"
113
+ end
114
+ c[:files] = files.to_a.sort
115
+ end
116
+
117
+ def stats_bookmarks
118
+ c = @stats[:bookmarks] = {}
119
+ c[:codes] = []
120
+ files = {}
121
+ @doc.bookmarks.each_pair do |k, v|
122
+ c[:codes] << k
123
+ files[v.file] ||= 0
124
+ files[v.file] +=1
125
+ end
126
+ c[:codes].sort!
127
+ referenced = {}
128
+ with_macros(:link) do |n|
129
+ target =n.parameters[0][:value].to_s
130
+ if target.match(/^#/) then
131
+ code = target.gsub(/^#/, '').to_sym
132
+ referenced[code] ||= 0
133
+ referenced[code] += 1
134
+ end
135
+ end
136
+ c[:referenced] = referenced.to_a.sort
137
+ c[:unreferenced] = c[:codes] - c[:referenced].map{|e| e[0]}
138
+ end
139
+
140
+ def stats_bookmark(name)
141
+ code = name.to_s.gsub(/^#/, '').to_sym
142
+ raise ArgumentError, "Bookmark '#{code}' does not exist" unless @doc.bookmark? code
143
+ c = @stats[:bookmark] = {}
144
+ bmk = @doc.bookmark? code
145
+ c[:param] = name
146
+ c[:definition] = bmk.definition.to_s
147
+ c[:file] = bmk.file.to_s
148
+ c[:type] = bmk.is_a?(Glyph::Header) ? :header : :anchor
149
+ references = {}
150
+ with_macros(:link) do |n|
151
+ target = n.parameters[0].to_s.gsub(/^#/, '').to_sym
152
+ count_occurrences_for references, target, n if target == code
153
+ end
154
+ c[:references]= references[code][:files] rescue []
155
+ end
156
+
157
+ def stats_links
158
+ c = @stats[:links] = {}
159
+ internal = {}
160
+ external = {}
161
+ with_macros(:link) do |n|
162
+ target = n.parameters[0].to_s
163
+ collection = target.match(/^#/) ? internal : external
164
+ #code = target.gsub(/^#/, '').to_sym
165
+ count_occurrences_for collection, target, n
166
+ end
167
+ c[:internal] = internal.to_a.sort
168
+ c[:external] = external.to_a.sort
169
+ end
170
+
171
+ def stats_link(name)
172
+ regexp = /#{name}/
173
+ links = {}
174
+ with_macros(:link) do |n|
175
+ target = n.parameters[0].to_s
176
+ if target.match regexp then
177
+ count_occurrences_for links, target, n
178
+ end
179
+ end
180
+ raise ArgumentError, "No link matching /#{name}/ was found" if links.blank?
181
+ @stats[:link] = {}
182
+ @stats[:link][:stats] = links.to_a.sort
183
+ @stats[:link][:param] = name
184
+ end
185
+
186
+ def stats_snippets
187
+ c = @stats[:snippets] = {}
188
+ snippets = {}
189
+ c[:definitions] = Glyph::SNIPPETS.keys.sort
190
+ c[:used] = []
191
+ c[:unused] = []
192
+ c[:total] = 0
193
+ with_macros(:snippet) do |n|
194
+ code = n.parameters[0].to_s.to_sym
195
+ c[:used] << code unless c[:used].include? code
196
+ c[:total] += 1
197
+ #count_occurrences_for snippets, code, n
198
+ end
199
+ #c[:used_details] = snippets.to_a.sort
200
+ c[:used].sort!
201
+ c[:unused] = (c[:definitions] - c[:used]).sort
202
+ end
203
+
204
+ def stats_snippet(name)
205
+ name = name.to_sym
206
+ snippets = {}
207
+ raise ArgumentError, "Snippet '#{name}' does not exist" unless Glyph::SNIPPETS[name]
208
+ with_macros(:snippet) do |n|
209
+ code = n.parameters[0].to_s.to_sym
210
+ if code == name then
211
+ count_occurrences_for snippets, code, n
212
+ end
213
+ end
214
+ raise ArgumentError, "Snippet '#{name}' is not used in this document" if snippets.blank?
215
+ @stats[:snippet] = {}
216
+ @stats[:snippet][:stats] = snippets[name]
217
+ @stats[:snippet][:param] = name
218
+ end
219
+
220
+ def stats_files
221
+ @stats[:files] = {}
222
+ count_files_in = lambda do |dir|
223
+ files = []
224
+ (Glyph::PROJECT/"#{dir}").find{|f| files << f if f.file? } rescue nil
225
+ files.length
226
+ end
227
+ @stats[:files][:text] = count_files_in.call 'text'
228
+ @stats[:files][:lib] = count_files_in.call 'lib'
229
+ @stats[:files][:styles] = count_files_in.call 'styles'
230
+ @stats[:files][:layouts] = count_files_in.call 'layouts'
231
+ @stats[:files][:images] = count_files_in.call 'images'
232
+ end
233
+
234
+ private
235
+
236
+ def count_occurrences_for(collection, code, n)
237
+ collection[code] ||= {:total => 0, :files =>[]} unless collection[code]
238
+ collection[code][:total] += 1
239
+ coll = collection[code][:files]
240
+ added = false
241
+ coll.each do |file|
242
+ if file[0] == n.source then
243
+ file[1] += 1
244
+ added = true
245
+ break
246
+ end
247
+ end
248
+ coll << [n.source, 1] unless added
249
+ coll.sort!
250
+ end
251
+
252
+ end
253
+ end