deface 0.8.0 → 0.9.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/lib/deface/search.rb CHANGED
@@ -17,6 +17,16 @@ module Deface
17
17
 
18
18
  result.flatten.compact.sort_by &:sequence
19
19
  end
20
+
21
+ # finds all overrides that are using a template / parital as there source
22
+ #
23
+ def find_using(virtual_path)
24
+ self.all.map do |key, overrides_by_name|
25
+ overrides_by_name.values.select do |override|
26
+ [:template, :partial].include?(override.source_argument) && override.args[override.source_argument] == virtual_path
27
+ end
28
+ end.flatten
29
+ end
20
30
  end
21
31
  end
22
32
  end
@@ -0,0 +1,2 @@
1
+ <!-- insert_bottom 'li' -->
2
+ Added to li!
@@ -0,0 +1,2 @@
1
+ <!-- insert_bottom 'li' -->
2
+ Added to li!
@@ -48,5 +48,21 @@ module ActionView
48
48
  end
49
49
  end
50
50
 
51
+ describe "method_name" do
52
+ let(:template) { ActionView::Template.new("<p>test</p>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html, :updated_at => (Time.now - 100)}) }
53
+
54
+ it "should return hash of overrides plus original method_name " do
55
+ deface_hash = Deface::Override.digest(:virtual_path => 'posts/index')
56
+
57
+ template.send(:method_name).should == "_#{Digest::MD5.new.update("#{deface_hash}_#{template.send(:method_name_without_deface)}").hexdigest}"
58
+ end
59
+
60
+ it "should alias original method_name method" do
61
+ template.send(:method_name_without_deface).should match /\A__some_path_to_file_erb_+[0-9]+_+[0-9]+\z/
62
+ end
63
+ end
64
+
51
65
  end
52
66
  end
67
+
68
+
@@ -4,6 +4,8 @@ class Dummy
4
4
  extend Deface::Applicator::ClassMethods
5
5
  extend Deface::Search::ClassMethods
6
6
 
7
+ attr_reader :parsed_document
8
+
7
9
  def self.all
8
10
  Rails.application.config.deface.overrides.all
9
11
  end
@@ -321,6 +323,17 @@ module Deface
321
323
  end
322
324
  end
323
325
 
326
+ describe "with a single surround override defined using :closing_selector" do
327
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :surround => "h1", :closing_selector => "p",
328
+ :text => "<% some_method('test') do %><%= render_original %><% end %>") }
329
+ let(:source) { "<span><h1>Start</h1><h2>middle</h2><p><span>This is the</span> end.</p></span>" }
330
+
331
+ it "should return modified source" do
332
+ Dummy.apply(source, {:virtual_path => "posts/index"}).gsub("\n", '').should == "<span><% some_method('test') do %><h1>Start</h1><h2>middle</h2><p><span>This is the</span> end.</p><% end %></span>"
333
+ end
334
+ end
335
+
336
+
324
337
  describe "with a single html surround_contents override defined" do
325
338
  before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :surround_contents => "div", :text => "<span><%= render_original %></span>") }
326
339
  let(:source) { "<h4>yay!</h4><div><p>test</p></div>" }
@@ -339,6 +352,17 @@ module Deface
339
352
  end
340
353
  end
341
354
 
355
+ describe "with a single erb surround_contents override defined using :closing_selector" do
356
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :surround_contents => "h1", :closing_selector => "p",
357
+ :text => "<% if 1==1 %><%= render_original %><% end %>") }
358
+ let(:source) { "<div><h1>Start</h1><h2>middle</h2><h3>child</h3><p><span>This is the</span> end.</p></div>" }
359
+
360
+ it "should return modified source" do
361
+ Dummy.apply(source, {:virtual_path => "posts/index"}).gsub("\n", '').should == "<div><h1>Start</h1><% if 1==1 %><h2>middle</h2><h3>child</h3><% end %><p><span>This is the</span> end.</p></div>"
362
+ end
363
+ end
364
+
365
+
342
366
  describe "with a single disabled override defined" do
343
367
  before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :remove => "p", :text => "<h1>Argh!</h1>", :disabled => true) }
344
368
  let(:source) { "<p>test</p><%= raw(text) %>" }
@@ -349,6 +373,48 @@ module Deface
349
373
  end
350
374
  end
351
375
 
376
+ describe "with a single :copy override defined" do
377
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "p", :copy => "h1") }
378
+ let(:source) { "<h1>World</h1><p>Hello</p>" }
379
+
380
+
381
+ it "should return modified source" do
382
+ Dummy.apply(source, {:virtual_path => "posts/index"}).should == "<h1>World</h1><p>Hello</p><h1>World</h1>"
383
+ end
384
+ end
385
+
386
+ describe "with a single :copy using :start and :end" do
387
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_before => "h1",
388
+ :copy => {:start => "code:contains('if true')", :end => "code:contains('end')"}) }
389
+ let(:source) { "<h1>World</h1><% if true %><p>True that!</p><% end %><p>Hello</p>" }
390
+
391
+
392
+ it "should return modified source" do
393
+ Dummy.apply(source, {:virtual_path => "posts/index"}).should == "<% if true %><p>True that!</p><% end %><h1>World</h1><% if true %><p>True that!</p><% end %><p>Hello</p>"
394
+ end
395
+ end
396
+
397
+ describe "with a single :cut override defined" do
398
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :insert_after => "p", :cut => "h1") }
399
+ let(:source) { "<h1>World</h1><p>Hello</p>" }
400
+
401
+
402
+ it "should return modified source" do
403
+ Dummy.apply(source, {:virtual_path => "posts/index"}).should == "<p>Hello</p><h1>World</h1>"
404
+ end
405
+ end
406
+
407
+ describe "with a single :cut using :start and :end" do
408
+ before { Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :replace => "h1",
409
+ :cut => {:start => "code:contains('if true')", :end => "code:contains('end')"}) }
410
+ let(:source) { "<h1>World</h1><% if true %><p>True that!</p><% end %><p>Hello</p>" }
411
+
412
+
413
+ it "should return modified source" do
414
+ Dummy.apply(source, {:virtual_path => "posts/index"}).should == "<% if true %><p>True that!</p><% end %><p>Hello</p>"
415
+ end
416
+ end
417
+
352
418
  describe "with mulitple sequenced overrides defined" do
353
419
  before do
354
420
  Deface::Override.new(:virtual_path => "posts/index", :name => "third", :insert_after => "li:contains('second')", :text => "<li>third</li>", :sequence => {:after => "second"})
@@ -363,5 +429,18 @@ module Deface
363
429
  end
364
430
  end
365
431
 
432
+ describe "with incompatible actions and :closing_selector" do
433
+ let(:source) { "<ul><li>first</li><li>second</li><li>third</li></ul>" }
434
+
435
+ it "should return modified source" do
436
+ [:insert_before, :insert_after, :insert_top, :insert_bottom, :set_attributes, :remove_from_attributes, :add_to_attributes].each do |action|
437
+ Deface::Override.all.clear
438
+ Deface::Override.new(:virtual_path => "posts/index", :name => "first", action => "li", :closing_selector => "p", :text => "<li>first</li>")
439
+
440
+ expect { Dummy.apply(source, {:virtual_path => "posts/index"}) }.to raise_error(Deface::NotSupportedError)
441
+ end
442
+ end
443
+ end
444
+
366
445
  end
367
446
  end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+
3
+ require 'deface/dsl/context'
4
+
5
+ describe Deface::DSL::Context do
6
+ include_context "mock Rails"
7
+
8
+ context '#create_override' do
9
+ subject { context = Deface::DSL::Context.new('sample_name') }
10
+
11
+ def override_should_be_created_with(expected_hash)
12
+ Deface::Override.should_receive(:new).with(hash_including(
13
+ :name => 'sample_name'
14
+ ))
15
+
16
+ subject.create_override
17
+ end
18
+
19
+ it 'should use name passed in through initializer' do
20
+ override_should_be_created_with(:name => 'sample_name')
21
+ end
22
+
23
+ it 'should use value set with #virtual_path' do
24
+ subject.virtual_path('test/path')
25
+
26
+ override_should_be_created_with(:virtual_path => 'test/path')
27
+ end
28
+
29
+ context 'actions' do
30
+ Deface::Override.actions.each do |action|
31
+ it "should use value set with ##{action}" do
32
+ subject.send(action, "#{action}/selector")
33
+
34
+ override_should_be_created_with(action => "#{action}/selector")
35
+ end
36
+ end
37
+
38
+ it 'should generate a warning if two action values are specified' do
39
+ subject.insert_top('selector')
40
+
41
+ logger = mock('logger')
42
+ Rails.should_receive(:logger).and_return(logger)
43
+ logger.should_receive(:error).with("\e[1;32mDeface: [WARNING]\e[0m Multiple action methods have been called. The last one will be used.")
44
+
45
+ subject.insert_bottom('selector')
46
+ end
47
+
48
+ it 'should use the last action that is specified' do
49
+ Rails.stub_chain(:logger, :error)
50
+
51
+ subject.insert_top('insert_top/selector')
52
+ subject.insert_bottom('insert_bottom/selector')
53
+
54
+ override_should_be_created_with(:insert_bottom => 'insert_bottom/selector')
55
+ end
56
+ end
57
+
58
+ context 'sources' do
59
+ Deface::Override.sources.each do |source|
60
+ it "should use value set with ##{source}" do
61
+ subject.send(source, "#{source} value")
62
+
63
+ override_should_be_created_with(source => "#{source} value")
64
+ end
65
+ end
66
+
67
+ it 'should generate a warning if two sources are specified' do
68
+ subject.partial('partial name')
69
+
70
+ logger = mock('logger')
71
+ Rails.should_receive(:logger).and_return(logger)
72
+ logger.should_receive(:error).with("\e[1;32mDeface: [WARNING]\e[0m Multiple source methods have been called. The last one will be used.")
73
+
74
+ subject.template('template/path')
75
+ end
76
+
77
+ it 'should use the last source that is specified' do
78
+ Rails.stub_chain(:logger, :error)
79
+
80
+ subject.partial('partial name')
81
+ subject.template('template/path')
82
+
83
+ override_should_be_created_with(:template => 'template/path')
84
+ end
85
+ end
86
+
87
+ # * <tt>:original</tt> - String containing original markup that is being overridden.
88
+ # If supplied Deface will log when the original markup changes, which helps highlight overrides that need
89
+ # attention when upgrading versions of the source application. Only really warranted for :replace overrides.
90
+ # NB: All whitespace is stripped before comparsion.
91
+ it 'should use value set with #original' do
92
+ subject.original('<div>original markup</div>')
93
+
94
+ override_should_be_created_with(:original => '<div>original markup</div>')
95
+ end
96
+
97
+ # * <tt>:closing_selector</tt> - A second css selector targeting an end element, allowing you to select a range
98
+ # of elements to apply an action against. The :closing_selector only supports the :replace, :remove and
99
+ # :replace_contents actions, and the end element must be a sibling of the first/starting element. Note the CSS
100
+ # general sibling selector (~) is used to match the first element after the opening selector.
101
+ it 'should use value set wih #closing_selector' do
102
+ subject.closing_selector('closing/selector')
103
+
104
+ override_should_be_created_with(:closing_selector => 'closing/selector')
105
+ end
106
+
107
+ # * <tt>:sequence</tt> - Used to order the application of an override for a specific virtual path, helpful when
108
+ # an override depends on another override being applied first.
109
+ # Supports:
110
+ # :sequence => n - where n is a positive or negative integer (lower numbers get applied first, default 100).
111
+ # :sequence => {:before => "override_name"} - where "override_name" is the name of an override defined for the
112
+ # same virutal_path, the current override will be appplied before
113
+ # the named override passed.
114
+ # :sequence => {:after => "override_name") - the current override will be applied after the named override passed.
115
+ it 'should use hash value set with #sequence' do
116
+ subject.sequence(:before => 'something')
117
+
118
+ override_should_be_created_with(:sequence => {:before => 'something'})
119
+ end
120
+
121
+ it 'should use integer value set with #sequence' do
122
+ subject.sequence(12)
123
+
124
+ override_should_be_created_with(:sequence => 12)
125
+ end
126
+
127
+ ## todo: combine #set_attributes and attributes for clarity
128
+
129
+ # * <tt>:attributes</tt> - A hash containing all the attributes to be set on the matched elements, eg: :attributes => {:class => "green", :title => "some string"}
130
+ it 'should use value set with attributes' do
131
+ subject.attributes(:class => "green", :title => "some string")
132
+
133
+ override_should_be_created_with(:attributes => {:class => "green", :title => "some string"})
134
+ end
135
+
136
+ # * <tt>:disabled</tt> - When set to true the override will not be applied.
137
+ it 'should pass { :disabled => true } when #disabled is called' do
138
+ subject.disabled
139
+
140
+ override_should_be_created_with(:disabled => true)
141
+ end
142
+
143
+ it 'should pass { :disabled => false} #enabled is called' do
144
+ subject.enabled
145
+
146
+ override_should_be_created_with(:disabled => false)
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ require 'deface/dsl/loader'
4
+
5
+ describe Deface::DSL::Loader do
6
+ context '.load' do
7
+ context 'extension check' do
8
+ it 'should succeed if file ends with .deface' do
9
+ file = mock('deface file')
10
+ filename = 'app/overrides/example_name.deface'
11
+
12
+ lambda { Deface::DSL::Loader.load(filename) }.should_not raise_error(
13
+ "Deface::DSL does not know how to read 'app/overrides/example_name.deface'. Override files should end with just .deface, .html.erb.deface, or .html.haml.deface")
14
+ end
15
+
16
+ it 'should succeed if file ends with .html.erb.deface' do
17
+ file = mock('deface file')
18
+ filename = 'app/overrides/example_name.html.erb.deface'
19
+
20
+ lambda { Deface::DSL::Loader.load(filename) }.should_not raise_error(
21
+ "Deface::DSL does not know how to read 'app/overrides/example_name.html.erb.deface'. Override files should end with just .deface, .html.erb.deface, or .html.haml.deface")
22
+ end
23
+
24
+ it 'should succeed if file ends with .html.haml.deface' do
25
+ file = mock('deface file')
26
+ filename = 'app/overrides/example_name.html.haml.deface'
27
+
28
+ lambda { Deface::DSL::Loader.load(filename) }.should_not raise_error(
29
+ "Deface::DSL does not know how to read 'app/overrides/example_name.html.haml.deface'. Override files should end with just .deface, .html.erb.deface, or .html.haml.deface")
30
+ end
31
+
32
+ it 'should fail if file ends with .blargh.deface' do
33
+ file = mock('deface file')
34
+ filename = 'app/overrides/example_name.blargh.deface'
35
+
36
+ lambda { Deface::DSL::Loader.load(filename) }.should raise_error(
37
+ "Deface::DSL does not know how to read 'app/overrides/example_name.blargh.deface'. Override files should end with just .deface, .html.erb.deface, or .html.haml.deface")
38
+ end
39
+
40
+ it "should suceed if parent directory has a dot(.) in it's name" do
41
+ file = mock('deface file')
42
+ filename = 'app/overrides/parent.dir.with.dot/example_name.html.haml.deface'
43
+
44
+ lambda { Deface::DSL::Loader.load(filename) }.should_not raise_error(
45
+ "Deface::DSL does not know how to read 'app/overrides/parent.dir.with.dot/example_name.html.haml.deface'. Override files should end with just .deface, .html.erb.deface, or .html.haml.deface")
46
+ end
47
+ end
48
+
49
+ it 'should fail if .html.erb.deface file is in the root of app/overrides' do
50
+ file = mock('html/erb/deface file')
51
+ filename = 'app/overrides/example_name.html.erb.deface'
52
+
53
+ lambda { Deface::DSL::Loader.load(filename) }.should raise_error(
54
+ "Deface::DSL overrides must be in a sub-directory that matches the views virtual path. Move 'app/overrides/example_name.html.erb.deface' into a sub-directory.")
55
+ end
56
+
57
+ it 'should set the virtual_path for a .deface file in a directory below overrides' do
58
+ file = mock('deface file')
59
+ filename = 'app/overrides/path/to/view/example_name.deface'
60
+ File.should_receive(:open).with(filename).and_yield(file)
61
+
62
+ override_name = 'example_name'
63
+ context = mock('dsl context')
64
+ Deface::DSL::Context.should_receive(:new).with(override_name).
65
+ and_return(context)
66
+
67
+ file_contents = mock('file contents')
68
+ file.should_receive(:read).and_return(file_contents)
69
+
70
+ context.should_receive(:virtual_path).with('path/to/view').ordered
71
+ context.should_receive(:instance_eval).with(file_contents).ordered
72
+ context.should_receive(:create_override).ordered
73
+
74
+ Deface::DSL::Loader.load(filename)
75
+ end
76
+
77
+ it 'should set the virtual_path for a .html.erb.deface file in a directory below overrides' do
78
+ file = mock('html/erb/deface file')
79
+ filename = 'app/overrides/path/to/view/example_name.html.erb.deface'
80
+ File.should_receive(:open).with(filename).and_yield(file)
81
+
82
+ override_name = 'example_name'
83
+ context = mock('dsl context')
84
+ Deface::DSL::Context.should_receive(:new).with(override_name).
85
+ and_return(context)
86
+
87
+ file_contents = mock('file contents')
88
+ file.should_receive(:read).and_return(file_contents)
89
+
90
+ Deface::DSL::Loader.should_receive(:extract_dsl_commands_from_erb).
91
+ with(file_contents).
92
+ and_return(['dsl commands', 'erb'])
93
+
94
+ context.should_receive(:virtual_path).with('path/to/view').ordered
95
+ context.should_receive(:instance_eval).with('dsl commands').ordered
96
+ context.should_receive(:erb).with('erb').ordered
97
+ context.should_receive(:create_override).ordered
98
+
99
+ Deface::DSL::Loader.load(filename)
100
+ end
101
+
102
+ it 'should set the virtual_path for a .html.haml.deface file in a directory below overrides' do
103
+ file = mock('html/haml/deface file')
104
+ filename = 'app/overrides/path/to/view/example_name.html.haml.deface'
105
+ File.should_receive(:open).with(filename).and_yield(file)
106
+
107
+ override_name = 'example_name'
108
+ context = mock('dsl context')
109
+ Deface::DSL::Context.should_receive(:new).with(override_name).
110
+ and_return(context)
111
+
112
+ file_contents = mock('file contents')
113
+ file.should_receive(:read).and_return(file_contents)
114
+
115
+ Deface::DSL::Loader.should_receive(:extract_dsl_commands_from_haml).
116
+ with(file_contents).
117
+ and_return(['dsl commands', 'haml'])
118
+
119
+ context.should_receive(:virtual_path).with('path/to/view').ordered
120
+ context.should_receive(:instance_eval).with('dsl commands').ordered
121
+ context.should_receive(:haml).with('haml').ordered
122
+ context.should_receive(:create_override).ordered
123
+
124
+ Deface::DSL::Loader.load(filename)
125
+ end
126
+
127
+ end
128
+
129
+ context '.register' do
130
+ it 'should register the deface extension with the polyglot library' do
131
+ Polyglot.should_receive(:register).with('deface', Deface::DSL::Loader)
132
+
133
+ Deface::DSL::Loader.register
134
+ end
135
+ end
136
+
137
+ context '.extract_dsl_commands_from_erb' do
138
+ it 'should work in the simplest case' do
139
+ example = "<!-- test 'command' --><h1>Wow!</h1>"
140
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
141
+ dsl_commands.should == "test 'command'\n"
142
+ the_rest.should == "<h1>Wow!</h1>"
143
+ end
144
+
145
+ it 'should combine multiple comments' do
146
+ example = "<!-- test 'command' --><!-- another 'command' --><h1>Wow!</h1>"
147
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
148
+ dsl_commands.should == "test 'command'\nanother 'command'\n"
149
+ the_rest.should == "<h1>Wow!</h1>"
150
+ end
151
+
152
+ it 'should leave internal comments alone' do
153
+ example = "<br/><!-- test 'command' --><!-- another 'command' --><h1>Wow!</h1>"
154
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
155
+ dsl_commands.should == ""
156
+ the_rest.should == example
157
+ end
158
+
159
+ it 'should work with comments on own lines' do
160
+ example = "<!-- test 'command' -->\n<!-- another 'command' -->\n<h1>Wow!</h1>"
161
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
162
+ dsl_commands.should == "test 'command'\nanother 'command'\n"
163
+ the_rest.should == "\n<h1>Wow!</h1>"
164
+ end
165
+
166
+ it 'should work with newlines inside the comment' do
167
+ example = "<!--\n test 'command'\nanother 'command'\n -->\n<h1>Wow!</h1>"
168
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
169
+ dsl_commands.should == "test 'command'\nanother 'command'\n"
170
+ the_rest.should == "\n<h1>Wow!</h1>"
171
+ end
172
+ end
173
+
174
+ context '.extract_dsl_commands_from_haml' do
175
+ it 'should work in the simplest case' do
176
+ example = "/ test 'command'\n/ another 'command'\n%h1 Wow!"
177
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_haml(example)
178
+ dsl_commands.should == "test 'command'\nanother 'command'\n"
179
+ the_rest.should == "%h1 Wow!"
180
+ end
181
+
182
+ it 'should work with a block style comment using spaces' do
183
+ example = "/\n test 'command'\n another 'command'\n%h1 Wow!"
184
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_haml(example)
185
+ dsl_commands.should == "\ntest 'command'\nanother 'command'\n"
186
+ the_rest.should == "%h1 Wow!"
187
+ end
188
+
189
+ it 'should leave internal comments alone' do
190
+ example = "%br\n/ test 'command'\n/ another 'command'\n%h1 Wow!"
191
+ dsl_commands, the_rest = Deface::DSL::Loader.extract_dsl_commands_from_erb(example)
192
+ dsl_commands.should == ""
193
+ the_rest.should == example
194
+ end
195
+
196
+ end
197
+ end