panmind-rtf 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,14 @@
1
+ == Purpose of this fork
2
+
3
+ * Add support for ordered and unordered lists [done]
4
+ * Write comprehensive tests for OL and UL [TODO]
5
+ * Clean up the API [TODO]
6
+ * DRY the code [TODO]
7
+
8
+ Please, please, please: if you come along this library and would lend me an
9
+ hand to complete tests, please help. Thank you!
10
+
11
+
1
12
  == Ruby Rich Text Format (RTF) Library
2
13
  The RTF library provides a pure Ruby set of functionality that can be used to
3
14
  programmatically create RTF documents. The main aim in developing this library
@@ -58,8 +69,6 @@ you are already familiar with the Ruby language. So, for a start, consider...
58
69
  require 'rubygems'
59
70
  require 'rtf'
60
71
 
61
- include RTF
62
-
63
72
  The first thing to look at here at the are the first two lines. The RTF library
64
73
  is provided as a Ruby gem and these two lines load the libraries functionality
65
74
  into the script. The third line of code includes the RTF module into the current
@@ -67,7 +76,7 @@ name space. This is a convenience mechanism that saves on specifically having
67
76
  to refer to the module when accessing the RTF library. Next we want to create
68
77
  an RTF document and that is done like this...
69
78
 
70
- document = Document.new(Font.new(Font::ROMAN, 'Times New Roman'))
79
+ document = RTF::Document.new(RTF::Font.new(RTF::Font::ROMAN, 'Times New Roman'))
71
80
 
72
81
  This line of code creates a new Document object, specifying that the default
73
82
  font for the document will the the Times New Roman font. So we have a document,
@@ -93,74 +102,69 @@ some code into the document. We want the code to appear in the document slightly
93
102
  indented on the left hand side, in a non-proportionately space font and we want
94
103
  it in bold text. Heres the code that shows how to do that...
95
104
 
96
- 01 styles = {}
97
- 02 styles['PS_CODE'] = ParagraphStyle.new
98
- 03 styles['CS_CODE'] = CharacterStyle.new
99
- 04
100
- 05 styles['PS_CODE'].left_indent = 200
101
- 06 styles['CS_CODE'].font = Font.new(Font::MODERN, 'Courier')
102
- 07 styles['CS_CODE'].bold = true
103
- 08
104
- 09 document.paragraph(styles['PS_CODE']) do |n1|
105
- 10 n1.apply(styles['CS_CODE']) do |n2|
106
- 11 n2 << "count = 0"
107
- 12 n2.line_break
108
- 13 n2 << "File.open('file.txt', 'r') do |file|"
109
- 14 n2.line_break
110
- 15 n2 << " file.each_line {|line| count += 1}"
111
- 16 n2.line_break
112
- 17 n2 << "end"
113
- 18 n2.line_break
114
- 19 n2 << "puts \"File contains \#{count} lines.\""
115
- 20 end
116
- 21 end
105
+ 01 code_para = ParagraphStyle.new
106
+ 02 code_para.left_indent = 200
107
+ 03
108
+ 04 code_char = CharacterStyle.new
109
+ 05 code_char.font = RTF::Font::MODERN
110
+ 06 code_char.bold = true
111
+ 07
112
+ 08 document.paragraph(code_para) do |p|
113
+ 09 p.apply(code_char) do |c|
114
+ 10 c << "count = 0"
115
+ 11 c.line_break
116
+ 12 c << "File.open('file.txt', 'r') do |file|"
117
+ 13 c.line_break
118
+ 14 c << " file.each_line {|line| count += 1}"
119
+ 15 c.line_break
120
+ 16 c << "end"
121
+ 17 c.line_break
122
+ 18 c << "puts \"File contains \#{count} lines.\""
123
+ 19 end
124
+ 20 end
117
125
 
118
126
  This is a much larger piece of code and covers a number of topics that need to
119
127
  be addressed. I have included line numbers with code so that individual elements
120
- can be referenced. Lines 1 to 3 are the first new elements. Here we create a
121
- Hash and assign it to a variable called styles. On the next two lines we create
128
+ can be referenced. Lines 1 to 6 are the first new elements. Here we create
122
129
  two style objects, one that can be applied to paragraphs and one that applies
123
130
  to characters.
124
131
 
125
- On lines 5 to 7 we update settings on the style objects we've created. We set
126
- the left indentation value of the paragraph style to 200. The 200 in this case
127
- refers to a measurement of twips. A twip is a type setting measurement that
128
- equates to one twentieth of a point (about a fifty seventh of a millimetre or
129
- one seventy second of an inch). This is the measurement scale used by RTF
130
- documents so it is also employed in the library.
132
+ On line 2 we set the left indentation value of the paragraph style to 200 *twips*.
133
+ A twip is a type setting measurement that equates to one twentieth of a point
134
+ (about a fifty seventh of a millimetre or one seventy second of an inch). This is
135
+ the measurement scale used by RTF documents.
136
+
137
+ On lines 5 and 6 we update the character style to use a courier font and to
138
+ apply bold styling to the text.
131
139
 
132
- On lines 6 and 7 we update the character style to use a courier font and to
133
- apply bold styling to the text. On line 9 we start a new paragraph in our
134
- document. This differs from our previous use of this method in that we specify
135
- a style that will be applied to the paragraph created, the paragraph style we
136
- had prepared earlier.
140
+ On line 8 we start a new paragraph in our document. This differs from our previous
141
+ use of this method in that we specify a style that will be applied to the paragraph
142
+ using the one we prepared earlier.
137
143
 
138
144
  The block accompanying the paragraph method takes the single parameter that we
139
145
  have seen previously. At this point its probably a good idea to point out that
140
146
  the elements that make up an RTF document created with the library are all
141
- stored as nodes in a tree. We've named the one passed to the paragraph method as
142
- n1 to reflect this.
147
+ stored as nodes in a tree.
148
+
149
+ Within the block, the +apply+ method applies a character style, and we're using
150
+ the one we prepared earlier.
143
151
 
144
- Within the block we've called a method on the paragraph node called apply. This
145
- method applies a character style and we're using the one we prepared earlier.
146
152
  Like the call to the paragraph method, the apply method is passed a block. All
147
- text added to the blocks node (n2 in this case) will have the styling we've
148
- defined (bold courier font) applied to it.
153
+ text added to the blocks node will have the styling we've defined (bold courier
154
+ font) applied to it.
149
155
 
150
- Note, that within the apply block we could still use the n1 node. Any text we
151
- added to this would appear in the paragraph but wouldn't be styled and, it
152
- should be noted, will appear before any text added to n2 (as the n2 node only
153
- becomes part of the document when the apply block completes).
156
+ Note, that within the apply block we could still use the previous (p) node. Any
157
+ text we added to this would appear in the paragraph but wouldn't be styled and,
158
+ it should be noted, will appear before any text added to c, as the c node only
159
+ becomes part of the document when the apply block completes.
154
160
 
155
- Within the apply method block we add some lines of text to the n2 node. Note
161
+ Within the apply method block we add some lines of text to the c node. Note
156
162
  that, as this is all encompassed within the parapgraph block, all the text is
157
163
  part of a single paragraph. To get each of the lines of code to appear on a
158
164
  line of their own we have used the line_break method which inserts a carriage
159
165
  return into the document. Note you should use this method to insert line breaks
160
166
  rather than trying to add a string containing "\n". RTF is a text based standard
161
- and won't treat "\n" as you're expecting. You should note also that we've had to
162
- escape the '#' in one of the code lines to stop Ruby considering it as an
163
- interpolated value.
167
+ and won't treat "\n" as you're expecting.
164
168
 
165
169
  Okay, so we've seen have the basics of creating a document and adding elements
166
170
  to that document. How do we get what we've created to a file. Well thats
@@ -183,4 +187,4 @@ Chris O'Sullivan
183
187
  COPYRIGHT
184
188
  =========
185
189
 
186
- Copyright (c) 2009-2010 Peter Wood. See LICENSE for details.
190
+ Copyright (c) 2009-2010 Peter Wood. See LICENSE for details.
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 3
4
- :patch: 1
3
+ :minor: 4
4
+ :patch: 0
5
5
  :build:
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.
@@ -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
@@ -212,6 +212,9 @@ module RTF
212
212
  # be written to separate lines whether the node is converted
213
213
  # to RTF. Defaults to true
214
214
  attr_accessor :split
215
+ # A boolean to indicate whether the prefix and suffix should
216
+ # be wrapped in curly braces. Defaults to true.
217
+ attr_accessor :wrap
215
218
 
216
219
  # This is the constructor for the CommandNode class.
217
220
  #
@@ -223,11 +226,14 @@ module RTF
223
226
  # split:: A boolean to indicate whether the prefix and suffix should
224
227
  # be written to separate lines whether the node is converted
225
228
  # to RTF. Defaults to true.
226
- def initialize(parent, prefix, suffix=nil, split=true)
229
+ # wrap:: A boolean to indicate whether the prefix and suffix should
230
+ # be wrapped in curly braces. Defaults to true.
231
+ def initialize(parent, prefix, suffix=nil, split=true, wrap=true)
227
232
  super(parent)
228
233
  @prefix = prefix
229
234
  @suffix = suffix
230
235
  @split = split
236
+ @wrap = wrap
231
237
  end
232
238
 
233
239
  # This method adds text to a command node. If the last child node of the
@@ -246,19 +252,20 @@ module RTF
246
252
 
247
253
  # This method generates the RTF text for a CommandNode object.
248
254
  def to_rtf
249
- text = StringIO.new
250
- separator = split? ? "\n" : " "
251
- line = (separator == " ")
255
+ text = StringIO.new
256
+
257
+ text << '{' if wrap?
258
+ text << @prefix if @prefix
252
259
 
253
- text << "{#{@prefix}"
254
- text << separator if self.size > 0
255
260
  self.each do |entry|
256
- text << "\n" if line
257
- line = true
258
- text << "#{entry.to_rtf}"
261
+ text << "\n" if split?
262
+ text << entry.to_rtf
259
263
  end
260
- text << "\n" if split?
261
- text << "#{@suffix}}"
264
+
265
+ text << "\n" if split?
266
+ text << @suffix if @suffix
267
+ text << '}' if wrap?
268
+
262
269
  text.string
263
270
  end
264
271
 
@@ -273,16 +280,43 @@ module RTF
273
280
  # for the new paragraph. Defaults to nil to indicate that the
274
281
  # currently applied paragraph styling should be used.
275
282
  def paragraph(style=nil)
276
- # Create the node prefix.
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')
283
+ node = ParagraphNode.new(self, style)
282
284
  yield node if block_given?
283
285
  self.store(node)
284
286
  end
285
287
 
288
+ # This method provides a short cut means of creating a new ordered or
289
+ # unordered list. The method requires a block that will be passed a
290
+ # single parameter that'll be a reference to the first level of the
291
+ # list. See the +ListLevelNode+ doc for more information.
292
+ #
293
+ # Example usage:
294
+ #
295
+ # rtf.list do |level1|
296
+ # level1.item do |li|
297
+ # li << 'some text'
298
+ # li.apply(some_style) {|x| x << 'some styled text'}
299
+ # end
300
+ #
301
+ # level1.list(:decimal) do |level2|
302
+ # level2.item {|li| li << 'some other text in a decimal list'}
303
+ # level2.item {|li| li << 'and here we go'}
304
+ # end
305
+ # end
306
+ #
307
+ def list(kind=:bullets)
308
+ node = ListNode.new(self)
309
+ yield node.list(kind)
310
+ self.store(node)
311
+ end
312
+
313
+ def link(url, text=nil)
314
+ node = LinkNode.new(self, url)
315
+ node << text if text
316
+ yield node if block_given?
317
+ self.store(node)
318
+ end
319
+
286
320
  # This method provides a short cut means of creating a line break command
287
321
  # node. This command node does not take a block and may possess no other
288
322
  # content.
@@ -424,6 +458,21 @@ module RTF
424
458
  end
425
459
  end
426
460
 
461
+ # This method provides a short cut means of creating a strike command
462
+ # node. The method accepts a block that will be passed a single parameter
463
+ # which will be a reference to the strike node created. After the
464
+ # block is complete the strike node is appended to the end of the
465
+ # child nodes on the object that the method is call against.
466
+ def strike
467
+ style = CharacterStyle.new
468
+ style.strike = true
469
+ if block_given?
470
+ apply(style) {|node| yield node}
471
+ else
472
+ apply(style)
473
+ end
474
+ end
475
+
427
476
  # This method provides a short cut means of creating a font command node.
428
477
  # The method accepts a block that will be passed a single parameter which
429
478
  # will be a reference to the font node created. After the block is
@@ -526,11 +575,123 @@ module RTF
526
575
  node
527
576
  end
528
577
 
529
- alias :write :<<
530
- alias :color :colour
578
+ alias :write :<<
579
+ alias :color :colour
531
580
  alias :split? :split
581
+ alias :wrap? :wrap
532
582
  end # End of the CommandNode class.
533
583
 
584
+ # This class represents a paragraph within an RTF document.
585
+ class ParagraphNode < CommandNode
586
+ def initialize(parent, style=nil)
587
+ prefix = '\pard'
588
+ prefix << style.prefix(nil, nil) if style
589
+
590
+ super(parent, prefix, '\par')
591
+ end
592
+ end
593
+
594
+ # This class represents an ordered/unordered list within an RTF document.
595
+ #
596
+ # Currently list nodes can contain any type of node, but this behaviour
597
+ # will change in future releases. The class overrides the +list+ method
598
+ # to return a +ListLevelNode+.
599
+ #
600
+ class ListNode < CommandNode
601
+ def initialize(parent)
602
+ prefix = "\\"
603
+
604
+ suffix = '\pard'
605
+ suffix << ListLevel::ResetTabs.map {|tw| "\\tx#{tw}"}.join
606
+ suffix << '\ql\qlnatural\pardirnatural\cf0 \\'
607
+
608
+ super(parent, prefix, suffix, true, false)
609
+
610
+ @template = root.lists.new_template
611
+ end
612
+
613
+ # This method creates a new +ListLevelNode+ of the given kind and
614
+ # stores it in the document tree.
615
+ #
616
+ # ==== Parameters
617
+ # kind:: The kind of this list level, may be either :bullets or :decimal
618
+ def list(kind)
619
+ self.store ListLevelNode.new(self, @template, kind)
620
+ end
621
+ end
622
+
623
+ # This class represents a list level, and carries out indenting information
624
+ # and the bullet or number that is prepended to each +ListTextNode+.
625
+ #
626
+ # The class overrides the +list+ method to implement nesting, and provides
627
+ # the +item+ method to add a new list item, the +ListTextNode+.
628
+ class ListLevelNode < CommandNode
629
+ def initialize(parent, template, kind, level=1)
630
+ @template = template
631
+ @kind = kind
632
+ @level = template.level_for(level, kind)
633
+
634
+ prefix = '\pard'
635
+ prefix << @level.tabs.map {|tw| "\\tx#{tw}"}.join
636
+ prefix << "\\li#{@level.indent}\\fi-#{@level.indent}"
637
+ prefix << "\\ql\\qlnatural\\pardirnatural\n"
638
+ prefix << "\\ls#{@template.id}\\ilvl#{@level.level-1}\\cf0"
639
+
640
+ super(parent, prefix, nil, true, false)
641
+ end
642
+
643
+ # Returns the kind of this level, either :bullets or :decimal
644
+ attr_reader :kind
645
+
646
+ # Returns the indenting level of this list, from 1 to 9
647
+ def level
648
+ @level.level
649
+ end
650
+
651
+ # Creates a new +ListTextNode+ and yields it to the calling block
652
+ def item
653
+ node = ListTextNode.new(self, @level)
654
+ yield node
655
+ self.store(node)
656
+ end
657
+
658
+ # Creates a new +ListLevelNode+ to implement nested lists
659
+ def list(kind=@kind)
660
+ node = ListLevelNode.new(self, @template, kind, @level.level+1)
661
+ yield node
662
+ self.store(node)
663
+ end
664
+ end
665
+
666
+ # This class represents a list item, that can contain text or
667
+ # other nodes. Currently any type of node is accepted, but after
668
+ # more extensive testing this behaviour may change.
669
+ class ListTextNode < CommandNode
670
+ def initialize(parent, level)
671
+ @level = level
672
+ @parent = parent
673
+
674
+ number = siblings_count + 1 if parent.kind == :decimal
675
+ prefix = "{\\listtext#{@level.marker.text_format(number)}}"
676
+ suffix = '\\'
677
+
678
+ super(parent, prefix, suffix, false, false)
679
+ end
680
+
681
+ private
682
+ def siblings_count
683
+ parent.children.select {|n| n.kind_of?(self.class)}.size
684
+ end
685
+ end
686
+
687
+ class LinkNode < CommandNode
688
+ def initialize(parent, url)
689
+ prefix = "\\field{\\*\\fldinst HYPERLINK \"#{url}\"}{\\fldrslt "
690
+ suffix = "}"
691
+
692
+ super(parent, prefix, suffix, false)
693
+ end
694
+ end
534
695
 
535
696
  # This class represents a table node within an RTF document. Table nodes are
536
697
  # specialised container nodes that contain only TableRowNodes and have their
@@ -936,19 +1097,8 @@ module RTF
936
1097
  # ComamndNode class to forbid the creation of paragraphs.
937
1098
  #
938
1099
  # ==== Parameters
939
- # justification:: The justification to be applied to the paragraph.
940
- # before:: The amount of space, in twips, to be inserted before
941
- # the paragraph. Defaults to nil.
942
- # after:: The amount of space, in twips, to be inserted after
943
- # the paragraph. Defaults to nil.
944
- # left:: The amount of indentation to place on the left of the
945
- # paragraph. Defaults to nil.
946
- # right:: The amount of indentation to place on the right of the
947
- # paragraph. Defaults to nil.
948
- # first:: The amount of indentation to place on the left of the
949
- # first line in the paragraph. Defaults to nil.
950
- def paragraph(justification=CommandNode::LEFT_JUSTIFY, before=nil,
951
- after=nil, left=nil, right=nil, first=nil)
1100
+ # style:: The paragraph style, ignored
1101
+ def paragraph(style=nil)
952
1102
  RTFError.fire("TableCellNode#paragraph() called. Table cells cannot "\
953
1103
  "contain paragraphs.")
954
1104
  end
@@ -1481,8 +1631,8 @@ module RTF
1481
1631
  LC_VIETNAMESE = 1066
1482
1632
 
1483
1633
  # Attribute accessor.
1484
- attr_reader :fonts, :colours, :information, :character_set, :language,
1485
- :style
1634
+ attr_reader :fonts, :lists, :colours, :information, :character_set,
1635
+ :language, :style
1486
1636
 
1487
1637
  # Attribute mutator.
1488
1638
  attr_writer :character_set, :language
@@ -1501,6 +1651,7 @@ module RTF
1501
1651
  def initialize(font, style=nil, character=CS_ANSI, language=LC_ENGLISH_UK)
1502
1652
  super(nil, '\rtf1')
1503
1653
  @fonts = FontTable.new(font)
1654
+ @lists = ListTable.new
1504
1655
  @default_font = 0
1505
1656
  @colours = ColourTable.new
1506
1657
  @information = Information.new
@@ -1654,6 +1805,7 @@ module RTF
1654
1805
  text << "\n#{@fonts.to_rtf}"
1655
1806
  text << "\n#{@colours.to_rtf}" if @colours.size > 0
1656
1807
  text << "\n#{@information.to_rtf}"
1808
+ text << "\n#{@lists.to_rtf}"
1657
1809
  if @headers.compact != []
1658
1810
  text << "\n#{@headers[3].to_rtf}" if @headers[3] != nil
1659
1811
  text << "\n#{@headers[2].to_rtf}" if @headers[2] != nil
@@ -302,4 +302,4 @@ module RTF
302
302
  end
303
303
  end
304
304
  end # End of the DocumentStyle class.
305
- end # End of the RTF module.
305
+ end # End of the RTF module.
@@ -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 == CommandNode)
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)
@@ -161,6 +161,11 @@ class CommandNodeTest < Test::Unit::TestCase
161
161
  assert(node.prefix == '\sub')
162
162
  assert(node.suffix == nil)
163
163
  assert(node == root[-1])
164
+
165
+ node = root.strike
166
+ assert(node.prefix == '\strike')
167
+ assert(node.suffix == nil)
168
+ assert(node == root[-1])
164
169
  end
165
170
 
166
171
  # Test text node addition.
@@ -202,6 +207,32 @@ class CommandNodeTest < Test::Unit::TestCase
202
207
  assert(table[0][2].width == 200)
203
208
  end
204
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
+
205
236
  # This test checks the previous_node and next_node methods that could not be
206
237
  # fully and properly checked in the NodeTest.rb file.
207
238
  def test_peers
@@ -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
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 1
9
- version: 0.3.1
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Peter Wood
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-09-14 00:00:00 +02:00
17
+ date: 2010-09-15 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -26,11 +26,11 @@ extensions: []
26
26
 
27
27
  extra_rdoc_files:
28
28
  - LICENSE
29
- - README
29
+ - README.rdoc
30
30
  files:
31
31
  - CHANGES
32
32
  - LICENSE
33
- - README
33
+ - README.rdoc
34
34
  - Rakefile
35
35
  - VERSION.yml
36
36
  - examples/example01.rb
@@ -45,6 +45,7 @@ files:
45
45
  - lib/rtf/colour.rb
46
46
  - lib/rtf/font.rb
47
47
  - lib/rtf/information.rb
48
+ - lib/rtf/list.rb
48
49
  - lib/rtf/node.rb
49
50
  - lib/rtf/paper.rb
50
51
  - lib/rtf/style.rb