Skip to content

Commit

Permalink
Merge pull request #13 from yasaichi/support-sprockets4
Browse files Browse the repository at this point in the history
Support Sprockets 4
  • Loading branch information
yasaichi authored Mar 12, 2017
2 parents 198a207 + 0b1e437 commit 93df768
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ gemfile:
- gemfiles/sprockets_rails_2_with_sprockets_2.gemfile
- gemfiles/sprockets_rails_2_with_sprockets_3.gemfile
- gemfiles/sprockets_rails_3_with_sprockets_3.gemfile
- gemfiles/sprockets_rails_3_with_sprockets_4.gemfile
matrix:
exclude:
- rvm: 2.0
gemfile: gemfiles/sprockets_rails_3_with_sprockets_3.gemfile
- rvm: 2.1.9
gemfile: gemfiles/sprockets_rails_3_with_sprockets_3.gemfile
- rvm: 2.0
gemfile: gemfiles/sprockets_rails_3_with_sprockets_4.gemfile
- rvm: 2.1.9
gemfile: gemfiles/sprockets_rails_3_with_sprockets_4.gemfile
branches:
only:
- master
Expand Down
5 changes: 5 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ appraise "sprockets-rails 3 with sprockets 3" do
gem "sprockets-rails", "~> 3.0"
gem "sprockets", "~> 3.0"
end

appraise "sprockets-rails 3 with sprockets 4" do
gem "sprockets-rails", "~> 3.0"
gem "sprockets", "~> 4.0.0.beta1"
end
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ This will generate `public/404.html`.

## Template engines
Gakubuchi supports some template engines: `ERB`, `Haml` and `Slim`.
If you want to use `Haml` or `Slim`, you need to put them in your Gemfile:
When you want to use `Haml` or `Slim`, you need to put them in your Gemfile:

```ruby
# Use Haml
gem 'haml-rails'
gem 'haml'

# Use Slim
gem 'slim-rails'
gem 'slim'
```

## Using assets
Expand Down Expand Up @@ -123,7 +123,7 @@ bundle install
appraisal install

# Run RSpec with a specific combination
appraisal 'sprockets-rails 3 with sprockets 3' rspec
appraisal 'sprockets-rails 3 with sprockets 4' rspec

# Run RSpec with all combinations
appraisal rspec
Expand Down
6 changes: 4 additions & 2 deletions gakubuchi.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ Gem::Specification.new do |s|
s.description = "Gakubuchi provides a simple way to manage static pages with Asset Pipeline."
s.license = "MIT"

s.required_ruby_version = '>= 2.0.0'
s.required_ruby_version = ">= 2.0.0"
s.files = Dir["lib/**/*", "MIT-LICENSE", "Rakefile", "README.md"]

s.add_dependency "grease", "~> 0.3.0"
s.add_dependency "railties", ">= 4.0.0"
s.add_dependency "sprockets-rails", ">= 2.0.0"

Expand All @@ -28,6 +29,7 @@ Gem::Specification.new do |s|
s.add_development_dependency "rspec-rails", ">= 3.0.1"
s.add_development_dependency "rubocop"
s.add_development_dependency "simplecov"
s.add_development_dependency "slim-rails"
# TODO: Deal with the bugs on the latest version of slim-rails
s.add_development_dependency "slim-rails", "< 3.1.1"
s.add_development_dependency "sqlite3"
end
13 changes: 13 additions & 0 deletions gemfiles/sprockets_rails_3_with_sprockets_4.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "sprockets-rails", "~> 3.0"
gem "sprockets", "~> 4.0.0.beta1"

group :development, :test do
gem "pry-byebug"
gem "pry-coolline"
end

gemspec :path => "../"
1 change: 1 addition & 0 deletions lib/gakubuchi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "gakubuchi/configuration"
require "gakubuchi/error"
require "gakubuchi/fileutils"
require "gakubuchi/mime_type"
require "gakubuchi/task"
require "gakubuchi/version"

Expand Down
47 changes: 35 additions & 12 deletions lib/gakubuchi/engine_registrar.rb
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
require "active_support/inflector"
require "grease"
require "sprockets"

module Gakubuchi
class EngineRegistrar
EXTENSION_WITH_SIGLE_DOT = /\A\.[^\.]+\z/

def initialize(env)
@env = env
end

def register(target, engine)
klass = constantize(engine)
return false if !klass.instance_of?(::Class) || registered?(target)
def register(mime_type, engine_name_or_class)
engine = constantize(engine_name_or_class)
return false if !engine.instance_of?(::Class) || mime_type.extensions.empty?

args = [target, klass]
args << { silence_deprecation: true } if Sprockets::VERSION.start_with?("3")
if sprockets_major_version >= 4
register_as_transformer(mime_type, engine)
else
register_as_engine(mime_type, engine)
end

@env.register_engine(*args)
true
end

def registered?(target)
@env.engines.key?(::Sprockets::Utils.normalize_extension(target))
end

private

def constantize(klass)
klass.to_s.constantize
def constantize(constant_name)
constant_name.to_s.constantize
rescue ::LoadError, ::NameError
nil
end

def sprockets_major_version
@sprockets_major_version ||= ::Gem::Version.new(::Sprockets::VERSION).segments.first
end

def register_as_engine(mime_type, engine)
mime_type.extensions.select { |ext| ext =~ EXTENSION_WITH_SIGLE_DOT }.each do |ext|
args = [ext, engine]
args << { silence_deprecation: true } if sprockets_major_version == 3
@env.register_engine(*args)
end
end

def register_as_transformer(mime_type, engine)
content_type = mime_type.content_type

@env.register_mime_type(content_type, extensions: mime_type.extensions)
@env.register_transformer(content_type, engine.default_mime_type, ::Grease.apply(engine))
end
end
end
1 change: 1 addition & 0 deletions lib/gakubuchi/error.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Gakubuchi
class Error < StandardError
InvalidTemplate = Class.new(self)
InvalidMimeType = Class.new(self)
end
end
20 changes: 20 additions & 0 deletions lib/gakubuchi/mime_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "gakubuchi/error"
require "set"

module Gakubuchi
class MimeType
CONTENT_TYPE_FORMAT = %r(\A[^/]+/[^/]+\z)

attr_reader :content_type, :extensions

def initialize(content_type, extensions: [])
unless content_type =~ CONTENT_TYPE_FORMAT
message = %(`#{content_type}' is invalid as Content-Type)
raise ::Gakubuchi::Error::InvalidMimeType, message
end

@content_type = content_type
@extensions = ::Set.new(extensions).map(&:to_s)
end
end
end
13 changes: 11 additions & 2 deletions lib/gakubuchi/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ class Railtie < ::Rails::Railtie
config.assets.configure do |env|
engine_registrar = EngineRegistrar.new(env)

engine_registrar.register(:haml, "::Tilt::HamlTemplate")
engine_registrar.register(:slim, "::Slim::Template")
haml = ::Gakubuchi::MimeType.new("text/haml", extensions: %w(.haml .html.haml))
engine_registrar.register(haml, "Tilt::HamlTemplate")

slim = ::Gakubuchi::MimeType.new("text/slim", extensions: %w(.slim .html.slim))
engine_registrar.register(slim, "Slim::Template")
end

config.after_initialize do
# NOTE: Call #to_s for Sprockets 4 or later
templates = ::Gakubuchi::Template.all.map { |template| template.logical_path.to_s }
config.assets.precompile += templates
end

rake_tasks do
Expand Down
3 changes: 2 additions & 1 deletion lib/gakubuchi/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def destination_path
end

def digest_path
asset = assets.find_asset(logical_path)
# NOTE: Call #to_s for Sprockets 4 or later
asset = assets.find_asset(logical_path.to_s)
return if asset.nil?

::Pathname.new(::File.join(::Rails.public_path, app.config.assets.prefix, asset.digest_path))
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy/app/assets/config/manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
Empty file.
83 changes: 40 additions & 43 deletions spec/lib/gakubuchi/engine_registrar_spec.rb
Original file line number Diff line number Diff line change
@@ -1,71 +1,68 @@
require "rails_helper"

RSpec.describe Gakubuchi::EngineRegistrar do
let(:env) { Sprockets::Environment.new }
let(:engine_registrar) { described_class.new(env) }
let(:env) { Sprockets::Environment.new }

describe "#register" do
let(:described_method) { -> { engine_registrar.register(target, engine) } }
let(:described_method) { -> { engine_registrar.register(mime_type, engine) } }
let(:mime_type) { Gakubuchi::MimeType.new(content_type, extensions: extensions) }
let(:sprokcets_extensions) do
extension_type = major_version_of(Sprockets) >= 4 ? :transformers : :engines
-> { env.public_send(extension_type) }
end

context "when specified engine is an uninitialized constant" do
let(:target) { :foo }
let(:content_type) { "application/csv+ruby" }
let(:engine) { "Foo" }
let(:extensions) { %w(.rcsv .csv.ruby) }

describe "env.engines" do
subject { -> { env.engines } }
it { expect(&described_method).not_to change(&subject) }
it "should return false" do
expect(described_method.call).to eq false
end

describe "return value" do
subject { described_method.call }
it { is_expected.to eq false }
it "shouldn't register the engine for the MIME type" do
expect(&described_method).not_to change(&sprokcets_extensions)
end
end

context "when specified target is already registered" do
let(:target) { :sass }
let(:engine) { "Sprockets::SassTemplate" }
context "when there is no extensions corresponding the MIME type" do
let(:content_type) { "application/csv+ruby" }
let(:engine) { Tilt::CSVTemplate }
let(:extensions) { nil }

describe "env.engines" do
subject { -> { env.engines } }
it { expect(&described_method).not_to change(&subject) }
it "should return false" do
expect(described_method.call).to eq false
end

describe "return value" do
subject { described_method.call }
it { is_expected.to eq false }
it "shouldn't register the engine for the MIME type" do
expect(&described_method).not_to change(&sprokcets_extensions)
end
end

context "when specified target is not registered" do
let(:target) { :foo }
let(:engine) { "Sprockets::SassTemplate" }
context "when all parameters are valid" do
let(:content_type) { "application/csv+ruby" }
let(:engine) { Tilt::CSVTemplate }
let(:extensions) { %w(.rcsv .csv.ruby) }
let(:extensions_with_single_dot) { extensions.select { |ext| ext =~ /\A\.[^\.]+\z/ } }

describe "env.engines" do
subject { -> { env.engines } }
let(:expectation) { a_hash_including(".foo" => Sprockets::SassTemplate) }

it { expect(&described_method).to change(&subject).to(expectation) }
it "should return true" do
expect(described_method.call).to eq true
end

describe "return value" do
subject { described_method.call }
it { is_expected.to eq true }
end
end
end

describe "#registered?" do
subject { engine_registrar.registered?(target) }
it "should register the engine for the MIME type" do
diff =
case major_version_of(Sprockets)
when 2
Hash[extensions_with_single_dot.map { |ext| [ext, engine] }]
when 3
Hash[extensions_with_single_dot.map { |ext| [ext, an_object_responding_to(:call)] }]
when 4..Float::INFINITY
{ content_type => { engine.default_mime_type => an_object_responding_to(:call) } }
end

context "when specified target is not registered" do
let(:target) { :foo }
it { is_expected.to eq false }
end

context "when specified target is already registered" do
let(:target) { :erb }
it { is_expected.to eq true }
expect(&described_method).to change(&sprokcets_extensions).to(hash_including(diff))
end
end
end
end
49 changes: 49 additions & 0 deletions spec/lib/gakubuchi/mime_type_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require "rails_helper"

RSpec.describe Gakubuchi::MimeType do
describe "#new" do
subject { -> { described_class.new(content_type) } }

context "when an invalid `content_type` is specified" do
let(:content_type) { "foo" }
it { is_expected.to raise_error(Gakubuchi::Error::InvalidMimeType, /#{content_type}/) }
end

context "when a valid `content_type` is specified" do
let(:content_type) { "application/csv+ruby" }
it { is_expected.not_to raise_error }
end
end

describe "#content_type" do
subject { described_class.new(content_type).content_type }
let(:content_type) { "application/csv+ruby" }

it { is_expected.to eq content_type }
end

describe "#extensions" do
subject { described_class.new("application/csv+ruby", options).extensions }

context "when `extensions` isn't specified" do
let(:options) { { extensions: nil } }

it { is_expected.to be_an_instance_of(Array) }
it { is_expected.to be_empty }
end

context "when `extensions` includes duplicated values" do
let(:options) { { extensions: %w(.rcsv .csv.ruby .rcsv) } }

it { is_expected.to be_an_instance_of(Array) }
it { is_expected.to contain_exactly(*options[:extensions].uniq) }
end

context "when `extensions` includes non-string values" do
let(:options) { { extensions: %i(.rcsv .csv.ruby) } }

it { is_expected.to be_an_instance_of(Array) }
it { is_expected.to contain_exactly(*options[:extensions].map(&:to_s)) }
end
end
end
Loading

0 comments on commit 93df768

Please sign in to comment.