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.
- data/Gemfile +8 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.md +23 -0
- data/README.rdoc +59 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/doc/BUGS +2 -0
- data/doc/examples/README +6 -0
- data/doc/examples/connection.rb +16 -0
- data/doc/examples/connection_auto.rb +22 -0
- data/doc/examples/connection_ctor.rb +18 -0
- data/doc/examples/connection_default.rb +15 -0
- data/doc/examples/connection_exec.rb +18 -0
- data/doc/examples/connection_manual.rb +12 -0
- data/doc/examples/connection_wrapped_new.rb +13 -0
- data/doc/examples/connection_wrapped_open.rb +13 -0
- data/doc/examples/cursor.rb +38 -0
- data/doc/examples/include_module.rb +9 -0
- data/doc/examples/include_module2.rb +12 -0
- data/doc/examples/insert.rb +30 -0
- data/doc/examples/insert2.rb +36 -0
- data/doc/examples/insert_bytea.rb +16 -0
- data/doc/examples/insert_bytea_array.rb +17 -0
- data/doc/examples/insert_default_values.rb +16 -0
- data/doc/examples/insert_insert.rb +16 -0
- data/doc/examples/insert_insert_default.rb +16 -0
- data/doc/examples/insert_insert_select.rb +20 -0
- data/doc/examples/insert_select.rb +20 -0
- data/doc/examples/interval.rb +17 -0
- data/doc/examples/savepoint.rb +38 -0
- data/doc/examples/select.rb +33 -0
- data/doc/examples/select2.rb +36 -0
- data/doc/examples/select_cross_join.rb +18 -0
- data/doc/examples/select_distinct.rb +18 -0
- data/doc/examples/select_distinct_on +19 -0
- data/doc/examples/select_for_update.rb +18 -0
- data/doc/examples/select_from.rb +17 -0
- data/doc/examples/select_from_subselect.rb +20 -0
- data/doc/examples/select_group_by.rb +19 -0
- data/doc/examples/select_having.rb +20 -0
- data/doc/examples/select_join_on.rb +18 -0
- data/doc/examples/select_join_using.rb +18 -0
- data/doc/examples/select_limit.rb +19 -0
- data/doc/examples/select_natural_join.rb +18 -0
- data/doc/examples/select_offset.rb +19 -0
- data/doc/examples/select_order_by.rb +20 -0
- data/doc/examples/select_select.rb +30 -0
- data/doc/examples/select_select_alias.rb +30 -0
- data/doc/examples/select_select_expression.rb +31 -0
- data/doc/examples/select_select_literal.rb +24 -0
- data/doc/examples/select_union.rb +21 -0
- data/doc/examples/select_where_array.rb +18 -0
- data/doc/examples/select_where_in.rb +18 -0
- data/doc/examples/select_where_string.rb +18 -0
- data/doc/examples/simple.rb +34 -0
- data/doc/examples/transaction.rb +30 -0
- data/doc/examples/transaction_abort.rb +30 -0
- data/doc/examples/transaction_commit.rb +34 -0
- data/doc/examples/translate_substitute_values.rb +17 -0
- data/doc/examples/update.rb +32 -0
- data/doc/examples/update2.rb +44 -0
- data/doc/examples/update_only.rb +17 -0
- data/doc/examples/update_set.rb +17 -0
- data/doc/examples/update_set_array.rb +16 -0
- data/doc/examples/update_set_bytea.rb +16 -0
- data/doc/examples/update_set_expression.rb +16 -0
- data/doc/examples/update_set_subselect.rb +20 -0
- data/doc/examples/update_where.rb +17 -0
- data/doc/examples/use_prefix.rb +8 -0
- data/doc/examples/use_prefix2.rb +11 -0
- data/doc/index.html +31 -0
- data/doc/insertexamples.rb +9 -0
- data/doc/makemanual +4 -0
- data/doc/makerdoc +5 -0
- data/doc/manual.dbk +622 -0
- data/lib/sqlpostgres/Connection.rb +198 -0
- data/lib/sqlpostgres/Cursor.rb +157 -0
- data/lib/sqlpostgres/Delete.rb +67 -0
- data/lib/sqlpostgres/Exceptions.rb +15 -0
- data/lib/sqlpostgres/Insert.rb +279 -0
- data/lib/sqlpostgres/NullConnection.rb +22 -0
- data/lib/sqlpostgres/PgBit.rb +73 -0
- data/lib/sqlpostgres/PgBox.rb +37 -0
- data/lib/sqlpostgres/PgCidr.rb +21 -0
- data/lib/sqlpostgres/PgCircle.rb +75 -0
- data/lib/sqlpostgres/PgInet.rb +21 -0
- data/lib/sqlpostgres/PgInterval.rb +208 -0
- data/lib/sqlpostgres/PgLineSegment.rb +37 -0
- data/lib/sqlpostgres/PgMacAddr.rb +21 -0
- data/lib/sqlpostgres/PgPath.rb +64 -0
- data/lib/sqlpostgres/PgPoint.rb +65 -0
- data/lib/sqlpostgres/PgPolygon.rb +56 -0
- data/lib/sqlpostgres/PgTime.rb +77 -0
- data/lib/sqlpostgres/PgTimeWithTimeZone.rb +98 -0
- data/lib/sqlpostgres/PgTimestamp.rb +93 -0
- data/lib/sqlpostgres/PgTwoPoints.rb +54 -0
- data/lib/sqlpostgres/PgType.rb +34 -0
- data/lib/sqlpostgres/PgWrapper.rb +41 -0
- data/lib/sqlpostgres/Savepoint.rb +98 -0
- data/lib/sqlpostgres/Select.rb +855 -0
- data/lib/sqlpostgres/Transaction.rb +120 -0
- data/lib/sqlpostgres/Translate.rb +436 -0
- data/lib/sqlpostgres/Update.rb +188 -0
- data/lib/sqlpostgres.rb +67 -0
- data/test/Assert.rb +72 -0
- data/test/Connection.test.rb +246 -0
- data/test/Cursor.test.rb +190 -0
- data/test/Delete.test.rb +68 -0
- data/test/Insert.test.rb +123 -0
- data/test/MockPGconn.rb +62 -0
- data/test/NullConnection.test.rb +32 -0
- data/test/PgBit.test.rb +98 -0
- data/test/PgBox.test.rb +108 -0
- data/test/PgCidr.test.rb +61 -0
- data/test/PgCircle.test.rb +107 -0
- data/test/PgInet.test.rb +61 -0
- data/test/PgInterval.test.rb +180 -0
- data/test/PgLineSegment.test.rb +108 -0
- data/test/PgMacAddr.test.rb +61 -0
- data/test/PgPath.test.rb +106 -0
- data/test/PgPoint.test.rb +100 -0
- data/test/PgPolygon.test.rb +95 -0
- data/test/PgTime.test.rb +120 -0
- data/test/PgTimeWithTimeZone.test.rb +117 -0
- data/test/PgTimestamp.test.rb +134 -0
- data/test/RandomThings.rb +25 -0
- data/test/Savepoint.test.rb +286 -0
- data/test/Select.test.rb +930 -0
- data/test/Test.rb +62 -0
- data/test/TestConfig.rb +21 -0
- data/test/TestSetup.rb +13 -0
- data/test/TestUtil.rb +92 -0
- data/test/Transaction.test.rb +275 -0
- data/test/Translate.test.rb +354 -0
- data/test/Update.test.rb +227 -0
- data/test/roundtrip.test.rb +565 -0
- data/test/test +34 -0
- data/tools/exampleinserter/ExampleInserter.rb +177 -0
- data/tools/rdoc/ChangeLog +796 -0
- data/tools/rdoc/EXAMPLE.rb +48 -0
- data/tools/rdoc/MANIFEST +58 -0
- data/tools/rdoc/Makefile +27 -0
- data/tools/rdoc/NEW_FEATURES +226 -0
- data/tools/rdoc/README +390 -0
- data/tools/rdoc/ToDo +6 -0
- data/tools/rdoc/contrib/Index +6 -0
- data/tools/rdoc/contrib/xslfo/ChangeLog +181 -0
- data/tools/rdoc/contrib/xslfo/README +106 -0
- data/tools/rdoc/contrib/xslfo/TODO +10 -0
- data/tools/rdoc/contrib/xslfo/convert.xsl +151 -0
- data/tools/rdoc/contrib/xslfo/demo/README +21 -0
- data/tools/rdoc/contrib/xslfo/demo/rdocfo +99 -0
- data/tools/rdoc/contrib/xslfo/fcm.xsl +54 -0
- data/tools/rdoc/contrib/xslfo/files.xsl +62 -0
- data/tools/rdoc/contrib/xslfo/labeled-lists.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/lists.xsl +44 -0
- data/tools/rdoc/contrib/xslfo/modules.xsl +152 -0
- data/tools/rdoc/contrib/xslfo/rdoc.xsl +75 -0
- data/tools/rdoc/contrib/xslfo/source.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/styles.xsl +69 -0
- data/tools/rdoc/contrib/xslfo/tables.xsl +67 -0
- data/tools/rdoc/contrib/xslfo/utils.xsl +21 -0
- data/tools/rdoc/debian/changelog +33 -0
- data/tools/rdoc/debian/compat +1 -0
- data/tools/rdoc/debian/control +20 -0
- data/tools/rdoc/debian/copyright +10 -0
- data/tools/rdoc/debian/dirs +2 -0
- data/tools/rdoc/debian/docs +2 -0
- data/tools/rdoc/debian/rdoc.1 +252 -0
- data/tools/rdoc/debian/rdoc.manpages +1 -0
- data/tools/rdoc/debian/rdoc.pod +149 -0
- data/tools/rdoc/debian/rules +9 -0
- data/tools/rdoc/dot/dot.rb +255 -0
- data/tools/rdoc/etc/rdoc.dtd +203 -0
- data/tools/rdoc/install.rb +137 -0
- data/tools/rdoc/markup/install.rb +43 -0
- data/tools/rdoc/markup/sample/sample.rb +42 -0
- data/tools/rdoc/markup/simple_markup/fragments.rb +323 -0
- data/tools/rdoc/markup/simple_markup/inline.rb +348 -0
- data/tools/rdoc/markup/simple_markup/lines.rb +147 -0
- data/tools/rdoc/markup/simple_markup/preprocess.rb +68 -0
- data/tools/rdoc/markup/simple_markup/to_html.rb +281 -0
- data/tools/rdoc/markup/simple_markup.rb +474 -0
- data/tools/rdoc/markup/test/AllTests.rb +2 -0
- data/tools/rdoc/markup/test/TestInline.rb +151 -0
- data/tools/rdoc/markup/test/TestParse.rb +411 -0
- data/tools/rdoc/rdoc/code_objects.rb +536 -0
- data/tools/rdoc/rdoc/diagram.rb +331 -0
- data/tools/rdoc/rdoc/generators/chm_generator.rb +112 -0
- data/tools/rdoc/rdoc/generators/html_generator.rb +1268 -0
- data/tools/rdoc/rdoc/generators/template/chm/chm.rb +86 -0
- data/tools/rdoc/rdoc/generators/template/html/html.rb +705 -0
- data/tools/rdoc/rdoc/generators/template/html/kilmer.rb +377 -0
- data/tools/rdoc/rdoc/generators/template/xml/rdf.rb +110 -0
- data/tools/rdoc/rdoc/generators/template/xml/xml.rb +110 -0
- data/tools/rdoc/rdoc/generators/xml_generator.rb +130 -0
- data/tools/rdoc/rdoc/options.rb +451 -0
- data/tools/rdoc/rdoc/parsers/parse_c.rb +287 -0
- data/tools/rdoc/rdoc/parsers/parse_f95.rb +118 -0
- data/tools/rdoc/rdoc/parsers/parse_rb.rb +2311 -0
- data/tools/rdoc/rdoc/parsers/parse_simple.rb +37 -0
- data/tools/rdoc/rdoc/parsers/parserfactory.rb +75 -0
- data/tools/rdoc/rdoc/rdoc.rb +219 -0
- data/tools/rdoc/rdoc/template.rb +234 -0
- data/tools/rdoc/rdoc/tokenstream.rb +25 -0
- data/tools/rdoc/rdoc.rb +9 -0
- metadata +291 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
module SM
|
|
2
|
+
|
|
3
|
+
# We manage a set of attributes. Each attribute has a symbol name
|
|
4
|
+
# and a bit value
|
|
5
|
+
|
|
6
|
+
class Attribute
|
|
7
|
+
SPECIAL = 1
|
|
8
|
+
|
|
9
|
+
@@name_to_bitmap = { :_SPECIAL_ => SPECIAL }
|
|
10
|
+
@@next_bitmap = 2
|
|
11
|
+
|
|
12
|
+
def Attribute.bitmap_for(name)
|
|
13
|
+
bitmap = @@name_to_bitmap[name]
|
|
14
|
+
if !bitmap
|
|
15
|
+
bitmap = @@next_bitmap
|
|
16
|
+
@@next_bitmap <<= 1
|
|
17
|
+
@@name_to_bitmap[name] = bitmap
|
|
18
|
+
end
|
|
19
|
+
bitmap
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def Attribute.as_string(bitmap)
|
|
23
|
+
return "none" if bitmap.zero?
|
|
24
|
+
res = []
|
|
25
|
+
@@name_to_bitmap.each do |name, bit|
|
|
26
|
+
res << name if (bitmap & bit) != 0
|
|
27
|
+
end
|
|
28
|
+
res.join(",")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def Attribute.each_name_of(bitmap)
|
|
32
|
+
@@name_to_bitmap.each do |name, bit|
|
|
33
|
+
next if bit == SPECIAL
|
|
34
|
+
yield name.to_s if (bitmap & bit) != 0
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# An AttrChanger records a change in attributes. It contains
|
|
41
|
+
# a bitmap of the attributes to turn on, and a bitmap of those to
|
|
42
|
+
# turn off
|
|
43
|
+
|
|
44
|
+
AttrChanger = Struct.new(:turn_on, :turn_off)
|
|
45
|
+
class AttrChanger
|
|
46
|
+
def to_s
|
|
47
|
+
"Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# An array of attributes which parallels the characters in a string
|
|
52
|
+
class AttrSpan
|
|
53
|
+
def initialize(length)
|
|
54
|
+
@attrs = Array.new(length, 0)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def set_attrs(start, length, bits)
|
|
58
|
+
for i in start ... (start+length)
|
|
59
|
+
@attrs[i] |= bits
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def [](n)
|
|
64
|
+
@attrs[n]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Hold details of a special sequence
|
|
70
|
+
|
|
71
|
+
class Special
|
|
72
|
+
attr_reader :type
|
|
73
|
+
attr_accessor :text
|
|
74
|
+
|
|
75
|
+
def initialize(type, text)
|
|
76
|
+
@type, @text = type, text
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def ==(o)
|
|
80
|
+
self.text == o.text && self.type == o.type
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def to_s
|
|
84
|
+
"Special: type=#{type}, text=#{text.dump}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class AttributeManager
|
|
89
|
+
|
|
90
|
+
NULL = "\000".freeze
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# We work by substituting non-printing characters in to the
|
|
94
|
+
# text. For now I'm assuming that I can substitute
|
|
95
|
+
# a character in the range 0..8 for a 7 bit character
|
|
96
|
+
# without damaging the encoded string, but this might
|
|
97
|
+
# be optimistic
|
|
98
|
+
#
|
|
99
|
+
|
|
100
|
+
=begin
|
|
101
|
+
ATTR_FLAG = 001
|
|
102
|
+
A_START = 002
|
|
103
|
+
A_END = 003
|
|
104
|
+
A_SPECIAL_START = 005
|
|
105
|
+
A_SPECIAL_END = 006
|
|
106
|
+
|
|
107
|
+
START_ATTR = ATTR_FLAG.chr + A_START.chr
|
|
108
|
+
END_ATTR = ATTR_FLAG.chr + A_END.chr
|
|
109
|
+
|
|
110
|
+
START_SPECIAL = ATTR_FLAG.chr + A_SPECIAL_START.chr
|
|
111
|
+
END_SPECIAL = ATTR_FLAG.chr + A_SPECIAL_END.chr
|
|
112
|
+
|
|
113
|
+
=end
|
|
114
|
+
A_PROTECT = 004
|
|
115
|
+
PROTECT_ATTR = A_PROTECT.chr
|
|
116
|
+
|
|
117
|
+
# This maps delimiters that occur around words (such as
|
|
118
|
+
# *bold* or +tt+) where the start and end delimiters
|
|
119
|
+
# and the same. This lets us optimize the regexp
|
|
120
|
+
MATCHING_WORD_PAIRS = {}
|
|
121
|
+
|
|
122
|
+
# And this is used when the delimiters aren't the same. In this
|
|
123
|
+
# case the hash maps a pattern to the attribute character
|
|
124
|
+
WORD_PAIR_MAP = {}
|
|
125
|
+
|
|
126
|
+
# This maps HTML tags to the corresponding attribute char
|
|
127
|
+
HTML_TAGS = {}
|
|
128
|
+
|
|
129
|
+
# And this maps _special_ sequences to a name. A special sequence
|
|
130
|
+
# is something like a WikiWord
|
|
131
|
+
SPECIAL = {}
|
|
132
|
+
|
|
133
|
+
# Return an attribute object with the given turn_on
|
|
134
|
+
# and turn_off bits set
|
|
135
|
+
|
|
136
|
+
def attribute(turn_on, turn_off)
|
|
137
|
+
AttrChanger.new(turn_on, turn_off)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def change_attribute(current, new)
|
|
142
|
+
diff = current ^ new
|
|
143
|
+
attribute(new & diff, current & diff)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def changed_attribute_by_name(current_set, new_set)
|
|
147
|
+
current = new = 0
|
|
148
|
+
current_set.each {|name| current |= Attribute.bitmap_for(name) }
|
|
149
|
+
new_set.each {|name| new |= Attribute.bitmap_for(name) }
|
|
150
|
+
change_attribute(current, new)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def copy_string(start_pos, end_pos)
|
|
154
|
+
res = @str[start_pos...end_pos]
|
|
155
|
+
res.gsub!(/\000/, '')
|
|
156
|
+
res
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Map attributes like <b>text</b>to the sequence \001\002<char>\001\003<char>,
|
|
160
|
+
# where <char> is a per-attribute specific character
|
|
161
|
+
|
|
162
|
+
def convert_attrs(str, attrs)
|
|
163
|
+
# first do matching ones
|
|
164
|
+
tags = MATCHING_WORD_PAIRS.keys.join("")
|
|
165
|
+
re = "(^|\\W)([#{tags}])([A-Za-z_]+?)\\2(\\W|\$)"
|
|
166
|
+
# re = "(^|\\W)([#{tags}])(\\S+?)\\2(\\W|\$)"
|
|
167
|
+
1 while str.gsub!(Regexp.new(re)) {
|
|
168
|
+
attr = MATCHING_WORD_PAIRS[$2];
|
|
169
|
+
attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
|
|
170
|
+
$1 + NULL*$2.length + $3 + NULL*$2.length + $4
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# then non-matching
|
|
174
|
+
unless WORD_PAIR_MAP.empty?
|
|
175
|
+
WORD_PAIR_MAP.each do |regexp, attr|
|
|
176
|
+
str.gsub!(regexp) {
|
|
177
|
+
attrs.set_attrs($`.length + $1.length, $2.length, attr)
|
|
178
|
+
NULL*$1.length + $2 + NULL*$3.length
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def convert_html(str, attrs)
|
|
185
|
+
tags = HTML_TAGS.keys.join("|")
|
|
186
|
+
re = "<(#{tags})>(.*?)</\\1>"
|
|
187
|
+
1 while str.gsub!(Regexp.new(re, Regexp::IGNORECASE)) {
|
|
188
|
+
attr = HTML_TAGS[$1.downcase]
|
|
189
|
+
html_length = $1.length + 2
|
|
190
|
+
seq = NULL * html_length
|
|
191
|
+
attrs.set_attrs($`.length + html_length, $2.length, attr)
|
|
192
|
+
seq + $2 + seq + NULL
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def convert_specials(str, attrs)
|
|
197
|
+
unless SPECIAL.empty?
|
|
198
|
+
SPECIAL.each do |regexp, attr|
|
|
199
|
+
str.scan(regexp) do
|
|
200
|
+
attrs.set_attrs($`.length, $1.length, attr | Attribute::SPECIAL)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# A \ in front of a character that would normally be
|
|
207
|
+
# processed turns off processing. We do this by turning
|
|
208
|
+
# \< into <#{PROTECT}
|
|
209
|
+
|
|
210
|
+
PROTECTABLE = [ "<" << "\\" ] #"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def mask_protected_sequences
|
|
214
|
+
protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])")
|
|
215
|
+
@str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def unmask_protected_sequences
|
|
219
|
+
@str.gsub!(/(.)#{PROTECT_ATTR}/, '\1')
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def initialize
|
|
223
|
+
add_word_pair("*", "*", :BOLD)
|
|
224
|
+
add_word_pair("_", "_", :EM)
|
|
225
|
+
add_word_pair("+", "+", :TT)
|
|
226
|
+
|
|
227
|
+
add_html("em", :EM)
|
|
228
|
+
add_html("i", :EM)
|
|
229
|
+
add_html("b", :BOLD)
|
|
230
|
+
add_html("tt", :TT)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def add_word_pair(start, stop, name)
|
|
234
|
+
raise "Word flags may not start '<'" if start[0] == ?<
|
|
235
|
+
bitmap = Attribute.bitmap_for(name)
|
|
236
|
+
if start == stop
|
|
237
|
+
MATCHING_WORD_PAIRS[start] = bitmap
|
|
238
|
+
else
|
|
239
|
+
pattern = Regexp.new("(" + Regexp.escape(start) + ")" +
|
|
240
|
+
# "([A-Za-z]+)" +
|
|
241
|
+
"(\\S+)" +
|
|
242
|
+
"(" + Regexp.escape(stop) +")")
|
|
243
|
+
WORD_PAIR_MAP[pattern] = bitmap
|
|
244
|
+
end
|
|
245
|
+
PROTECTABLE << start[0,1]
|
|
246
|
+
PROTECTABLE.uniq!
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def add_html(tag, name)
|
|
250
|
+
HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def add_special(pattern, name)
|
|
254
|
+
SPECIAL[pattern] = Attribute.bitmap_for(name)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def flow(str)
|
|
258
|
+
@str = str
|
|
259
|
+
@attrs = AttrSpan.new(str.length)
|
|
260
|
+
|
|
261
|
+
puts("Before flow, str='#{@str.dump}'") if $DEBUG
|
|
262
|
+
mask_protected_sequences
|
|
263
|
+
convert_attrs(@str, @attrs)
|
|
264
|
+
convert_html(@str, @attrs)
|
|
265
|
+
convert_specials(str, @attrs)
|
|
266
|
+
unmask_protected_sequences
|
|
267
|
+
puts("After flow, str='#{@str.dump}'") if $DEBUG
|
|
268
|
+
return split_into_flow
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def display_attributes
|
|
272
|
+
puts
|
|
273
|
+
puts @str.tr(NULL, "!")
|
|
274
|
+
bit = 1
|
|
275
|
+
16.times do |bno|
|
|
276
|
+
line = ""
|
|
277
|
+
@str.length.times do |i|
|
|
278
|
+
if (@attrs[i] & bit) == 0
|
|
279
|
+
line << " "
|
|
280
|
+
else
|
|
281
|
+
if bno.zero?
|
|
282
|
+
line << "S"
|
|
283
|
+
else
|
|
284
|
+
line << ("%d" % (bno+1))
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
puts(line) unless line =~ /^ *$/
|
|
289
|
+
bit <<= 1
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def split_into_flow
|
|
294
|
+
|
|
295
|
+
display_attributes if $DEBUG
|
|
296
|
+
|
|
297
|
+
res = []
|
|
298
|
+
current_attr = 0
|
|
299
|
+
str = ""
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
str_len = @str.length
|
|
303
|
+
|
|
304
|
+
# skip leading invisible text
|
|
305
|
+
i = 0
|
|
306
|
+
i += 1 while i < str_len and @str[i].zero?
|
|
307
|
+
start_pos = i
|
|
308
|
+
|
|
309
|
+
# then scan the string, chunking it on attribute changes
|
|
310
|
+
while i < str_len
|
|
311
|
+
new_attr = @attrs[i]
|
|
312
|
+
if new_attr != current_attr
|
|
313
|
+
if i > start_pos
|
|
314
|
+
res << copy_string(start_pos, i)
|
|
315
|
+
start_pos = i
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
res << change_attribute(current_attr, new_attr)
|
|
319
|
+
current_attr = new_attr
|
|
320
|
+
|
|
321
|
+
if (current_attr & Attribute::SPECIAL) != 0
|
|
322
|
+
i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0
|
|
323
|
+
res << Special.new(current_attr, copy_string(start_pos, i))
|
|
324
|
+
start_pos = i
|
|
325
|
+
next
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# move on, skipping any invisible characters
|
|
330
|
+
begin
|
|
331
|
+
i += 1
|
|
332
|
+
end while i < str_len and @str[i].zero?
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# tidy up trailing text
|
|
336
|
+
if start_pos < str_len
|
|
337
|
+
res << copy_string(start_pos, str_len)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# and reset to all attributes off
|
|
341
|
+
res << change_attribute(current_attr, 0) if current_attr != 0
|
|
342
|
+
|
|
343
|
+
return res
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
##########################################################################
|
|
2
|
+
#
|
|
3
|
+
# We store the lines we're working on as objects of class Line.
|
|
4
|
+
# These contain the text of the line, along with a flag indicating the
|
|
5
|
+
# line type, and an indentation level
|
|
6
|
+
|
|
7
|
+
module SM
|
|
8
|
+
|
|
9
|
+
class Line
|
|
10
|
+
INFINITY = 9999
|
|
11
|
+
|
|
12
|
+
BLANK = :BLANK
|
|
13
|
+
HEADING = :HEADING
|
|
14
|
+
LIST = :LIST
|
|
15
|
+
RULE = :RULE
|
|
16
|
+
PARAGRAPH = :PARAGRAPH
|
|
17
|
+
VERBATIM = :VERBATIM
|
|
18
|
+
|
|
19
|
+
# line type
|
|
20
|
+
attr_accessor :type
|
|
21
|
+
|
|
22
|
+
# The indentation nesting level
|
|
23
|
+
attr_accessor :level
|
|
24
|
+
|
|
25
|
+
# The contents
|
|
26
|
+
attr_accessor :text
|
|
27
|
+
|
|
28
|
+
# A prefix or parameter. For LIST lines, this is
|
|
29
|
+
# the text that introduced the list item (the label)
|
|
30
|
+
attr_accessor :param
|
|
31
|
+
|
|
32
|
+
# A flag. For list lines, this is the type of the list
|
|
33
|
+
attr_accessor :flag
|
|
34
|
+
|
|
35
|
+
# the number of leading spaces
|
|
36
|
+
attr_accessor :leading_spaces
|
|
37
|
+
|
|
38
|
+
# true if this line has been deleted from the list of lines
|
|
39
|
+
attr_accessor :deleted
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def initialize(text)
|
|
43
|
+
@text = text.dup
|
|
44
|
+
@deleted = false
|
|
45
|
+
|
|
46
|
+
# expand tabs
|
|
47
|
+
1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #`
|
|
48
|
+
|
|
49
|
+
# Strip trailing whitespace
|
|
50
|
+
@text.sub!(/\s+$/, '')
|
|
51
|
+
|
|
52
|
+
# and look for leading whitespace
|
|
53
|
+
if @text.length > 0
|
|
54
|
+
@text =~ /^(\s*)/
|
|
55
|
+
@leading_spaces = $1.length
|
|
56
|
+
else
|
|
57
|
+
@leading_spaces = INFINITY
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Return true if this line is blank
|
|
62
|
+
def isBlank?
|
|
63
|
+
@text.length.zero?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# stamp a line with a type, a level, a prefix, and a flag
|
|
67
|
+
def stamp(type, level, param="", flag=nil)
|
|
68
|
+
@type, @level, @param, @flag = type, level, param, flag
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Strip off the leading margin
|
|
73
|
+
#
|
|
74
|
+
|
|
75
|
+
def strip_leading(size)
|
|
76
|
+
@text[0,size] = ""
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def to_s
|
|
80
|
+
"#@type#@level: #@text"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
###############################################################################
|
|
85
|
+
#
|
|
86
|
+
# A container for all the lines
|
|
87
|
+
#
|
|
88
|
+
|
|
89
|
+
class Lines
|
|
90
|
+
include Enumerable
|
|
91
|
+
|
|
92
|
+
attr_reader :lines # for debugging
|
|
93
|
+
|
|
94
|
+
def initialize(lines)
|
|
95
|
+
@lines = lines
|
|
96
|
+
rewind
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def empty?
|
|
100
|
+
@lines.size.zero?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def each
|
|
104
|
+
@lines.each do |line|
|
|
105
|
+
yield line unless line.deleted
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# def [](index)
|
|
110
|
+
# @lines[index]
|
|
111
|
+
# end
|
|
112
|
+
|
|
113
|
+
def rewind
|
|
114
|
+
@nextline = 0
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def next
|
|
118
|
+
begin
|
|
119
|
+
res = @lines[@nextline]
|
|
120
|
+
@nextline += 1 if @nextline < @lines.size
|
|
121
|
+
end while res and res.deleted and @nextline < @lines.size
|
|
122
|
+
res
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def unget
|
|
126
|
+
@nextline -= 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def delete(a_line)
|
|
130
|
+
a_line.deleted = true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def normalize
|
|
134
|
+
margin = @lines.collect{|l| l.leading_spaces}.min
|
|
135
|
+
margin = 0 if margin == Line::INFINITY
|
|
136
|
+
@lines.each {|line| line.strip_leading(margin) } if margin > 0
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def as_text
|
|
140
|
+
@lines.map {|l| l.text}.join("\n")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def line_types
|
|
144
|
+
@lines.map {|l| l.type }
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module SM
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Handle common directives that can occur in a block of text:
|
|
5
|
+
#
|
|
6
|
+
# : include : filename
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
class PreProcess
|
|
10
|
+
|
|
11
|
+
def initialize(input_file_name, include_path)
|
|
12
|
+
@input_file_name = input_file_name
|
|
13
|
+
@include_path = include_path
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Look for common options in a chunk of text. Options that
|
|
17
|
+
# we don't handle are passed back to our caller
|
|
18
|
+
# as |directive, param|
|
|
19
|
+
|
|
20
|
+
def handle(text)
|
|
21
|
+
text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
|
|
22
|
+
|
|
23
|
+
directive = $2.downcase
|
|
24
|
+
param = $3
|
|
25
|
+
|
|
26
|
+
case directive
|
|
27
|
+
|
|
28
|
+
when "include"
|
|
29
|
+
include_file($3, $1)
|
|
30
|
+
|
|
31
|
+
else
|
|
32
|
+
yield(directive, param)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#######
|
|
38
|
+
private
|
|
39
|
+
#######
|
|
40
|
+
|
|
41
|
+
# Include a file, indenting it correctly
|
|
42
|
+
|
|
43
|
+
def include_file(name, indent)
|
|
44
|
+
if (full_name = find_include_file(name))
|
|
45
|
+
content = File.open(full_name) {|f| f.read}
|
|
46
|
+
res = content.gsub(/^#?/, indent)
|
|
47
|
+
else
|
|
48
|
+
$stderr.puts "Couldn't find file to include: '#{name}'"
|
|
49
|
+
''
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Look for the given file in the directory containing the current
|
|
54
|
+
# file, and then in each of the directories specified in the
|
|
55
|
+
# RDOC_INCLUDE path
|
|
56
|
+
|
|
57
|
+
def find_include_file(name)
|
|
58
|
+
to_search = [ File.dirname(@input_file_name) ].concat @include_path
|
|
59
|
+
to_search.each do |dir|
|
|
60
|
+
full_name = File.join(dir, name)
|
|
61
|
+
stat = File.stat(full_name) rescue next
|
|
62
|
+
return full_name if stat.readable?
|
|
63
|
+
end
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|