tartan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +130 -0
  3. data/TODO +17 -0
  4. data/lib/core_ext/array.rb +12 -0
  5. data/lib/core_ext/file.rb +15 -0
  6. data/lib/core_ext/hash.rb +16 -0
  7. data/lib/core_ext/match_data.rb +62 -0
  8. data/lib/core_ext/module.rb +17 -0
  9. data/lib/core_ext/regexp.rb +33 -0
  10. data/lib/markdown.yml +499 -0
  11. data/lib/symbolize.rb +78 -0
  12. data/lib/table.yml +63 -0
  13. data/lib/tartan.rb +359 -0
  14. data/lib/tartan_markdown.rb +8 -0
  15. data/lib/tartan_markdown_def.rb +7 -0
  16. data/lib/tartan_table_def.rb +7 -0
  17. data/lib/tartan_test_base_def.rb +5 -0
  18. data/lib/tartan_wikilink_def.rb +14 -0
  19. data/lib/test_base.yml +18 -0
  20. data/lib/wiki-test.rb +94 -0
  21. data/lib/wiki_rule.rb +240 -0
  22. data/lib/wikilink.yml +18 -0
  23. data/test/MarkdownTest_1.0/Amps and angle encoding.html +17 -0
  24. data/test/MarkdownTest_1.0/Amps and angle encoding.text +21 -0
  25. data/test/MarkdownTest_1.0/Auto links.html +18 -0
  26. data/test/MarkdownTest_1.0/Auto links.text +13 -0
  27. data/test/MarkdownTest_1.0/Backslash codeescapes.html +68 -0
  28. data/test/MarkdownTest_1.0/Backslash codeescapes.text +68 -0
  29. data/test/MarkdownTest_1.0/Backslash simpleescapes.html +33 -0
  30. data/test/MarkdownTest_1.0/Backslash simpleescapes.text +33 -0
  31. data/test/MarkdownTest_1.0/Blockquotes with code blocks.html +15 -0
  32. data/test/MarkdownTest_1.0/Blockquotes with code blocks.text +11 -0
  33. data/test/MarkdownTest_1.0/Hard-wrapped paragraphs with list-like lines.html +8 -0
  34. data/test/MarkdownTest_1.0/Hard-wrapped paragraphs with list-like lines.text +8 -0
  35. data/test/MarkdownTest_1.0/Horizontal rules.html +71 -0
  36. data/test/MarkdownTest_1.0/Horizontal rules.text +67 -0
  37. data/test/MarkdownTest_1.0/Inline HTML (Advanced).html +14 -0
  38. data/test/MarkdownTest_1.0/Inline HTML (Advanced).text +14 -0
  39. data/test/MarkdownTest_1.0/Inline HTML (Simple).html +72 -0
  40. data/test/MarkdownTest_1.0/Inline HTML (Simple).text +69 -0
  41. data/test/MarkdownTest_1.0/Inline HTML comments.html +13 -0
  42. data/test/MarkdownTest_1.0/Inline HTML comments.text +13 -0
  43. data/test/MarkdownTest_1.0/Links, inline style.html +9 -0
  44. data/test/MarkdownTest_1.0/Links, inline style.text +9 -0
  45. data/test/MarkdownTest_1.0/Links, reference style.html +18 -0
  46. data/test/MarkdownTest_1.0/Links, reference style.text +31 -0
  47. data/test/MarkdownTest_1.0/Literal quotes in titles.html +3 -0
  48. data/test/MarkdownTest_1.0/Literal quotes in titles.text +7 -0
  49. data/test/MarkdownTest_1.0/Markdown Documentation - Basics.html +314 -0
  50. data/test/MarkdownTest_1.0/Markdown Documentation - Basics.text +306 -0
  51. data/test/MarkdownTest_1.0/Markdown Documentation - Syntax.html +942 -0
  52. data/test/MarkdownTest_1.0/Markdown Documentation - Syntax.text +888 -0
  53. data/test/MarkdownTest_1.0/Nested blockquotes.html +9 -0
  54. data/test/MarkdownTest_1.0/Nested blockquotes.text +5 -0
  55. data/test/MarkdownTest_1.0/Ordered and unordered lists.html +137 -0
  56. data/test/MarkdownTest_1.0/Ordered and unordered lists.text +122 -0
  57. data/test/MarkdownTest_1.0/Strong and em together.html +7 -0
  58. data/test/MarkdownTest_1.0/Strong and em together.text +7 -0
  59. data/test/MarkdownTest_1.0/Tabs.html +25 -0
  60. data/test/MarkdownTest_1.0/Tabs.text +21 -0
  61. data/test/MarkdownTest_1.0/Tidyness.html +8 -0
  62. data/test/MarkdownTest_1.0/Tidyness.text +5 -0
  63. data/test/MarkdownTest_1.0/run-markdown.rb +56 -0
  64. data/test/MarkdownTest_1.0/test-fireball-markdown.rb +177 -0
  65. data/test/MarkdownTest_1.0/testdiff.rb +42 -0
  66. data/test/harder/test-markdown-harder.rb +11 -0
  67. data/test/harder/test-markdown-harder.yml +111 -0
  68. data/test/redcloth/redcloth-markdown-tests.rb +29 -0
  69. data/test/redcloth/redcloth-markdown-tests.yml +218 -0
  70. data/test/test-combo.rb +23 -0
  71. data/test/test-hash.rb +31 -0
  72. data/test/test-markdown.rb +11 -0
  73. data/test/test-markdown.yml +1144 -0
  74. data/test/test-match-data.rb +54 -0
  75. data/test/test-readme-example.rb +48 -0
  76. data/test/test-tables.rb +16 -0
  77. data/test/test-tables.yml +82 -0
  78. data/test/test-tartan-markdown.rb +11 -0
  79. data/test/test-tartan.rb +306 -0
  80. data/test/test-wikilink.rb +18 -0
  81. data/test/test-wikilink.yml +22 -0
  82. data/test/wikilink-test-helper.rb +14 -0
  83. metadata +139 -0
data/lib/symbolize.rb ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Larry Baltz
4
+ # Copyright (c) 2006. All rights reserved.
5
+
6
+ class Object
7
+ def symbolize; self; end
8
+ end
9
+
10
+ class String
11
+ def symbolize; match(/\A\w+\z/) ? to_sym : self; end
12
+ end
13
+
14
+ class Array
15
+ def symbolize; map { |e| e.symbolize }; end
16
+ end
17
+
18
+ class Hash
19
+ def symbolize
20
+ inject({}) do |hash, (attribute, value)|
21
+ hash[attribute.symbolize] = value.symbolize
22
+ hash
23
+ end
24
+ end
25
+ end
26
+
27
+ if __FILE__ == $0
28
+ require 'test/unit'
29
+
30
+ class TestSymbolize < Test::Unit::TestCase
31
+ def test_integer_symbolize
32
+ assert_equal(1, 1.symbolize)
33
+ end
34
+
35
+ def test_string_symbolize
36
+ assert_equal(:expected, "expected".symbolize)
37
+ end
38
+
39
+ def test_array_symbolize
40
+ array = ('a'..'d').to_a
41
+ expected = array.map { |e| e.to_sym }
42
+
43
+ assert_equal(expected, array.symbolize)
44
+ end
45
+
46
+ def test_hash_symbolize
47
+ hash = {'a' => 'x', 'b' => 'y', 'c' => 'z'}
48
+
49
+ expected = hash.inject({}) { |h, (a, v)| h[a.to_sym] = v.to_sym; h }
50
+
51
+ assert_equal(expected, hash.symbolize)
52
+ end
53
+
54
+ def test_array_with_non_word_element
55
+ assert_equal([:a, :b, :c, 'x x'], ['a', 'b', 'c', 'x x'].symbolize)
56
+ end
57
+
58
+ def test_hash_with_non_word_strings
59
+ assert_equal( {:a => :x, :b => :y, :c => 'a b', 'x x' => :c},
60
+ { 'a' => 'x',
61
+ 'b' => 'y',
62
+ 'c' => 'a b',
63
+ 'x x' => 'c'
64
+ }.symbolize
65
+ )
66
+ end
67
+
68
+ def test_hash_with_array_inside
69
+ assert_equal( {:a => :x, :b => [ :c, :d, 'x x']},
70
+ {'a' => 'x', 'b' => [ 'c', 'd', 'x x']}.symbolize )
71
+ end
72
+
73
+ def test_array_with_hash_inside
74
+ assert_equal( [:a , { :b => :c, :d => 'x x'}],
75
+ ['a' , { 'b' => 'c', 'd' => 'x x'}].symbolize )
76
+ end
77
+ end
78
+ end
data/lib/table.yml ADDED
@@ -0,0 +1,63 @@
1
+ block:
2
+ - title: table
3
+ html:
4
+ start_mark: "<table class=\"\\1\">\n"
5
+ end_mark: </table>
6
+ after: html_comment
7
+ match: |-
8
+ / (?:\[([\w]*)[|!](?:.*?)\|\])
9
+ (?:\s*)
10
+ (?:(?:\[[|!](?:.*?)\|\])(?:\s*))*/mx
11
+ subparse: table
12
+ table:
13
+ - title: spanrow
14
+ match: "/\[(?:[\w]*)([|!]\s*.*?\s*\|)\](?:\s*)/"
15
+ subparse:
16
+ match_group: 1
17
+ context: span_table_row
18
+ html:
19
+ start_mark: <tr>
20
+ end_mark: "</tr>\n"
21
+ - title: blockrow
22
+ match: "/\[(?:[\w]*)([|!]\s*.*?\s*\|)\](?:\s*)/m"
23
+ subparse:
24
+ match_group: 1
25
+ context: block_table_row
26
+ html:
27
+ start_mark: <tr>
28
+ end_mark: "</tr>\n"
29
+ span_table_row:
30
+ - title: span_th
31
+ match: "/\! \s* (.*?) \s* \|(?=[|!]|\z)/mx"
32
+ subparse:
33
+ match_group: 1
34
+ context: span
35
+ html:
36
+ start_mark: <th>
37
+ end_mark: </th>
38
+ - title: span_td
39
+ match: "/\| \s* (.*?) \s* \|(?=[|!]|\z)/mx"
40
+ subparse:
41
+ match_group: 1
42
+ context: span
43
+ html:
44
+ start_mark: <td>
45
+ end_mark: </td>
46
+ block_table_row:
47
+ - title: block_th
48
+ match: "/\! \s* (.*?) \s* \|(?=[|!]|\z)/mx"
49
+ subparse:
50
+ match_group: 1
51
+ context: block
52
+ html:
53
+ start_mark: <th>
54
+ end_mark: </th>
55
+ - title: block_td
56
+ match: "/\| \s* (.*?) \s* \|(?=[|!]|\z)/mx"
57
+ subparse:
58
+ match_group: 1
59
+ context: block
60
+ html:
61
+ start_mark: <td>
62
+ end_mark: </td>
63
+
data/lib/tartan.rb ADDED
@@ -0,0 +1,359 @@
1
+ #$Id: tartan.rb 159 2006-07-24 08:13:02Z larry $
2
+
3
+ require 'rubygems'
4
+ require 'yaml'
5
+ require 'core_ext/hash'
6
+ require 'core_ext/match_data'
7
+ require 'wiki_rule'
8
+ require 'symbolize'
9
+ require 'core_ext/module'
10
+ require 'core_ext/array'
11
+
12
+ class Shelf
13
+ Front = "\001"
14
+ Back = "\002"
15
+
16
+ def initialize
17
+ @counter = 0
18
+ @hash = {}
19
+ end
20
+
21
+ def replacement(i)
22
+ replacement = String.new(Front + i.to_s + Back)
23
+ end
24
+
25
+ def shelve(string)
26
+ @counter = @counter.next
27
+ @hash[@counter] = string
28
+ replacement(@counter)
29
+ end
30
+
31
+ def putback(text)
32
+ new_text = text.gsub(/#{Front}([[:digit:]]+)#{Back}/) do
33
+ putback(@hash[$1.to_i])
34
+ end
35
+ end
36
+ end
37
+
38
+ class ParsedText < String
39
+ def initialize(claimed, value)
40
+ super(value)
41
+ @claimed = claimed
42
+ end
43
+
44
+ def claimed?
45
+ @claimed
46
+ end
47
+ end
48
+
49
+ class ParsedTextList < Array
50
+ def initialize(*args)
51
+ self
52
+
53
+ if 1 == args.length
54
+ add_text(false, args[0])
55
+ end
56
+ end
57
+
58
+ def add_text(claimed, text)
59
+ push(ParsedText.new(claimed, text))
60
+ end
61
+
62
+ def add(text_element)
63
+ push(text_element)
64
+ end
65
+
66
+ def add_back(text_element)
67
+ parsed_text = args.first
68
+ unshift(parsed_text)
69
+ end
70
+
71
+ def add_back_text(claimed, text)
72
+ unshift(ParsedText.new(claimed, text))
73
+ end
74
+
75
+ alias :to_s :join
76
+ end
77
+
78
+
79
+ class Object
80
+ def wiki_hash
81
+ raise ArgumentError, "Argument can not generate a WikiDef"
82
+ end
83
+ end
84
+
85
+ class Hash
86
+ def wiki_hash
87
+ yield self
88
+ end
89
+ end
90
+
91
+ class String
92
+ def wiki_hash
93
+ yield YAML.load(self).symbolize
94
+ end
95
+ end
96
+
97
+ class Array
98
+ def wiki_hash
99
+ each { |element| yield element }
100
+ end
101
+ end
102
+
103
+ class WikiDefs < Hash
104
+ class << self
105
+ def find_file_in_path(file_name)
106
+ $:.each do |path|
107
+ file = path+'/'+file_name
108
+ return file if File.file?(file)
109
+ end
110
+
111
+ raise ArgumentError, "Can't find file #{file_name} in Ruby library path"
112
+ end
113
+ end
114
+
115
+ # Initialize initial defs
116
+ def initialize(external_defs={})
117
+ add(external_defs)
118
+ end
119
+
120
+ def find_sub_hash_index(hash_array, title)
121
+ index = hash_array.index { |sub_hash|
122
+ sub_hash.title == title
123
+ }
124
+ end
125
+
126
+ def add_yaml_file(def_file)
127
+ file_with_path = WikiDefs.find_file_in_path(def_file)
128
+
129
+ defs = YAML.load_file(file_with_path).symbolize
130
+
131
+ add(defs)
132
+ end
133
+
134
+ def add(defs)
135
+ defs.wiki_hash {|h| add_hash(h)}
136
+ self
137
+ end
138
+
139
+ def add_hash(external_defs)
140
+ external_defs.each {|context_name, external_rule_list|
141
+ self[context_name] ||= []
142
+ # self[context_name] ||= Dictionary.new
143
+ rule_dictionary = self[context_name]
144
+
145
+ external_rule_list.each { |proto_rule|
146
+ rule = case proto_rule
147
+ when WikiRule: proto_rule
148
+ when Symbol, String: WikiRule.new({ proto_rule => true })
149
+ when Hash: WikiRule.new(proto_rule);
150
+ else raise ArgumentError, "each matching rule must be a Hash"
151
+ end
152
+
153
+ if rule.template
154
+ index = find_sub_hash_index(self[context_name], rule.template)
155
+
156
+ rule = WikiRule.new(self[context_name][index].merge(rule))
157
+ end
158
+
159
+ if rule.before
160
+ # rule_dictionary
161
+ addByPosition(context_name, rule, :before)
162
+ rule.placed(:before)
163
+ elsif rule.after
164
+ addByPosition(context_name, rule, :after, 1)
165
+ rule.placed(:after)
166
+ elsif rule.beginning
167
+ self[context_name].unshift(rule)
168
+ rule.placed(:beginning)
169
+ else
170
+ self[context_name].push(rule)
171
+ end
172
+ }
173
+ }
174
+ end
175
+
176
+ private
177
+
178
+ def addByPosition(context_name, rule, position, index_offset=0)
179
+ index = find_sub_hash_index(self[context_name], rule[position])
180
+
181
+ unless index
182
+ raise "\"#{rule.title}\" can not be added #{position.to_s}" +
183
+ " \"#{rule[position]}\", because it does not exist"
184
+ end
185
+ self[context_name].insert(index+index_offset, rule)
186
+ end
187
+ end
188
+
189
+ class Tartan < String
190
+ class << self
191
+ def yaml(file_name)
192
+ @defs ||= WikiDefs.new
193
+ @defs.add_yaml_file(file_name)
194
+ end
195
+
196
+ def defs
197
+ @defs
198
+ end
199
+
200
+ def add_defs (def_set)
201
+ @defs ||= WikiDefs.new
202
+ @defs.add(def_set)
203
+ end
204
+
205
+ alias :set_defs :add_defs
206
+ end
207
+
208
+ # parser helper methods
209
+
210
+ def initialize_helper
211
+ @sequences = {}
212
+ end
213
+
214
+ def count(str)
215
+ str.length
216
+ end
217
+
218
+ def sequence(sequence_id)
219
+ @sequences[sequence_id] ||= 0
220
+ @sequences[sequence_id] += 1
221
+ end
222
+
223
+ def sequence_reset(sequence_id)
224
+ @sequences[sequence_id] = 0
225
+ end
226
+
227
+ def untabify(text)
228
+ text.gsub(/(\n?)(?:([^\t\n]{4})|([^\t\n]*)\t)/n) {$1+[$+].pack("A4")}
229
+ end
230
+
231
+ def len(text)
232
+ text.length
233
+ end
234
+
235
+ def finalize(type, text)
236
+ text
237
+ end
238
+
239
+ # core Tartan methods
240
+
241
+ def initialize(wstring, options=nil)
242
+ wstring.gsub!(/\r/, '')
243
+
244
+ @default_rule = WikiRule.new
245
+
246
+ @shelf = Shelf.new
247
+
248
+ @wiki_string = wstring
249
+
250
+ if !options
251
+ if defined? WikiOptions
252
+ @options = WikiOptions.dup
253
+ else
254
+ @options = {}
255
+ end
256
+ else
257
+ @options = options
258
+ end
259
+
260
+ initialize_helper
261
+ end
262
+
263
+ def substitute(string, match)
264
+ # do function value substutution
265
+ local_string = string.gsub(/#\{([a-zA-Z_]+)(?:\((.*?)\))?\}/m) {|to_eval|
266
+ function_match = $~
267
+
268
+ # break the parameters up
269
+ # '-1' used to retain all parameters even if they are empty
270
+ params = function_match[2].split(/,/,-1)
271
+
272
+ params.collect! { |param|
273
+ "nul param" ": " + string if ! param
274
+ substitute(param, match)
275
+ }
276
+
277
+ send(function_match[1].to_sym, *params)
278
+ }
279
+
280
+ local_string = match.replace(local_string) if match
281
+
282
+ # do variable substitution
283
+ return local_string.gsub(/\{\{\{(.+?)\}\}\}/) {|var| get_var($1)}
284
+ end
285
+
286
+ def shelve(string)
287
+ @shelf.shelve(string)
288
+ end
289
+
290
+ def to_type(type=:html)
291
+ out = @shelf.putback(parse_by_context(type, :block, @wiki_string))
292
+ finalize(type, out)
293
+ end
294
+
295
+ alias :to_html :to_type
296
+
297
+ def to_db
298
+ to_type(:db)
299
+ end
300
+
301
+ def set_vars(var_cluster, match)
302
+ return unless var_cluster
303
+
304
+ if Array == var_cluster.class
305
+ var_cluster.each do |a_hash|
306
+ set_vars(a_hash, match)
307
+ end
308
+ return
309
+ end
310
+
311
+ local_hash = var_cluster.dup
312
+
313
+ var_cluster.each do |var_name,var_val|
314
+ var_val = substitute(var_val, match)
315
+ var_name = substitute(var_name, match)
316
+
317
+ local_hash[var_name] = var_val
318
+ # allow case-insensitive names via :set for markdown
319
+ local_hash[var_name.downcase] = var_val
320
+ end
321
+ @options.merge!(local_hash)
322
+ end
323
+
324
+ def get_var(var)
325
+ # not all variable names are downcased
326
+ value = @options[var]
327
+ value ||= @options[var.downcase]
328
+ return value
329
+ end
330
+
331
+ def parse_by_context(parse_type, parse_context, parse_string)
332
+ parsing = ParsedTextList.new(parse_string)
333
+
334
+ self.class.defs[parse_context].each do |rule|
335
+
336
+ if rule.default_rule
337
+ @default_rule = @default_rule.deep_merge(rule)
338
+ next if rule.ignore
339
+ else
340
+ next if rule.ignore
341
+ rule = @default_rule.deep_merge(rule)
342
+ end
343
+
344
+ if !rule.match && rule.vars_to_set
345
+ set_vars(rule.vars_to_set, nil)
346
+ end
347
+
348
+ if rule.match
349
+ parsing = rule.parse_element(parse_type, parsing, self)
350
+ end
351
+
352
+ if rule.rescan
353
+ parsing = ParsedTextList.new(parsing.to_s)
354
+ end
355
+ end
356
+
357
+ parsing.to_s
358
+ end
359
+ end