typeout 1.4.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 (5) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +133 -0
  3. data/lib/typeout.js +276 -0
  4. data/lib/typeout.rb +170 -0
  5. metadata +86 -0
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Connor McKay
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,133 @@
1
+ = Typeout
2
+
3
+ Typeout is a plain text formatting language designed around two goals:
4
+
5
+ * Syntax simple enough for computer illiterate users
6
+ * Easily typed into an HTML textbox, meaning no tabs or extra spaces.
7
+
8
+ It is also a set of libraries in different programming languages for converting
9
+ Typeout formatted text into HTML. The primary implementation is in Ruby, which
10
+ has been more or less directly translated into Javascript.
11
+
12
+ Typeout is inspired by:
13
+
14
+ * Markdown http://daringfireball.net/projects/markdown
15
+ * Textile http://textism.com/tools/textile
16
+ * Creole http://www.wikicreole.org
17
+
18
+ *Author*:: Connor McKay (mailto:connor@verticalforest.com)
19
+ *Version*:: 1.4.1 (2010-7-8)
20
+ *Copyright*:: Copyright (c) 2007-2010 Connor McKay. All rights reserved.
21
+ *License*:: MIT License (http://opensource.org/licenses/mit-license.php)
22
+ *Website*:: http://github.com/greneholt/typeout
23
+
24
+ == Requires
25
+
26
+ Ruby version:
27
+
28
+ * Sanitize >= 1.2.1
29
+
30
+ Javascript version:
31
+
32
+ * MooTools Core >= 1.2.4
33
+
34
+ == Installation
35
+
36
+ Gem:
37
+
38
+ gem install typeout
39
+
40
+ Rails plugin:
41
+
42
+ ./script/plugin install git://github.com/greneholt/typeout.git
43
+
44
+ == Usage
45
+
46
+ Ruby:
47
+
48
+ Typeout.convert(text)
49
+
50
+ Javascript:
51
+
52
+ var text = new TypeOut(text);
53
+ text.toHTML();
54
+
55
+ == Syntax
56
+
57
+ ---
58
+ Code block
59
+ ---
60
+
61
+ = Level 1 Header
62
+ == Level 2 Header, etc.
63
+
64
+ * Unordered
65
+ * List
66
+
67
+ # Ordered
68
+ # List
69
+
70
+ * Multilevel
71
+ * Unordered
72
+ ** List
73
+ ** With
74
+ *** Multiple
75
+ * Asterisks
76
+
77
+ * Mixed
78
+ * Unordered
79
+ *# And
80
+ *# Ordered
81
+ *# Nested
82
+ * List
83
+
84
+ ~~~
85
+ Four score and seven years ago, blockquotes use at least three tildes at
86
+ beginning and end.
87
+ ~~~
88
+
89
+ Average paragraph containing *bold text*, _italic text_, and a
90
+ [link to google](http://google.com) and some `inline code`.
91
+
92
+ Another paragraph with a [link](http://google.com):button with a class of "button".
93
+
94
+ Images
95
+
96
+ !(http://example.com/an_image.png)
97
+
98
+ !(http://example.com/logo.png)[An image with optional alt text]
99
+
100
+
101
+ Name: Jane Alice
102
+ Age: 25
103
+ Favorite food: Pizza
104
+
105
+ Text at the beginning of a line followed by a colon will be automatically bolded.
106
+
107
+ Newlines in the middle of a paragraph are preserved in Typeout, meaning
108
+ that a paragraph cannot be split across multiple lines.
109
+
110
+ Plain html can be preserved intact by surrounding it in [html], [/html]
111
+ pairs. It will be sanitized using the Sanitize library in the Ruby version.
112
+
113
+ == License
114
+
115
+ Copyright (c) 2010 Connor McKay
116
+
117
+ Permission is hereby granted, free of charge, to any person obtaining a copy
118
+ of this software and associated documentation files (the "Software"), to deal
119
+ in the Software without restriction, including without limitation the rights
120
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
121
+ copies of the Software, and to permit persons to whom the Software is
122
+ furnished to do so, subject to the following conditions:
123
+
124
+ The above copyright notice and this permission notice shall be included in
125
+ all copies or substantial portions of the Software.
126
+
127
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
128
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
129
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
130
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
131
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
132
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
133
+ THE SOFTWARE.
data/lib/typeout.js ADDED
@@ -0,0 +1,276 @@
1
+ var Typeout = new Class({
2
+ initialize: function(content) {
3
+ var self = this;
4
+
5
+ self.content = content;
6
+ },
7
+
8
+ toHTML: function() {
9
+ var self = this;
10
+
11
+ var text = self.content;
12
+
13
+ text = self.cleanWhitespace(text);
14
+ text = '\n\n' + text + '\n\n'; // a few guaranteed newlines
15
+
16
+ self.archive = [];
17
+
18
+ text = self.archiveHtml(text);
19
+
20
+ text = self.htmlEscape(text);
21
+
22
+ text = self.archiveCode(text);
23
+
24
+ text = self.makeBlockquotes(text);
25
+ text = self.makeHeadings(text);
26
+ text = self.makeLists(text);
27
+ text = self.makeParagraphs(text);
28
+ text = self.makeInlines(text);
29
+
30
+ text = self.removeExcessNewlines(text);
31
+
32
+ text = self.retrieveArchive(text);
33
+
34
+ return text;
35
+ },
36
+
37
+ htmlEscape: function(text) {
38
+ return text.
39
+ replace(/&/g, '&').
40
+ replace(/</g, '&lt;').
41
+ replace(/>/g, '&gt;').
42
+ replace(/"/g, '&quot;')
43
+ },
44
+
45
+ regexpEscape: function(text) {
46
+ return text.replace(/([\{\}\(\)\[\]\*\+\?\$\^\.\#\\])/g, '\\$1')
47
+ },
48
+
49
+ cleanWhitespace: function(text) {
50
+ return text.
51
+ replace(/\r\n/g, '\n').
52
+ replace(/\r/g, '\n').
53
+ replace(/^ +$/gm, '');
54
+ },
55
+
56
+ removeExcessNewlines: function(text) {
57
+ return text.replace(/\n{3,}/g, '\n\n');
58
+ },
59
+
60
+ archiveHtml: function(text) {
61
+ var self = this;
62
+
63
+ return text.replace(/\[html\]([\s\S]*?)\[\/html\]/gmi, function(wholeMatch, m1) {
64
+ return self.addToArchive(m1);
65
+ });
66
+ },
67
+
68
+ archiveCode: function(text) {
69
+ var self = this;
70
+
71
+ text = text.replace(/^-{3,}\n([\s\S]+?)\n-{3,}$/gm, function(wholeMatch, m1) {
72
+ return self.addToArchive('<pre><code>' + m1 +'</code></pre>');
73
+ });
74
+
75
+ return text.replace(/`(?!\s)((?:\s*\S)+?)`/g, function(wholeMatch, m1) {
76
+ return self.addToArchive('<code>' + m1 + '</code>');
77
+ });
78
+ },
79
+
80
+ addToArchive: function(text) {
81
+ var self = this;
82
+
83
+ var index = self.archive.push(text) - 1;
84
+ return '!a!r!c!h!i!v!e!' + index + '!a!r!c!h!i!v!e!'; // nobody's going to type that!
85
+ },
86
+
87
+ retrieveArchive: function(text) {
88
+ var self = this;
89
+
90
+ self.archive.each(function(content, index) {
91
+ text = text.replace(new RegExp('!a!r!c!h!i!v!e!' + index + '!a!r!c!h!i!v!e!'), content); // the block is so gsub won't substitute \&
92
+ });
93
+ return text;
94
+ },
95
+
96
+ makeBlockquotes: function(text) {
97
+ return text.replace(/^~{3,}\n([\s\S]+?)\n~{3,}$/gm, '\n\n<blockquote>\n\n$1\n\n</blockquote>\n\n');
98
+ },
99
+
100
+ makeHeadings: function(text) {
101
+ return text.replace(/^(={1,6})(.+?)=*?$/gm, function(wholeMatch, m1, m2) {
102
+ var depth = m1.length;
103
+ return '\n\n<h' + depth + '>' + m2.trim() + '</h' + depth + '>\n\n';
104
+ });
105
+ },
106
+
107
+ makeLists: function(text, baseLevel) {
108
+ var self = this;
109
+
110
+ if (baseLevel == undefined) {
111
+ baseLevel = '';
112
+ }
113
+
114
+ return text.replace(new RegExp('^(' + self.regexpEscape(baseLevel) + '[\\*\\#])[\\*\\#]* [^\n]+?\n(?:\\1[\\*\\#]* (?:[^\n])+?\n)*', 'gm'), function(content, level) {
115
+ content = self.makeLists(content, level);
116
+ content = content.replace(new RegExp('^' + self.regexpEscape(level) + ' (.+)$', 'gm'), '<li>$1</li>');
117
+ content = content.replace(/<\/li>\n<([uo])l>/gm, '<$1l>');
118
+
119
+ if (level.slice(-1) == '*') { // its an unordered list
120
+ content = '<ul>\n' + content + '</ul>';
121
+ } else {
122
+ content = '<ol>\n' + content + '</ol>';
123
+ }
124
+
125
+ if (baseLevel) {
126
+ content += '</li>\n';
127
+ } else {
128
+ content += '\n';
129
+ }
130
+ return content;
131
+ });
132
+ },
133
+
134
+ makeParagraphs: function(text) {
135
+ var self = this;
136
+
137
+ return text.replace(/^(?!<|!a!r!c!h!i!v!e!)([^\n]+\n)+\n/gm, function(content) {
138
+ return '\n\n<p>\n' + self.makeBreaks(content.trim()) + '</p>\n\n';
139
+ });
140
+ },
141
+
142
+ makeBreaks: function(text) {
143
+ return text.replace(/([^\n])\n(?!\n)/gm, '$1<br />\n');
144
+ },
145
+
146
+ makeInlines: function(text) {
147
+ var self = this;
148
+
149
+ text = text.
150
+ replace(/^((?: ?[\w\(\)']){3,}:) (?!\s*$)/gm, '<b>$1</b> '). // spaces are not allowed directly in front of the colon, there must be a space after it, and the rest of the line can't be blank
151
+ replace(/!\((.+?)\)(?:\:([a-zA-Z0-9\_]+))?/g, function(wholeMatch, m1, m2) {
152
+ if (m2) {
153
+ return '<img src="' + self.addToArchive(m1.trim()) + '" class="' + m2 + '" />';
154
+ } else {
155
+ return '<img src="' + self.addToArchive(m1.trim()) + '" />';
156
+ }
157
+ }).
158
+ replace(/\[(.+?)\]\((.+?)\)(?:\:([a-zA-Z0-9\_]+))?/g, function(wholeMatch, m1, m2, m3) {
159
+ if (m3) {
160
+ return '<a href="' + self.addToArchive(m2.trim()) + '" class="' + m3 + '">' + self.addToArchive(m1) + '</a>';
161
+ } else {
162
+ return '<a href="' + self.addToArchive(m2.trim()) + '">' + self.addToArchive(m1) + '</a>';
163
+ }
164
+ }).
165
+ replace(/([a-z0-9\.\-\_\+]+)@((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)/gi, function(wholeMatch, address, subdomain, domain, tld) {
166
+ return '<a href="mailto:' + self.addToArchive(address + '@' + subdomain + domain + tld) + '">' + self.addToArchive(address + '@' + subdomain + domain + tld) + '</a>';
167
+ }).
168
+ replace(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/[a-z0-9\-\._=\?&;\%#]+)*\/?)/gi, function(wholeMatch, protocol, subdomain, domain, tld, file) {
169
+ if (!protocol) {
170
+ protocol = 'http://';
171
+ }
172
+ return '<a href="' + self.addToArchive(protocol + subdomain + domain + tld + file) + '">' + self.addToArchive(protocol + subdomain + domain + tld + file) + '</a>';
173
+ });
174
+
175
+ var inlines = [
176
+ ['*', 'strong'],
177
+ ['_', 'em'],
178
+ ['`', 'code'],
179
+ ['^', 'sup'],
180
+ ['~', 'sub']
181
+ ];
182
+
183
+ inlines.each(function(pair) {
184
+ var char = self.regexpEscape(pair[0]);
185
+ var tag = pair[1];
186
+ text = text.replace(new RegExp(char + '(?!\\s)((?:\\s*\\S)+?)' + char, 'g'), '<' + tag + '>$1</' + tag + '>');
187
+ });
188
+
189
+ return text;
190
+ }
191
+ });
192
+
193
+ var TypeOutPreview = new Class({
194
+ Implements: Options,
195
+
196
+ options: {
197
+ frequency: 500
198
+ },
199
+
200
+ initialize: function(textArea, previewDiv, options) {
201
+ var self = this;
202
+
203
+ self.textArea = $(textArea);
204
+ self.previewDiv = $(previewDiv);
205
+
206
+ self.setOptions(options);
207
+
208
+ self.typeOut = new TypeOut;
209
+ self.dirty = true;
210
+ self.ready = false;
211
+
212
+ self.textArea.addEvent('keyup', self.setDirty.bind(self));
213
+ self.setReady();
214
+ },
215
+
216
+ setDirty: function() {
217
+ var self = this;
218
+
219
+ self.dirty = true;
220
+ if (self.ready) {
221
+ self.setUnReady();
222
+ self.preview();
223
+ }
224
+ },
225
+
226
+ setUnReady: function() {
227
+ var self = this;
228
+
229
+ self.ready = false;
230
+ self.setReady.delay(self.options.frequency, self);
231
+ },
232
+
233
+ setReady: function() {
234
+ var self = this;
235
+
236
+ self.ready = true;
237
+ if (self.dirty) {
238
+ self.setUnReady();
239
+ self.preview();
240
+ }
241
+ },
242
+
243
+ render: function(text) {
244
+ var self = this;
245
+
246
+ self.typeOut.content = text;
247
+ return self.typeOut.toHTML();
248
+ },
249
+
250
+ preview: function() {
251
+ var self = this;
252
+
253
+ self.previewDiv.set('html', self.render(self.textArea.value));
254
+ self.dirty = false;
255
+ }
256
+ });
257
+
258
+ TypeOutTemplatePreview = new Class({
259
+ Extends: TypeOutPreview,
260
+
261
+ initialize: function(textArea, previewDiv, template, options) {
262
+ var self = this;
263
+
264
+ self.template = template;
265
+ self.parent(textArea, previewDiv, options);
266
+ },
267
+
268
+ render: function(content) {
269
+ var self = this;
270
+
271
+ self.template.tags.each(function(tag) {
272
+ content = content.replace(RegExp(self.regexpEscape(tag.name), 'gi'), tag.example);
273
+ });
274
+ return self.parent(content);
275
+ }
276
+ });
data/lib/typeout.rb ADDED
@@ -0,0 +1,170 @@
1
+ require 'sanitize'
2
+
3
+ class Typeout < String
4
+ VERSION = '1.4.1'
5
+
6
+ include ERB::Util
7
+
8
+ def self.convert(text)
9
+ self.new(text.to_s).to_html
10
+ end
11
+
12
+ def to_html
13
+ text = self.dup
14
+
15
+ text = clean_whitespace text
16
+ text = "\n\n#{text}\n\n" # a few guaranteed newlines
17
+
18
+ @archive = []
19
+
20
+ text = archive_html text
21
+
22
+ text = html_escape text
23
+
24
+ text = archive_code text
25
+ text = archive_blockquotes text
26
+
27
+ text = make_headings text
28
+ text = make_lists text
29
+ text = make_paragraphs text
30
+ text = make_inlines text
31
+
32
+ text = remove_excess_newlines text
33
+
34
+ text = retrieve_archive text
35
+
36
+ text
37
+ end
38
+
39
+ def sanitize_html(text)
40
+ Sanitize.clean(text, Sanitize::Config::RELAXED)
41
+ end
42
+
43
+ def clean_whitespace(text)
44
+ text.gsub(/\r\n/, "\n").
45
+ gsub(/\r/, "\n").
46
+ gsub(/^ +$/, '')
47
+ end
48
+
49
+ def remove_excess_newlines(text)
50
+ text.gsub(/\n{3,}/, "\n\n")
51
+ end
52
+
53
+ def archive_html(text)
54
+ text.gsub(/\[html\](.*?)\[\/html\]/mi) { archive(sanitize_html($1)) }
55
+ end
56
+
57
+ def archive_code(text)
58
+ text = text.gsub(/^-{3,}\n(.+?)\n-{3,}$/m) { archive("<pre><code>#{$1}</code></pre>") }
59
+ text.gsub(/`(?!\s)((?:\s*\S)+?)`/) { archive("<code>#{$1}</code>") }
60
+ end
61
+
62
+ def archive_blockquotes(text)
63
+ text.gsub(/^~{3,}\n(.+?)\n~{3,}$/m) do
64
+ content = remove_excess_newlines(make_paragraphs(make_lists("\n\n#{$1}\n\n"))) # blockquotes support paragraphs and lists
65
+ archive("<blockquote>#{content}</blockquote>")
66
+ end
67
+ end
68
+
69
+ def archive(text)
70
+ @archive << text
71
+ "!a!r!c!h!i!v!e!#{@archive.length-1}!a!r!c!h!i!v!e!" # nobody's going to type that!
72
+ end
73
+
74
+ def retrieve_archive(text)
75
+ @archive.each_with_index do |content, index|
76
+ text = text.sub("!a!r!c!h!i!v!e!#{index}!a!r!c!h!i!v!e!") { content } # the block is so gsub won't substitute \&
77
+ end
78
+ text
79
+ end
80
+
81
+ def make_headings(text)
82
+ text.gsub(/^(={1,6})(.+?)=*?$/) do
83
+ depth = $1.length
84
+ "\n\n<h#{depth}>#{$2.strip}</h#{depth}>\n\n"
85
+ end
86
+ end
87
+
88
+ def make_lists(text, base_level = nil)
89
+ text.gsub(/^(#{Regexp.escape(base_level.to_s)}[\*\#])[\*\#]* [^\n]+?\n(?:\1[\*\#]* (?:[^\n])+?\n)*/m) do |content|
90
+ level = $1
91
+
92
+ content = make_lists(content, level)
93
+ content = content.gsub(/^#{Regexp.escape(level)} (.+)$/, '<li>\1</li>')
94
+ content = content.gsub(/<\/li>\n<([uo])l>/m, '<\1l>')
95
+
96
+ if level.last == "*" # its an unordered list
97
+ content = "<ul>\n#{content}</ul>"
98
+ else
99
+ content = "<ol>\n#{content}</ol>"
100
+ end
101
+
102
+ if base_level
103
+ content += "</li>\n"
104
+ else
105
+ content += "\n"
106
+ end
107
+ content
108
+ end
109
+ end
110
+
111
+ def make_paragraphs(text)
112
+ text.gsub(/^(?!<|!a!r!c!h!i!v!e!)([^\n]+\n)+\n/m) { |content| "\n\n<p>\n#{make_breaks(content.strip)}</p>\n\n" }
113
+ end
114
+
115
+ def make_breaks(text)
116
+ text.gsub(/([^\n])\n(?!\n)/m, "\\1<br />\n")
117
+ end
118
+
119
+ def make_inlines(text)
120
+ text = text.
121
+ gsub(/^((?: ?[\w\(\)']){3,}:) (?!\s*$)/, '<b>\1</b> '). # spaces are not allowed directly in front of the colon, there must be a space after it, and the rest of the line can't be blank
122
+ gsub(/!\((.+?)\)(?:\:([a-zA-Z0-9\_]+))?/) do
123
+ if $2
124
+ "<img src=\"#{archive($1)}\" class=\"#{$2}\" />"
125
+ else
126
+ "<img src=\"#{archive($1)}\" />"
127
+ end
128
+ end.
129
+ gsub(/\[(.+?)\]\((.+?)\)(?:\:([a-zA-Z0-9\_]+))?/) do
130
+ if $3
131
+ "<a href=\"#{archive($2)}\" class=\"#{$3}\">#{archive($1)}</a>"
132
+ else
133
+ "<a href=\"#{archive($2)}\">#{archive($1)}</a>"
134
+ end
135
+ end.
136
+ gsub(/([a-z0-9\.\-\_\+]+)@((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)/i) do
137
+ "<a href=\"mailto:#{archive($1 + '@' + $2 + $3 + $4)}\">#{archive($1 + '@' + $2 + $3 + $4)}</a>"
138
+ end.
139
+ gsub(/(https?:\/\/)?((?:[a-z0-9\-]{2,}\.)*)([a-z0-9\-]+\.)(com|org|net|biz|edu|info|gov|co\.uk|co\.us)((?:\/[a-z0-9\-\._=\?&;\%#]+)*\/?)/i) do
140
+ if $1.nil?
141
+ protocol = 'http://'
142
+ else
143
+ protocol = $1
144
+ end
145
+ "<a href=\"#{archive(protocol + $2 + $3 + $4 + $5)}\">#{archive(protocol + $2 + $3 + $4 + $5)}</a>"
146
+ end
147
+
148
+ inlines = [
149
+ ['*', 'strong'],
150
+ ['_', 'em'],
151
+ ['`', 'code'],
152
+ ['^', 'sup'],
153
+ ['~', 'sub']
154
+ ]
155
+
156
+ inlines.each do |char, tag|
157
+ char = Regexp.escape(char)
158
+ re = /#{char} # the opening character
159
+ (?!\s) # no spaces directly after the char
160
+ ( # main capture group
161
+ (?:\s*\S)+? # because of no lookbehinds, every space must be followed by a non-space
162
+ ) # with lookbehinds, the whole regex is: \*(?! )(.+?)(?<! )\*
163
+ #{char}/x # closing character, no spaces directly before it
164
+ #re = /#{char}(.+?)#{char}/
165
+ text.gsub!(re, "<#{tag}>\\1</#{tag}>")
166
+ end
167
+
168
+ text
169
+ end
170
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typeout
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 4
9
+ - 1
10
+ version: 1.4.1
11
+ platform: ruby
12
+ authors:
13
+ - Connor McKay
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-08 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: sanitize
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description:
36
+ email:
37
+ - connor@verticalforest.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - README.rdoc
46
+ - LICENSE
47
+ - lib/typeout.js
48
+ - lib/typeout.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/greneholt/typeout
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 17
73
+ segments:
74
+ - 1
75
+ - 3
76
+ - 5
77
+ version: 1.3.5
78
+ requirements: []
79
+
80
+ rubyforge_project: typeout
81
+ rubygems_version: 1.3.7
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Dead simple plain text to HTML converter
85
+ test_files: []
86
+