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.
Files changed (71) hide show
  1. data/lib/components/captcha.rb +24 -0
  2. data/lib/components/captcha.yml +2 -0
  3. data/lib/kit/{http_controller → controller}/authorized.rb +1 -1
  4. data/lib/kit/controller/captcha.rb +23 -0
  5. data/lib/kit/{http_controller → controller}/localized.rb +1 -1
  6. data/lib/kit/controller.rb +5 -0
  7. data/lib/kit/gems.rb +10 -6
  8. data/lib/kit/i18n/locales/ru/pluralization.rb +62 -0
  9. data/lib/kit/i18n.rb +16 -0
  10. data/lib/kit/kit.rb +10 -7
  11. data/lib/kit/kit_text_utils.rb +30 -0
  12. data/lib/kit/misc/prepare_model.rb +16 -0
  13. data/lib/kit/misc/user_error.rb +12 -0
  14. data/lib/kit/models/attachments_uploader_helper.rb +1 -1
  15. data/lib/kit/models/authorized.rb +6 -8
  16. data/lib/kit/models/authorized_object.rb +3 -4
  17. data/lib/kit/models/{micelaneous.rb → miscellaneous.rb} +0 -0
  18. data/lib/kit/models_after.rb +1 -1
  19. data/lib/kit/mongoid/{rad_micelaneous.rb → rad_miscellaneous.rb} +1 -1
  20. data/lib/kit/mongoid/text_processor.rb +1 -1
  21. data/lib/kit/mongoid.rb +2 -2
  22. data/lib/kit/spec.rb +1 -2
  23. data/lib/kit/tasks.rb +1 -1
  24. data/lib/text_utils/code_highlighter.rb +75 -0
  25. data/lib/text_utils/custom_markdown.rb +64 -0
  26. data/lib/text_utils/ensure_utf.rb +14 -0
  27. data/lib/text_utils/format_qualifier.rb +13 -0
  28. data/lib/{kit/text_utils → text_utils}/html_sanitizer.rb +8 -6
  29. data/lib/text_utils/markdown.rb +33 -0
  30. data/lib/text_utils/pipe.rb +16 -0
  31. data/lib/text_utils/processor.rb +14 -0
  32. data/lib/text_utils/support.rb +15 -0
  33. data/lib/text_utils/truncate.rb +30 -0
  34. data/lib/text_utils.rb +23 -0
  35. data/readme.md +1 -8
  36. data/spec/controller/authorization_spec.rb +1 -1
  37. data/spec/controller/captcha_spec.rb +66 -0
  38. data/spec/i18n/i18n_spec/locales/en/general.yml +5 -0
  39. data/spec/i18n/i18n_spec/locales/ru/general.yml +7 -0
  40. data/spec/i18n/i18n_spec.rb +32 -0
  41. data/spec/misc/kit_text_utils_spec.rb +29 -0
  42. data/spec/misc/prepare_model_spec.rb +37 -0
  43. data/spec/misc/user_error_spec.rb +38 -0
  44. data/spec/models/authorized_object_spec.rb +10 -3
  45. data/spec/spec_helper/factories.rb +4 -0
  46. data/spec/spec_helper/user.rb +2 -3
  47. data/spec/spec_helper.rb +0 -5
  48. data/spec/text_utils/code_highlighter_spec.rb +38 -0
  49. data/spec/text_utils/custom_markdown_spec.rb +82 -0
  50. data/spec/text_utils/format_qualifier_spec.rb +37 -0
  51. data/spec/text_utils/html_sanitizer_spec.rb +88 -0
  52. data/spec/text_utils/markdown_spec.rb +114 -0
  53. data/spec/text_utils/pipe_spec.rb +35 -0
  54. data/spec/text_utils/spec_helper.rb +26 -0
  55. data/spec/text_utils/text_processor_shared.rb +9 -0
  56. data/spec/text_utils/truncate_spec.rb +22 -0
  57. metadata +57 -47
  58. data/lib/kit/http_controller.rb +0 -4
  59. data/lib/kit/text_utils/code_highlighter.rb +0 -58
  60. data/lib/kit/text_utils/custom_markdown.rb +0 -90
  61. data/lib/kit/text_utils/ensure_utf.rb +0 -8
  62. data/lib/kit/text_utils/github_flavoured_markdown.rb +0 -32
  63. data/lib/kit/text_utils/image_box.rb +0 -35
  64. data/lib/kit/text_utils/markup.rb +0 -43
  65. data/lib/kit/text_utils/processor.rb +0 -25
  66. data/lib/kit/text_utils/tag_shortcuts.rb +0 -14
  67. data/lib/kit/text_utils/truncate.rb +0 -29
  68. data/lib/kit/text_utils/truncator.rb +0 -15
  69. data/lib/kit/text_utils/urls.rb +0 -13
  70. data/lib/kit/text_utils.rb +0 -43
  71. 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,14 @@
1
+ class TextUtils::Processor
2
+ def initialize next_processor = nil
3
+ @next_processor = next_processor
4
+ end
5
+
6
+ protected
7
+ def call_next data, env
8
+ if @next_processor
9
+ @next_processor.call data, env
10
+ else
11
+ data
12
+ end
13
+ end
14
+ 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
@@ -1,10 +1,3 @@
1
1
  # Rapid Application Development Kit for Rad Framework
2
2
 
3
- [add docs]
4
-
5
- # Low
6
-
7
- - WYSIWYG from WordPress/GitHub
8
- - remove unused locale tokens
9
-
10
- # TODO
3
+ [add docs]
@@ -15,7 +15,7 @@ describe "Authorizations" do
15
15
  class ::AuthorizationController
16
16
  inherit Rad::Controller::Http
17
17
 
18
- inherit Rad::Controller::Http::Authorized
18
+ inherit Rad::Controller::Authorized
19
19
 
20
20
  require_permission :call_controller_level, only: :controller_level
21
21
 
@@ -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,5 @@
1
+ en:
2
+ name: "Name"
3
+ comments:
4
+ one: "%{count} comment"
5
+ many: "%{count} comments"
@@ -0,0 +1,7 @@
1
+ ru:
2
+ name: "Имя"
3
+ comments_count:
4
+ one: "%{count} комментарий"
5
+ few: "%{count} комментария"
6
+ many: "%{count} комментариев"
7
+ other: "%{count} комментариев"
@@ -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
@@ -11,6 +11,10 @@ Factory.define :user, class: 'Models::User' do |u|
11
11
  u.sequence(:name){|i| "user#{i}"}
12
12
  end
13
13
 
14
+ Factory.define :registered, parent: :user do |u|
15
+ u.name 'alex'
16
+ end
17
+
14
18
  Factory.define :admin, parent: :user do |u|
15
19
  u.admin true
16
20
  end
@@ -5,9 +5,8 @@ class Models::User
5
5
 
6
6
  include Mongoid::Authorized
7
7
 
8
- def anonymous?
9
- name == 'anonymous'
10
- end
8
+ # def self.anonymous_name; 'anonymous' end
9
+ # def anonymous?; name == self.class.anonymous_name end
11
10
 
12
11
  class << self
13
12
  def avatar_url *a; end
data/spec/spec_helper.rb CHANGED
@@ -3,11 +3,6 @@ require 'rspec_ext'
3
3
  require 'rad'
4
4
  require 'rad/spec'
5
5
 
6
- require 'rad_ext'
7
- require 'rad_ext/spec'
8
-
9
- # require 'mongoid_rad'
10
-
11
6
  require 'kit/spec'
12
7
 
13
8
  # rad.config.runtime_path = 'tmp'
@@ -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