rrtf 0.1.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.
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'