emcee 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }