sqlpostgres 1.2.4

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 (207) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +22 -0
  3. data/LICENSE.md +23 -0
  4. data/README.rdoc +59 -0
  5. data/Rakefile +32 -0
  6. data/VERSION +1 -0
  7. data/doc/BUGS +2 -0
  8. data/doc/examples/README +6 -0
  9. data/doc/examples/connection.rb +16 -0
  10. data/doc/examples/connection_auto.rb +22 -0
  11. data/doc/examples/connection_ctor.rb +18 -0
  12. data/doc/examples/connection_default.rb +15 -0
  13. data/doc/examples/connection_exec.rb +18 -0
  14. data/doc/examples/connection_manual.rb +12 -0
  15. data/doc/examples/connection_wrapped_new.rb +13 -0
  16. data/doc/examples/connection_wrapped_open.rb +13 -0
  17. data/doc/examples/cursor.rb +38 -0
  18. data/doc/examples/include_module.rb +9 -0
  19. data/doc/examples/include_module2.rb +12 -0
  20. data/doc/examples/insert.rb +30 -0
  21. data/doc/examples/insert2.rb +36 -0
  22. data/doc/examples/insert_bytea.rb +16 -0
  23. data/doc/examples/insert_bytea_array.rb +17 -0
  24. data/doc/examples/insert_default_values.rb +16 -0
  25. data/doc/examples/insert_insert.rb +16 -0
  26. data/doc/examples/insert_insert_default.rb +16 -0
  27. data/doc/examples/insert_insert_select.rb +20 -0
  28. data/doc/examples/insert_select.rb +20 -0
  29. data/doc/examples/interval.rb +17 -0
  30. data/doc/examples/savepoint.rb +38 -0
  31. data/doc/examples/select.rb +33 -0
  32. data/doc/examples/select2.rb +36 -0
  33. data/doc/examples/select_cross_join.rb +18 -0
  34. data/doc/examples/select_distinct.rb +18 -0
  35. data/doc/examples/select_distinct_on +19 -0
  36. data/doc/examples/select_for_update.rb +18 -0
  37. data/doc/examples/select_from.rb +17 -0
  38. data/doc/examples/select_from_subselect.rb +20 -0
  39. data/doc/examples/select_group_by.rb +19 -0
  40. data/doc/examples/select_having.rb +20 -0
  41. data/doc/examples/select_join_on.rb +18 -0
  42. data/doc/examples/select_join_using.rb +18 -0
  43. data/doc/examples/select_limit.rb +19 -0
  44. data/doc/examples/select_natural_join.rb +18 -0
  45. data/doc/examples/select_offset.rb +19 -0
  46. data/doc/examples/select_order_by.rb +20 -0
  47. data/doc/examples/select_select.rb +30 -0
  48. data/doc/examples/select_select_alias.rb +30 -0
  49. data/doc/examples/select_select_expression.rb +31 -0
  50. data/doc/examples/select_select_literal.rb +24 -0
  51. data/doc/examples/select_union.rb +21 -0
  52. data/doc/examples/select_where_array.rb +18 -0
  53. data/doc/examples/select_where_in.rb +18 -0
  54. data/doc/examples/select_where_string.rb +18 -0
  55. data/doc/examples/simple.rb +34 -0
  56. data/doc/examples/transaction.rb +30 -0
  57. data/doc/examples/transaction_abort.rb +30 -0
  58. data/doc/examples/transaction_commit.rb +34 -0
  59. data/doc/examples/translate_substitute_values.rb +17 -0
  60. data/doc/examples/update.rb +32 -0
  61. data/doc/examples/update2.rb +44 -0
  62. data/doc/examples/update_only.rb +17 -0
  63. data/doc/examples/update_set.rb +17 -0
  64. data/doc/examples/update_set_array.rb +16 -0
  65. data/doc/examples/update_set_bytea.rb +16 -0
  66. data/doc/examples/update_set_expression.rb +16 -0
  67. data/doc/examples/update_set_subselect.rb +20 -0
  68. data/doc/examples/update_where.rb +17 -0
  69. data/doc/examples/use_prefix.rb +8 -0
  70. data/doc/examples/use_prefix2.rb +11 -0
  71. data/doc/index.html +31 -0
  72. data/doc/insertexamples.rb +9 -0
  73. data/doc/makemanual +4 -0
  74. data/doc/makerdoc +5 -0
  75. data/doc/manual.dbk +622 -0
  76. data/lib/sqlpostgres/Connection.rb +198 -0
  77. data/lib/sqlpostgres/Cursor.rb +157 -0
  78. data/lib/sqlpostgres/Delete.rb +67 -0
  79. data/lib/sqlpostgres/Exceptions.rb +15 -0
  80. data/lib/sqlpostgres/Insert.rb +279 -0
  81. data/lib/sqlpostgres/NullConnection.rb +22 -0
  82. data/lib/sqlpostgres/PgBit.rb +73 -0
  83. data/lib/sqlpostgres/PgBox.rb +37 -0
  84. data/lib/sqlpostgres/PgCidr.rb +21 -0
  85. data/lib/sqlpostgres/PgCircle.rb +75 -0
  86. data/lib/sqlpostgres/PgInet.rb +21 -0
  87. data/lib/sqlpostgres/PgInterval.rb +208 -0
  88. data/lib/sqlpostgres/PgLineSegment.rb +37 -0
  89. data/lib/sqlpostgres/PgMacAddr.rb +21 -0
  90. data/lib/sqlpostgres/PgPath.rb +64 -0
  91. data/lib/sqlpostgres/PgPoint.rb +65 -0
  92. data/lib/sqlpostgres/PgPolygon.rb +56 -0
  93. data/lib/sqlpostgres/PgTime.rb +77 -0
  94. data/lib/sqlpostgres/PgTimeWithTimeZone.rb +98 -0
  95. data/lib/sqlpostgres/PgTimestamp.rb +93 -0
  96. data/lib/sqlpostgres/PgTwoPoints.rb +54 -0
  97. data/lib/sqlpostgres/PgType.rb +34 -0
  98. data/lib/sqlpostgres/PgWrapper.rb +41 -0
  99. data/lib/sqlpostgres/Savepoint.rb +98 -0
  100. data/lib/sqlpostgres/Select.rb +855 -0
  101. data/lib/sqlpostgres/Transaction.rb +120 -0
  102. data/lib/sqlpostgres/Translate.rb +436 -0
  103. data/lib/sqlpostgres/Update.rb +188 -0
  104. data/lib/sqlpostgres.rb +67 -0
  105. data/test/Assert.rb +72 -0
  106. data/test/Connection.test.rb +246 -0
  107. data/test/Cursor.test.rb +190 -0
  108. data/test/Delete.test.rb +68 -0
  109. data/test/Insert.test.rb +123 -0
  110. data/test/MockPGconn.rb +62 -0
  111. data/test/NullConnection.test.rb +32 -0
  112. data/test/PgBit.test.rb +98 -0
  113. data/test/PgBox.test.rb +108 -0
  114. data/test/PgCidr.test.rb +61 -0
  115. data/test/PgCircle.test.rb +107 -0
  116. data/test/PgInet.test.rb +61 -0
  117. data/test/PgInterval.test.rb +180 -0
  118. data/test/PgLineSegment.test.rb +108 -0
  119. data/test/PgMacAddr.test.rb +61 -0
  120. data/test/PgPath.test.rb +106 -0
  121. data/test/PgPoint.test.rb +100 -0
  122. data/test/PgPolygon.test.rb +95 -0
  123. data/test/PgTime.test.rb +120 -0
  124. data/test/PgTimeWithTimeZone.test.rb +117 -0
  125. data/test/PgTimestamp.test.rb +134 -0
  126. data/test/RandomThings.rb +25 -0
  127. data/test/Savepoint.test.rb +286 -0
  128. data/test/Select.test.rb +930 -0
  129. data/test/Test.rb +62 -0
  130. data/test/TestConfig.rb +21 -0
  131. data/test/TestSetup.rb +13 -0
  132. data/test/TestUtil.rb +92 -0
  133. data/test/Transaction.test.rb +275 -0
  134. data/test/Translate.test.rb +354 -0
  135. data/test/Update.test.rb +227 -0
  136. data/test/roundtrip.test.rb +565 -0
  137. data/test/test +34 -0
  138. data/tools/exampleinserter/ExampleInserter.rb +177 -0
  139. data/tools/rdoc/ChangeLog +796 -0
  140. data/tools/rdoc/EXAMPLE.rb +48 -0
  141. data/tools/rdoc/MANIFEST +58 -0
  142. data/tools/rdoc/Makefile +27 -0
  143. data/tools/rdoc/NEW_FEATURES +226 -0
  144. data/tools/rdoc/README +390 -0
  145. data/tools/rdoc/ToDo +6 -0
  146. data/tools/rdoc/contrib/Index +6 -0
  147. data/tools/rdoc/contrib/xslfo/ChangeLog +181 -0
  148. data/tools/rdoc/contrib/xslfo/README +106 -0
  149. data/tools/rdoc/contrib/xslfo/TODO +10 -0
  150. data/tools/rdoc/contrib/xslfo/convert.xsl +151 -0
  151. data/tools/rdoc/contrib/xslfo/demo/README +21 -0
  152. data/tools/rdoc/contrib/xslfo/demo/rdocfo +99 -0
  153. data/tools/rdoc/contrib/xslfo/fcm.xsl +54 -0
  154. data/tools/rdoc/contrib/xslfo/files.xsl +62 -0
  155. data/tools/rdoc/contrib/xslfo/labeled-lists.xsl +66 -0
  156. data/tools/rdoc/contrib/xslfo/lists.xsl +44 -0
  157. data/tools/rdoc/contrib/xslfo/modules.xsl +152 -0
  158. data/tools/rdoc/contrib/xslfo/rdoc.xsl +75 -0
  159. data/tools/rdoc/contrib/xslfo/source.xsl +66 -0
  160. data/tools/rdoc/contrib/xslfo/styles.xsl +69 -0
  161. data/tools/rdoc/contrib/xslfo/tables.xsl +67 -0
  162. data/tools/rdoc/contrib/xslfo/utils.xsl +21 -0
  163. data/tools/rdoc/debian/changelog +33 -0
  164. data/tools/rdoc/debian/compat +1 -0
  165. data/tools/rdoc/debian/control +20 -0
  166. data/tools/rdoc/debian/copyright +10 -0
  167. data/tools/rdoc/debian/dirs +2 -0
  168. data/tools/rdoc/debian/docs +2 -0
  169. data/tools/rdoc/debian/rdoc.1 +252 -0
  170. data/tools/rdoc/debian/rdoc.manpages +1 -0
  171. data/tools/rdoc/debian/rdoc.pod +149 -0
  172. data/tools/rdoc/debian/rules +9 -0
  173. data/tools/rdoc/dot/dot.rb +255 -0
  174. data/tools/rdoc/etc/rdoc.dtd +203 -0
  175. data/tools/rdoc/install.rb +137 -0
  176. data/tools/rdoc/markup/install.rb +43 -0
  177. data/tools/rdoc/markup/sample/sample.rb +42 -0
  178. data/tools/rdoc/markup/simple_markup/fragments.rb +323 -0
  179. data/tools/rdoc/markup/simple_markup/inline.rb +348 -0
  180. data/tools/rdoc/markup/simple_markup/lines.rb +147 -0
  181. data/tools/rdoc/markup/simple_markup/preprocess.rb +68 -0
  182. data/tools/rdoc/markup/simple_markup/to_html.rb +281 -0
  183. data/tools/rdoc/markup/simple_markup.rb +474 -0
  184. data/tools/rdoc/markup/test/AllTests.rb +2 -0
  185. data/tools/rdoc/markup/test/TestInline.rb +151 -0
  186. data/tools/rdoc/markup/test/TestParse.rb +411 -0
  187. data/tools/rdoc/rdoc/code_objects.rb +536 -0
  188. data/tools/rdoc/rdoc/diagram.rb +331 -0
  189. data/tools/rdoc/rdoc/generators/chm_generator.rb +112 -0
  190. data/tools/rdoc/rdoc/generators/html_generator.rb +1268 -0
  191. data/tools/rdoc/rdoc/generators/template/chm/chm.rb +86 -0
  192. data/tools/rdoc/rdoc/generators/template/html/html.rb +705 -0
  193. data/tools/rdoc/rdoc/generators/template/html/kilmer.rb +377 -0
  194. data/tools/rdoc/rdoc/generators/template/xml/rdf.rb +110 -0
  195. data/tools/rdoc/rdoc/generators/template/xml/xml.rb +110 -0
  196. data/tools/rdoc/rdoc/generators/xml_generator.rb +130 -0
  197. data/tools/rdoc/rdoc/options.rb +451 -0
  198. data/tools/rdoc/rdoc/parsers/parse_c.rb +287 -0
  199. data/tools/rdoc/rdoc/parsers/parse_f95.rb +118 -0
  200. data/tools/rdoc/rdoc/parsers/parse_rb.rb +2311 -0
  201. data/tools/rdoc/rdoc/parsers/parse_simple.rb +37 -0
  202. data/tools/rdoc/rdoc/parsers/parserfactory.rb +75 -0
  203. data/tools/rdoc/rdoc/rdoc.rb +219 -0
  204. data/tools/rdoc/rdoc/template.rb +234 -0
  205. data/tools/rdoc/rdoc/tokenstream.rb +25 -0
  206. data/tools/rdoc/rdoc.rb +9 -0
  207. metadata +291 -0
@@ -0,0 +1,474 @@
1
+ # = Introduction
2
+ #
3
+ # SimpleMarkup parses plain text documents and attempts to decompose
4
+ # them into their constituent parts. Some of these parts are high-level:
5
+ # paragraphs, chunks of verbatim text, list entries and the like. Other
6
+ # parts happen at the character level: a piece of bold text, a word in
7
+ # code font. This markup is similar in spirit to that used on WikiWiki
8
+ # webs, where folks create web pages using a simple set of formatting
9
+ # rules.
10
+ #
11
+ # SimpleMarkup itself does no output formatting: this is left to a
12
+ # different set of classes.
13
+ #
14
+ # SimpleMarkup is extendable at runtime: you can add new markup
15
+ # elements to be recognised in the documents that SimpleMarkup parses.
16
+ #
17
+ # SimpleMarkup is intended to be the basis for a family of tools which
18
+ # share the common requirement that simple, plain-text should be
19
+ # rendered in a variety of different output formats and media. It is
20
+ # envisaged that SimpleMarkup could be the basis for formating RDoc
21
+ # style comment blocks, Wiki entries, and online FAQs.
22
+ #
23
+ # = Basic Formatting
24
+ #
25
+ # * SimpleMarkup looks for a document's natural left margin. This is
26
+ # used as the initial margin for the document.
27
+ #
28
+ # * Consecutive lines starting at this margin are considered to be a
29
+ # paragraph.
30
+ #
31
+ # * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
32
+ # taken to be the start of a list. The margin in increased to be the
33
+ # first non-space following the list start flag. Subsequent lines
34
+ # should be indented to this new margin until the list ends. For
35
+ # example:
36
+ #
37
+ # * this is a list with three paragraphs in
38
+ # the first item. This is the first paragraph.
39
+ #
40
+ # And this is the second paragraph.
41
+ #
42
+ # 1. This is an indented, numbered list.
43
+ # 2. This is the second item in that list
44
+ #
45
+ # This is the third conventional paragraph in the
46
+ # first list item.
47
+ #
48
+ # * This is the second item in the original list
49
+ #
50
+ # * You can also construct labeled lists, sometimes called description
51
+ # or definition lists. Do this by putting the label in square brackets
52
+ # and indenting the list body:
53
+ #
54
+ # [cat] a small furry mammal
55
+ # that seems to sleep a lot
56
+ #
57
+ # [ant] a little insect that is known
58
+ # to enjoy picnics
59
+ #
60
+ # A minor variation on labeled lists uses two colons to separate the
61
+ # label from the list body:
62
+ #
63
+ # cat:: a small furry mammal
64
+ # that seems to sleep a lot
65
+ #
66
+ # ant:: a little insect that is known
67
+ # to enjoy picnics
68
+ #
69
+ # This latter style guarantees that the list bodies' left margins are
70
+ # aligned: think of them as a two column table.
71
+ #
72
+ # * Any line that starts to the right of the current margin is treated
73
+ # as verbatim text. This is useful for code listings. The example of a
74
+ # list above is also verbatim text.
75
+ #
76
+ # * A line starting with an equals sign (=) is treated as a
77
+ # heading. Level one headings have one equals sign, level two headings
78
+ # have two,and so on.
79
+ #
80
+ # * A line starting with three or more hyphens (at the current indent)
81
+ # generates a horizontal rule. THe more hyphens, the thicker the rule
82
+ # (within reason, and if supported by the output device)
83
+ #
84
+ # * You can use markup within text (except verbatim) to change the
85
+ # appearance of parts of that text. Out of the box, SimpleMarkup
86
+ # supports word-based and general markup.
87
+ #
88
+ # Word-based markup uses flag characters around individual words:
89
+ #
90
+ # [\*word*] displays word in a *bold* font
91
+ # [\_word_] displays word in an _emphasized_ font
92
+ # [\+word+] displays word in a +code+ font
93
+ #
94
+ # General markup affects text between a start delimiter and and end
95
+ # delimiter. Not surprisingly, these delimiters look like HTML markup.
96
+ #
97
+ # [\<b>text...</b>] displays word in a *bold* font
98
+ # [\<em>text...</em>] displays word in an _emphasized_ font
99
+ # [\<i>text...</i>] displays word in an _emphasized_ font
100
+ # [\<tt>text...</tt>] displays word in a +code+ font
101
+ #
102
+ # Unlike conventional Wiki markup, general markup can cross line
103
+ # boundaries. You can turn off the interpretation of markup by
104
+ # preceding the first character with a backslash, so \\\<b>bold
105
+ # text</b> and \\\*bold* produce \<b>bold text</b> and \*bold
106
+ # respectively.
107
+ #
108
+ # = Using SimpleMarkup
109
+ #
110
+ # For information on using SimpleMarkup programatically,
111
+ # see SM::SimpleMarkup.
112
+ #
113
+ # Author:: Dave Thomas, dave@pragmaticprogrammer.com
114
+ # Version:: 0.0
115
+ # License:: Ruby license
116
+
117
+
118
+
119
+ require 'markup/simple_markup/fragments'
120
+ require 'markup/simple_markup/lines.rb'
121
+
122
+ module SM #:nodoc:
123
+
124
+ # == Synopsis
125
+ #
126
+ # This code converts <tt>input_string</tt>, which is in the format
127
+ # described in markup/simple_markup.rb, to HTML. The conversion
128
+ # takes place in the +convert+ method, so you can use the same
129
+ # SimpleMarkup object to convert multiple input strings.
130
+ #
131
+ # require 'markup/simple_markup'
132
+ # require 'markup/simple_markup/to_html'
133
+ #
134
+ # p = SM::SimpleMarkup.new
135
+ # h = SM::ToHtml.new
136
+ #
137
+ # puts p.convert(input_string, h)
138
+ #
139
+ # You can extend the SimpleMarkup parser to recognise new markup
140
+ # sequences, and to add special processing for text that matches a
141
+ # regular epxression. Here we make WikiWords significant to the parser,
142
+ # and also make the sequences {word} and \<no>text...</no> signify
143
+ # strike-through text. When then subclass the HTML output class to deal
144
+ # with these:
145
+ #
146
+ # require 'markup/simple_markup'
147
+ # require 'markup/simple_markup/to_html'
148
+ #
149
+ # class WikiHtml < SM::ToHtml
150
+ # def handle_special_WIKIWORD(special)
151
+ # "<font color=red>" + special.text + "</font>"
152
+ # end
153
+ # end
154
+ #
155
+ # p = SM::SimpleMarkup.new
156
+ # p.add_word_pair("{", "}", :STRIKE)
157
+ # p.add_html("no", :STRIKE)
158
+ #
159
+ # p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
160
+ #
161
+ # h = WikiHtml.new
162
+ # h.add_tag(:STRIKE, "<strike>", "</strike>")
163
+ #
164
+ # puts "<body>" + p.convert(ARGF.read, h) + "</body>"
165
+ #
166
+ # == Output Formatters
167
+ #
168
+ # _missing_
169
+ #
170
+ #
171
+
172
+ class SimpleMarkup
173
+
174
+ SPACE = ?\s
175
+
176
+ # List entries look like:
177
+ # * text
178
+ # 1. text
179
+ # [label] text
180
+ # label:: text
181
+ #
182
+ # Flag it as a list entry, and
183
+ # work out the indent for subsequent lines
184
+
185
+ SIMPLE_LIST_RE = /^(
186
+ ( \* (?# bullet)
187
+ |- (?# bullet)
188
+ |\d+\. (?# numbered )
189
+ )
190
+ \s+
191
+ )\S/x
192
+
193
+ LABEL_LIST_RE = /^(
194
+ ( \[.*?\] (?# labeled )
195
+ |\S.*:: (?# note )
196
+ )(?=\s|$)
197
+ \s*
198
+ )/x
199
+
200
+
201
+ ##
202
+ # take a block of text and use various heuristics to determine
203
+ # it's structure (paragraphs, lists, and so on). Invoke an
204
+ # event handler as we identify significant chunks.
205
+ #
206
+
207
+ def initialize
208
+ @am = AttributeManager.new
209
+ @output = nil
210
+ end
211
+
212
+ ##
213
+ # Add to the sequences used to add formatting to an individual word
214
+ # (such as *bold*). Matching entries will generate attibutes
215
+ # that the output formatters can recognize by their +name+
216
+
217
+ def add_word_pair(start, stop, name)
218
+ @am.add_word_pair(start, stop, name)
219
+ end
220
+
221
+ ##
222
+ # Add to the sequences recognized as general markup
223
+ #
224
+
225
+ def add_html(tag, name)
226
+ @am.add_html(tag, name)
227
+ end
228
+
229
+ ##
230
+ # Add to other inline sequences. For example, we could add
231
+ # WikiWords using something like:
232
+ #
233
+ # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
234
+ #
235
+ # Each wiki word will be presented to the output formatter
236
+ # via the accept_special method
237
+ #
238
+
239
+ def add_special(pattern, name)
240
+ @am.add_special(pattern, name)
241
+ end
242
+
243
+
244
+ # We take a string, split it into lines, work out the type of
245
+ # each line, and from there deduce groups of lines (for example
246
+ # all lines in a paragraph). We then invoke the output formatter
247
+ # using a Visitor to display the result
248
+
249
+ def convert(str, op)
250
+ @lines = Lines.new(str.split(/\r?\n/).collect { |aLine|
251
+ Line.new(aLine) })
252
+ return "" if @lines.empty?
253
+ @lines.normalize
254
+ assign_types_to_lines
255
+ group = group_lines
256
+ # call the output formatter to handle the result
257
+ # group.to_a.each {|i| p i}
258
+ group.accept(@am, op)
259
+ end
260
+
261
+
262
+ #######
263
+ private
264
+ #######
265
+
266
+
267
+ ##
268
+ # Look through the text at line indentation. We flag each line as being
269
+ # Blank, a paragraph, a list element, or verbatim text
270
+ #
271
+
272
+ def assign_types_to_lines(margin = 0, level = 0)
273
+
274
+ while line = @lines.next
275
+ if line.isBlank?
276
+ line.stamp(Line::BLANK, level)
277
+ next
278
+ end
279
+
280
+ # if a line contains non-blanks before the margin, then it must belong
281
+ # to an outer level
282
+
283
+ text = line.text
284
+
285
+ for i in 0...margin
286
+ if text[i] != SPACE
287
+ @lines.unget
288
+ return
289
+ end
290
+ end
291
+
292
+ active_line = text[margin..-1]
293
+
294
+ # Rules (horizontal lines) look like
295
+ #
296
+ # --- (three or more hyphens)
297
+ #
298
+ # The more hyphens, the thicker the rule
299
+ #
300
+
301
+ if /^(---+)\s*$/ =~ active_line
302
+ line.stamp(Line::RULE, level, $1.length-2)
303
+ next
304
+ end
305
+
306
+ # Then look for list entries. First the ones that have to have
307
+ # text following them (* xxx, - xxx, and dd. xxx)
308
+
309
+ if SIMPLE_LIST_RE =~ active_line
310
+
311
+ offset = margin + $1.length
312
+ prefix = $2
313
+ prefix_length = prefix.length
314
+
315
+ flag = case prefix
316
+ when "*","-" then ListBase::BULLET
317
+ when /^\d/ then ListBase::NUMBER
318
+ else raise "Invalid List Type: #{self.inspect}"
319
+ end
320
+
321
+ line.stamp(Line::LIST, level+1, prefix, flag)
322
+ text[margin, prefix_length] = " " * prefix_length
323
+ assign_types_to_lines(offset, level + 1)
324
+ next
325
+ end
326
+
327
+
328
+ if LABEL_LIST_RE =~ active_line
329
+ offset = margin + $1.length
330
+ prefix = $2
331
+ prefix_length = prefix.length
332
+
333
+ next if handled_labeled_list(line, level, margin, offset, prefix)
334
+ end
335
+
336
+ # Headings look like
337
+ # = Main heading
338
+ # == Second level
339
+ # === Third
340
+ #
341
+ # Headings reset the level to 0
342
+
343
+ if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
344
+ prefix_length = $1.length
345
+ prefix_length = 6 if prefix_length > 6
346
+ line.stamp(Line::HEADING, 0, prefix_length)
347
+ line.strip_leading(margin + prefix_length)
348
+ next
349
+ end
350
+
351
+ # If the character's a space, then we have verbatim text,
352
+ # otherwise
353
+
354
+ if active_line[0] == SPACE
355
+ line.strip_leading(margin) if margin > 0
356
+ line.stamp(Line::VERBATIM, level)
357
+ else
358
+ line.stamp(Line::PARAGRAPH, level)
359
+ end
360
+ end
361
+ end
362
+
363
+ # Handle labeled list entries, We have a special case
364
+ # to deal with. Because the labels can be long, they force
365
+ # the remaining block of text over the to right:
366
+ #
367
+ # this is a long label that I wrote:: and here is the
368
+ # block of text with
369
+ # a silly margin
370
+ #
371
+ # So we allow the special case. If the label is followed
372
+ # by nothing, and if the following line is indented, then
373
+ # we take the indent of that line as the new margin
374
+ #
375
+ # this is a long label that I wrote::
376
+ # here is a more reasonably indented block which
377
+ # will ab attached to the label.
378
+ #
379
+
380
+ def handled_labeled_list(line, level, margin, offset, prefix)
381
+ prefix_length = prefix.length
382
+ text = line.text
383
+ flag = nil
384
+ case prefix
385
+ when /^\[/
386
+ flag = ListBase::LABELED
387
+ prefix = prefix[1, prefix.length-2]
388
+ when /:$/
389
+ flag = ListBase::NOTE
390
+ prefix.chop!
391
+ else raise "Invalid List Type: #{self.inspect}"
392
+ end
393
+
394
+ # body is on the next line
395
+
396
+ if text.length <= offset
397
+ original_line = line
398
+ line = @lines.next
399
+ return(false) unless line
400
+ text = line.text
401
+
402
+ for i in 0..margin
403
+ if text[i] != SPACE
404
+ @lines.unget
405
+ return false
406
+ end
407
+ end
408
+ i = margin
409
+ i += 1 while text[i] == SPACE
410
+ if i >= text.length
411
+ @lines.unget
412
+ return false
413
+ else
414
+ offset = i
415
+ prefix_length = 0
416
+ @lines.delete(original_line)
417
+ end
418
+ end
419
+
420
+ line.stamp(Line::LIST, level+1, prefix, flag)
421
+ text[margin, prefix_length] = " " * prefix_length
422
+ assign_types_to_lines(offset, level + 1)
423
+ return true
424
+ end
425
+
426
+ # Return a block consisting of fragments which are
427
+ # paragraphs, list entries or verbatim text. We merge consecutive
428
+ # lines of the same type and level together. We are also slightly
429
+ # tricky with lists: the lines following a list introduction
430
+ # look like paragraph lines at the next level, and we remap them
431
+ # into list entries instead
432
+
433
+ def group_lines
434
+ @lines.rewind
435
+
436
+ inList = false
437
+ wantedType = wantedLevel = nil
438
+
439
+ block = LineCollection.new
440
+ group = nil
441
+
442
+ while line = @lines.next
443
+ if line.level == wantedLevel and line.type == wantedType
444
+ group.add_text(line.text)
445
+ else
446
+ group = block.fragment_for(line)
447
+ block.add(group)
448
+ if line.type == Line::LIST
449
+ wantedType = Line::PARAGRAPH
450
+ else
451
+ wantedType = line.type
452
+ end
453
+ wantedLevel = line.level
454
+ end
455
+ end
456
+
457
+ block.normalize
458
+ block
459
+ end
460
+
461
+ ## for debugging, we allow access to our line contents as text
462
+ def content
463
+ @lines.as_text
464
+ end
465
+ public :content
466
+
467
+ ## for debugging, return the list of line types
468
+ def get_line_types
469
+ @lines.line_types
470
+ end
471
+ public :get_line_types
472
+ end
473
+
474
+ end
@@ -0,0 +1,2 @@
1
+ require 'TestParse.rb'
2
+ require 'TestInline.rb'
@@ -0,0 +1,151 @@
1
+ require "rubyunit"
2
+
3
+ $:.unshift "../.."
4
+
5
+ require "markup/simple_markup/inline"
6
+
7
+ class TestInline < TestCase
8
+
9
+
10
+ def setup
11
+ @am = SM::AttributeManager.new
12
+
13
+ @bold_on = @am.changed_attribute_by_name([], [:BOLD])
14
+ @bold_off = @am.changed_attribute_by_name([:BOLD], [])
15
+
16
+ @tt_on = @am.changed_attribute_by_name([], [:TT])
17
+ @tt_off = @am.changed_attribute_by_name([:TT], [])
18
+
19
+ @em_on = @am.changed_attribute_by_name([], [:EM])
20
+ @em_off = @am.changed_attribute_by_name([:EM], [])
21
+
22
+ @bold_em_on = @am.changed_attribute_by_name([], [:BOLD] | [:EM])
23
+ @bold_em_off = @am.changed_attribute_by_name([:BOLD] | [:EM], [])
24
+
25
+ @em_then_bold = @am.changed_attribute_by_name([:EM], [:EM] | [:BOLD])
26
+
27
+ @em_to_bold = @am.changed_attribute_by_name([:EM], [:BOLD])
28
+
29
+ @am.add_word_pair("{", "}", :WOMBAT)
30
+ @wombat_on = @am.changed_attribute_by_name([], [:WOMBAT])
31
+ @wombat_off = @am.changed_attribute_by_name([:WOMBAT], [])
32
+ end
33
+
34
+ def crossref(text)
35
+ [ @am.changed_attribute_by_name([], [:CROSSREF] | [:_SPECIAL_]),
36
+ SM::Special.new(33, text),
37
+ @am.changed_attribute_by_name([:CROSSREF] | [:_SPECIAL_], [])
38
+ ]
39
+ end
40
+
41
+ def test_special
42
+ # class names, variable names, file names, or instance variables
43
+ @am.add_special(/(
44
+ \b([A-Z]\w+(::\w+)*)
45
+ | \#\w+[!?=]?
46
+ | \b\w+([_\/\.]+\w+)+[!?=]?
47
+ )/x,
48
+ :CROSSREF)
49
+
50
+ assert_equals(["cat"], @am.flow("cat"))
51
+
52
+ assert_equals(["cat ", crossref("#fred"), " dog"].flatten,
53
+ @am.flow("cat #fred dog"))
54
+
55
+ assert_equals([crossref("#fred"), " dog"].flatten,
56
+ @am.flow("#fred dog"))
57
+
58
+ assert_equals(["cat ", crossref("#fred")].flatten, @am.flow("cat #fred"))
59
+ end
60
+
61
+ def test_basic
62
+ assert_equals(["cat"], @am.flow("cat"))
63
+
64
+ assert_equals(["cat ", @bold_on, "and", @bold_off, " dog"],
65
+ @am.flow("cat *and* dog"))
66
+
67
+ assert_equals(["cat ", @bold_on, "AND", @bold_off, " dog"],
68
+ @am.flow("cat *AND* dog"))
69
+
70
+ assert_equals(["cat ", @em_on, "And", @em_off, " dog"],
71
+ @am.flow("cat _And_ dog"))
72
+
73
+ assert_equals(["cat *and dog*"], @am.flow("cat *and dog*"))
74
+
75
+ assert_equals(["*cat and* dog"], @am.flow("*cat and* dog"))
76
+
77
+ assert_equals(["cat *and ", @bold_on, "dog", @bold_off],
78
+ @am.flow("cat *and *dog*"))
79
+
80
+ assert_equals(["cat ", @em_on, "and", @em_off, " dog"],
81
+ @am.flow("cat _and_ dog"))
82
+
83
+ assert_equals(["cat_and_dog"],
84
+ @am.flow("cat_and_dog"))
85
+
86
+ assert_equals(["cat ", @tt_on, "and", @tt_off, " dog"],
87
+ @am.flow("cat +and+ dog"))
88
+
89
+ assert_equals(["cat ", @bold_on, "a_b_c", @bold_off, " dog"],
90
+ @am.flow("cat *a_b_c* dog"))
91
+
92
+ assert_equals(["cat __ dog"],
93
+ @am.flow("cat __ dog"))
94
+
95
+ assert_equals(["cat ", @em_on, "_", @em_off, " dog"],
96
+ @am.flow("cat ___ dog"))
97
+
98
+ end
99
+
100
+ def test_combined
101
+ assert_equals(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off],
102
+ @am.flow("cat _and_ *dog*"))
103
+
104
+ assert_equals(["cat ", @em_on, "a__nd", @em_off, " ", @bold_on, "dog", @bold_off],
105
+ @am.flow("cat _a__nd_ *dog*"))
106
+ end
107
+
108
+ def test_html_like
109
+ assert_equals(["cat ", @tt_on, "dog", @tt_off], @am.flow("cat <tt>dog</Tt>"))
110
+
111
+ assert_equals(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off],
112
+ @am.flow("cat <i>and</i> <B>dog</b>"))
113
+
114
+ assert_equals(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off],
115
+ @am.flow("cat <i>and <B>dog</B></I>"))
116
+
117
+ assert_equals(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off],
118
+ @am.flow("cat <i>and </i><b>dog</b>"))
119
+
120
+ assert_equals(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off],
121
+ @am.flow("cat <i>and <b></i>dog</b>"))
122
+
123
+ assert_equals([@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off],
124
+ @am.flow("<tt>cat</tt> <i>and <b></i>dog</b>"))
125
+
126
+ assert_equals(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off],
127
+ @am.flow("cat <i>and <b>dog</b></i>"))
128
+
129
+ assert_equals(["cat ", @bold_em_on, "and", @bold_em_off, " dog"],
130
+ @am.flow("cat <i><b>and</b></i> dog"))
131
+
132
+
133
+ end
134
+
135
+ def test_protect
136
+ assert_equals(['cat \\ dog'], @am.flow('cat \\ dog'))
137
+
138
+ assert_equals(["cat <tt>dog</Tt>"], @am.flow("cat \\<tt>dog</Tt>"))
139
+
140
+ assert_equals(["cat ", @em_on, "and", @em_off, " <B>dog</b>"],
141
+ @am.flow("cat <i>and</i> \\<B>dog</b>"))
142
+
143
+ assert_equals(["*word* or <b>text</b>"], @am.flow("\\*word* or \\<b>text</b>"))
144
+ end
145
+
146
+ def test_adding
147
+ assert_equals(["cat ", @wombat_on, "and", @wombat_off, " dog" ],
148
+ @am.flow("cat {and} dog"))
149
+ assert_equals(["cat {and} dog" ], @am.flow("cat \\{and} dog"))
150
+ end
151
+ end