html_slicer 0.0.7 → 0.1.0

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/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.1.0
2
+
3
+ * The big changes. :)
4
+ * Code has been optimized and rewritten by ~70%.
5
+ * Caching option provided.
6
+
1
7
  == 0.0.7
2
8
 
3
9
  * Code refactoring.
data/README.rdoc CHANGED
@@ -65,6 +65,7 @@ where:
65
65
  * <tt>:as</tt> is a name of basic accessor for result.
66
66
  * <tt>:slice</tt> is a hash of <tt>slicing options</tt> as a part of configuration.
67
67
  * <tt>:resize</tt> is a hash of <tt>resizing options</tt> as a part of configuration.
68
+ * <tt>:cache_to</tt> is an accessor name used to store the cache. +True+ value make it by default.
68
69
 
69
70
  You can define any configuration key you want. Otherwise, default configuration options (if available) will be picked up automatically.
70
71
 
@@ -198,7 +199,7 @@ you can override/complete any configuration.
198
199
  By applying +:config+ key you can use one of stylized configurations:
199
200
 
200
201
  class Post < ActiveRecord::Base
201
- slice :content, :config => :paged, :slice = {:complete => /\s+/, :maximum => 3000}
202
+ slice :content, :config => :paged, :slice => {:complete => /\s+/, :maximum => 3000}
202
203
  end
203
204
 
204
205
  Through passing the block you get a more flexible approach to configure slicer:
@@ -304,6 +305,52 @@ Examples:
304
305
  :param_name => [:article, :page]
305
306
  # means you define params[:article][:page] as a slice key.
306
307
 
308
+ == Caching
309
+
310
+ Caching implies that resizing/slicing procedures is both time-consuming processes will be started only at once, and once again will be launched only if the target content has been changed or resizing/slicing options has been modified.
311
+
312
+ For caching, pass the option: <tt>:cache_to => true</tt> or <tt>:cache_to => :any_other_accessor</tt> within your config definition.
313
+
314
+ === ActiveRecord model
315
+
316
+ Example:
317
+
318
+ class Article < ActiveRecord::Base
319
+ slice :content, :as => :paged, :slice => {:maximum => 1000, :complete => /\s+|\z/}, :cache_to => :content_page_cache
320
+ end
321
+
322
+ Accessor method <tt>.content_page_cache=</tt> used for caching here.
323
+ The first time when resizing and slicing procedures is called, generated maps will be cached and assigned to <tt>.content_page_cache</tt> accessor. Before the article saves itself, assigned dump stuff is recorded like any other attribute of article (callback <tt>before_save</tt> is set up).
324
+
325
+ Of course, attribute is recorded only as a column of the database :), So, before, add the column to a model:
326
+
327
+ <tt>% rails generate migration AddContentPageCacheToArticle content_page_cache:text</tt>
328
+
329
+ <tt>% rake db:migrate </tt>
330
+
331
+ Slicing/resizing procedures repeat again only if target content has been changed or options has been modified.
332
+
333
+ === ActiveModel
334
+
335
+ Example:
336
+
337
+ class TextModel
338
+ attr_accessor :text, :paged_cache
339
+
340
+ extend HtmlSlicer::Installer
341
+
342
+ slice :text, :as => :paged, :slice => {:complete => /\s+/, :maximum => 300}, :cache_to => true
343
+
344
+ def initialize(text)
345
+ @text = text
346
+ end
347
+
348
+ end
349
+
350
+ +True+ value of <tt>:cache_to</tt> option set default cache accessor name consisted of basic accessor name + <tt>_page</tt>.
351
+
352
+ In fact, caching ActiveModel not so significant in most cases, but still works. The next time you call slicing method, the cached resizing/slicing map(s) will be used.
353
+
307
354
  == More
308
355
 
309
356
  === Slicing a general String or ActiveModel (or any other) object
@@ -0,0 +1,70 @@
1
+ require 'digest/sha1'
2
+
3
+ module HtmlSlicer
4
+ # Object to be serialized and dumped as cache storage.
5
+ # Include +resizing+ and +slicing+ objects, and original text's hexdigest hash value to provide authenticity.
6
+ # During the runtime object is used as an +maps+ accessor too.
7
+
8
+ class CachedStuff
9
+ attr_reader :hexdigest, :resizing, :slicing
10
+ attr_accessor :changed, :time
11
+
12
+ def initialize(text = nil)
13
+ @changed = false
14
+ self.hexdigest_for = text if text
15
+ end
16
+
17
+ def hexdigest_for=(text)
18
+ hex = Digest::SHA1.hexdigest(text)
19
+ unless hex == @hexdigest
20
+ @changed = true
21
+ @hexdigest = hex
22
+ end
23
+ hex
24
+ end
25
+
26
+ def slicing=(object)
27
+ case object
28
+ when HtmlSlicer::Mappers::Slicing, nil then
29
+ @changed = true unless object.try(:options).try(:hexdigest) == @slicing.try(:options).try(:hexdigest)
30
+ @slicing = object
31
+ else
32
+ raise(TypeError, "HtmlSlicer::Mappers::Slicing or nil expected, '#{object.class}' passed")
33
+ end
34
+ end
35
+
36
+ def resizing=(object)
37
+ case object
38
+ when HtmlSlicer::Mappers::Resizing, nil then
39
+ @changed = true unless object.try(:options).try(:hexdigest) == @slicing.try(:options).try(:hexdigest)
40
+ @resizing = object
41
+ else
42
+ raise(TypeError, "HtmlSlicer::Mappers::Resizing or nil expected, '#{object.class}' passed")
43
+ end
44
+ end
45
+
46
+ def valid_text?(text)
47
+ Digest::SHA1.hexdigest(text) == @hexdigest
48
+ end
49
+
50
+ def valid_resizing_options?(options)
51
+ options.try(:hexdigest) == @resizing.try(:options).try(:hexdigest)
52
+ end
53
+
54
+ def valid_slicing_options?(options)
55
+ options.try(:hexdigest) == @slicing.try(:options).try(:hexdigest)
56
+ end
57
+
58
+ def changed?
59
+ @changed
60
+ end
61
+
62
+ # Serialize self, using Marshal and Base64 encoding
63
+ def to_dump
64
+ @time = Time.now
65
+ Base64.encode64(Marshal.dump(self))
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -39,7 +39,7 @@ module HtmlSlicer
39
39
 
40
40
  # Config accessor for HtmlSlicer. Accepts argument as a +style+.
41
41
  def self.config(style = nil)
42
- eval("@config#{"_#{style}" if style}")
42
+ eval("@config#{"_#{style}" if style}") || raise("Config style '#{style}' is invalid.")
43
43
  end
44
44
 
45
45
  # need a Class for 3.0
@@ -57,6 +57,7 @@ module HtmlSlicer
57
57
  config_accessor :left
58
58
  config_accessor :right
59
59
  config_accessor :param_name
60
+ config_accessor :cache_to
60
61
 
61
62
  def slice # Ugly coding. Override Hash::slice method
62
63
  config[:slice]
@@ -105,12 +105,18 @@ module HtmlSlicer
105
105
  end
106
106
  end
107
107
  method_name = config.as||"#{attr_name}_slice"
108
- class_exec do
108
+ config.cache_to = "#{method_name}_cache" if config.cache_to == true
109
+ class_eval do
109
110
  define_method method_name do
110
111
  var_name = "@_#{method_name}"
111
112
  instance_variable_get(var_name)||instance_variable_set(var_name, HtmlSlicer::Interface.new(self, attr_name, config.config))
112
113
  end
113
114
  end
115
+ if config.cache_to && self.superclass == ActiveRecord::Base
116
+ before_save do
117
+ send(method_name).load!
118
+ end
119
+ end
114
120
  end
115
121
 
116
122
  end
@@ -1,3 +1,9 @@
1
+ require 'html_slicer/options'
2
+ require 'html_slicer/processor'
3
+ require 'html_slicer/cached_stuff'
4
+ require 'html_slicer/mappers/slicing'
5
+ require 'html_slicer/mappers/resizing'
6
+
1
7
  module HtmlSlicer
2
8
 
3
9
  # Interface code.
@@ -10,17 +16,75 @@ module HtmlSlicer
10
16
  #
11
17
 
12
18
  class Interface # General accessor instance
13
- attr_reader :options, :current_slice, :document
14
-
15
- delegate :sliced?, :resized?, :slice_number, :to => :document
16
-
19
+ include HtmlSlicer::Mappers
20
+
21
+ attr_reader :options, :document, :current_slice, :cached_stuff
22
+
23
+ delegate :slicing, :resizing, :to => :cached_stuff
24
+
17
25
  def initialize(env, method_name, options = {})
26
+ @env, @method_name = env, method_name
18
27
  @options = options
19
- @document = Document.new(env, method_name, options)
28
+ @resizing_options = ResizingOptions.new(options[:resize]) if options[:resize]
29
+ @slicing_options = SlicingOptions.new(options[:slice]) if options[:slice]
20
30
  @current_slice = 1
31
+ load!
32
+ end
33
+
34
+ # Getting source content
35
+ def source
36
+ case options[:processors].present?
37
+ when true then HtmlSlicer::Process.iterate(@env.send(@method_name), options[:processors])
38
+ else
39
+ @env.send(@method_name)
40
+ end
21
41
  end
22
42
 
23
- # General slicing method. Passing the argument changes the slice.
43
+ # Process initializer
44
+ def load!
45
+ text = source
46
+ @cached_stuff ||=
47
+ begin
48
+ if options[:cache_to] # Getting recorded hash dump
49
+ Marshal.load(Base64.decode64(@env.send(options[:cache_to])))
50
+ else
51
+ raise Exception
52
+ end
53
+ rescue Exception, TypeError, NoMethodError # New cache object otherwise
54
+ CachedStuff.new
55
+ end
56
+ if @document.blank? || !@cached_stuff.valid_text?(text) # Initialize new @document if not exist or content has been changed
57
+ @document = HTML::Document.new(text)
58
+ @cached_stuff.hexdigest_for = text
59
+ end
60
+ if @cached_stuff.changed? || !@cached_stuff.valid_resizing_options?(@resizing_options) # Initialize new resizing process if the content or options has been changed
61
+ if @resizing_options
62
+ @cached_stuff.resizing = Resizing.new(@document, @resizing_options)
63
+ else
64
+ @cached_stuff.resizing = nil
65
+ end
66
+ end
67
+ if @cached_stuff.changed? || !@cached_stuff.valid_slicing_options?(@slicing_options) # Initialize new slicing process if the content or options has been changed
68
+ if @slicing_options
69
+ @cached_stuff.slicing = Slicing.new(@document, @slicing_options)
70
+ else
71
+ @cached_stuff.slicing = nil
72
+ end
73
+ end
74
+ if @cached_stuff.changed? # Serialize and dump the cache if any changes provided
75
+ @cached_stuff.changed = false
76
+ if options[:cache_to]
77
+ @env.send("#{options[:cache_to]}=", @cached_stuff.to_dump)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Return number of slices.
83
+ def slice_number
84
+ sliced? ? slicing.slice_number : 1
85
+ end
86
+
87
+ # General slicing method. Passing the argument changes the +current_slice+.
24
88
  def slice!(slice = nil)
25
89
  raise(Exception, "Slicing unavailable!") unless sliced?
26
90
  if slice.present?
@@ -32,10 +96,10 @@ module HtmlSlicer
32
96
  end
33
97
  self
34
98
  end
35
-
36
- # Textual representation according to a current slice.
99
+
37
100
  def to_s
38
- document.to_s(current_slice)
101
+ load!
102
+ view(document.root, @current_slice)
39
103
  end
40
104
 
41
105
  def inspect
@@ -45,10 +109,66 @@ module HtmlSlicer
45
109
  def method_missing(*args, &block)
46
110
  to_s.send(*args, &block)
47
111
  end
112
+
113
+ # True if any HTML tag has been resized
114
+ def resized?
115
+ resizing ? resizing.map.any? : false
116
+ end
48
117
 
118
+ # True if any part of document has been sliced
119
+ def sliced?
120
+ slicing ? slicing.map.any? : false
121
+ end
122
+
49
123
  # Return the current slice is a last or not?
50
124
  def last_slice?
51
125
  current_slice == slice_number
126
+ end
127
+
128
+ private
129
+
130
+ # Return a textual representation of the node including all children.
131
+ def view(node, slice)
132
+ slice = slice.to_i
133
+ case node
134
+ when HTML::Tag then
135
+ children_view = node.children.collect {|child| view(child, slice)}.compact.join
136
+ if resized?
137
+ resizing.resize_node(node)
138
+ end
139
+ if sliced?
140
+ if slicing.map.get(node, slice) || children_view.present?
141
+ if node.closing == :close
142
+ "</#{node.name}>"
143
+ else
144
+ s = "<#{node.name}"
145
+ node.attributes.each do |k,v|
146
+ s << " #{k}"
147
+ s << "=\"#{v}\"" if String === v
148
+ end
149
+ s << " /" if node.closing == :self
150
+ s << ">"
151
+ s += children_view
152
+ s << "</#{node.name}>" if node.closing != :self && !node.children.empty?
153
+ s
154
+ end
155
+ end
156
+ else
157
+ node.to_s
158
+ end
159
+ when HTML::Text then
160
+ if sliced?
161
+ if range = slicing.map.get(node, slice)
162
+ "#{node.content[Range.new(*range)]}#{slicing.options.text_break unless range.last == -1}"
163
+ end
164
+ else
165
+ node.to_s
166
+ end
167
+ when HTML::CDATA then
168
+ node.to_s
169
+ when HTML::Node then
170
+ node.children.collect {|child| view(child, slice)}.compact.join
171
+ end
52
172
  end
53
173
 
54
174
  end
@@ -1,17 +1,38 @@
1
1
  module HtmlSlicer
2
- module Makers
2
+ module Mappers
3
3
 
4
- class Resizing # Resizing engine
5
- attr_reader :options
6
-
7
- def initialize(document, options = {})
4
+ class Resizing # Resizing engine, generate and store slicing Map (hash)
5
+ attr_reader :options, :map
6
+
7
+ class Map < Hash #:nodoc:
8
+ include HtmlSlicer::Utilities::NodeIdent
9
+
10
+ def commit(node, width, height)
11
+ self[node_identify(node)] = [width, height]
12
+ end
13
+ def width(node)
14
+ self[node_identify(node)].try(:first)
15
+ end
16
+ def height(node)
17
+ self[node_identify(node)].try(:last)
18
+ end
19
+ end
20
+
21
+ def initialize(document, options)
8
22
  raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
9
- @options = ResizeOptions.new(options)
10
- resize_document!(document.root)
23
+ raise(TypeError, "HtmlSlicer::Options expected, '#{options.class}' passed") unless options.is_a?(HtmlSlicer::Options)
24
+ @options = options
25
+ @map = Map.new
26
+ process!(document.root)
11
27
  end
12
-
13
- def did?
14
- @did||false
28
+
29
+ def resize_node(node)
30
+ if w = @map.width(node)
31
+ width(node) { w.to_s }
32
+ end
33
+ if h = @map.height(node)
34
+ height(node) { h.to_s }
35
+ end
15
36
  end
16
37
 
17
38
  private
@@ -19,9 +40,18 @@ module HtmlSlicer
19
40
  include HtmlSlicer::Utilities::ParseNode
20
41
  include HtmlSlicer::Utilities::NodeMatchExtension
21
42
 
22
- def resize_document!(root)
43
+ def process!(root)
23
44
  parse(root) do |node|
24
- resize!(node) if node.is_a?(HTML::Tag) && resizeable?(node)
45
+ if node.is_a?(HTML::Tag) && resizeable?(node)
46
+ target_width = node.parent.is_a?(HTML::Tag) ? @map.width(node.parent)||@options.width : @options.width
47
+ if target_width.present? && node_width = width(node)
48
+ node_height = height(node)
49
+ if node_width > target_width
50
+ ratio = node_width.to_f/target_width
51
+ @map.commit(node, target_width, node_height ? (node_height/ratio).round : nil)
52
+ end
53
+ end
54
+ end
25
55
  end
26
56
  end
27
57
 
@@ -31,7 +61,7 @@ module HtmlSlicer
31
61
 
32
62
  def width(node)
33
63
  values = []
34
- if block_given?
64
+ if block_given? && node.attributes.has_key?("width")
35
65
  node.attributes["width"] = yield
36
66
  else
37
67
  values << absolute_resolution(node.attributes["width"])
@@ -53,7 +83,7 @@ module HtmlSlicer
53
83
 
54
84
  def height(node)
55
85
  values = []
56
- if block_given?
86
+ if block_given? && node.attributes.has_key?("height")
57
87
  node.attributes["height"] = yield
58
88
  else
59
89
  values << absolute_resolution(node.attributes["height"])
@@ -73,19 +103,6 @@ module HtmlSlicer
73
103
  values.compact.min
74
104
  end
75
105
 
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
106
  def absolute_resolution(value)
90
107
  (value.present? && value.last != "%") ? value.to_i : nil
91
108
  end
@@ -1,19 +1,28 @@
1
1
  module HtmlSlicer
2
- module Makers
2
+ module Mappers
3
3
 
4
- class Slicing # Slicing engine
5
- attr_reader :options, :map
4
+ class Slicing # Slicing engine, generate and store resizing Map (hash)
5
+ attr_reader :options, :map, :slice_number
6
+
7
+ class Map < Hash #:nodoc:
8
+ include HtmlSlicer::Utilities::NodeIdent
6
9
 
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)
10
+ def commit(node, number, value)
11
+ self[node_identify(node)] ||= {}
12
+ self[node_identify(node)].merge!(number => value)
13
+ end
14
+ def get(node, number)
15
+ self[node_identify(node)] ? self[node_identify(node)][number] : nil
16
+ end
12
17
  end
13
18
 
14
- # Resturn number of slices.
15
- def slice_number
16
- @map.size
19
+ def initialize(document, options)
20
+ raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
21
+ raise(TypeError, "HtmlSlicer::Options expected, '#{options.class}' passed") unless options.is_a?(HtmlSlicer::Options)
22
+ @options = options
23
+ @map = Map.new
24
+ @slice_number = 1
25
+ @options.unit.is_a?(Hash) ? process_by_node!(document.root) : process_by_text!(document.root)
17
26
  end
18
27
 
19
28
  private
@@ -21,7 +30,7 @@ module HtmlSlicer
21
30
  include HtmlSlicer::Utilities::ParseNode
22
31
  include HtmlSlicer::Utilities::NodeMatchExtension
23
32
 
24
- def slice_document_by_text!(root)
33
+ def process_by_text!(root)
25
34
  units_count = 0
26
35
  parse(root) do |node|
27
36
  if node.is_a?(HTML::Text)
@@ -36,48 +45,48 @@ module HtmlSlicer
36
45
  if units_count == @options.maximum
37
46
  units_count = 0
38
47
  index = complete!(content, match.end(0))
39
- @map.last[node.object_id] = Range.new(last_index, index-1)
48
+ @map.commit(node, @slice_number, [last_index, index-1])
40
49
  last_index = index
41
- limited? ? raise(Exception) : @map << Hash.new
50
+ limited? ? raise(Exception) : @slice_number += 1
42
51
  else
43
52
  index = match.end(0)
44
53
  end
45
54
  if units_count > 0
46
- @map.last[node.object_id] = Range.new(last_index, -1)
55
+ @map.commit(node, @slice_number, [last_index, -1])
47
56
  end
48
57
  end
49
58
  rescue Exception
50
59
  break
51
60
  end
52
61
  else
53
- @map.last[node.object_id] = Range.new(0, -1)
62
+ @map.commit(node, @slice_number, [0, -1])
54
63
  end
55
64
  else
56
- @map.last[node.object_id] = true
65
+ @map.commit(node, @slice_number, true)
57
66
  end
58
67
  end
59
68
  end
60
69
 
61
- def slice_document_by_node!(root)
70
+ def process_by_node!(root)
62
71
  units_count = 0
63
72
  parse(root) do |node|
64
73
  if node.is_a?(HTML::Text)
65
- @map.last[node.object_id] = Range.new(0, -1)
74
+ @map.commit(node, @slice_number, [0, -1])
66
75
  else
67
- @map.last[node.object_id] = true
76
+ @map.commit(node, @slice_number, true)
68
77
  end
69
78
  if node.match(@options.unit) && sliceable?(node)
70
79
  units_count += 1
71
80
  if units_count == @options.maximum
72
81
  units_count = 0
73
- limited? ? break : @map << Hash.new
82
+ limited? ? break : @slice_number += 1
74
83
  end
75
84
  end
76
85
  end
77
86
  end
78
87
 
79
88
  def limited?
80
- @options.limit && slice_number >= @options.limit
89
+ @options.limit && @slice_number >= @options.limit
81
90
  end
82
91
 
83
92
  def sanitize_content!(node)
@@ -1,3 +1,5 @@
1
+ require 'digest/sha1'
2
+
1
3
  module HtmlSlicer
2
4
 
3
5
  # Make options adjective and convinient for processing needs.
@@ -5,15 +7,26 @@ module HtmlSlicer
5
7
  class Options #:nodoc:
6
8
  # Superclass
7
9
  attr_reader :only, :except
10
+
8
11
  def initialize(options)
9
12
  options ||= {}
10
13
  @only = options[:only]
11
14
  @except = options[:except]
12
15
  end
16
+
17
+ def hexdigest
18
+ Digest::SHA1.hexdigest(string_value)
19
+ end
20
+
21
+ def string_value
22
+ instance_variables.collect {|name| name.to_s + ":" + instance_variable_get(name).to_s}.join
23
+ end
24
+
13
25
  end
14
26
 
15
- class SliceOptions < Options #:nodoc:
27
+ class SlicingOptions < Options #:nodoc:
16
28
  attr_reader :unit, :maximum, :complete, :text_break, :limit
29
+
17
30
  def initialize(options)
18
31
  super(options)
19
32
  @unit = case options[:unit]
@@ -47,14 +60,17 @@ module HtmlSlicer
47
60
  end
48
61
  @text_break = options[:text_break]
49
62
  end
63
+
50
64
  end
51
65
 
52
- class ResizeOptions < Options
66
+ class ResizingOptions < Options
53
67
  attr_reader :width
68
+
54
69
  def initialize(options)
55
70
  super(options)
56
- @width = options[:width]
71
+ @width = options[:width].to_i
57
72
  end
73
+
58
74
  end
59
75
 
60
76
  end
@@ -5,11 +5,19 @@ module HtmlSlicer
5
5
  def parse(node, &block)
6
6
  node.children.each do |node|
7
7
  yield node if block_given?
8
- parse(node, &block) if node.is_a?(HTML::Tag)
8
+ if node.is_a?(HTML::Tag)
9
+ parse(node, &block)
10
+ end
9
11
  end
10
12
  end
11
13
  end
12
14
 
15
+ module NodeIdent
16
+ def node_identify(node)
17
+ [node.line, node.position]
18
+ end
19
+ end
20
+
13
21
  module Deepcopy
14
22
  # Return the 'deep' brand new copy of Hash or Array. All nested hashes/arrays rebuilded at the same way.
15
23
  def deepcopy(object)
@@ -1,3 +1,3 @@
1
1
  module HtmlSlicer
2
- VERSION = "0.0.7"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/html_slicer.rb CHANGED
@@ -7,9 +7,6 @@ module HtmlSlicer
7
7
  def self.load!
8
8
  require 'html_slicer/utilities'
9
9
  require 'html_slicer/config'
10
- require 'html_slicer/options'
11
- require 'html_slicer/processor'
12
- require 'html_slicer/document'
13
10
  require 'html_slicer/interface'
14
11
  require 'html_slicer/engine'
15
12
  require 'html_slicer/helpers/action_view_extension'
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.7
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-22 00:00:00.000000000 Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -82,8 +82,8 @@ files:
82
82
  - config/locales/html_slicer.yml
83
83
  - html_slicer.gemspec
84
84
  - lib/html_slicer.rb
85
+ - lib/html_slicer/cached_stuff.rb
85
86
  - lib/html_slicer/config.rb
86
- - lib/html_slicer/document.rb
87
87
  - lib/html_slicer/engine.rb
88
88
  - lib/html_slicer/helpers/action_view_extension.rb
89
89
  - lib/html_slicer/helpers/slicer.rb
@@ -91,8 +91,8 @@ files:
91
91
  - lib/html_slicer/helpers/tags.rb
92
92
  - lib/html_slicer/installer.rb
93
93
  - lib/html_slicer/interface.rb
94
- - lib/html_slicer/makers/resizing.rb
95
- - lib/html_slicer/makers/slicing.rb
94
+ - lib/html_slicer/mappers/resizing.rb
95
+ - lib/html_slicer/mappers/slicing.rb
96
96
  - lib/html_slicer/models/active_record_extension.rb
97
97
  - lib/html_slicer/options.rb
98
98
  - lib/html_slicer/processor.rb
@@ -1,107 +0,0 @@
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