html_slicer 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ == 0.0.7
2
+
3
+ * Code refactoring.
4
+
5
+ == 0.0.6
6
+
7
+ * New feature: Now you can resize HTML tags through ‘style=’ attribute.
8
+
9
+ == 0.0.5
10
+
11
+ * Some improvements :)
12
+
1
13
  == 0.0.4
2
14
 
3
15
  * Bug fixes: with param names again... sorry
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = HtmlSlicer
1
+ = html_slicer
2
2
 
3
3
  A little gem for Rails 3 helps you implement a smart way to split textual content. This is a quick approach to create ‘pageable’ views for ActiveRecord Model’s attributes, just independent strings, or any other Ruby classes. Or course it can split HTML content. More over, it can ‘resize’ HTML tags through <tt>width=</tt> attribute*.
4
4
 
@@ -51,7 +51,7 @@ Then bundle:
51
51
  slice <method_name>, <configuration>, [:config => <:style>]*
52
52
 
53
53
  where:
54
- * <method_name> - any method or local variable which returns source String (can be called with .send()).
54
+ * <method_name> - any method name which returns source String (can be called with .send()).
55
55
  * <configuration> - Hash of configuration options and/or +:config+ parameter.
56
56
 
57
57
  === Basic example
@@ -73,20 +73,18 @@ Console:
73
73
  @article = Article.find(1)
74
74
  @article.content
75
75
  # => "Words like violence break the silence\r\nCome crashing in into my little world\r\n<iframe width=\"560\" height=\"315\" src=\"http://www.youtube.com/embed/ms0bd_hCZsk\" frameborder=\"0\" allowfullscreen></iframe>\r\nPainful to me, pierce right through me\r\nCan't you understand, oh my little girl?"
76
-
76
+
77
77
  @article_paged = @article.paged
78
78
  # => "Words like violence bre"
79
-
80
- * the +nil+ argument assumes it is number +1+.
81
79
 
82
80
  @article_paged.slice!(2)
83
81
  # => "ak the silence"
84
-
85
- * the passed slice number is remembered.
86
-
82
+
87
83
  @article_paged.slice!(4)
88
84
  # => "rld
89
- <iframe width="300" height="169" src="http://www.youtube.com/embed/ms0bd_hCZsk" frameborder="0" allowfullscreen></iframe>"
85
+ <iframe width="300" height="169" src="http://www.youtube.com/embed/ms0bd_hCZsk" frameborder="0" allowfullscreen></iframe>"
86
+
87
+ The <tt>.slice!()</tt> method accepts number of slice (page). No argument (or +nil+) assumes it is number +1+. Passed slice number is remembered.
90
88
 
91
89
  === Configuration options
92
90
 
@@ -109,7 +107,7 @@ All configuration keys:
109
107
 
110
108
  * <tt>:unit</tt> is a +Regexp/String/Hash+ description of text units counted to split the text by slices.
111
109
  When value is a +Hash+, it assumes the unit is a HTML tag (look at <tt>:only/:except</tt> options for details).
112
- Undefined value or +nil+ assumes it by default Regexp /&#?\w+;|\S/. As you can see it counts any regular character or HTML special character as a unit.
110
+ Undefined value or +nil+ assumes it by default regular expression <tt>/&#?\w+;|\S/</tt>. As you can see it counts any regular character or HTML special character as a unit.
113
111
  * <tt>:maximum</tt> is a +Fixnum+ number of units to be a one slice.
114
112
 
115
113
  If +:unit+ defined as Regexp or String, default value is 300.
@@ -119,7 +117,7 @@ If +:unit+ defined as Hash, default value is 10.
119
117
  If +:unit+ is default, default value is 2000.
120
118
 
121
119
  * <tt>:complete</tt> is a +Regexp+ description of a character used to complete the slice.
122
- For example, if you want to end the slice with a complete word, using :complete => /s+|z/ the counter would continue the slice until the first whitespace character.
120
+ For example, if you want to end the slice with a complete word, using <tt>:complete => /s+|z/</tt> the counter would continue the slice until the first whitespace character.
123
121
  * <tt>:limit</tt> - a +Fixnum+ limit number of slices.
124
122
  In many cases we just need the first slice to perform it as a partial.
125
123
  * <tt>:text_break</tt> - a responsible <tt>.to_s</tt> value of text breaks between slices.
@@ -130,17 +128,17 @@ It can be an ellipsis or any other symbol.
130
128
  * Actually the hash is an argument for HTML::Conditions class (the part of ActionPack's html_scanner code). Look at http://github.com/rails/rails/blob/master/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
131
129
  This is a very flexible utility to navigate via HTML content. Read native documentation for details.
132
130
 
133
- For example: ID for <tt><hr class="break"> tag</tt> is a hash: <tt>{:tag => "hr", :attributes => {:class => "break"}}</tt>
131
+ For example: ID for <tt><hr class="break"></tt> tag is a hash: <tt>{:tag => "hr", :attributes => {:class => "break"}}</tt>
134
132
 
135
133
  === Resizing options
136
134
 
137
- * <tt>:width</tt> is a Fixnum number of pixels as a target value to squeeze the HTML tag. It does the resize automatically proportional with the +:height+ (if exists). The percentage values are ignored.
135
+ * <tt>:width</tt> is a Fixnum number of pixels as a target value to squeeze the HTML tag. It does the resize automatically proportional with the 'height=' (if the tag has one). The percentage values are ignored.
138
136
  * <tt>:only</tt> is a +Hash+ or +Array+ of hashes, describes which exactly nodes of HTML content to resize.
139
137
  * <tt>:except</tt> is a +Hash+ or +Array+ of hashes, describes which exactly nodes of HTML content NOT to resize.
140
138
 
141
139
  === Processors
142
140
 
143
- Processors are used to transform the source text before it is sliced. Many of us use various markup languages for dynamic contents. This is basically the same thing. Just create any class as a subclass of HtmlSlicer::Processor, put it in +/lib/html_slicer_processors+ directory and define its name within the +:processors+ option.
141
+ Processors are used to transform the source text before it is sliced. Many of us use various markup languages for dynamic contents. This is basically the same thing. Just create any class and inherit it from HtmlSlicer::Processor, put it in +/lib/html_slicer_processors+ directory and define its name within the +:processors+ option.
144
142
 
145
143
  Example:
146
144
 
@@ -310,14 +308,14 @@ Examples:
310
308
 
311
309
  === Slicing a general String or ActiveModel (or any other) object
312
310
 
313
- There is no apecific approach to it. Just extend target class to +HtmlSlicer::Installer+ and call the method slice as described before:
311
+ There is no apecific approach to it. Just extend target class to HtmlSlicer::Installer and call the method slice as described before:
314
312
 
315
313
  String.extend HtmlSlicer::Installer
316
314
  String.slice :to_s, :as => :page, :config => :for_string
317
315
 
318
316
  == Questions, Feedback
319
317
 
320
- Message me and I’ll do my best to help everybody. Github (addagger), no Twitter account, Facebook (http://www.facebook.com/profile.php?id=100002178326782)
318
+ Message me and I’ll do my best to help everybody. Github (addagger), no Twitter account, Facebook (http://www.facebook.com/valery.kvon)
321
319
 
322
320
 
323
321
  == Contributing to HtmlSlicer
data/html_slicer.gemspec CHANGED
@@ -10,10 +10,11 @@ Gem::Specification.new do |s|
10
10
  s.authors = ["Valery Kvon"]
11
11
  s.email = ["addagger@gmail.com"]
12
12
  s.homepage = %q{http://vkvon.ru/projects/html_slicer}
13
- s.summary = %q{HTML text slicer}
13
+ s.summary = %q{HTML text pagination for Ruby on Rails}
14
14
  s.description = %q{HtmlSlicer is a smart way to cut an HTML text into pieces. It also provides on option to resize "width"/"height" attributes of HTML tags, such as <iframe>, <object>, <img> or any other.}
15
15
 
16
16
  s.add_development_dependency "actionpack", ['>= 3.0.0']
17
+ s.add_development_dependency "activesupport", ['>= 3.0.0']
17
18
 
18
19
  s.rubyforge_project = "html_slicer"
19
20
 
data/lib/html_slicer.rb CHANGED
@@ -9,8 +9,7 @@ module HtmlSlicer
9
9
  require 'html_slicer/config'
10
10
  require 'html_slicer/options'
11
11
  require 'html_slicer/processor'
12
- require 'html_slicer/slicing'
13
- require 'html_slicer/resizing'
12
+ require 'html_slicer/document'
14
13
  require 'html_slicer/interface'
15
14
  require 'html_slicer/engine'
16
15
  require 'html_slicer/helpers/action_view_extension'
@@ -0,0 +1,107 @@
1
+ require 'html_slicer/makers/slicing'
2
+ require 'html_slicer/makers/resizing'
3
+
4
+ module HtmlSlicer
5
+
6
+ class Document # Framework
7
+ include HtmlSlicer::Makers
8
+
9
+ attr_reader :options, :document, :slicing, :resizing
10
+
11
+ delegate :root, :to => :document
12
+
13
+ def initialize(env, method_name, options = {})
14
+ @options = options
15
+ @source = Proc.new do
16
+ if options[:processors].present?
17
+ HtmlSlicer::Process.iterate(env.send(method_name), options[:processors])
18
+ else
19
+ env.send(method_name)
20
+ end
21
+ end
22
+ prepare!
23
+ end
24
+
25
+ # Resturn number of slices.
26
+ def slice_number
27
+ sliced? ? @slicing.slice_number : 1
28
+ end
29
+
30
+ def to_s(slice = 1)
31
+ prepare! if changed?
32
+ if sliced? && map = slicing.map[slice-1]
33
+ view(root, map, slicing.options.text_break)
34
+ else
35
+ root
36
+ end
37
+ end
38
+
39
+ def inspect
40
+ to_s
41
+ end
42
+
43
+ def method_missing(*args, &block)
44
+ to_s.send(*args, &block)
45
+ end
46
+
47
+ def resized?
48
+ resizing.try(:did?)||false
49
+ end
50
+
51
+ def sliced?
52
+ slicing.present?
53
+ end
54
+
55
+ def changed?
56
+ @source_hash != @source.call.hash
57
+ end
58
+
59
+ private
60
+
61
+ # Return a textual representation of the node including all children assigned to a +map+.
62
+ def view(node, map = {}, text_break = nil)
63
+ case node
64
+ when HTML::Tag then
65
+ children_view = node.children.collect {|child| view(child, map, text_break)}.compact.join
66
+ if map[node.object_id] || children_view.present?
67
+ if node.closing == :close
68
+ "</#{node.name}>"
69
+ else
70
+ s = "<#{node.name}"
71
+ node.attributes.each do |k,v|
72
+ s << " #{k}"
73
+ s << "=\"#{v}\"" if String === v
74
+ end
75
+ s << " /" if node.closing == :self
76
+ s << ">"
77
+ s += children_view
78
+ s << "</#{node.name}>" if node.closing != :self && !node.children.empty?
79
+ s
80
+ end
81
+ end
82
+ when HTML::Text then
83
+ if range = map[node.object_id]
84
+ "#{node.content[range]}#{text_break unless range.last == -1}"
85
+ end
86
+ when HTML::CDATA then
87
+ node.to_s
88
+ when HTML::Node then
89
+ node.children.collect {|child| view(child, map, text_break)}.compact.join
90
+ end
91
+ end
92
+
93
+ # Mapping the original source.
94
+ def prepare!
95
+ @source_hash = @source.call.hash
96
+ @document = HTML::Document.new(@source.call)
97
+ if options[:resize]
98
+ @resizing = Resizing.new(document, options[:resize])
99
+ end
100
+ if options[:slice]
101
+ @slicing = Slicing.new(document, options[:slice])
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
File without changes
@@ -1,5 +1,4 @@
1
1
  module HtmlSlicer
2
-
3
2
  module Installer
4
3
 
5
4
  # The basic implementation method.
@@ -109,10 +108,10 @@ module HtmlSlicer
109
108
  class_exec do
110
109
  define_method method_name do
111
110
  var_name = "@_#{method_name}"
112
- instance_variable_get(var_name)||instance_variable_set(var_name, HtmlSlicer::Interface.new(send(attr_name), config.config))
111
+ instance_variable_get(var_name)||instance_variable_set(var_name, HtmlSlicer::Interface.new(self, attr_name, config.config))
113
112
  end
114
113
  end
115
114
  end
115
+
116
116
  end
117
-
118
117
  end
@@ -1,26 +1,23 @@
1
1
  module HtmlSlicer
2
2
 
3
+ # Interface code.
4
+ # Accepts slice number, store it into instance variable and provides resulted String.
5
+ #
6
+ # === Example:
7
+ #
8
+ # @article = Article.find(1)
9
+ # @article_paged = @article.paged.slice!(params[:slice])
10
+ #
11
+
3
12
  class Interface # General accessor instance
4
- attr_reader :document, :options, :current_slice
5
-
6
- delegate :root, :to => :document
13
+ attr_reader :options, :current_slice, :document
14
+
15
+ delegate :sliced?, :resized?, :slice_number, :to => :document
7
16
 
8
- def initialize(content, options = {})
9
- raise(TypeError, "String object expected, '#{content.class}' passed") unless content.is_a?(String)
17
+ def initialize(env, method_name, options = {})
10
18
  @options = options
19
+ @document = Document.new(env, method_name, options)
11
20
  @current_slice = 1
12
- @document = HTML::Document.new(HtmlSlicer::Process.iterate(content, options[:processors]))
13
- if @options[:slice]
14
- @slicing = Slicing.new(document, @options[:slice])
15
- end
16
- if @options[:resize]
17
- @resizing = Resizing.new(document, @options[:resize])
18
- end
19
- end
20
-
21
- # Resturn number of slices.
22
- def slice_number
23
- sliced? ? @slicing.slice_number : 1
24
21
  end
25
22
 
26
23
  # General slicing method. Passing the argument changes the slice.
@@ -38,11 +35,7 @@ module HtmlSlicer
38
35
 
39
36
  # Textual representation according to a current slice.
40
37
  def to_s
41
- if sliced? && map = @slicing.map[current_slice-1]
42
- view(root, map, @slicing.options.text_break)
43
- else
44
- root
45
- end
38
+ document.to_s(current_slice)
46
39
  end
47
40
 
48
41
  def inspect
@@ -53,52 +46,10 @@ module HtmlSlicer
53
46
  to_s.send(*args, &block)
54
47
  end
55
48
 
56
- def sliced?
57
- @slicing.present?
58
- end
59
-
60
- def resized?
61
- @resizing.present?
62
- end
63
-
64
49
  # Return the current slice is a last or not?
65
50
  def last_slice?
66
51
  current_slice == slice_number
67
52
  end
68
-
69
- private
70
-
71
- # Return a textual representation of the node including all children assigned to a +map+.
72
- def view(node, map = {}, text_break = nil)
73
- case node
74
- when HTML::Tag then
75
- children_view = node.children.collect {|child| view(child, map, text_break)}.compact.join
76
- if map[node.object_id] || children_view.present?
77
- if node.closing == :close
78
- "</#{node.name}>"
79
- else
80
- s = "<#{node.name}"
81
- node.attributes.each do |k,v|
82
- s << " #{k}"
83
- s << "=\"#{v}\"" if String === v
84
- end
85
- s << " /" if node.closing == :self
86
- s << ">"
87
- s += children_view
88
- s << "</#{node.name}>" if node.closing != :self && !node.children.empty?
89
- s
90
- end
91
- end
92
- when HTML::Text then
93
- if range = map[node.object_id]
94
- "#{node.content[range]}#{text_break unless range.last == -1}"
95
- end
96
- when HTML::CDATA then
97
- node.to_s
98
- when HTML::Node then
99
- node.children.collect {|child| view(child, map, text_break)}.compact.join
100
- end
101
- end
102
53
 
103
54
  end
104
55
 
@@ -0,0 +1,96 @@
1
+ module HtmlSlicer
2
+ module Makers
3
+
4
+ class Resizing # Resizing engine
5
+ attr_reader :options
6
+
7
+ def initialize(document, options = {})
8
+ raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
9
+ @options = ResizeOptions.new(options)
10
+ resize_document!(document.root)
11
+ end
12
+
13
+ def did?
14
+ @did||false
15
+ end
16
+
17
+ private
18
+
19
+ include HtmlSlicer::Utilities::ParseNode
20
+ include HtmlSlicer::Utilities::NodeMatchExtension
21
+
22
+ def resize_document!(root)
23
+ parse(root) do |node|
24
+ resize!(node) if node.is_a?(HTML::Tag) && resizeable?(node)
25
+ end
26
+ end
27
+
28
+ def resizeable?(node)
29
+ able_to?(node, @options)
30
+ end
31
+
32
+ def width(node)
33
+ values = []
34
+ if block_given?
35
+ node.attributes["width"] = yield
36
+ else
37
+ values << absolute_resolution(node.attributes["width"])
38
+ end
39
+ if style = node.attributes["style"]
40
+ style.gsub!(/width:\s+\d+px;/) do |t|
41
+ t.gsub(/\d+/) do |w|
42
+ if block_given?
43
+ yield
44
+ else
45
+ values << w.to_i
46
+ w
47
+ end
48
+ end
49
+ end
50
+ end
51
+ values.compact.min
52
+ end
53
+
54
+ def height(node)
55
+ values = []
56
+ if block_given?
57
+ node.attributes["height"] = yield
58
+ else
59
+ values << absolute_resolution(node.attributes["height"])
60
+ end
61
+ if style = node.attributes["style"]
62
+ style.gsub!(/height:\s+\d+px;/) do |t|
63
+ t.gsub(/\d+/) do |h|
64
+ if block_given?
65
+ yield
66
+ else
67
+ values << h.to_i
68
+ h
69
+ end
70
+ end
71
+ end
72
+ end
73
+ values.compact.min
74
+ end
75
+
76
+ def resize!(node)
77
+ target_width = node.parent.is_a?(HTML::Tag) ? width(node.parent)||@options.width : nil
78
+ if target_width.present? && node_width = width(node)
79
+ node_height = height(node)
80
+ if node_width > target_width
81
+ ratio = node_width.to_f/target_width
82
+ width(node) { target_width.to_s }
83
+ height(node) { (node_height/ratio).round.to_s } if node_height
84
+ @did = true
85
+ end
86
+ end
87
+ end
88
+
89
+ def absolute_resolution(value)
90
+ (value.present? && value.last != "%") ? value.to_i : nil
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,103 @@
1
+ module HtmlSlicer
2
+ module Makers
3
+
4
+ class Slicing # Slicing engine
5
+ attr_reader :options, :map
6
+
7
+ def initialize(document, options = {})
8
+ raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
9
+ @options = SliceOptions.new(options)
10
+ @map = [Hash.new]
11
+ @options.unit.is_a?(Hash) ? slice_document_by_node!(document.root) : slice_document_by_text!(document.root)
12
+ end
13
+
14
+ # Resturn number of slices.
15
+ def slice_number
16
+ @map.size
17
+ end
18
+
19
+ private
20
+
21
+ include HtmlSlicer::Utilities::ParseNode
22
+ include HtmlSlicer::Utilities::NodeMatchExtension
23
+
24
+ def slice_document_by_text!(root)
25
+ units_count = 0
26
+ parse(root) do |node|
27
+ if node.is_a?(HTML::Text)
28
+ if sliceable?(node)
29
+ sanitize_content!(node)
30
+ content = node.to_s
31
+ index = 0
32
+ begin
33
+ while (match = content.match(@options.unit, index)) && index < content.size
34
+ units_count += 1
35
+ last_index ||= 0
36
+ if units_count == @options.maximum
37
+ units_count = 0
38
+ index = complete!(content, match.end(0))
39
+ @map.last[node.object_id] = Range.new(last_index, index-1)
40
+ last_index = index
41
+ limited? ? raise(Exception) : @map << Hash.new
42
+ else
43
+ index = match.end(0)
44
+ end
45
+ if units_count > 0
46
+ @map.last[node.object_id] = Range.new(last_index, -1)
47
+ end
48
+ end
49
+ rescue Exception
50
+ break
51
+ end
52
+ else
53
+ @map.last[node.object_id] = Range.new(0, -1)
54
+ end
55
+ else
56
+ @map.last[node.object_id] = true
57
+ end
58
+ end
59
+ end
60
+
61
+ def slice_document_by_node!(root)
62
+ units_count = 0
63
+ parse(root) do |node|
64
+ if node.is_a?(HTML::Text)
65
+ @map.last[node.object_id] = Range.new(0, -1)
66
+ else
67
+ @map.last[node.object_id] = true
68
+ end
69
+ if node.match(@options.unit) && sliceable?(node)
70
+ units_count += 1
71
+ if units_count == @options.maximum
72
+ units_count = 0
73
+ limited? ? break : @map << Hash.new
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def limited?
80
+ @options.limit && slice_number >= @options.limit
81
+ end
82
+
83
+ def sanitize_content!(node)
84
+ content = HTML::FullSanitizer.new.sanitize(node.to_s)
85
+ node.instance_variable_set(:@content, content)
86
+ end
87
+
88
+ def complete!(content, index)
89
+ if regexp = @options.complete
90
+ content.match(regexp, index).try(:begin, 0)||index
91
+ else
92
+ index
93
+ end
94
+ end
95
+
96
+ def sliceable?(node)
97
+ able_to?(node, @options)
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+ end
@@ -1,8 +1,8 @@
1
1
  require 'html_slicer/installer'
2
2
 
3
3
  module HtmlSlicer
4
-
5
4
  module ActiveRecordExtension
5
+
6
6
  def self.included(base)
7
7
  base.extend(ClassMethods)
8
8
  end
@@ -18,5 +18,4 @@ module HtmlSlicer
18
18
  end
19
19
 
20
20
  end
21
-
22
21
  end
@@ -1,6 +1,6 @@
1
1
  module HtmlSlicer
2
+
2
3
  class Processor
3
-
4
4
  attr_accessor :content
5
5
 
6
6
  def initialize(stuff = nil)
@@ -1,6 +1,7 @@
1
1
  require 'rails'
2
2
 
3
3
  module HtmlSlicer
4
+
4
5
  class Railtie < ::Rails::Railtie
5
6
  config.before_initialize do
6
7
  ActiveSupport.on_load :active_record do
@@ -12,4 +13,5 @@ module HtmlSlicer
12
13
  end
13
14
  end
14
15
  end
16
+
15
17
  end
@@ -1,5 +1,4 @@
1
1
  module HtmlSlicer
2
-
3
2
  module Utilities
4
3
 
5
4
  module ParseNode
@@ -127,5 +126,4 @@ module HtmlSlicer
127
126
  end
128
127
 
129
128
  end
130
-
131
129
  end
@@ -1,3 +1,3 @@
1
1
  module HtmlSlicer
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html_slicer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-17 00:00:00.000000000 Z
12
+ date: 2012-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
16
- requirement: &70294283808420 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,28 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70294283808420
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 3.0.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
25
46
  description: HtmlSlicer is a smart way to cut an HTML text into pieces. It also provides
26
47
  on option to resize "width"/"height" attributes of HTML tags, such as <iframe>,
27
48
  <object>, <img> or any other.
@@ -62,6 +83,7 @@ files:
62
83
  - html_slicer.gemspec
63
84
  - lib/html_slicer.rb
64
85
  - lib/html_slicer/config.rb
86
+ - lib/html_slicer/document.rb
65
87
  - lib/html_slicer/engine.rb
66
88
  - lib/html_slicer/helpers/action_view_extension.rb
67
89
  - lib/html_slicer/helpers/slicer.rb
@@ -69,12 +91,12 @@ files:
69
91
  - lib/html_slicer/helpers/tags.rb
70
92
  - lib/html_slicer/installer.rb
71
93
  - lib/html_slicer/interface.rb
94
+ - lib/html_slicer/makers/resizing.rb
95
+ - lib/html_slicer/makers/slicing.rb
72
96
  - lib/html_slicer/models/active_record_extension.rb
73
97
  - lib/html_slicer/options.rb
74
98
  - lib/html_slicer/processor.rb
75
99
  - lib/html_slicer/railtie.rb
76
- - lib/html_slicer/resizing.rb
77
- - lib/html_slicer/slicing.rb
78
100
  - lib/html_slicer/utilities.rb
79
101
  - lib/html_slicer/version.rb
80
102
  homepage: http://vkvon.ru/projects/html_slicer
@@ -98,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
120
  version: '0'
99
121
  requirements: []
100
122
  rubyforge_project: html_slicer
101
- rubygems_version: 1.8.10
123
+ rubygems_version: 1.8.24
102
124
  signing_key:
103
125
  specification_version: 3
104
- summary: HTML text slicer
126
+ summary: HTML text pagination for Ruby on Rails
105
127
  test_files: []
@@ -1,89 +0,0 @@
1
- module HtmlSlicer
2
-
3
- class Resizing # Resizing engine
4
- attr_reader :options
5
-
6
- def initialize(document, options = {})
7
- raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
8
- @options = ResizeOptions.new(options)
9
- resize_document!(document.root)
10
- end
11
-
12
- private
13
-
14
- include HtmlSlicer::Utilities::ParseNode
15
- include HtmlSlicer::Utilities::NodeMatchExtension
16
-
17
- def resize_document!(root)
18
- parse(root) do |node|
19
- resize!(node) if node.is_a?(HTML::Tag) && resizeable?(node)
20
- end
21
- end
22
-
23
- def resizeable?(node)
24
- able_to?(node, @options)
25
- end
26
-
27
- def width(node)
28
- values = []
29
- if block_given?
30
- node.attributes["width"] = yield
31
- else
32
- values << absolute_resolution(node.attributes["width"])
33
- end
34
- if style = node.attributes["style"]
35
- style.gsub!(/width:\s+\d+px;/) do |t|
36
- t.gsub(/\d+/) do |w|
37
- if block_given?
38
- yield
39
- else
40
- values << w.to_i
41
- w
42
- end
43
- end
44
- end
45
- end
46
- values.compact.min
47
- end
48
-
49
- def height(node)
50
- values = []
51
- if block_given?
52
- node.attributes["height"] = yield
53
- else
54
- values << absolute_resolution(node.attributes["height"])
55
- end
56
- if style = node.attributes["style"]
57
- style.gsub!(/height:\s+\d+px;/) do |t|
58
- t.gsub(/\d+/) do |h|
59
- if block_given?
60
- yield
61
- else
62
- values << h.to_i
63
- h
64
- end
65
- end
66
- end
67
- end
68
- values.compact.min
69
- end
70
-
71
- def resize!(node)
72
- target_width = node.parent.is_a?(HTML::Tag) ? width(node.parent)||@options.width : nil
73
- if target_width.present? && node_width = width(node)
74
- node_height = height(node)
75
- if node_width > target_width
76
- ratio = node_width.to_f/target_width
77
- width(node) { target_width.to_s }
78
- height(node) { (node_height/ratio).round.to_s } if node_height
79
- end
80
- end
81
- end
82
-
83
- def absolute_resolution(value)
84
- (value.present? && value.last != "%") ? value.to_i : nil
85
- end
86
-
87
- end
88
-
89
- end
@@ -1,101 +0,0 @@
1
- module HtmlSlicer
2
-
3
- class Slicing # Slicing engine
4
- attr_reader :options, :map
5
-
6
- def initialize(document, options = {})
7
- raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
8
- @options = SliceOptions.new(options)
9
- @map = [Hash.new]
10
- @options.unit.is_a?(Hash) ? slice_document_by_node!(document.root) : slice_document_by_text!(document.root)
11
- end
12
-
13
- # Resturn number of slices.
14
- def slice_number
15
- @map.size
16
- end
17
-
18
- private
19
-
20
- include HtmlSlicer::Utilities::ParseNode
21
- include HtmlSlicer::Utilities::NodeMatchExtension
22
-
23
- def slice_document_by_text!(root)
24
- units_count = 0
25
- parse(root) do |node|
26
- if node.is_a?(HTML::Text)
27
- if sliceable?(node)
28
- sanitize_content!(node)
29
- content = node.to_s
30
- index = 0
31
- begin
32
- while (match = content.match(@options.unit, index)) && index < content.size
33
- units_count += 1
34
- last_index ||= 0
35
- if units_count == @options.maximum
36
- units_count = 0
37
- index = complete!(content, match.end(0))
38
- @map.last[node.object_id] = Range.new(last_index, index-1)
39
- last_index = index
40
- limited? ? raise(Exception) : @map << Hash.new
41
- else
42
- index = match.end(0)
43
- end
44
- if units_count > 0
45
- @map.last[node.object_id] = Range.new(last_index, -1)
46
- end
47
- end
48
- rescue Exception
49
- break
50
- end
51
- else
52
- @map.last[node.object_id] = Range.new(0, -1)
53
- end
54
- else
55
- @map.last[node.object_id] = true
56
- end
57
- end
58
- end
59
-
60
- def slice_document_by_node!(root)
61
- units_count = 0
62
- parse(root) do |node|
63
- if node.is_a?(HTML::Text)
64
- @map.last[node.object_id] = Range.new(0, -1)
65
- else
66
- @map.last[node.object_id] = true
67
- end
68
- if node.match(@options.unit) && sliceable?(node)
69
- units_count += 1
70
- if units_count == @options.maximum
71
- units_count = 0
72
- limited? ? break : @map << Hash.new
73
- end
74
- end
75
- end
76
- end
77
-
78
- def limited?
79
- @options.limit && slice_number >= @options.limit
80
- end
81
-
82
- def sanitize_content!(node)
83
- content = HTML::FullSanitizer.new.sanitize(node.to_s)
84
- node.instance_variable_set(:@content, content)
85
- end
86
-
87
- def complete!(content, index)
88
- if regexp = @options.complete
89
- content.match(regexp, index).try(:begin, 0)||index
90
- else
91
- index
92
- end
93
- end
94
-
95
- def sliceable?(node)
96
- able_to?(node, @options)
97
- end
98
-
99
- end
100
-
101
- end