glyph 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +19 -40
- data/benchmark.rb +1 -2
- data/book/config.yml +8 -8
- data/book/document.glyph +18 -19
- data/book/images/glyph/commands_tasks.png +0 -0
- data/book/lib/layouts/bookindex.glyph +113 -111
- data/book/lib/layouts/bookpage.glyph +112 -108
- data/book/lib/macros/reference.rb +2 -2
- data/book/lib/tasks/tasks.rake +1 -1
- data/book/text/acknowledgements.glyph +1 -0
- data/book/text/changelog.glyph +140 -112
- data/book/text/compiling/compiling.glyph +36 -24
- data/book/text/compiling/lite_mode.glyph +11 -11
- data/book/text/compiling/programmatic_usage.glyph +57 -57
- data/book/text/config/document.glyph +7 -1
- data/book/text/config/options.glyph +5 -3
- data/book/text/config/output.glyph +41 -8
- data/book/text/extending/bookmarks_headers.glyph +13 -11
- data/book/text/extending/command.glyph +1 -1
- data/book/text/extending/commands_tasks.glyph +2 -2
- data/book/text/extending/internals.glyph +29 -29
- data/book/text/extending/interpreting.glyph +48 -9
- data/book/text/extending/macro_def.glyph +80 -32
- data/book/text/extending/output_format.glyph +2 -2
- data/book/text/extending/placeholders.glyph +27 -15
- data/book/text/extending/validators.glyph +1 -1
- data/book/text/getting_started/configuration.glyph +1 -1
- data/book/text/getting_started/create_project.glyph +4 -5
- data/book/text/getting_started/structure.glyph +2 -2
- data/book/text/macros/macros_core.glyph +341 -199
- data/book/text/macros/macros_filters.glyph +1 -1
- data/book/text/macros/macros_inline.glyph +3 -3
- data/book/text/macros/macros_structure.glyph +1 -1
- data/book/text/ref_commands.glyph +98 -93
- data/book/text/snippets.glyph +18 -0
- data/book/text/stats/bookmarks.glyph +16 -16
- data/book/text/stats/links.glyph +23 -23
- data/book/text/stats/macros.glyph +14 -14
- data/book/text/stats/snippets.glyph +26 -26
- data/book/text/stats/stats.glyph +14 -15
- data/book/text/text_editing/attribute_intro.glyph +8 -8
- data/book/text/text_editing/code.glyph +16 -16
- data/book/text/text_editing/conditionals.glyph +12 -13
- data/book/text/text_editing/esc_quot.glyph +3 -3
- data/book/text/text_editing/evaluation.glyph +57 -3
- data/book/text/text_editing/inclusions.glyph +34 -25
- data/book/text/text_editing/macro_composition.glyph +28 -0
- data/book/text/text_editing/macro_intro.glyph +4 -4
- data/book/text/text_editing/section_aliases.glyph +23 -23
- data/book/text/text_editing/sections.glyph +22 -22
- data/book/text/text_editing/stylesheets.glyph +33 -33
- data/book/text/text_editing/topics.glyph +6 -6
- data/book/text/text_editing/xml_fallback.glyph +1 -1
- data/book/text/troubleshooting/errors_command.glyph +4 -4
- data/book/text/troubleshooting/errors_generic.glyph +16 -10
- data/book/text/troubleshooting/errors_macro.glyph +18 -21
- data/book/text/troubleshooting/errors_parser.glyph +7 -7
- data/config.yml +51 -29
- data/document.glyph +18 -18
- data/glyph.gemspec +39 -287
- data/layouts/web5/topic.glyph +1 -1
- data/lib/glyph.rb +42 -10
- data/lib/glyph/analyzer.rb +5 -2
- data/lib/glyph/bookmark.rb +3 -1
- data/lib/glyph/commands.rb +11 -9
- data/lib/glyph/commands/add.rb +3 -1
- data/lib/glyph/commands/compile.rb +10 -7
- data/lib/glyph/commands/config.rb +7 -5
- data/lib/glyph/commands/init.rb +2 -0
- data/lib/glyph/commands/outline.rb +2 -0
- data/lib/glyph/commands/stats.rb +3 -0
- data/lib/glyph/commands/todo.rb +2 -0
- data/lib/glyph/config.rb +2 -0
- data/lib/glyph/document.rb +34 -9
- data/lib/glyph/interpreter.rb +2 -0
- data/lib/glyph/macro.rb +97 -25
- data/lib/glyph/macro_validators.rb +9 -6
- data/lib/glyph/node.rb +3 -1
- data/lib/glyph/parser.rb +68 -33
- data/lib/glyph/reporter.rb +3 -1
- data/lib/glyph/syntax_node.rb +23 -28
- data/lib/glyph/system_extensions.rb +21 -0
- data/lib/glyph/utils.rb +24 -4
- data/macros/block.rb +111 -0
- data/macros/core.rb +163 -33
- data/macros/filters.rb +3 -2
- data/macros/inline.rb +97 -0
- data/macros/reps/html.rb +180 -0
- data/macros/reps/html5.rb +100 -0
- data/macros/reps/web.rb +4 -0
- data/macros/reps/web5.rb +4 -0
- data/macros/structure.rb +229 -0
- data/macros/xml.rb +29 -24
- data/spec/config.yml +7 -0
- data/spec/files/article.glyph +2 -2
- data/spec/files/web_doc.glyph +9 -5
- data/spec/lib/commands_spec.rb +13 -9
- data/spec/lib/config_spec.rb +2 -2
- data/spec/lib/document_spec.rb +10 -0
- data/spec/lib/glyph_spec.rb +30 -8
- data/spec/lib/macro_spec.rb +39 -4
- data/spec/lib/macro_validators_spec.rb +3 -4
- data/spec/lib/parser_spec.rb +7 -0
- data/spec/lib/reporter_spec.rb +1 -0
- data/spec/lib/syntax_node_spec.rb +40 -6
- data/spec/macros/core_spec.rb +154 -21
- data/spec/macros/filters_spec.rb +1 -1
- data/spec/macros/html5_spec.rb +4 -5
- data/spec/macros/macros_spec.rb +6 -7
- data/spec/macros/web5_spec.rb +3 -3
- data/spec/macros/web_spec.rb +10 -7
- data/spec/macros/xml_spec.rb +11 -2
- data/spec/spec_helper.rb +11 -5
- data/spec/tasks/generate_spec.rb +40 -5
- data/spec/tasks/load_spec.rb +1 -13
- data/styles/coderay.css +147 -38
- data/styles/default.css +19 -22
- data/styles/pagination.css +30 -30
- data/tasks/generate.rake +54 -18
- data/tasks/load.rake +9 -24
- data/tasks/project.rake +0 -2
- metadata +208 -207
- data/.gitignore +0 -7
- data/VERSION +0 -1
- data/book/snippets.yml +0 -18
- data/lib/glyph/macro_helpers.rb +0 -282
- data/macros/html/block.rb +0 -124
- data/macros/html/inline.rb +0 -42
- data/macros/html/structure.rb +0 -191
- data/macros/html5/block.rb +0 -69
- data/macros/html5/inline.rb +0 -24
- data/macros/html5/structure.rb +0 -140
@@ -1,12 +1,33 @@
|
|
1
|
+
# Core Symbol class.
|
1
2
|
class Symbol
|
3
|
+
# Comparison operator based on the one in the String class.
|
2
4
|
def <=>(b)
|
3
5
|
self.to_s <=> b.to_s
|
4
6
|
end
|
5
7
|
end
|
6
8
|
|
9
|
+
# Core String class.
|
7
10
|
class String
|
11
|
+
# Converts the strings to "title case" (capitalizes each word).
|
8
12
|
def title_case
|
9
13
|
self.snake_case.split('_').map{|s| s.capitalize}.join(' ')
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
17
|
+
# Core Hash class.
|
18
|
+
class Hash
|
19
|
+
# Converts the hash to a string of Glyph options.
|
20
|
+
def to_options(sep=" ")
|
21
|
+
"".tap do |s|
|
22
|
+
self.each_pair do |k, v|
|
23
|
+
key = k.to_s
|
24
|
+
s += key.length == 1 ? "-" : "--"
|
25
|
+
s += key
|
26
|
+
s += sep
|
27
|
+
s += v.to_s =~ /\s/ ? "\"#{v}\"" : v.to_s
|
28
|
+
s += " "
|
29
|
+
end
|
30
|
+
end.strip
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/glyph/utils.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Glyph
|
2
4
|
#@since 0.4.0
|
3
5
|
module Utils
|
@@ -51,7 +53,7 @@ module Glyph
|
|
51
53
|
# @return [String] the contents of the file
|
52
54
|
def file_load(file)
|
53
55
|
result = ""
|
54
|
-
File.open(file.to_s, 'r') do |f|
|
56
|
+
File.open(file.to_s, 'r:utf-8') do |f|
|
55
57
|
while l = f.gets
|
56
58
|
result << l
|
57
59
|
end
|
@@ -64,7 +66,7 @@ module Glyph
|
|
64
66
|
# @param [String] contents the string to write
|
65
67
|
# @return [String] the string written to the file
|
66
68
|
def file_write(file, contents="")
|
67
|
-
File.open(file.to_s, 'w
|
69
|
+
File.open(file.to_s, 'w+:utf-8') do |f|
|
68
70
|
f.print contents
|
69
71
|
end
|
70
72
|
contents
|
@@ -96,7 +98,7 @@ module Glyph
|
|
96
98
|
# @yield [src, dest] the source file and the corresponding output file
|
97
99
|
# @since 0.4.0
|
98
100
|
def with_files_from(dir, &block)
|
99
|
-
output =
|
101
|
+
output = complex_output? ? 'tmp' : Glyph['document.output']
|
100
102
|
dir_path = Glyph::PROJECT/"output/#{output}/#{dir}"
|
101
103
|
dir_path.mkpath
|
102
104
|
(Glyph::PROJECT/dir).find do |i|
|
@@ -109,6 +111,13 @@ module Glyph
|
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
114
|
+
# Returns true if Glyph['document.output'] requires two or more conversions
|
115
|
+
# @since 0.5.0
|
116
|
+
def complex_output?
|
117
|
+
out = Glyph['document.output']
|
118
|
+
!Glyph["output.#{out}.generator"].blank? || !Glyph["output.#{out}.through"].blank?
|
119
|
+
end
|
120
|
+
|
112
121
|
# Returns true if the macro name is used as an alias
|
113
122
|
# @param [String, Symbol] name the macro name to check
|
114
123
|
def macro_alias?(name)
|
@@ -145,7 +154,7 @@ module Glyph
|
|
145
154
|
|
146
155
|
# Returns true if the PROJECT constant is set to a valid Glyph project directory
|
147
156
|
def project?
|
148
|
-
children = ["text", "
|
157
|
+
children = ["text", "config.yml", "document.glyph"].sort
|
149
158
|
actual_children = PROJECT.children.map{|c| c.basename.to_s}.sort
|
150
159
|
(actual_children & children) == children
|
151
160
|
end
|
@@ -155,5 +164,16 @@ module Glyph
|
|
155
164
|
Glyph["output.#{Glyph['document.output']}.multifile"]
|
156
165
|
end
|
157
166
|
|
167
|
+
# Execute an external command
|
168
|
+
# @since 0.5.0
|
169
|
+
def run_external_command(cmd)
|
170
|
+
IO.popen(cmd+" 2>&1") do |pipe|
|
171
|
+
pipe.sync = true
|
172
|
+
while str = pipe.gets do
|
173
|
+
puts str
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
158
178
|
end
|
159
179
|
end
|
data/macros/block.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
macro :note do
|
5
|
+
@data[:name] = @name
|
6
|
+
@data[:text] = value
|
7
|
+
render
|
8
|
+
end
|
9
|
+
|
10
|
+
macro :box do
|
11
|
+
exact_parameters 2
|
12
|
+
@data[:title] = param 0
|
13
|
+
@data[:text] = param 1
|
14
|
+
render
|
15
|
+
end
|
16
|
+
|
17
|
+
macro :codeblock do
|
18
|
+
exact_parameters 1
|
19
|
+
@data[:text] = param 0
|
20
|
+
render
|
21
|
+
end
|
22
|
+
|
23
|
+
macro :image do
|
24
|
+
min_parameters 1
|
25
|
+
max_parameters 3
|
26
|
+
image = param(0)
|
27
|
+
src_file = Glyph.lite? ? image : Glyph::PROJECT/"images/#{image}"
|
28
|
+
dest_file = Glyph.lite? ? image : "images/#{image}"
|
29
|
+
warning "Image '#{image}' not found" unless Pathname.new(src_file).exist?
|
30
|
+
@data[:attrs] = @node.attrs
|
31
|
+
@data[:src] = Glyph["output.#{Glyph['document.output']}.base"].to_s+dest_file
|
32
|
+
render
|
33
|
+
end
|
34
|
+
|
35
|
+
macro :figure do
|
36
|
+
min_parameters 1
|
37
|
+
max_parameters 2
|
38
|
+
image = param(0)
|
39
|
+
caption = param(1) rescue nil
|
40
|
+
src_file = Glyph.lite? ? image : Glyph::PROJECT/"images/#{image}"
|
41
|
+
dest_file = Glyph.lite? ? image : "images/#{image}"
|
42
|
+
warning "Figure '#{image}' not found" unless Pathname.new(src_file).exist?
|
43
|
+
@data[:attrs] = @node.attrs
|
44
|
+
@data[:src] = Glyph["output.#{Glyph['document.output']}.base"].to_s+dest_file
|
45
|
+
@data[:caption] = param(1)
|
46
|
+
render
|
47
|
+
end
|
48
|
+
|
49
|
+
macro :title do
|
50
|
+
no_parameters
|
51
|
+
unless Glyph["document.title"].blank? then
|
52
|
+
render
|
53
|
+
else
|
54
|
+
""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
macro :subtitle do
|
59
|
+
no_parameters
|
60
|
+
unless Glyph["document.subtitle"].blank? then
|
61
|
+
render
|
62
|
+
else
|
63
|
+
""
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
macro :author do
|
68
|
+
no_parameters
|
69
|
+
render
|
70
|
+
end
|
71
|
+
|
72
|
+
# TODO -- document new param!
|
73
|
+
macro :pubdate do
|
74
|
+
max_parameters 1
|
75
|
+
@data[:date] = params(0).blank? ? Time.now.strftime("%B %Y") : params(0)
|
76
|
+
render
|
77
|
+
end
|
78
|
+
|
79
|
+
macro :revision do
|
80
|
+
no_parameters
|
81
|
+
unless Glyph["document.revision"].blank? then
|
82
|
+
render
|
83
|
+
else
|
84
|
+
""
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
macro :navigation do
|
89
|
+
exact_parameters 1
|
90
|
+
topic_id = param(0).to_sym
|
91
|
+
base_url = Glyph["output.#{Glyph['document.output']}.base"]
|
92
|
+
@data[:contents] = render :link, :target => "#{base_url}index.html", :title => "Contents"
|
93
|
+
# Get the previous topic
|
94
|
+
previous_topic = @node[:document].topics.last
|
95
|
+
if previous_topic then
|
96
|
+
@data[:previous] = render :link, :target => "#{base_url}#{previous_topic[:src].gsub(/\..+$/, '.html')}", :title => previous_topic[:title]
|
97
|
+
else
|
98
|
+
@data[:previous] = ""
|
99
|
+
end
|
100
|
+
# The next topic is not going to be available yet, use a placeholder
|
101
|
+
@data[:next] = placeholder do |document|
|
102
|
+
current_topic = document.topics.select{|t| t[:id] == topic_id}[0] rescue nil
|
103
|
+
next_topic = document.topics[document.topics.index(current_topic)+1] rescue nil
|
104
|
+
render :link, :title => next_topic[:title], :target => "#{base_url}#{next_topic[:src].gsub(/\..+$/, '.html')}" if next_topic
|
105
|
+
end
|
106
|
+
render
|
107
|
+
end
|
108
|
+
|
109
|
+
macro_alias :important => :note
|
110
|
+
macro_alias :tip => :note
|
111
|
+
macro_alias :caution => :note
|
data/macros/core.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
2
3
|
|
3
4
|
macro :snippet do
|
4
|
-
no_mutual_inclusion_in 0
|
5
5
|
ident = value.to_sym
|
6
|
-
if
|
6
|
+
if snippet? ident then
|
7
7
|
begin
|
8
8
|
update_source "snippet[#{ident}]"
|
9
|
-
interpret
|
9
|
+
interpret snippet?(ident)
|
10
10
|
rescue Exception => e
|
11
11
|
case
|
12
12
|
when e.is_a?(Glyph::MutualInclusionError) then
|
@@ -16,7 +16,6 @@ macro :snippet do
|
|
16
16
|
else
|
17
17
|
macro_warning e.message, e
|
18
18
|
end
|
19
|
-
macro_todo "Correct errors in snippet '#{ident}'"
|
20
19
|
end
|
21
20
|
else
|
22
21
|
macro_warning "Snippet '#{ident}' does not exist"
|
@@ -28,7 +27,7 @@ macro "snippet:" do
|
|
28
27
|
exact_parameters 2
|
29
28
|
ident = param(0)
|
30
29
|
text = param(1)
|
31
|
-
|
30
|
+
snippet ident, text
|
32
31
|
""
|
33
32
|
end
|
34
33
|
|
@@ -43,6 +42,19 @@ macro "macro:" do
|
|
43
42
|
""
|
44
43
|
end
|
45
44
|
|
45
|
+
macro :load do
|
46
|
+
safety_check
|
47
|
+
exact_parameters 1
|
48
|
+
file = param 0
|
49
|
+
path = Glyph::PROJECT/file
|
50
|
+
if path.exist? then
|
51
|
+
file_load path
|
52
|
+
else
|
53
|
+
macro_warning "File '#{file}' no found."
|
54
|
+
"[FILE '#{value}' NOT FOUND]"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
46
58
|
macro :include do
|
47
59
|
safety_check
|
48
60
|
exact_parameters 1
|
@@ -85,10 +97,8 @@ macro :include do
|
|
85
97
|
raise
|
86
98
|
rescue Glyph::MacroError => e
|
87
99
|
macro_warning e.message, e
|
88
|
-
macro_todo "Correct errors in file '#{value}'"
|
89
100
|
rescue Exception => e
|
90
101
|
macro_warning e.message, e
|
91
|
-
macro_todo "Correct errors in file '#{value}'"
|
92
102
|
end
|
93
103
|
end
|
94
104
|
else
|
@@ -137,44 +147,48 @@ macro :condition do
|
|
137
147
|
end
|
138
148
|
|
139
149
|
macro :eq do
|
140
|
-
|
141
|
-
|
142
|
-
max_parameters 2
|
143
|
-
(param(0).to_s == param(1).to_s) ? true : nil
|
150
|
+
exact_parameters 2
|
151
|
+
(param(0) == param(1)) ? true : nil
|
144
152
|
end
|
145
153
|
|
146
154
|
macro :not do
|
147
|
-
within :condition
|
148
155
|
max_parameters 1
|
149
156
|
v = param(0).to_s
|
150
157
|
(v.blank? || v == "false") ? true : nil
|
151
158
|
end
|
152
159
|
|
153
160
|
macro :and do
|
154
|
-
|
155
|
-
min_parameters 1
|
156
|
-
max_parameters 2
|
161
|
+
exact_parameters 2
|
157
162
|
res_a = !param(0).blank?
|
158
163
|
res_b = !param(1).blank?
|
159
164
|
(res_a && res_b) ? true : nil
|
160
165
|
end
|
161
166
|
|
162
167
|
macro :or do
|
163
|
-
|
164
|
-
min_parameters 1
|
165
|
-
max_parameters 2
|
168
|
+
exact_parameters 2
|
166
169
|
res_a = !param(0).blank?
|
167
170
|
res_b = !param(1).blank?
|
168
171
|
(res_a || res_b) ? true : nil
|
169
172
|
end
|
170
173
|
|
171
|
-
macro :
|
172
|
-
|
174
|
+
macro :lt do
|
175
|
+
exact_parameters 2
|
176
|
+
(param(0) < param(1)) ? true : nil
|
177
|
+
end
|
178
|
+
|
179
|
+
macro :lte do
|
173
180
|
exact_parameters 2
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
181
|
+
(param(0) <= param(1)) ? true : nil
|
182
|
+
end
|
183
|
+
|
184
|
+
macro :gt do
|
185
|
+
exact_parameters 2
|
186
|
+
(param(0) > param(1)) ? true : nil
|
187
|
+
end
|
188
|
+
|
189
|
+
macro :gte do
|
190
|
+
exact_parameters 2
|
191
|
+
(param(0) >= param(1)) ? true : nil
|
178
192
|
end
|
179
193
|
|
180
194
|
macro "alias:" do
|
@@ -182,16 +196,10 @@ macro "alias:" do
|
|
182
196
|
Glyph.macro_alias param(0) => param(1)
|
183
197
|
end
|
184
198
|
|
185
|
-
macro "
|
199
|
+
macro "define:" do
|
186
200
|
safety_check
|
187
201
|
exact_parameters 2
|
188
|
-
|
189
|
-
@node.param(1).descend do |n, level|
|
190
|
-
if n[:name] == macro_name then
|
191
|
-
macro_error "Macro '#{macro_name}' cannot be defined by itself"
|
192
|
-
end
|
193
|
-
end
|
194
|
-
Glyph.rewrite macro_name, raw_param(1).dup
|
202
|
+
Glyph.define param(0).to_sym, raw_param(1).dup
|
195
203
|
nil
|
196
204
|
end
|
197
205
|
|
@@ -199,6 +207,122 @@ macro "output?" do
|
|
199
207
|
Glyph['document.output'].in? parameters
|
200
208
|
end
|
201
209
|
|
210
|
+
macro :layout do
|
211
|
+
dispatch do |node|
|
212
|
+
node[:name] = "layout/#{node[:name]}".to_sym
|
213
|
+
Glyph::Macro.new(node).expand
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
macro :let do
|
218
|
+
exact_parameters 1
|
219
|
+
param(0).to_s
|
220
|
+
end
|
221
|
+
|
222
|
+
macro :attribute do
|
223
|
+
exact_parameters 1
|
224
|
+
a = param(0).to_sym
|
225
|
+
macro_node = @node.find_parent do |n|
|
226
|
+
n.is_a?(Glyph::MacroNode) && n.attr(a)
|
227
|
+
end
|
228
|
+
if macro_node then
|
229
|
+
Glyph::Macro.new(macro_node).attr(a)
|
230
|
+
else
|
231
|
+
nil
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
macro "attribute:" do
|
236
|
+
exact_parameters 2
|
237
|
+
a = param(0).to_sym
|
238
|
+
macro_node = @node.find_parent do |n|
|
239
|
+
n.is_a?(Glyph::MacroNode) && n.attr(a)
|
240
|
+
end
|
241
|
+
macro_error "Undeclared attribute '#{a}'" unless macro_node
|
242
|
+
attr_value = param(1)
|
243
|
+
macro_node.attr(a).children.clear
|
244
|
+
macro_node.attr(a) << Glyph::TextNode.new.from(:value => attr_value)
|
245
|
+
nil
|
246
|
+
end
|
247
|
+
|
248
|
+
macro :add do
|
249
|
+
min_parameters 2
|
250
|
+
params.inject(0){|sum, n| sum + n.to_i}
|
251
|
+
end
|
252
|
+
|
253
|
+
macro :subtract do
|
254
|
+
min_parameters 2
|
255
|
+
params[1..params.length-1].inject(params[0].to_i){|diff, n| diff - n.to_i}
|
256
|
+
end
|
257
|
+
|
258
|
+
macro :multiply do
|
259
|
+
min_parameters 2
|
260
|
+
params.inject(1){|mult, n| mult * n.to_i}
|
261
|
+
end
|
262
|
+
|
263
|
+
macro :s do
|
264
|
+
dispatch do |node|
|
265
|
+
forbidden = [:each, :each_line, :each_byte, :upto, :intern, :to_sym, :to_f]
|
266
|
+
meth = node[:name]
|
267
|
+
infer_type = lambda do |str|
|
268
|
+
case
|
269
|
+
when str.match(/[+-]?\d+/) then
|
270
|
+
# Integer
|
271
|
+
str.to_i
|
272
|
+
when str.match(/^\/.+?\/[imoxneus]?$/) then
|
273
|
+
# Regexp
|
274
|
+
Kernel.instance_eval str
|
275
|
+
else
|
276
|
+
str
|
277
|
+
end
|
278
|
+
end
|
279
|
+
macro_error "Macro 's/#{meth}' takes at least one parameter" unless node.params.length > 0
|
280
|
+
macro_error "String method '#{meth}' is not supported" if meth.in?(forbidden) || meth.to_s.match(/\!$/)
|
281
|
+
str = node.param(0).evaluate(node, :params => true)
|
282
|
+
begin
|
283
|
+
if node.param(1) then
|
284
|
+
meth_params = node.params[1..node.params.length-1].map{|p| infer_type.call(p.evaluate(node, :params => true))}
|
285
|
+
str.send(meth, *meth_params).to_s
|
286
|
+
else
|
287
|
+
str.send(meth).to_s
|
288
|
+
end
|
289
|
+
rescue Exception => e
|
290
|
+
macro_warning "\"#{str}\".#{meth}(#{meth_params.map{|p| p.inspect}.join(', ') rescue nil}) - #{e.message}", e
|
291
|
+
""
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
macro :while do
|
297
|
+
exact_parameters 2
|
298
|
+
raw_cond = @node.parameter 0
|
299
|
+
raw_body = @node.parameter 1
|
300
|
+
cond = raw_cond.evaluate(@node, :params => true)
|
301
|
+
while (!cond.blank? && cond != "false") do
|
302
|
+
result = raw_body.evaluate(@node, :params => true)
|
303
|
+
cond = raw_cond.evaluate(@node, :params => true)
|
304
|
+
result
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
macro :fragment do
|
309
|
+
exact_parameters 2
|
310
|
+
ident, contents = param(0).to_sym, param(1)
|
311
|
+
macro_error "Fragment '#{ident}' is already defined" if @node[:document].fragments.has_key? ident
|
312
|
+
@node[:document].fragments[ident] = contents
|
313
|
+
end
|
314
|
+
|
315
|
+
macro :embed do
|
316
|
+
exact_parameters 1
|
317
|
+
ident = param(0).to_sym
|
318
|
+
placeholder do |document|
|
319
|
+
fragment = document.fragments[ident]
|
320
|
+
macro_error "Fragment '#{ident}' is not defined" unless fragment
|
321
|
+
fragment
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
|
202
326
|
macro_alias '--' => :comment
|
203
327
|
macro_alias '&' => :snippet
|
204
328
|
macro_alias '&:' => 'snippet:'
|
@@ -208,4 +332,10 @@ macro_alias '$' => :config
|
|
208
332
|
macro_alias '$:' => 'config:'
|
209
333
|
macro_alias '.' => :escape
|
210
334
|
macro_alias '?' => :condition
|
211
|
-
macro_alias '
|
335
|
+
macro_alias 'def:' => 'define:'
|
336
|
+
macro_alias '@' => :attribute
|
337
|
+
macro_alias :attr => :attribute
|
338
|
+
macro_alias '@:' => "attribute:"
|
339
|
+
macro_alias "attr:" => "attribute:"
|
340
|
+
macro_alias "##" => :fragment
|
341
|
+
macro_alias "<=" => :embed
|