maruku 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/docs/todo.md CHANGED
@@ -1,12 +1,3 @@
1
1
 
2
-
3
-
4
-
5
-
6
-
7
- Latex export
8
- ------------
9
-
10
- * Convert HTML entities in the input to the equivalent in Latex.
11
- For example, `$` to `\$`, ` ` to `\ `.
2
+ * include RubyPants
12
3
 
@@ -16,18 +16,25 @@ class Maruku
16
16
  span = MDElement.new
17
17
  span.children = res
18
18
 
19
- # then, encode all escapes
19
+ # encode all escapes
20
20
  span.replace_each_string { |s| s.escape_md_special }
21
21
 
22
+
23
+ # The order of processing is significant:
24
+ # 1. inline code
25
+ # 2. immediate links
26
+ # 3. inline HTML
27
+ # 4. everything else
28
+
22
29
  # search for ``code`` markers
23
- span.match_couple_of('``') { |children|
30
+ span.match_couple_of('``') { |children, match1, match2|
24
31
  e = create_md_element(:inline_code)
25
32
  e.meta[:raw_code] = children.join('') # this is now opaque to processing
26
33
  e
27
34
  }
28
35
 
29
36
  # Search for `single tick` code markers
30
- span.match_couple_of('`') { |children|
37
+ span.match_couple_of('`') { |children, match1, match2|
31
38
  e = create_md_element(:inline_code)
32
39
  e.meta[:raw_code] = children.join('').unescape_md_special
33
40
  # this is now opaque to processing
@@ -122,32 +129,76 @@ class Maruku
122
129
  e
123
130
  }
124
131
 
132
+ # an id reference: "[id]", "[ id ]"
133
+ reg_id_ref = %r{
134
+ \[ # opening bracket
135
+ ([^\]]*) # 0 or more non-closing bracket (this is too permissive)
136
+ \] # closing bracket
137
+ }x
138
+
125
139
  # Detect any link like [Google engine][google]
126
- span.map_match(/\[([^\]]+)\]\s?\[([^\]]*)\]/) { |match|
127
- text = match[1]
128
- id = match[2]
140
+ span.match_couple_of('[', # opening bracket
141
+ %r{\] # closing bracket
142
+ [ ]? # optional whitespace
143
+ #{reg_id_ref} # ref id, with $1 being the reference
144
+ }x
145
+ ) { |children, match1, match2|
146
+ id = match2[1]
129
147
  id = id.strip.downcase
130
148
 
131
149
  if id.size == 0
132
- id = text.strip.downcase
150
+ id = children.join.strip.downcase
133
151
  end
134
152
 
135
- e = create_md_element(:link, [text])
153
+ e = create_md_element(:link, children)
136
154
  e.meta[:ref_id] = id
137
155
  e
138
156
  }
139
157
 
158
+ # validates a url, only $1 is set to the url
159
+ reg_url =
160
+ /((?:\w+):\/\/(?:\w+:{0,1}\w*@)?(?:\S+)(?::[0-9]+)?(?:\/|\/([\w#!:.?+=&%@!\-\/]))?)/
161
+ reg_url = %r{([^\s\]\)]+)}
162
+
163
+ # short_url = /(#?[\w]+)/
164
+ # reg_url = Regexp::union(long_url, short_url)
165
+
166
+ # A string enclosed in quotes.
167
+ reg_title = %r{
168
+ " # opening
169
+ [^"]* # anything = 1
170
+ " # closing
171
+ }x
172
+
173
+ # (http://www.google.com "Google.com"), (http://www.google.com),
174
+ reg_url_and_title = %r{
175
+ \( # opening
176
+ \s* # whitespace
177
+ #{reg_url} # url = 1
178
+ (?:\s+["'](.*)["'])? # optional title = 2
179
+ \s* # whitespace
180
+ \) # closing
181
+ }x
182
+
140
183
  # Detect any link with immediate url: [Google](http://www.google.com)
141
184
  # a dummy ref is created and put in the symbol table
142
- span.map_match(/\[([^\]]+)\]\s?\(([^\)]*)\)/) { |match|
143
- text = match[1]
144
- url = match[2]
145
- url = url.strip.downcase
185
+
186
+ span.match_couple_of('[', # opening bracket
187
+ %r{\] # closing bracket
188
+ [ ]? # optional whitespace
189
+ #{reg_url_and_title} # ref id, with $1 being the url and $2 being the title
190
+ }x
191
+ ) { |children, match1, match2|
192
+
193
+ url = match2[1]
194
+ title = match2[3] # XXX? Is it a bug? I would use [2]
195
+
146
196
  # create a dummy id
147
197
  id="dummy_#{@refs.size}"
148
198
  @refs[id] = {:url=>url}
149
-
150
- e = create_md_element(:link, [text])
199
+ @refs[id][:title] = title if title
200
+
201
+ e = create_md_element(:link, children)
151
202
  e.meta[:ref_id] = id
152
203
  e
153
204
  }
@@ -164,16 +215,16 @@ class Maruku
164
215
  # And now the easy stuff
165
216
 
166
217
  # search for **strong**
167
- span.match_couple_of('**') { |children| create_md_element(:strong, children) }
218
+ span.match_couple_of('**') { |children,m1,m2| create_md_element(:strong, children) }
168
219
 
169
220
  # search for __strong__
170
- span.match_couple_of('__') { |children| create_md_element(:strong, children) }
221
+ span.match_couple_of('__') { |children,m1,m2| create_md_element(:strong, children) }
171
222
 
172
223
  # search for *emphasis*
173
- span.match_couple_of('*') { |children| create_md_element(:emphasis, children) }
224
+ span.match_couple_of('*') { |children,m1,m2| create_md_element(:emphasis, children) }
174
225
 
175
226
  # search for _emphasis_
176
- span.match_couple_of('_') { |children| create_md_element(:emphasis, children) }
227
+ span.match_couple_of('_') { |children,m1,m2| create_md_element(:emphasis, children) }
177
228
 
178
229
  # finally, unescape the special characters
179
230
  span.replace_each_string { |s| s.unescape_md_special}
@@ -264,11 +315,20 @@ class MDElement
264
315
  end
265
316
 
266
317
  # Finds couple of delimiters in a hierarchy of Strings and MDElements
267
- def match_couple_of(marker, &block)
268
- regexp = Regexp.new(Regexp.escape(marker))
318
+ #
319
+ # Open and close are two delimiters (like '[' and ']'), or two Regexp.
320
+ #
321
+ # If you don't pass close, it defaults to open.
322
+ #
323
+ # Each block is called with |contained children, match1, match2|
324
+ def match_couple_of(open, close=nil, &block)
325
+ close = close || open
326
+ open_regexp = open.kind_of?(Regexp) ? open : Regexp.new(Regexp.escape(open))
327
+ close_regexp = close.kind_of?(Regexp) ? close : Regexp.new(Regexp.escape(close))
269
328
 
329
+ # Do the same to children first
270
330
  for c in @children; if c.kind_of? MDElement
271
- c.match_couple_of(marker, &block)
331
+ c.match_couple_of(open_regexp, close_regexp, &block)
272
332
  end end
273
333
 
274
334
  processed_children = []
@@ -276,37 +336,37 @@ class MDElement
276
336
  until @children.empty?
277
337
  c = @children.shift
278
338
  if c.kind_of? String
279
- match = regexp.match(c)
280
- if not match
339
+ match1 = open_regexp.match(c)
340
+ if not match1
281
341
  processed_children << c
282
342
  else # we found opening, now search closing
283
343
  # puts "Found opening (#{marker}) in #{c.inspect}"
284
344
  # pre match is processed
285
- processed_children.push match.pre_match if
286
- match.pre_match && match.pre_match.size > 0
345
+ processed_children.push match1.pre_match if
346
+ match1.pre_match && match1.pre_match.size > 0
287
347
  # we will process again the post_match
288
- @children.unshift match.post_match if
289
- match.post_match && match.post_match.size>0
290
-
348
+ @children.unshift match1.post_match if
349
+ match1.post_match && match1.post_match.size>0
350
+
291
351
  contained = []; found_closing = false
292
352
  until @children.empty? || found_closing
293
353
  c = @children.shift
294
354
  if c.kind_of? String
295
- match = regexp.match(c)
296
- if not match
355
+ match2 = close_regexp.match(c)
356
+ if not match2
297
357
  contained << c
298
358
  else
299
359
  # we found closing
300
360
  found_closing = true
301
361
  # pre match is contained
302
- contained.push match.pre_match if
303
- match.pre_match && match.pre_match.size>0
362
+ contained.push match2.pre_match if
363
+ match2.pre_match && match2.pre_match.size>0
304
364
  # we will process again the post_match
305
- @children.unshift match.post_match if
306
- match.post_match && match.post_match.size>0
365
+ @children.unshift match2.post_match if
366
+ match2.post_match && match2.post_match.size>0
307
367
 
308
368
  # And now we call the block
309
- substitute = block.call(contained)
369
+ substitute = block.call(contained, match1, match2)
310
370
  processed_children << substitute
311
371
 
312
372
  # puts "Found closing (#{marker}) in #{c.inspect}"
@@ -319,8 +379,8 @@ class MDElement
319
379
  end
320
380
 
321
381
  if not found_closing
322
- $stderr.puts "##### Could not find closing for #{marker}"
323
- processed_children << "?"
382
+ # $stderr.puts "##### Could not find closing for #{open}, #{close} -- ignoring"
383
+ processed_children << match1.to_s
324
384
  contained.reverse.each do |c|
325
385
  @children.unshift c
326
386
  end
@@ -331,6 +391,17 @@ class MDElement
331
391
  end
332
392
  end
333
393
 
334
- @children = processed_children
394
+ raise "BugBug" unless @children.empty?
395
+
396
+ rebuilt = []
397
+ # rebuild strings
398
+ processed_children.each do |c|
399
+ if c.kind_of?(String) && rebuilt.last && rebuilt.last.kind_of?(String)
400
+ rebuilt.last << c
401
+ else
402
+ rebuilt << c
403
+ end
404
+ end
405
+ @children = rebuilt
335
406
  end
336
407
  end
@@ -78,7 +78,22 @@ class MDElement
78
78
  else
79
79
  color
80
80
  end
81
-
81
+ end
82
+
83
+ # \color[named]{name}
84
+ # \color[rgb]{1,0.2,0.3}
85
+ def latex_color(s, command='color')
86
+ if s =~ /^\#(\w\w)(\w\w)(\w\w)$/
87
+ r = $1.hex; g = $2.hex; b=$3.hex
88
+ # convert from 0-255 to 0.0-1.0
89
+ r = r / 255.0
90
+ g = g / 255.0
91
+ b = b / 255.0
92
+
93
+ "\\#{command}[rgb]{#{r},#{g},#{b}}"
94
+ else
95
+ "\\#{command}{#{s}}"
96
+ end
82
97
  end
83
98
 
84
99
  def to_latex_code;
@@ -95,13 +110,10 @@ class MDElement
95
110
  s+= "\\lstset{showspaces=false,showtabs=false}\n"
96
111
  end
97
112
 
98
- color = get_setting(:code_background_color,DEFAULT_CODE_COLOR)
99
- if color
100
- colorname, declaration = define_color_if_necessary(color)
101
- s+= declaration if declaration
102
- s+= "\\lstset{backgroundcolor=\\color{#{colorname}}}\n"
103
- end
104
-
113
+ color = latex_color get_setting(:code_background_color,DEFAULT_CODE_COLOR)
114
+
115
+ s+= "\\lstset{backgroundcolor=#{color}}\n"
116
+
105
117
  s+= "\\lstset{basicstyle=\\ttfamily\\footnotesize}\n"
106
118
 
107
119
 
@@ -175,10 +187,9 @@ class MDElement
175
187
  # Convert to printable latex chars (is much better than using \verb)
176
188
  s=latex_escape(source)
177
189
 
178
- color = get_setting(:code_background_color,DEFAULT_CODE_COLOR)
179
- colorname, declaration = define_color_if_necessary(color)
180
- (declaration||'')+
181
- "\\colorbox{#{colorname}}{\\tt #{s}}"
190
+ color = latex_color(get_setting(:code_background_color,DEFAULT_CODE_COLOR),'colorbox')
191
+
192
+ "#{color}{\\tt #{s}}"
182
193
  end
183
194
 
184
195
  def to_latex_immediate_link
data/tests/links.md CHANGED
@@ -11,6 +11,13 @@ Search on [Google images][]
11
11
 
12
12
  Search on [Google images][ GoOgle search ]
13
13
 
14
+ Inline: [Google images](http://google.com)
15
+
16
+ Inline with title: [Google images](http://google.com "Title")
17
+
18
+ Inline with title: [Google images]( http://google.com "Title" )
19
+
20
+
14
21
  Search on <http://www.gogole.com> or <http://Here.com> or ask <mailto:bill@google.com>
15
22
  or you might ask bill@google.com.
16
23
 
data/tests/sss06.md CHANGED
@@ -339,14 +339,14 @@ And here's the research version:
339
339
  References
340
340
  ----------
341
341
 
342
- [1] [http://www.spellingsociety.org/news/media/poems.php](http://www.spellingsociety.org/news/media/poems.php)
343
- [2] [http://www.flickr.com/photos/censi/236722418/](http://www.flickr.com/photos/censi/236722418/)
344
- [3] [http://www.oxfordstory.co.uk](http://www.oxfordstory.co.uk)
345
- [4] [http://www.botanical.com/botanical/mgmh/p/parsni12.html](http://www.botanical.com/botanical/mgmh/p/parsni12.html )
346
- [5] E. Meijer, M. Fokkinga, R. Paterson. "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" (1991)
342
+ \[1\] [http://www.spellingsociety.org/news/media/poems.php](http://www.spellingsociety.org/news/media/poems.php)
343
+ \[2\] dde [http://www.flickr.com/photos/censi/236722418/](http://www.flickr.com/photos/censi/236722418/)
344
+ \[3\] [http://www.oxfordstory.co.uk](http://www.oxfordstory.co.uk)
345
+ \[4\] [http://www.botanical.com/botanical/mgmh/p/parsni12.html](http://www.botanical.com/botanical/mgmh/p/parsni12.html )
346
+ \[5\] E. Meijer, M. Fokkinga, R. Paterson. "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" (1991)
347
347
  [http://citeseer.ist.psu.edu/meijer91functional.html](http://citeseer.ist.psu.edu/meijer91functional.html)
348
- [6] R. Lammel, J. Visser, J. Kort. "Dealing with large bananas" (2000) <http://citeseer.ist.psu.edu/lammel00dealing.html>
349
- [7] [http://www.informatik.uni-freiburg.de/~burgard/](http://citeseer.ist.psu.edu/lammel00dealing.html)
350
- [8] [http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv](http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv)
351
- [9] [http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/](http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/)
352
- [10] [http://www.infonegocio.com/xeron/bruno/italy.html](http://www.infonegocio.com/xeron/bruno/italy.html)
348
+ \[6\] R. Lammel, J. Visser, J. Kort. "Dealing with large bananas" (2000) <http://citeseer.ist.psu.edu/lammel00dealing.html>
349
+ \[7\] [http://www.informatik.uni-freiburg.de/~burgard/](http://citeseer.ist.psu.edu/lammel00dealing.html)
350
+ \[8\] [http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv](http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv)
351
+ \[9\] [http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/](http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/)
352
+ \[10\] [http://www.infonegocio.com/xeron/bruno/italy.html](http://www.infonegocio.com/xeron/bruno/italy.html)
metadata CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: maruku
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.2"
6
+ version: 0.2.1
7
7
  date: 2006-12-25 00:00:00 +01:00
8
8
  summary: A Markdown interpreter in Ruby
9
9
  require_paths: