Skip to content

Commit

Permalink
Sprockets 4 support
Browse files Browse the repository at this point in the history
  • Loading branch information
tjgrathwell committed Dec 19, 2015
1 parent 53443fa commit b08c93c
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 247 deletions.
2 changes: 1 addition & 1 deletion handlebars_assets.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency "execjs", "~> 2.0"
s.add_runtime_dependency "tilt", "~> 1.2"
s.add_runtime_dependency "multi_json", "~> 1.0"
s.add_runtime_dependency "sprockets", ">= 2.0.0", "< 4.0"
s.add_runtime_dependency "sprockets", ">= 2.0.0"

s.add_development_dependency "minitest", '~> 5.5'
s.add_development_dependency "haml", '~> 4.0'
Expand Down
8 changes: 8 additions & 0 deletions lib/handlebars_assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module HandlebarsAssets
autoload(:Config, 'handlebars_assets/config')
autoload(:Handlebars, 'handlebars_assets/handlebars')
autoload(:HandlebarsTemplate, 'handlebars_assets/handlebars_template')
autoload(:HandlebarsProcessor, 'handlebars_assets/handlebars_template')

PATH = File.expand_path('../../vendor/assets/javascripts', __FILE__)

Expand Down Expand Up @@ -31,6 +32,13 @@ def self.register_extensions(sprockets_environment)
end
end

def self.register_transformers(config)
config.assets.configure do |env|
env.register_mime_type 'text/x-handlebars-template', extensions: Config.handlebars_extensions
env.register_transformer 'text/x-handlebars-template', 'application/javascript', HandlebarsProcessor
end
end

def self.add_to_asset_versioning(sprockets_environment)
sprockets_environment.config.version += "-#{HandlebarsAssets::VERSION}"
end
Expand Down
9 changes: 7 additions & 2 deletions lib/handlebars_assets/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ module HandlebarsAssets
# NOTE: must be an engine because we are including assets in the gem
class Engine < ::Rails::Engine
initializer "handlebars_assets.assets.register", :group => :all do |app|
::HandlebarsAssets::register_extensions(app.assets)
app.assets.version += "#{::HandlebarsAssets::VERSION}"
if Gem::Version.new(Sprockets::VERSION) < Gem::Version.new('4')
::HandlebarsAssets::register_extensions(app.assets)
app.assets.version += "#{::HandlebarsAssets::VERSION}"
else
::HandlebarsAssets::register_transformers(config)
config.assets.version += "#{::HandlebarsAssets::VERSION}"
end
end
end
end
85 changes: 65 additions & 20 deletions lib/handlebars_assets/handlebars_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,63 @@ def unindent(heredoc)
end
end

# Sprockets <= 3
class HandlebarsTemplate < Tilt::Template

include Unindent

def self.default_mime_type
'application/javascript'
end

def initialize_engine
HandleHelper.initialize_engine
end

def prepare
@template_path = HandleHelper::TemplatePath.new(@file)
@engine = helper.choose_engine(data)
end

def evaluate(scope, locals, &block)
source =
if @engine
@engine.render(scope, locals, &block)
else
data
end

helper.compile(source)
end

private

def helper
@helper ||= HandleHelper.new(path: @file)
end
end

# Sprockets 4
class HandlebarsProcessor
def self.call(input)
HandleHelper.initialize_engine

hh = HandleHelper.new(path: input[:filename])

template_string = input[:data]

engine = hh.choose_engine(template_string)
if engine
hh.compile(engine.render)
else
hh.compile(template_string)
end
end
end

class HandleHelper
include Unindent

def self.initialize_engine
return if @initialized

begin
require 'haml'
rescue LoadError
Expand All @@ -31,28 +79,25 @@ def initialize_engine
rescue LoadError
# slim not available
end

@initialized = true
end

def prepare
@template_path = TemplatePath.new(@file)
@engine =
if @template_path.is_haml?
Haml::Engine.new(data, HandlebarsAssets::Config.haml_options)
elsif @template_path.is_slim?
Slim::Template.new(HandlebarsAssets::Config.slim_options) { data }
else
nil
end
def initialize(options)
@template_path = TemplatePath.new(options[:path])
end

def evaluate(scope, locals, &block)
source =
if @engine
@engine.render(scope, locals, &block)
else
data
end
def choose_engine(data)
if @template_path.is_haml?
Haml::Engine.new(data, HandlebarsAssets::Config.haml_options)
elsif @template_path.is_slim?
Slim::Template.new(HandlebarsAssets::Config.slim_options) { data }
else
nil
end
end

def compile(source)
# remove trailing \n on file, for some reason the directives pipeline adds this
source.chomp!($/)

Expand Down
17 changes: 17 additions & 0 deletions test/handlebars_assets/handlebars_processor_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'test_helper'
require_relative 'shared/adapter_tests'

module HandlebarsAssets
class HandlebarsProcessorTest < Minitest::Test
include AdapterTests

def teardown
HandlebarsAssets::Config.reset!
HandlebarsAssets::Handlebars.reset!
end

def render_it(scope, source)
HandlebarsAssets::HandlebarsProcessor.call(filename: scope.pathname.to_s, data: source)
end
end
end
199 changes: 199 additions & 0 deletions test/handlebars_assets/shared/adapter_tests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
require 'test_helper'
require 'haml'
require 'slim'

module AdapterTests
include CompilerSupport
include SprocketsScope

def compile_haml(source)
::Haml::Engine.new(source, HandlebarsAssets::Config.haml_options).render
end

def compile_slim(source)
::Slim::Template.new(HandlebarsAssets::Config.slim_options) { source }.render
end

def test_render
root = '/myapp/app/assets/templates'
file = 'test_render.hbs'
scope = make_scope root, file
source = "This is {{handlebars}}"

assert_equal hbs_compiled('test_render', source), render_it(scope, source)
end

# Sprockets does not add nested root paths (i.e.
# app/assets/javascripts/templates is rooted at app/assets/javascripts)
def test_template_misnaming
root = '/myapp/app/assets/javascripts'
file = 'templates/test_template_misnaming.hbs'
scope = make_scope root, file
source = "This is {{handlebars}}"

assert_equal hbs_compiled('test_template_misnaming', source), render_it(scope, source)
end

def test_path_prefix
root = '/myapp/app/assets/javascripts'
file = 'app/templates/test_path_prefix.hbs'
scope = make_scope root, file
source = "This is {{handlebars}}"

HandlebarsAssets::Config.path_prefix = 'app/templates'

assert_equal hbs_compiled('test_path_prefix', source), render_it(scope, source)
end

def test_underscore_partials
root = '/myapp/app/assets/javascripts'
file1 = 'app/templates/_test_underscore.hbs'
scope1 = make_scope root, file1
file2 = 'app/templates/some/thing/_test_underscore.hbs'
scope2 = make_scope root, file2
source = "This is {{handlebars}}"

HandlebarsAssets::Config.path_prefix = 'app/templates'

assert_equal hbs_compiled_partial('_test_underscore', source), render_it(scope1, source)

assert_equal hbs_compiled_partial('some/thing/_test_underscore', source), render_it(scope2, source)
end

def test_chomped_underscore_partials
assert_equal HandlebarsAssets::Config.chomp_underscore_for_partials?, false

HandlebarsAssets::Config.chomp_underscore_for_partials = true
assert_equal HandlebarsAssets::Config.chomp_underscore_for_partials?, true

root = '/myapp/app/assets/javascripts'
file1 = 'app/templates/_test_underscore.hbs'
scope1 = make_scope root, file1
file2 = 'app/templates/some/thing/_test_underscore.hbs'
scope2 = make_scope root, file2
source = "This is {{handlebars}}"

HandlebarsAssets::Config.path_prefix = 'app/templates'

assert_equal hbs_compiled_partial('test_underscore', source), render_it(scope1, source)

assert_equal hbs_compiled_partial('some/thing/test_underscore', source), render_it(scope2, source)

end

def test_without_known_helpers_opt
root = '/myapp/app/assets/templates'
file = 'test_without_known.hbs'
scope = make_scope root, file
source = "{{#with author}}By {{first_name}} {{last_name}}{{/with}}"

assert_equal hbs_compiled('test_without_known', source), render_it(scope, source)
end

def test_known_helpers_opt
root = '/myapp/app/assets/templates'
file = 'test_known.hbs'
scope = make_scope root, file
source = "{{#with author}}By {{first_name}} {{last_name}}{{/with}}"

HandlebarsAssets::Config.known_helpers_only = true

assert_equal hbs_compiled('test_known', source), render_it(scope, source)
end

def test_with_custom_helpers
root = '/myapp/app/assets/templates'
file = 'test_custom_helper.hbs'
scope = make_scope root, file
source = "{{#custom author}}By {{first_name}} {{last_name}}{{/custom}}"

assert_equal hbs_compiled('test_custom_helper', source), render_it(scope, source)
end

def test_with_custom_known_helpers
root = '/myapp/app/assets/templates'
file = 'test_custom_known_helper.hbs'
scope = make_scope root, file
source = "{{#custom author}}By {{first_name}} {{last_name}}{{/custom}}"

HandlebarsAssets::Config.known_helpers_only = true
HandlebarsAssets::Config.known_helpers = %w(custom)

assert_equal hbs_compiled('test_custom_known_helper', source), render_it(scope, source)
end

def test_template_namespace
root = '/myapp/app/assets/javascripts/templates'
file = 'test_template_namespace.hbs'
scope = make_scope root, file
source = "This is {{handlebars}}"

HandlebarsAssets::Config.template_namespace = 'JST'

assert_equal hbs_compiled('test_template_namespace', source), render_it(scope, source)
end

def test_ember_render
root = '/myapp/app/assets/templates'
file = 'test_render.hbs'
scope = make_scope root, file
source = "This is {{handlebars}}"

HandlebarsAssets::Config.ember = true
HandlebarsAssets::Config.multiple_frameworks = false

expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("This is {{handlebars}}");};
assert_equal expected_compiled, render_it(scope, source)
end

def test_multiple_frameworks_with_ember_render
root = '/myapp/app/assets/templates'
non_ember = 'test_render.hbs'
non_ember_but_with_ember = 'test_member.hbs'
ember_ext_no_hbs = 'test_render.ember'
ember_ext = 'test_render.ember.hbs'
ember_with_haml = 'test_render.ember.hamlbars'
ember_with_slim = 'test_render.ember.slimbars'
ember_ext_with_erb = 'test_render.ember.hbs.erb'

HandlebarsAssets::Config.ember = true
HandlebarsAssets::Config.multiple_frameworks = true

# File without ember extension should compile to default namespace
scope = make_scope root, non_ember
source = "This is {{handlebars}}"
assert_equal hbs_compiled('test_render', source), render_it(scope, source)

# File without ember extension but with ember in it should compile to default namespace
scope = make_scope root, non_ember_but_with_ember
source = "This is {{handlebars}}"
assert_equal hbs_compiled('test_member', source), render_it(scope, source)

# File with ember extension should compile to ember specific namespace
expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("This is {{handlebars}}");};
scope = make_scope root, ember_ext_no_hbs
assert_equal expected_compiled, render_it(scope, source)

# File with ember and erb extension should compile to ember specific namespace
expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("This is {{handlebars}}");};
scope = make_scope root, ember_ext_with_erb
assert_equal expected_compiled, render_it(scope, source)

# File with ember.hbs extension should compile to ember specific namespace
expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("This is {{handlebars}}");};
scope = make_scope root, ember_ext
assert_equal expected_compiled, render_it(scope, source)

# File with ember.hamlbars extension should compile to ember specific namespace
expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("<p>This is {{handlebars}}</p>");};
scope = make_scope root, ember_with_haml
source = "%p This is {{handlebars}}"
assert_equal expected_compiled, render_it(scope, source)

# File with ember.slimbars extension should compile to ember specific namespace
expected_compiled = %{window.Ember.TEMPLATES["test_render"] = Ember.Handlebars.compile("<p>This is {{handlebars}}</p>");};
source = "p This is {{handlebars}}"
scope = make_scope root, ember_with_slim
assert_equal expected_compiled, render_it(scope, source)
end
end
Loading

0 comments on commit b08c93c

Please sign in to comment.