panmind-rtf 0.3.1

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 (48) hide show
  1. data/CHANGES +8 -0
  2. data/LICENSE +20 -0
  3. data/README +186 -0
  4. data/Rakefile +48 -0
  5. data/VERSION.yml +5 -0
  6. data/examples/example01.rb +51 -0
  7. data/examples/example02.rb +45 -0
  8. data/examples/example03.rb +66 -0
  9. data/examples/example03.rtf +164 -0
  10. data/examples/example04.rb +50 -0
  11. data/examples/rubyrtf.bmp +0 -0
  12. data/examples/rubyrtf.jpg +0 -0
  13. data/examples/rubyrtf.png +0 -0
  14. data/lib/rtf.rb +34 -0
  15. data/lib/rtf/colour.rb +173 -0
  16. data/lib/rtf/font.rb +173 -0
  17. data/lib/rtf/information.rb +111 -0
  18. data/lib/rtf/node.rb +1680 -0
  19. data/lib/rtf/paper.rb +55 -0
  20. data/lib/rtf/style.rb +305 -0
  21. data/test/character_style_test.rb +136 -0
  22. data/test/colour_table_test.rb +93 -0
  23. data/test/colour_test.rb +116 -0
  24. data/test/command_node_test.rb +219 -0
  25. data/test/container_node_test.rb +64 -0
  26. data/test/document_style_test.rb +79 -0
  27. data/test/document_test.rb +106 -0
  28. data/test/fixtures/bitmap1.bmp +0 -0
  29. data/test/fixtures/bitmap2.bmp +0 -0
  30. data/test/fixtures/jpeg1.jpg +0 -0
  31. data/test/fixtures/jpeg2.jpg +0 -0
  32. data/test/fixtures/png1.png +0 -0
  33. data/test/fixtures/png2.png +0 -0
  34. data/test/font_table_test.rb +91 -0
  35. data/test/font_test.rb +48 -0
  36. data/test/footer_node_test.rb +30 -0
  37. data/test/header_node_test.rb +30 -0
  38. data/test/image_node_test.rb +125 -0
  39. data/test/information_test.rb +127 -0
  40. data/test/node_test.rb +25 -0
  41. data/test/paragraph_style_test.rb +81 -0
  42. data/test/style_test.rb +16 -0
  43. data/test/table_cell_node_test.rb +89 -0
  44. data/test/table_node_test.rb +83 -0
  45. data/test/table_row_node_test.rb +59 -0
  46. data/test/test_helper.rb +13 -0
  47. data/test/text_node_test.rb +50 -0
  48. metadata +133 -0
data/lib/rtf/paper.rb ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module RTF
4
+ # This class represents a definition for a paper size and provides a set
5
+ # of class constants for common paper sizes. An instance of the Paper class
6
+ # is considered immutable after creation.
7
+ class Paper
8
+ # Attribute accessor.
9
+ attr_reader :name, :width, :height
10
+
11
+
12
+ # This is the constructor for the Paper class. All dimension parameters
13
+ # to this method are in twips.
14
+ #
15
+ # ==== Parameters
16
+ # name:: The name for the paper object.
17
+ # width:: The width of the paper in portrait mode.
18
+ # height:: The height of the paper in portrait mode.
19
+ def initialize(name, width, height)
20
+ @name = name
21
+ @width = width
22
+ @height = height
23
+ end
24
+
25
+ # Definition of an international paper constant.
26
+ A0 = Paper.new('A0', 47685, 67416)
27
+
28
+ # Definition of an international paper constant.
29
+ A1 = Paper.new('A1', 33680, 47685)
30
+
31
+ # Definition of an international paper constant.
32
+ A2 = Paper.new('A2', 23814, 33680)
33
+
34
+ # Definition of an international paper constant.
35
+ A3 = Paper.new('A3', 16840, 23814)
36
+
37
+ # Definition of an international paper constant.
38
+ A4 = Paper.new('A4', 11907, 16840)
39
+
40
+ # Definition of an international paper constant.
41
+ A5 = Paper.new('A5', 8392, 11907)
42
+
43
+ # Definition of a US paper constant.
44
+ LETTER = Paper.new('Letter', 12247, 15819)
45
+
46
+ # Definition of a US paper constant.
47
+ LEGAL = Paper.new('Legal', 12247, 20185)
48
+
49
+ # Definition of a US paper constant.
50
+ EXECUTIVE = Paper.new('Executive', 10773, 14402)
51
+
52
+ # Definition of a US paper constant.
53
+ LEDGER_TABLOID = Paper.new('Ledger/Tabloid', 15819, 24494)
54
+ end # End of the Paper class.
55
+ end # End of the RTF module.
data/lib/rtf/style.rb ADDED
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stringio'
4
+
5
+ module RTF
6
+ # This is a parent class that all style classes will derive from.
7
+ class Style
8
+ # A definition for a character flow setting.
9
+ LEFT_TO_RIGHT = :rtl
10
+
11
+ # A definition for a character flow setting.
12
+ RIGHT_TO_LEFT = :ltr
13
+
14
+ # This method retrieves the command prefix text associated with a Style
15
+ # object. This method always returns nil and should be overridden by
16
+ # derived classes as needed.
17
+ #
18
+ # ==== Parameters
19
+ # fonts:: A reference to the document fonts table. May be nil if no
20
+ # fonts are used.
21
+ # colours:: A reference to the document colour table. May be nil if no
22
+ # colours are used.
23
+ def prefix(fonts, colours)
24
+ nil
25
+ end
26
+
27
+ # This method retrieves the command suffix text associated with a Style
28
+ # object. This method always returns nil and should be overridden by
29
+ # derived classes as needed.
30
+ #
31
+ # ==== Parameters
32
+ # fonts:: A reference to the document fonts table. May be nil if no
33
+ # fonts are used.
34
+ # colours:: A reference to the document colour table. May be nil if no
35
+ # colours are used.
36
+ def suffix(fonts, colours)
37
+ nil
38
+ end
39
+
40
+ # Used to determine if the style applies to characters. This method always
41
+ # returns false and should be overridden by derived classes as needed.
42
+ def is_character_style?
43
+ false
44
+ end
45
+
46
+ # Used to determine if the style applies to paragraphs. This method always
47
+ # returns false and should be overridden by derived classes as needed.
48
+ def is_paragraph_style?
49
+ false
50
+ end
51
+
52
+ # Used to determine if the style applies to documents. This method always
53
+ # returns false and should be overridden by derived classes as needed.
54
+ def is_document_style?
55
+ false
56
+ end
57
+
58
+ # Used to determine if the style applies to tables. This method always
59
+ # returns false and should be overridden by derived classes as needed.
60
+ def is_table_style?
61
+ false
62
+ end
63
+ end # End of the style class.
64
+
65
+
66
+ # This class represents a character style for an RTF document.
67
+ class CharacterStyle < Style
68
+ # Attribute accessor.
69
+ attr_reader :bold, :italic, :underline, :superscript, :capitalise,
70
+ :strike, :subscript, :hidden, :foreground, :background,
71
+ :flow, :font, :font_size
72
+
73
+ # Attribute mutator.
74
+ attr_writer :bold, :italic, :underline, :superscript, :capitalise,
75
+ :strike, :subscript, :hidden, :foreground, :background,
76
+ :flow, :font, :font_size
77
+
78
+ # This is the constructor for the CharacterStyle class.
79
+ #
80
+ # ==== Exceptions
81
+ # RTFError:: Generate if the parent style specified is not an instance
82
+ # of the CharacterStyle class.
83
+ def initialize
84
+ @bold = false
85
+ @italic = false
86
+ @underline = false
87
+ @superscript = false
88
+ @capitalise = false
89
+ @strike = false
90
+ @subscript = false
91
+ @hidden = false
92
+ @foreground = nil
93
+ @background = nil
94
+ @font = nil
95
+ @font_size = nil
96
+ @flow = LEFT_TO_RIGHT
97
+ end
98
+
99
+ # This method overrides the is_character_style? method inherited from the
100
+ # Style class to always return true.
101
+ def is_character_style?
102
+ true
103
+ end
104
+
105
+ # This method generates a string containing the prefix associated with a
106
+ # style object.
107
+ #
108
+ # ==== Parameters
109
+ # fonts:: A reference to a FontTable containing any fonts used by the
110
+ # style (may be nil if no fonts used).
111
+ # colours:: A reference to a ColourTable containing any colours used by
112
+ # the style (may be nil if no colours used).
113
+ def prefix(fonts, colours)
114
+ text = StringIO.new
115
+
116
+ text << '\b' if @bold
117
+ text << '\i' if @italic
118
+ text << '\ul' if @underline
119
+ text << '\super' if @superscript
120
+ text << '\caps' if @capitalise
121
+ text << '\strike' if @strike
122
+ text << '\sub' if @subscript
123
+ text << '\v' if @hidden
124
+ text << "\\cf#{colours.index(@foreground)}" if @foreground != nil
125
+ text << "\\cb#{colours.index(@background)}" if @background != nil
126
+ text << "\\f#{fonts.index(@font)}" if @font != nil
127
+ text << "\\fs#{@font_size.to_i}" if @font_size != nil
128
+ text << '\rtlch' if @flow == RIGHT_TO_LEFT
129
+
130
+ text.string.length > 0 ? text.string : nil
131
+ end
132
+
133
+ alias :capitalize :capitalise
134
+ alias :capitalize= :capitalise=
135
+ end # End of the CharacterStyle class.
136
+
137
+
138
+ # This class represents a styling for a paragraph within an RTF document.
139
+ class ParagraphStyle < Style
140
+ # A definition for a paragraph justification setting.
141
+ LEFT_JUSTIFY = :ql
142
+
143
+ # A definition for a paragraph justification setting.
144
+ RIGHT_JUSTIFY = :qr
145
+
146
+ # A definition for a paragraph justification setting.
147
+ CENTER_JUSTIFY = :qc
148
+
149
+ # A definition for a paragraph justification setting.
150
+ CENTRE_JUSTIFY = :qc
151
+
152
+ # A definition for a paragraph justification setting.
153
+ FULL_JUSTIFY = :qj
154
+
155
+ # Attribute accessor.
156
+ attr_reader :justification, :left_indent, :right_indent,
157
+ :first_line_indent, :space_before, :space_after,
158
+ :line_spacing, :flow
159
+
160
+ # Attribute mutator.
161
+ attr_writer :justification, :left_indent, :right_indent,
162
+ :first_line_indent, :space_before, :space_after,
163
+ :line_spacing, :flow
164
+
165
+ # This is a constructor for the ParagraphStyle class.
166
+ #
167
+ # ==== Parameters
168
+ # base:: A reference to base object that the new style will inherit its
169
+ # initial properties from. Defaults to nil.
170
+ def initialize(base=nil)
171
+ @justification = base == nil ? LEFT_JUSTIFY : base.justification
172
+ @left_indent = base == nil ? nil : base.left_indent
173
+ @right_indent = base == nil ? nil : base.right_indent
174
+ @first_line_indent = base == nil ? nil : base.first_line_indent
175
+ @space_before = base == nil ? nil : base.space_before
176
+ @space_after = base == nil ? nil : base.space_after
177
+ @line_spacing = base == nil ? nil : base.line_spacing
178
+ @flow = base == nil ? LEFT_TO_RIGHT : base.flow
179
+ end
180
+
181
+ # This method overrides the is_paragraph_style? method inherited from the
182
+ # Style class to always return true.
183
+ def is_paragraph_style?
184
+ true
185
+ end
186
+
187
+ # This method generates a string containing the prefix associated with a
188
+ # style object.
189
+ #
190
+ # ==== Parameters
191
+ # fonts:: A reference to a FontTable containing any fonts used by the
192
+ # style (may be nil if no fonts used).
193
+ # colours:: A reference to a ColourTable containing any colours used by
194
+ # the style (may be nil if no colours used).
195
+ def prefix(fonts, colours)
196
+ text = StringIO.new
197
+
198
+ text << "\\#{@justification.id2name}"
199
+ text << "\\li#{@left_indent}" if @left_indent != nil
200
+ text << "\\ri#{@right_indent}" if @right_indent != nil
201
+ text << "\\fi#{@first_line_indent}" if @first_line_indent != nil
202
+ text << "\\sb#{@space_before}" if @space_before != nil
203
+ text << "\\sa#{@space_after}" if @space_after != nil
204
+ text << "\\sl#{@line_spacing}" if @line_spacing != nil
205
+ text << '\rtlpar' if @flow == RIGHT_TO_LEFT
206
+
207
+ text.string.length > 0 ? text.string : nil
208
+ end
209
+ end # End of the ParagraphStyle class.
210
+
211
+
212
+ # This class represents styling attributes that are to be applied at the
213
+ # document level.
214
+ class DocumentStyle < Style
215
+ # Definition for a document orientation setting.
216
+ PORTRAIT = :portrait
217
+
218
+ # Definition for a document orientation setting.
219
+ LANDSCAPE = :landscape
220
+
221
+ # Definition for a default margin setting.
222
+ DEFAULT_LEFT_MARGIN = 1800
223
+
224
+ # Definition for a default margin setting.
225
+ DEFAULT_RIGHT_MARGIN = 1800
226
+
227
+ # Definition for a default margin setting.
228
+ DEFAULT_TOP_MARGIN = 1440
229
+
230
+ # Definition for a default margin setting.
231
+ DEFAULT_BOTTOM_MARGIN = 1440
232
+
233
+ # Attribute accessor.
234
+ attr_reader :paper, :left_margin, :right_margin, :top_margin,
235
+ :bottom_margin, :gutter, :orientation
236
+
237
+ # Attribute mutator.
238
+ attr_writer :paper, :left_margin, :right_margin, :top_margin,
239
+ :bottom_margin, :gutter, :orientation
240
+
241
+ # This is a constructor for the DocumentStyle class. This creates a
242
+ # document style with a default paper setting of A4 and portrait
243
+ # orientation (all other attributes are nil).
244
+ def initialize
245
+ @paper = Paper::A4
246
+ @left_margin = DEFAULT_LEFT_MARGIN
247
+ @right_margin = DEFAULT_RIGHT_MARGIN
248
+ @top_margin = DEFAULT_TOP_MARGIN
249
+ @bottom_margin = DEFAULT_BOTTOM_MARGIN
250
+ @gutter = nil
251
+ @orientation = PORTRAIT
252
+ end
253
+
254
+ # This method overrides the is_document_style? method inherited from the
255
+ # Style class to always return true.
256
+ def is_document_style?
257
+ true
258
+ end
259
+
260
+ # This method generates a string containing the prefix associated with a
261
+ # style object.
262
+ #
263
+ # ==== Parameters
264
+ # document:: A reference to the document using the style.
265
+ def prefix(fonts=nil, colours=nil)
266
+ text = StringIO.new
267
+
268
+ if orientation == LANDSCAPE
269
+ text << "\\paperw#{@paper.height}" if @paper != nil
270
+ text << "\\paperh#{@paper.width}" if @paper != nil
271
+ else
272
+ text << "\\paperw#{@paper.width}" if @paper != nil
273
+ text << "\\paperh#{@paper.height}" if @paper != nil
274
+ end
275
+ text << "\\margl#{@left_margin}" if @left_margin != nil
276
+ text << "\\margr#{@right_margin}" if @right_margin != nil
277
+ text << "\\margt#{@top_margin}" if @top_margin != nil
278
+ text << "\\margb#{@bottom_margin}" if @bottom_margin != nil
279
+ text << "\\gutter#{@gutter}" if @gutter != nil
280
+ text << '\sectd\lndscpsxn' if @orientation == LANDSCAPE
281
+
282
+ text.string
283
+ end
284
+
285
+ # This method fetches the width of the available work area space for a
286
+ # DocumentStyle object.
287
+ def body_width
288
+ if orientation == PORTRAIT
289
+ @paper.width - (@left_margin + @right_margin)
290
+ else
291
+ @paper.height - (@left_margin + @right_margin)
292
+ end
293
+ end
294
+
295
+ # This method fetches the height of the available work area space for a
296
+ # DocumentStyle object.
297
+ def body_height
298
+ if orientation == PORTRAIT
299
+ @paper.height - (@top_margin + @bottom_margin)
300
+ else
301
+ @paper.width - (@top_margin + @bottom_margin)
302
+ end
303
+ end
304
+ end # End of the DocumentStyle class.
305
+ end # End of the RTF module.
@@ -0,0 +1,136 @@
1
+ require 'test_helper'
2
+
3
+ # Information class unit test class.
4
+ class CharacterStyleTest < Test::Unit::TestCase
5
+ def test_basics
6
+ style = CharacterStyle.new
7
+
8
+ assert(style.is_character_style? == true)
9
+ assert(style.is_document_style? == false)
10
+ assert(style.is_paragraph_style? == false)
11
+ assert(style.is_table_style? == false)
12
+
13
+ assert(style.prefix(nil, nil) == nil)
14
+ assert(style.suffix(nil, nil) == nil)
15
+
16
+ assert(style.background == nil)
17
+ assert(style.bold == false)
18
+ assert(style.capitalise == false)
19
+ assert(style.flow == CharacterStyle::LEFT_TO_RIGHT)
20
+ assert(style.font == nil)
21
+ assert(style.font_size == nil)
22
+ assert(style.foreground == nil)
23
+ assert(style.hidden == false)
24
+ assert(style.italic == false)
25
+ assert(style.strike == false)
26
+ assert(style.subscript == false)
27
+ assert(style.superscript == false)
28
+ assert(style.underline == false)
29
+ end
30
+
31
+ def test_mutators
32
+ style = CharacterStyle.new
33
+
34
+ style.background = Colour.new(100, 100, 100)
35
+ assert(style.background == Colour.new(100, 100, 100))
36
+
37
+ style.bold = true
38
+ assert(style.bold)
39
+
40
+ style.capitalise = true
41
+ assert(style.capitalize)
42
+
43
+ style.flow = CharacterStyle::RIGHT_TO_LEFT
44
+ assert(style.flow == CharacterStyle::RIGHT_TO_LEFT)
45
+
46
+ style.font = Font.new(Font::ROMAN, 'Arial')
47
+ assert(style.font == Font.new(Font::ROMAN, 'Arial'))
48
+
49
+ style.font_size = 38
50
+ assert(style.font_size == 38)
51
+
52
+ style.foreground = Colour.new(250, 200, 150)
53
+ assert(style.foreground == Colour.new(250, 200, 150))
54
+
55
+ style.hidden = true
56
+ assert(style.hidden)
57
+
58
+ style.italic = true
59
+ assert(style.italic)
60
+
61
+ style.strike = true
62
+ assert(style.strike)
63
+
64
+ style.subscript = true
65
+ assert(style.subscript)
66
+
67
+ style.superscript = true
68
+ assert(style.superscript)
69
+
70
+ style.underline = true
71
+ assert(style.underline)
72
+ end
73
+
74
+ def test_prefix
75
+ fonts = FontTable.new(Font.new(Font::ROMAN, 'Arial'))
76
+ colours = ColourTable.new(Colour.new(100, 100, 100))
77
+ style = CharacterStyle.new
78
+
79
+ style.background = colours[0]
80
+ assert(style.prefix(fonts, colours) == '\cb1')
81
+
82
+ style.background = nil
83
+ style.bold = true
84
+ assert(style.prefix(nil, nil) == '\b')
85
+
86
+ style.bold = false
87
+ style.capitalise = true
88
+ assert(style.prefix(nil, nil) == '\caps')
89
+
90
+ style.capitalize = false
91
+ style.flow = CharacterStyle::RIGHT_TO_LEFT
92
+ assert(style.prefix(nil, nil) == '\rtlch')
93
+
94
+ style.flow = nil
95
+ style.font = fonts[0]
96
+ assert(style.prefix(fonts, colours) == '\f0')
97
+
98
+ style.font = nil
99
+ style.font_size = 40
100
+ assert(style.prefix(nil, nil) == '\fs40')
101
+
102
+ style.font_size = nil
103
+ style.foreground = colours[0]
104
+ assert(style.prefix(fonts, colours) == '\cf1')
105
+
106
+ style.foreground = nil
107
+ style.hidden = true
108
+ assert(style.prefix(nil, nil) == '\v')
109
+
110
+ style.hidden = false
111
+ style.italic = true
112
+ assert(style.prefix(nil, nil) == '\i')
113
+
114
+ style.italic = false
115
+ style.strike = true
116
+ assert(style.prefix(nil, nil) == '\strike')
117
+
118
+ style.strike = false
119
+ style.subscript = true
120
+ assert(style.prefix(nil, nil) == '\sub')
121
+
122
+ style.subscript = false
123
+ style.superscript = true
124
+ assert(style.prefix(fonts, colours) == '\super')
125
+
126
+ style.superscript = false
127
+ style.underline = true
128
+ assert(style.prefix(fonts, colours) == '\ul')
129
+
130
+ style.flow = CharacterStyle::RIGHT_TO_LEFT
131
+ style.background = colours[0]
132
+ style.font_size = 18
133
+ style.subscript = true
134
+ assert(style.prefix(fonts, colours) == '\ul\sub\cb1\fs18\rtlch')
135
+ end
136
+ end