trunction 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in trunction.gemspec
4
+ gemspec
5
+
6
+ gem "rake"
7
+ gem "rspec"
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :spec
4
+
5
+ require "rspec/core/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new do |t|
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
@@ -0,0 +1,3 @@
1
+ module Trunction
2
+ VERSION = "0.0.1"
3
+ end
data/lib/trunction.rb ADDED
@@ -0,0 +1,71 @@
1
+ require "trunction/version"
2
+ require "nokogiri"
3
+
4
+ module Trunction
5
+
6
+ extend self
7
+
8
+ def truncate_html(html, max)
9
+ doc = Nokogiri::HTML::DocumentFragment.parse(html)
10
+ Truncation.new(doc, max).execute
11
+ doc.to_html
12
+ end
13
+
14
+ class Truncation
15
+
16
+ def initialize(doc, max)
17
+ @doc = doc
18
+ @max = max
19
+ @chars_remaining = max
20
+ end
21
+
22
+ def execute
23
+ find_the_end
24
+ remove_everything_else
25
+ end
26
+
27
+ private
28
+
29
+ def find_the_end
30
+ catch(:done) do
31
+ @doc.traverse do |node|
32
+ accumulate_text(node) if node.text?
33
+ record(node)
34
+ end
35
+ end
36
+ end
37
+
38
+ def accumulate_text(text_node)
39
+ @chars_remaining -= text_node.text.length
40
+ throw(:done) if limit_reached?
41
+ end
42
+
43
+ def limit_reached?
44
+ @chars_remaining <= 0
45
+ end
46
+
47
+ def record(node)
48
+ @last_block_element = node if block?(node)
49
+ @last_element = node
50
+ end
51
+
52
+ def last_node
53
+ @last_block_element || @last_element
54
+ end
55
+
56
+ def block?(node)
57
+ node.description && node.description.block?
58
+ end
59
+
60
+ def remove_everything_else
61
+ node = last_node
62
+ while node
63
+ node.next.remove while node.next
64
+ break unless node.respond_to?(:parent)
65
+ node = node.parent
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,5 @@
1
+ require "rspec"
2
+
3
+ RSpec.configure do |config|
4
+
5
+ end
@@ -0,0 +1,92 @@
1
+ require 'trunction'
2
+
3
+ describe Trunction do
4
+
5
+ let(:total_length) { Nokogiri::HTML::DocumentFragment.parse(input).text.length }
6
+ let(:ellipsis) { "&#8230;" }
7
+
8
+ include Trunction
9
+
10
+ let(:result) do
11
+ truncate_html(input, max_length).gsub("\n", '')
12
+ end
13
+
14
+ describe "#truncate_html" do
15
+
16
+ context "given multiple paragraphs" do
17
+
18
+ let(:input) { "<p>one</p><p>two</p><p>three</p>" }
19
+
20
+ context "with max-length longer than input" do
21
+
22
+ let(:max_length) { total_length + 1 }
23
+
24
+ it "returns input intact" do
25
+ result.should == input
26
+ end
27
+
28
+ end
29
+
30
+ context "with max-length shorter than input" do
31
+
32
+ let(:max_length) { total_length - 1 }
33
+
34
+ it "drops elements until beneath max-length" do
35
+ result.should == "<p>one</p><p>two</p>"
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ context "given multiple paragraphs, wrapped in a div" do
43
+
44
+ let(:input) { "<div><p>one</p><p>two</p><p>three</p></div>" }
45
+
46
+ context "with max-length shorter than input" do
47
+
48
+ let(:max_length) { total_length - 1 }
49
+
50
+ it "drops elements until beneath max-length" do
51
+ result.should == "<div><p>one</p><p>two</p></div>"
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ context "a single paragraph with inline elements" do
59
+
60
+ let(:input) { "<p><b>one</b>, <b>two</b>, <b>three</b>, <b>four</b></p>" }
61
+
62
+ context "with max-length shorter than input" do
63
+
64
+ let(:max_length) { total_length - 1 }
65
+
66
+ it "drops the last word" do
67
+ result.should == "<p><b>one</b>, <b>two</b>, <b>three</b>, </p>"
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ context "a final paragraph with inline elements" do
75
+
76
+ let(:input) { "<p>one</p><p>two</p><p><b>one</b>, <b>two</b>, <b>three</b>, <b>four</b></p>" }
77
+
78
+ context "with max-length shorter than input" do
79
+
80
+ let(:max_length) { total_length - 1 }
81
+
82
+ it "drops the entire final paragraph" do
83
+ result.should == "<p>one</p><p>two</p>"
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ end
data/trunction.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "trunction/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "trunction"
7
+ s.version = Trunction::VERSION
8
+ s.authors = ["Mike Williams"]
9
+ s.email = ["mdub@dogbiscuit.org"]
10
+ s.homepage = ""
11
+ s.summary = %q{Beat your HTML down to size}
12
+ s.description = %q{Trunction implements intelligent truncation of HTML text.}
13
+
14
+ s.rubyforge_project = "trunction"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "nokogiri"
22
+
23
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trunction
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: &70261283968360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70261283968360
25
+ description: Trunction implements intelligent truncation of HTML text.
26
+ email:
27
+ - mdub@dogbiscuit.org
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - Rakefile
35
+ - lib/trunction.rb
36
+ - lib/trunction/version.rb
37
+ - spec/spec_helper.rb
38
+ - spec/trunction_spec.rb
39
+ - trunction.gemspec
40
+ homepage: ''
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project: trunction
60
+ rubygems_version: 1.8.10
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Beat your HTML down to size
64
+ test_files:
65
+ - spec/spec_helper.rb
66
+ - spec/trunction_spec.rb