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 +7 -0
- data/.byebug_history +4 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +45 -0
- data/README.md +110 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/01.rtf +45 -0
- data/examples/01_mac_libreoffice5_2_3_3.png +0 -0
- data/examples/01_mac_pages6_2.png +0 -0
- data/examples/01_mac_textedit1_12.png +0 -0
- data/examples/01_mac_word15_36.png +0 -0
- data/examples/01_styles_and_paragraphs.rb +33 -0
- data/examples/resources/json/redshirt_styles.json +49 -0
- data/lib/rrtf/colour.rb +182 -0
- data/lib/rrtf/converters/html.rb +123 -0
- data/lib/rrtf/converters.rb +5 -0
- data/lib/rrtf/font.rb +182 -0
- data/lib/rrtf/information.rb +110 -0
- data/lib/rrtf/list.rb +219 -0
- data/lib/rrtf/node.rb +1932 -0
- data/lib/rrtf/paper.rb +53 -0
- data/lib/rrtf/style/character_style.rb +68 -0
- data/lib/rrtf/style/document_style.rb +116 -0
- data/lib/rrtf/style/formatting.rb +276 -0
- data/lib/rrtf/style/paragraph_style.rb +79 -0
- data/lib/rrtf/style/style.rb +101 -0
- data/lib/rrtf/style.rb +8 -0
- data/lib/rrtf/stylesheet.rb +202 -0
- data/lib/rrtf/version.rb +3 -0
- data/lib/rrtf.rb +27 -0
- data/rrtf.gemspec +30 -0
- metadata +163 -0
data/lib/rrtf/style.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module RRTF
|
4
|
+
|
5
|
+
# Class that represents a stylesheet in an RTF document
|
6
|
+
class Stylesheet
|
7
|
+
# An array of styles associated with the stylesheet
|
8
|
+
attr_reader :styles
|
9
|
+
|
10
|
+
# The document to which the stylesheet belongs
|
11
|
+
attr_accessor :document
|
12
|
+
|
13
|
+
def initialize(document, options = {})
|
14
|
+
@options = {
|
15
|
+
"styles" => [],
|
16
|
+
"base_style_handle" => 1,
|
17
|
+
"base_style_priority" => 100,
|
18
|
+
"assign_style_handles" => true,
|
19
|
+
"assign_style_priorities" => true
|
20
|
+
}.merge(options)
|
21
|
+
@document = document
|
22
|
+
@next_styles_hash = {}
|
23
|
+
@base_styles_hash = {}
|
24
|
+
@styles = {}
|
25
|
+
add_styles(@options["styles"])
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_styles(hash_array)
|
29
|
+
hash_array.each { |hash| add_style(hash) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_style(options)
|
33
|
+
style = options.delete("style")
|
34
|
+
type = options.delete("type")
|
35
|
+
add_options = extract_add_options(options)
|
36
|
+
|
37
|
+
if !style.nil?
|
38
|
+
# style object given; add directly
|
39
|
+
if !add_style_object(style, add_options)
|
40
|
+
RTFError.fire("#{style.to_s} could not be added to the stylesheet (hint: make sure it's a style object).")
|
41
|
+
end # if
|
42
|
+
elsif !type.nil?
|
43
|
+
# style object not given; create based on type
|
44
|
+
case type
|
45
|
+
when "paragraph"
|
46
|
+
add_style_object(ParagraphStyle.new(options), add_options)
|
47
|
+
when "character"
|
48
|
+
add_style_object(CharacterStyle.new(options), add_options)
|
49
|
+
else
|
50
|
+
RTFError.fire("Unreconized style type '#{type.to_s}'.")
|
51
|
+
end # case
|
52
|
+
else
|
53
|
+
RTFError.fire("A style type or style object must be specified for each style in a stylesheet.")
|
54
|
+
end # if
|
55
|
+
end # add_style_from_hash()
|
56
|
+
|
57
|
+
# Converts the stylesheet to its RTF representation
|
58
|
+
# NOTE calling to_rtf causes all next styles to be updated (to_rtf "commits"
|
59
|
+
# the stylesheet)
|
60
|
+
def to_rtf(options = {})
|
61
|
+
# load default options
|
62
|
+
options = {
|
63
|
+
"uglify" => false,
|
64
|
+
"base_indent" => 0,
|
65
|
+
"child_indent" => 0
|
66
|
+
}.merge(options)
|
67
|
+
# build line prefixes
|
68
|
+
newline_prefix = options["uglify"] ? '' : "\n"
|
69
|
+
base_prefix = options["uglify"] ? '' : " "*options["base_indent"]
|
70
|
+
|
71
|
+
# lookup and set next style handles on component styles
|
72
|
+
substitute_next_style_handles()
|
73
|
+
substitute_base_style_handles()
|
74
|
+
|
75
|
+
rtf = StringIO.new
|
76
|
+
|
77
|
+
rtf << "#{base_prefix}{\\stylesheet"
|
78
|
+
@styles.values.each do |style|
|
79
|
+
rtf << newline_prefix
|
80
|
+
rtf << style.to_rtf(
|
81
|
+
document,
|
82
|
+
"uglify" => options["uglify"],
|
83
|
+
"base_indent" => options["base_indent"]+options["child_indent"]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
rtf << "#{newline_prefix}#{base_prefix}}"
|
87
|
+
|
88
|
+
rtf.string
|
89
|
+
end # to_rtf()
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Strips options used in adding a style to a stylesheet from a hash
|
94
|
+
# and returns a subhash containing those options
|
95
|
+
def extract_add_options(hash)
|
96
|
+
{
|
97
|
+
"id" => hash.delete("id"),
|
98
|
+
"default" => hash.delete("default") || false,
|
99
|
+
"next_style_id" => hash.delete("next_style") || nil,
|
100
|
+
"base_style_id" => hash.delete("base_style") || nil,
|
101
|
+
"assign_handle" => hash.delete("assign_handle") || @options["assign_style_handles"],
|
102
|
+
"assign_priority" => hash.delete("assign_priority") || @options["assign_style_priorities"]
|
103
|
+
}
|
104
|
+
end # extract_add_options()
|
105
|
+
|
106
|
+
# Adds a style object to the stylesheet
|
107
|
+
def add_style_object(style, options = {})
|
108
|
+
# load default options
|
109
|
+
options = {
|
110
|
+
"id" => nil,
|
111
|
+
"default" => false,
|
112
|
+
"next_style_id" => nil,
|
113
|
+
"base_style_id" => nil,
|
114
|
+
"assign_handle" => true,
|
115
|
+
"assign_priority" => true
|
116
|
+
}.merge(options)
|
117
|
+
|
118
|
+
if style.kind_of?(Style)
|
119
|
+
unless @styles.values.index(style).nil?
|
120
|
+
# style already present in stylesheet
|
121
|
+
return true
|
122
|
+
end # unless
|
123
|
+
|
124
|
+
# Verify ID is present and does not conflict with another style's ID
|
125
|
+
if options["id"].nil? || !options["id"].kind_of?(String) || options["id"].length < 1
|
126
|
+
RTFError.fire("All styles in a stylesheet must have unique non-empty string IDs.")
|
127
|
+
elsif !@styles[options["id"]].nil?
|
128
|
+
RTFError.fire("Multiple styles cannot have the same ID '#{style.id}'.")
|
129
|
+
end # if
|
130
|
+
|
131
|
+
# Auto-assign handle to style if nil
|
132
|
+
if style.handle.nil? && options["assign_handle"]
|
133
|
+
if options["default"]
|
134
|
+
# default style takes on the '0' handle
|
135
|
+
style.handle = 0
|
136
|
+
else
|
137
|
+
max_h = @styles.values.collect(&:handle).max
|
138
|
+
base_h = @options["base_style_handle"]
|
139
|
+
style.handle = (max_h || (base_h - 1)) + 1
|
140
|
+
end # if
|
141
|
+
end # if
|
142
|
+
|
143
|
+
# Auto-assign priority if nil
|
144
|
+
if style.priority.nil? && options["assign_priority"]
|
145
|
+
max_p = @styles.values.collect(&:priority).max
|
146
|
+
base_p = @options["base_style_priority"]
|
147
|
+
style.priority = (max_p || (base_p - 1)) + 1
|
148
|
+
end # if
|
149
|
+
|
150
|
+
# Add key in next styles hash if next style given
|
151
|
+
unless options["next_style_id"].nil?
|
152
|
+
@next_styles_hash[options["id"]] = options["next_style_id"]
|
153
|
+
end # unless
|
154
|
+
|
155
|
+
# Add key in base styles hash if next style given
|
156
|
+
unless options["base_style_id"].nil?
|
157
|
+
@base_styles_hash[options["id"]] = options["base_style_id"]
|
158
|
+
end # unless
|
159
|
+
|
160
|
+
# Add style fonts and colours to respective tables
|
161
|
+
style.push_colours(document.colours)
|
162
|
+
style.push_fonts(document.fonts)
|
163
|
+
|
164
|
+
@styles[options["id"]] = style
|
165
|
+
true
|
166
|
+
else
|
167
|
+
false
|
168
|
+
end # if
|
169
|
+
end # add()
|
170
|
+
|
171
|
+
# Sets the "next style" handle on each style based on the entries in
|
172
|
+
# next_styles_hash (when add is called with the next_style_id option,
|
173
|
+
# an entry in the hash is created with the id of the next style; the hash
|
174
|
+
# maps the ids of styles to the ids of the corresponding "next styles")
|
175
|
+
def substitute_next_style_handles
|
176
|
+
@styles.each do |id,style|
|
177
|
+
next_style_id = @next_styles_hash[id]
|
178
|
+
# skip style if there is not a "next style"
|
179
|
+
next if next_style_id.nil?
|
180
|
+
# raise error if the specified "next style" is not defined
|
181
|
+
if @styles[next_style_id].nil?
|
182
|
+
RTFError.fire("'#{next_style_id}' cannot be the next style for '#{id}' because '#{next_style_id}'' has not been added to the stylesheet.")
|
183
|
+
end # if
|
184
|
+
style.next_style_handle = @styles[next_style_id].handle
|
185
|
+
end # styles each
|
186
|
+
end # substitute_next_style_handles()
|
187
|
+
|
188
|
+
def substitute_base_style_handles
|
189
|
+
@styles.each do |id,style|
|
190
|
+
base_style_id = @base_styles_hash[id]
|
191
|
+
# skip style if there is not a base style
|
192
|
+
next if base_style_id.nil?
|
193
|
+
# raise error if the specified base style is not defined
|
194
|
+
if @styles[base_style_id].nil?
|
195
|
+
RTFError.fire("'#{base_style_id}' cannot be the base style for '#{id}' because '#{base_style_id}'' has not been added to the stylesheet.")
|
196
|
+
end # if
|
197
|
+
style.based_on_style_handle = @styles[base_style_id].handle
|
198
|
+
end # styles each
|
199
|
+
end # substitute_next_style_handles()
|
200
|
+
end # class Stylesheet
|
201
|
+
|
202
|
+
end # module RRTF
|
data/lib/rrtf/version.rb
ADDED
data/lib/rrtf.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rrtf/version'
|
2
|
+
require 'rrtf/font'
|
3
|
+
require 'rrtf/colour'
|
4
|
+
require 'rrtf/style'
|
5
|
+
require 'rrtf/stylesheet'
|
6
|
+
require 'rrtf/information'
|
7
|
+
require 'rrtf/paper'
|
8
|
+
require 'rrtf/node'
|
9
|
+
require 'rrtf/list'
|
10
|
+
|
11
|
+
module RRTF
|
12
|
+
class RTFError < StandardError
|
13
|
+
def initialize(message=nil)
|
14
|
+
super(message == nil ? 'No error message available.' : message)
|
15
|
+
end
|
16
|
+
|
17
|
+
def RTFError.fire(message=nil)
|
18
|
+
raise RTFError.new(message)
|
19
|
+
end
|
20
|
+
end # class RTFError
|
21
|
+
|
22
|
+
class Utilities
|
23
|
+
def self.constantize(string)
|
24
|
+
string.split('::').inject(Object) {|o,c| o.const_get c}
|
25
|
+
end
|
26
|
+
end # class Utilities
|
27
|
+
end # module RRTF
|
data/rrtf.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rrtf/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rrtf"
|
8
|
+
spec.version = RRTF::VERSION
|
9
|
+
spec.authors = ["Wesley Hileman"]
|
10
|
+
spec.email = ["whileman133@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A ruby-based rich text format (RTF) document generator.}
|
13
|
+
spec.homepage = "https://github.com/whileman133/rrtf"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
spec.add_development_dependency "byebug"
|
27
|
+
# Required for HTML converter functionality
|
28
|
+
spec.add_dependency "nokogiri"
|
29
|
+
spec.add_dependency "tidy"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rrtf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wesley Hileman
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tidy
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- whileman133@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".byebug_history"
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".travis.yml"
|
108
|
+
- Gemfile
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- bin/console
|
113
|
+
- bin/setup
|
114
|
+
- examples/01.rtf
|
115
|
+
- examples/01_mac_libreoffice5_2_3_3.png
|
116
|
+
- examples/01_mac_pages6_2.png
|
117
|
+
- examples/01_mac_textedit1_12.png
|
118
|
+
- examples/01_mac_word15_36.png
|
119
|
+
- examples/01_styles_and_paragraphs.rb
|
120
|
+
- examples/resources/json/redshirt_styles.json
|
121
|
+
- lib/rrtf.rb
|
122
|
+
- lib/rrtf/colour.rb
|
123
|
+
- lib/rrtf/converters.rb
|
124
|
+
- lib/rrtf/converters/html.rb
|
125
|
+
- lib/rrtf/font.rb
|
126
|
+
- lib/rrtf/information.rb
|
127
|
+
- lib/rrtf/list.rb
|
128
|
+
- lib/rrtf/node.rb
|
129
|
+
- lib/rrtf/paper.rb
|
130
|
+
- lib/rrtf/style.rb
|
131
|
+
- lib/rrtf/style/character_style.rb
|
132
|
+
- lib/rrtf/style/document_style.rb
|
133
|
+
- lib/rrtf/style/formatting.rb
|
134
|
+
- lib/rrtf/style/paragraph_style.rb
|
135
|
+
- lib/rrtf/style/style.rb
|
136
|
+
- lib/rrtf/stylesheet.rb
|
137
|
+
- lib/rrtf/version.rb
|
138
|
+
- rrtf.gemspec
|
139
|
+
homepage: https://github.com/whileman133/rrtf
|
140
|
+
licenses:
|
141
|
+
- MIT
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.5.2
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: A ruby-based rich text format (RTF) document generator.
|
163
|
+
test_files: []
|