ghazel-truncate_html 0.2.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ coverage
data/README.markdown ADDED
@@ -0,0 +1,53 @@
1
+ TruncateHtml
2
+ ============
3
+
4
+ truncate_html is a Rails helper plugin that [cuts off](http://www.youtube.com/watch?v=6XG4DIOA7nU) a string of HTML and takes care of closing any lingering open tags. There are many possible solutions to this. This plugin does not have any dependencies, and does all it's work via [regular expressions](http://xkcd.com/208/).
5
+
6
+ The API is very similar to Rails' own truncate method.
7
+
8
+
9
+ Example
10
+ -------
11
+
12
+ some_html = '<ul><li><a href="http://whatever">This is a link</a></li></ul>'
13
+
14
+ truncate_html(some_html, :length => 5, :omission => '...(continued)')
15
+
16
+ => <ul><li><a href="http://whatever">This is...(continued)</a></li></ul>
17
+
18
+
19
+ A few notes:
20
+
21
+ * It will truncate on a word boundary.
22
+ * The default options are:
23
+ * :length => 100
24
+ * :omission => '...'
25
+
26
+ Installation
27
+ ------------
28
+
29
+ #### As a gem
30
+ Add this to your <code>config/environment.rb</code>:
31
+
32
+ config.gem 'truncate_html',
33
+ :source => 'http://gemcutter.org'
34
+
35
+ Then either
36
+ <code>sudo rake gems:install</code>
37
+ or
38
+ <code>sudo gem install truncate_html</code>
39
+
40
+ #### As a plugin:
41
+ <code>script/plugin install git://github.com/hgimenez/truncate_html.git</code>
42
+
43
+ Issues
44
+ ------
45
+
46
+ Found an issue? Please report it on [Github's issue tracker](http://github.com/hgimenez/truncate_html/issues).
47
+
48
+ Testing
49
+ -------
50
+
51
+ The plugin is tested using RSpec. [Install it](http://wiki.github.com/dchelimsky/rspec/rails) on your app if you wish to run the tests.
52
+
53
+ Copyright (c) 2009 Harold A. Giménez, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc 'Run the specs'
8
+ Spec::Rake::SpecTask.new(:spec) do |t|
9
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
10
+ t.spec_files = FileList['spec/**/*_spec.rb']
11
+ end
12
+
13
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
14
+ spec.libs << 'lib' << 'spec'
15
+ spec.pattern = 'spec/**/*_spec.rb'
16
+ spec.rcov = true
17
+ end
18
+
19
+ begin
20
+ require 'jeweler'
21
+ Jeweler::Tasks.new do |gem|
22
+ gem.name = "truncate_html"
23
+ gem.summary = %Q{Uses an API similar to Rails' truncate helper to truncate HTML and close any lingering open tags.}
24
+ gem.description = %Q{Truncates html so you don't have to}
25
+ gem.email = "harold.gimenez@gmail.com"
26
+ gem.homepage = "http://github.com/hgimenez/truncate_html"
27
+ gem.authors = ["hgimenez"]
28
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
29
+ end
30
+ Jeweler::GemcutterTasks.new
31
+
32
+ rescue LoadError
33
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
34
+ end
35
+
36
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'truncate_html'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,7 @@
1
+ module TruncateHtmlHelper
2
+
3
+ def truncate_html(html, options={})
4
+ TruncateHtml::HtmlTruncator.new(html).truncate(options)
5
+ end
6
+
7
+ end
@@ -0,0 +1,10 @@
1
+ path = File.join(File.dirname(__FILE__), 'app', 'helpers')
2
+ $LOAD_PATH << path
3
+ ActiveSupport::Dependencies.load_paths << path
4
+ ActiveSupport::Dependencies.load_once_paths.delete(path)
5
+
6
+ require File.join(File.dirname(__FILE__), 'truncate_html', 'html_truncator')
7
+
8
+ ActionView::Base.class_eval do
9
+ include TruncateHtmlHelper
10
+ end
@@ -0,0 +1,74 @@
1
+ module TruncateHtml
2
+ class HtmlTruncator
3
+
4
+ UNPAIRED_TAGS = %w(br hr img)
5
+
6
+ def initialize(original_html)
7
+ @original_html = original_html
8
+ end
9
+
10
+ def truncate(options = {})
11
+ return '' if @original_html.nil?
12
+ options[:length] ||= 100
13
+ options[:omission] ||= '...'
14
+ @chars_remaining = options[:length] - options[:omission].length
15
+ @open_tags, result = [], ['']
16
+
17
+ html_tokens.each do |str|
18
+ if @chars_remaining > 0
19
+ if html_tag?(str)
20
+ if open_tag?(str)
21
+ @open_tags << str
22
+ else
23
+ open_tags = remove_latest_open_tag(str)
24
+ end
25
+ else
26
+ @chars_remaining -= str.length
27
+ end
28
+ result << str
29
+ else
30
+ result[-1] = result[-1].rstrip + options[:omission]
31
+ @open_tags.reverse_each do |open_tag|
32
+ result << matching_close_tag(open_tag)
33
+ end
34
+ break
35
+ end
36
+ end
37
+ result.join('')
38
+ end
39
+
40
+ def html_tokens
41
+ @original_html.scan(/(?:<script.*>.*<\/script>)+|<\/?[^>]+>|[\w\|`~!@#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+/).map do
42
+ |t| t.gsub(
43
+ #remove newline characters
44
+ /\n/,''
45
+ ).gsub(
46
+ #clean out extra consecutive whitespace
47
+ /\s+/, ' '
48
+ )
49
+ end
50
+ end
51
+
52
+ def html_tag?(string)
53
+ string =~ /<\/?[^>]+>/ ? true : false
54
+ end
55
+
56
+ def open_tag?(html_tag)
57
+ html_tag =~ /<(?!(?:#{UNPAIRED_TAGS.join('|')}|script|\/))[^>]+>/i ? true : false
58
+ end
59
+
60
+ def remove_latest_open_tag(close_tag)
61
+ (0...@open_tags.length).to_a.reverse.each do |i|
62
+ if matching_close_tag(@open_tags[i]) == close_tag
63
+ @open_tags.delete_at(i)
64
+ break
65
+ end
66
+ end
67
+ end
68
+
69
+ def matching_close_tag(open_tag)
70
+ open_tag.gsub(/<(\w+)\s?.*>/, '</\1>').strip
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,113 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ include TruncateHtmlHelper
4
+
5
+ describe TruncateHtmlHelper do
6
+
7
+ it 'is included in ActionView::Base' do
8
+ ActionView::Base.included_modules.should include(TruncateHtmlHelper)
9
+ end
10
+
11
+ describe '#truncate_html' do
12
+
13
+ it "includes the omission text's length in the returned truncated html" do
14
+ truncate_html('a b c', :length => 4, :omission => '...').should == 'a...'
15
+ end
16
+
17
+ it "supports omisions longer than the maximum length" do
18
+ truncate_html('a b c', :length => 2, :omission => '...').should == '...'
19
+ end
20
+
21
+ context 'the input html is nil' do
22
+ it 'returns an empty string' do
23
+ truncate_html(nil).should be_empty
24
+ truncate_html(nil).should be_kind_of(String)
25
+ end
26
+ end
27
+
28
+ context 'the input html contains a script tag' do
29
+ before(:each) do
30
+ @input_html = "<p>I have a script <script type=text/javascript>document.write('lum dee dum');</script> and more text</p>"
31
+ @expected_out = "<p>I have a script <script type=text/javascript>document.write('lum dee dum');</script> and...</p>"
32
+ end
33
+ it 'treats the script tag as lengthless string' do
34
+ truncate_html(@input_html, :length => 23).should == @expected_out
35
+ end
36
+ end
37
+
38
+ context 'truncating in the middle of a link' do
39
+ before(:each) do
40
+ @html = '<div><ul><li>Look at <a href="foo">this</a> link </li></ul></div>'
41
+ end
42
+
43
+ it 'truncates, and closes the <a>, and closes any remaining open tags' do
44
+ truncate_html(@html, :length => 14).should == '<div><ul><li>Look at <a href="foo">this...</a></li></ul></div>'
45
+ end
46
+ end
47
+
48
+ %w(! @ # $ % ^ & * \( \) - _ + = [ ] { } \ | , . / ?).each do |char|
49
+ context "when the html has a #{char} character after a closing tag" do
50
+ before(:each) do
51
+ @html = "<p>Look at <strong>this</strong>#{char} More words here</p>"
52
+ end
53
+ it 'places the punctuation after the tag without any whitespace' do
54
+ truncate_html(@html, :length => 19).should == "<p>Look at <strong>this</strong>#{char} More...</p>"
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'when the html has a non punctuation character after a closing tag' do
60
+ before(:each) do
61
+ @html = '<p>Look at <a href="awesomeful.net">this</a> link for randomness</p>'
62
+ end
63
+ it 'leaves a whitespace between the closing tag and the following word character' do
64
+ truncate_html(@html, :length => 21).should == '<p>Look at <a href="awesomeful.net">this</a> link...</p>'
65
+ end
66
+ end
67
+
68
+ #unusual, but just covering my ass
69
+ context 'when the HTML tags are multiline' do
70
+ before(:each) do
71
+ @html = <<-END_HTML
72
+ <div id="foo"
73
+ class="bar">
74
+ This is ugly html.
75
+ </div>
76
+ END_HTML
77
+ end
78
+
79
+ it 'recognizes the multiline html properly' do
80
+ truncate_html(@html, :length => 12).should == ' <div id="foo" class="bar"> This is...</div>'
81
+ end
82
+ end
83
+
84
+ %w(br hr img).each do |unpaired_tag|
85
+ context "when the html contains a #{unpaired_tag} tag" do
86
+
87
+ context "and the #{unpaired_tag} does not have the closing slash" do
88
+ before(:each) do
89
+ @html = "<div>Some before. <#{unpaired_tag}>and some after</div>"
90
+ @html_caps = "<div>Some before. <#{unpaired_tag.capitalize}>and some after</div>"
91
+ end
92
+ it "does not close the #{unpaired_tag} tag" do
93
+ truncate_html(@html, :length => 19).should == "<div>Some before. <#{unpaired_tag}>and...</div>"
94
+ truncate_html(@html_caps, :length => 19).should == "<div>Some before. <#{unpaired_tag.capitalize}>and...</div>"
95
+ end
96
+ end
97
+
98
+ context "and the #{unpaired_tag} does have the closing slash" do
99
+ before(:each) do
100
+ @html = "<div>Some before. <#{unpaired_tag} />and some after</div>"
101
+ @html_caps = "<div>Some before. <#{unpaired_tag.capitalize} />and some after</div>"
102
+ end
103
+ it "does not close the #{unpaired_tag} tag" do
104
+ truncate_html(@html, :length => 19).should == "<div>Some before. <#{unpaired_tag} />and...</div>"
105
+ truncate_html(@html_caps, :length => 19).should == "<div>Some before. <#{unpaired_tag.capitalize} />and...</div>"
106
+ end
107
+ end
108
+
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
3
+ rescue LoadError
4
+ puts "You need to install rspec in your base app"
5
+ exit
6
+ end
7
+
8
+ plugin_spec_dir = File.dirname(__FILE__)
9
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'app', 'helpers', 'truncate_html_helper')
@@ -0,0 +1,75 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ describe TruncateHtml::HtmlTruncator do
4
+
5
+ def truncator(html = nil)
6
+ @truncator ||= TruncateHtml::HtmlTruncator.new(html)
7
+ end
8
+
9
+ describe '#html_tokens' do
10
+ before(:each) do
11
+ @html = '<h1>Hi there</h1> <p>This is sweet!</p>'
12
+ end
13
+
14
+ it 'returns each token in the string as an array element removing any consecutive whitespace from the string' do
15
+ truncator(@html).html_tokens.should == ['<h1>', 'Hi', ' ', 'there', '</h1>', ' ', '<p>', 'This', ' ', 'is', ' ', 'sweet!', '</p>']
16
+ end
17
+
18
+ end
19
+
20
+ describe '#html_tag?' do
21
+
22
+ it 'returns false when the string parameter is not an html tag' do
23
+ truncator.html_tag?('no tags').should be_false
24
+ end
25
+
26
+ it 'returns true when the string parameter is an html tag' do
27
+ truncator.html_tag?('<img src="foo">').should be_true
28
+ truncator.html_tag?('</img>').should be_true
29
+ end
30
+
31
+ end
32
+
33
+ describe '#open_tag?' do
34
+
35
+ it 'returns true if the tag is an open tag' do
36
+ truncator.open_tag?('<a>').should be_true
37
+ end
38
+
39
+ it 'returns true if the tag is an open tag, and has whitespace and html properties with either single or double quotes' do
40
+ truncator.open_tag?(' <a href="http://awesomeful.net">').should be_true
41
+ truncator.open_tag?(" <a href='http://awesomeful.net' >").should be_true
42
+ end
43
+
44
+ it 'returns false if the tag is a close tag' do
45
+ truncator.open_tag?('</a>').should be_false
46
+ end
47
+
48
+ it 'returns false if the string is not an html tag' do
49
+ truncator.open_tag?('foo bar').should be_false
50
+ end
51
+
52
+ it 'returns false if it is a <script> tag' do
53
+ truncator.open_tag?('<script>').should be_false
54
+ end
55
+ end
56
+
57
+ describe '#matching_close_tag' do
58
+
59
+ it 'closes a tag given an open tag' do
60
+ truncator.matching_close_tag('<a>').should == '</a>'
61
+ truncator.matching_close_tag(' <div>').should == '</div>'
62
+ truncator.matching_close_tag('<h1>').should == '</h1>'
63
+ truncator.matching_close_tag('<a href="foo">').should == '</a>'
64
+ end
65
+ end
66
+
67
+ describe 'nil string' do
68
+
69
+ it 'returns an empty string' do
70
+ truncator(nil).truncate.should be_empty
71
+ truncator(nil).truncate.should be_kind_of(String)
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :truncate_html do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ghazel-truncate_html}
8
+ s.version = "0.2.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["hgimenez"]
12
+ s.date = %q{2009-12-18}
13
+ s.description = %q{Truncates html so you don't have to}
14
+ s.email = %q{harold.gimenez@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "init.rb",
24
+ "install.rb",
25
+ "lib/app/helpers/truncate_html_helper.rb",
26
+ "lib/truncate_html.rb",
27
+ "lib/truncate_html/html_truncator.rb",
28
+ "spec/helpers/truncate_html_helper_spec.rb",
29
+ "spec/spec_helper.rb",
30
+ "spec/truncate_html/html_truncator_spec.rb",
31
+ "tasks/truncate_html_tasks.rake",
32
+ "truncate_html.gemspec",
33
+ "uninstall.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/hgimenez/truncate_html}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{Uses an API similar to Rails' truncate helper to truncate HTML and close any lingering open tags.}
40
+ s.test_files = [
41
+ "spec/helpers/truncate_html_helper_spec.rb",
42
+ "spec/spec_helper.rb",
43
+ "spec/truncate_html/html_truncator_spec.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ghazel-truncate_html
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1.1
5
+ platform: ruby
6
+ authors:
7
+ - hgimenez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-18 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Truncates html so you don't have to
17
+ email: harold.gimenez@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - .gitignore
26
+ - README.markdown
27
+ - Rakefile
28
+ - VERSION
29
+ - init.rb
30
+ - install.rb
31
+ - lib/app/helpers/truncate_html_helper.rb
32
+ - lib/truncate_html.rb
33
+ - lib/truncate_html/html_truncator.rb
34
+ - spec/helpers/truncate_html_helper_spec.rb
35
+ - spec/spec_helper.rb
36
+ - spec/truncate_html/html_truncator_spec.rb
37
+ - tasks/truncate_html_tasks.rake
38
+ - truncate_html.gemspec
39
+ - uninstall.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/hgimenez/truncate_html
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Uses an API similar to Rails' truncate helper to truncate HTML and close any lingering open tags.
68
+ test_files:
69
+ - spec/helpers/truncate_html_helper_spec.rb
70
+ - spec/spec_helper.rb
71
+ - spec/truncate_html/html_truncator_spec.rb