emcee 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/emcee.rb +4 -4
  3. data/lib/emcee/compressors/html_compressor.rb +11 -42
  4. data/lib/emcee/helpers/{action_view/asset_tag_helper.rb → asset_tag_helper.rb} +0 -0
  5. data/lib/emcee/helpers/{action_view/asset_url_helper.rb → asset_url_helper.rb} +0 -0
  6. data/lib/emcee/helpers/{sprockets/view_helpers.rb → sprockets_helper.rb} +0 -0
  7. data/lib/emcee/loose_assets.rb +19 -0
  8. data/lib/emcee/processors/directive_processor.rb +33 -0
  9. data/lib/emcee/processors/import_processor.rb +39 -0
  10. data/lib/emcee/processors/script_processor.rb +67 -0
  11. data/lib/emcee/processors/stylesheet_processor.rb +90 -0
  12. data/lib/emcee/railtie.rb +23 -27
  13. data/lib/emcee/version.rb +1 -1
  14. data/test/compressors_test.rb +1 -1
  15. data/test/dummy/app/assets/elements/application.html +1 -0
  16. data/test/dummy/app/assets/elements/compile/test5.css.scss +5 -0
  17. data/test/dummy/app/assets/elements/compile/test5.html +2 -0
  18. data/test/dummy/log/development.log +120 -0
  19. data/test/dummy/log/test.log +20934 -0
  20. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  21. data/test/dummy/tmp/cache/assets/test/sprockets/1b8013559a887e8b8d91472ef246fef9 +0 -0
  22. data/test/dummy/tmp/cache/assets/test/sprockets/1e24025f59396708b3bb44543bed32fc +0 -0
  23. data/test/dummy/tmp/cache/assets/test/sprockets/219d0afb67879a67bae32b4fe4c708ac +0 -0
  24. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  25. data/test/dummy/tmp/cache/assets/test/sprockets/2f90dac85033dad7b068860c3f6b7b27 +0 -0
  26. data/test/dummy/tmp/cache/assets/test/sprockets/32cae461a9446107294c8a0230f5080c +0 -0
  27. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  28. data/test/dummy/tmp/cache/assets/test/sprockets/4fd1effec4d6579ba9d4f03ed156a15b +0 -0
  29. data/test/dummy/tmp/cache/assets/test/sprockets/6c9d8a21af4539e19a3462e79ac4d70c +0 -0
  30. data/test/dummy/tmp/cache/assets/test/sprockets/a69c3d00e22ad6c0d6ece35c9fd5f316 +0 -0
  31. data/test/dummy/tmp/cache/assets/test/sprockets/af6ba4ae23c6790e0f474b01ceee8dd9 +0 -0
  32. data/test/dummy/tmp/cache/assets/test/sprockets/cf517b62bd978b748afe38d5beb317de +0 -0
  33. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  34. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  35. data/test/dummy/tmp/cache/assets/test/sprockets/df6cfcc50da209231a7d9e140e5bafdc +0 -0
  36. data/test/dummy/tmp/cache/assets/test/sprockets/e0949aa3dcdcab5f8b45d30e26f6ddd2 +0 -0
  37. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  38. data/test/dummy/tmp/cache/assets/test/sprockets/ffd4adb86602a60c7fcedd5d472166d3 +0 -0
  39. data/test/{controllers_test.rb → dummy_app_integration_test.rb} +7 -4
  40. data/test/processors_test.rb +45 -11
  41. metadata +34 -12
  42. data/lib/emcee/helpers/sprockets/compressing_helpers.rb +0 -35
  43. data/lib/emcee/processors/html_processor.rb +0 -84
  44. data/lib/emcee/processors/processor_includes.rb +0 -111
  45. data/test/emcee_test.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f84512c12570cf26feb1bad8ffaf319e6c6c1ff1
4
- data.tar.gz: b472037fa77a3734c926253b8f1583ca3492e05c
3
+ metadata.gz: 8c387ce066ddbe7c70f67a78aaa1a73069136cbb
4
+ data.tar.gz: 73d6cd25ac0479920b3de9e64137faf64b6a1910
5
5
  SHA512:
6
- metadata.gz: 651de8d67870c283eacb05f1edb9d6f93b0f74fcc860fe59f0470a381c3a1f644969b451f6225657d2f66339c776c0c31ee2fa814bd20d3d71f1b9569ff177ca
7
- data.tar.gz: 82099ebba30e021ae3821d2b94b09b7b038e613962cbd7518db8b4cca40a88e92baa38efde566c6b930ea94ac47e66df90fe5f91d01021dd89806e442c54fff6
6
+ metadata.gz: cfa30497244debf49f23ba859b7d30983d524c7deec742151b6389c7afb145963e1a2071fb60ba03ddd86f9063612e162c9ed4ccee345ca1089625d13f984c5d
7
+ data.tar.gz: 7e3be5d29444812fd9443da6366fc49a39853ff40d0fb9b21f640b9ceec73279072771b6dfe1f0525bb9d48dfc9fa38b824a5ef8c98d8490b99e53df7bda8fc3
data/lib/emcee.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require "emcee/version"
2
2
 
3
- require "emcee/helpers/action_view/asset_url_helper"
4
- require "emcee/helpers/action_view/asset_tag_helper"
5
- require "emcee/helpers/sprockets/view_helpers"
6
- require "emcee/helpers/sprockets/compressing_helpers"
3
+ require "emcee/helpers/asset_url_helper"
4
+ require "emcee/helpers/asset_tag_helper"
5
+ require "emcee/helpers/sprockets_helper"
7
6
 
7
+ require "emcee/loose_assets"
8
8
  require "emcee/railtie"
@@ -1,48 +1,17 @@
1
1
  module Emcee
2
- module Compressors
3
- # HtmlCompressor is our basic implementation of an html minifier. For
4
- # sprockets to use it, it must have a compress method that only accepts a
5
- # string and returns the compressed output.
6
- #
7
- # Our implementation only strips out html and javascript comments, and
8
- # removes blank lines.
9
- #
10
- class HtmlCompressor
11
- # Match html comments.
12
- #
13
- # <!--
14
- # Comments
15
- # -->
16
- #
17
- HTML_COMMENTS = /\<!\s*--(?:.*?)(?:--\s*\>)/m
2
+ # HtmlCompressor is a very basic compressor that removes blank lines and
3
+ # comments from an HTML file.
4
+ class HtmlCompressor
5
+ HTML_COMMENTS = /\<!\s*--(?:.*?)(?:--\s*\>)/m
6
+ JS_MULTI_COMMENTS = /\/\*(?:.*?)\*\//m
7
+ JS_COMMENTS = /\/\/.*$/
8
+ BLANK_LINES = /^[\s]*$\n/
18
9
 
19
- # Match multi-line javascript/css comments.
20
- #
21
- # /*
22
- # Comments
23
- # */
24
- #
25
- JS_MULTI_COMMENTS = /\/\*(?:.*?)\*\//m
10
+ def compress(string)
11
+ ops = [HTML_COMMENTS, JS_MULTI_COMMENTS, JS_COMMENTS, BLANK_LINES]
26
12
 
27
- # Match single-line javascript comments.
28
- #
29
- # // Comments
30
- #
31
- # This does not have the /m modifier, because we only want it to match a
32
- # single line at a time.
33
- #
34
- JS_COMMENTS = /\/\/.*$/
35
-
36
- # Match blank lines.
37
- BLANK_LINES = /^[\s]*$\n/
38
-
39
- # Remove comments and blank lines from our html.
40
- def compress(string)
41
- ops = [HTML_COMMENTS, JS_MULTI_COMMENTS, JS_COMMENTS, BLANK_LINES]
42
-
43
- ops.reduce(string) do |output, op|
44
- output.gsub(op, "")
45
- end
13
+ ops.reduce(string) do |output, op|
14
+ output.gsub(op, "")
46
15
  end
47
16
  end
48
17
  end
@@ -0,0 +1,19 @@
1
+ # Monkey patch Sprockets-rails so that loose html files are handled correctly.
2
+ #
3
+ # Not sure that modifying another gem's railtie is a good idea, but it works
4
+ # for now.
5
+ module Sprockets
6
+ class Railtie
7
+ # Remove the LOOSE_APP_ASSETS constant so we can modify it without Ruby
8
+ # complaining.
9
+ remove_const(:LOOSE_APP_ASSETS) if defined?(LOOSE_APP_ASSETS)
10
+
11
+ # Add .html to the loose app assets file extensions.
12
+ LOOSE_APP_ASSETS = lambda do |filename, path|
13
+ path =~ /app\/assets/ && !%w(.js .css .html).include?(File.extname(filename))
14
+ end
15
+
16
+ # Add the .html extension to the 'precompile' regex.
17
+ config.assets.precompile = [LOOSE_APP_ASSETS, /(?:\/|\\|\A)application\.(css|js|html)$/]
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ module Emcee
2
+ # The `DirectiveProcessor` is responsible for parsing and evaluating
3
+ # directive comments in a source file.
4
+ class DirectiveProcessor < Sprockets::DirectiveProcessor
5
+ # Matches the entire header/directive block. This is everything from the
6
+ # top of the file, enclosed in html comments.
7
+ HEADER_PATTERN = /\A((?m:\s*)(<!--(?m:.*?)-->))+/
8
+
9
+ # Implement `render` so that it uses our own header pattern.
10
+ def render(context, locals)
11
+ @context = context
12
+ @pathname = context.pathname
13
+ @directory = File.dirname(@pathname)
14
+
15
+ @header = data[HEADER_PATTERN, 0] || ""
16
+ @body = $' || data
17
+ # Ensure body ends in a new line
18
+ @body += "\n" if @body != "" && @body !~ /\n\Z/m
19
+
20
+ @included_pathnames = []
21
+
22
+ @result = ""
23
+ @result.force_encoding(body.encoding)
24
+
25
+ @has_written_body = false
26
+
27
+ process_directives
28
+ process_source
29
+
30
+ @result
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ module Emcee
2
+ # ImportProcessor scans a file for html imports and adds them to the current
3
+ # required assets.
4
+ class ImportProcessor
5
+ # Match an html import tag.
6
+ #
7
+ # <link rel="import" href="assets/example.html">
8
+ #
9
+ IMPORT_PATTERN = /^\s*<link .*rel=["']import["'].*>$/
10
+
11
+ # Match the path from the href attribute of an html import or stylesheet
12
+ # include tag. Captures the actual path.
13
+ #
14
+ # href="/assets/example.css"
15
+ #
16
+ HREF_PATH_PATTERN = /href=["'](?<path>[\w\.\/-]+)["']/
17
+
18
+ def process(context, data, directory)
19
+ require_assets(context, data, directory)
20
+ remove_imports(data)
21
+ end
22
+
23
+ private
24
+
25
+ def require_assets(context, data, directory)
26
+ data.scan(IMPORT_PATTERN) do |import_tag|
27
+ path = import_tag[HREF_PATH_PATTERN, :path]
28
+ return unless path
29
+
30
+ absolute_path = File.absolute_path(path, directory)
31
+ context.require_asset(absolute_path)
32
+ end
33
+ end
34
+
35
+ def remove_imports(data)
36
+ data.gsub(IMPORT_PATTERN, "")
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,67 @@
1
+ module Emcee
2
+ # ScriptProcessor scans a document for external script references and inlines
3
+ # them into the current document.
4
+ class ScriptProcessor
5
+ # Match a script tag.
6
+ #
7
+ # <script src="assets/example.js"></script>
8
+ #
9
+ SCRIPT_PATTERN = /^\s*<script .*src=["'].+\.js["']><\/script>$/
10
+
11
+ # Match the source path from a script tag. Captures the actual path.
12
+ #
13
+ # src="/assets/example.js"
14
+ #
15
+ SRC_PATH_PATTERN = /src=["'](?<path>[\w\.\/-]+)["']/
16
+
17
+ # Match the indentation whitespace of a line
18
+ #
19
+ INDENT_PATTERN = /^(?<indent>\s*)/
20
+
21
+ def process(context, data, directory)
22
+ tags = find_tags(data)
23
+ paths = get_paths(tags)
24
+ indents = get_indents(tags)
25
+ contents = get_contents(paths, directory)
26
+ inline_scripts(data, tags, indents, contents)
27
+ end
28
+
29
+ private
30
+
31
+ def read_file(path)
32
+ File.read(path)
33
+ end
34
+
35
+ def find_tags(data)
36
+ data.scan(SCRIPT_PATTERN).map do |tag|
37
+ tag
38
+ end
39
+ end
40
+
41
+ def get_paths(tags)
42
+ tags.map do |tag|
43
+ tag[SRC_PATH_PATTERN, :path]
44
+ end
45
+ end
46
+
47
+ def get_indents(tags)
48
+ tags.map do |tag|
49
+ tag[INDENT_PATTERN, :indent] || ""
50
+ end
51
+ end
52
+
53
+ def get_contents(paths, directory)
54
+ paths.map do |path|
55
+ absolute_path = File.absolute_path(path, directory)
56
+ read_file(absolute_path)
57
+ end
58
+ end
59
+
60
+ def inline_scripts(data, tags, indents, contents)
61
+ tags.each_with_index.reduce(data) do |output, (tag, i)|
62
+ indent, content = indents[i], contents[i]
63
+ output.gsub(tag, "#{indent}<script>#{content}\n#{indent}</script>")
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,90 @@
1
+ require "sass"
2
+
3
+ module Emcee
4
+ # StylesheetProcessor scans a document for external stylesheet references and
5
+ # inlines them into the current document.
6
+ class StylesheetProcessor
7
+ # Match a stylesheet link tag.
8
+ #
9
+ # <link rel="stylesheet" href="assets/example.css">
10
+ #
11
+ STYLESHEET_PATTERN = /^\s*<link .*rel=["']stylesheet["'].*>$/
12
+
13
+ # Match the path from the href attribute of an html import or stylesheet
14
+ # include tag. Captures the actual path.
15
+ #
16
+ # href="/assets/example.css"
17
+ #
18
+ HREF_PATH_PATTERN = /href=["'](?<path>[\w\.\/-]+)["']/
19
+
20
+ # Match the indentation whitespace of a line
21
+ #
22
+ INDENT_PATTERN = /^(?<indent>\s*)/
23
+
24
+ def process(context, data, directory)
25
+ tags = find_tags(data)
26
+ paths = get_paths(tags)
27
+ indents = get_indents(tags)
28
+ contents = get_contents(paths, directory)
29
+ inline_styles(data, tags, indents, contents)
30
+ end
31
+
32
+ private
33
+
34
+ def read_file(path)
35
+ File.read(path)
36
+ end
37
+
38
+ def find_tags(data)
39
+ data.scan(STYLESHEET_PATTERN).map do |tag|
40
+ tag
41
+ end
42
+ end
43
+
44
+ def get_paths(tags)
45
+ tags.map do |tag|
46
+ tag[HREF_PATH_PATTERN, :path]
47
+ end
48
+ end
49
+
50
+ def get_indents(tags)
51
+ tags.map do |tag|
52
+ tag[INDENT_PATTERN, :indent] || ""
53
+ end
54
+ end
55
+
56
+ def get_contents(paths, directory)
57
+ paths.map do |path|
58
+ absolute_path = get_absolute_path(path, directory)
59
+ if sass?(absolute_path)
60
+ get_sass_content(absolute_path)
61
+ else
62
+ read_file(absolute_path)
63
+ end
64
+ end
65
+ end
66
+
67
+ def get_absolute_path(path, directory)
68
+ normal_path = File.absolute_path(path, directory)
69
+ sassy_path = File.absolute_path(path + ".scss", directory)
70
+ return sassy_path if File.file?(sassy_path)
71
+ normal_path
72
+ end
73
+
74
+ def get_sass_content(path)
75
+ content = read_file(path)
76
+ Sass::Engine.new(content, syntax: :scss).render
77
+ end
78
+
79
+ def sass?(path)
80
+ File.extname(path) == ".scss"
81
+ end
82
+
83
+ def inline_styles(data, tags, indents, contents)
84
+ tags.each_with_index.reduce(data) do |output, (tag, i)|
85
+ indent, content = indents[i], contents[i]
86
+ output.gsub(tag, "#{indent}<style>#{content}\n#{indent}</style>")
87
+ end
88
+ end
89
+ end
90
+ end
data/lib/emcee/railtie.rb CHANGED
@@ -1,39 +1,35 @@
1
- require "emcee/processors/html_processor"
1
+ require "emcee/processors/directive_processor"
2
+ require "emcee/processors/import_processor"
3
+ require "emcee/processors/script_processor"
4
+ require "emcee/processors/stylesheet_processor"
2
5
  require "emcee/compressors/html_compressor"
3
6
 
4
7
  module Emcee
5
8
  class Railtie < Rails::Railtie
6
- initializer :add_html_processor do |app|
9
+ initializer :add_preprocessors do |app|
7
10
  app.assets.register_mime_type "text/html", ".html"
8
- app.assets.register_preprocessor "text/html", Processors::HtmlProcessor
11
+ app.assets.register_preprocessor "text/html", DirectiveProcessor
9
12
  end
10
13
 
11
- initializer :add_html_compressor do |app|
12
- app.assets.html_compressor = Compressors::HtmlCompressor.new
14
+ initializer :add_postprocessors do |app|
15
+ app.assets.register_postprocessor "text/html", :import_processor do |context, data|
16
+ directory = File.dirname(context.pathname)
17
+ ImportProcessor.new.process(context, data, directory)
18
+ end
19
+ app.assets.register_postprocessor "text/html", :script_processor do |context, data|
20
+ directory = File.dirname(context.pathname)
21
+ ScriptProcessor.new.process(context, data, directory)
22
+ end
23
+ app.assets.register_postprocessor "text/html", :stylesheet_processor do |context, data|
24
+ directory = File.dirname(context.pathname)
25
+ StylesheetProcessor.new.process(context, data, directory)
26
+ end
13
27
  end
14
- end
15
- end
16
28
 
17
- # Monkey patch Sprockets-rails so that loose html files are handled correctly.
18
- # In the /assets/elements directory, loose html files should be compiled into
19
- # application.html. They should not be carried over as single files.
20
- #
21
- # Not sure that modifying another gem's railtie is a good idea, but it works
22
- # for now.
23
- module Sprockets
24
- class Railtie
25
- # Horrible hack: remove this 'constant' so we can redefine it without ruby
26
- # complaining.
27
- remove_const(:LOOSE_APP_ASSETS) if defined?(LOOSE_APP_ASSETS)
28
-
29
- # Ugly hack #1: redefine this 'constant' to recognize html files. Is there
30
- # a way to extend instead of redefining?
31
- LOOSE_APP_ASSETS = lambda do |filename, path|
32
- path =~ /app\/assets/ && !%w(.js .css .html).include?(File.extname(filename))
29
+ initializer :add_compressors do |app|
30
+ app.assets.register_bundle_processor "text/html", :html_compressor do |context, data|
31
+ HtmlCompressor.new.compress(data)
32
+ end
33
33
  end
34
-
35
- # Ugly hack #2: same as above (#1). Is there a way to extend this instead
36
- # of redefining?
37
- config.assets.precompile = [LOOSE_APP_ASSETS, /(?:\/|\\|\A)application\.(css|js|html)$/]
38
34
  end
39
35
  end
data/lib/emcee/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Emcee
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class CompressorsTest < ActiveSupport::TestCase
4
4
  setup do
5
- @compressor = Emcee::Compressors::HtmlCompressor.new
5
+ @compressor = Emcee::HtmlCompressor.new
6
6
  end
7
7
 
8
8
  test "compressor should remove html comments" do
@@ -6,5 +6,6 @@
6
6
  * can be referenced here using a relative path.
7
7
  *
8
8
  *= require test4
9
+ *= require compile/test5
9
10
  *= require_tree .
10
11
  -->
@@ -0,0 +1,5 @@
1
+ $color: red;
2
+
3
+ p {
4
+ color: $color;
5
+ }