README.markdown in deface-0.9.1 vs README.markdown in deface-1.0.0.rc1

- old
+ new

@@ -102,141 +102,203 @@ ### Examples Replaces all instances of `h1` in the `posts/_form.html.erb` partial with `<h1>New Post</h1>` - Deface::Override.new(:virtual_path => "posts/_form", - :name => "example-1", - :replace => "h1", - :text => "<h1>New Post</h1>") +```ruby +Deface::Override.new(:virtual_path => "posts/_form", + :name => "example-1", + :replace => "h1", + :text => "<h1>New Post</h1>") +``` Alternatively pass it a block of code to run: - Deface::Override.new(:virtual_path => "posts/_form", - :name => "example-1", - :replace => "h1") do - "<h1>New Post</h1>" - end +```ruby +Deface::Override.new(:virtual_path => "posts/_form", + :name => "example-1", + :replace => "h1") do + "<h1>New Post</h1>" +end +``` Inserts `<%= link_to "List Comments", comments_url(post) %>` before all instances of `p` with css class `comment` in `posts/index.html.erb` - Deface::Override.new(:virtual_path => "posts/index", - :name => "example-2", - :insert_before => "p.comment", - :text => "<%= link_to "List Comments", comments_url(post) %>") +```ruby +Deface::Override.new(:virtual_path => "posts/index", + :name => "example-2", + :insert_before => "p.comment", + :text => "<%= link_to 'List Comments', comments_url(post) %>") +``` Inserts the contents of `shared/_comment.html.erb` after all instances of `div` with an id of `comment_21` in `posts/show.html.erb` - Deface::Override.new(:virtual_path => "posts/show", - :name => "example-3", - :insert_after => "div#comment_21", - :partial => "shared/comment") +```ruby +Deface::Override.new(:virtual_path => "posts/show", + :name => "example-3", + :insert_after => "div#comment_21", + :partial => "shared/comment") +``` 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 %>` - Deface::Override.new(:virtual_path => "posts/new", - :name => "example-4", - :remove => "code[erb-loud]:contains('helper_method')", - :original => "<%= helper_method %>") +```ruby +Deface::Override.new(:virtual_path => "posts/new", + :name => "example-4", + :remove => "code[erb-loud]:contains('helper_method')", + :original => "<%= helper_method %>") +``` Wraps the `div` with id of `products` in ruby if statement, the <%= render_original %> in the `text` indicates where the matching content should be re-included. - Deface::Override.new(:virtual_path => "posts/new", - :name => "example-5", - :surround => "div#products", - :text => "<% if @product.present? %><%= render_original %><% end %>") +```ruby +Deface::Override.new(:virtual_path => "posts/new", + :name => "example-5", + :surround => "div#products", + :text => "<% if @product.present? %><%= render_original %><% end %>") +``` Sets (or adds if not present) the `class` and `title` attributes to all instances of `a` with an id of `link` in `posts/index.html.erb` - Deface::Override.new(:virtual_path => 'posts/index', - :name => 'add_attrs_to_a_link', - :set_attributes => 'a#link', - :attributes => {:class => 'pretty', :title => 'This is a link'}) +```ruby +Deface::Override.new(:virtual_path => 'posts/index', + :name => 'add_attrs_to_a_link', + :set_attributes => 'a#link', + :attributes => {:class => 'pretty', :title => 'This is a link'}) +``` Remove an entire ERB if statement (and all it's contents) in the 'admin/products/index.html.erb' template, using the :closing_selector. - Deface::Override.new(:virtual_path => 'admin/products/index', - :name => "remove_if_statement", - :remove => "code[erb-silent]:contains('if @product.sold?')", - :closing_selector => "code[erb-silent]:contains('end')" +```ruby +Deface::Override.new(:virtual_path => 'admin/products/index', + :name => "remove_if_statement", + :remove => "code[erb-silent]:contains('if @product.sold?')", + :closing_selector => "code[erb-silent]:contains('end')" +``` ### Scope Deface scopes overrides by virtual_path (or partial / template file), that means all override names only need to be unique within that single file. ### Redefining Overrides 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. You do not need to resupply all the values originally used, just the ones you want to change: +```ruby Deface::Override.new(:virtual_path => 'posts/index', :name => 'add_attrs_to_a_link', :disabled => true) +``` +### Namespacing +If you want to avoid inadvertently redefining overrides in other engines, you can use the `namespaced` option to have +an override automatically be namespaced to the engine in which it was defined: + +```ruby + Deface::Override.new(:virtual_path => 'posts/index', + :name => 'add_link', + :namespaced => true) +``` + +So for example if the above override was defined in `MyEngine` it would be automatically named `my_engine_add_link`. +This can also be activated globally for all DSL overrides in your app's `application.rb` file: + +```ruby +config.deface.namespaced = true # default is false +``` + Using the Deface DSL (.deface files) ------------------------------------ -Instead of defining Deface::Override instances directly, you can alternatively add `.deface` files to the `app/overrides` folder and Deface will automatically them pick up. +Instead of defining Deface::Override instances directly, you can alternatively add `.deface` files to the `app/overrides` folder and Deface will automatically pick them up. The path of each override should match the path of the view template you want to modify, say for example if you have a template at: app/views/posts/_post.html.erb Then you can override it by adding a .deface file at: app/overrides/posts/_post/my_override.html.erb.deface The format of a .deface file is a comment showing the action to be performed, followed by any markup that would be normally passed to the :erb, :text, :haml arguments: - <!-- insert_after 'h1' --> - <h2>These robots are awesome.</h2> +```html +<!-- insert_after 'h1' --> +<h2>These robots are awesome.</h2> +``` The same effect can also be achieved with haml, by changing the overrides filename to: app/overrides/posts/_post/my_override.html.haml.deface and including haml source: - / - insert_after 'h1' - %h2 These robots are awesome. +```haml +/ + insert_after 'h1' +%h2 These robots are awesome. +``` - #### Additional Options You can include all the additional options you can normally use when defining a Deface::Override manually, a more complex example: - <!-- replace_contents 'h1' - closing_selector 'div#intro' - disabled --> - <p>This is a complicated example</p> +```html +<!-- replace_contents 'h1' closing_selector 'div#intro' disabled --> +<p>This is a complicated example</p> +``` #### Disabled / Enabled The DSL does not accept the instance style ````:disabled => boolean```` instead you can simply include either: - <!-- enabled --> +```html +<!-- enabled --> +``` or - <!-- disabled --> +```html +<!-- disabled --> +``` +#### Namespacing + +When using the DSL, overrides automatically take their name from the filename of the file in which they are defined +(ie `my_override.html.erb.deface` becomes `my_override`) so overrides with the same filename will replace each other, +even if they are defined in separate engines. If you want to avoid this, you can use the `namespaced` option : + +```erb +<!-- insert_bottom 'head' namespaced--> +``` +or activate it globally for all DSL overrides in your app's `application.rb` file: + +```ruby +config.deface.namespaced = true # default is false +``` + +Each override will then have its name namespaced to the engine in which it was defined +(ie `my_override.html.erb.deface` defined in `MyEngine` becomes `my_engine_my_override`), +allowing overrides in different engines with identical filenames to co-exist. + ### DSL usage for overrides that do not include markup If your override does not require any markup, for example actions including ````:remove, :set_attributes, :remove_from_attributes, :add_to_attrbiutes```` you can exclude the "html.erb" or "html.haml" from the file name and you do not need to wrap the arguments in a comment. So the override filename becomes simply: app/overrides/posts/_post/my_override.deface And the contents: - add_to_attributes 'a#search' - attributes :alt => 'Click here to search' +```ruby +add_to_attributes 'a#search' +attributes :alt => 'Click here to search' +``` - Rake Tasks ---------- Deface includes a couple of rake tasks that can be helpful when defining or debugging overrides. @@ -278,31 +340,43 @@ Implementation ============== Deface temporarily converts ERB files into a pseudo HTML markup that can be parsed and queired by Nokogiri, using the following approach: - <%= some ruby code %> +```erb +<%= some ruby code %> +``` - becomes +becomes: - <code erb-loud> some ruby code </code> +```html +<code erb-loud> some ruby code </code> +``` and - <% other ruby code %> +```erb +<% other ruby code %> +``` - becomes +becomes: - <code erb-silent> other ruby code </code> +```html +<code erb-silent> other ruby code </code> +``` ERB that is contained inside a HTML tag definition is converted slightly differently to ensure a valid HTML document that Nokogiri can parse: - <p id="<%= dom_id @product %>" <%= "style='display:block';" %>> +```erb +<p id="<%= dom_id @product %>" <%= "style='display:block';" %>> +``` - becomes +becomes: - <p data-erb-id="&lt;%= dom_id @product %&gt;" data-erb-0="&lt;%= &quot;style='display:block';&quot; %&gt;"> +```html +<p data-erb-id="&lt;%= dom_id @product %&gt;" data-erb-0="&lt;%= &quot;style='display:block';&quot; %&gt;"> +``` Deface overrides have full access to all variables accessible to the view being customized. Caveats @@ -311,6 +385,12 @@ 1. Ensure that your layout views include doctype, html, head and body tags in a single file, as Nokogiri will create such elements if it detects any of these tags have been incorrectly nested. 2. Parsing will fail and result in invalid output if ERB blocks are responsible for closing an HTML tag that was opened normally, i.e. don't do this: - &lt;div <%= ">" %> +```html +&lt;div <%= ">" %> +``` + +3. Gems or Spree Extensions that add overrides to your application will load them in the order they are added to your Gemfile. + +4. Applying an override to a view that contains invalid markup (which, occasionally happens in Spree views) can break rendering that would normally pass a browser's own permissive rendering. This is because the nokogiri library takes it upon itself to correct the issue, which doesn't happen prior to applying deface. Sometimes that correction changes the rendering of the view in an unintended manner, appearing to break it. The easiest way to tell if this is the cause of an issue for you is to put your view into http://deface.heroku.com/ and diff the output with the html which rails renders without your override. If you see a difference in the structure of the html, you may have invalid markup in your view which nokogiri is correcting for you. See [Spree issue #1789](https://github.com/spree/spree/pull/1789) for an example of what may be wrong in a view.