deface 1.4.0 → 1.6.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.
@@ -48,8 +48,8 @@ module Deface
48
48
  end
49
49
  end
50
50
 
51
- #prevents any caching by rails in development mode
52
- details[:updated_at] = Time.now
51
+ # Prevents any caching by rails in development mode.
52
+ details[:updated_at] = Time.now if Deface.before_rails_6?
53
53
 
54
54
  source = doc.to_s
55
55
 
@@ -57,13 +57,7 @@ module Deface
57
57
  Deface::DSL::Loader.register
58
58
 
59
59
  # check all railties / engines / extensions / application for overrides
60
- railties = if Rails.version >= "4.0"
61
- app.railties._all
62
- else
63
- app.railties.all
64
- end
65
-
66
- railties.dup.push(app).each do |railtie|
60
+ app.railties._all.dup.push(app).each do |railtie|
67
61
  next unless railtie.respond_to? :root
68
62
  load_overrides(railtie)
69
63
  end
@@ -89,11 +83,9 @@ module Deface
89
83
  paths ||= ["app/overrides"]
90
84
 
91
85
  paths.each do |path|
92
- if Rails.version[0..2] >= "3.2"
93
- # add path to watchable_dir so Rails will call to_prepare on file changes
94
- # allowing overrides to be updated / reloaded in development mode.
95
- Rails.application.config.watchable_dirs[root.join(path).to_s] = [:rb, :deface]
96
- end
86
+ # add path to watchable_dir so Rails will call to_prepare on file changes
87
+ # allowing overrides to be updated / reloaded in development mode.
88
+ Rails.application.config.watchable_dirs[root.join(path).to_s] = [:rb, :deface]
97
89
 
98
90
  Dir.glob(root.join path, "**/*.rb") do |c|
99
91
  Rails.application.config.cache_classes ? require(c) : load(c)
@@ -0,0 +1,5 @@
1
+ module Deface
2
+ class DefaceError < StandardError; end
3
+
4
+ class NotSupportedError < DefaceError; end
5
+ end
@@ -37,6 +37,7 @@ module Deface
37
37
  # coverts { attributes into deface compatibily attributes
38
38
  def deface_attributes(attrs)
39
39
  return if attrs.nil?
40
+ return attrs if attrs.scan(/\{/).count > 1
40
41
 
41
42
  attrs.gsub! /\{|\}/, ''
42
43
 
@@ -211,21 +211,22 @@ module Deface
211
211
 
212
212
  private
213
213
 
214
- # check if method is compiled for the current virtual path
215
- #
216
- def expire_compiled_template
217
- if compiled_method_name = ActionView::Base.instance_methods.detect { |name| name =~ /#{args[:virtual_path].gsub(/[^a-z_]/, '_')}/ }
218
- #if the compiled method does not contain the current deface digest
219
- #then remove the old method - this will allow the template to be
220
- #recompiled the next time it is rendered (showing the latest changes)
221
-
222
- unless compiled_method_name =~ /\A_#{self.class.digest(:virtual_path => @args[:virtual_path])}_/
223
- ActionView::Base.send :remove_method, compiled_method_name
224
- end
225
- end
226
-
214
+ # Check if method is compiled for the current virtual path.
215
+ #
216
+ # If the compiled method does not contain the current deface digest
217
+ # then remove the old method - this will allow the template to be
218
+ # recompiled the next time it is rendered (showing the latest changes).
219
+ def expire_compiled_template
220
+ virtual_path = args[:virtual_path]
221
+
222
+ method_name = Deface.template_class.instance_methods.detect do |name|
223
+ name =~ /#{virtual_path.gsub(/[^a-z_]/, '_')}/
227
224
  end
228
225
 
226
+ if method_name && method_name !~ /\A_#{self.class.digest(virtual_path: virtual_path)}_/
227
+ Deface.template_class.send :remove_method, method_name
228
+ end
229
+ end
229
230
  end
230
231
 
231
232
  end
@@ -36,19 +36,15 @@ module Deface
36
36
  initializer "deface.tweak_eager_loading", :before => :set_load_path do |app|
37
37
 
38
38
  # application
39
- app.config.eager_load_paths = app.config.eager_load_paths.reject { |path| path.to_s =~ /app\/overrides\z/ }
39
+ tweak_eager_loading(app)
40
40
 
41
41
  # railites / engines / extensions
42
- railties = if Rails.version >= "4.0"
43
- app.railties._all
44
- else
45
- app.railties.all
46
- end
47
-
48
- railties.each do |railtie|
42
+ app.railties._all.each do |railtie|
49
43
  next unless railtie.respond_to?(:root) && railtie.config.respond_to?(:eager_load_paths)
50
- railtie.config.eager_load_paths = railtie.config.eager_load_paths.reject { |path| path.to_s =~ /app\/overrides\z/ }
44
+
45
+ tweak_eager_loading(railtie)
51
46
  end
47
+
52
48
  end
53
49
 
54
50
  # sets up deface environment and requires / loads all
@@ -87,5 +83,15 @@ module Deface
87
83
  end
88
84
  end
89
85
 
86
+ private
87
+
88
+ def tweak_eager_loading(railtie)
89
+ paths_to_reject = railtie.config.eager_load_paths.select { |path| path.to_s =~ /app\/overrides\z/ }
90
+ railtie.config.eager_load_paths = railtie.config.eager_load_paths.reject { |path| path.in?(paths_to_reject) }
91
+
92
+ if Rails.configuration.respond_to?(:autoloader) && Rails.configuration.autoloader == :zeitwerk
93
+ Rails.autoloaders.each { |autoloader| autoloader.ignore(*paths_to_reject) }
94
+ end
95
+ end
90
96
  end
91
97
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deface
4
+ VERSION = "1.6.0"
5
+ end
@@ -1,95 +1,146 @@
1
1
  require 'spec_helper'
2
2
 
3
- module ActionView
4
- describe Template do
5
- include_context "mock Rails.application"
6
-
7
- describe "with no overrides defined" do
8
- before(:each) do
9
- @updated_at = Time.now - 600
10
- @template = ActionView::Template.new("<p>test</p>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html, :updated_at => @updated_at})
11
- #stub for Rails < 3.1
12
- unless defined?(@template.updated_at)
13
- allow(@template).to receive(:updated_at).and_return(@updated_at)
14
- end
15
- end
3
+ describe Deface::ActionViewExtensions do
4
+ include_context "mock Rails.application"
16
5
 
17
- it "should initialize new template object" do
18
- expect(@template.is_a?(ActionView::Template)).to eq(true)
19
- end
6
+ before supports_updated_at: true do
7
+ skip "Current Rails doesn't support the updated_at attribute on ActionView" unless supports_updated_at?
8
+ end
20
9
 
21
- it "should return unmodified source" do
22
- expect(@template.source).to eq("<p>test</p>")
23
- end
10
+ let(:template) { ActionView::Template.new(
11
+ source,
12
+ path,
13
+ handler,
14
+ **options,
15
+ **(supports_updated_at? ? {updated_at: updated_at} : {})
16
+ ) }
17
+
18
+ let(:source) { "<p>test</p>" }
19
+ let(:path) { "/some/path/to/file.erb" }
20
+ let(:handler) { ActionView::Template::Handlers::ERB }
21
+ let(:options) {{
22
+ virtual_path: virtual_path,
23
+ format: format,
24
+ locals: {}
25
+ }}
26
+ let(:format) { :html }
27
+ let(:virtual_path) { "posts/index" }
28
+
29
+ let(:supports_updated_at?) { Deface.before_rails_6? }
30
+ let(:updated_at) { Time.now - 600 }
31
+
32
+ describe "with no overrides defined" do
33
+ it "should initialize new template object" do
34
+ expect(template.is_a?(ActionView::Template)).to eq(true)
35
+ end
24
36
 
25
- it "should not change updated_at" do
26
- expect(@template.updated_at).to eq(@updated_at)
27
- end
37
+ it "should return unmodified source" do
38
+ expect(template.source).to eq("<p>test</p>")
39
+ end
28
40
 
41
+ it "should not change updated_at", :supports_updated_at do
42
+ expect(template.updated_at).to eq(updated_at)
29
43
  end
44
+ end
30
45
 
31
- describe "with a single remove override defined" do
32
- before(:each) do
33
- @updated_at = Time.now - 300
34
- Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :remove => "p", :text => "<h1>Argh!</h1>")
35
- @template = ActionView::Template.new("<p>test</p><%= raw(text) %>", "/some/path/to/file.erb", ActionView::Template::Handlers::ERB, {:virtual_path=>"posts/index", :format=>:html, :updated_at => @updated_at})
36
- #stub for Rails < 3.1
37
- unless defined?(@template.updated_at)
38
- allow(@template).to receive(:updated_at).and_return(@updated_at + 500)
39
- end
40
- end
46
+ describe "with a single remove override defined" do
47
+ let(:updated_at) { Time.now - 300 }
48
+ let(:source) { "<p>test</p><%= raw(text) %>" }
41
49
 
42
- it "should return modified source" do
43
- expect(@template.source).to eq("<%= raw(text) %>")
44
- end
50
+ before do
51
+ Deface::Override.new(virtual_path: "posts/index", name: "Posts#index", remove: "p", text: "<h1>Argh!</h1>")
52
+ end
45
53
 
46
- it "should change updated_at" do
47
- expect(@template.updated_at).to be > @updated_at
48
- end
54
+ it "should return modified source" do
55
+ expect(template.source).to eq("<%= raw(text) %>")
56
+ end
57
+
58
+ it "should change updated_at", :supports_updated_at do
59
+ expect(template.updated_at).to be > updated_at
49
60
  end
61
+ end
50
62
 
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)}) }
63
+ describe "#method_name" do
64
+ before do
65
+ ActionView::Template.define_method(
66
+ :method_name_without_deface,
67
+ ActionView::Template.instance_method(:method_name)
68
+ )
69
+ end
53
70
 
54
- it "should return hash of overrides plus original method_name " do
55
- deface_hash = Deface::Override.digest(:virtual_path => 'posts/index')
71
+ it "returns hash of overrides plus original method_name " do
72
+ deface_hash = Deface::Override.digest(virtual_path: 'posts/index')
73
+ super_method = template.method(:method_name).super_method
74
+ method_name = "_#{Digest::MD5.new.update("#{deface_hash}_#{super_method.call}").hexdigest}"
56
75
 
57
- expect(template.send(:method_name)).to eq("_#{Digest::MD5.new.update("#{deface_hash}_#{template.send(:method_name_without_deface)}").hexdigest}")
58
- end
76
+ expect(template.send(:method_name)).to eq(method_name)
77
+ end
78
+ end
59
79
 
60
- it "should alias original method_name method" do
61
- expect(template.send(:method_name_without_deface)).to match /\A__some_path_to_file_erb_+[0-9]+_+[0-9]+\z/
62
- end
80
+ describe "non erb or haml template" do
81
+ let(:source) { "xml.post => :blah" }
82
+ let(:path) { "/some/path/to/file.erb" }
83
+ let(:handler) { ActionView::Template::Handlers::Builder }
84
+ let(:updated_at) { Time.now - 100 }
85
+ let(:format) { :xml }
86
+
87
+ before(:each) do
88
+ Deface::Override.new(virtual_path: "posts/index", name: "Posts#index", remove: "p")
63
89
  end
64
90
 
65
- describe "non erb or haml template" do
66
- before(:each) do
67
- Deface::Override.new(:virtual_path => "posts/index", :name => "Posts#index", :remove => "p")
68
- @template = ActionView::Template.new("xml.post => :blah", "/some/path/to/file.erb", ActionView::Template::Handlers::Builder, {:virtual_path=>"posts/index", :format=>:xml, :updated_at => (Time.now - 100)})
69
- end
91
+ it "should return unmodified source" do
92
+ expect(template.source).to eq("xml.post => :blah")
93
+ expect(template.source).not_to include("=&gt;")
94
+ end
95
+ end
70
96
 
71
- it "should return unmodified source" do
72
- #if processed, source would include "=&gt;"
73
- expect(@template.source).to eq("xml.post => :blah")
97
+ describe ".determine_syntax(handler)" do
98
+ let(:source) { "xml.post => :blah" }
99
+ let(:format) { :xml }
100
+
101
+ # Not so BDD, but it keeps us from making mistakes in the future for instance,
102
+ # we test ActionView::Template here with a handler == ....::Handlers::ERB,
103
+ # while in rails it seems it's an instance of ...::Handlers::ERB.
104
+ it "recognizes supported syntaxes" do
105
+ expectations = { Haml::Plugin => :haml,
106
+ ActionView::Template::Handlers::ERB => :erb,
107
+ ActionView::Template::Handlers::ERB.new => :erb,
108
+ ActionView::Template::Handlers::Builder => nil }
109
+ expectations.each do |handler, expected|
110
+ expect(template.is_a?(ActionView::Template)).to eq(true)
111
+ expect(described_class.determine_syntax(handler)).to eq(expected), "unexpected result for handler #{handler}"
74
112
  end
75
113
  end
114
+ end
76
115
 
77
- describe "#should_be_defaced?(handler) method" do
78
- #not so BDD, but it keeps us from making mistakes in the future
79
- #for instance, we test ActionView::Template here with a handler == ....::Handlers::ERB,
80
- #while in rails it seems it's an instance of ...::Handlers::ERB
81
- it "should be truthy only for haml/erb handlers and their instances" do
82
- expectations = { Haml::Plugin => true,
83
- ActionView::Template::Handlers::ERB => true,
84
- ActionView::Template::Handlers::ERB.new => true,
85
- ActionView::Template::Handlers::Builder => false }
86
- expectations.each do |handler, expected|
87
- @template = ActionView::Template.new("xml.post => :blah", "/some/path/to/file.erb", handler, {:virtual_path=>"posts/index", :format=>:xml, :updated_at => (Time.now - 100)})
88
- expect(@template.is_a?(ActionView::Template)).to eq(true)
89
- syntax = @template.send(:determine_syntax, handler)
90
- expect(@template.send(:should_be_defaced?, syntax)).to eq(expected), "unexpected result for handler "+handler.to_s
91
- end
116
+ describe '#render' do
117
+ let(:source) { "<p>test</p><%= raw(text) %>".inspect }
118
+ let(:local_assigns) { {text: "some <br> text"} }
119
+ let(:lookup_context) { ActionView::LookupContext.new(["#{__dir__}/views"]) }
120
+ let(:view) do
121
+ if Rails::VERSION::STRING >= '6.1'
122
+ ActionView::Base.with_empty_template_cache.new(lookup_context, {}, nil)
123
+ else
124
+ ActionView::Base.new(lookup_context)
92
125
  end
93
126
  end
127
+ let(:options) { {
128
+ virtual_path: virtual_path,
129
+ format: format,
130
+ locals: local_assigns.keys
131
+ } }
132
+
133
+ let!(:deface) {
134
+ Deface::Override.new(
135
+ virtual_path: virtual_path,
136
+ name: "Posts#index",
137
+ replace: "p",
138
+ text: "<h1>Argh!</h1>"
139
+ )
140
+ }
141
+
142
+ it 'renders the template modified by deface' do
143
+ expect(template.render(view, local_assigns)).to eq(%{"<h1>Argh!</h1>some <br> text"})
144
+ end
94
145
  end
95
146
  end
@@ -19,8 +19,6 @@ module Deface
19
19
  Deface::Override.new(:virtual_path => "posts/new", :name => "Posts#new", :replace => "h1", :text => "<h1>argh!</h1>")
20
20
  end
21
21
 
22
- let(:railties_collection_accessor) { Rails.version >= "4.0" ? :_all : :all }
23
-
24
22
  describe ".overrides" do
25
23
 
26
24
  it "should return all overrides" do
@@ -37,7 +35,7 @@ module Deface
37
35
  before do
38
36
  allow(Rails.application).to receive_messages :root => Pathname.new(File.join(File.dirname(__FILE__), '..', "assets"))
39
37
  allow(Rails.application).to receive_messages :paths => {}
40
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => []
38
+ allow(Rails.application).to receive_message_chain :railties, :_all => []
41
39
 
42
40
  expect(Deface::DSL::Loader).to receive(:register)
43
41
  end
@@ -54,7 +52,7 @@ module Deface
54
52
  end
55
53
 
56
54
  it "should enumerate_and_load nil when railtie has no app/overrides path set" do
57
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => [double('railtie', :root => "/some/path")]
55
+ allow(Rails.application).to receive_message_chain :railties, :_all => [double('railtie', :root => "/some/path")]
58
56
 
59
57
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(nil, Rails.application.root)
60
58
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(nil, "/some/path")
@@ -62,7 +60,7 @@ module Deface
62
60
  end
63
61
 
64
62
  it "should enumerate_and_load path when railtie has app/overrides path set" do
65
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => [ double('railtie', :root => "/some/path", :paths => {"app/overrides" => ["app/some_path"] } )]
63
+ allow(Rails.application).to receive_message_chain :railties, :_all => [ double('railtie', :root => "/some/path", :paths => {"app/overrides" => ["app/some_path"] } )]
66
64
 
67
65
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(nil, Rails.application.root)
68
66
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(["app/some_path"] , "/some/path")
@@ -70,7 +68,7 @@ module Deface
70
68
  end
71
69
 
72
70
  it "should enumerate_and_load railties first, followed by the application iteslf" do
73
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => [ double('railtie', :root => "/some/path", :paths => {"app/overrides" => ["app/some_path"] } )]
71
+ allow(Rails.application).to receive_message_chain :railties, :_all => [ double('railtie', :root => "/some/path", :paths => {"app/overrides" => ["app/some_path"] } )]
74
72
 
75
73
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(["app/some_path"] , "/some/path").ordered
76
74
  expect(Rails.application.config.deface.overrides).to receive(:enumerate_and_load).with(nil, Rails.application.root).ordered
@@ -79,7 +77,7 @@ module Deface
79
77
 
80
78
  it "should ignore railtie with no root" do
81
79
  railtie = double('railtie')
82
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => [railtie]
80
+ allow(Rails.application).to receive_message_chain :railties, :_all => [railtie]
83
81
 
84
82
  expect(railtie).to receive(:respond_to?).with(:root)
85
83
  expect(railtie).not_to receive(:respond_to?).with(:paths)
@@ -101,7 +99,7 @@ module Deface
101
99
 
102
100
  it "should keep a reference to which railtie/app defined the override" do
103
101
  allow(Rails.application).to receive_messages :root => assets_path, :paths => {"app/overrides" => ["dummy_app"] }
104
- allow(Rails.application).to receive_message_chain :railties, railties_collection_accessor => [ engine ]
102
+ allow(Rails.application).to receive_message_chain :railties, :_all => [ engine ]
105
103
 
106
104
  Rails.application.config.deface.overrides.load_all(Rails.application)
107
105
 
@@ -127,10 +125,8 @@ module Deface
127
125
  end
128
126
 
129
127
  it "should add paths to watchable_dir when running Rails 3.2" do
130
- if Rails.version[0..2] >= '3.2'
131
- Rails.application.config.deface.overrides.send(:enumerate_and_load, ["app/gold"], root)
132
- expect(Rails.application.config.watchable_dirs).to eq({"/some/path/app/gold" => [:rb, :deface] })
133
- end
128
+ Rails.application.config.deface.overrides.send(:enumerate_and_load, ["app/gold"], root)
129
+ expect(Rails.application.config.watchable_dirs).to eq({"/some/path/app/gold" => [:rb, :deface] })
134
130
  end
135
131
 
136
132
  end
@@ -24,18 +24,28 @@ module Deface
24
24
  end
25
25
 
26
26
  it "should handle simple haml attributes" do
27
- expect(haml_to_erb("%meta{:charset => 'utf-8'}")).to eq("<meta charset='utf-8'>")
27
+ expect(haml_to_erb("%meta{:charset => 'utf-8'}")).to eq("<meta charset='utf-8' />")
28
28
  expect(haml_to_erb("%p(alt='hello world')Hello World!")).to eq("<p alt='hello world'>Hello World!</p>")
29
29
  end
30
30
 
31
+ it "should handle recursive attributes" do
32
+ expect(haml_to_erb("%div{:data => {:foo => 'bar'}}")).to eq("<div data-foo='bar'></div>")
33
+ expect(haml_to_erb("%div{:data => {:foo => { :bar => 'baz' }, :qux => 'corge'}}")).to eq("<div data-foo-bar='baz' data-qux='corge'></div>")
34
+
35
+ if RUBY_VERSION > "1.9"
36
+ expect(haml_to_erb("%div{data: {foo: 'bar'}}")).to eq("<div data-foo='bar'></div>")
37
+ expect(haml_to_erb("%div{data: {foo: { bar: 'baz' }, qux: 'corge'}}")).to eq("<div data-foo-bar='baz' data-qux='corge'></div>")
38
+ end
39
+ end
40
+
31
41
  it "should handle haml attributes with commas" do
32
- expect(haml_to_erb("%meta{'http-equiv' => 'X-UA-Compatible', :content => 'IE=edge,chrome=1'}")).to eq("<meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'>")
33
- expect(haml_to_erb("%meta(http-equiv='X-UA-Compatible' content='IE=edge,chrome=1')")).to eq("<meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'>")
34
- expect(haml_to_erb('%meta{:name => "author", :content => "Example, Inc."}')).to eq("<meta content='Example, Inc.' name='author'>")
35
- expect(haml_to_erb('%meta(name="author" content="Example, Inc.")')).to eq("<meta content='Example, Inc.' name='author'>")
42
+ expect(haml_to_erb("%meta{'http-equiv' => 'X-UA-Compatible', :content => 'IE=edge,chrome=1'}")).to eq("<meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible' />")
43
+ expect(haml_to_erb("%meta(http-equiv='X-UA-Compatible' content='IE=edge,chrome=1')")).to eq("<meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible' />")
44
+ expect(haml_to_erb('%meta{:name => "author", :content => "Example, Inc."}')).to eq("<meta content='Example, Inc.' name='author' />")
45
+ expect(haml_to_erb('%meta(name="author" content="Example, Inc.")')).to eq("<meta content='Example, Inc.' name='author' />")
36
46
 
37
47
  if RUBY_VERSION > "1.9"
38
- expect(haml_to_erb('%meta{name: "author", content: "Example, Inc."}')).to eq("<meta content='Example, Inc.' name='author'>")
48
+ expect(haml_to_erb('%meta{name: "author", content: "Example, Inc."}')).to eq("<meta content='Example, Inc.' name='author' />")
39
49
  end
40
50
  end
41
51