Git Product home page Git Product logo

deface's Introduction

Deface

Travis build

Deface is a library that allows you to customize HTML (ERB, Haml and Slim) views in a Rails application without editing the underlying view.

It allows you to easily target html & erb elements as the hooks for customization using CSS selectors as supported by Nokogiri.

Usage

There are two ways of using Deface:

  • Using Deface::Override - this is the traditional method whereby you define instances of the Deface::Override class directly.
  • Using the Deface DSL (.deface files) - the DSL provides a terser syntax, and better organization of the individual override files.

Both methods are interoperable, so you can use a mix, and redefine overrides defined one-way using the other.

Using Deface::Override

A new instance of the Deface::Override class is initialized for each customization you wish to define. When initializing a new override you must supply only one Target, Action & Source parameter and any number of Optional parameters.

Note: the source parameter is not required when the :remove, :set_attributes, :add_to_attributes, :remove_from_attributes actions are specified.

You should save your overrides in the app/overrides, normally one override per file using the same file name as specified in the :name argument. Deface will automatically require these from your application, and any engines installed.

Note: You should NOT manually require override files, as this can cause problems for precompiling.

Target

  • :virtual_path - The template / partial / layout where the override should take effect eg: "shared/_person", "admin/posts/new" this will apply to all controller actions that use the specified template.

Action

  • :remove - Removes all elements that match the supplied selector

  • :replace - Replaces all elements that match the supplied selector

  • :replace_contents - Replaces the contents of all elements that match the supplied selector

  • :surround - Surrounds all elements that match the supplied selector, expects replacement markup to contain <%= render_original %> placeholder

  • :surround_contents - Surrounds the contents of all elements that match the supplied selector, expects replacement markup to contain <%= render_original %> placeholder

  • :insert_after - Inserts after all elements that match the supplied selector

  • :insert_before - Inserts before all elements that match the supplied selector

  • :insert_top - Inserts inside all elements that match the supplied selector, as the first child.

  • :insert_bottom - Inserts inside all elements that match the supplied selector, as the last child.

  • :set_attributes - Sets attributes on all elements that match the supplied selector, replacing existing attribute value if present or adding if not. Expects :attributes option to be passed.

  • :add_to_attributes - Appends value to attributes on all elements that match the supplied selector, adds attribute if not present. Expects :attributes option to be passed.

  • :remove_from_attributes - Removes value from attributes on all elements that match the supplied selector. Expects :attributes option to be passed.

Source

  • :text - String containing markup

  • :partial - Relative path to a partial

  • :template - Relative path to a template

  • :cut - Cuts (i.e. copies and removes) an element or a range of elements from the current template as the source, using css selector(s). Supports two versions:

    • selector - A single string css selector (first match is used).
    • {:start => 'selector_a', :end => 'selector_b'} - select a range of elements using :start and :end css selectors. The end element must be a sibling of the first/starting element.
  • :copy - Copies an element or a range of elements from the current template as the source, using css selector(s). Supports two versions:

    • selector - A single string css selector (first match is used).
    • {:start => 'selector_a', :end => 'selector_b'} - select a range of elements using :start and :end css selectors. The end element must be a sibling of the first/starting element.

Optional

  • :name - Unique name for override so it can be identified and modified later. This needs to be unique within the same :virtual_path

  • :disabled - When set to true the override will not be applied.

  • :original - Either a string containing the original markup that is being overridden, or a string that is the SHA1 digest of the original markup. If supplied Deface will log when the original markup changes, which helps highlight overrides that need attention when upgrading versions of the source application. Only really warranted for :replace overrides. NB: All whitespace is stripped before comparison. To generate the SHA1 digest do: Digest::SHA1.hexdigest(original_markup_string.gsub(/\s/, ''))

  • :closing_selector - A second css selector targeting an end element, allowing you to select a range of elements to apply an action against. The :closing_selector only supports the :replace, :remove and :replace_contents actions, and the end element must be a sibling of the first/starting element. Note the CSS general sibling selector (~) is used to match the first element after the opening selector (see below for an example).

  • :sequence - Used to order the application of an override for a specific virtual path, helpful when an override depends on another override being applied first, supports:

    • :sequence => n - where n is a positive or negative integer (lower numbers get applied first, default 100).
    • :sequence => {:before => "*override_name*"} - where "override_name" is the name of an override defined for the same virtual_path, the current override will be appplied before the named override passed.
    • :sequence => {:after => "*override_name*"} - the current override will be applied after the named override passed.
  • :attributes - A hash containing all the attributes to be set on the matched elements, eg: :attributes => {:class => "green", :title => "some string"}

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>")

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

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) %>")

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")

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 => "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 %>")

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'})

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 => "erb[silent]:contains('if @product.sold?')",
                     :closing_selector => "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 :virtual_path, :name and action that was originally used. You do not need to resupply all the values originally used, just the ones you want to change:

Deface::Override.new(:virtual_path => 'posts/index',
                     :name => 'add_attrs_to_a_link',
                     :set_attributes => '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:

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:

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 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>

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.

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'
  sequence :before => 'my_other_override'
  disabled -->
<p>This is a complicated example</p>

Note options requiring a hash should be on a separate line.

Disabled / Enabled

The DSL does not accept the instance style :disabled => boolean instead you can simply include either:

<!-- enabled -->

or

<!-- 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 :

<!-- insert_bottom 'head' namespaced -->

or activate it globally for all DSL overrides in your app's application.rb file:

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_attributes 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'

Rake Tasks

Deface includes a couple of rake tasks that can be helpful when defining or debugging overrides.

rake deface:get_result - Will list the original contents of a partial or template, the overrides that have been defined for a that file, and the resulting markup. get_result takes a single argument which is the virtual path of the template / partial:

rake deface:get_result[shared/_head]

rake deface:get_result['admin/products/index']

rake deface:test_selector - Applies a given CSS selector against a partial or template and outputs the markup for each match (if any). test_selector requires two arguments, the first is the virtual_path for the partial / template, the second is the CSS selector to apply:

rake deface:test_selector[shared/_head,title]

rake deface:test_selector['admin/products/index','div.toolbar']

rake deface:precompile - Generates compiled views that contain all overrides applied. See Production & Precompiling section below for more.

rake deface:precompile

Production & Precompiling

Deface now supports precompiling where all overrides are loaded and applied to the original views and the resulting templates are then saved to your application's app/compiled_views directory. To precompile run:

 DEFACE_ENABLED=true bundle exec rake deface:precompile

It's important to disable Deface once precompiling is used to prevent overrides getting applied twice. To disable add the following line to your application's production.rb file:

config.deface.enabled = ENV['DEFACE_ENABLED'] == 'true'

NOTE: You can also use precompiling in development mode.

Adding to Capistrano

Adding the following to your deploy.rb will automatically compile the views during deploy

namespace :deface do
  desc "Pre-compile Deface overrides into templates"
  task :precompile do
    on roles(:app) do
      within release_path do
        with rails_env: fetch(:rails_env), deface_enabled: true do
          execute :rake, 'deface:precompile'
        end
      end
    end
  end
end

after 'deploy:updated', 'deface:precompile'

Upgrading from 0.9 to 1.0

If you are updating from 0.9.x to 1.0.0 or higher, there's a major internal change you should be aware of.

Previously, erb blocks (i.e. <%= some_method %>) were converted as:

  <code erb-loud> some_method </code>

They are now converted to:

  <erb loud> some_method </erb>

This change will affect any Override that uses a selector that matches on code or code[erb-loud] or code[erb-silent] etc, they should be updated to erb, erb[loud] or erb[silent], etc.

Note: HAML & SLIM are preconverted to ERB before Deface parsers them, so the same conversions are happening there.

See the Implementation section below for more details.

Implementation

Deface temporarily converts ERB files into a pseudo HTML markup that can be parsed and queried by Nokogiri, using the following approach:

<%= some ruby code %>

becomes:

<erb loud> some ruby code </erb>

and

<% other ruby code %>

becomes:

<erb silent> other ruby code </erb>

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';" %>>

becomes:

<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

Deface uses the amazing Nokogiri library (and in turn libxml) for parsing HTML / view files, in some circumstances either Deface's own pre-parser or libxml's will fail to correctly parse a template. You can avoid such issues by ensuring your templates contain valid HTML. Some other caveats include:

  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 <%= ">" %>

  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 for an example of what may be wrong in a view.

deface's People

Contributors

aldesantis avatar alexblackie avatar aplegatt avatar balvig avatar bbonislawski avatar bdq avatar binaryphile avatar damianlegawiec avatar dependabot-preview[bot] avatar elia avatar frodotus avatar hoshinotsuyoshi avatar huoxito avatar jdutil avatar jhawthorn avatar klevo avatar krzysiek1507 avatar minad avatar mscottford avatar parndt avatar peterberkenbosch avatar pszyszkaspark avatar pusewicz avatar radar avatar robertoles avatar schof avatar stevenh512 avatar tomash avatar tvdeyen avatar vygovskysergey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deface's Issues

undefined method `render' using HAML partial

I am trying to override the user login

Deface::Override.new(:virtual_path => "spree/user_sessions/new",
:replace => "[data-hook='login']",
:namespaced => true,
:name => "my_store_login",
:partial => "my_store/user_login")

with the following HAML partial

my_store/user_login.html.haml

= render :partial 'spree/shared/login'
= t(:or)
= link_to t(:create_a_new_account), spree.signup_path
= t(:or)
= link_to t(:forgot_password), spree.new_user_password_path

but an error is raised with haml :
=> undefined method `render' for #Object:0x007ff6b2a80380

trace log ...
(haml):1:in block in render' haml (4.0.0) lib/haml/engine.rb:129:ineval'
haml (4.0.0) lib/haml/engine.rb:129:in render' deface (0.9.1) lib/deface/haml_converter.rb:4:inresult'
deface (0.9.1) lib/deface/template_helper.rb:24:in load_template_source' deface (0.9.1) lib/deface/override.rb:131:insource'
deface (0.9.1) lib/deface/override.rb:185:in source_element' deface (0.9.1) lib/deface/applicator.rb:45:inblock (2 levels) in apply'

what's wrong with haml ?

Deface breaks spree's checkout.js

When a Deface override targets 'spree/checkout/_address', even if the override is disabled, it breaks the checkout.js file, which populates a state drop-down when a country with states is selected and replaces it with a text-field box when a country without states is selected. After Deface goes over and rewrites the view (even "without changing" anything), both the drop-down and the text-field box show up - PLUS the states are sorted seemingly randomly.

Steps to reproduce:

  1. Install fresh Spree store, version 1.0.4 (I have not tested on other versions, especially since it seems to be a Deface issue)
  2. Create a test override that is disabled, something as simple as:
Deface::Override.new( :virtual_path => 'spree/checkout/_address',
                      :name => 'test',
                      :insert_bottom => 'p#sphone',
                      :text => "<% %>",
                      :disabled => true)
  1. Run rails s.
  2. Add product to cart.
  3. Checkout - and you will see the issue on the address form.

I assume this happens because Deface makes subtle changes to the html.erb even when not applying any overrides. Any suggested workarounds?

Allow String Input

Would be great to allow string targets in addition to a view path target.

Update documentation

Hi,

Man, please, update the documentation (mainly the README) about the new place to put the Deface's files. A few months ago the files were put at config/initializers, now the Deface look at app/overrides. There isn't this information at the documentation.

Thanks ;)

sequence option regression

When using edge Deface to take advantage of the multiple render_original update I ran into this error that didn't present itself while using Deface 0.9.1:

ArgumentError: wrong number of arguments (0 for 1)
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/dsl/loader.rb:28:in `instance_eval'
(eval):3:in `block in load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/dsl/loader.rb:28:in `instance_eval'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/dsl/loader.rb:28:in `block in load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/dsl/loader.rb:17:in `open'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/dsl/loader.rb:17:in `load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:96:in `block (2 levels) in enumerate_and_load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:95:in `glob'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:95:in `block in enumerate_and_load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:85:in `each'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:85:in `enumerate_and_load'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:79:in `load_overrides'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:61:in `block in load_all'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:59:in `each'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/environment.rb:59:in `load_all'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/deface-cc8d0c5ee575/lib/deface/railtie.rb:12:in `activate'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.2.8/lib/active_support/callbacks.rb:429:in `_run__3340563893381929601__prepare__2512575180036981927__callbacks'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.2.8/lib/active_support/callbacks.rb:405:in `__run_callback'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.2.8/lib/active_support/callbacks.rb:385:in `_run_prepare_callbacks'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.2.8/lib/active_support/callbacks.rb:81:in `run_callbacks'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.2.8/lib/action_dispatch/middleware/reloader.rb:74:in `prepare!'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.2.8/lib/action_dispatch/middleware/reloader.rb:48:in `prepare!'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/application/finisher.rb:47:in `block in <module:Finisher>'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/initializable.rb:30:in `instance_exec'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/initializable.rb:30:in `run'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/initializable.rb:55:in `block in run_initializers'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/initializable.rb:54:in `each'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/initializable.rb:54:in `run_initializers'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/application.rb:136:in `initialize!'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.2.8/lib/rails/railtie/configurable.rb:30:in `method_missing'
~/spree_gelaskins/config/environment.rb:5:in `<top (required)>'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
/usr/local/Cellar/rbenv/0.3.0/versions/1.9.3-p194/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
~/spree_gelaskins/config.ru:3:in `block in <main>'
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/builder.rb:4:in `instance_eval'
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/builder.rb:4:in `initialize'
~/spree_gelaskins/config.ru:1:in `new'

The issue boiled down to being due to the way I was passing in the sequence option value.

Raises error:

<!-- replace "[data-hook='products_list_item'] .price.selling"
 ย  ย  sequence 2
 ย  ย  original 'f92eb818cbfff0ab67dcce9d43cdb445d510076c' -->

Works fine:

 <!-- replace "[data-hook='products_list_item'] .price.selling"
     sequence '2'
     original 'f92eb818cbfff0ab67dcce9d43cdb445d510076c' -->

So one of the changes since the last release causes sequence to require a string value rather than an integer. May take a whack at fixing this when I have time, but wanted to point it out for anyone else running into this quite confusing error message...

At the least would be nice if we could improve the error message output to indicate which override is causing the error since I thought it was possibly something wrong with Deface itself on edge not one of my overrides.

can't redefine overrides with :disabled => false

Hi

My problem is, if someone defined overrides in a gem with the option

:disabled => false

Example: https://github.com/jsqu99/spree_flexi_variants/blob/master/app/overrides/add_ad_hoc_option_types_to_cart_form.rb

It isn't possible to disable this override in my rails app (which includes the gem) using this:

Deface::Override.new(:virtual_path => "spree/products/_cart_form",
                     :name => "converted_product_price_733808074",
                     :insert_after => "[data-hook='product_price'], #product_price[data-hook]",
                     :partial => "spree/products/ad_hoc_option_types",
                     :disabled => true)

My Gemfile.lock shows this Version of deface:

deface (0.8.0)
      nokogiri (~> 1.5.0)
      rails (>= 3.0.9)

Thanks

Matthias

invalid multibyte char (US-ASCII)

Hi,

I have in Spree an override like this:

Deface::Override.new replace: "#footer-left",
                 text: "Copyright ยฉ 2012",
                 name: "footer"

When trying to start the server I get:

app/overrides/spree_application.rb:4: invalid multibyte char (US-ASCII)
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.1.3/lib/active_support/dependencies.rb:234:in `block in load'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.1.3/lib/active_support/dependencies.rb:223:in `block in load_dependency'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.1.3/lib/active_support/dependencies.rb:640:in `new_constants_in'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.1.3/lib/active_support/dependencies.rb:223:in `load_dependency'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.1.3/lib/active_support/dependencies.rb:234:in `load'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:52:in `block (2 levels) in enumerate_and_load'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:51:in `glob'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:51:in `block in enumerate_and_load'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:50:in `each'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:50:in `enumerate_and_load'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/environment.rb:27:in `load_all'
from /Users/dcrec1/.rvm/gems/ruby-1.9.3-p0/bundler/gems/deface-7d097c794fec/lib/deface/railtie.rb:12:in `activate'

Haml attributes missing from output (regression)

The following HAML in spree_application.haml

- x = 1
%body(class='one')

Gets rendered without the attributes:

<body>
</body>

Removing the assignment line makes it render correctly, which doesn't make sense as it shouldn't have any effect on the output.

Happens in any of the following combinations:

  • Spree: 1.1.0 - 1.2.0
  • deface 0.9.1 - 1.0.0.rc1
  • haml: 3.1.7 - 3.2.0.rc1
  • nokogiri: 1.5.5

Regression from Spree 1.1.0beta , deface 0.8.0 , haml 3.2.0.alpha.13

Might be a side effect of Nokogiri, from the deface README:

  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.

Wrapping around contents of whole template

I've been trying to wrap the contents of a partial, irrespective of its markup, by selecting the first and last elements.
Although the :surround action doesn't support using a range of elements with:closing_selector I was under the impression that I could replicate the desired behavior using a combination of overrides. Unfortunately I couldn't even select the first document element with Nokogiri selectors. The *:first syntax returns the first nodes for each element type.
This is not a Deface bug, but I couldn't find a group/list to post this sort of question.
Thanks

spree - deface products view based on product name

I'm trying to deface my /products page based on the product name and struggling.

I need to remove any products which contain the string "xyz". I've got as far as the following but i'm not sure how i can specify the string...

Deface::Override.new(:virtual_path => "spree/shared/_products",
:name => "remove_xyz_products",
:replace => "[data-hook='products_list_item']",
:text =>"",
)

thanks

Deface does not work with .js.erb template rendering .html.erb template

I have just tried to customize this template in Spree: https://github.com/spree/spree/blob/master/core/app/views/spree/admin/products/new.html.erb

It can be loaded in 2 ways:

  1. By going directly to /admin/products/new - then loads properly and deface works as expected
  2. By loading via AJAX, then it's rendered indirectly, via https://github.com/spree/spree/blob/master/core/app/views/spree/admin/products/new.js.erb

Problem is with 2nd case: deface cannot handle it and original template is rendered within javascript template.

Same override being called multiple times

All my Deface Overrides are being called 3 times in the same page load.

For example, I have the following override:

Deface::Override.new(:virtual_path => "spree/shared/_sidebar", 
                     :name => "subscribe", 
                     :insert_bottom => "aside", 
                     :partial => "spree/shared/subscribe",
                     :original => '583d3e1ae41e681779da7cdac8bee81e4efdb436')

When the page is loaded log shows:

Rendered spree_xxxx_theme/app/views/spree/shared/_cart.html.erb (2.9ms)
Rendered spree_xxxx_theme/app/views/spree/shared/_header.html.erb (6.4ms)
Deface: 1 overrides found for 'spree/shared/_sidebar'
Deface: 'subscribe' matched 1 times with 'aside'
Deface: 1 overrides found for 'spree/shared/_sidebar'
Deface: 'subscribe' matched 1 times with 'aside'
Deface: 1 overrides found for 'spree/shared/_sidebar'
Deface: 'subscribe' matched 1 times with 'aside'
Rendered spree_xxxx_theme/app/views/spree/shared/_sidebar.html.erb (1.4ms)

Everything is working fine in my app, but this behaviour seems very weird. Not sure what I have changed - in past overrides used to be called only once. Any idea on what might be causing it?

Thanks!

can't figure how to make deface work

Hello,

I'm trying to make deface work since a few hours, but with no success.

I've made a very basic example rails 3.2.6 app with:

# Gemfile:
gem 'deface'

A basic controller & view:

rails g controller index home

At this point, my app works, and openig the view in a browser shows the classic:

<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

I'm trying to add a deface override;

#app/overrides/index/home.html.erb.deface:

<!-- insert_after 'h1' -->
<h2>These robots are awesome.</h2>

I restart the server, but no results (server starts, but the view is not 'defaced').

And "rake deface:precompile" outputs:

Unable to precompile 'home' due to: 
can't convert nil into String

I've uploaded the code here so you can take a look:

https://github.com/danielres/test-deface

Any idea ? Am I missing something ?
Thank you.

HAML converter undefined method `[]' for nil:NilClass

Trying to use Deface as a simple way to let people customize Diaspora and I've run into a problem. I've traced this down to Deface::HamlConverter#deface_attributes not liking the following two lines in layouts/application.html.haml

    %meta{'http-equiv' => 'X-UA-Compatible', :content => 'IE=edge,chrome=1'}
    %meta{:name => "author", :content => "Diaspora, Inc."}

I've forked Deface and written tests for this, which I'm about to push to a branch (wanted to open an issue first so I could reference it in the commit message), but haven't found an easy way to fix it without breaking other tests.. lol

Targeting an image tag after id

Hi, I'm sorry to be posting here. I know Github isn't a tech support forum but I couldn't find anything relevant on google.

For a simple Deface override on Spree 1.0.3, I do

Deface::Override.new(
:virtual_path => "spree/products/show",
:replace=>"div#main-image",
:text=>"Hello World",
:name=>"want_to_do_something",
)

This works.

But what I want to do is to target the product image after the id #main-image. I tried adding :replace=>"div#main-image img" and a few combinations such as "div#main-image img:first", but at no point was the image replaced with hello world.

Sorry what am I missing out? Does Deface work on the ERB layer only and hence "img" doesnt work?

Error when file extension is .deface, :action is invalid (ArgumentError)

Rails server throws and ':action is invalid (ArgumentError)' error when the file has a .deface extension, for example, remove_shipping_phone.deface.

In order to gett it working, the file needs to be renamed to .rb, so no errors are thrown.

This happens with version 0.9.3 and ~1.0.0 of Deface.

Deterministic override ordering

I recently ran into an issue on a project where one override was removing a block of content with a selector of #header h1, and another override, for the same view, was inserting a block of content after #header h1.

We didn't really notice the issue until we had scaled up in production to two different web servers. Refreshing the page would sometimes insert the block of content, and sometimes it would not. It was baffling, and it took quite a while to track it down. The conclusion we came to is that the order that Deface uses to apply the overrides is not deterministic.

The solution we're going with is pretty much "don't do that", don't write Deface overrides that can be affected by another deface override. But it got me thinking about whether or not there should be some control over the order that the overrides are applied in.

I've listed out a couple of different options that I thought of. I'd like to collect feedback on which direction to go in, and then I'll work towards a patch.

before and after

Add before and after as options to the Override class. These will be used to sort the overrides before they are applied.

numeric order

Add a order option to the Override class. This will be used to numerically sort the overrides before they are applied. A warning (or error) can be produced if there are two overrides with the same value.

alphabetical ordering

Sort the overrides alphabetically by virtual_path and name. This limits the amount of control that users have over ordering, but it would make things deterministic. If someone wants to manipulate the order, they can always manipulate the filename.

Precompilation is borked

Hey Brian,

Precompilation of defaced views was broken for me for any environment that had config.deface.enabled = false.

Deface decides whether to load its action_view_extensions.rb at Rails boot time via https://github.com/spree/deface/blob/master/lib/deface/railtie.rb#L53-55

And by the time the enabled flag is turned on by the template_helper.rb in https://github.com/spree/deface/blob/master/lib/deface/template_helper.rb#L17 it is already too late.

This is what I did for now, for my own purposes: jumph4x@f369a79

I am not attaching this as a pull request for the obvious flaw: should this code ever run in the context of a loaded app on a server, the code does not unload the extensions or rewrite the method alias chain.

However, for running rake tasks this is fine.

If you want to throw a suggestion for how you'd rather have this handled, I'll send you a proper pull request.

Cheers

:action is invalid,lib/deface/override.rb:110:in `initialize'

Hi everyone, When try to migrate I have this error, It 's so strange .
Did you see this before? PLease help me find out this bug

I use rails 3.1.3 , ruby 1.9.2p and ,My gem file:

gem 'deface', :git => 'git://github.com/railsdog/deface.git'
....```

and error in 
```:action is invalid
/home/wf04/.rvm/gems/ruby-1.9.2-p290/bundler/gems/deface-d749e05cc971/lib/deface/override.rb:110:in `initialize'```

Thank you :D

Merging in DSL branch

Not really an "issue" so sorry to post it here, but wasn't sure how else to get in touch! :)

I just wanted to know if there is anything holding back the DSL branch from being merged into master and released as a gem? And if so, if there is anything I can do to help speed up the process, I will gladly work on any bugs/documentation if needed!

The reason I'm asking is I'm developing a gem for conditionally adding new features to a rails app (https://github.com/balvig/chili) and it's making use of features in the DSL branch but as far as I understand I can't add deface to the gemspec unless it is actually released as an official gem!

Problem with non-ERB views

It seems deface assumes an ActionView template is either ERB or HAML, but that's of course not the case. I hit the problem when trying to write a plugin for Redmine, which has its own DSL for API, used in views with the same "virtual_path" as some other html views.

I didn't find any way to tell deface to process only app/views/issues/index.html.erb but not app/views/issues/index.api.rsb for instance. Is there anything I missed ?

To be clearer, I reproduced the problem with a minimal rails app available here: https://github.com/jbbarth/defacepb

If you confirm it's a bug, I can work on it and issue you a pull request with corresponding specs.

Override edits between requests

I'm theming a Spree site with Deface. When working with Spree 1.0.3 (Rails 3.1.4) I was able to make changes to Deface overrides and have the changes show up after new http requests, without having to restart the server (in development). Now I'm on Spree 1.1.0 (Rails 3.2.3) and it seems that I need to restart the server in order to see the override. Any idea what this might be?

Support for new action 'move_{before,after}'

The following additional action would help adapt to existing stylesheets or changing the structure of a view.

In it's simplest form it could be documented like this:

Action

  • :move_before - Move element selected by parameter :from. The supplied selector is expected to select only a single element.

Optional

  • :from - A Selector specifying which element should be removed from it's original place and be inserted at the selector parameter for :move_before

I'm not exactly sure if move_before and move_after should be accompanied by move_to, and move_bottom.

Another possible API would be to add another two source types:

Source

  • :cut - A Selector specifying which elements should be removed from it's original place and be inserted at the selector pointed to in insertion actions
  • :copy - A Selector specifying which elements should be copied and be inserted at the selector pointed to in insertion actions

Thanx for this gem, btw!!!
Cheers
Simon

Broken on 1.9.3

I followed the Spree Getting Started guide using Ruby 1.9.3 and Rails 3.1.1 and in a new project the login bar defacement wasn't in effect. I believe that this is a bug in Deface and not Spree.

Apologies, but I haven't had the time to investigate this issue right now. Hopefully this GH issue will serve as a reminder to me to investigate it later if someone doesn't beat me to it first.

invalid selector can hit nil

Gets a nil in

/deface-2a1af4fc423d/lib/deface/override.rb:238:in `apply'

when .children is called without checking.

PS: latest source as of 10.9.

HAML Compatibility

Hi,

I use Spree, and they use Deface... But all my views are in HAML.

Its possible to add support of HAML to deface ?

Regards,

Deface/JRuby closes head tag leaving head elements within the body

This is similar to the behavior reported in spree/spree#2633

Test this issue with:

https://github.com/spree/spree/tree/jruby
https://github.com/spree/deface/tree/master
jruby-1.7.3

Look at the HTML source of the index page or run it through http://validator.w3.org/ to see all of the errors this generates. First few lines of the doc as a sample:

<!DOCTYPE html>
<!--[if lt IE 7 ]> <html class="ie ie6"  lang="en"> <![endif]--><!--[if IE 7 ]>    <html class="ie ie7"  lang="en"> <![endif]--><!--[if IE 8 ]>    <html class="ie ie8"  lang="en"> <![endif]--><!--[if IE 9 ]>    <html class="ie ie9"  lang="en"> <![endif]--><!--[if gt IE 9]><!--><html lang="en">
<!--<![endif]-->
<head data-hook="inside_head">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Spree Analytics has not been initialized correctly -->

</head>
<body>
<meta charset="utf-8">
<title>Spree Demo Site</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1" name="viewport">
<meta content="spree, demo" name="keywords" />
<meta content="Spree demo site" name="description" />

App/local overrides not loaded In production

Solved this one for myself, want to throw it up here for posterity's sake.

Basically if you had a manual require in your config/application.rb (or another similar Railtie configuration file) to the file(s) containing your overrides that deface already knew about, app/overrides most likely, it would get loaded twice.

This not a problem normal, but there is an edge case that makes it troublesome.

In production, or any environment set to cache classes with config.cache_classes = true as well as config.deface.enabled = false the following happens:

  1. Manual load of app/overrides
  2. rake deface:precompile is run, since we disabled it
  3. Deface clears its Environment (https://github.com/spree/deface/blob/v0.9.1/tasks/precompile.rake#L13)
  4. Deface goes through and loads each railtie's overrides, but in this case it won't be a load, it will be a require instead.

Since the app knows the file to be required already, this will return false, nothing loaded.

Deface already warns about manually requiring overrides, but it can't hurt to have this here.

Redefining overrides failed on 0.7.1 and 0.7.2

Hi, it's Matthias

After bundle upgrade which contained the new versions of deface I got the following error after rails s:

=> Booting WEBrick
=> Rails 3.1.1 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/usr/lib/ruby/gems/1.8/gems/deface-0.7.1/lib/deface/override.rb:98:in initialize': :action is invalid (ArgumentError) from /path/to/railsapp/app/overrides/test_override_without_action.rb:1:innew'
from /path/to/railsapp/app/overrides/test_override_without_action.rb:1
from /usr/lib/ruby/gems/1.8/gems/activesupport-3.1.1/lib/active_support/dependencies.rb:234:in `load'
...

using the following code:

Deface::Override.new(:virtual_path => 'existing/path',
:name => 'existing_override_name_from_extension',
:disable => true)

This error appears with existing and nonexisting override name and on deface 0.7.1 and 0.7.2

If i add an empty insert_top and empty text it works again so its not a big problem.

Thanks

Matthias

Ps: Great Gem

Recommended Practices?

Spree uses Deface, so I came here to look at your documentation. The part that puzzles me quite a bit is the recommended placement for Deface code. I can pretty much rule out placement in Controller, because it deals more with View (Plus, I like to keep controller slim). But then, where do you put such code inside the view?

So essentially the steps would be like

  1. From the controller, render a view (lets call it "foo")
  2. the "foo" view contains Deface override block which overrides another view called "bar"
  3. Finally output the view would be a combined version of "foo" and "bar"

Deface precompile fails on HAML partials

Hi,

I was really glad to see the precompile option added to deface. I use deface quite widely for Spree Commerce and the precompile would certainly give a great boost - GREAT JOB Deface Team!

However, recently I've added several haml partials rendered through deface. When I try to precompile it on server using:

bundle exec rake deface:precompile

I got an error:

uninitialized constant Deface::HamlConverter

Do you have any idea how to correct it?

Inserting markup into existing empty element

This is more of a feature request than an issue.

Is there a reason that :insert_top and :insert_bottom require there to be an already-existing element inside the target? It seems to me that if this restriction were not in place, they (or simply :insert) would be a good way of having content inserted inside an empty element. I believe that currently we have to :replace an element with itself plus its new content to achieve this.

(As an aside, I'm a new Ruby/Rails/Spree user and spent about three hours last night trying to figure out how to get Deface rules to stick. I finally figured out it was because I was using :insert_top on an empty element. :-) )

Support rails 4

@BDQ: can you please create a branch and bump dependency to rails 4.0.0.beta? 'cause I am starting to poke into making Spree fully-compatible with Rails 4.

Test failures

I was looking at working on Rails 4 compatibility, but I'm seeing a few errors like below in master. My ruby version string is "ruby 1.9.3p374 (2013-01-15 revision 38858) [x86_64-darwin10.8.0]"

  1) Deface::TemplateHelper load_template_source with overrides defined should return overridden source for partial including overrides
 Failure/Error: load_template_source("shared/post", true).should == "\n<%= \"And I've got ERB\" %>"
   expected: "\n<%= \"And I've got ERB\" %>"
        got: "\n<%= \"And I've got ERB\" %>\n" (using ==)
   Diff:
 # ./spec/deface/template_helper_spec.rb:53:in `block (4 levels) in <module:Deface>'

Do not depend on rails

because deface extensively use activesupport and actionpack, i think deface should selectively choose gem to depend on.

cant insert on correctly matched element

rake deface:test_selector['admin/products/index','table//th[@data-hook]']
Querying 'admin/products/index' for 'table//th[@data-hook]'
---------------- Match 1 ----------------

but when I attempt an insert_top or other , I get a nil exception

Request: allow several overrides per file

Hi, here is a live example:
https://github.com/spree/spree/blob/master/core/app/views/spree/address/_form.html.erb

<p class="field" id=<%="#{address_id}address2" %>>
    <%= form.label :address2, t(:street_address_2) %><br />
    <%= form.text_field :address2 %>
  </p>
  <p class="field" id=<%="#{address_id}city" %>>
    <%= form.label :city, t(:city) %><span class="required">*</span><br />
    <%= form.text_field :city, :class => 'required' %>
  </p>
  <p class="field" id=<%="#{address_id}country" %>>
    <%= form.label :country_id, t(:country) %><span class="required">*</span><br />
    <span id=<%="#{address_id}country-selection" %>>
      <%= form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %>
    </span>
  </p>

I need several overrides for this one file:

  1. Remove id=<%="#{address_id}address2" %>, I've never seen how is it used
  2. Set default country for id=<%="#{address_id}country" %>, because my aim is to custmize spree for local, not for world-wide.
    Right now two overrides in one file does'nt work. The last one only works:
#Hide 2nd address
Deface::Override.new(:virtual_path  => "spree/address/_form",
                     :remove => "p[data-erb-id='<%=\"\#{address_id}address2\" %>']",
                     :name          => "checkout_address")

#Set fixed country to Russian Federation
Deface::Override.new(:virtual_path  => "spree/address/_form",
                     :remove => "p[data-erb-id='<%=\"\#{address_id}country\" %>']",
                     :name          => "checkout_address")

I suppose that patting together all overrides declarations for one file into one file is a clean point. Make several files containing 3-5 lines of code is not good...

support action like :enclose or :wrap_with

It would be very useful to have a syntax in Deface allowing to wrap around a selector-matching element with some two-part code.
The obvious usecases:

  • wrapping with conditionals
  • wrapping with cache block (fragment cache)

Actually the second usecase would make it an awesome addition.

I have no idea for the syntax extension. How about

:text => '<% if(true) %>{original}<% end %>'

at least for now?

I don't know how hard would it be to wrap my head around Deface codebase, but in case I succeed, are you open to pull requests?

Disabling deface when initialize_on_precompile is disabled

Setting config.deface.enabled = false in the production environment config when you have initialize_on_precompile disabled in config/application.rb will cause the following error:

undefined method `deface' for #<Rails::Application::Configuration:0x007fce85dc5fe0>

My workaround is to actually add a guard like this - if config.respond_to?(:deface)

I'm guessing there's another place the config setting can be defined so that it's available without initializing?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.