slodown 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/README.md CHANGED
@@ -1,6 +1,13 @@
1
- # Slodown
1
+ # Slodown: the ultimate user input rendering pipeline.
2
2
 
3
- TODO: Write a gem description
3
+ I love Markdown. I love syntax highlighting. I love oEmbed. And last but not least, I love whitelist-based HTML sanitizing. **Slodown** rolls all of these into one, and then some.
4
+
5
+ Here's what Slodown does by default:
6
+
7
+ - **render extended Markdown into HTML**. It uses the [kramdown](http://kramdown.rubyforge.org/) library, so yes, footnotes are supported!
8
+ - **supports super-easy rich media embeds**, [sloblog.io-style](http://sloblog.io/~hmans/qhdsk2SMoAU). Just point the Markdown image syntax at, say, a Youtube video, and Slodown will fetch the complete embed code through the magic of [ruby-oembed](https://github.com/judofyr/ruby-oembed).
9
+ - **auto-link contained URLs** using [Rinku](https://github.com/vmg/rinku), which is smart enough to not auto-link URLs contained in, say, code blocks.
10
+ - **sanitize the generated HTML** using the white-list based [sanitize](https://github.com/rgrove/sanitize) gem.
4
11
 
5
12
  ## Installation
6
13
 
@@ -18,7 +25,36 @@ Or install it yourself as:
18
25
 
19
26
  ## Usage
20
27
 
21
- TODO: Write usage instructions here
28
+ For every piece of user input that needs to be rendered, create an instance of `Slodown::Formatter` with the source text and use it to perform somre or all transformations on it. Finally, call `#to_s` to get the rendered output.
29
+
30
+ ### Examples:
31
+
32
+ ~~~ruby
33
+ # let's create an instance to work with
34
+ formatter = Slodown::Formatter.new(text)
35
+
36
+ # just markdown
37
+ @formatter.markdown.to_s
38
+
39
+ # just HTML tag sanitizing
40
+ @formatter.sanitize.to_s
41
+
42
+ # you can chain multiple operations
43
+ @formatter.markdown.sanitize.to_s
44
+
45
+ # this is the whole deal:
46
+ @formatter.markdown.autolink.sanitize.to_s
47
+
48
+ # which is the same as:
49
+ @formatter.complete.to_s
50
+ ~~~
51
+
52
+ ## Hints
53
+
54
+ * If you want to add more transformations or change the behavior of the `#complete` method, just subclass `Slodown::Formatter` and go wild. :-)
55
+ * Markdown transformations, HTML sanitizing, oEmbed handshakes and other operations are pretty expensive operations. For sake of performance (and stability), it is recommended that you cache the generated output in some manner.
56
+ * Eat more Schnitzel.
57
+
22
58
 
23
59
  ## Contributing
24
60
 
@@ -0,0 +1,15 @@
1
+ # This is the custom kramdown converter class we will be using to render
2
+ # HTML from Markdown. It's essentially a handy way to hook into various
3
+ # elements and add our own logic (like supporting oEmbed embeds in
4
+ # Markdown image elements.)
5
+ #
6
+ class Kramdown::Converter::SlodownHtml < Kramdown::Converter::Html
7
+ # Hook into image tags to allow oEmbed embeds.
8
+ #
9
+ def convert_img(el, indent)
10
+ oembed = OEmbed::Providers.get(el.attr['src'])
11
+ %q(<div class="embedded %s %s">%s</div>) % [oembed.type, oembed.provider_name.parameterize, oembed.html]
12
+ rescue OEmbed::NotFound
13
+ super
14
+ end
15
+ end
@@ -4,105 +4,15 @@ require 'kramdown'
4
4
  require 'coderay'
5
5
  require 'sanitize'
6
6
 
7
+ require "kramdown/converter/slodown_html"
7
8
  require "slodown/version"
9
+ require "slodown/formatter"
10
+ require "slodown/embed_transformer"
8
11
 
12
+ # Register all known oEmbed providers.
13
+ #
9
14
  OEmbed::Providers.register_all
10
15
 
11
- class Kramdown::Converter::SloblogHtml < Kramdown::Converter::Html
12
- def convert_img(el, indent)
13
- oembed = OEmbed::Providers.get(el.attr['src'])
14
- %q(<div class="embedded %s %s">%s</div>) % [oembed.type, oembed.provider_name.parameterize, oembed.html]
15
- rescue OEmbed::NotFound
16
- super
17
- end
18
- end
19
-
20
16
  module Slodown
21
- class EmbedTransformer
22
- ALLOWED_DOMAINS = %w[youtube.com soundcloud.com vimeo.com]
23
-
24
- def self.call(env)
25
- node = env[:node]
26
- node_name = env[:node_name]
27
-
28
- return if env[:is_whitelisted] || !env[:node].element?
29
- return unless %w[iframe embed].include? env[:node_name]
30
-
31
- uri = URI(env[:node]['src'])
32
- domains = ALLOWED_DOMAINS.map { |d| Regexp.escape(d) }.join("|")
33
- return unless uri.host =~ /^(.+\.)?(#{domains})/
34
-
35
- Sanitize.clean_node!(node, {
36
- elements: %w[iframe embed],
37
- attributes: {
38
- all: %w[allowfullscreen frameborder height src width]
39
- }
40
- })
41
-
42
- { node_whitelist: [node] }
43
- end
44
- end
45
-
46
- class Formatter
47
- def initialize(source)
48
- @current = @source = source.to_s
49
- end
50
-
51
- def complete
52
- markdown.autolink.sanitize
53
- end
54
-
55
- def markdown
56
- @current = Kramdown::Document.new(@current).to_sloblog_html
57
- self
58
- end
59
-
60
- def autolink
61
- @current = Rinku.auto_link(@current)
62
- self
63
- end
64
-
65
- def sanitize(mode = :normal)
66
- @current = case mode
67
- when :normal
68
- Sanitize.clean(@current,
69
- elements: %w(
70
- p a span sub sup strong em div hr abbr
71
- ul ol li
72
- blockquote pre code
73
- h1 h2 h3 h4 h5 h6
74
- img object param del
75
- ),
76
- attributes: {
77
- :all => ['class', 'style', 'title'],
78
- 'a' => ['href', 'rel', 'name'],
79
- 'li' => ['id'],
80
- 'sup' => ['id'],
81
- 'img' => ['src', 'title', 'alt', 'width', 'height'],
82
- 'object' => ['width', 'height'],
83
- 'param' => ['name', 'value'],
84
- 'embed' => ['allowscriptaccess', 'width', 'height', 'src'],
85
- 'iframe' => ['width', 'height', 'src']
86
- },
87
- protocols: {
88
- 'a' => { 'href' => ['ftp', 'http', 'https', 'mailto', '#fn', '#fnref', :relative] },
89
- 'img' => {'src' => ['http', 'https', :relative]},
90
- 'iframe' => {'src' => ['http', 'https']},
91
- 'embed' => {'src' => ['http', 'https']},
92
- 'object' => {'src' => ['http', 'https']},
93
- 'li' => {'id' => ['fn']},
94
- 'sup' => {'id' => ['fnref']}
95
- },
96
- transformers: EmbedTransformer)
97
- else
98
- Sanitize.clean(@current)
99
- end
100
-
101
- self
102
- end
103
-
104
- def to_s
105
- @current
106
- end
107
- end
17
+ # Our main module. Not much happening here. I like huskies.
108
18
  end
@@ -0,0 +1,26 @@
1
+ module Slodown
2
+ class EmbedTransformer
3
+ ALLOWED_DOMAINS = %w[youtube.com soundcloud.com vimeo.com]
4
+
5
+ def self.call(env)
6
+ node = env[:node]
7
+ node_name = env[:node_name]
8
+
9
+ return if env[:is_whitelisted] || !env[:node].element?
10
+ return unless %w[iframe embed].include? env[:node_name]
11
+
12
+ uri = URI(env[:node]['src'])
13
+ domains = ALLOWED_DOMAINS.map { |d| Regexp.escape(d) }.join("|")
14
+ return unless uri.host =~ /^(.+\.)?(#{domains})/
15
+
16
+ Sanitize.clean_node!(node, {
17
+ elements: %w[iframe embed],
18
+ attributes: {
19
+ all: %w[allowfullscreen frameborder height src width]
20
+ }
21
+ })
22
+
23
+ { node_whitelist: [node] }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,72 @@
1
+ module Slodown
2
+ class Formatter
3
+ def initialize(source)
4
+ @current = @source = source.to_s
5
+ end
6
+
7
+ # Runs the entire pipeline.
8
+ #
9
+ def complete
10
+ markdown.autolink.sanitize
11
+ end
12
+
13
+ # Convert the current document state from Markdown into HTML.
14
+ #
15
+ def markdown
16
+ @current = Kramdown::Document.new(@current).to_slodown_html
17
+ self
18
+ end
19
+
20
+ # Auto-link URLs through Rinku.
21
+ #
22
+ def autolink
23
+ @current = Rinku.auto_link(@current)
24
+ self
25
+ end
26
+
27
+ # Sanitize HTML tags.
28
+ #
29
+ def sanitize(mode = :normal)
30
+ @current = case mode
31
+ when :normal
32
+ Sanitize.clean(@current,
33
+ elements: %w(
34
+ p a span sub sup strong em div hr abbr
35
+ ul ol li
36
+ blockquote pre code
37
+ h1 h2 h3 h4 h5 h6
38
+ img object param del
39
+ ),
40
+ attributes: {
41
+ :all => ['class', 'style', 'title'],
42
+ 'a' => ['href', 'rel', 'name'],
43
+ 'li' => ['id'],
44
+ 'sup' => ['id'],
45
+ 'img' => ['src', 'title', 'alt', 'width', 'height'],
46
+ 'object' => ['width', 'height'],
47
+ 'param' => ['name', 'value'],
48
+ 'embed' => ['allowscriptaccess', 'width', 'height', 'src'],
49
+ 'iframe' => ['width', 'height', 'src']
50
+ },
51
+ protocols: {
52
+ 'a' => { 'href' => ['ftp', 'http', 'https', 'mailto', '#fn', '#fnref', :relative] },
53
+ 'img' => {'src' => ['http', 'https', :relative]},
54
+ 'iframe' => {'src' => ['http', 'https']},
55
+ 'embed' => {'src' => ['http', 'https']},
56
+ 'object' => {'src' => ['http', 'https']},
57
+ 'li' => {'id' => ['fn']},
58
+ 'sup' => {'id' => ['fnref']}
59
+ },
60
+ transformers: EmbedTransformer)
61
+ else
62
+ Sanitize.clean(@current)
63
+ end
64
+
65
+ self
66
+ end
67
+
68
+ def to_s
69
+ @current
70
+ end
71
+ end
72
+ end
@@ -1,3 +1,3 @@
1
1
  module Slodown
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Slodown::VERSION
9
9
  gem.authors = ["Hendrik Mans"]
10
10
  gem.email = ["hendrik@mans.de"]
11
- gem.description = %q{Markdown formatting code, extracted from sloblog.io.}
12
- gem.summary = %q{Markdown formatting code, extracted from sloblog.io.}
11
+ gem.description = %q{Markdown + oEmbed + Sanitize + CodeRay = the ultimate user input rendering pipeline.}
12
+ gem.summary = %q{Markdown + oEmbed + Sanitize + CodeRay = the ultimate user input rendering pipeline.}
13
13
  gem.homepage = "http://github.com/hmans/slodown"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
@@ -25,4 +25,5 @@ Gem::Specification.new do |gem|
25
25
 
26
26
  gem.add_development_dependency 'rspec', '>= 2.12.0'
27
27
  gem.add_development_dependency 'rspec-html-matchers'
28
+ gem.add_development_dependency 'rake'
28
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slodown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -123,7 +123,24 @@ dependencies:
123
123
  - - ! '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
- description: Markdown formatting code, extracted from sloblog.io.
126
+ - !ruby/object:Gem::Dependency
127
+ name: rake
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: Markdown + oEmbed + Sanitize + CodeRay = the ultimate user input rendering
143
+ pipeline.
127
144
  email:
128
145
  - hendrik@mans.de
129
146
  executables: []
@@ -134,10 +151,13 @@ files:
134
151
  - .rspec
135
152
  - .travis.yml
136
153
  - Gemfile
137
- - LICENSE.txt
154
+ - LICENSE
138
155
  - README.md
139
156
  - Rakefile
157
+ - lib/kramdown/converter/slodown_html.rb
140
158
  - lib/slodown.rb
159
+ - lib/slodown/embed_transformer.rb
160
+ - lib/slodown/formatter.rb
141
161
  - lib/slodown/version.rb
142
162
  - slodown.gemspec
143
163
  - spec/basic_formatting_spec.rb
@@ -165,7 +185,8 @@ rubyforge_project:
165
185
  rubygems_version: 1.8.23
166
186
  signing_key:
167
187
  specification_version: 3
168
- summary: Markdown formatting code, extracted from sloblog.io.
188
+ summary: Markdown + oEmbed + Sanitize + CodeRay = the ultimate user input rendering
189
+ pipeline.
169
190
  test_files:
170
191
  - spec/basic_formatting_spec.rb
171
192
  - spec/spec_helper.rb