tartan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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