deface 1.5.0 → 1.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.
@@ -1,32 +1,58 @@
1
1
  module Deface
2
2
  module TemplateHelper
3
+ def self.lookup_context
4
+ @lookup_context ||= ActionView::LookupContext.new(
5
+ ActionController::Base.view_paths, {:formats => [:html]}
6
+ )
7
+ end
3
8
 
4
9
  # used to find source for a partial or template using virtual_path
5
- def load_template_source(virtual_path, partial, apply_overrides=true)
10
+ def load_template_source(virtual_path, partial, apply_overrides=true, lookup_context: Deface::TemplateHelper.lookup_context)
6
11
  parts = virtual_path.split("/")
7
- prefix = []
12
+
8
13
  if parts.size == 2
9
- prefix << ""
14
+ prefix = nil
10
15
  name = virtual_path
11
16
  else
12
- prefix << parts.shift
17
+ prefix = [parts.shift]
13
18
  name = parts.join("/")
14
19
  end
15
20
 
16
- #this needs to be reviewed for production mode, overrides not present
17
- Rails.application.config.deface.enabled = apply_overrides
18
- @lookup_context ||= ActionView::LookupContext.new(ActionController::Base.view_paths, {:formats => [:html]})
19
- view = @lookup_context.disable_cache do
20
- @lookup_context.find(name, prefix, partial)
21
- end
21
+ view = lookup_context.disable_cache { lookup_context.find(name, prefix, partial) }
22
22
 
23
- if view.handler.to_s == "Haml::Plugin"
24
- Deface::HamlConverter.new(view.source).result
25
- elsif view.handler.class.to_s == "Slim::RailsTemplate"
26
- Deface::SlimConverter.new(view.source).result
27
- else
28
- view.source
23
+ source =
24
+ if view.handler.to_s == "Haml::Plugin"
25
+ Deface::HamlConverter.new(view.source).result
26
+ elsif view.handler.class.to_s == "Slim::RailsTemplate"
27
+ Deface::SlimConverter.new(view.source).result
28
+ else
29
+ view.source
30
+ end
31
+
32
+ if apply_overrides
33
+ begin
34
+ # This needs to be reviewed for production mode, overrides not present
35
+ original_enabled = Rails.application.config.deface.enabled
36
+ Rails.application.config.deface.enabled = apply_overrides
37
+
38
+ syntax = Deface::ActionViewExtensions.determine_syntax(view.handler)
39
+ overrides = Deface::Override.find(
40
+ locals: view.instance_variable_get(:@locals),
41
+ format: view.instance_variable_get(:@format),
42
+ variant: view.instance_variable_get(:@variant),
43
+ virtual_path: view.instance_variable_get(:@virtual_path),
44
+ )
45
+
46
+ if syntax && overrides.any?
47
+ source = Deface::Override.convert_source(source, syntax: syntax)
48
+ source = Deface::Override.apply_overrides(source, overrides: overrides)
49
+ end
50
+ ensure
51
+ Rails.application.config.deface.enabled = original_enabled
52
+ end
29
53
  end
54
+
55
+ source
30
56
  end
31
57
 
32
58
  #gets source erb for an element
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deface
4
+ VERSION = '1.9.0'
5
+
6
+ def gem_version
7
+ Gem::Version.new(VERSION)
8
+ end
9
+ end
data/lib/deface.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "action_view"
2
2
  require "action_controller"
3
+ require "deface/errors"
3
4
  require "deface/template_helper"
4
5
  require "deface/original_validator"
5
6
  require "deface/applicator"
@@ -38,18 +39,21 @@ require "deface/matchers/range"
38
39
  require "deface/environment"
39
40
  require "deface/precompiler"
40
41
 
42
+ require "deface/railtie" if defined?(Rails)
43
+
41
44
  module Deface
42
- if defined?(Rails)
43
- require "deface/railtie"
45
+ @before_rails_6 = ActionView.gem_version < Gem::Version.new('6.0.0')
46
+ @template_class = @before_rails_6 ? ActionView::CompiledTemplates : ActionDispatch::DebugView
47
+
48
+ def self.before_rails_6?
49
+ @before_rails_6
50
+ end
51
+
52
+ def self.template_class
53
+ @template_class
44
54
  end
45
55
 
46
56
  if defined?(ActiveSupport::Digest)
47
57
  Deface::Digest.digest_class = ActiveSupport::Digest
48
58
  end
49
-
50
- # Exceptions
51
- class DefaceError < StandardError; end
52
-
53
- class NotSupportedError < DefaceError; end
54
-
55
59
  end
@@ -1,94 +1,152 @@
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 after_rails_6: true do
7
+ skip "This spec is targeted at Rails v6+" if Deface.before_rails_6?
8
+ end
20
9
 
21
- it "should return unmodified source" do
22
- expect(@template.source).to eq("<p>test</p>")
23
- end
10
+ before before_rails_6: true do
11
+ skip "This spec is targeted at Rails before v6+" unless Deface.before_rails_6?
12
+ end
24
13
 
25
- it "should not change updated_at" do
26
- expect(@template.updated_at).to eq(@updated_at)
27
- end
14
+ let(:template) { ActionView::Template.new(
15
+ source,
16
+ path,
17
+ handler,
18
+ **options,
19
+ **(Deface.before_rails_6? ? {updated_at: updated_at} : {})
20
+ ) }
21
+
22
+ let(:source) { "<p>test</p>" }
23
+ let(:path) { "/some/path/to/file.erb" }
24
+ let(:handler) { ActionView::Template::Handlers::ERB }
25
+ let(:options) {{
26
+ virtual_path: virtual_path,
27
+ format: format,
28
+ locals: {}
29
+ }}
30
+ let(:format) { :html }
31
+ let(:virtual_path) { "posts/index" }
32
+
33
+ let(:updated_at) { Time.now - 600 }
34
+
35
+ describe "with no overrides defined" do
36
+ it "should initialize new template object" do
37
+ expect(template.is_a?(ActionView::Template)).to eq(true)
38
+ end
28
39
 
40
+ it "should return unmodified source" do
41
+ expect(template.source).to eq("<p>test</p>")
29
42
  end
30
43
 
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
44
+ it "should not change updated_at", :before_rails_6 do
45
+ expect(template.updated_at).to eq(updated_at)
46
+ end
47
+ end
41
48
 
42
- it "should return modified source" do
43
- expect(@template.source).to eq("<%= raw(text) %>")
44
- end
49
+ describe "unsupported template" do
50
+ let(:source) { "xml.post => :blah" }
51
+ let(:path) { "/some/path/to/file.erb" }
52
+ let(:handler) { ActionView::Template::Handlers::Builder }
53
+ let(:updated_at) { Time.now - 100 }
54
+ let(:format) { :xml }
45
55
 
46
- it "should change updated_at" do
47
- expect(@template.updated_at).to be > @updated_at
48
- end
56
+ before(:each) do
57
+ Deface::Override.new(virtual_path: "posts/index", name: "Posts#index", remove: "p")
49
58
  end
50
59
 
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')
60
+ it "should return unmodified source" do
61
+ expect(template.source).to eq("xml.post => :blah")
62
+ expect(template.source).not_to include("=&gt;")
63
+ end
64
+ end
56
65
 
57
- expect(template.send(:method_name)).to eq("_#{Digest::MD5.new.update("#{deface_hash}_#{template.send(:method_name_without_deface)}").hexdigest}")
66
+ describe ".determine_syntax(handler)" do
67
+ let(:source) { "xml.post => :blah" }
68
+ let(:format) { :xml }
69
+
70
+ # Not so BDD, but it keeps us from making mistakes in the future for instance,
71
+ # we test ActionView::Template here with a handler == ....::Handlers::ERB,
72
+ # while in rails it seems it's an instance of ...::Handlers::ERB.
73
+ it "recognizes supported syntaxes" do
74
+ expectations = { Haml::Plugin => :haml,
75
+ ActionView::Template::Handlers::ERB => :erb,
76
+ ActionView::Template::Handlers::ERB.new => :erb,
77
+ ActionView::Template::Handlers::Builder => nil }
78
+ expectations.each do |handler, expected|
79
+ expect(template.is_a?(ActionView::Template)).to eq(true)
80
+ expect(described_class.determine_syntax(handler)).to eq(expected), "unexpected result for handler #{handler}"
58
81
  end
82
+ end
83
+ end
59
84
 
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/
85
+ describe '#render' do
86
+ let(:source) { "<p>test</p><%= raw(text) %>".inspect }
87
+ let(:local_assigns) { {text: "some <br> text"} }
88
+ let(:lookup_context) { ActionView::LookupContext.new(["#{__dir__}/views"]) }
89
+ let(:view) do
90
+ if Rails::VERSION::STRING >= '6.1'
91
+ ActionView::Base.with_empty_template_cache.new(lookup_context, {}, nil)
92
+ else
93
+ ActionView::Base.new(lookup_context)
62
94
  end
63
95
  end
96
+ let(:options) { {
97
+ virtual_path: virtual_path,
98
+ format: format,
99
+ locals: local_assigns.keys
100
+ } }
101
+
102
+ it 'renders the template modified by deface using :replace' do
103
+ Deface::Override.new(
104
+ virtual_path: virtual_path,
105
+ name: "Posts#index",
106
+ replace: "p",
107
+ text: "<h1>Argh!</h1>"
108
+ )
109
+
110
+ expect(template.render(view, local_assigns)).to eq(%{"<h1>Argh!</h1>some <br> text"})
111
+ end
64
112
 
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
113
+ it 'renders the template modified by deface using :remove' do
114
+ Deface::Override.new(
115
+ virtual_path: virtual_path,
116
+ name: "Posts#index",
117
+ remove: "p",
118
+ )
70
119
 
71
- it "should return unmodified source" do
72
- #if processed, source would include "=&gt;"
73
- expect(@template.source).to eq("xml.post => :blah")
120
+ expect(template.render(view, local_assigns)).to eq(%{"some <br> text"})
121
+ end
122
+
123
+ context 'with a haml template' do
124
+ let(:source) { "%p test\n= raw(text)\n" }
125
+ let(:handler) { Haml::Plugin }
126
+
127
+ it 'renders the template modified by deface using :remove' do
128
+ Deface::Override.new(
129
+ virtual_path: virtual_path,
130
+ name: "Posts#index",
131
+ remove: "p",
132
+ )
133
+
134
+ expect(template.render(view, local_assigns)).to eq(%{\nsome <br> text})
74
135
  end
75
136
  end
76
137
 
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
138
+ context 'with a slim template' do
139
+ let(:source) { "p test\n= raw(text)\n" }
140
+ let(:handler) { Slim::RailsTemplate.new }
141
+
142
+ it 'renders the template modified by deface using :remove' do
143
+ Deface::Override.new(
144
+ virtual_path: virtual_path,
145
+ name: "Posts#index",
146
+ remove: "p",
147
+ )
148
+
149
+ expect(template.render(view, local_assigns)).to eq(%{\nsome <br> text\n})
92
150
  end
93
151
  end
94
152
  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
@@ -28,6 +28,16 @@ module Deface
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
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' />")
33
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' />")
@@ -561,7 +561,7 @@ module Deface
561
561
 
562
562
  describe "#expire_compiled_template" do
563
563
  it "should remove compiled method when method name matches virtual path but not digest" do
564
- if Rails.version < "6.0.0.beta1"
564
+ if Deface.before_rails_6?
565
565
  instance_methods_count = ActionView::CompiledTemplates.instance_methods.size
566
566
 
567
567
  module ActionView::CompiledTemplates
@@ -598,7 +598,7 @@ module Deface
598
598
  end
599
599
 
600
600
  it "should not remove compiled method when virtual path and digest matach" do
601
- if Rails.version < "6.0.0.beta1"
601
+ if Deface.before_rails_6?
602
602
  instance_methods_count = ActionView::CompiledTemplates.instance_methods.size
603
603
 
604
604
  module ActionView::CompiledTemplates
@@ -20,6 +20,12 @@ module Deface
20
20
  it "should return empty array when no details hash passed" do
21
21
  expect(Deface::Override.find({})).to eq([])
22
22
  end
23
+
24
+ context 'with a frozen string as virtual_path' do
25
+ it 'works' do
26
+ expect(Deface::Override.find({:virtual_path => "posts/index".freeze}).size).to eq(1)
27
+ end
28
+ end
23
29
  end
24
30
 
25
31
  describe "#find_using" do
data/spec/spec_helper.rb CHANGED
@@ -2,13 +2,12 @@ require 'simplecov'
2
2
  SimpleCov.start 'rails'
3
3
  require 'rspec'
4
4
  require 'active_support'
5
- require 'action_view'
6
- require 'action_controller'
7
5
  require 'deface'
8
6
  require 'rails/generators'
9
7
  # have to manually require following for testing purposes
10
8
  require 'deface/action_view_extensions'
11
9
  require 'rails/version'
10
+ require 'pry'
12
11
 
13
12
  #adding fake class as it's needed by haml 4.0, don't
14
13
  #want to have to require the entire rails stack in specs.
@@ -42,7 +41,7 @@ RSpec.configure do |config|
42
41
  config.mock_framework = :rspec
43
42
  end
44
43
 
45
- if Rails.version < "6.0.0.beta1"
44
+ if Deface.before_rails_6?
46
45
  module ActionView::CompiledTemplates
47
46
  #empty module for testing purposes
48
47
  end
@@ -69,9 +68,7 @@ shared_context "mock Rails" do
69
68
  allow(Rails.application.config).to receive(:deface).and_return ActiveSupport::OrderedOptions.new
70
69
  Rails.application.config.deface.enabled = true
71
70
 
72
- if Rails.version[0..2] >= '3.2'
73
- allow(Rails.application.config).to receive(:watchable_dirs).and_return({})
74
- end
71
+ allow(Rails.application.config).to receive(:watchable_dirs).and_return({})
75
72
 
76
73
  allow(Rails).to receive(:root).and_return Pathname.new('spec/dummy')
77
74