deface 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,13 @@
1
+ <p style="float:right;">
2
+ <a href="http://travis-ci.org/#!/railsdog/deface">
3
+ <img src="http://travis-ci.org/railsdog/deface.png">
4
+ </a>
5
+ </p>
6
+
1
7
  Deface
2
8
  ======
3
9
 
4
- Deface is a library that allows you to customize ERB views in a Rails application without editing the underlying view.
10
+ Deface is a library that allows you to customize HTML ERB views in a Rails application without editing the underlying view.
5
11
 
6
12
  It allows you to easily target html & erb elements as the hooks for customization using CSS selectors as supported by Nokogiri.
7
13
 
@@ -50,7 +56,9 @@ Optional
50
56
 
51
57
  * <tt>:disabled</tt> - When set to true the override will not be applied.
52
58
 
53
- * <tt>:original</tt> - String containing original markup that is being overridden. If supplied Deface will log when the original markup changes, which helps highlight overrides that need attention when upgrading versions of the source application. Only really warranted for :replace overrides. NB: All whitespace is stripped before comparsion.
59
+ * <tt>:original</tt> - String containing original markup that is being overridden. If supplied Deface will log when the original markup changes, which helps highlight overrides that need attention when upgrading versions of the source application. Only really warranted for :replace overrides. NB: All whitespace is stripped before comparison.
60
+
61
+ * <tt>:closing_selector</tt> - A second css selector targeting an end element, allowing you to select a range of elements to apply an action against. The :closing_selector only supports the :replace, :remove and :replace_contents actions, and the end element must be a sibling of the first/starting element. Note the CSS general sibling selector (~) is used to match the first element after the opening selector (see below for an example).
54
62
 
55
63
  * <tt>:sequence</tt> - Used to order the application of an override for a specific virtual path, helpful when an override depends on another override being applied first, supports:
56
64
  * <tt>:sequence => n</tt> - where n is a positive or negative integer (lower numbers get applied first, default 100).
@@ -85,7 +93,7 @@ Inserts the contents of `shared/_comment.html.erb` after all instances of `div`
85
93
  :insert_after => "div#comment_21",
86
94
  :partial => "shared/comment")
87
95
 
88
- Removes any ERB block containing the string `helper_method` in the `posts/new.html.erb` template, will also log if markup being removed does not match `<%= helper_method %>`
96
+ Removes any ERB block containing the string `helper_method` in the `posts/new.html.erb` template, will also log if markup being removed does not exactly match `<%= helper_method %>`
89
97
 
90
98
  Deface::Override.new(:virtual_path => "posts/new",
91
99
  :name => "example-4",
@@ -99,6 +107,46 @@ Sets (or adds if not present) the `class` and `title` attributes to all instance
99
107
  :set_attributes => 'a#link',
100
108
  :attributes => {:class => 'pretty', :title => 'This is a link'})
101
109
 
110
+ Remove an entire ERB if statement (and all it's contents) in the 'admin/products/index.html.erb' template, using the :closing_selector.
111
+
112
+ Deface::Override.new(:virtual_path => 'admin/products/index',
113
+ :name => "remove_if_statement",
114
+ :remove => "code[:erb-silent]:contains('if @product.sold?')",
115
+ :closing_selector => "code[:erb-silent]:contains('end')"
116
+
117
+ Scope
118
+ =====
119
+
120
+ Deface scopes overrides by virtual_path (or partial / template file), that means all override names only need to be unique within that single file.
121
+
122
+ Redefining Overrides
123
+ ====================
124
+
125
+ You can redefine an existing override by simply declaring a new override with the same <tt>:virtual_path</tt> and <tt>:name</tt> that was originally used.
126
+ You do not need to resupply all the values originally used, just the ones you want to change:
127
+
128
+ Deface::Override.new(:virtual_path => 'posts/index',
129
+ :name => 'add_attrs_to_a_link',
130
+ :disabled => true)
131
+
132
+ Rake Tasks
133
+ ==========
134
+
135
+ Deface includes a couple of rake tasks that can be helpful when defining or debugging overrides.
136
+
137
+ **deface:get_result** - Will list the original contents of a partial or template, the overrides that have been defined for a that file, and the resulting markup. *get_result* takes a single argument which is the virtual path of the template / partial:
138
+
139
+ rake deface:get_result[shared/_head]
140
+
141
+ rake deface:get_result['admin/products/index']
142
+
143
+ **deface:test_selector** - Applies a given CSS selector against a parital or template and outputs the markup for each match (if any). *test_selector* requires two arguments, the first is the virtual_path for the partial / template, the second is the CSS selector to apply:
144
+
145
+ rake deface:test_selector[shared/_head,title]
146
+
147
+ rake deface:test_selector['admin/products/index','div.toolbar']
148
+
149
+
102
150
  Implementation
103
151
  ==============
104
152
 
data/Rakefile CHANGED
@@ -1,24 +1,12 @@
1
1
  require 'rake'
2
2
  require 'rubygems'
3
3
  require 'rake/testtask'
4
- require 'rake/rdoctask'
4
+ require 'rdoc/task'
5
5
  require 'rspec'
6
6
  require 'rspec/core/rake_task'
7
7
 
8
8
  desc 'Default: run specs'
9
9
  task :default => :spec
10
- Rspec::Core::RakeTask.new do |t|
10
+ RSpec::Core::RakeTask.new do |t|
11
11
  t.pattern = "spec/**/*_spec.rb"
12
12
  end
13
-
14
-
15
- task :default => :spec
16
-
17
- desc 'Generate documentation for the deface plugin.'
18
- Rake::RDocTask.new(:rdoc) do |rdoc|
19
- rdoc.rdoc_dir = 'rdoc'
20
- rdoc.title = 'Spreme'
21
- rdoc.options << '--line-numbers' << '--inline-source'
22
- rdoc.rdoc_files.include('README')
23
- rdoc.rdoc_files.include('lib/**/*.rb')
24
- end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "deface"
3
- s.version = "0.6.1"
3
+ s.version = "0.7.0"
4
4
 
5
5
  s.authors = ["Brian D Quinn"]
6
6
  s.description = "Deface is a library that allows you to customize ERB views in a Rails application without editing the underlying view."
@@ -4,7 +4,10 @@ require "deface/action_view_extensions"
4
4
  require "deface/template_helper"
5
5
  require "deface/override"
6
6
  require "deface/parser"
7
+ require "deface/environment"
7
8
 
8
9
  module Deface
9
- require 'deface/railtie' if defined?(Rails)
10
+ if defined?(Rails)
11
+ require "deface/railtie"
12
+ end
10
13
  end
@@ -0,0 +1,30 @@
1
+ module Deface
2
+
3
+ class Environment
4
+ attr_accessor :overrides
5
+ def initialize
6
+ @overrides = Overrides.new
7
+ end
8
+ end
9
+
10
+ class Environment::Overrides
11
+ attr_accessor :all
12
+
13
+ def initialize
14
+ @all = {}
15
+ end
16
+
17
+ def find(*args)
18
+ Deface::Override.find(*args)
19
+ end
20
+
21
+ def early_check
22
+ Deface::Override._early.each do |args|
23
+ Deface::Override.new(args)
24
+ end
25
+
26
+ Deface::Override._early.clear
27
+ end
28
+ end
29
+ end
30
+
@@ -2,11 +2,12 @@ module Deface
2
2
  class Override
3
3
  include Deface::TemplateHelper
4
4
 
5
- cattr_accessor :all, :actions
5
+ cattr_accessor :actions, :_early
6
6
  attr_accessor :args
7
7
 
8
- @@all ||= {}
9
- @@actions = [:remove, :replace, :insert_after, :insert_before, :insert_top, :insert_bottom, :set_attributes]
8
+ @@_early = []
9
+ @@actions = [:remove, :replace, :replace_contents, :insert_after, :insert_before, :insert_top, :insert_bottom, :set_attributes]
10
+ @@sources = [:text, :partial, :template]
10
11
 
11
12
  # Initializes new override, you must supply only one Target, Action & Source
12
13
  # parameter for each override (and any number of Optional parameters).
@@ -21,6 +22,7 @@ module Deface
21
22
  #
22
23
  # * <tt>:remove</tt> - Removes all elements that match the supplied selector
23
24
  # * <tt>:replace</tt> - Replaces all elements that match the supplied selector
25
+ # * <tt>:replace_contents</tt> - Replaces the contents of all elements that match the supplied selector
24
26
  # * <tt>:insert_after</tt> - Inserts after all elements that match the supplied selector
25
27
  # * <tt>:insert_before</tt> - Inserts before all elements that match the supplied selector
26
28
  # * <tt>:insert_top</tt> - Inserts inside all elements that match the supplied selector, before all existing child
@@ -42,6 +44,10 @@ module Deface
42
44
  # If supplied Deface will log when the original markup changes, which helps highlight overrides that need
43
45
  # attention when upgrading versions of the source application. Only really warranted for :replace overrides.
44
46
  # NB: All whitespace is stripped before comparsion.
47
+ # * <tt>:closing_selector</tt> - A second css selector targeting an end element, allowing you to select a range
48
+ # of elements to apply an action against. The :closing_selector only supports the :replace, :remove and
49
+ # :replace_contents actions, and the end element must be a sibling of the first/starting element. Note the CSS
50
+ # general sibling selector (~) is used to match the first element after the opening selector.
45
51
  # * <tt>:sequence</tt> - Used to order the application of an override for a specific virtual path, helpful when
46
52
  # an override depends on another override being applied first.
47
53
  # Supports:
@@ -53,15 +59,43 @@ module Deface
53
59
  # * <tt>:attributes</tt> - A hash containing all the attributes to be set on the matched elements, eg: :attributes => {:class => "green", :title => "some string"}
54
60
  #
55
61
  def initialize(args)
56
- @args = args
62
+ unless Rails.application.try(:config).try(:deface)
63
+ @@_early << args
64
+ warn "[WARNING] Deface railtie has not initialized yet, override '#{args[:name]}' is being declared too early."
65
+ return
66
+ end
57
67
 
58
- raise(ArgumentError, "Invalid action") if self.action.nil?
68
+ raise(ArgumentError, ":name must be defined") unless args.key? :name
59
69
  raise(ArgumentError, ":virtual_path must be defined") if args[:virtual_path].blank?
60
70
 
61
- key = args[:virtual_path].to_sym
71
+ virtual_key = args[:virtual_path].to_sym
72
+ name_key = args[:name].to_s.parameterize
73
+
74
+ self.class.all[virtual_key] ||= {}
75
+
76
+ if self.class.all[virtual_key].has_key? name_key
77
+ #updating exisiting override
78
+
79
+ @args = self.class.all[virtual_key][name_key].args
62
80
 
63
- @@all[key] ||= {}
64
- @@all[key][args[:name].to_s.parameterize] = self
81
+ #check if the action is being redefined, and reject old action
82
+ if (@@actions & args.keys).present?
83
+ @args.reject!{|key, value| (@@actions & @args.keys).include? key }
84
+ end
85
+
86
+ #check if the source is being redefined, and reject old action
87
+ if (@@sources & args.keys).present?
88
+ @args.reject!{|key, value| (@@sources & @args.keys).include? key }
89
+ end
90
+
91
+ @args.merge!(args)
92
+ else
93
+ #initializing new override
94
+ @args = args
95
+ raise(ArgumentError, ":action is invalid") if self.action.nil?
96
+ end
97
+
98
+ self.class.all[virtual_key][name_key] = self
65
99
  end
66
100
 
67
101
  def selector
@@ -80,16 +114,16 @@ module Deface
80
114
  if @args[:sequence].key? :before
81
115
  ref_name = @args[:sequence][:before]
82
116
 
83
- if @@all[key].key? ref_name.to_s
84
- return @@all[key][ref_name.to_s].sequence - 1
117
+ if self.class.all[key].key? ref_name.to_s
118
+ return self.class.all[key][ref_name.to_s].sequence - 1
85
119
  else
86
120
  return 100
87
121
  end
88
122
  elsif @args[:sequence].key? :after
89
123
  ref_name = @args[:sequence][:after]
90
124
 
91
- if @@all[key].key? ref_name.to_s
92
- return @@all[key][ref_name.to_s].sequence + 1
125
+ if self.class.all[key].key? ref_name.to_s
126
+ return self.class.all[key][ref_name.to_s].sequence + 1
93
127
  else
94
128
  return 100
95
129
  end
@@ -139,7 +173,7 @@ module Deface
139
173
 
140
174
  valid = self.original_source.to_s.gsub(/\s/, '') == match.to_s.gsub(/\s/, '')
141
175
 
142
- if !valid && defined?(Rails) == "constant"
176
+ if !valid && defined?(Rails.logger) == "constant"
143
177
  Rails.logger.error "\e[1;32mDeface: [WARNING]\e[0m The original source for '#{self.name}' has changed, this override should be reviewed to ensure it's still valid."
144
178
  end
145
179
 
@@ -151,7 +185,8 @@ module Deface
151
185
  end
152
186
 
153
187
  def end_selector
154
- @args[:closing_selector]
188
+ return nil if @args[:closing_selector].blank?
189
+ "#{self.selector} ~ #{@args[:closing_selector]}"
155
190
  end
156
191
 
157
192
  def attributes
@@ -164,12 +199,10 @@ module Deface
164
199
  overrides = find(details)
165
200
 
166
201
  if log
167
- @enable_logging ||= defined?(Rails)
168
- else
169
- @enable_logging = false
202
+ log = defined?(Rails.logger)
170
203
  end
171
204
 
172
- if @enable_logging && overrides.size > 0
205
+ if log && overrides.size > 0
173
206
  Rails.logger.info "\e[1;32mDeface:\e[0m #{overrides.size} overrides found for '#{details[:virtual_path]}'"
174
207
  end
175
208
 
@@ -178,7 +211,7 @@ module Deface
178
211
 
179
212
  overrides.each do |override|
180
213
  if override.disabled?
181
- Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' is disabled") if @enable_logging
214
+ Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' is disabled") if log
182
215
  next
183
216
  end
184
217
 
@@ -187,7 +220,7 @@ module Deface
187
220
 
188
221
  matches = doc.css(override.selector)
189
222
 
190
- if @enable_logging
223
+ if log
191
224
  Rails.logger.send(matches.size == 0 ? :error : :info, "\e[1;32mDeface:\e[0m '#{override.name}' matched #{matches.size} times with '#{override.selector}'")
192
225
  end
193
226
 
@@ -199,14 +232,25 @@ module Deface
199
232
  match.replace ""
200
233
  when :replace
201
234
  match.replace override.source_element
235
+ when :replace_contents
236
+ match.children.remove
237
+ match.add_child(override.source_element)
202
238
  when :insert_before
203
239
  match.before override.source_element
204
240
  when :insert_after
205
241
  match.after override.source_element
206
242
  when :insert_top
207
- match.children.before(override.source_element)
243
+ if match.children.size == 0
244
+ match.children = override.source_element
245
+ else
246
+ match.children.before(override.source_element)
247
+ end
208
248
  when :insert_bottom
209
- match.children.after(override.source_element)
249
+ if match.children.size == 0
250
+ match.children = override.source_element
251
+ else
252
+ match.children.after(override.source_element)
253
+ end
210
254
  when :set_attributes
211
255
  override.attributes.each do |name, value|
212
256
  match.set_attribute(name.to_s, value.to_s)
@@ -217,6 +261,7 @@ module Deface
217
261
  else
218
262
  # targeting range of elements as end_selector is present
219
263
  starting = doc.css(override.selector).first
264
+
220
265
  if starting && starting.parent
221
266
  ending = starting.parent.css(override.end_selector).first
222
267
  else
@@ -224,14 +269,29 @@ module Deface
224
269
  end
225
270
 
226
271
  if starting && ending
272
+ if log
273
+ Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' matched starting with '#{override.selector}' and ending with '#{override.end_selector}'")
274
+ end
275
+
227
276
  elements = select_range(starting, ending)
228
277
 
229
- if override.action == :replace
230
- starting.before(override.source_element)
278
+ case override.action
279
+ when :remove
280
+ elements.map &:remove
281
+ when :replace
282
+ starting.before(override.source_element)
283
+ elements.map &:remove
284
+ when :replace_contents
285
+ elements[1..-2].map &:remove
286
+ starting.after(override.source_element)
287
+ end
288
+ else
289
+ if starting.nil?
290
+ Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with starting selector '#{override.selector}'")
291
+ else
292
+ Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with end selector '#{override.end_selector}'")
231
293
  end
232
294
 
233
- #now remove all matched elements
234
- elements.map &:remove
235
295
  end
236
296
  end
237
297
 
@@ -251,17 +311,22 @@ module Deface
251
311
  # finds all applicable overrides for supplied template
252
312
  #
253
313
  def self.find(details)
254
- return [] if @@all.empty? || details.empty?
314
+ return [] if self.all.empty? || details.empty?
255
315
 
256
316
  virtual_path = details[:virtual_path]
257
317
  return [] if virtual_path.nil?
258
318
 
259
319
  result = []
260
- result << @@all[virtual_path.to_sym].try(:values)
320
+ result << self.all[virtual_path.to_sym].try(:values)
261
321
 
262
322
  result.flatten.compact.sort_by &:sequence
263
323
  end
264
324
 
325
+
326
+ def self.all
327
+ Rails.application.config.deface.overrides.all
328
+ end
329
+
265
330
  private
266
331
  # finds all elements upto closing sibling in nokgiri document
267
332
  #
@@ -3,5 +3,10 @@ module Deface
3
3
  rake_tasks do
4
4
  load File.join([File.dirname(__FILE__) , "../../tasks/deface.rake"])
5
5
  end
6
+
7
+ initializer "deface.environment" do |app|
8
+ app.config.deface = Deface::Environment.new
9
+ app.config.deface.overrides.early_check
10
+ end
6
11
  end
7
12
  end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ module Deface
4
+ describe Environment do
5
+ include_context "mock Rails"
6
+
7
+ before(:each) do
8
+ #declare this override (early) before Rails.application.deface is present
9
+ silence_warnings do
10
+ Deface::Override._early.clear
11
+ Deface::Override.new(:virtual_path => "posts/edit", :name => "Posts#edit", :replace => "h1", :text => "<h1>Urgh!</h1>")
12
+ end
13
+ end
14
+
15
+ include_context "mock Rails.application"
16
+
17
+ before(:each) do
18
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
19
+ Deface::Override.new(:virtual_path => "posts/new", :name => "Posts#new", :replace => "h1", :text => "<h1>argh!</h1>")
20
+ end
21
+
22
+ describe ".overrides" do
23
+
24
+ it "should return all overrides" do
25
+ Rails.application.config.deface.overrides.all.size.should == 2
26
+ Rails.application.config.deface.overrides.all.should == Deface::Override.all
27
+ end
28
+
29
+ it "should find overrides" do
30
+ Rails.application.config.deface.overrides.find(:virtual_path => "posts/new").size.should == 1
31
+ end
32
+ end
33
+
34
+ describe "#_early" do
35
+ it "should contain one override" do
36
+ Deface::Override._early.size.should == 1
37
+ end
38
+
39
+ it "should initialize override and be emtpy after early_check" do
40
+ before_count = Rails.application.config.deface.overrides.all.size
41
+ Rails.application.config.deface.overrides.early_check
42
+
43
+ Deface::Override._early.size.should == 0
44
+ Rails.application.config.deface.overrides.all.size.should == (before_count + 1)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -2,12 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  module Deface
4
4
  describe Override do
5
+ include_context "mock Rails.application"
6
+
5
7
  before(:each) do
6
8
  @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
7
9
  end
8
10
 
9
11
  it "should return correct action" do
10
12
  Deface::Override.actions.each do |action|
13
+ Rails.application.config.deface.overrides.all.clear
11
14
  @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", action => "h1", :text => "<h1>Argh!</h1>")
12
15
  @override.action.should == action
13
16
  end
@@ -29,21 +32,28 @@ module Deface
29
32
  end
30
33
  end
31
34
 
32
- describe "#validate_original" do
35
+ describe "#validate_original when :original is not present" do
33
36
  before(:each) do
34
- @original = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>", :original => "<p><%= something %></p>")
37
+ @original = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
35
38
  end
36
39
 
37
- it "should return true when :original is not present" do
38
- @override.validate_original("").should be_true
40
+ it "should not validate" do
41
+ @override.validate_original("<p>this gets ignored</p>").should be_true
42
+ end
43
+
44
+ end
45
+
46
+ describe "#validate_original when :original is present" do
47
+ before(:each) do
48
+ @original = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Argh!</h1>", :original => "<p><%= something %></p>")
39
49
  end
40
50
 
41
- it "should return true when :original present, and input contains similar (ignoring whitespace)" do
51
+ it "should return true when input contains similar (ignoring whitespace)" do
42
52
  @original.validate_original("<p><code erb-loud> something </code></p>").should be_true
43
53
  @original.validate_original("<p><code erb-loud>something\n</code> </p>").should be_true
44
54
  end
45
55
 
46
- it "should return false when :original present, and input contains different string" do
56
+ it "should return false when and input contains different string" do
47
57
  @original.validate_original("wrong").should be_false
48
58
  end
49
59
  end
@@ -121,25 +131,60 @@ module Deface
121
131
  end
122
132
  end
123
133
 
124
- describe "when redefining an existing virutal_path and name" do
134
+ describe "when redefining an override without changing action or source type" do
125
135
  before(:each) do
126
- @replacement = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Arrrr!</h1>")
136
+ Rails.application.config.deface.overrides.all.clear
137
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :text => "<h1>Argh!</h1>", :replace => "h1")
138
+ expect {
139
+ @replacement = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :text => "<h1>Arrrr!</h1>")
140
+ }.to change{Rails.application.config.deface.overrides.all.size}.by(0)
141
+ end
142
+
143
+ it "should return new source" do
144
+ @replacement.source.should_not == "<h1>Argh!</h1>"
145
+ @replacement.source.should == "<h1>Arrrr!</h1>"
127
146
  end
128
147
 
129
- it "should not increase all#size by 1" do
148
+ end
149
+
150
+ describe "when redefining an override when changing action" do
151
+ before(:each) do
152
+ Rails.application.config.deface.overrides.all.clear
153
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1")
130
154
  expect {
131
- Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :text => "<h1>Arrrr!</h1>")
132
- }.to change{Deface::Override.all.size}.by(0)
155
+ @replacement = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "h1")
156
+ }.to change{Rails.application.config.deface.overrides.all.size}.by(0)
157
+ end
158
+
159
+ it "should return new action" do
160
+ @replacement.action.should == :insert_after
161
+ end
162
+
163
+ it "should remove old action" do
164
+ @replacement.args.has_key?(:replace).should be_false
165
+ end
166
+
167
+ end
168
+
169
+ describe "when redefining an override when changing source type" do
170
+ before(:each) do
171
+ #stub view paths to be local spec/assets directory
172
+ ActionController::Base.stub(:view_paths).and_return([File.join(File.dirname(__FILE__), '..', "assets")])
133
173
 
174
+ Rails.application.config.deface.overrides.all.clear
175
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :partial => "shared/post", :replace => "h1")
176
+ expect {
177
+ @replacement = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :text => "<p>I do be a pirate!</p>")
178
+ }.to change{Rails.application.config.deface.overrides.all.size}.by(0)
134
179
  end
135
180
 
136
181
  it "should return new source" do
137
- @replacement.source.should_not == @override.source
138
- @replacement.source.should == "<h1>Arrrr!</h1>"
182
+ @override.source.should == "<p>I do be a pirate!</p>"
139
183
  end
140
184
 
141
185
  end
142
186
 
187
+
143
188
  describe "#sequence" do
144
189
  it "should calculate correct after sequences" do
145
190
  @third = Deface::Override.new(:virtual_path => "posts/index", :name => "third", :insert_after => "li:contains('second')", :text => "<li>third</li>", :sequence => {:after => "second"})
@@ -157,19 +202,38 @@ module Deface
157
202
 
158
203
  @second.sequence.should == 99
159
204
  @first.sequence.should == 98
160
-
161
205
  end
162
206
 
163
-
164
207
  it "should calculate correct sequences with invalid hash" do
165
208
  @second = Deface::Override.new(:virtual_path => "posts/index", :name => "second", :insert_after => "li", :text => "<li>second</li>", :sequence => {})
166
209
  @first = Deface::Override.new(:virtual_path => "posts/show", :name => "first", :replace => "li", :text => "<li>first</li>", :sequence => {:before => "second"})
167
210
 
168
211
  @second.sequence.should == 100
169
212
  @first.sequence.should == 100
213
+ end
214
+
215
+ end
216
+
170
217
 
218
+ describe "#end_selector" do
219
+ it "should return nil when closing_selector is not defined" do
220
+ @override.end_selector.should be_nil
171
221
  end
172
222
 
223
+ it "should return nil when closing_selector is an empty string" do
224
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :closing_selector => "", :text => "<h1>Argh!</h1>")
225
+ @override.end_selector.should be_nil
226
+ end
227
+
228
+ it "should return nil when closing_selector is nil" do
229
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :closing_selector => nil, :text => "<h1>Argh!</h1>")
230
+ @override.end_selector.should be_nil
231
+ end
232
+
233
+ it "should return combined sibling selector when closing_selector is present" do
234
+ @override = Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :closing_selector => "h4", :text => "<h1>Argh!</h1>")
235
+ @override.end_selector.should == "h1 ~ h4"
236
+ end
173
237
  end
174
238
 
175
239
  end
@@ -14,19 +14,27 @@ module Deface
14
14
  it "should parse html document" do
15
15
  parsed = Deface::Parser.convert("<html><head><title>Hello</title></head><body>test</body>")
16
16
  parsed.should be_an_instance_of(Nokogiri::HTML::Document)
17
- parsed = parsed.to_s.split("\n")[1..-1]
18
- parsed.should == "<html>\n<head><title>Hello</title></head>\n<body>test</body>\n</html>".split("\n") #ignore doctype added by noko
17
+ parsed = parsed.to_s.split("\n")[1..-1] #ignore doctype added by noko
18
+
19
+ if RUBY_VERSION < "1.9"
20
+ parsed.should == "<html>\n<head><title>Hello</title></head>\n<body>test</body>\n</html>".split("\n")
21
+ else
22
+ parsed.should == "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=US-ASCII\">\n<title>Hello</title>\n</head>\n<body>test</body>\n</html>".split("\n")
23
+ end
19
24
 
20
25
  parsed = Deface::Parser.convert("<html><title>test</title></html>")
21
26
  parsed.should be_an_instance_of(Nokogiri::HTML::Document)
22
- parsed = parsed.to_s.split("\n")[1..-1]
23
- parsed.should == "<html><head><title>test</title></head></html>".split("\n") #ignore doctype added by noko
24
-
27
+ parsed = parsed.to_s.split("\n")[1..-1] #ignore doctype added by noko
28
+ if RUBY_VERSION < "1.9"
29
+ parsed.should == ["<html><head><title>test</title></head></html>"]
30
+ else
31
+ parsed.should == "<html><head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=US-ASCII\">\n<title>test</title>\n</head></html>".split("\n")
32
+ end
25
33
 
26
34
  parsed = Deface::Parser.convert("<html><p>test</p></html>")
27
35
  parsed.should be_an_instance_of(Nokogiri::HTML::Document)
28
- parsed = parsed.to_s.split("\n")[1..-1]
29
- parsed.should == "<html><body><p>test</p></body></html>".split("\n") #ignore doctype added by noko
36
+ parsed = parsed.to_s.split("\n")[1..-1] #ignore doctype added by noko
37
+ parsed.should == "<html><body><p>test</p></body></html>".split("\n")
30
38
  end
31
39
 
32
40
  it "should parse body tag" do
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module Deface
4
4
  describe TemplateHelper do
5
+ include_context "mock Rails.application"
5
6
  include Deface::TemplateHelper
6
7
 
7
8
  describe "load_template_source" do
@@ -30,8 +31,9 @@ module Deface
30
31
  end
31
32
 
32
33
  describe "with overrides defined" do
33
- before(:all) do
34
- Deface::Override.all.clear
34
+ include_context "mock Rails.application"
35
+
36
+ before(:each) do
35
37
  Deface::Override.new(:virtual_path => "shared/_post", :name => "shared#post", :remove => "p")
36
38
  Deface::Override.new(:virtual_path => "shared/person", :name => "shared#person", :replace => "p", :text => "<h1>Argh!</h1>")
37
39
  Deface::Override.new(:virtual_path => "admin/posts/index", :name => "admin#posts#index", :replace => "h1", :text => "<h1>Argh!</h1>")
@@ -2,9 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module ActionView
4
4
  describe Template do
5
- before(:all) do
6
- Deface::Override.all.clear
7
- end
5
+ include_context "mock Rails.application"
8
6
 
9
7
  describe "with no overrides defined" do
10
8
  before(:each) do
@@ -50,8 +48,19 @@ module ActionView
50
48
  end
51
49
  end
52
50
 
51
+ describe "with a single remove override with closing_selector defined" do
52
+ before(:each) do
53
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :remove => "h1", :closing_selector => "h2")
54
+ @template = ActionView::Template.new("<h2>I should be safe</h2><span>Before!</span><h1>start</h1><p>some junk</p><div>more junk</div><h2>end</h2><span>After!</span>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
55
+ end
56
+
57
+ it "should return modified source" do
58
+ @template.source.should == "<h2>I should be safe</h2><span>Before!</span><span>After!</span>"
59
+ end
60
+ end
61
+
53
62
  describe "with a single replace override defined" do
54
- before(:all) do
63
+ before(:each) do
55
64
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "p", :text => "<h1>Argh!</h1>")
56
65
  @template = ActionView::Template.new("<p>test</p>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
57
66
  end
@@ -61,8 +70,41 @@ module ActionView
61
70
  end
62
71
  end
63
72
 
73
+ describe "with a single replace override with closing_selector defined" do
74
+ before(:each) do
75
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1", :closing_selector => "h2", :text => "<span>Argh!</span>")
76
+ @template = ActionView::Template.new("<h1>start</h1><p>some junk</p><div>more junk</div><h2>end</h2>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
77
+ end
78
+
79
+ it "should return modified source" do
80
+ @template.source.should == "<span>Argh!</span>"
81
+ end
82
+ end
83
+
84
+ describe "with a single replace_contents override defined" do
85
+ before(:each) do
86
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace_contents => "p", :text => "<h1>Argh!</h1>")
87
+ @template = ActionView::Template.new("<p><span>Hello</span>I am not a <em>pirate</em></p>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
88
+ end
89
+
90
+ it "should return modified source" do
91
+ @template.source.should == "<p><h1>Argh!</h1></p>"
92
+ end
93
+ end
94
+
95
+ describe "with a single replace_contents override with closing_selector defined" do
96
+ before(:each) do
97
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace_contents => "h1", :closing_selector => "h2", :text => "<span>Argh!</span>")
98
+ @template = ActionView::Template.new("<h1>start</h1><p>some junk</p><div>more junk</div><h2>end</h2>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
99
+ end
100
+
101
+ it "should return modified source" do
102
+ @template.source.should == "<h1>start</h1><span>Argh!</span><h2>end</h2>"
103
+ end
104
+ end
105
+
64
106
  describe "with a single insert_after override defined" do
65
- before(:all) do
107
+ before(:each) do
66
108
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "img.button", :text => "<% help %>")
67
109
 
68
110
  @template = ActionView::Template.new("<div><img class=\"button\" src=\"path/to/button.png\"></div>",
@@ -77,7 +119,7 @@ module ActionView
77
119
  end
78
120
 
79
121
  describe "with a single insert_before override defined" do
80
- before(:all) do
122
+ before(:each) do
81
123
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "ul li:last", :text => "<%= help %>")
82
124
 
83
125
  @template = ActionView::Template.new("<ul><li>first</li><li>second</li><li>third</li></ul>",
@@ -92,7 +134,7 @@ module ActionView
92
134
  end
93
135
 
94
136
  describe "with a single insert_top override defined" do
95
- before(:all) do
137
+ before(:each) do
96
138
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_top => "ul", :text => "<li>me first</li>")
97
139
 
98
140
  @template = ActionView::Template.new("<ul><li>first</li><li>second</li><li>third</li></ul>",
@@ -106,8 +148,23 @@ module ActionView
106
148
  end
107
149
  end
108
150
 
151
+ describe "with a single insert_top override defined when targetted elemenet has no children" do
152
+ before(:each) do
153
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_top => "ul", :text => "<li>first</li><li>second</li><li>third</li>")
154
+
155
+ @template = ActionView::Template.new("<ul></ul>",
156
+ "/path/to/file.erb",
157
+ ActionView::Template::Handlers::ERB,
158
+ {:virtual_path=>"posts/index", :format=>:html})
159
+ end
160
+
161
+ it "should return modified source" do
162
+ @template.source.gsub("\n", "").should == "<ul><li>first</li><li>second</li><li>third</li></ul>"
163
+ end
164
+ end
165
+
109
166
  describe "with a single insert_bottom override defined" do
110
- before(:all) do
167
+ before(:each) do
111
168
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_bottom => "ul", :text => "<li>I'm always last</li>")
112
169
 
113
170
  @template = ActionView::Template.new("<ul><li>first</li><li>second</li><li>third</li></ul>",
@@ -121,8 +178,23 @@ module ActionView
121
178
  end
122
179
  end
123
180
 
181
+ describe "with a single insert_bottom override defined when targetted elemenet has no children" do
182
+ before(:each) do
183
+ Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_bottom => "ul", :text => "<li>I'm always last</li>")
184
+
185
+ @template = ActionView::Template.new("<ul></ul>",
186
+ "/path/to/file.erb",
187
+ ActionView::Template::Handlers::ERB,
188
+ {:virtual_path=>"posts/index", :format=>:html})
189
+ end
190
+
191
+ it "should return modified source" do
192
+ @template.source.gsub("\n", "").should == "<ul><li>I'm always last</li></ul>"
193
+ end
194
+ end
195
+
124
196
  describe "with a single set_attributes override defined" do
125
- before(:all) do
197
+ before(:each) do
126
198
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :set_attributes => 'img',
127
199
  :attributes => {:class => 'pretty', :alt => 'something interesting'})
128
200
 
@@ -138,7 +210,7 @@ module ActionView
138
210
  end
139
211
 
140
212
  describe "with a single disabled override defined" do
141
- before(:all) do
213
+ before(:each) do
142
214
  Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :remove => "p", :text => "<h1>Argh!</h1>", :disabled => true)
143
215
  @template = ActionView::Template.new("<p>test</p><%= raw(text) %>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html})
144
216
  end
@@ -148,9 +220,8 @@ module ActionView
148
220
  end
149
221
  end
150
222
 
151
-
152
223
  describe "with mulitple sequenced overrides defined" do
153
- before(:all) do
224
+ before(:each) do
154
225
  Deface::Override.new(:virtual_path => "posts/index", :name => "third", :insert_after => "li:contains('second')", :text => "<li>third</li>", :sequence => {:after => "second"})
155
226
  Deface::Override.new(:virtual_path => "posts/index", :name => "second", :insert_after => "li", :text => "<li>second</li>", :sequence => {:after => "first"})
156
227
  Deface::Override.new(:virtual_path => "posts/index", :name => "first", :replace => "li", :text => "<li>first</li>")
@@ -3,3 +3,27 @@ require 'rspec'
3
3
  require 'action_view'
4
4
  require 'action_controller'
5
5
  require 'deface'
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_framework = :rspec
9
+ end
10
+
11
+ shared_context "mock Rails" do
12
+ before(:each) do
13
+ unless defined? Rails
14
+ Rails = mock 'Rails'
15
+ end
16
+ Rails.stub :application => mock('application')
17
+ Rails.application.stub :config => mock('config')
18
+ Rails.application.config.stub :cache_classes => true
19
+ Rails.application.config.stub :deface => nil
20
+ end
21
+ end
22
+
23
+ shared_context "mock Rails.application" do
24
+ include_context "mock Rails"
25
+
26
+ before(:each) do
27
+ Rails.application.config.stub :deface => Deface::Environment.new
28
+ end
29
+ end
@@ -1,10 +1,13 @@
1
+ require 'deface'
2
+
1
3
  namespace :deface do
2
- desc 'Gets source of html element from template.'
3
- task :get_source, [:template_path, :selector] => [:environment] do |t, args|
4
- include Deface::TemplateHelper
4
+ include Deface::TemplateHelper
5
+
6
+ desc 'Applies selectors to given partial/template, and returns match(s) source.'
7
+ task :test_selector, [:virtual_path, :selector] => [:environment] do |t, args|
5
8
 
6
9
  begin
7
- source = load_template_source(args[:template_path], false)
10
+ source = load_template_source(args[:virtual_path], false)
8
11
  output = element_source(source, args[:selector])
9
12
  rescue
10
13
  puts "Failed to find tempalte/partial"
@@ -15,7 +18,7 @@ namespace :deface do
15
18
  if output.empty?
16
19
  puts "0 matches found"
17
20
  else
18
- puts "Querying '#{args[:template_path]}' for '#{args[:selector]}'"
21
+ puts "Querying '#{args[:virtual_path]}' for '#{args[:selector]}'"
19
22
  output.each_with_index do |content, i|
20
23
  puts "---------------- Match #{i+1} ----------------"
21
24
  puts content
@@ -23,4 +26,34 @@ namespace :deface do
23
26
  end
24
27
 
25
28
  end
29
+
30
+
31
+ desc 'Get the resulting markup for a partial/template'
32
+ task :get_result, [:virtual_path] => [:environment] do |t,args|
33
+ puts "---------------- Before ----------------"
34
+ before = load_template_source(args[:virtual_path], false, false).dup
35
+ puts before
36
+ puts ""
37
+
38
+ overrides = Deface::Override.find(:virtual_path => args[:virtual_path])
39
+ puts "---------------- Overrides (#{overrides.size})--------"
40
+ overrides.each do |override|
41
+ puts "- '#{override.name}' will#{ ' NOT' if override.args[:disabled]} be applied."
42
+ end
43
+ puts ""
44
+
45
+ puts "---------------- After ----------------"
46
+ after = load_template_source(args[:virtual_path], false, true).dup
47
+ puts after
48
+
49
+ begin
50
+ puts ""
51
+ puts "---------------- Diff -----------------"
52
+ puts Diffy::Diff.new(before, after).to_s(:color)
53
+ rescue
54
+ puts "Add 'diffy' to your Gemfile to see the diff."
55
+ end
56
+
57
+ end
58
+
26
59
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deface
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brian D Quinn
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-27 00:00:00 +01:00
19
- default_executable:
18
+ date: 2011-10-05 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: nokogiri
@@ -84,6 +83,7 @@ files:
84
83
  - init.rb
85
84
  - lib/deface.rb
86
85
  - lib/deface/action_view_extensions.rb
86
+ - lib/deface/environment.rb
87
87
  - lib/deface/override.rb
88
88
  - lib/deface/parser.rb
89
89
  - lib/deface/railtie.rb
@@ -91,13 +91,13 @@ files:
91
91
  - spec/assets/admin/posts/index.html.erb
92
92
  - spec/assets/shared/_post.html.erb
93
93
  - spec/assets/shared/person.html.erb
94
+ - spec/deface/environment_spec.rb
94
95
  - spec/deface/override_spec.rb
95
96
  - spec/deface/parser_spec.rb
96
97
  - spec/deface/template_helper_spec.rb
97
98
  - spec/deface/template_spec.rb
98
99
  - spec/spec_helper.rb
99
100
  - tasks/deface.rake
100
- has_rdoc: true
101
101
  homepage: http://github.com/railsdog/deface
102
102
  licenses: []
103
103
 
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  requirements: []
128
128
 
129
129
  rubyforge_project:
130
- rubygems_version: 1.6.2
130
+ rubygems_version: 1.8.10
131
131
  signing_key:
132
132
  specification_version: 3
133
133
  summary: Deface is a library that allows you to customize ERB views in Rails
@@ -135,6 +135,7 @@ test_files:
135
135
  - spec/assets/admin/posts/index.html.erb
136
136
  - spec/assets/shared/_post.html.erb
137
137
  - spec/assets/shared/person.html.erb
138
+ - spec/deface/environment_spec.rb
138
139
  - spec/deface/override_spec.rb
139
140
  - spec/deface/parser_spec.rb
140
141
  - spec/deface/template_helper_spec.rb