css-rewrite 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc776cbf9f90435b4988cf29c875cbb2ce2e691c
4
- data.tar.gz: afdc21aa137284b0242ade4d4355641b29f1718c
3
+ metadata.gz: ceec306108646763d41b4a97611cca6509506718
4
+ data.tar.gz: 67a34318674dfa93a473810229310ffbfe55adf1
5
5
  SHA512:
6
- metadata.gz: f5218b6f5ddd5be6bbc8fd333c91833d9847c35c61ea2207a72b63cd2bee5537975cde43b8efe845e14910d0054b40a3ba113f674673b8103a3626bf71a50bdb
7
- data.tar.gz: db6eb3a7cc43d1853b1d8f58663a74b935adc45bd4bc4f1981853efb3db2852eaec81f88926a45bdeac2c09a079f42929a395c816397959c58481d5aece2070e
6
+ metadata.gz: 162bf7a19c513fe517c99cdc620ac02f55aadeeb66347e38866ab2a20df7b80c67585a6c83de1177ef5bbdf9b1f1484b7f25aba1275dabe3c926b7a27c38c0dc
7
+ data.tar.gz: 6fccb97733b69087c09fd4b59fa970d4098ec2213913e83b14cefeec37523ffa9df1a517044d34e36c365dcf5f011e5371be96c5afd98f0be4436e544b367958
@@ -0,0 +1,76 @@
1
+ ## css-rewrite
2
+ Rewrite URLs in your 3rd-party CSS files using the asset pipeline.
3
+
4
+ ## Installation
5
+
6
+ `gem install css-rewrite`
7
+
8
+ or put it in your Gemfile:
9
+
10
+ ```ruby
11
+ gem 'css-rewrite'
12
+ ```
13
+
14
+ ## Rationale
15
+
16
+ Have you ever pulled a 3rd-party JavaScript or CSS library into your Rails web app? It can take some effort to get it to play nicely with the asset pipeline. You have to hunt through the tangle of potentially minified CSS to find all the URLs to images and fonts that should be using the Rails asset URL helpers. In other words, instead of this:
17
+
18
+ ```css
19
+ .some-selector {
20
+ background-image: url("puppy.png");
21
+ }
22
+ ```
23
+
24
+ you want this:
25
+
26
+ ```css
27
+ .some-selector {
28
+ background-image: image-url("puppy.png");
29
+ }
30
+ ```
31
+
32
+ Every time the author of the CSS library publishes a new version, you have to pull it down and do the hunt-and-replace thing all over again. How tedious.
33
+
34
+ That's where css-rewrite comes in. Rather than hunting for and converting URLs by hand, css-rewrite adds a post-processor to the asset pipeline that finds and replaces them for you. Whenever the file is served or precompiled, the URLs will point to the correct asset paths. No manual hunting or replacing necessary.
35
+
36
+ ### Ok I'm listening. How does it work?
37
+
38
+ Behind the scenes, css-rewrite uses the [crass gem](https://github.com/rgrove/crass) to parse and reconstitute CSS. It searches through the parse tree crass generates looking for URLs. When it finds one, it yields it to you for replacement. You (or more accurately your application) can decide what the replacement URL should be using all the power afforded to you by the Ruby programming language.
39
+
40
+ ## How 'bout some examples?
41
+
42
+ Sure! It's pretty straightforward. In an initializer (i.e. config/initializers/css_rewrite.rb), simply configure css-rewrite with a callback. Here's how you might configure it to resolve all URLs in application.css as if they were assets managed by the asset pipeline (which hopefully they are):
43
+
44
+ ```ruby
45
+ CssRewrite.configure do |config|
46
+ config.rewrite(/application\.css$/) do |url|
47
+ ActionController::Base.helpers.asset_path(url)
48
+ end
49
+ end
50
+ ```
51
+
52
+ As you can see, the callback approach is pretty flexible; it gives you direct control over the replacement value of each URL. Here's another example that only replaces image URLs:
53
+
54
+ ```ruby
55
+ CssRewrite.configure do |config|
56
+ config.rewrite(/application\.css$/) do |url|
57
+ if %w(.png .jpg .gif).include?(File.extname(url))
58
+ ActionController::Base.helpers.image_path(url)
59
+ end
60
+ end
61
+ end
62
+ ```
63
+
64
+ In this last example you'll notice that the block passed to `rewrite` can return `nil`. In such a case, css-rewrite will replace the URL with itself, i.e. won't change the URL at all. In addition, you can call `#rewrite` as many times as you want to set up different rewrite rules. When replacing URLs, css-rewrite will search through the rewriters that apply to the current file in the order they were added. The first one that returns something other than `nil` will be used for URL replacement. All the rewriters that come _after_ the matching one will be skipped. This happens on a per-URL basis.
65
+
66
+ ## Nice! What else do I need to know?
67
+
68
+ That's pretty much it. The URL replacements should happen whenever the earmarked CSS files are requested by the browser or precompiled via `rake assets:precompile`.
69
+
70
+ ## License
71
+
72
+ Licensed under the MIT license. See LICENSE for details.
73
+
74
+ ## Authors
75
+
76
+ * Cameron C. Dutro: http://github.com/camertron
@@ -1,8 +1,6 @@
1
1
  module CssRewrite
2
- autoload :CallRewriter, 'css-rewrite/call_rewriter'
3
2
  autoload :Config, 'css-rewrite/config'
4
3
  autoload :Postprocessor, 'css-rewrite/postprocessor'
5
- autoload :RegexRewriter, 'css-rewrite/regex_rewriter'
6
4
  autoload :Rewriter, 'css-rewrite/rewriter'
7
5
 
8
6
  def self.configure
@@ -10,8 +10,8 @@ module CssRewrite
10
10
 
11
11
  attr_reader :rewriters
12
12
 
13
- def rewrite(*args, &block)
14
- rewriters << Rewriter.create(*args, &block)
13
+ def rewrite(file_filter, &block)
14
+ rewriters << Rewriter.new(file_filter, &block)
15
15
  end
16
16
 
17
17
  private
@@ -4,11 +4,19 @@ module CssRewrite
4
4
  class Postprocessor
5
5
  class << self
6
6
  def run(filename, source, context)
7
+ rewriters = find_rewriters(filename)
8
+ return source if rewriters.empty?
7
9
  tree = Crass.parse(source, preserve_comments: true)
8
10
 
9
11
  replace_urls(tree) do |url|
10
- rewriter = Config.instance.rewriters.find { |re| re.matches?(url) }
11
- rewriter ? rewriter.rewrite(url, filename) : url
12
+ rewritten_url = nil
13
+
14
+ rewriters.each do |rewriter|
15
+ rewritten_url = rewriter.rewrite(url)
16
+ break if rewritten_url
17
+ end
18
+
19
+ rewritten_url || url
12
20
  end
13
21
 
14
22
  Crass::Parser.stringify(tree)
@@ -25,6 +33,12 @@ module CssRewrite
25
33
 
26
34
  private
27
35
 
36
+ def find_rewriters(filename)
37
+ Config.instance.rewriters.select do |re|
38
+ re.matches?(filename)
39
+ end
40
+ end
41
+
28
42
  def replace_urls(root, &block)
29
43
  return unless root
30
44
 
@@ -1,13 +1,27 @@
1
1
  module CssRewrite
2
2
  class Rewriter
3
- REWRITERS = [CssRewrite::RegexRewriter, CssRewrite::CallRewriter]
3
+ attr_reader :file_filter, :replacement_block
4
4
 
5
- def self.create(*args, &block)
6
- rewriter = REWRITERS.find do |rewriter|
7
- rewriter.applies_to?(*args, &block)
5
+ def initialize(file_filter, &block)
6
+ @file_filter = file_filter
7
+ @replacement_block = block
8
+ end
9
+
10
+ def matches?(filename)
11
+ case file_filter
12
+ when String
13
+ file_filter == filename
14
+ when Regexp
15
+ !!(file_filter =~ filename)
16
+ else
17
+ if file_filter.respond_to?(:call)
18
+ file_filter.call(filename)
19
+ end
8
20
  end
21
+ end
9
22
 
10
- rewriter.new(*args, &block)
23
+ def rewrite(url)
24
+ replacement_block.call(url)
11
25
  end
12
26
  end
13
27
  end
@@ -1,3 +1,3 @@
1
1
  module CssRewrite
2
- VERSION = '1.0.0'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -24,14 +24,10 @@ describe CssRewrite::Config do
24
24
  subject { described_class.instance }
25
25
 
26
26
  describe '#rewrite' do
27
- it 'adds a call rewriter to the list of rewriters' do
28
- expect { subject.rewrite {} }.to change { subject.rewriters.size }.by(1)
29
- expect(subject.rewriters.first).to be_a(CssRewrite::CallRewriter)
30
- end
31
-
32
- it 'adds a regex rewriter to the list of rewriters' do
33
- expect { subject.rewrite(/re/) {} }.to change { subject.rewriters.size }.by(1)
34
- expect(subject.rewriters.first).to be_a(CssRewrite::RegexRewriter)
27
+ it 'adds a rewriter to the list of rewriters' do
28
+ expect { subject.rewrite('application.css') {} }.to(
29
+ change { subject.rewriters.size }.by(1)
30
+ )
35
31
  end
36
32
  end
37
33
  end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe CssRewrite::Postprocessor do
4
+ describe '.run' do
5
+ before do
6
+ CssRewrite.configure do |config|
7
+ config.rewrite(/application\.css$/) { |url| nil }
8
+ end
9
+ end
10
+
11
+ let(:filename) { Rails.root.join(*%w(app assets stylesheets application.css)).to_s }
12
+ let(:source) { File.read(filename) }
13
+ let(:context) { nil }
14
+
15
+ subject { described_class.run(filename, source, context) }
16
+
17
+ it 'defaults to using the original url' do
18
+ expect(subject).to eq(source)
19
+ end
20
+
21
+ context 'with more rewriters' do
22
+ before do
23
+ CssRewrite.configure do |config|
24
+ config.rewrite(/application\.css$/) do |url|
25
+ if url.end_with?('.png')
26
+ url.gsub(/\.png/, '.foo')
27
+ end
28
+ end
29
+
30
+ config.rewrite(/application\.css$/) do |url|
31
+ if url.end_with?('.jpg')
32
+ url.gsub(/\.jpg/, '.bar')
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'stops after finding a matching rewriter' do
39
+ expect(subject).to(
40
+ eq(".my-class {\n background-image: url('foo/bar.foo');\n}\n")
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
@@ -8,7 +8,7 @@ describe 'Asset precompile' do
8
8
 
9
9
  before do
10
10
  CssRewrite.configure do |config|
11
- config.rewrite do |url, filename|
11
+ config.rewrite(/application\.css$/) do |url|
12
12
  url.chomp(File.extname(url)) + '.foo'
13
13
  end
14
14
  end
@@ -1,21 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CssRewrite::Rewriter do
4
- describe '.create' do
5
- it 'creates a call rewriter from the given args' do
6
- block = -> {}
7
- rewriter = described_class.create(&block)
8
- expect(rewriter).to be_a(CssRewrite::CallRewriter)
9
- expect(rewriter.replacement_block).to eq(block)
4
+ let(:rewriter) { described_class.new(/application\.css$/, &block) }
5
+ let(:block) { -> (url) { url.gsub(/\.png$/, '.foo') } }
6
+
7
+ describe '#matches?' do
8
+ it "returns false if the filename doesn't match" do
9
+ expect(rewriter.matches?('something.js')).to eq(false)
10
+ end
11
+
12
+ it 'returns true if the filename matches' do
13
+ expect(rewriter.matches?('application.css')).to eq(true)
10
14
  end
15
+ end
11
16
 
12
- it 'creates a regex rewriter' do
13
- block = -> {}
14
- regex = /re/
15
- rewriter = described_class.create(regex, &block)
16
- expect(rewriter).to be_a(CssRewrite::RegexRewriter)
17
- expect(rewriter.replacement_block).to eq(block)
18
- expect(rewriter.regex).to eq(regex)
17
+ describe '#rewrite' do
18
+ it 'uses the replacement block to modify the url' do
19
+ expect(rewriter.rewrite('path/to/image.png')).to eq('path/to/image.foo')
19
20
  end
20
21
  end
21
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css-rewrite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-05 00:00:00.000000000 Z
11
+ date: 2017-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sprockets
@@ -60,23 +60,21 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - Gemfile
63
+ - README.md
63
64
  - Rakefile
64
65
  - css-rewrite.gemspec
65
66
  - lib/css-rewrite.rb
66
- - lib/css-rewrite/call_rewriter.rb
67
67
  - lib/css-rewrite/config.rb
68
68
  - lib/css-rewrite/postprocessor.rb
69
69
  - lib/css-rewrite/railtie.rb
70
- - lib/css-rewrite/regex_rewriter.rb
71
70
  - lib/css-rewrite/rewriter.rb
72
71
  - lib/css-rewrite/version.rb
73
72
  - spec/app/assets/stylesheets/application.css
74
- - spec/call_rewriter_spec.rb
75
73
  - spec/config/application.rb
76
74
  - spec/config_spec.rb
77
75
  - spec/log/test.log
76
+ - spec/postprocessor_spec.rb
78
77
  - spec/precompile_spec.rb
79
- - spec/regex_rewriter_spec.rb
80
78
  - spec/rewriter_spec.rb
81
79
  - spec/spec_helper.rb
82
80
  homepage: http://github.com/camertron/css-rewrite
@@ -1,21 +0,0 @@
1
- module CssRewrite
2
- class CallRewriter
3
- def self.applies_to?(*args, &block)
4
- args.size == 0 && block.present?
5
- end
6
-
7
- attr_reader :replacement_block
8
-
9
- def initialize(&block)
10
- @replacement_block = block
11
- end
12
-
13
- def matches?(url)
14
- true
15
- end
16
-
17
- def rewrite(url, filename)
18
- replacement_block.call(url, filename)
19
- end
20
- end
21
- end
@@ -1,22 +0,0 @@
1
- module CssRewrite
2
- class RegexRewriter
3
- def self.applies_to?(*args, &block)
4
- args.size == 1 && args.first.is_a?(Regexp) && block_given?
5
- end
6
-
7
- attr_reader :regex, :replacement_block
8
-
9
- def initialize(regex, &block)
10
- @regex = regex
11
- @replacement_block = block
12
- end
13
-
14
- def matches?(url)
15
- !!(regex =~ url)
16
- end
17
-
18
- def rewrite(url, filename)
19
- replacement_block.call(url, filename)
20
- end
21
- end
22
- end
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CssRewrite::CallRewriter do
4
- describe '.applies_to?' do
5
- it 'applies if passed a block' do
6
- expect(described_class.applies_to? {}).to eq(true)
7
- end
8
-
9
- it 'does not apply if passed any arguments' do
10
- expect(described_class.applies_to?(1) {}).to eq(false)
11
- end
12
-
13
- it 'does not apply if not passed a block' do
14
- expect(described_class.applies_to?).to eq(false)
15
- end
16
- end
17
-
18
- context 'with a rewriter' do
19
- subject { described_class.new(&block) }
20
-
21
- let(:block) do
22
- # replaces the extension with ".foo"
23
- -> (url, filename) { url.chomp(File.extname(url)) + '.foo' }
24
- end
25
-
26
- describe '#matches?' do
27
- it 'always matches' do
28
- expect(subject.matches?('foo')).to eq(true)
29
- end
30
- end
31
-
32
- describe '#rewrite' do
33
- it 'invokes the replacement block' do
34
- expect(subject.rewrite('foo.com/image.jpg', 'foo.css')).to eq(
35
- 'foo.com/image.foo'
36
- )
37
- end
38
- end
39
- end
40
- end
@@ -1,44 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CssRewrite::RegexRewriter do
4
- describe '.applies_to?' do
5
- it 'applies if passed a regex and a block' do
6
- expect(described_class.applies_to?(/re/) {}).to eq(true)
7
- end
8
-
9
- it 'does not apply if passed no arguments' do
10
- expect(described_class.applies_to? {}).to eq(false)
11
- end
12
-
13
- it 'does not apply if not passed a block' do
14
- expect(described_class.applies_to?(/re/)).to eq(false)
15
- end
16
- end
17
-
18
- context 'with a rewriter' do
19
- subject { described_class.new(/.jpg\z/, &block) }
20
-
21
- let(:block) do
22
- # replaces the extension with ".foo"
23
- -> (url, filename) { url.chomp(File.extname(url)) + '.foo' }
24
- end
25
-
26
- describe '#matches?' do
27
- it 'matches if the regex matches' do
28
- expect(subject.matches?('foo.jpg')).to eq(true)
29
- end
30
-
31
- it 'does not match if the regex fails to match' do
32
- expect(subject.matches?('foo.png')).to eq(false)
33
- end
34
- end
35
-
36
- describe '#rewrite' do
37
- it 'invokes the replacement block' do
38
- expect(subject.rewrite('foo.com/image.jpg', 'foo.css')).to eq(
39
- 'foo.com/image.foo'
40
- )
41
- end
42
- end
43
- end
44
- end