rad_kit 0.0.6 → 0.0.7
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.
- data/lib/components/captcha.rb +24 -0
- data/lib/components/captcha.yml +2 -0
- data/lib/kit/{http_controller → controller}/authorized.rb +1 -1
- data/lib/kit/controller/captcha.rb +23 -0
- data/lib/kit/{http_controller → controller}/localized.rb +1 -1
- data/lib/kit/controller.rb +5 -0
- data/lib/kit/gems.rb +10 -6
- data/lib/kit/i18n/locales/ru/pluralization.rb +62 -0
- data/lib/kit/i18n.rb +16 -0
- data/lib/kit/kit.rb +10 -7
- data/lib/kit/kit_text_utils.rb +30 -0
- data/lib/kit/misc/prepare_model.rb +16 -0
- data/lib/kit/misc/user_error.rb +12 -0
- data/lib/kit/models/attachments_uploader_helper.rb +1 -1
- data/lib/kit/models/authorized.rb +6 -8
- data/lib/kit/models/authorized_object.rb +3 -4
- data/lib/kit/models/{micelaneous.rb → miscellaneous.rb} +0 -0
- data/lib/kit/models_after.rb +1 -1
- data/lib/kit/mongoid/{rad_micelaneous.rb → rad_miscellaneous.rb} +1 -1
- data/lib/kit/mongoid/text_processor.rb +1 -1
- data/lib/kit/mongoid.rb +2 -2
- data/lib/kit/spec.rb +1 -2
- data/lib/kit/tasks.rb +1 -1
- data/lib/text_utils/code_highlighter.rb +75 -0
- data/lib/text_utils/custom_markdown.rb +64 -0
- data/lib/text_utils/ensure_utf.rb +14 -0
- data/lib/text_utils/format_qualifier.rb +13 -0
- data/lib/{kit/text_utils → text_utils}/html_sanitizer.rb +8 -6
- data/lib/text_utils/markdown.rb +33 -0
- data/lib/text_utils/pipe.rb +16 -0
- data/lib/text_utils/processor.rb +14 -0
- data/lib/text_utils/support.rb +15 -0
- data/lib/text_utils/truncate.rb +30 -0
- data/lib/text_utils.rb +23 -0
- data/readme.md +1 -8
- data/spec/controller/authorization_spec.rb +1 -1
- data/spec/controller/captcha_spec.rb +66 -0
- data/spec/i18n/i18n_spec/locales/en/general.yml +5 -0
- data/spec/i18n/i18n_spec/locales/ru/general.yml +7 -0
- data/spec/i18n/i18n_spec.rb +32 -0
- data/spec/misc/kit_text_utils_spec.rb +29 -0
- data/spec/misc/prepare_model_spec.rb +37 -0
- data/spec/misc/user_error_spec.rb +38 -0
- data/spec/models/authorized_object_spec.rb +10 -3
- data/spec/spec_helper/factories.rb +4 -0
- data/spec/spec_helper/user.rb +2 -3
- data/spec/spec_helper.rb +0 -5
- data/spec/text_utils/code_highlighter_spec.rb +38 -0
- data/spec/text_utils/custom_markdown_spec.rb +82 -0
- data/spec/text_utils/format_qualifier_spec.rb +37 -0
- data/spec/text_utils/html_sanitizer_spec.rb +88 -0
- data/spec/text_utils/markdown_spec.rb +114 -0
- data/spec/text_utils/pipe_spec.rb +35 -0
- data/spec/text_utils/spec_helper.rb +26 -0
- data/spec/text_utils/text_processor_shared.rb +9 -0
- data/spec/text_utils/truncate_spec.rb +22 -0
- metadata +57 -47
- data/lib/kit/http_controller.rb +0 -4
- data/lib/kit/text_utils/code_highlighter.rb +0 -58
- data/lib/kit/text_utils/custom_markdown.rb +0 -90
- data/lib/kit/text_utils/ensure_utf.rb +0 -8
- data/lib/kit/text_utils/github_flavoured_markdown.rb +0 -32
- data/lib/kit/text_utils/image_box.rb +0 -35
- data/lib/kit/text_utils/markup.rb +0 -43
- data/lib/kit/text_utils/processor.rb +0 -25
- data/lib/kit/text_utils/tag_shortcuts.rb +0 -14
- data/lib/kit/text_utils/truncate.rb +0 -29
- data/lib/kit/text_utils/truncator.rb +0 -15
- data/lib/kit/text_utils/urls.rb +0 -13
- data/lib/kit/text_utils.rb +0 -43
- data/spec/utils/text_utils_spec.rb +0 -280
@@ -0,0 +1,16 @@
|
|
1
|
+
class TextUtils::Pipe
|
2
|
+
def initialize *processors
|
3
|
+
@processor = processors.reverse.inject nil do |next_processor, meta|
|
4
|
+
klass, args = if meta.is_a? Array
|
5
|
+
[meta[0], meta[1..-1]]
|
6
|
+
else
|
7
|
+
[meta, []]
|
8
|
+
end
|
9
|
+
klass.new next_processor, *args
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def call text
|
14
|
+
@processor.call text, {}
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Object.class_eval do
|
2
|
+
unless method_defined? :try
|
3
|
+
def try method
|
4
|
+
self && self.send(method)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
class String
|
11
|
+
def self.random length = 3
|
12
|
+
@digits ||= ('a'..'z').to_a + (0..9).to_a
|
13
|
+
(0..(length-1)).map{@digits[rand(@digits.size)]}.join
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class TextUtils::Truncate < TextUtils::Processor
|
2
|
+
def initialize processor, length
|
3
|
+
super processor
|
4
|
+
@length = length
|
5
|
+
end
|
6
|
+
|
7
|
+
def call data, env
|
8
|
+
data ||= ""
|
9
|
+
|
10
|
+
# strip from HTML tags
|
11
|
+
data = data.gsub("<br", " <br").gsub("<p", " <p") # to preserve space in place of <> html elements
|
12
|
+
doc = Nokogiri::XML("<div class='root'>#{data}</div>")
|
13
|
+
data = doc.css('.root').first.content
|
14
|
+
|
15
|
+
# remove clear space
|
16
|
+
data = data.gsub(/\s+/, ' ')
|
17
|
+
|
18
|
+
# truncate with no broken words
|
19
|
+
data = if data.length >= @length
|
20
|
+
shortened = data[0, @length]
|
21
|
+
splitted = shortened.split(/\s/)
|
22
|
+
words = splitted.length
|
23
|
+
splitted[0, words-1].join(" ") + ' ...'
|
24
|
+
else
|
25
|
+
data
|
26
|
+
end
|
27
|
+
|
28
|
+
call_next data, env
|
29
|
+
end
|
30
|
+
end
|
data/lib/text_utils.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'iconv'
|
3
|
+
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'bluecloth'
|
6
|
+
require 'sanitize'
|
7
|
+
|
8
|
+
module TextUtils; end
|
9
|
+
|
10
|
+
%w(
|
11
|
+
support
|
12
|
+
|
13
|
+
processor
|
14
|
+
|
15
|
+
ensure_utf
|
16
|
+
html_sanitizer
|
17
|
+
format_qualifier
|
18
|
+
truncate
|
19
|
+
markdown
|
20
|
+
custom_markdown
|
21
|
+
pipe
|
22
|
+
code_highlighter
|
23
|
+
).each{|f| require "text_utils/#{f}"}
|
data/readme.md
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Captcha" do
|
4
|
+
before :all do
|
5
|
+
class TheController
|
6
|
+
inherit Rad::Controller::Http, Rad::Controller::Captcha
|
7
|
+
|
8
|
+
def action
|
9
|
+
render inline: 'ok'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
after(:all){remove_constants :TheController}
|
14
|
+
|
15
|
+
before do
|
16
|
+
rad.captcha.stub!(:enabled).and_return(true)
|
17
|
+
|
18
|
+
@request = Rad::Http::Request.stub
|
19
|
+
@request.stub!(:from_browser?).and_return(true)
|
20
|
+
|
21
|
+
@params = Rad::Conveyors::Params.new
|
22
|
+
|
23
|
+
@controller = TheController.new
|
24
|
+
@controller.stub!(:request).and_return(@request)
|
25
|
+
@controller.stub!(:params).and_return(@params)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should allow get for anyone" do
|
29
|
+
@request.stub!(:get?).and_return(true)
|
30
|
+
|
31
|
+
rad.user = Factory.build :anonymous
|
32
|
+
@controller.call(:action).should == 'ok'
|
33
|
+
|
34
|
+
rad.user = Factory.build :registered
|
35
|
+
@controller.call(:action).should == 'ok'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "shouldn't allow non-get for anonymous" do
|
39
|
+
@request.stub!(:get?).and_return(false)
|
40
|
+
|
41
|
+
rad.user = Factory.build :anonymous
|
42
|
+
-> {@controller.call(:action)}.should raise_error(UserError)
|
43
|
+
|
44
|
+
rad.user = Factory.build :registered
|
45
|
+
@controller.call(:action).should == 'ok'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should display captcha form for anonymous if format is :js" do
|
49
|
+
@request.stub!(:get?).and_return(false)
|
50
|
+
@params.format = 'js'
|
51
|
+
rad.captcha.stub!(:verify).and_return(false)
|
52
|
+
rad.user = Factory.build :anonymous
|
53
|
+
@controller.stub!(:render).and_return('form')
|
54
|
+
|
55
|
+
@controller.call(:action).should == 'form'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow anonymous access if it solved captcha" do
|
59
|
+
@request.stub!(:get?).and_return(false)
|
60
|
+
@params.format = 'js'
|
61
|
+
rad.captcha.stub!(:verify).and_return(true)
|
62
|
+
rad.user = Factory.build :anonymous
|
63
|
+
|
64
|
+
@controller.call(:action).should == 'ok'
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe 'I18n' do
|
6
|
+
before :all do
|
7
|
+
rad.web
|
8
|
+
rad.reset :conveyors
|
9
|
+
|
10
|
+
I18n.load_path += Dir["#{spec_dir}/locales/*/*.{rb,yml}"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def t *args
|
14
|
+
I18n.t *args
|
15
|
+
end
|
16
|
+
|
17
|
+
it "basic" do
|
18
|
+
I18n.locale = 'en'
|
19
|
+
t(:name).should == "Name"
|
20
|
+
t(:name).is_a?(String).should be_true
|
21
|
+
|
22
|
+
I18n.locale = 'ru'
|
23
|
+
t(:name).should == "Имя"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "pluggable pluralization" do
|
27
|
+
I18n.locale = 'ru'
|
28
|
+
t(:comments_count, count: 1).should == "1 комментарий"
|
29
|
+
t(:comments_count, count: 2).should == "2 комментария"
|
30
|
+
t(:comments_count, count: 5).should == "5 комментариев"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "TextUtils with Kit extensions" do
|
4
|
+
it "should truncate" do
|
5
|
+
TextUtils.truncate('lorem ipsum', 10).should == 'lorem ...'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should process markdown (should qualify markdown format automatically)" do
|
9
|
+
TextUtils.markup('lorem **ipsum**').should == '<p>lorem <strong>ipsum</strong></p>'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should process html (should qualify html format automatically)" do
|
13
|
+
TextUtils.markup('<p>lorem **ipsum**</p>').should == '<p>lorem **ipsum**</p>'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "code highlight" do
|
17
|
+
rad.config.stub!(:use_code_highlighter).and_return(true)
|
18
|
+
|
19
|
+
markdown = <<MARKDOWN
|
20
|
+
code
|
21
|
+
|
22
|
+
``` ruby
|
23
|
+
puts "Hello World"
|
24
|
+
```
|
25
|
+
MARKDOWN
|
26
|
+
|
27
|
+
TextUtils.markup(markdown).should =~ /span/i
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "User Error" do
|
4
|
+
isolate :conveyors, :router, before: :all
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
rad.delete :conveyors
|
8
|
+
rad.conveyors.web do |web|
|
9
|
+
web.use Rad::Controller::Processors::ControllerCaller
|
10
|
+
end
|
11
|
+
|
12
|
+
class ::SomeModel
|
13
|
+
def self.find! id
|
14
|
+
id.should == 'some id'
|
15
|
+
SomeModel.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
after :all do
|
20
|
+
remove_constants %w(SomeModel ControllerSpec)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "user error" do
|
24
|
+
class ::ControllerSpec
|
25
|
+
inherit Rad::Controller::Http
|
26
|
+
|
27
|
+
prepare_model SomeModel, id: :some_model, variable: 'some_model'
|
28
|
+
|
29
|
+
def action
|
30
|
+
@some_model.should_not == nil
|
31
|
+
render inline: 'ok'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ccall(ControllerSpec, :action, some_model: 'some id').should == 'ok'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "User Error" do
|
4
|
+
isolate :conveyors, :router, before: :all
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
rad.delete :conveyors
|
8
|
+
rad.conveyors.web do |web|
|
9
|
+
web.use Rad::Controller::Processors::ControllerCaller
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
remove_constants %w(UserErrorSpec)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "user error" do
|
18
|
+
class ::UserErrorSpec
|
19
|
+
inherit Rad::Controller::Http
|
20
|
+
|
21
|
+
def action
|
22
|
+
raise_user_error "some error"
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
def catch_user_error
|
27
|
+
begin
|
28
|
+
yield
|
29
|
+
rescue UserError => ue
|
30
|
+
render inline: "Catched #{ue.message}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
around :catch_user_error
|
34
|
+
end
|
35
|
+
|
36
|
+
ccall(UserErrorSpec, :action).should == "Catched some error"
|
37
|
+
end
|
38
|
+
end
|
@@ -98,6 +98,13 @@ describe "Authorized Object" do
|
|
98
98
|
o.normalized_collaborators.should == %w{manager member user:auser}
|
99
99
|
end
|
100
100
|
|
101
|
+
it "anonymous should never be collaborator (from error)" do
|
102
|
+
@user = Factory.build :anonymous
|
103
|
+
o = AModel.new
|
104
|
+
o.owner = @user
|
105
|
+
o.normalized_collaborators.should == []
|
106
|
+
end
|
107
|
+
|
101
108
|
it "viewers and collaborators dependance" do
|
102
109
|
o = AModel.new
|
103
110
|
o.owner = @user
|
@@ -174,8 +181,8 @@ describe "Authorized Object" do
|
|
174
181
|
@object = AModel.new
|
175
182
|
@owned_object = AModel.new
|
176
183
|
@owned_object.owner = @user
|
177
|
-
end
|
178
|
-
|
184
|
+
end
|
185
|
+
|
179
186
|
it "owner?" do
|
180
187
|
@user.should_not be_owner(@object)
|
181
188
|
@user.should be_owner(@owned_object)
|
@@ -189,7 +196,7 @@ describe "Authorized Object" do
|
|
189
196
|
|
190
197
|
@user.should_not be_owner(@owned_object)
|
191
198
|
end
|
192
|
-
|
199
|
+
|
193
200
|
it 'permissions for owner' do
|
194
201
|
@user.can?(:manage, @object).should be_false
|
195
202
|
@user.can?(:manage, @owned_object).should be_true
|
data/spec/spec_helper/user.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "Markdown" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@processor = TextUtils::CodeHighlighter.new
|
8
|
+
@options = {format: :html}
|
9
|
+
end
|
10
|
+
|
11
|
+
it_should_behave_like 'text processor'
|
12
|
+
|
13
|
+
it "basic" do
|
14
|
+
process(%{<p> text </p><code lang='ruby'>class A; p "Hello World" end</code><p> text </p>}).should =~ /span/i
|
15
|
+
process(%{<p> text </p><code language='ruby'>class A; p "Hello World" end</code><p> text </p>}).should =~ /span/i
|
16
|
+
process(%{<code lang='ruby'>\nclass A \n def p\n 10\n end\nend \n</code>}).should =~ /span/i
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should works with < and > in code" do
|
20
|
+
process(%{<code lang='ruby'>class A < ClassB; end</code>}).should include('ClassB')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should preserve custom classes in <code>' do
|
24
|
+
process(%{<code lang='ruby' class='my_code'>\nclass A \n def p\n 10\n end\nend \n</code>}).should =~ /my_code/i
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'markdown' do
|
28
|
+
markdown = <<MARKDOWN
|
29
|
+
text
|
30
|
+
|
31
|
+
``` ruby
|
32
|
+
print "Hello World"
|
33
|
+
```
|
34
|
+
MARKDOWN
|
35
|
+
|
36
|
+
process(markdown).should =~ /span/i
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "Markdown" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
markdown = TextUtils::Markdown.new
|
8
|
+
@processor = TextUtils::CustomMarkdown.new markdown
|
9
|
+
@options = {format: :markdown}
|
10
|
+
end
|
11
|
+
|
12
|
+
it_should_behave_like 'text processor'
|
13
|
+
|
14
|
+
it "should apply markup inside of html elements (from error)" do
|
15
|
+
html = <<HTML
|
16
|
+
<div class='right'>
|
17
|
+
![img]
|
18
|
+
</div>
|
19
|
+
|
20
|
+
[img]: /some_link
|
21
|
+
HTML
|
22
|
+
|
23
|
+
to_doc(html).css('.right img').size.should == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should leave existing links intact" do
|
27
|
+
doc = to_doc(%{<a href="http://some_domain.com">http://some_domain.com</a>})
|
28
|
+
doc.css('a').size.should == 1
|
29
|
+
doc.css('a').first['href'].should == "http://some_domain.com"
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'image box' do
|
33
|
+
it "should use simplifyed syntax for image boxes (!![img_thumb] => [![img_thumb]][img_full_version])" do
|
34
|
+
html = <<HTML
|
35
|
+
!![img]
|
36
|
+
![img]
|
37
|
+
|
38
|
+
!![img_2]
|
39
|
+
![img_2]
|
40
|
+
|
41
|
+
[img]: /some_prefix/image_name.png
|
42
|
+
[img_2]: /some_prefix/image_name2.icon.png
|
43
|
+
HTML
|
44
|
+
|
45
|
+
doc = to_doc html
|
46
|
+
doc.css('a').first.to_fuzzy_hash.should == {href: "/some_prefix/image_name.png"}
|
47
|
+
doc.css('a img').first.to_fuzzy_hash.should == {src: "/some_prefix/image_name.thumb.png"}
|
48
|
+
|
49
|
+
doc.css('a').last.to_fuzzy_hash.should == {href: "/some_prefix/image_name2.png"}
|
50
|
+
doc.css('a img').last.to_fuzzy_hash.should == {src: "/some_prefix/image_name2.icon.png"}
|
51
|
+
|
52
|
+
doc.css('img').size.should == 4
|
53
|
+
end
|
54
|
+
|
55
|
+
it "simplifyed syntax for image boxes should be robust (from error)" do
|
56
|
+
html = "!![img] " # without resolved reference
|
57
|
+
lambda{process(html)}.should_not raise_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# discarded
|
62
|
+
# it "clear div" do
|
63
|
+
# html = "[clear]"
|
64
|
+
#
|
65
|
+
# doc = to_doc html
|
66
|
+
# doc.css('div.clear').size.should == 1
|
67
|
+
# end
|
68
|
+
|
69
|
+
# discarded
|
70
|
+
# it "space div" do
|
71
|
+
# html = "[space]"
|
72
|
+
#
|
73
|
+
# doc = to_doc html
|
74
|
+
# doc.css('div.space').size.should == 1
|
75
|
+
# end
|
76
|
+
|
77
|
+
# discarded
|
78
|
+
# it "should skip empty paragraphs" do
|
79
|
+
# html = "line 1\n\nline 2\n\n\n\nline 3"
|
80
|
+
# process(html).should =~ /<p>\s*line 1<\/p>\n<p>line 2<\/p>\n<p>line 3\s*<\/p>.?/
|
81
|
+
# end
|
82
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "FormatQualifier" do
|
4
|
+
before do
|
5
|
+
@processor = TextUtils::FormatQualifier.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it_should_behave_like 'text processor'
|
9
|
+
|
10
|
+
it "should qualify format" do
|
11
|
+
[
|
12
|
+
'<b>some</b>', :html,
|
13
|
+
'<b>some</b> <p>other</p>', :html,
|
14
|
+
' <b> some</b> ', :html,
|
15
|
+
'<b/>', :html,
|
16
|
+
'<b>', :markdown,
|
17
|
+
'abc', :markdown
|
18
|
+
].each_slice 2 do |text, format|
|
19
|
+
env = {}
|
20
|
+
@processor.call(text, env)
|
21
|
+
env[:format].should == format
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should qualify :html (from error)" do
|
26
|
+
html = <<HTML
|
27
|
+
<h2>Title</h2>
|
28
|
+
|
29
|
+
<p>body</p>
|
30
|
+
HTML
|
31
|
+
|
32
|
+
env = {}
|
33
|
+
@processor.call(html, env)
|
34
|
+
env[:format].should == :html
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'text_utils/spec_helper'
|
2
|
+
|
3
|
+
describe "HtmlSanitizer" do
|
4
|
+
include RSpec::TextUtilsHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@processor = TextUtils::HtmlSanitizer.new
|
8
|
+
@options = {format: :html}
|
9
|
+
end
|
10
|
+
|
11
|
+
it_should_behave_like 'text processor'
|
12
|
+
|
13
|
+
it "should escape restricted tags" do
|
14
|
+
%w(script object).each do |tag|
|
15
|
+
html = "<#{tag}}>some text</#{tag}>"
|
16
|
+
process(html).should_not include(tag)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "shouldn't escape non-restricted tags" do
|
21
|
+
common_attr_names = %w(class style)
|
22
|
+
{
|
23
|
+
iframe: %w(height scrolling src width),
|
24
|
+
a: %w(href title rel)
|
25
|
+
}.each do |tag, attr_names|
|
26
|
+
attrs = {}; (common_attr_names + attr_names).each{|n| attrs[n] = 'value'}
|
27
|
+
|
28
|
+
attrs_html = ""; attrs.each{|n, v| attrs_html << "#{n}='#{v}'"}
|
29
|
+
html = "<#{tag} #{attrs_html}}>some text</#{tag}>"
|
30
|
+
|
31
|
+
to_doc(html).css(tag.to_s).first.to_fuzzy_hash.should == attrs
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow image inside of link (from error)" do
|
36
|
+
html = <<HTML
|
37
|
+
<a rel="images" class="image_box" href="/some_image">
|
38
|
+
<img src="/some_image"/>
|
39
|
+
</a>
|
40
|
+
HTML
|
41
|
+
|
42
|
+
doc = to_doc html
|
43
|
+
doc.css('a').first.to_fuzzy_hash.should == {href: "/some_image", class: "image_box"}
|
44
|
+
doc.css('a img').first.to_fuzzy_hash.should == {src: "/some_image"}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should allow 'a' elements (from error)" do
|
48
|
+
html = <<HTML
|
49
|
+
<a href="http://www.some.com/some">Absolute Link</a>
|
50
|
+
<a href="/some">Relative Link</a>
|
51
|
+
HTML
|
52
|
+
|
53
|
+
doc = to_doc html
|
54
|
+
doc.css("a").first[:href].should == "http://www.some.com/some"
|
55
|
+
doc.css("a").last[:href].should == "/some"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow div with any classes (from error)" do
|
59
|
+
html = %{<div class="col3 left"><a href='#'>text</a></div>}
|
60
|
+
to_doc(html).css("div.col3.left a").size.should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should embed YouTube Videos" do
|
64
|
+
html =<<HTML
|
65
|
+
<object width="425" height="344">
|
66
|
+
<param name="movie" value="http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&"></param>
|
67
|
+
<param name="allowFullScreen" value="true"></param>
|
68
|
+
<param name="allowscriptaccess" value="always"></param>
|
69
|
+
<embed src="http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
|
70
|
+
</object>
|
71
|
+
HTML
|
72
|
+
|
73
|
+
doc = to_doc html
|
74
|
+
obj = doc.css("object").first.to_fuzzy_hash.should == {width: '425', height: '344'}
|
75
|
+
p1, p2, p3, embed = doc.css('object *')
|
76
|
+
p1.to_fuzzy_hash.should == {name: 'movie', value: 'http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&'}
|
77
|
+
p2.to_fuzzy_hash.should == {name: 'allowFullScreen', value: 'true'}
|
78
|
+
p3.to_fuzzy_hash.should == {name: 'allowscriptaccess', value: 'always'}
|
79
|
+
embed.to_fuzzy_hash.should == {
|
80
|
+
src: 'http://www.youtube.com/v/s8hYKKXV5wU&hl=en_US&fs=1&',
|
81
|
+
type: 'application/x-shockwave-flash',
|
82
|
+
allowscriptaccess: 'always',
|
83
|
+
allowfullscreen: 'true',
|
84
|
+
width: '425',
|
85
|
+
height: '344'
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|