clbustos-rtf 0.3.1 → 0.4.2
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/CHANGES +16 -1
- data/README.rdoc +13 -1
- data/Rakefile +1 -1
- data/VERSION.yml +2 -2
- data/lib/rtf.rb +2 -1
- data/lib/rtf/list.rb +219 -0
- data/lib/rtf/node.rb +173 -34
- data/test/character_style_test.rb +1 -1
- data/test/colour_table_test.rb +1 -1
- data/test/colour_test.rb +1 -1
- data/test/command_node_test.rb +28 -2
- data/test/container_node_test.rb +1 -1
- data/test/document_style_test.rb +1 -1
- data/test/document_test.rb +1 -1
- data/test/font_table_test.rb +1 -1
- data/test/font_test.rb +1 -1
- data/test/footer_node_test.rb +1 -1
- data/test/header_node_test.rb +1 -1
- data/test/image_node_test.rb +1 -1
- data/test/information_test.rb +2 -2
- data/test/node_test.rb +1 -1
- data/test/paragraph_style_test.rb +1 -1
- data/test/style_test.rb +1 -1
- data/test/table_cell_node_test.rb +1 -1
- data/test/table_node_test.rb +1 -1
- data/test/table_row_node_test.rb +1 -1
- data/test/text_node_test.rb +1 -1
- metadata +33 -27
data/CHANGES
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
== CHANGES
|
2
|
-
|
2
|
+
0.4.2
|
3
|
+
* Fix bug causing TextNode.to_rtf to return nil under 1.8.7[Jason Langenauer]
|
4
|
+
* Tests run under Ruby 1.9.2 and later [clbustos]
|
5
|
+
0.4.1
|
6
|
+
* Links: implemented hyperlinks[Marcello Barnaba]
|
7
|
+
* Lists: add a newline before every new list[Marcello Barnaba]
|
8
|
+
0.4.0
|
9
|
+
* Lists: Decimal: quick&dirty implementation of sequential numbering[Marcello Barnaba]
|
10
|
+
* Lists: Decimal: fixed marker name generation: it must contain the dot[Marcello Barnaba]
|
11
|
+
* Lists: removed last StringIO occurrences in new code[Marcello Barnaba]
|
12
|
+
* Lists: wrote minimal object model test[Marcello Barnaba]
|
13
|
+
* Lists: refactored and cleaned up the API a bit[Marcello Barnaba]
|
14
|
+
* Lists: wrote the API bridge between Nodes and Lists[Marcello Barnaba]
|
15
|
+
* Lists: initial implementation of listtable header generation[Marcello Barnaba]
|
16
|
+
* Node: cleaned up the generic to_rtf, added the .wrap option to the constructor[Marcello Barnaba]
|
17
|
+
* Node: stubbed out paragraph generation into a new ParagraphNode[Marcello Barnaba]
|
3
18
|
0.3.1
|
4
19
|
* Added the #subscript helper to the CommandNode class [vjt]
|
5
20
|
|
data/README.rdoc
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
== Purpose of this fork
|
2
|
+
|
3
|
+
* [DONE] Add support for ordered and unordered lists
|
4
|
+
* [DONE] Add support for hyperlinks
|
5
|
+
* [TODO] Write comprehensive tests for OL and UL
|
6
|
+
* [TODO] Clean up the API
|
7
|
+
* [TODO] DRY the code
|
8
|
+
|
9
|
+
Please, please, please: if you come along this library and would lend me an
|
10
|
+
hand to complete tests, please help. Thank you!
|
11
|
+
|
12
|
+
|
1
13
|
== Ruby Rich Text Format (RTF) Library
|
2
14
|
The RTF library provides a pure Ruby set of functionality that can be used to
|
3
15
|
programmatically create RTF documents. The main aim in developing this library
|
@@ -65,7 +77,7 @@ name space. This is a convenience mechanism that saves on specifically having
|
|
65
77
|
to refer to the module when accessing the RTF library. Next we want to create
|
66
78
|
an RTF document and that is done like this...
|
67
79
|
|
68
|
-
document = RTF::Document.new(RTF::Font::ROMAN)
|
80
|
+
document = RTF::Document.new(RTF::Font.new(RTF::Font::ROMAN, 'Times New Roman'))
|
69
81
|
|
70
82
|
This line of code creates a new Document object, specifying that the default
|
71
83
|
font for the document will the the Times New Roman font. So we have a document,
|
data/Rakefile
CHANGED
data/VERSION.yml
CHANGED
data/lib/rtf.rb
CHANGED
@@ -7,6 +7,7 @@ require 'rtf/style'
|
|
7
7
|
require 'rtf/information'
|
8
8
|
require 'rtf/paper'
|
9
9
|
require 'rtf/node'
|
10
|
+
require 'rtf/list'
|
10
11
|
|
11
12
|
# This module encapsulates all the classes and definitions relating to the RTF
|
12
13
|
# library.
|
@@ -31,4 +32,4 @@ module RTF
|
|
31
32
|
raise RTFError.new(message)
|
32
33
|
end
|
33
34
|
end # End of the RTFError class.
|
34
|
-
end # End of the RTF module.
|
35
|
+
end # End of the RTF module.
|
data/lib/rtf/list.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
module RTF
|
2
|
+
class ListTable
|
3
|
+
def initialize
|
4
|
+
@templates = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def new_template
|
8
|
+
@templates.push ListTemplate.new(next_template_id)
|
9
|
+
@templates.last
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_rtf(indent=0)
|
13
|
+
return '' if @templates.empty?
|
14
|
+
|
15
|
+
prefix = indent > 0 ? ' ' * indent : ''
|
16
|
+
|
17
|
+
# List table
|
18
|
+
text = "#{prefix}{\\*\\listtable"
|
19
|
+
@templates.each {|tpl| text << tpl.to_rtf}
|
20
|
+
text << "}"
|
21
|
+
|
22
|
+
# List override table, a Cargo Cult.
|
23
|
+
text << "#{prefix}{\\*\\listoverridetable"
|
24
|
+
@templates.each do |tpl|
|
25
|
+
text << "{\\listoverride\\listid#{tpl.id}\\listoverridecount0\\ls#{tpl.id}}"
|
26
|
+
end
|
27
|
+
text << "}\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
def next_template_id
|
32
|
+
@templates.size + 1
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class ListMarker
|
38
|
+
def initialize(name, codepoint=nil)
|
39
|
+
@name = name
|
40
|
+
@codepoint = codepoint
|
41
|
+
end
|
42
|
+
|
43
|
+
def bullet?
|
44
|
+
!@codepoint.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def type
|
48
|
+
bullet? ? :bullet : :decimal
|
49
|
+
end
|
50
|
+
|
51
|
+
def number_type
|
52
|
+
# 23: bullet, 0: arabic
|
53
|
+
# applies to the \levelnfcN macro
|
54
|
+
#
|
55
|
+
bullet? ? 23 : 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def name
|
59
|
+
name = "\\{#@name\\}"
|
60
|
+
name << '.' unless bullet?
|
61
|
+
name
|
62
|
+
end
|
63
|
+
|
64
|
+
def template_format
|
65
|
+
# The first char is the string size, the next ones are
|
66
|
+
# either placeholders (\'0X) or actual characters to
|
67
|
+
# include in the format. In the bullet case, \uc0 is
|
68
|
+
# used to get rid of the multibyte translation: we want
|
69
|
+
# an Unicode character.
|
70
|
+
#
|
71
|
+
# In the decimal case, we have a fixed format, with a
|
72
|
+
# dot following the actual number.
|
73
|
+
#
|
74
|
+
if bullet?
|
75
|
+
"\\'01\\uc0\\u#@codepoint"
|
76
|
+
else
|
77
|
+
"\\'02\\'00. "
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def text_format(n=nil)
|
82
|
+
text =
|
83
|
+
if bullet?
|
84
|
+
"\\uc0\\u#@codepoint"
|
85
|
+
else
|
86
|
+
"#{n}."
|
87
|
+
end
|
88
|
+
|
89
|
+
"\t#{text}\t"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ListTemplate
|
94
|
+
attr_reader :id
|
95
|
+
|
96
|
+
Markers = {
|
97
|
+
:disc => ListMarker.new('disc', 0x2022),
|
98
|
+
:hyphen => ListMarker.new('hyphen', 0x2043),
|
99
|
+
:decimal => ListMarker.new('decimal' )
|
100
|
+
}
|
101
|
+
|
102
|
+
def initialize(id)
|
103
|
+
@levels = []
|
104
|
+
@id = id
|
105
|
+
end
|
106
|
+
|
107
|
+
def level_for(level, kind = :bullets)
|
108
|
+
@levels[level-1] ||= begin
|
109
|
+
# Only disc for now: we'll add support
|
110
|
+
# for more customization options later
|
111
|
+
marker = Markers[kind == :bullets ? :disc : :decimal]
|
112
|
+
ListLevel.new(self, marker, level)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_rtf(indent=0)
|
117
|
+
prefix = indent > 0 ? ' ' * indent : ''
|
118
|
+
|
119
|
+
text = "#{prefix}{\\list\\listtemplate#{id}\\listhybrid"
|
120
|
+
@levels.each {|lvl| text << lvl.to_rtf}
|
121
|
+
text << "{\\listname;}\\listid#{id}}\n"
|
122
|
+
|
123
|
+
text
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class ListLevel
|
128
|
+
ValidLevels = (1..9)
|
129
|
+
|
130
|
+
LevelTabs = [
|
131
|
+
220, 720, 1133, 1700, 2267,
|
132
|
+
2834, 3401, 3968, 4535, 5102,
|
133
|
+
5669, 6236, 6803
|
134
|
+
].freeze
|
135
|
+
|
136
|
+
ResetTabs = [560].concat(LevelTabs[2..-1]).freeze
|
137
|
+
|
138
|
+
attr_reader :level, :marker
|
139
|
+
|
140
|
+
def initialize(template, marker, level)
|
141
|
+
unless marker.kind_of? ListMarker
|
142
|
+
RTFError.fire("Invalid marker #{marker.inspect}")
|
143
|
+
end
|
144
|
+
|
145
|
+
unless ValidLevels.include? level
|
146
|
+
RTFError.fire("Invalid list level: #{level}")
|
147
|
+
end
|
148
|
+
|
149
|
+
@template = template
|
150
|
+
@level = level
|
151
|
+
@marker = marker
|
152
|
+
end
|
153
|
+
|
154
|
+
def type
|
155
|
+
@marker.type
|
156
|
+
end
|
157
|
+
|
158
|
+
def reset_tabs
|
159
|
+
ResetTabs
|
160
|
+
end
|
161
|
+
|
162
|
+
def tabs
|
163
|
+
@tabs ||= begin
|
164
|
+
tabs = LevelTabs.dup # Kernel#tap would be prettier here
|
165
|
+
|
166
|
+
(@level - 1).times do
|
167
|
+
# Reverse-engineered while looking at Textedit.app
|
168
|
+
# generated output: they already made sure that it
|
169
|
+
# would look good on every RTF editor :-p
|
170
|
+
#
|
171
|
+
a, = tabs.shift(3)
|
172
|
+
a,b = a + 720, a + 1220
|
173
|
+
tabs.shift while tabs.first < b
|
174
|
+
tabs.unshift a, b
|
175
|
+
end
|
176
|
+
|
177
|
+
tabs
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def id
|
182
|
+
@id ||= @template.id * 10 + level
|
183
|
+
end
|
184
|
+
|
185
|
+
def indent
|
186
|
+
@indent ||= level * 720
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_rtf(indent=0)
|
190
|
+
prefix = indent > 0 ? ' ' * indent : ''
|
191
|
+
|
192
|
+
text = "#{prefix}{\\listlevel\\levelstartat1"
|
193
|
+
|
194
|
+
# Marker type. The first declaration is for Backward Compatibility (BC).
|
195
|
+
nfc = @marker.number_type
|
196
|
+
text << "\\levelnfc#{nfc}\\levelnfcn#{nfc}"
|
197
|
+
|
198
|
+
# Justification, currently only left justified (0). First decl for BC.
|
199
|
+
text << '\leveljc0\leveljcn0'
|
200
|
+
|
201
|
+
# Character that follows the level text, currently only TAB.
|
202
|
+
text << '\levelfollow0'
|
203
|
+
|
204
|
+
# BC: Minimum distance from the left & right edges.
|
205
|
+
text << '\levelindent0\levelspace360'
|
206
|
+
|
207
|
+
# Marker name
|
208
|
+
text << "{\\*\\levelmarker #{@marker.name}}"
|
209
|
+
|
210
|
+
# Marker text format
|
211
|
+
text << "{\\leveltext\\leveltemplateid#{id}#{@marker.template_format};}"
|
212
|
+
text << '{\levelnumbers;}'
|
213
|
+
|
214
|
+
# The actual spacing
|
215
|
+
text << "\\fi-360\\li#{self.indent}\\lin#{self.indent}}\n"
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
end
|
data/lib/rtf/node.rb
CHANGED
@@ -120,6 +120,8 @@ module RTF
|
|
120
120
|
rtf.encode("UTF-16LE").each_codepoint.map {|cp|
|
121
121
|
cp < 128 ? cp.chr : "\\u#{cp}\\'3f"
|
122
122
|
}.join("")
|
123
|
+
else
|
124
|
+
rtf
|
123
125
|
end
|
124
126
|
end
|
125
127
|
end # End of the TextNode class.
|
@@ -212,6 +214,9 @@ module RTF
|
|
212
214
|
# be written to separate lines whether the node is converted
|
213
215
|
# to RTF. Defaults to true
|
214
216
|
attr_accessor :split
|
217
|
+
# A boolean to indicate whether the prefix and suffix should
|
218
|
+
# be wrapped in curly braces. Defaults to true.
|
219
|
+
attr_accessor :wrap
|
215
220
|
|
216
221
|
# This is the constructor for the CommandNode class.
|
217
222
|
#
|
@@ -223,11 +228,14 @@ module RTF
|
|
223
228
|
# split:: A boolean to indicate whether the prefix and suffix should
|
224
229
|
# be written to separate lines whether the node is converted
|
225
230
|
# to RTF. Defaults to true.
|
226
|
-
|
231
|
+
# wrap:: A boolean to indicate whether the prefix and suffix should
|
232
|
+
# be wrapped in curly braces. Defaults to true.
|
233
|
+
def initialize(parent, prefix, suffix=nil, split=true, wrap=true)
|
227
234
|
super(parent)
|
228
235
|
@prefix = prefix
|
229
236
|
@suffix = suffix
|
230
237
|
@split = split
|
238
|
+
@wrap = wrap
|
231
239
|
end
|
232
240
|
|
233
241
|
# This method adds text to a command node. If the last child node of the
|
@@ -246,19 +254,20 @@ module RTF
|
|
246
254
|
|
247
255
|
# This method generates the RTF text for a CommandNode object.
|
248
256
|
def to_rtf
|
249
|
-
text
|
250
|
-
|
251
|
-
|
257
|
+
text = StringIO.new
|
258
|
+
|
259
|
+
text << '{' if wrap?
|
260
|
+
text << @prefix if @prefix
|
252
261
|
|
253
|
-
text << "{#{@prefix}"
|
254
|
-
text << separator if self.size > 0
|
255
262
|
self.each do |entry|
|
256
|
-
text << "\n" if
|
257
|
-
|
258
|
-
text << "#{entry.to_rtf}"
|
263
|
+
text << "\n" if split?
|
264
|
+
text << entry.to_rtf
|
259
265
|
end
|
260
|
-
|
261
|
-
text << "
|
266
|
+
|
267
|
+
text << "\n" if split?
|
268
|
+
text << @suffix if @suffix
|
269
|
+
text << '}' if wrap?
|
270
|
+
|
262
271
|
text.string
|
263
272
|
end
|
264
273
|
|
@@ -273,16 +282,43 @@ module RTF
|
|
273
282
|
# for the new paragraph. Defaults to nil to indicate that the
|
274
283
|
# currently applied paragraph styling should be used.
|
275
284
|
def paragraph(style=nil)
|
276
|
-
|
277
|
-
text = StringIO.new
|
278
|
-
text << '\pard'
|
279
|
-
text << style.prefix(nil, nil) if style != nil
|
280
|
-
|
281
|
-
node = CommandNode.new(self, text.string, '\par')
|
285
|
+
node = ParagraphNode.new(self, style)
|
282
286
|
yield node if block_given?
|
283
287
|
self.store(node)
|
284
288
|
end
|
285
289
|
|
290
|
+
# This method provides a short cut means of creating a new ordered or
|
291
|
+
# unordered list. The method requires a block that will be passed a
|
292
|
+
# single parameter that'll be a reference to the first level of the
|
293
|
+
# list. See the +ListLevelNode+ doc for more information.
|
294
|
+
#
|
295
|
+
# Example usage:
|
296
|
+
#
|
297
|
+
# rtf.list do |level1|
|
298
|
+
# level1.item do |li|
|
299
|
+
# li << 'some text'
|
300
|
+
# li.apply(some_style) {|x| x << 'some styled text'}
|
301
|
+
# end
|
302
|
+
#
|
303
|
+
# level1.list(:decimal) do |level2|
|
304
|
+
# level2.item {|li| li << 'some other text in a decimal list'}
|
305
|
+
# level2.item {|li| li << 'and here we go'}
|
306
|
+
# end
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
def list(kind=:bullets)
|
310
|
+
node = ListNode.new(self)
|
311
|
+
yield node.list(kind)
|
312
|
+
self.store(node)
|
313
|
+
end
|
314
|
+
|
315
|
+
def link(url, text=nil)
|
316
|
+
node = LinkNode.new(self, url)
|
317
|
+
node << text if text
|
318
|
+
yield node if block_given?
|
319
|
+
self.store(node)
|
320
|
+
end
|
321
|
+
|
286
322
|
# This method provides a short cut means of creating a line break command
|
287
323
|
# node. This command node does not take a block and may possess no other
|
288
324
|
# content.
|
@@ -541,11 +577,123 @@ module RTF
|
|
541
577
|
node
|
542
578
|
end
|
543
579
|
|
544
|
-
alias :write
|
545
|
-
alias :color
|
580
|
+
alias :write :<<
|
581
|
+
alias :color :colour
|
546
582
|
alias :split? :split
|
583
|
+
alias :wrap? :wrap
|
547
584
|
end # End of the CommandNode class.
|
548
585
|
|
586
|
+
# This class represents a paragraph within an RTF document.
|
587
|
+
class ParagraphNode < CommandNode
|
588
|
+
def initialize(parent, style=nil)
|
589
|
+
prefix = '\pard'
|
590
|
+
prefix << style.prefix(nil, nil) if style
|
591
|
+
|
592
|
+
super(parent, prefix, '\par')
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
# This class represents an ordered/unordered list within an RTF document.
|
597
|
+
#
|
598
|
+
# Currently list nodes can contain any type of node, but this behaviour
|
599
|
+
# will change in future releases. The class overrides the +list+ method
|
600
|
+
# to return a +ListLevelNode+.
|
601
|
+
#
|
602
|
+
class ListNode < CommandNode
|
603
|
+
def initialize(parent)
|
604
|
+
prefix = "\\"
|
605
|
+
|
606
|
+
suffix = '\pard'
|
607
|
+
suffix << ListLevel::ResetTabs.map {|tw| "\\tx#{tw}"}.join
|
608
|
+
suffix << '\ql\qlnatural\pardirnatural\cf0 \\'
|
609
|
+
|
610
|
+
super(parent, prefix, suffix, true, false)
|
611
|
+
|
612
|
+
@template = root.lists.new_template
|
613
|
+
end
|
614
|
+
|
615
|
+
# This method creates a new +ListLevelNode+ of the given kind and
|
616
|
+
# stores it in the document tree.
|
617
|
+
#
|
618
|
+
# ==== Parameters
|
619
|
+
# kind:: The kind of this list level, may be either :bullets or :decimal
|
620
|
+
def list(kind)
|
621
|
+
self.store ListLevelNode.new(self, @template, kind)
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
# This class represents a list level, and carries out indenting information
|
626
|
+
# and the bullet or number that is prepended to each +ListTextNode+.
|
627
|
+
#
|
628
|
+
# The class overrides the +list+ method to implement nesting, and provides
|
629
|
+
# the +item+ method to add a new list item, the +ListTextNode+.
|
630
|
+
class ListLevelNode < CommandNode
|
631
|
+
def initialize(parent, template, kind, level=1)
|
632
|
+
@template = template
|
633
|
+
@kind = kind
|
634
|
+
@level = template.level_for(level, kind)
|
635
|
+
|
636
|
+
prefix = '\pard'
|
637
|
+
prefix << @level.tabs.map {|tw| "\\tx#{tw}"}.join
|
638
|
+
prefix << "\\li#{@level.indent}\\fi-#{@level.indent}"
|
639
|
+
prefix << "\\ql\\qlnatural\\pardirnatural\n"
|
640
|
+
prefix << "\\ls#{@template.id}\\ilvl#{@level.level-1}\\cf0"
|
641
|
+
|
642
|
+
super(parent, prefix, nil, true, false)
|
643
|
+
end
|
644
|
+
|
645
|
+
# Returns the kind of this level, either :bullets or :decimal
|
646
|
+
attr_reader :kind
|
647
|
+
|
648
|
+
# Returns the indenting level of this list, from 1 to 9
|
649
|
+
def level
|
650
|
+
@level.level
|
651
|
+
end
|
652
|
+
|
653
|
+
# Creates a new +ListTextNode+ and yields it to the calling block
|
654
|
+
def item
|
655
|
+
node = ListTextNode.new(self, @level)
|
656
|
+
yield node
|
657
|
+
self.store(node)
|
658
|
+
end
|
659
|
+
|
660
|
+
# Creates a new +ListLevelNode+ to implement nested lists
|
661
|
+
def list(kind=@kind)
|
662
|
+
node = ListLevelNode.new(self, @template, kind, @level.level+1)
|
663
|
+
yield node
|
664
|
+
self.store(node)
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
# This class represents a list item, that can contain text or
|
669
|
+
# other nodes. Currently any type of node is accepted, but after
|
670
|
+
# more extensive testing this behaviour may change.
|
671
|
+
class ListTextNode < CommandNode
|
672
|
+
def initialize(parent, level)
|
673
|
+
@level = level
|
674
|
+
@parent = parent
|
675
|
+
|
676
|
+
number = siblings_count + 1 if parent.kind == :decimal
|
677
|
+
prefix = "{\\listtext#{@level.marker.text_format(number)}}"
|
678
|
+
suffix = '\\'
|
679
|
+
|
680
|
+
super(parent, prefix, suffix, false, false)
|
681
|
+
end
|
682
|
+
|
683
|
+
private
|
684
|
+
def siblings_count
|
685
|
+
parent.children.select {|n| n.kind_of?(self.class)}.size
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
class LinkNode < CommandNode
|
690
|
+
def initialize(parent, url)
|
691
|
+
prefix = "\\field{\\*\\fldinst HYPERLINK \"#{url}\"}{\\fldrslt "
|
692
|
+
suffix = "}"
|
693
|
+
|
694
|
+
super(parent, prefix, suffix, false)
|
695
|
+
end
|
696
|
+
end
|
549
697
|
|
550
698
|
# This class represents a table node within an RTF document. Table nodes are
|
551
699
|
# specialised container nodes that contain only TableRowNodes and have their
|
@@ -951,19 +1099,8 @@ module RTF
|
|
951
1099
|
# ComamndNode class to forbid the creation of paragraphs.
|
952
1100
|
#
|
953
1101
|
# ==== Parameters
|
954
|
-
#
|
955
|
-
|
956
|
-
# the paragraph. Defaults to nil.
|
957
|
-
# after:: The amount of space, in twips, to be inserted after
|
958
|
-
# the paragraph. Defaults to nil.
|
959
|
-
# left:: The amount of indentation to place on the left of the
|
960
|
-
# paragraph. Defaults to nil.
|
961
|
-
# right:: The amount of indentation to place on the right of the
|
962
|
-
# paragraph. Defaults to nil.
|
963
|
-
# first:: The amount of indentation to place on the left of the
|
964
|
-
# first line in the paragraph. Defaults to nil.
|
965
|
-
def paragraph(justification=CommandNode::LEFT_JUSTIFY, before=nil,
|
966
|
-
after=nil, left=nil, right=nil, first=nil)
|
1102
|
+
# style:: The paragraph style, ignored
|
1103
|
+
def paragraph(style=nil)
|
967
1104
|
RTFError.fire("TableCellNode#paragraph() called. Table cells cannot "\
|
968
1105
|
"contain paragraphs.")
|
969
1106
|
end
|
@@ -1496,8 +1633,8 @@ module RTF
|
|
1496
1633
|
LC_VIETNAMESE = 1066
|
1497
1634
|
|
1498
1635
|
# Attribute accessor.
|
1499
|
-
attr_reader :fonts, :colours, :information, :character_set,
|
1500
|
-
:style
|
1636
|
+
attr_reader :fonts, :lists, :colours, :information, :character_set,
|
1637
|
+
:language, :style
|
1501
1638
|
|
1502
1639
|
# Attribute mutator.
|
1503
1640
|
attr_writer :character_set, :language
|
@@ -1516,6 +1653,7 @@ module RTF
|
|
1516
1653
|
def initialize(font, style=nil, character=CS_ANSI, language=LC_ENGLISH_UK)
|
1517
1654
|
super(nil, '\rtf1')
|
1518
1655
|
@fonts = FontTable.new(font)
|
1656
|
+
@lists = ListTable.new
|
1519
1657
|
@default_font = 0
|
1520
1658
|
@colours = ColourTable.new
|
1521
1659
|
@information = Information.new
|
@@ -1669,6 +1807,7 @@ module RTF
|
|
1669
1807
|
text << "\n#{@fonts.to_rtf}"
|
1670
1808
|
text << "\n#{@colours.to_rtf}" if @colours.size > 0
|
1671
1809
|
text << "\n#{@information.to_rtf}"
|
1810
|
+
text << "\n#{@lists.to_rtf}"
|
1672
1811
|
if @headers.compact != []
|
1673
1812
|
text << "\n#{@headers[3].to_rtf}" if @headers[3] != nil
|
1674
1813
|
text << "\n#{@headers[2].to_rtf}" if @headers[2] != nil
|
data/test/colour_table_test.rb
CHANGED
data/test/colour_test.rb
CHANGED
data/test/command_node_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'test_helper'
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+'/test_helper')
|
2
2
|
|
3
3
|
# Information class unit test class.
|
4
4
|
class CommandNodeTest < Test::Unit::TestCase
|
@@ -40,7 +40,7 @@ class CommandNodeTest < Test::Unit::TestCase
|
|
40
40
|
|
41
41
|
assert(root.paragraph(style) != nil)
|
42
42
|
assert(root.size == 1)
|
43
|
-
assert(root[0].class ==
|
43
|
+
assert(root[0].class == ParagraphNode)
|
44
44
|
assert(root[0].prefix == '\pard\ql')
|
45
45
|
assert(root[0].suffix == '\par')
|
46
46
|
assert(root.split == true)
|
@@ -207,6 +207,32 @@ class CommandNodeTest < Test::Unit::TestCase
|
|
207
207
|
assert(table[0][2].width == 200)
|
208
208
|
end
|
209
209
|
|
210
|
+
# List object model test
|
211
|
+
def test_list
|
212
|
+
root = Document.new(Font.new(Font::ROMAN, 'Arial'))
|
213
|
+
root.list do |l1|
|
214
|
+
assert l1.class == ListLevelNode
|
215
|
+
assert l1.level == 1
|
216
|
+
|
217
|
+
l1.item do |li|
|
218
|
+
assert li.class == ListTextNode
|
219
|
+
text = li << 'text'
|
220
|
+
assert text.class == TextNode
|
221
|
+
assert text.text == 'text'
|
222
|
+
end
|
223
|
+
|
224
|
+
l1.list do |l2|
|
225
|
+
assert l2.class == ListLevelNode
|
226
|
+
assert l2.level == 2
|
227
|
+
l2.item do |li|
|
228
|
+
text = li << 'text'
|
229
|
+
assert text.class == TextNode
|
230
|
+
assert text.text == 'text'
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
210
236
|
# This test checks the previous_node and next_node methods that could not be
|
211
237
|
# fully and properly checked in the NodeTest.rb file.
|
212
238
|
def test_peers
|
data/test/container_node_test.rb
CHANGED
data/test/document_style_test.rb
CHANGED
data/test/document_test.rb
CHANGED
data/test/font_table_test.rb
CHANGED
data/test/font_test.rb
CHANGED
data/test/footer_node_test.rb
CHANGED
data/test/header_node_test.rb
CHANGED
data/test/image_node_test.rb
CHANGED
data/test/information_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'test_helper'
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+'/test_helper')
|
2
2
|
|
3
3
|
# Information class unit test class.
|
4
4
|
class InformationTest < Test::Unit::TestCase
|
@@ -124,4 +124,4 @@ class InformationTest < Test::Unit::TestCase
|
|
124
124
|
text << "\\hr#{time.hour}\\min#{time.min}}"
|
125
125
|
text.string
|
126
126
|
end
|
127
|
-
end
|
127
|
+
end
|
data/test/node_test.rb
CHANGED
data/test/style_test.rb
CHANGED
data/test/table_node_test.rb
CHANGED
data/test/table_row_node_test.rb
CHANGED
data/test/text_node_test.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clbustos-rtf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 11
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Peter Wood
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-11-23 00:00:00 -03:00
|
18
19
|
default_executable:
|
19
20
|
dependencies: []
|
20
21
|
|
@@ -45,6 +46,7 @@ files:
|
|
45
46
|
- lib/rtf/colour.rb
|
46
47
|
- lib/rtf/font.rb
|
47
48
|
- lib/rtf/information.rb
|
49
|
+
- lib/rtf/list.rb
|
48
50
|
- lib/rtf/node.rb
|
49
51
|
- lib/rtf/paper.rb
|
50
52
|
- lib/rtf/style.rb
|
@@ -80,54 +82,58 @@ homepage: http://github.com/clbustos/rtf
|
|
80
82
|
licenses: []
|
81
83
|
|
82
84
|
post_install_message:
|
83
|
-
rdoc_options:
|
84
|
-
|
85
|
+
rdoc_options: []
|
86
|
+
|
85
87
|
require_paths:
|
86
88
|
- lib
|
87
89
|
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
88
91
|
requirements:
|
89
92
|
- - ">="
|
90
93
|
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
91
95
|
segments:
|
92
96
|
- 0
|
93
97
|
version: "0"
|
94
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
95
100
|
requirements:
|
96
101
|
- - ">="
|
97
102
|
- !ruby/object:Gem::Version
|
103
|
+
hash: 3
|
98
104
|
segments:
|
99
105
|
- 0
|
100
106
|
version: "0"
|
101
107
|
requirements: []
|
102
108
|
|
103
109
|
rubyforge_project: ruby-statsample
|
104
|
-
rubygems_version: 1.3.
|
110
|
+
rubygems_version: 1.3.7
|
105
111
|
signing_key:
|
106
112
|
specification_version: 3
|
107
113
|
summary: Ruby library to create rich text format documents.
|
108
114
|
test_files:
|
109
|
-
-
|
110
|
-
-
|
111
|
-
-
|
112
|
-
-
|
115
|
+
- examples/example01.rb
|
116
|
+
- examples/example02.rb
|
117
|
+
- examples/example03.rb
|
118
|
+
- examples/example04.rb
|
113
119
|
- test/character_style_test.rb
|
114
|
-
- test/paragraph_style_test.rb
|
115
|
-
- test/font_test.rb
|
116
|
-
- test/document_test.rb
|
117
|
-
- test/style_test.rb
|
118
|
-
- test/font_table_test.rb
|
119
|
-
- test/text_node_test.rb
|
120
|
-
- test/table_node_test.rb
|
121
120
|
- test/colour_table_test.rb
|
122
|
-
- test/
|
121
|
+
- test/colour_test.rb
|
122
|
+
- test/command_node_test.rb
|
123
|
+
- test/container_node_test.rb
|
123
124
|
- test/document_style_test.rb
|
124
|
-
- test/
|
125
|
+
- test/document_test.rb
|
126
|
+
- test/font_table_test.rb
|
127
|
+
- test/font_test.rb
|
125
128
|
- test/footer_node_test.rb
|
126
|
-
- test/table_row_node_test.rb
|
127
|
-
- test/colour_test.rb
|
128
129
|
- test/header_node_test.rb
|
129
|
-
- test/
|
130
|
-
-
|
131
|
-
-
|
132
|
-
-
|
133
|
-
-
|
130
|
+
- test/image_node_test.rb
|
131
|
+
- test/information_test.rb
|
132
|
+
- test/node_test.rb
|
133
|
+
- test/paragraph_style_test.rb
|
134
|
+
- test/style_test.rb
|
135
|
+
- test/table_cell_node_test.rb
|
136
|
+
- test/table_node_test.rb
|
137
|
+
- test/table_row_node_test.rb
|
138
|
+
- test/test_helper.rb
|
139
|
+
- test/text_node_test.rb
|