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,137 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ require 'ftools'
4
+
5
+ include Config
6
+
7
+ $ruby = CONFIG['ruby_install_name']
8
+
9
+ ##
10
+ # Install a binary file. We patch in on the way through to
11
+ # insert a #! line. If this is a Unix install, we name
12
+ # the command (for example) 'rdoc' and let the shebang line
13
+ # handle running it. Under windows, we add a '.rb' extension
14
+ # and let file associations to their stuff
15
+ #
16
+
17
+ def installBIN(from, opfile)
18
+
19
+ tmp_dir = nil
20
+ for t in [".", "/tmp", "c:/temp", $bindir]
21
+ stat = File.stat(t) rescue next
22
+ if stat.directory? and stat.writable?
23
+ tmp_dir = t
24
+ break
25
+ end
26
+ end
27
+
28
+ fail "Cannot find a temporary directory" unless tmp_dir
29
+ tmp_file = File.join(tmp_dir, "_tmp")
30
+
31
+
32
+ File.open(from) do |ip|
33
+ File.open(tmp_file, "w") do |op|
34
+ ruby = File.join($realbindir, $ruby)
35
+ op.puts "#!#{ruby}"
36
+ op.write ip.read
37
+ end
38
+ end
39
+
40
+ opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i
41
+ File::install(tmp_file, File.join($bindir, opfile), 0755, true)
42
+ File::unlink(tmp_file)
43
+ end
44
+
45
+
46
+
47
+
48
+
49
+ $sitedir = CONFIG["rubylibdir"]
50
+ unless $sitedir
51
+ version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
52
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
53
+ $sitedir = $:.find {|x| x =~ /site_ruby/}
54
+ if !$sitedir
55
+ $sitedir = File.join($libdir, "site_ruby")
56
+ elsif $sitedir !~ Regexp.quote(version)
57
+ $sitedir = File.join($sitedir, version)
58
+ end
59
+ end
60
+
61
+ $bindir = CONFIG["bindir"]
62
+
63
+ $realbindir = $bindir
64
+
65
+ bindir = CONFIG["bindir"]
66
+ if (destdir = ENV['DESTDIR'])
67
+ $bindir = destdir + $bindir
68
+ $sitedir = destdir + $sitedir
69
+
70
+ File::makedirs($bindir)
71
+ File::makedirs($sitedir)
72
+ end
73
+
74
+ rdoc_dest = File.join($sitedir, "rdoc")
75
+ dot_dest = File.join($sitedir, "dot")
76
+ rdoc_generators = File.join(rdoc_dest, "generators")
77
+ rdoc_templates = File.join(rdoc_generators, "template")
78
+ rdoc_parsers = File.join(rdoc_dest, "parsers")
79
+
80
+ File::makedirs(rdoc_dest,
81
+ dot_dest,
82
+ rdoc_generators,
83
+ rdoc_templates,
84
+ rdoc_parsers,
85
+ true)
86
+
87
+ File::chmod(0755, rdoc_dest)
88
+
89
+ # The library files
90
+ files = %w{
91
+ rdoc/code_objects.rb
92
+ rdoc/generators/*_generator.rb
93
+ rdoc/options.rb
94
+ rdoc/parsers/parserfactory.rb
95
+ rdoc/parsers/parse_*.rb
96
+ rdoc/template.rb
97
+ rdoc/tokenstream.rb
98
+ rdoc/diagram.rb
99
+ rdoc/rdoc.rb
100
+ dot/dot.rb
101
+ }.collect {|f| Dir.glob(f)}.flatten
102
+
103
+ for template in ["chm", "html", "xml"]
104
+ File::makedirs(File.join(rdoc_templates, template), true)
105
+ files.concat Dir.glob("rdoc/generators/template/#{template}/*.rb")
106
+ end
107
+
108
+ for aFile in files
109
+ File::install(aFile, File.join($sitedir, aFile), 0644, true)
110
+ end
111
+
112
+ # and the executable
113
+
114
+ installBIN("rdoc.rb", "rdoc")
115
+
116
+ # Temporary - we used to install html_generator in the rdoc
117
+ # directory, but now it's moved
118
+
119
+ File.unlink(File.join(rdoc_dest, "html_generator.rb")) rescue 1;
120
+
121
+ # and we used to have the templates under html_template
122
+ template = File.join(rdoc_dest, "generators", "html_template")
123
+ File.unlink(File.join(template, "standard.rb")) rescue 1;
124
+ File.unlink(File.join(template, "kilmer.rb")) rescue 1;
125
+
126
+ # and then they were in template/ ...
127
+ template = File.join(rdoc_dest, "generators", "template")
128
+ File.unlink(File.join(template, "standard.rb")) rescue 1;
129
+ File.unlink(File.join(template, "kilmer.rb")) rescue 1;
130
+ File.unlink(File.join(template, "xml.rb")) rescue 1;
131
+ File.unlink(File.join(template, "rdf.rb")) rescue 1;
132
+
133
+
134
+ # 'Markup' will eventually be a separate package, but
135
+ # for now we'll install it automatically
136
+
137
+ Dir.chdir("markup") && system("#$ruby install.rb")
@@ -0,0 +1,43 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ require 'ftools'
4
+
5
+ include Config
6
+
7
+ sitedir = CONFIG["rubylibdir"]
8
+ unless sitedir
9
+ version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
10
+ libdir = File.join(CONFIG["libdir"], "ruby", version)
11
+ sitedir = $:.find {|x| x =~ /site_ruby/}
12
+ if !sitedir
13
+ sitedir = File.join(libdir, "site_ruby")
14
+ elsif sitedir !~ Regexp.quote(version)
15
+ sitedir = File.join(sitedir, version)
16
+ end
17
+ end
18
+
19
+ if (destdir = ENV['DESTDIR'])
20
+ sitedir = destdir + sitedir
21
+ File::makedirs(sitedir)
22
+ end
23
+
24
+ if !File.directory?(sitedir)
25
+ $stderr.puts "Cannot find sitedir #{sitedir}"
26
+ exit 1
27
+ end
28
+
29
+ dest = File.join(sitedir, "markup")
30
+
31
+ File.mkpath(dest, true)
32
+
33
+ Find.find("simple_markup.rb", "simple_markup") do |fname|
34
+ if File.directory?(fname)
35
+ next if fname =~ /CVS/
36
+ File.mkpath(File.join(dest, fname), true)
37
+ else
38
+ next unless fname =~ /\.rb$/
39
+ next if fname =~ /install.rb$/
40
+ File.install(fname, File.join(dest, fname), 0444, true)
41
+ end
42
+ end
43
+
@@ -0,0 +1,42 @@
1
+ # This program illustrates the basic use of the SimpleMarkup
2
+ # class. It extracts the first comment block from the
3
+ # simple_markup.rb file and converts it into HTML on
4
+ # standard output. Run it using
5
+ #
6
+ # % ruby sample.rb
7
+ #
8
+ # You should be in the sample/ directory when you do this,
9
+ # as it hardwires the path to the files it needs to require.
10
+ # This isn't necessary in the code you write once you've
11
+ # installed the package.
12
+ #
13
+ # For a better way of formatting code comment blocks (and more)
14
+ # see the rdoc package.
15
+ #
16
+
17
+ $:.unshift "../.."
18
+
19
+ require 'markup/simple_markup'
20
+ require 'markup/simple_markup/to_html'
21
+
22
+ # Extract the comment block from the source file
23
+
24
+ input_string = ""
25
+
26
+ File.foreach("../simple_markup.rb") do |line|
27
+ break unless line.gsub!(/^\# ?/, '')
28
+ input_string << line
29
+ end
30
+
31
+ # Create a markup object
32
+ markup = SM::SimpleMarkup.new
33
+
34
+ # Attach it to an HTML formatter
35
+ h = SM::ToHtml.new
36
+
37
+ # And convert out comment block to html. Wrap it a body
38
+ # tag pair to let browsers view it
39
+
40
+ puts "<html><body>"
41
+ puts markup.convert(input_string, h)
42
+ puts "</body></html>"
@@ -0,0 +1,323 @@
1
+ require 'markup/simple_markup/lines.rb'
2
+ require 'markup/simple_markup/inline.rb'
3
+
4
+ module SM
5
+
6
+ ##
7
+ # A Fragment is a chunk of text, subclassed as a paragraph, a list
8
+ # entry, or verbatim text
9
+
10
+ class Fragment
11
+ attr_reader :level, :param, :txt
12
+ attr_accessor :type
13
+
14
+ def initialize(level, param, type, txt)
15
+ @level = level
16
+ @param = param
17
+ @type = type
18
+ @txt = ""
19
+ add_text(txt) if txt
20
+ end
21
+
22
+ def add_text(txt)
23
+ @txt << " " if @txt.length > 0
24
+ @txt << txt.tr_s("\n ", " ").strip
25
+ end
26
+
27
+ def to_s
28
+ "L#@level: #{self.class.name.split('::')[-1]}\n#@txt"
29
+ end
30
+
31
+ ######
32
+ # This is a simple factory system that lets us associate fragement
33
+ # types (a string) with a subclass of fragment
34
+
35
+ TYPE_MAP = {}
36
+
37
+ def Fragment.type_name(name)
38
+ TYPE_MAP[name] = self
39
+ end
40
+
41
+ def Fragment.for(line)
42
+ klass = TYPE_MAP[line.type] ||
43
+ raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'")
44
+ return klass.new(line.level, line.param, line.flag, line.text)
45
+ end
46
+ end
47
+
48
+ ##
49
+ # A paragraph is a fragment which gets wrapped to fit. We remove all
50
+ # newlines when we're created, and have them put back on output
51
+
52
+ class Paragraph < Fragment
53
+ type_name Line::PARAGRAPH
54
+ end
55
+
56
+ class BlankLine < Paragraph
57
+ type_name Line::BLANK
58
+ end
59
+
60
+ class Heading < Paragraph
61
+ type_name Line::HEADING
62
+
63
+ def head_level
64
+ @param.to_i
65
+ end
66
+ end
67
+
68
+ ##
69
+ # A List is a fragment with some kind of label
70
+ #
71
+
72
+ class ListBase < Paragraph
73
+ # List types
74
+ BULLET = :BULLET
75
+ NUMBER = :NUMBER
76
+ LABELED = :LABELED
77
+ NOTE = :NOTE
78
+ end
79
+
80
+ class ListItem < ListBase
81
+ type_name Line::LIST
82
+
83
+ # def label
84
+ # am = AttributeManager.new(@param)
85
+ # am.flow
86
+ # end
87
+ end
88
+
89
+ class ListStart < ListBase
90
+ def initialize(level, param, type)
91
+ super(level, param, type, nil)
92
+ end
93
+ end
94
+
95
+ class ListEnd < ListBase
96
+ def initialize(level, type)
97
+ super(level, "", type, nil)
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Verbatim code contains lines that don't get wrapped.
103
+
104
+ class Verbatim < Fragment
105
+ type_name Line::VERBATIM
106
+
107
+ def add_text(txt)
108
+ @txt << txt.chomp << "\n"
109
+ end
110
+
111
+ end
112
+
113
+ ##
114
+ # A horizontal rule
115
+ class Rule < Fragment
116
+ type_name Line::RULE
117
+ end
118
+
119
+
120
+ # Collect groups of lines together. Each group
121
+ # will end up containing a flow of text
122
+
123
+ class LineCollection
124
+
125
+ def initialize
126
+ @fragments = []
127
+ end
128
+
129
+ def add(fragment)
130
+ @fragments << fragment
131
+ end
132
+
133
+ def each(&b)
134
+ @fragments.each(&b)
135
+ end
136
+
137
+ # For testing
138
+ def to_a
139
+ @fragments.map {|fragment| fragment.to_s}
140
+ end
141
+
142
+ # Factory for different fragment types
143
+ def fragment_for(*args)
144
+ Fragment.for(*args)
145
+ end
146
+
147
+ # tidy up at the end
148
+ def normalize
149
+ change_verbatim_blank_lines
150
+ add_list_start_and_ends
151
+ add_list_breaks
152
+ tidy_blank_lines
153
+ end
154
+
155
+ def to_s
156
+ @fragments.join("\n----\n")
157
+ end
158
+
159
+ def accept(am, visitor)
160
+
161
+ visitor.start_accepting
162
+
163
+ @fragments.each do |fragment|
164
+ case fragment
165
+ when Verbatim
166
+ visitor.accept_verbatim(am, fragment)
167
+ when Rule
168
+ visitor.accept_rule(am, fragment)
169
+ when ListStart
170
+ visitor.accept_list_start(am, fragment)
171
+ when ListEnd
172
+ visitor.accept_list_end(am, fragment)
173
+ when ListItem
174
+ visitor.accept_list_item(am, fragment)
175
+ when BlankLine
176
+ visitor.accept_blank_line(am, fragment)
177
+ when Heading
178
+ visitor.accept_heading(am, fragment)
179
+ when Paragraph
180
+ visitor.accept_paragraph(am, fragment)
181
+ end
182
+ end
183
+
184
+ visitor.end_accepting
185
+ end
186
+ #######
187
+ private
188
+ #######
189
+
190
+ # If you have:
191
+ #
192
+ # normal paragraph text.
193
+ #
194
+ # this is code
195
+ #
196
+ # and more code
197
+ #
198
+ # You'll end up with the fragments Paragraph, BlankLine,
199
+ # Verbatim, BlankLine, Verbatim, BlankLine, etc
200
+ #
201
+ # The BlankLine in the middle of the verbatim chunk needs to
202
+ # be changed to a real verbatim newline, and the two
203
+ # verbatim blocks merged
204
+ #
205
+ #
206
+ def change_verbatim_blank_lines
207
+ last_was_verbatim = false
208
+ @fragments.size.times do |i|
209
+ if BlankLine === @fragments[i]
210
+ if last_was_verbatim and
211
+ i < @fragments.size - 1 and
212
+ Verbatim === @fragments[i+1]
213
+ merge_fragments(i-1)
214
+ @fragments[i] = @fragments[i+1] = nil
215
+ end
216
+ end
217
+ last_was_verbatim = Verbatim === @fragments[i]
218
+ end
219
+ @fragments.compact!
220
+ end
221
+
222
+ # Merge the sequence Verbatim/Blank/Verbatim into
223
+ # a single Verbatim fragment
224
+ def merge_fragments(start)
225
+ target = @fragments[start]
226
+ target.add_text("\n")
227
+ target.add_text(@fragments[start+2].txt)
228
+ end
229
+
230
+ # List nesting is implicit given the level of
231
+ # Make it explicit, just to make life a tad
232
+ # easier for the output processors
233
+
234
+ def add_list_start_and_ends
235
+ level = 0
236
+ res = []
237
+ type_stack = []
238
+
239
+ @fragments.each do |fragment|
240
+ # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}"
241
+ new_level = fragment.level
242
+ while (level < new_level)
243
+ level += 1
244
+ type = fragment.type
245
+ res << ListStart.new(level, fragment.param, type) if type
246
+ type_stack.push type
247
+ # $stderr.puts "Start: #{level}"
248
+ end
249
+
250
+ while level > new_level
251
+ type = type_stack.pop
252
+ res << ListEnd.new(level, type) if type
253
+ level -= 1
254
+ # $stderr.puts "End: #{level}, #{type}"
255
+ end
256
+
257
+ res << fragment
258
+ level = fragment.level
259
+ end
260
+ level.downto(1) do |i|
261
+ type = type_stack.pop
262
+ res << ListEnd.new(i, type) if type
263
+ end
264
+
265
+ @fragments = res
266
+ end
267
+
268
+ # now insert start/ends between list entries at the
269
+ # same level that have different element types
270
+
271
+ def add_list_breaks
272
+ res = @fragments
273
+
274
+ @fragments = []
275
+ list_stack = []
276
+
277
+ res.each do |fragment|
278
+ case fragment
279
+ when ListStart
280
+ list_stack.push fragment
281
+ when ListEnd
282
+ start = list_stack.pop
283
+ fragment.type = start.type
284
+ when ListItem
285
+ l = list_stack.last
286
+ if fragment.type != l.type
287
+ @fragments << ListEnd.new(l.level, l.type)
288
+ start = ListStart.new(l.level, fragment.param, fragment.type)
289
+ @fragments << start
290
+ list_stack.pop
291
+ list_stack.push start
292
+ end
293
+ else
294
+ ;
295
+ end
296
+ @fragments << fragment
297
+ end
298
+ end
299
+
300
+ # Finally tidy up the blank lines:
301
+ # * change Blank/ListEnd into ListEnd/Blank
302
+ # * remove blank lines at the front
303
+
304
+ def tidy_blank_lines
305
+ (@fragments.size - 1).times do |i|
306
+ if @fragments[i].kind_of?(BlankLine) and
307
+ @fragments[i+1].kind_of?(ListEnd)
308
+ @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i]
309
+ end
310
+ end
311
+
312
+ # remove leading blanks
313
+ @fragments.each_with_index do |f, i|
314
+ break unless f.kind_of? BlankLine
315
+ @fragments[i] = nil
316
+ end
317
+
318
+ @fragments.compact!
319
+ end
320
+
321
+ end
322
+
323
+ end