deface 0.9.1 → 1.0.0.rc1

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.
Files changed (63) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +1 -0
  4. data/README.markdown +139 -59
  5. data/deface.gemspec +4 -2
  6. data/gemfiles/haml3_2.gemfile +5 -0
  7. data/lib/deface.rb +28 -1
  8. data/lib/deface/action_view_extensions.rb +7 -1
  9. data/lib/deface/actions/action.rb +19 -0
  10. data/lib/deface/actions/add_to_attributes.rb +15 -0
  11. data/lib/deface/actions/attribute_action.rb +33 -0
  12. data/lib/deface/actions/element_action.rb +13 -0
  13. data/lib/deface/actions/insert_after.rb +9 -0
  14. data/lib/deface/actions/insert_before.rb +9 -0
  15. data/lib/deface/actions/insert_bottom.rb +14 -0
  16. data/lib/deface/actions/insert_top.rb +14 -0
  17. data/lib/deface/actions/remove.rb +13 -0
  18. data/lib/deface/actions/remove_from_attributes.rb +13 -0
  19. data/lib/deface/actions/replace.rb +14 -0
  20. data/lib/deface/actions/replace_contents.rb +19 -0
  21. data/lib/deface/actions/set_attributes.rb +12 -0
  22. data/lib/deface/actions/surround.rb +24 -0
  23. data/lib/deface/actions/surround_action.rb +15 -0
  24. data/lib/deface/actions/surround_contents.rb +33 -0
  25. data/lib/deface/applicator.rb +35 -191
  26. data/lib/deface/dsl/context.rb +7 -3
  27. data/lib/deface/dsl/loader.rb +5 -2
  28. data/lib/deface/environment.rb +31 -1
  29. data/lib/deface/haml_converter.rb +33 -5
  30. data/lib/deface/matchers/element.rb +13 -0
  31. data/lib/deface/matchers/range.rb +52 -0
  32. data/lib/deface/override.rb +28 -57
  33. data/lib/deface/sources/copy.rb +15 -0
  34. data/lib/deface/sources/cut.rb +25 -0
  35. data/lib/deface/sources/erb.rb +9 -0
  36. data/lib/deface/sources/haml.rb +14 -0
  37. data/lib/deface/sources/partial.rb +13 -0
  38. data/lib/deface/sources/source.rb +11 -0
  39. data/lib/deface/sources/template.rb +13 -0
  40. data/lib/deface/sources/text.rb +9 -0
  41. data/lib/deface/utils/failure_finder.rb +41 -0
  42. data/spec/deface/action_view_template_spec.rb +28 -2
  43. data/spec/deface/actions/add_to_attributes_spec.rb +62 -0
  44. data/spec/deface/actions/insert_after_spec.rb +19 -0
  45. data/spec/deface/actions/insert_before_spec.rb +19 -0
  46. data/spec/deface/actions/insert_bottom_spec.rb +28 -0
  47. data/spec/deface/actions/insert_top_spec.rb +28 -0
  48. data/spec/deface/actions/remove_from_attributes_spec.rb +81 -0
  49. data/spec/deface/actions/remove_spec.rb +30 -0
  50. data/spec/deface/actions/replace_contents_spec.rb +29 -0
  51. data/spec/deface/actions/replace_spec.rb +52 -0
  52. data/spec/deface/actions/set_attributes_spec.rb +62 -0
  53. data/spec/deface/actions/surround_contents_spec.rb +57 -0
  54. data/spec/deface/actions/surround_spec.rb +57 -0
  55. data/spec/deface/applicator_spec.rb +0 -354
  56. data/spec/deface/dsl/context_spec.rb +14 -7
  57. data/spec/deface/dsl/loader_spec.rb +12 -4
  58. data/spec/deface/override_spec.rb +26 -3
  59. data/spec/deface/template_helper_spec.rb +11 -0
  60. data/spec/deface/utils/failure_finder_spec.rb +76 -0
  61. data/spec/spec_helper.rb +21 -2
  62. data/tasks/utils.rake +24 -0
  63. metadata +91 -14
@@ -0,0 +1,13 @@
1
+ module Deface
2
+ module Actions
3
+ class ElementAction < Action
4
+ attr_reader :source_element
5
+
6
+ def initialize(options = {})
7
+ super(options)
8
+ @source_element = options[:source_element]
9
+ raise(DefaceError, "No source_element option specified") unless @source_element
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Deface
2
+ module Actions
3
+ class InsertAfter < ElementAction
4
+ def execute(target_element)
5
+ target_element.first.after(source_element)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Deface
2
+ module Actions
3
+ class InsertBefore < ElementAction
4
+ def execute(target_element)
5
+ target_element.first.before(source_element)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module Deface
2
+ module Actions
3
+ class InsertBottom < ElementAction
4
+ def execute(target_element)
5
+ target_element = target_element.first
6
+ if target_element.children.size == 0
7
+ target_element.children = source_element
8
+ else
9
+ target_element.children.after(source_element)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Deface
2
+ module Actions
3
+ class InsertTop < ElementAction
4
+ def execute(target_element)
5
+ target_element = target_element.first
6
+ if target_element.children.size == 0
7
+ target_element.children = source_element
8
+ else
9
+ target_element.children.before(source_element)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Deface
2
+ module Actions
3
+ class Remove < Action
4
+ def execute(target_range)
5
+ target_range.map(&:remove)
6
+ end
7
+
8
+ def range_compatible?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Deface
2
+ module Actions
3
+ class RemoveFromAttributes < AttributeAction
4
+ def execute_for_attribute(target_element, name, value)
5
+ if target_element.attributes.key?(name)
6
+ target_element.set_attribute(name, target_element.attributes[name].value.gsub(value.to_s, '').strip)
7
+ elsif target_element.attributes.key?("data-erb-#{name}")
8
+ target_element.set_attribute("data-erb-#{name}", target_element.attributes["data-erb-#{name}"].value.gsub(value.to_s, '').strip)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Deface
2
+ module Actions
3
+ class Replace < ElementAction
4
+ def execute(target_range)
5
+ target_range.first.before(source_element)
6
+ target_range.map(&:remove)
7
+ end
8
+
9
+ def range_compatible?
10
+ true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module Deface
2
+ module Actions
3
+ class ReplaceContents < ElementAction
4
+ def execute(target_range)
5
+ if target_range.length == 1
6
+ target_range.first.children.remove
7
+ target_range.first.add_child(source_element)
8
+ else
9
+ target_range[1..-2].map(&:remove)
10
+ target_range.first.after(source_element)
11
+ end
12
+ end
13
+
14
+ def range_compatible?
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module Deface
2
+ module Actions
3
+ class SetAttributes < AttributeAction
4
+ def execute_for_attribute(target_element, name, value)
5
+ target_element.remove_attribute(name)
6
+ target_element.remove_attribute("data-erb-#{name}")
7
+
8
+ target_element.set_attribute("data-erb-#{name}", value.to_s)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module Deface
2
+ module Actions
3
+ class Surround < SurroundAction
4
+ def execute(target_range)
5
+ original_placeholders.each do |placeholder|
6
+ start = target_range[0].clone(1)
7
+ placeholder.replace start
8
+
9
+ target_range[1..-1].each do |element|
10
+ element = element.clone(1)
11
+ start.after element
12
+ start = element
13
+ end
14
+ end
15
+ target_range.first.before(source_element)
16
+ target_range.map(&:remove)
17
+ end
18
+
19
+ def range_compatible?
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module Deface
2
+ module Actions
3
+ class SurroundAction < ElementAction
4
+ def source_element
5
+ @cloned_source_element ||= super.clone(1)
6
+ end
7
+
8
+ def original_placeholders
9
+ @original_placeholders ||= source_element.css("code:contains('render_original')")
10
+ raise(DefaceError, "The surround action couldn't find <%= render_original %> in your template") unless @original_placeholders.first
11
+ @original_placeholders
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module Deface
2
+ module Actions
3
+ class SurroundContents < SurroundAction
4
+ def execute(target_range)
5
+ if target_range.length == 1
6
+ target_element = target_range.first
7
+ original_placeholders.each do |placeholder|
8
+ placeholder.replace target_element.clone(1).children
9
+ end
10
+ target_element.children.remove
11
+ target_element.add_child(source_element)
12
+ else
13
+ original_placeholders.each do |placeholder|
14
+ start = target_range[1].clone(1)
15
+ placeholder.replace start
16
+
17
+ target_range[2...-1].each do |element|
18
+ element = element.clone(1)
19
+ start.after(element)
20
+ start = element
21
+ end
22
+ end
23
+ target_range.first.after(source_element)
24
+ target_range[1...-1].map(&:remove)
25
+ end
26
+ end
27
+
28
+ def range_compatible?
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
@@ -25,171 +25,18 @@ module Deface
25
25
  end
26
26
 
27
27
  override.parsed_document = doc
28
+ matches = override.matcher.matches(doc, log)
28
29
 
29
- if override.end_selector.blank?
30
- # single css selector
31
-
32
- matches = doc.css(override.selector)
33
-
34
- if log
35
- Rails.logger.send(matches.size == 0 ? :error : :info, "\e[1;32mDeface:\e[0m '#{override.name}' matched #{matches.size} times with '#{override.selector}'")
36
- end
37
-
38
- matches.each do |match|
39
- override.validate_original(match)
40
-
41
- case override.action
42
- when :remove
43
- match.replace ""
44
- when :replace
45
- match.replace override.source_element
46
- when :replace_contents
47
- match.children.remove
48
- match.add_child(override.source_element)
49
- when :surround, :surround_contents
50
-
51
- new_source = override.source_element.clone(1)
52
-
53
- if original = new_source.css("code:contains('render_original')").first
54
- if override.action == :surround
55
- original.replace match.clone(1)
56
- match.replace new_source
57
- elsif override.action == :surround_contents
58
- original.replace match.children
59
- match.children.remove
60
- match.add_child new_source
61
- end
62
- else
63
- #maybe we should log that the original wasn't found.
64
- end
65
-
66
- when :insert_before
67
- match.before override.source_element
68
- when :insert_after
69
- match.after override.source_element
70
- when :insert_top
71
- if match.children.size == 0
72
- match.children = override.source_element
73
- else
74
- match.children.before(override.source_element)
75
- end
76
- when :insert_bottom
77
- if match.children.size == 0
78
- match.children = override.source_element
79
- else
80
- match.children.after(override.source_element)
81
- end
82
- when :set_attributes
83
- override.attributes.each do |name, value|
84
- name = normalize_attribute_name(name)
85
-
86
- match.remove_attribute(name)
87
- match.remove_attribute("data-erb-#{name}")
88
-
89
- if match.attributes.key? name
90
- match.set_attribute name, value.to_s
91
- else
92
- match.set_attribute "data-erb-#{name}", value.to_s
93
- end
94
- end
95
- when :add_to_attributes
96
- override.attributes.each do |name, value|
97
- name = normalize_attribute_name(name)
98
-
99
- if match.attributes.key? name
100
- match.set_attribute name, match.attributes[name].value << " #{value}"
101
- elsif match.attributes.key? "data-erb-#{name}"
102
- match.set_attribute "data-erb-#{name}", match.attributes["data-erb-#{name}"].value << " #{value}"
103
- else
104
- match.set_attribute "data-erb-#{name}", value.to_s
105
- end
106
-
107
- end
108
- when :remove_from_attributes
109
- override.attributes.each do |name, value|
110
- name = normalize_attribute_name(name)
111
-
112
- if match.attributes.key? name
113
- match.set_attribute name, match.attributes[name].value.gsub(value.to_s, '').strip
114
- elsif match.attributes.key? "data-erb-#{name}"
115
- match.set_attribute "data-erb-#{name}", match.attributes["data-erb-#{name}"].value.gsub(value.to_s, '').strip
116
- end
117
- end
118
-
119
- end
120
-
121
- end
122
- else
123
- unless [:remove, :replace, :replace_contents, :surround, :surround_contents].include? override.action
124
- raise Deface::NotSupportedError, ":#{override.action} action does not support :closing_selector"
125
- end
126
- # targeting range of elements as end_selector is present
127
- starting, ending = select_endpoints(doc, override.selector, override.end_selector)
128
-
129
- if starting && ending
130
- if log
131
- Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' matched starting with '#{override.selector}' and ending with '#{override.end_selector}'")
132
- end
133
-
134
- elements = select_range(starting, ending)
135
-
136
- case override.action
137
- when :remove
138
- elements.map &:remove
139
- when :replace
140
- starting.before(override.source_element)
141
- elements.map &:remove
142
- when :replace_contents
143
- elements[1..-2].map &:remove
144
- starting.after(override.source_element)
145
- when :surround, :surround_contents
146
-
147
- new_source = override.source_element.clone(1)
148
-
149
- if original = new_source.css("code:contains('render_original')").first
150
-
151
- if override.action == :surround
152
- start = elements[0].clone(1)
153
- original.replace start
154
-
155
- elements[1..-1].each do |element|
156
- element = element.clone(1)
157
- start.after element
158
- start = element
159
- end
160
-
161
- starting.before(new_source)
162
- elements.map &:remove
163
-
164
-
165
- elsif override.action == :surround_contents
166
-
167
- start = elements[1].clone(1)
168
- original.replace start
169
-
170
- elements[2...-1].each do |element|
171
- element = element.clone(1)
172
- start.after element
173
- start = element
174
- end
175
-
176
- starting.after(new_source)
177
- elements[1...-1].map &:remove
178
- end
179
- else
180
- #maybe we should log that the original wasn't found.
181
- end
182
- end
183
- else
184
- if starting.nil?
185
- Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with starting selector '#{override.selector}'")
186
- else
187
- Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with end selector '#{override.end_selector}'")
188
- end
189
-
190
- end
30
+ if log
31
+ Rails.logger.send(matches.size == 0 ? :error : :info, "\e[1;32mDeface:\e[0m '#{override.name}' matched #{matches.size} times with '#{override.selector}'")
191
32
  end
192
33
 
34
+ if matches.empty?
35
+ override.failure = "failed to match :#{override.action} selector '#{override.selector}'"
36
+ else
37
+ override.failure = nil
38
+ matches.each {|match| override.execute_action match }
39
+ end
193
40
  end
194
41
 
195
42
  #prevents any caching by rails in development mode
@@ -202,41 +49,38 @@ module Deface
202
49
 
203
50
  source
204
51
  end
52
+ end
205
53
 
54
+ def execute_action(target_element)
55
+ validate_original(target_element)
56
+ create_action_command.execute(target_element)
57
+ end
206
58
 
207
- def select_endpoints(doc, start, finish)
208
- # targeting range of elements as end_selector is present
209
- #
210
- finish = "#{start} ~ #{finish}"
211
- starting = doc.css(start).first
212
-
213
- ending = if starting && starting.parent
214
- starting.parent.css(finish).first
215
- else
216
- doc.css(finish).first
217
- end
218
-
219
- return starting, ending
220
-
221
- end
222
-
223
- # finds all elements upto closing sibling in nokgiri document
224
- #
225
- def select_range(first, last)
226
- first == last ? [first] : [first, *select_range(first.next, last)]
227
- end
228
-
229
- private
59
+ def execute_action_on_range(target_range)
60
+ create_action_command.execute_on_range(target_range)
61
+ end
230
62
 
231
- def normalize_attribute_name(name)
232
- name = name.to_s.gsub /"|'/, ''
63
+ def create_action_command
64
+ commands = Rails.application.config.deface.actions
65
+ command = commands.find { |command| command.to_sym == action }
66
+ raise(DefaceError, "Action #{action} not found") unless command
67
+ command.new(:source_element => safe_source_element, :attributes => attributes)
68
+ end
233
69
 
234
- if /\Adata-erb-/ =~ name
235
- name.gsub! /\Adata-erb-/, ''
236
- end
70
+ def compatible_with_end_selector?
71
+ create_action_command.range_compatible?
72
+ end
237
73
 
238
- name
74
+ def matcher
75
+ if end_selector.blank?
76
+ Deface::Matchers::Element.new(selector) # single css selector
77
+ else
78
+ unless compatible_with_end_selector?
79
+ raise Deface::NotSupportedError, ":#{action} action does not support :closing_selector"
239
80
  end
81
+ # targeting range of elements as end_selector is present
82
+ Deface::Matchers::Range.new(name, selector, end_selector)
83
+ end
240
84
  end
241
85
  end
242
86
  end