html_truncator 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +19 -8
  2. data/lib/html_truncator.rb +32 -17
  3. metadata +3 -3
data/README.md CHANGED
@@ -14,19 +14,19 @@ It's very simple. Install it with rubygems:
14
14
 
15
15
  Or, if you use bundler, add it to your `Gemfile`:
16
16
 
17
- gem "html_truncator", :version => "~>0.1"
17
+ gem "html_truncator", :version => "~>0.2"
18
18
 
19
19
  Then you can use it in your code:
20
20
 
21
21
  require "html_truncator"
22
22
  HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3)
23
- # => "<p>Lorem ipsum dolor...</p>"
23
+ # => "<p>Lorem ipsum dolor…</p>"
24
24
 
25
25
  The HTML_Truncator class has only one method, `truncate`, with 3 arguments:
26
26
 
27
27
  * the HTML-formatted string to truncate
28
28
  * the number of words to keep (real words, tags and attributes aren't count)
29
- * the ellipsis (optional, '...' by default).
29
+ * some options like the ellipsis (optional, '' by default).
30
30
 
31
31
  And an attribute, `ellipsable_tags`, which lists the tags that can contain the ellipsis
32
32
  (by default: p ol ul li div header article nav section footer aside dd dt dl).
@@ -38,33 +38,43 @@ Examples
38
38
  A simple example:
39
39
 
40
40
  HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3)
41
- # => "<p>Lorem ipsum dolor...</p>"
41
+ # => "<p>Lorem ipsum dolor…</p>"
42
42
 
43
43
  If the text is too short to be truncated, it won't be modified:
44
44
 
45
45
  HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 5)
46
46
  # => "<p>Lorem ipsum dolor sit amet.</p>"
47
47
 
48
+ If you prefer, you can have the length in characters instead of words:
49
+
50
+ HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 12, :length_in_chars => true)
51
+ # => "<p>Lorem ipsum …</p>"
52
+
48
53
  You can customize the ellipsis:
49
54
 
50
- HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, " (truncated)")
55
+ HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, :ellipsis => " (truncated)")
51
56
  # => "<p>Lorem ipsum dolor (truncated)</p>"
52
57
 
53
58
  And even have HTML in the ellipsis:
54
59
 
55
- HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, '<a href="/more-to-read">...</a>')
60
+ HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, :ellipsis => '<a href="/more-to-read">...</a>')
56
61
  # => "<p>Lorem ipsum dolor<a href="/more-to-read">...</a></p>"
57
62
 
58
63
  The ellipsis is put at the right place, inside `<p>`, but not `<i>`:
59
64
 
60
65
  HTML_Truncator.truncate("<p><i>Lorem ipsum dolor sit amet.</i></p>", 3)
61
- # => "<p><i>Lorem ipsum dolor</i>...</p>"
66
+ # => "<p><i>Lorem ipsum dolor</i>…</p>"
62
67
 
63
68
  You can indicate that a tag can contain the ellipsis but adding it to the ellipsable_tags:
64
69
 
65
70
  HTML_Truncator.ellipsable_tags << "blockquote"
66
71
  HTML_Truncator.truncate("<blockquote>Lorem ipsum dolor sit amet.</blockquote>", 3)
67
- # => "<blockquote>Lorem ipsum dolor...</blockquote>"
72
+ # => "<blockquote>Lorem ipsum dolor…</blockquote>"
73
+
74
+ You can know if a string was truncated with the `html_truncated?` method:
75
+
76
+ HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3).html_truncated?
77
+ # => true
68
78
 
69
79
 
70
80
  Alternatives
@@ -102,5 +112,6 @@ Credits
102
112
  -------
103
113
 
104
114
  Thanks to François de Metz for his awesome help!
115
+ Thanks to [kuroir](https://github.com/kuroir) and [benhutton](https://github.com/benhutton) for their suggestions.
105
116
 
106
117
  Copyright (c) 2011 Bruno Michel <bmichel@menfin.info>, released under the MIT license
@@ -1,11 +1,19 @@
1
+ # encoding: utf-8
2
+
1
3
  require "nokogiri"
2
4
  require "set"
3
5
 
4
6
 
5
7
  class HTML_Truncator
6
- def self.truncate(text, max_words, ellipsis="...")
8
+ DEFAULT_OPTIONS = { :ellipsis => "", :length_in_chars => false }
9
+
10
+ def self.truncate(text, max, opts={})
11
+ return truncate(text, max, :ellipsis => opts) if String === opts
12
+ opts = DEFAULT_OPTIONS.merge(opts)
7
13
  doc = Nokogiri::HTML::DocumentFragment.parse(text)
8
- doc.truncate(max_words, ellipsis).first
14
+ str, _, opts = doc.truncate(max, opts)
15
+ eval "class <<str; def html_truncated?; #{opts[:was_truncated]} end end"
16
+ str
9
17
  end
10
18
 
11
19
  class <<self
@@ -22,28 +30,29 @@ class Nokogiri::HTML::DocumentFragment
22
30
  end
23
31
 
24
32
  class Nokogiri::XML::Node
25
- def truncate(max_words, ellipsis)
26
- return ["", 1, ellipsis] if max_words == 0 && !ellipsable?
27
- inner, remaining, ellipsis = inner_truncate(max_words, ellipsis)
33
+ def truncate(max, opts)
34
+ return ["", 1, opts] if max == 0 && !ellipsable?
35
+ inner, remaining, opts = inner_truncate(max, opts)
28
36
  children.remove
29
37
  add_child Nokogiri::HTML::DocumentFragment.parse(inner)
30
- [to_xml(:indent => 0), max_words - remaining, ellipsis]
38
+ [to_html(:indent => 0), max - remaining, opts]
31
39
  end
32
40
 
33
- def inner_truncate(max_words, ellipsis)
34
- inner, remaining = "", max_words
41
+ def inner_truncate(max, opts)
42
+ inner, remaining = "", max
35
43
  self.children.each do |node|
36
- txt, nb, ellipsis = node.truncate(remaining, ellipsis)
44
+ txt, nb, opts = node.truncate(remaining, opts)
37
45
  remaining -= nb
38
46
  inner += txt
39
47
  next if remaining >= 0
40
48
  if ellipsable?
41
- inner += ellipsis
42
- ellipsis = ""
49
+ inner += opts[:ellipsis]
50
+ opts[:ellipsis] = ""
51
+ opts[:was_truncated] = true
43
52
  end
44
53
  break
45
54
  end
46
- [inner, remaining, ellipsis]
55
+ [inner, remaining, opts]
47
56
  end
48
57
 
49
58
  def ellipsable?
@@ -52,10 +61,16 @@ class Nokogiri::XML::Node
52
61
  end
53
62
 
54
63
  class Nokogiri::XML::Text
55
- def truncate(max_words, ellipsis)
56
- words = content.split
57
- nb_words = words.length
58
- return [to_xhtml, nb_words, ellipsis] if nb_words <= max_words && max_words > 0
59
- [words.slice(0, max_words).join(' '), nb_words, ellipsis]
64
+ def truncate(max, opts)
65
+ if opts[:length_in_chars]
66
+ count = content.length
67
+ return [to_xhtml, count, opts] if count <= max && max > 0
68
+ [content.slice(0, max), count, opts]
69
+ else
70
+ words = content.split
71
+ count = words.length
72
+ return [to_xhtml, count, opts] if count <= max && max > 0
73
+ [words.slice(0, max).join(' '), count, opts]
74
+ end
60
75
  end
61
76
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
7
  - 2
9
- version: 0.1.2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Bruno Michel
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-14 00:00:00 +01:00
17
+ date: 2011-01-28 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency