deface 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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