rrtf 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3467d6a2c8f2088bea129baf92e38489313e095a
4
+ data.tar.gz: e747dbf2f17843d3774d064d7de258b810c03744
5
+ SHA512:
6
+ metadata.gz: 25846effd9f89636439d227ab600633b50e76ee5a8554bd925367eca05350def4d32b0004dfeaa9d28bfc944270f26d8f1ada2a67b60bf3a3f286f478fc861c2
7
+ data.tar.gz: 1e6372a0cc1ada21f428d7b7798690e435029e2e17a88d9690d17b7b7063bc0671faceddcc80087018d399d6ca60b122b0010958e34de9d5c6bf7bd87dd46e3b
data/.byebug_history ADDED
@@ -0,0 +1,4 @@
1
+ next
2
+ document
3
+ next
4
+ document
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.13.7
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rrtf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,45 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Wesley Hileman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
23
+
24
+
25
+ Copyright (c) 2009 Peter Wood
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining
28
+ a copy of this software and associated documentation files (the
29
+ "Software"), to deal in the Software without restriction, including
30
+ without limitation the rights to use, copy, modify, merge, publish,
31
+ distribute, sublicense, and/or sell copies of the Software, and to
32
+ permit persons to whom the Software is furnished to do so, subject to
33
+ the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be
36
+ included in all copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
42
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
43
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
+
data/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # RRTF: Ruby Rich-Text-Format Document Generator
2
+
3
+ RRTF enables programatic creation of Rich Text Format (RTF) documents in Ruby, focusing on simplifying RTF document assembly and generating clean RTF source code. This gem is founded on the [ifad-rtf gem](https://github.com/clbustos/rtf), but differs in several respects:
4
+
5
+ - The syntax for creating documents and styles is simpler.
6
+ - Paragraph styles can take on character formatting attributes (in accord to the RTF specification).
7
+ - Document stylesheets can be defined, enabling the end user to easily modify the look larger RTF documents.
8
+
9
+ The gem was created with reference to the [Microsoft Office RTF Specification (v1.9.1)](https://www.microsoft.com/en-us/download/details.aspx?id=10725).
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'rrtf'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install rrtf
26
+
27
+ ## Usage
28
+
29
+ Define the paragraph and character styles your document is to leverage in
30
+ a hashmap array or JSON file:
31
+
32
+ ```json
33
+ [
34
+ {
35
+ "type": "paragraph",
36
+ "id": "TITLE",
37
+ "name": "Title",
38
+ "primary": true,
39
+ "next_style": "BODY",
40
+ "justification": "CENTER",
41
+ "space_after": 100,
42
+ "bold": true,
43
+ "underline": "DOUBLE",
44
+ "uppercase": true,
45
+ "font_size": 36,
46
+ "underline_color": "#ff0000"
47
+ },
48
+ {
49
+ "type": "paragraph",
50
+ "id": "BODY",
51
+ "name": "Body",
52
+ "primary": true,
53
+ "justification": "LEFT",
54
+ "font_size": 24,
55
+ "hyphenate": true
56
+ },
57
+ {
58
+ "type": "character",
59
+ "id": "EMPH",
60
+ "name": "Emphasis",
61
+ "additive": true,
62
+ "italic": true,
63
+ "bold": true,
64
+ "foreground_color": "#ff0000"
65
+ }
66
+ ]
67
+ ```
68
+
69
+ (Note that font size is given in _half points_ and spacing in _twentieth points_, or "twips" using the somewhat disagreeable abbreviation, in accord with the RTF specification.)
70
+
71
+ Create a RTF document object using the settings needed for your document, then build your document and save it in an RTF file:
72
+
73
+ ```ruby
74
+ require 'rrtf'
75
+ require 'JSON'
76
+
77
+ raw_styles = JSON.parse File.read('styles.json')
78
+
79
+ rtf = RRTF::Document.new("stylesheet" => raw_styles)
80
+ styles = rtf.stylesheet.styles
81
+
82
+ rtf.paragraph(styles['TITLE']) << "RedShirts 101"
83
+ rtf.paragraph(styles['BODY']) do |p|
84
+ p << "Should you ever find yourself on a spacefaring vessel wearing a"
85
+ p.apply(styles['EMPH']) << " red "
86
+ p << "shirt, take heed and be on guard, for danger is immanent and you are "
87
+ p << "likely expendable among the crew..."
88
+ end
89
+
90
+ File.open('01.rtf', 'w') do |file|
91
+ file.write(rtf.to_rtf)
92
+ end
93
+ ```
94
+
95
+ ![Opened in Word 2016](examples/01_mac_word15_36.png "Opened in Word 2016")
96
+
97
+ ## Development
98
+
99
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
100
+
101
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
102
+
103
+ ## Contributing
104
+
105
+ Bug reports and pull requests are welcome on GitHub at https://github.com/whileman133/rrtf.
106
+
107
+
108
+ ## License
109
+
110
+ Just like ifad-rtf, this gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rrtf"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/examples/01.rtf ADDED
@@ -0,0 +1,45 @@
1
+ {\rtf1\ansi\deff0\deflang1033\plain\fs24\fet1
2
+ {\fonttbl
3
+ {\f0\fswiss Helvetica;}
4
+ }
5
+ {\colortbl
6
+ ;
7
+ \red255\green0\blue0;
8
+ }
9
+ {\stylesheet
10
+ {\s1 \qc\sa100\ltrpar \b\uldb\caps\ulc1\fs36 \sbasedon3 \sautoupd \snext3 \sqformat \spriority100 Title;}
11
+ {\s2 \ql\sb200\sa40\ltrpar \b\ul\ulc1\fs24 \snext3 \sqformat \spriority101 Heading 1;}
12
+ {\s3 \ql\hyphpar\ltrpar \fs24 \sqformat \spriority102 Body;}
13
+ {\*\cs4 \b\i\cf1 \additive \spriority103 Emphasis;}
14
+ }
15
+ {\info
16
+ {\createim\yr2017\mo7\dy23\hr19\min18}
17
+ }
18
+
19
+ \stylesortmethod1\paperw12247\paperh15819\margl1800\margr1800\margt1440\margb1440
20
+ {\pard\s1 \qc\sa100\ltrpar \b\uldb\caps\ulc1\fs36
21
+ RedShirts 101
22
+ \par}
23
+ {\pard\s3 \ql\hyphpar\ltrpar \fs24
24
+ Should you ever find yourself on a spacefaring vessel wearing a
25
+ {\cs4 \b\i\cf1
26
+ red
27
+ }
28
+ shirt, take heed and be on guard, for danger is immanent and you are likely expendable among the crew...
29
+ \par}
30
+ {\pard\s2 \ql\sb200\sa40\ltrpar \b\ul\ulc1\fs24
31
+ 1. The Danger of Away Missions
32
+ \par}
33
+ {\pard\s3 \ql\hyphpar\ltrpar \fs24
34
+ If you're ever assigned an away mission, its almost certian to be your doom. The optimal stategy is to avoid away missions to begin with...
35
+ \par}
36
+ {\pard\s2 \ql\sb200\sa40\ltrpar \b\ul\ulc1\fs24
37
+ 2. Avoiding High-Ranking Officers
38
+ \par}
39
+ {\pard\s3 \ql\hyphpar\ltrpar \fs24
40
+ You're likely to notice an influx of unfortunate outcomes around certian high-ranking officers. Its to your advantage to quickly identify and avoid these officers...
41
+ \par}
42
+ {\pard\s2 \ql\sb200\sa40\ltrpar \b\ul\ulc1\fs24
43
+ 3. Miscellaneous Hazards
44
+ \par}
45
+ }
Binary file
Binary file
Binary file
@@ -0,0 +1,33 @@
1
+ require 'rrtf'
2
+ require 'JSON'
3
+
4
+ DIR = File.dirname(__FILE__)
5
+
6
+ raw_styles = JSON.parse File.read(DIR+'/resources/json/redshirt_styles.json')
7
+
8
+ rtf = RRTF::Document.new("stylesheet" => raw_styles)
9
+ styles = rtf.stylesheet.styles
10
+
11
+ rtf.paragraph(styles['TITLE']) << "RedShirts 101"
12
+ rtf.paragraph(styles['BODY']) do |p|
13
+ p << "Should you ever find yourself on a spacefaring vessel wearing a"
14
+ p.apply(styles['EMPH']) << " red "
15
+ p << "shirt, take heed and be on guard, for danger is immanent and you are "
16
+ p << "likely expendable among the crew..."
17
+ end
18
+ rtf.paragraph(styles['H1']) << "1. The Danger of Away Missions"
19
+ rtf.paragraph(styles['BODY']) do |p|
20
+ p << "If you're ever assigned an away mission, its almost certian to be your doom. "
21
+ p << "The optimal stategy is to avoid away missions to begin with..."
22
+ end
23
+ rtf.paragraph(styles['H1']) << "2. Avoiding High-Ranking Officers"
24
+ rtf.paragraph(styles['BODY']) do |p|
25
+ p << "You're likely to notice an influx of unfortunate outcomes around "
26
+ p << "certian high-ranking officers. Its to your advantage to quickly identify and "
27
+ p << "avoid these officers..."
28
+ end
29
+
30
+
31
+ File.open(DIR+'/01.rtf', 'w') do |file|
32
+ file.write(rtf.to_rtf)
33
+ end
@@ -0,0 +1,49 @@
1
+ [
2
+ {
3
+ "type": "paragraph",
4
+ "id": "TITLE",
5
+ "name": "Title",
6
+ "primary": true,
7
+ "auto_update": true,
8
+ "next_style": "BODY",
9
+ "base_style": "BODY",
10
+ "justification": "CENTER",
11
+ "space_after": 100,
12
+ "bold": true,
13
+ "underline": "DOUBLE",
14
+ "underline_color": "#ff0000",
15
+ "uppercase": true,
16
+ "font_size": 36
17
+ },
18
+ {
19
+ "type": "paragraph",
20
+ "id": "H1",
21
+ "name": "Heading 1",
22
+ "primary": true,
23
+ "next_style": "BODY",
24
+ "space_after": 40,
25
+ "space_before": 200,
26
+ "underline": "SINGLE",
27
+ "underline_color": "#ff0000",
28
+ "bold": true,
29
+ "font_size": 24
30
+ },
31
+ {
32
+ "type": "paragraph",
33
+ "id": "BODY",
34
+ "name": "Body",
35
+ "primary": true,
36
+ "justification": "LEFT",
37
+ "font_size": 24,
38
+ "hyphenate": true
39
+ },
40
+ {
41
+ "type": "character",
42
+ "id": "EMPH",
43
+ "name": "Emphasis",
44
+ "additive": true,
45
+ "italic": true,
46
+ "bold": true,
47
+ "foreground_color": "#ff0000"
48
+ }
49
+ ]
@@ -0,0 +1,182 @@
1
+ require 'stringio'
2
+
3
+ module RRTF
4
+ # This class represents a colour within a RTF document.
5
+ class Colour
6
+ # Attribute accessor.
7
+ attr_reader :red, :green, :blue
8
+
9
+
10
+ # Format: HEX RGB with '#' prefix
11
+ def self.from_string(str)
12
+ if str =~ /\#[0-9a-f]{6}/i
13
+ m = str.match /([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i
14
+ self.new(m[1].hex, m[2].hex, m[3].hex)
15
+ else
16
+ RTFError.fire("Unreconized string colour format '#{str}'.")
17
+ end
18
+ end
19
+
20
+
21
+ # This is the constructor for the Colour class.
22
+ #
23
+ # ==== Parameters
24
+ # red:: The intensity setting for red in the colour. Must be an
25
+ # integer between 0 and 255.
26
+ # green:: The intensity setting for green in the colour. Must be an
27
+ # integer between 0 and 255.
28
+ # blue:: The intensity setting for blue in the colour. Must be an
29
+ # integer between 0 and 255.
30
+ #
31
+ # ==== Exceptions
32
+ # RTFError:: Generated whenever an invalid intensity setting is
33
+ # specified for the red, green or blue values.
34
+ def initialize(red, green, blue)
35
+ if !red.kind_of?(Integer) || red < 0 || red > 255
36
+ RTFError.fire("Invalid red intensity setting ('#{red}') specified "\
37
+ "for a Colour object.")
38
+ end
39
+ if !green.kind_of?(Integer) || green < 0 || green > 255
40
+ RTFError.fire("Invalid green intensity setting ('#{green}') "\
41
+ "specified for a Colour object.")
42
+ end
43
+ if !blue.kind_of?(Integer) || blue < 0 || blue > 255
44
+ RTFError.fire("Invalid blue intensity setting ('#{blue}') "\
45
+ "specified for a Colour object.")
46
+ end
47
+
48
+ @red = red
49
+ @green = green
50
+ @blue = blue
51
+ end
52
+
53
+ # This method overloads the comparison operator for the Colour class.
54
+ #
55
+ # ==== Parameters
56
+ # object:: A reference to the object to be compared with.
57
+ def ==(object)
58
+ object.instance_of?(Colour) and
59
+ object.red == @red and
60
+ object.green == @green and
61
+ object.blue == @blue
62
+ end
63
+
64
+ # This method returns a textual description for a Colour object.
65
+ #
66
+ # ==== Parameters
67
+ # indent:: The number of spaces to prefix to the lines created by the
68
+ # method. Defaults to zero.
69
+ def to_s(indent=0)
70
+ prefix = indent > 0 ? ' ' * indent : ''
71
+ "#{prefix}Colour (#{@red}/#{@green}/#{@blue})"
72
+ end
73
+
74
+ # This method generates the RTF text for a Colour object.
75
+ #
76
+ # ==== Parameters
77
+ # indent:: The number of spaces to prefix to the lines created by the
78
+ # method. Defaults to zero.
79
+ def to_rtf(indent=0)
80
+ prefix = indent > 0 ? ' ' * indent : ''
81
+ "#{prefix}\\red#{@red}\\green#{@green}\\blue#{@blue};"
82
+ end
83
+ end # End of the Colour class.
84
+
85
+
86
+ # This class represents a table of colours used within a RTF document. This
87
+ # class need not be directly instantiated as it will be used internally by,
88
+ # and can be obtained from a Document object.
89
+ class ColourTable
90
+ # This is the constructor for the ColourTable class.
91
+ #
92
+ # ==== Parameters
93
+ # *colours:: An array of zero or more colours that make up the colour
94
+ # table entries.
95
+ def initialize(*colours)
96
+ @colours = []
97
+ colours.each {|colour| add(colour)}
98
+ end
99
+
100
+ # This method fetches a count of the number of colours within a colour
101
+ # table.
102
+ def size
103
+ @colours.size
104
+ end
105
+
106
+ # This method adds a new colour to a ColourTable object. If the colour
107
+ # already exists within the table or is not a Colour object then this
108
+ # method does nothing.
109
+ #
110
+ # ==== Parameters
111
+ # colour:: The colour to be added to the table.
112
+ def add(colour)
113
+ if colour.instance_of?(Colour)
114
+ @colours.push(colour) if @colours.index(colour).nil?
115
+ end
116
+ self
117
+ end
118
+
119
+ # This method iterates over the contents of a ColourTable object. This
120
+ # iteration does not include the implicit default colour entry.
121
+ def each
122
+ if block_given?
123
+ @colours.each {|colour| yield colour}
124
+ end
125
+ end
126
+
127
+ # This method overloads the array dereference operator for the ColourTable
128
+ # class. It is not possible to dereference the implicit default colour
129
+ # using this method. An invalid index will return a nil value.
130
+ #
131
+ # ==== Parameters
132
+ # index:: The index of the colour to be retrieved.
133
+ def [](index)
134
+ @colours[index]
135
+ end
136
+
137
+ # This method retrieves the index of a specified colour within the table.
138
+ # If the colour doesn't exist within the table then nil is returned. It
139
+ # should be noted that the index of a colour will be one more than its
140
+ # order of entry to account for the implicit default colour entry.
141
+ #
142
+ # ==== Parameters
143
+ # colour:: The colour to retrieve the index of.
144
+ def index(colour)
145
+ index = @colours.index(colour)
146
+ index.nil? ? index : index + 1
147
+ end
148
+
149
+ # This method generates a textual description for a ColourTable object.
150
+ #
151
+ # ==== Parameters
152
+ # indent:: The number of spaces to prefix to the lines generated by the
153
+ # method. Defaults to zero.
154
+ def to_s(indent=0)
155
+ prefix = indent > 0 ? ' ' * indent : ''
156
+ text = StringIO.new
157
+
158
+ text << "#{prefix}Colour Table (#{@colours.size} colours)"
159
+ @colours.each {|colour| text << "\n#{prefix} #{colour}"}
160
+
161
+ text.string
162
+ end
163
+
164
+ # This method generates the RTF text for a ColourTable object.
165
+ #
166
+ # ==== Parameters
167
+ # indent:: The number of spaces to prefix to the lines generated by the
168
+ # method. Defaults to zero.
169
+ def to_rtf(indent=0)
170
+ prefix = indent > 0 ? ' ' * indent : ''
171
+ text = StringIO.new
172
+
173
+ text << "#{prefix}{\\colortbl\n#{prefix};"
174
+ @colours.each {|colour| text << "\n#{prefix}#{colour.to_rtf}"}
175
+ text << "\n#{prefix}}"
176
+
177
+ text.string
178
+ end
179
+
180
+ alias << add
181
+ end # End of the ColourTable class.
182
+ end # End of the RTF module.
@@ -0,0 +1,123 @@
1
+ require 'nokogiri'
2
+ require 'tidy'
3
+
4
+ module RRTF::Converters
5
+ class HTML
6
+
7
+ def initialize(html, options = {})
8
+ html = options[:noclean] ? html : clean(html, options[:tidy_options] || {})
9
+ @html = Nokogiri::HTML::Document.parse(html)
10
+ end
11
+
12
+ def to_rtf(options = {})
13
+ to_rtf_document(options).to_rtf
14
+ end
15
+
16
+ def to_rtf_document(options = {})
17
+ font = Helpers.font(options[:font] || :default)
18
+ nodes = NodeSet.new @html.css('body').children
19
+
20
+ RRTF::Document.new(font).tap do |rtf|
21
+ nodes.to_rtf(rtf)
22
+ end
23
+ end
24
+
25
+ protected
26
+ def clean(html, options = {})
27
+ defaults = {
28
+ :doctype => 'omit',
29
+ :bare => true,
30
+ :clean => true,
31
+ :drop_empty_paras => true,
32
+ :logical_emphasis => true,
33
+ :lower_literals => true,
34
+ :merge_spans => 1,
35
+ :merge_divs => 1,
36
+ :output_html => true,
37
+ :indent => 0,
38
+ :wrap => 0,
39
+ :char_encoding => 'utf8'
40
+ }
41
+
42
+ tidy = Tidy.new defaults.merge(options)
43
+ tidy.clean(html)
44
+ end
45
+
46
+ module Helpers
47
+ extend self
48
+
49
+ def font(key)
50
+ RRTF::Font.new(*case key
51
+ when :default then [RTF::Font::ROMAN, 'Times New Roman']
52
+ when :monospace then [RTF::Font::MODERN, 'Courier New' ]
53
+ end)
54
+ end
55
+
56
+ def style(key)
57
+ RRTF::CharacterStyle.new.tap do |style|
58
+ case key.to_sym
59
+ when :h1
60
+ style.font_size = 44
61
+ style.bold = true
62
+ when :h2
63
+ style.font_size = 36
64
+ style.bold = true
65
+ when :h3
66
+ style.font_size = 28
67
+ style.bold = true
68
+ when :h4
69
+ style.font_size = 22
70
+ style.bold = true
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ class NodeSet
77
+ def initialize(nodeset)
78
+ @nodeset = nodeset
79
+ end
80
+
81
+ def to_rtf(rtf)
82
+ @nodeset.each do |node|
83
+ Node.new(node).to_rtf(rtf)
84
+ end
85
+ end
86
+ end
87
+
88
+ class Node # :nodoc:
89
+ def initialize(node)
90
+ @node = node
91
+ end
92
+
93
+ def to_rtf(rtf)
94
+ case @node.name
95
+ when 'text' then rtf << @node.text.gsub(/\n+/, ' ').strip
96
+ when 'br' then rtf.line_break
97
+ when 'b', 'strong' then rtf.bold &recurse
98
+ when 'i', 'em', 'cite' then rtf.italic &recurse
99
+ when 'u' then rtf.underline &recurse
100
+ when 'blockquote', 'p', 'div' then rtf.paragraph &recurse
101
+ when 'span' then recurse.call(rtf)
102
+ when 'sup' then rtf.subscript &recurse
103
+ when 'sub' then rtf.superscript &recurse
104
+ when 'ul' then rtf.list :bullets, &recurse
105
+ when 'ol' then rtf.list :decimal, &recurse
106
+ when 'li' then rtf.item &recurse
107
+ when 'a' then rtf.link @node[:href], &recurse
108
+ when 'h1', 'h2', 'h3', 'h4' then rtf.apply(Helpers.style(@node.name), &recurse); rtf.line_break
109
+ when 'code' then rtf.font Helpers.font(:monospace), &recurse
110
+ else
111
+ #puts "Ignoring #{@node.to_html}"
112
+ end
113
+
114
+ return rtf
115
+ end
116
+
117
+ def recurse
118
+ lambda {|rtf| NodeSet.new(@node.children).to_rtf(rtf)}
119
+ end
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,5 @@
1
+ require 'rrtf'
2
+ module RRTF::Converters
3
+ # Empty, for now
4
+ end
5
+ require 'rrtf/converters/html'