glyph 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/AUTHORS.textile +8 -7
- data/CHANGELOG.textile +89 -8
- data/LICENSE.textile +1 -2
- data/README.textile +89 -61
- data/Rakefile +12 -10
- data/VERSION +1 -1
- data/benchmark.rb +1 -1
- data/book/config.yml +18 -4
- data/book/document.glyph +269 -45
- data/book/images/glyph/commands_tasks.png +0 -0
- data/book/images/{document_generation.png → glyph/document_generation.png} +0 -0
- data/book/images/glyph/glyph.eps +123 -0
- data/book/images/glyph/glyph.png +0 -0
- data/book/images/glyph/glyph.svg +29 -0
- data/book/lib/commands/commands.rb +11 -0
- data/book/lib/layouts/bookindex.glyph +127 -0
- data/book/lib/layouts/bookpage.glyph +129 -0
- data/book/lib/layouts/project.glyph +26 -0
- data/book/lib/macros/reference.rb +27 -7
- data/book/lib/tasks/tasks.rake +52 -0
- data/book/snippets.yml +1 -1
- data/book/text/{acknowledgement.glyph → acknowledgements.glyph} +4 -2
- data/book/text/changelog.glyph +29 -3
- data/book/text/compiling/compiling.glyph +44 -20
- data/book/text/compiling/lite_mode.glyph +0 -4
- data/book/text/compiling/programmatic_usage.glyph +1 -5
- data/book/text/config/document.glyph +35 -0
- data/book/text/config/filters.glyph +28 -0
- data/book/text/config/options.glyph +25 -0
- data/book/text/config/output.glyph +83 -0
- data/book/text/extending/bookmarks_headers.glyph +0 -5
- data/book/text/extending/command.glyph +56 -0
- data/book/text/extending/commands_tasks.glyph +39 -0
- data/book/text/extending/further_reading.glyph +0 -3
- data/book/text/extending/internals.glyph +3 -5
- data/book/text/extending/interpreting.glyph +0 -4
- data/book/text/extending/layouts.glyph +68 -0
- data/book/text/extending/macro_def.glyph +0 -5
- data/book/text/extending/output_format.glyph +78 -0
- data/book/text/extending/params_attrs.glyph +0 -3
- data/book/text/extending/placeholders.glyph +0 -4
- data/book/text/extending/task.glyph +46 -0
- data/book/text/extending/validators.glyph +5 -6
- data/book/text/getting_started/configuration.glyph +1 -5
- data/book/text/getting_started/create_project.glyph +1 -5
- data/book/text/getting_started/structure.glyph +0 -4
- data/book/text/introduction.glyph +100 -75
- data/book/text/license.glyph +1 -2
- data/book/text/macros/macros_block.glyph +8 -4
- data/book/text/macros/macros_core.glyph +0 -3
- data/book/text/macros/macros_filters.glyph +2 -7
- data/book/text/macros/macros_inline.glyph +0 -4
- data/book/text/macros/macros_structure.glyph +0 -4
- data/book/text/ref_commands.glyph +29 -7
- data/book/text/stats/bookmarks.glyph +49 -0
- data/book/text/stats/links.glyph +90 -0
- data/book/text/stats/macros.glyph +73 -0
- data/book/text/stats/snippets.glyph +50 -0
- data/book/text/stats/stats.glyph +79 -0
- data/book/text/text_editing/attribute_intro.glyph +22 -0
- data/book/text/text_editing/code.glyph +0 -5
- data/book/text/text_editing/conditionals.glyph +0 -4
- data/book/text/text_editing/esc_quot.glyph +64 -0
- data/book/text/text_editing/evaluation.glyph +0 -3
- data/book/text/text_editing/glyph_files.glyph +0 -3
- data/book/text/text_editing/images.glyph +0 -5
- data/book/text/text_editing/inclusions.glyph +0 -4
- data/book/text/text_editing/links.glyph +2 -7
- data/book/text/text_editing/macro_intro.glyph +1 -98
- data/book/text/text_editing/raw_html.glyph +0 -87
- data/book/text/text_editing/section_aliases.glyph +28 -0
- data/book/text/text_editing/sections.glyph +1 -32
- data/book/text/text_editing/stylesheets.glyph +3 -5
- data/book/text/text_editing/topics.glyph +33 -0
- data/book/text/text_editing/xml_fallback.glyph +73 -0
- data/book/text/troubleshooting/errors_command.glyph +0 -3
- data/book/text/troubleshooting/errors_generic.glyph +21 -6
- data/book/text/troubleshooting/errors_macro.glyph +11 -8
- data/book/text/troubleshooting/errors_parser.glyph +0 -3
- data/config.yml +60 -25
- data/glyph.gemspec +90 -36
- data/layouts/web/index.glyph +16 -0
- data/layouts/web/topic.glyph +15 -0
- data/layouts/web5/index.glyph +16 -0
- data/layouts/web5/topic.glyph +17 -0
- data/lib/glyph.rb +36 -49
- data/lib/glyph/analyzer.rb +253 -0
- data/lib/glyph/bookmark.rb +92 -0
- data/lib/glyph/commands.rb +9 -221
- data/lib/glyph/commands/add.rb +8 -0
- data/lib/glyph/commands/compile.rb +93 -0
- data/lib/glyph/commands/config.rb +38 -0
- data/lib/glyph/commands/init.rb +6 -0
- data/lib/glyph/commands/outline.rb +45 -0
- data/lib/glyph/commands/stats.rb +48 -0
- data/lib/glyph/commands/todo.rb +29 -0
- data/lib/glyph/config.rb +2 -0
- data/lib/glyph/document.rb +61 -30
- data/lib/glyph/interpreter.rb +2 -2
- data/lib/glyph/macro.rb +14 -5
- data/lib/glyph/macro_helpers.rb +280 -0
- data/lib/glyph/macro_validators.rb +37 -2
- data/lib/glyph/reporter.rb +182 -0
- data/lib/glyph/syntax_node.rb +37 -10
- data/lib/glyph/system_extensions.rb +8 -45
- data/lib/glyph/utils.rb +148 -0
- data/macros/core.rb +10 -15
- data/macros/filters.rb +4 -5
- data/macros/html/block.rb +46 -30
- data/macros/html/inline.rb +9 -35
- data/macros/html/structure.rb +59 -72
- data/macros/html5/block.rb +69 -0
- data/macros/html5/inline.rb +24 -0
- data/macros/html5/structure.rb +139 -0
- data/macros/xml.rb +1 -1
- data/spec/files/custom_command.rb +6 -0
- data/spec/files/custom_tasks.rake +6 -0
- data/spec/files/document_for_stats.glyph +12 -0
- data/spec/files/references.glyph +4 -0
- data/spec/files/web1.glyph +11 -0
- data/spec/files/web2.glyph +10 -0
- data/spec/files/web_doc.glyph +23 -0
- data/spec/lib/analyzer_spec.rb +137 -0
- data/spec/lib/bookmark_spec.rb +64 -0
- data/spec/lib/commands_spec.rb +30 -5
- data/spec/lib/document_spec.rb +49 -9
- data/spec/lib/glyph_spec.rb +21 -1
- data/spec/lib/macro_spec.rb +6 -6
- data/spec/lib/macro_validators_spec.rb +24 -0
- data/spec/lib/reporter_spec.rb +132 -0
- data/spec/macros/core_spec.rb +2 -3
- data/spec/macros/filters_spec.rb +2 -2
- data/spec/macros/html5_spec.rb +101 -0
- data/spec/macros/macros_spec.rb +16 -6
- data/spec/macros/web5_spec.rb +32 -0
- data/spec/macros/web_spec.rb +59 -0
- data/spec/macros/xml_spec.rb +1 -1
- data/spec/spec_helper.rb +24 -4
- data/spec/tasks/generate_spec.rb +54 -0
- data/spec/tasks/load_spec.rb +29 -3
- data/spec/tasks/project_spec.rb +21 -3
- data/styles/default.css +40 -4
- data/styles/pagination.css +59 -41
- data/tasks/generate.rake +110 -31
- data/tasks/load.rake +39 -7
- data/tasks/project.rake +9 -7
- metadata +115 -34
- data/book/images/glyph.png +0 -0
- data/book/images/glyph.svg +0 -351
- data/book/output/html/glyph.html +0 -4482
- data/book/output/html/images/document_generation.png +0 -0
- data/book/output/html/images/glyph.png +0 -0
- data/book/output/html/images/glyph.svg +0 -351
- data/book/output/pdf/glyph.pdf +4 -10254
- data/book/script/authors +0 -1
- data/book/script/changelog +0 -1
- data/book/script/license +0 -1
- data/book/script/readme +0 -1
- data/book/text/ref_config.glyph +0 -100
- data/book/text/ref_macros.glyph +0 -6
- data/book/text/troubleshooting/errors_intro.glyph +0 -3
@@ -0,0 +1,45 @@
|
|
1
|
+
GLI.desc 'Display the document outline'
|
2
|
+
command :outline do |c|
|
3
|
+
c.desc "Limit to level N"
|
4
|
+
c.flag :l, :level
|
5
|
+
c.desc "Show file names"
|
6
|
+
c.switch :f, :files
|
7
|
+
c.desc "Show titles"
|
8
|
+
c.switch :t, :titles
|
9
|
+
c.desc "Show IDs"
|
10
|
+
c.switch :i, :ids
|
11
|
+
c.action do |global_options, options, args|
|
12
|
+
levels = options[:l]
|
13
|
+
ids = options[:i]
|
14
|
+
files = options[:f]
|
15
|
+
titles = options[:t]
|
16
|
+
titles = true if !ids && !levels && !files || levels && !ids
|
17
|
+
Glyph['system.quiet'] = true
|
18
|
+
Glyph.run "generate:document"
|
19
|
+
Glyph['system.quiet'] = false
|
20
|
+
puts "====================================="
|
21
|
+
puts "#{Glyph['document.title']} - Outline"
|
22
|
+
puts "====================================="
|
23
|
+
Glyph.document.structure.descend do |n, level|
|
24
|
+
if n.is_a?(Glyph::MacroNode) then
|
25
|
+
case
|
26
|
+
when n[:name].in?(Glyph['system.structure.headers']) then
|
27
|
+
header = Glyph.document.header?(n[:header].code) rescue nil
|
28
|
+
next if !header || levels && header.level-1 > levels.to_i
|
29
|
+
last_level = header.level
|
30
|
+
h_id = ids ? "[##{header.code}]" : ""
|
31
|
+
h_title = titles ? "#{header.title} " : ""
|
32
|
+
text = (" "*(header.level-1))+"- "+h_title+h_id
|
33
|
+
puts text unless text.blank?
|
34
|
+
when n[:name] == :include then
|
35
|
+
if files && n.find_parent{|p| p[:name] == :document && p.is_a?(Glyph::MacroNode)} then
|
36
|
+
# When using the book or article macros, includes appear twice:
|
37
|
+
# * in the macro parameters
|
38
|
+
# * as children of the document macro
|
39
|
+
puts "=== #{n.param(0)}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
GLI.desc 'Display statistics'
|
2
|
+
command :stats do |c|
|
3
|
+
c.desc "Display stats about macros"
|
4
|
+
c.switch [:m, :macros]
|
5
|
+
c.desc "Display stats about snippets"
|
6
|
+
c.switch [:s, :snippets]
|
7
|
+
c.desc "Display stats about bookmarks"
|
8
|
+
c.switch [:b, :bookmarks]
|
9
|
+
c.desc "Display stats about links"
|
10
|
+
c.switch [:l, :links]
|
11
|
+
c.desc "Display stats about project files"
|
12
|
+
c.switch [:f, :files]
|
13
|
+
c.desc "Display stats about a single macro"
|
14
|
+
c.flag :macro
|
15
|
+
c.desc "Display stats about a single bookmark"
|
16
|
+
c.flag :bookmark
|
17
|
+
c.desc "Display stats about links matching a regular expression"
|
18
|
+
c.flag :link
|
19
|
+
c.desc "Display stats about a single snippet"
|
20
|
+
c.flag :snippet
|
21
|
+
c.action do |global_options, options, args|
|
22
|
+
Glyph.info "Collecting stats..."
|
23
|
+
Glyph.run 'generate:document'
|
24
|
+
analyzer = Glyph::Analyzer.new
|
25
|
+
no_switches = true
|
26
|
+
[[:m, :macros], [:s, :snippets], [:b, :bookmarks], [:l, :links], [:f, :files]].each do |s|
|
27
|
+
if options[s[0]] then
|
28
|
+
analyzer.stats_for s[1]
|
29
|
+
no_switches = false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
no_flags = true
|
33
|
+
[:macro, :bookmark, :link, :snippet].each do |f|
|
34
|
+
if options[f] then
|
35
|
+
analyzer.stats_for f, options[f]
|
36
|
+
no_flags = false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
analyzer.stats_for :global if no_switches && no_flags
|
40
|
+
puts "====================================="
|
41
|
+
puts "#{Glyph['document.title']} - Statistics"
|
42
|
+
puts "====================================="
|
43
|
+
puts
|
44
|
+
reporter = Glyph::Reporter.new(analyzer.stats)
|
45
|
+
reporter.detailed = false if no_switches && no_flags
|
46
|
+
reporter.display
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
GLI.desc 'Display all project TODO items'
|
2
|
+
command :todo do |c|
|
3
|
+
c.action do |global_options, options, args|
|
4
|
+
Glyph['system.quiet'] = true
|
5
|
+
Glyph.run "generate:document"
|
6
|
+
Glyph['system.quiet'] = false
|
7
|
+
unless Glyph.document.todos.blank?
|
8
|
+
puts "====================================="
|
9
|
+
puts "#{Glyph['document.title']} - TODOs"
|
10
|
+
puts "====================================="
|
11
|
+
# Group items
|
12
|
+
if Glyph.document.todos.respond_to? :group_by then
|
13
|
+
Glyph.document.todos.group_by{|e| e[:source]}.each_pair do |k, v|
|
14
|
+
puts
|
15
|
+
puts "=== #{k} "
|
16
|
+
v.each do |i|
|
17
|
+
puts " * #{i[:text]}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
Glyph.document.todos.each do |t|
|
22
|
+
Glyph.info t
|
23
|
+
end
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Glyph.info "Nothing left to do."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/glyph/config.rb
CHANGED
@@ -4,6 +4,8 @@ module Glyph
|
|
4
4
|
# and provides some useful methods to access keys and subkeys.
|
5
5
|
class Config
|
6
6
|
|
7
|
+
include Glyph::Utils
|
8
|
+
|
7
9
|
# Initializes the configuration with a hash of options:
|
8
10
|
# * :file (default: nil) - A YAML file to read data from
|
9
11
|
# * :data (default: {})- The initial contents
|
data/lib/glyph/document.rb
CHANGED
@@ -18,24 +18,28 @@ module Glyph
|
|
18
18
|
['\\|', '|']
|
19
19
|
]
|
20
20
|
|
21
|
-
attr_reader :bookmarks, :placeholders, :headers, :context, :errors, :todos
|
21
|
+
attr_reader :bookmarks, :placeholders, :headers, :styles, :context, :errors, :todos, :topics, :links, :toc
|
22
22
|
|
23
23
|
# Creates a new document
|
24
24
|
# @param [GlyphSyntaxNode] tree the syntax tree to be evaluate
|
25
25
|
# @param [Glyph::Node] context the context associated with the tree
|
26
26
|
# @raise [RuntimeError] unless tree responds to :evaluate
|
27
|
-
def initialize(tree, context)
|
27
|
+
def initialize(tree, context={})
|
28
28
|
@tree = tree
|
29
29
|
@context = context
|
30
|
-
@
|
30
|
+
@context[:source] ||= {:file => nil, :name => '--', :topic => nil}
|
31
31
|
@placeholders = {}
|
32
|
-
@
|
32
|
+
@bookmarks = {}
|
33
|
+
@headers = {}
|
34
|
+
@styles = []
|
33
35
|
@errors = []
|
34
36
|
@todos = []
|
37
|
+
@topics = []
|
38
|
+
@links = []
|
39
|
+
@toc = {}
|
35
40
|
@state = :new
|
36
41
|
end
|
37
42
|
|
38
|
-
|
39
43
|
# Returns a tree of Glyph::Node objects corresponding to the analyzed document
|
40
44
|
# @raise [RuntimeError] unless the document has been analized
|
41
45
|
def structure
|
@@ -43,13 +47,18 @@ module Glyph
|
|
43
47
|
@tree
|
44
48
|
end
|
45
49
|
|
46
|
-
# Copies bookmarks, headers, todos and placeholders from another Glyph::Document
|
50
|
+
# Copies bookmarks, headers, todos, styles and placeholders from another Glyph::Document
|
47
51
|
# @param [Glyph::Document] document a valid Glyph::Document
|
48
52
|
def inherit_from(document)
|
49
53
|
@bookmarks = document.bookmarks
|
50
54
|
@headers = document.headers
|
51
55
|
@todos = document.todos
|
56
|
+
@styles = document.styles
|
57
|
+
@topics = document.topics
|
52
58
|
@placeholders = document.placeholders
|
59
|
+
@toc = document.toc
|
60
|
+
@links = document.links
|
61
|
+
self
|
53
62
|
end
|
54
63
|
|
55
64
|
# Defines a placeholder block that will be evaluated after the whole document has been analyzed
|
@@ -63,34 +72,51 @@ module Glyph
|
|
63
72
|
|
64
73
|
# Returns a stored bookmark or nil
|
65
74
|
# @param [#to_sym] key the bookmark identifier
|
66
|
-
# @return [
|
75
|
+
# @return [Glyph::Bookmark, nil] the bookmark or nil if no bookmark is found
|
67
76
|
def bookmark?(key)
|
68
77
|
@bookmarks[key.to_sym]
|
69
78
|
end
|
70
79
|
|
71
80
|
# Stores a new bookmark
|
72
|
-
# @param [Hash] hash the bookmark hash: {:id => "
|
73
|
-
# @return [
|
81
|
+
# @param [Hash] hash the bookmark hash: {:id => "BookmarkID", :title => "Bookmark Title", :file => "dir/preface.glyph"}
|
82
|
+
# @return [Glyph::Bookmark] the stored bookmark
|
83
|
+
# @raise [RuntimeError] if the bookmark is already defined.
|
74
84
|
def bookmark(hash)
|
75
|
-
|
76
|
-
|
77
|
-
@bookmarks[
|
78
|
-
|
85
|
+
b = Glyph::Bookmark.new(hash)
|
86
|
+
raise RuntimeError, "Bookmark '#{b.code}' already exists" if @bookmarks.has_key? b.code
|
87
|
+
@bookmarks[b.code] = b
|
88
|
+
b
|
79
89
|
end
|
80
90
|
|
81
91
|
# Stores a new header
|
82
|
-
# @param [Hash] hash the header hash: {:id => "
|
83
|
-
# @return [
|
92
|
+
# @param [Hash] hash the header hash: {:id => "Bookmark_ID", :title => "Bookmark Title", :level => 3}
|
93
|
+
# @return [Glyph::Header] the stored header
|
94
|
+
# @raise [RuntimeError] if the bookmark is already defined.
|
84
95
|
def header(hash)
|
85
|
-
|
86
|
-
|
96
|
+
b = Glyph::Header.new(hash)
|
97
|
+
raise RuntimeError, "Bookmark '#{b.code}' already exists" if @bookmarks.has_key? b.code
|
98
|
+
@bookmarks[b.code] = b
|
99
|
+
@headers[b.code] = b
|
100
|
+
b
|
87
101
|
end
|
88
102
|
|
89
103
|
# Returns a stored header or nil
|
90
|
-
# @param [String] key the header identifier
|
91
|
-
# @return [
|
104
|
+
# @param [String, Symbol] key the header identifier
|
105
|
+
# @return [Glyph::Header, nil] the header or nil if no header is found
|
92
106
|
def header?(key)
|
93
|
-
@headers
|
107
|
+
@headers[key.to_sym]
|
108
|
+
end
|
109
|
+
|
110
|
+
# @since 0.4.0
|
111
|
+
# Stores a stylesheet
|
112
|
+
# @param [String] file the stylesheet file
|
113
|
+
# @raises [RuntimeError] if the stylesheet is already specified for the document (unless the output has more than one file)
|
114
|
+
def style(file)
|
115
|
+
f = Pathname.new file
|
116
|
+
if @styles.include?(f) && !Glyph.multiple_output_files? then
|
117
|
+
raise RuntimeError, "Stylesheet '#{f}' already specified for the current document"
|
118
|
+
end
|
119
|
+
@styles << f
|
94
120
|
end
|
95
121
|
|
96
122
|
# Analyzes the document by evaluating its @tree
|
@@ -114,18 +140,23 @@ module Glyph
|
|
114
140
|
raise RuntimeError, "Document cannot be finalized due to previous errors" unless @context[:document].errors.blank?
|
115
141
|
# Substitute placeholders
|
116
142
|
ESCAPES.each{|e| @output.gsub! e[0], e[1]}
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
143
|
+
@placeholders.each_pair do |key, value|
|
144
|
+
begin
|
145
|
+
key_s = key.to_s
|
146
|
+
value_s = value.call(self).to_s
|
147
|
+
toc[:contents].gsub! key_s, value_s if toc[:contents].to_s.match key_s
|
148
|
+
if Glyph.multiple_output_files? then
|
149
|
+
@topics.each do |t|
|
150
|
+
ESCAPES.each{|e| t[:contents].gsub! e[0], e[1]}
|
151
|
+
t[:contents].gsub! key_s, value_s
|
152
|
+
end
|
126
153
|
end
|
154
|
+
@output.gsub! key_s, value_s
|
155
|
+
rescue Glyph::MacroError => e
|
156
|
+
e.macro.macro_warning e.message, e
|
157
|
+
rescue Exception => e
|
158
|
+
Glyph.warning e.message
|
127
159
|
end
|
128
|
-
rescue Exception => e
|
129
160
|
end
|
130
161
|
@state = :finalized
|
131
162
|
end
|
data/lib/glyph/interpreter.rb
CHANGED
@@ -11,7 +11,7 @@ module Glyph
|
|
11
11
|
# @param [Hash] context the context to pass along when expanding macros
|
12
12
|
def initialize(text, context={})
|
13
13
|
@context = context
|
14
|
-
@context[:source] ||= {:name => "--"}
|
14
|
+
@context[:source] ||= {:name => "--", :file => nil, :topic => nil}
|
15
15
|
@text = text
|
16
16
|
@parser = Glyph::Parser.new text, @context[:source][:name]
|
17
17
|
end
|
@@ -47,7 +47,7 @@ module Glyph
|
|
47
47
|
@document.inherit_from @context[:document] if @context[:document]
|
48
48
|
@tree
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
data/lib/glyph/macro.rb
CHANGED
@@ -8,8 +8,10 @@ module Glyph
|
|
8
8
|
class Macro
|
9
9
|
|
10
10
|
include Validators
|
11
|
+
include Helpers
|
12
|
+
include Utils
|
11
13
|
|
12
|
-
attr_reader :node, :
|
14
|
+
attr_reader :node, :source_name, :source_file, :source_topic
|
13
15
|
|
14
16
|
# Creates a new macro instance from a Node
|
15
17
|
# @param [Node] node a node populated with macro data
|
@@ -17,14 +19,20 @@ module Glyph
|
|
17
19
|
@node = node
|
18
20
|
@name = @node[:name]
|
19
21
|
@updated_source = nil
|
20
|
-
@
|
22
|
+
@source_name = @node[:source][:name] || nil rescue "--"
|
23
|
+
@source_topic = @node[:source][:topic] || nil rescue "--"
|
24
|
+
@source_file = @node[:source][:file] rescue nil
|
21
25
|
end
|
22
26
|
|
23
27
|
# Resets the name of the updated source (call before calling
|
24
28
|
# Macro#interpret)
|
25
29
|
# @param [String] name the source name
|
26
|
-
|
27
|
-
|
30
|
+
# @param [String] file the source file
|
31
|
+
# @param [String] topic the topic file
|
32
|
+
# @since 0.3.0
|
33
|
+
def update_source(name, file=nil, topic=nil)
|
34
|
+
file ||= @node[:source][:file] rescue nil
|
35
|
+
@updated_source = {:name => name, :file => file, :topic => topic}
|
28
36
|
end
|
29
37
|
|
30
38
|
# Returns a Glyph code representation of the specified parameter
|
@@ -180,7 +188,7 @@ module Glyph
|
|
180
188
|
if e.is_a?(Glyph::MacroError) then
|
181
189
|
e.display
|
182
190
|
else
|
183
|
-
message = "#{msg}\n source: #{@
|
191
|
+
message = "#{msg}\n source: #{@source_name}\n path: #{path}"
|
184
192
|
if Glyph.debug? then
|
185
193
|
message << %{\n#{"-"*54}\n#{@node.to_s.gsub(/\t/, ' ')}\n#{"-"*54}}
|
186
194
|
if e then
|
@@ -206,6 +214,7 @@ module Glyph
|
|
206
214
|
context[:document] = @node[:document]
|
207
215
|
interpreter = Glyph::Interpreter.new string, context
|
208
216
|
subtree = interpreter.parse
|
217
|
+
subtree[:source] = context[:source]
|
209
218
|
@node << subtree
|
210
219
|
result = interpreter.document.output
|
211
220
|
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module Glyph
|
2
|
+
class Macro
|
3
|
+
|
4
|
+
# This module includes some output-agnostic methods used by the most common Glyph macros.
|
5
|
+
# @since 0.4.0
|
6
|
+
module Helpers
|
7
|
+
|
8
|
+
# Renders a link
|
9
|
+
# @param [String] target the target of the link
|
10
|
+
# @param[String] title the title of the link
|
11
|
+
# @yield [link_path, link_title] the block to call to render the link
|
12
|
+
# @yieldparam [String] link_path the path to the link target
|
13
|
+
# @yieldparam [String] link_title the title of the link
|
14
|
+
def link_element_for(target, title, &block)
|
15
|
+
if target.match /^#/ then
|
16
|
+
@node[:document].links << target
|
17
|
+
anchor = target.gsub /^#/, ''
|
18
|
+
bmk = bookmark? anchor
|
19
|
+
if !bmk then
|
20
|
+
placeholder do |document|
|
21
|
+
bmk = document.bookmark?(anchor)
|
22
|
+
macro_error "Bookmark '#{anchor}' does not exist" unless bmk
|
23
|
+
bmk_title = title
|
24
|
+
bmk_title = bmk.title if bmk_title.blank?
|
25
|
+
block.call bmk.link(@source_file), bmk_title
|
26
|
+
end
|
27
|
+
else
|
28
|
+
bmk_title = title
|
29
|
+
bmk_title = bmk.title if bmk_title.blank?
|
30
|
+
block.call bmk.link(@source_file), bmk_title
|
31
|
+
end
|
32
|
+
else
|
33
|
+
if Glyph['options.url_validation'] && !@node[:document].links.include?(target) then
|
34
|
+
begin
|
35
|
+
url = URI.parse(target.gsub(/\\\./, ''))
|
36
|
+
rescue Exception => e
|
37
|
+
macro_warning "Invalid URL: #{url||target}", e
|
38
|
+
end
|
39
|
+
response = Net::HTTP.get_response(url)
|
40
|
+
debug "Checking link URL: #{url} (#{response.code})"
|
41
|
+
if response.code.to_i > 302 then
|
42
|
+
macro_warning "Linked URL '#{url}' returned status #{response.code} (#{response.message})"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
@node[:document].links << target
|
46
|
+
title ||= target
|
47
|
+
block.call target, title
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Renders a For More Information note
|
52
|
+
# @param [String] topic the topic of the note
|
53
|
+
# @param [String] href the reference to link to
|
54
|
+
# @yield [topic, link] the block used to render the FMI note
|
55
|
+
def fmi_element_for(topic, href, &block)
|
56
|
+
link = placeholder do |document|
|
57
|
+
interpret "link[#{href}]"
|
58
|
+
end
|
59
|
+
block.call topic, link
|
60
|
+
end
|
61
|
+
|
62
|
+
# Renders a draft comment element
|
63
|
+
# @yield [value] the block used to render the comment
|
64
|
+
# @yieldparam [String] value the comment text
|
65
|
+
def draftcomment_element(&block)
|
66
|
+
if Glyph['document.draft'] then
|
67
|
+
block.call value
|
68
|
+
else
|
69
|
+
""
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Renders a todo element
|
74
|
+
# @yield [value] the block used to render the todo element
|
75
|
+
# @yieldparam [String] value the todo text
|
76
|
+
def todo_element(&block)
|
77
|
+
todo = {:source => @source_name, :text => value}
|
78
|
+
@node[:document].todos << todo unless @node[:document].todos.include? todo
|
79
|
+
if Glyph['document.draft'] then
|
80
|
+
block.call value
|
81
|
+
else
|
82
|
+
""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Renders an image element
|
87
|
+
# @param [String] image the image to render
|
88
|
+
# @param [String] alt the value of the image's ALT tag
|
89
|
+
# @yield [alt, dest_file] the block used to render the image
|
90
|
+
def image_element_for(image, alt, &block)
|
91
|
+
src_file = Glyph.lite? ? image : Glyph::PROJECT/"images/#{image}"
|
92
|
+
dest_file = Glyph.lite? ? image : "images/#{image}"
|
93
|
+
warning "Image '#{image}' not found" unless Pathname.new(src_file).exist?
|
94
|
+
block.call alt, dest_file
|
95
|
+
end
|
96
|
+
|
97
|
+
# Renders a figure element
|
98
|
+
# @param [String] image the image to render
|
99
|
+
# @param [String] alt the value of the image's ALT tag
|
100
|
+
# @param [String] caption
|
101
|
+
# @yield alt, dest_file, caption] the block used to render the figure
|
102
|
+
def figure_element_for(image, alt, caption, &block)
|
103
|
+
src_file = Glyph.lite? ? image : Glyph::PROJECT/"images/#{image}"
|
104
|
+
dest_file = Glyph.lite? ? image : "images/#{image}"
|
105
|
+
warning "Figure '#{image}' not found" unless Pathname.new(src_file).exist?
|
106
|
+
block.call alt, dest_file, caption
|
107
|
+
end
|
108
|
+
|
109
|
+
# Renders a title element
|
110
|
+
def title_element(&block)
|
111
|
+
unless Glyph["document.title"].blank? then
|
112
|
+
block.call
|
113
|
+
else
|
114
|
+
""
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Renders a subtitle element
|
119
|
+
def subtitle_element(&block)
|
120
|
+
unless Glyph["document.subtitle"].blank? then
|
121
|
+
block.call
|
122
|
+
else
|
123
|
+
""
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Renders an author element
|
128
|
+
def author_element(&block)
|
129
|
+
unless Glyph['document.author'].blank? then
|
130
|
+
block.call
|
131
|
+
else
|
132
|
+
""
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Renders a revision element
|
137
|
+
def revision_element(&block)
|
138
|
+
unless Glyph["document.revision"].blank? then
|
139
|
+
block.call
|
140
|
+
else
|
141
|
+
""
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Renders a Table of Contents
|
146
|
+
# @param [Integer] depth the maximum header level
|
147
|
+
# @param [String] title the title of the TOC
|
148
|
+
# @param [Hash] procs the Proc objects used to render the TOC
|
149
|
+
# @option procs [Proc] :link used to render TOC header links (parameters: Glyph::Header).
|
150
|
+
# @option procs [Proc] :toc_list used to render the TOC list (parameters: a Proc used to traverse the document tree, the Glyph::Bookmark used for the TOC header, a Glyph::Document)
|
151
|
+
# @option procs [Proc] :toc_item used to render a TOC item (parameters: an Array of header classes, a String used for the header link)
|
152
|
+
# @option procs [Proc] :toc_sublist used to render a TOC sublist (parameters: a String containing the contents of the list)
|
153
|
+
def toc_element_for(depth, title, procs={})
|
154
|
+
return @node[:document].toc[:contents] if @node[:document].toc[:contents]
|
155
|
+
link_header = procs[:link]
|
156
|
+
toc = placeholder do |document|
|
157
|
+
descend_section = lambda do |n1, added_headers|
|
158
|
+
list = ""
|
159
|
+
added_headers ||= []
|
160
|
+
n1.descend do |n2, level|
|
161
|
+
if n2.is_a?(Glyph::MacroNode) && Glyph['system.structure.headers'].include?(n2[:name]) then
|
162
|
+
if Glyph.multiple_output_files? then
|
163
|
+
# Only consider topics/booklets when building TOC for web/web5
|
164
|
+
next if !n2.attribute(:src) && n2.child_macros.select{|child| child.attribute(:src)}.blank?
|
165
|
+
end
|
166
|
+
next if n2.find_parent{|node| Glyph['system.structure.special'].include? node[:name] }
|
167
|
+
header_hash = n2[:header]
|
168
|
+
next if depth && header_hash && (header_hash.level-1 > depth.to_i) || header_hash && !header_hash.toc?
|
169
|
+
next if added_headers.include? header_hash
|
170
|
+
added_headers << header_hash
|
171
|
+
# Check if part of frontmatter, bodymatter or backmatter
|
172
|
+
container = n2.find_parent do |node|
|
173
|
+
node.is_a?(Glyph::MacroNode) &&
|
174
|
+
node[:name].in?([:frontmatter, :bodymatter, :appendix, :backmatter])
|
175
|
+
end[:name] rescue nil
|
176
|
+
list << procs[:toc_item].call([container, n2[:name]], link_header.call(header_hash)) if header_hash
|
177
|
+
child_list = ""
|
178
|
+
n2.children.each do |c|
|
179
|
+
child_list << descend_section.call(c, added_headers)
|
180
|
+
end
|
181
|
+
list << procs[:toc_sublist].call(child_list) unless child_list.blank?
|
182
|
+
end
|
183
|
+
end
|
184
|
+
list
|
185
|
+
end
|
186
|
+
title ||= "Table of Contents"
|
187
|
+
bmk = @node[:document].bookmark?(:toc) || bookmark(:id => :toc, :file => @source_file, :title => title)
|
188
|
+
procs[:toc_list].call descend_section, bmk, document
|
189
|
+
end
|
190
|
+
@node[:document].toc[:contents] = toc.to_s
|
191
|
+
toc
|
192
|
+
end
|
193
|
+
|
194
|
+
# Renders a section element
|
195
|
+
# @param [Hash] procs the Proc objects used to render the section
|
196
|
+
# @option procs [Proc] :title used to render the section header (parameters: the header level, the section ID, the section title)
|
197
|
+
# @option procs [Proc] :body used to render the section body (parameters: the section title, the section body)
|
198
|
+
def section_element_for(procs={})
|
199
|
+
h = ""
|
200
|
+
if attr(:title) then
|
201
|
+
level = 1
|
202
|
+
@node.ascend do |n|
|
203
|
+
break if n.respond_to?(:attribute) && n.attribute(:class) && n.attribute(:class).children.join.strip == "topic"
|
204
|
+
if n.is_a?(Glyph::MacroNode) && Glyph["system.structure.headers"].include?(n[:name]) then
|
205
|
+
level+=1
|
206
|
+
end
|
207
|
+
end
|
208
|
+
ident = (attr(:id) || "h_#{@node[:document].headers.length+1}").to_sym
|
209
|
+
# The bookmark is added when the section is first processed; therefore it will exist already when a topic layout is processed
|
210
|
+
bmk = @node[:document].bookmark?(ident)
|
211
|
+
bmk ||= header :title => attr(:title),
|
212
|
+
:level => level,
|
213
|
+
:id => ident,
|
214
|
+
:toc => !attr(:notoc),
|
215
|
+
:definition => @source_file,
|
216
|
+
:file => (attr(:src) || @source_file)
|
217
|
+
@node[:header] = bmk
|
218
|
+
h = procs[:title].call level, bmk, attr(:title)
|
219
|
+
end
|
220
|
+
if attr(:src) then
|
221
|
+
# Create topic
|
222
|
+
if Glyph.multiple_output_files?
|
223
|
+
topic_id = (attr(:id) || "t_#{@node[:document].topics.length}").to_sym
|
224
|
+
layout = attr(:layout) || Glyph["output.#{Glyph['document.output']}.layouts.topic"] || :topic
|
225
|
+
layout_name = "layout:#{layout}".to_sym
|
226
|
+
macro_error "Layout '#{layout}' not found" unless Glyph::MACROS[layout_name]
|
227
|
+
result = interpret %{#{layout_name}[
|
228
|
+
@title[#{attr(:title)}]
|
229
|
+
@id[#{topic_id}]
|
230
|
+
@contents[include[@topic[true]#{attr(:src)}]]
|
231
|
+
]}
|
232
|
+
bmk = @node[:document].bookmark? topic_id
|
233
|
+
if bmk then
|
234
|
+
# Fix file for topic bookmark
|
235
|
+
@node[:document].bookmark?(topic_id).file = attr(:src)
|
236
|
+
else
|
237
|
+
bookmark :title => attr(:title), :id => topic_id, :file => attr(:src), :definition => @source_file
|
238
|
+
end
|
239
|
+
topic_src = attr(:src)
|
240
|
+
topic_src += ".glyph" unless topic_src.match /\..+$/
|
241
|
+
@node[:document].topics << {:src => topic_src, :title => attr(:title), :id => topic_id, :contents => result}
|
242
|
+
# Process section contents
|
243
|
+
procs[:body].call h, value
|
244
|
+
# Return nothing
|
245
|
+
nil
|
246
|
+
else
|
247
|
+
v = raw_value
|
248
|
+
@node.children.delete_if{|c| !c.is_a?(Glyph::AttributeNode)}
|
249
|
+
body = interpret "include[#{attr(:src)}]#{v}"
|
250
|
+
procs[:body].call h, body
|
251
|
+
end
|
252
|
+
else
|
253
|
+
procs[:body].call h, value
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Renders a navigation element
|
258
|
+
# @param [String] topic_id the ID of the current topic
|
259
|
+
# @param [Hash] procs the Proc objects used to render the navigation element
|
260
|
+
# @option procs [Proc] :previous the link to the previous topic
|
261
|
+
# @option procs [Proc] :next the link to the next topic
|
262
|
+
# @option procs [Proc] :contents the link to the document contents
|
263
|
+
def navigation_element_for(topic_id, procs={})
|
264
|
+
# Get the previous topic
|
265
|
+
previous_topic = @node[:document].topics.last
|
266
|
+
previous_link = procs[:previous].call previous_topic
|
267
|
+
# The next topic is not going to be available yet, use a placeholder
|
268
|
+
next_link = placeholder do |document|
|
269
|
+
current_topic = document.topics.select{|t| t[:id] == topic_id}[0] rescue nil
|
270
|
+
next_topic = document.topics[document.topics.index(current_topic)+1] rescue nil
|
271
|
+
procs[:next].call next_topic
|
272
|
+
end
|
273
|
+
contents_link = procs[:contents].call
|
274
|
+
procs[:navigation].call contents_link, previous_link, next_link
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|