web_resource_bundler 0.0.13

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 (56) hide show
  1. data/.bundle/config +2 -0
  2. data/.gitignore +21 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +10 -0
  5. data/README +118 -0
  6. data/Rakefile +29 -0
  7. data/VERSION +1 -0
  8. data/lib/web_resource_bundler.rb +195 -0
  9. data/lib/web_resource_bundler/content_management/block_data.rb +57 -0
  10. data/lib/web_resource_bundler/content_management/block_parser.rb +63 -0
  11. data/lib/web_resource_bundler/content_management/css_url_rewriter.rb +23 -0
  12. data/lib/web_resource_bundler/content_management/resource_file.rb +35 -0
  13. data/lib/web_resource_bundler/exceptions.rb +26 -0
  14. data/lib/web_resource_bundler/file_manager.rb +30 -0
  15. data/lib/web_resource_bundler/filters.rb +9 -0
  16. data/lib/web_resource_bundler/filters/base_filter.rb +28 -0
  17. data/lib/web_resource_bundler/filters/bundle_filter.rb +58 -0
  18. data/lib/web_resource_bundler/filters/bundle_filter/resource_packager.rb +49 -0
  19. data/lib/web_resource_bundler/filters/cdn_filter.rb +48 -0
  20. data/lib/web_resource_bundler/filters/image_encode_filter.rb +56 -0
  21. data/lib/web_resource_bundler/filters/image_encode_filter/css_generator.rb +85 -0
  22. data/lib/web_resource_bundler/filters/image_encode_filter/image_data.rb +51 -0
  23. data/lib/web_resource_bundler/rails_app_helpers.rb +65 -0
  24. data/lib/web_resource_bundler/settings.rb +46 -0
  25. data/lib/web_resource_bundler/web_resource_bundler_init.rb +17 -0
  26. data/spec/public/foo.css +4 -0
  27. data/spec/public/images/good.jpg +0 -0
  28. data/spec/public/images/logo.jpg +0 -0
  29. data/spec/public/images/sdfo.jpg +0 -0
  30. data/spec/public/images/too_big_image.jpg +0 -0
  31. data/spec/public/marketing.js +14 -0
  32. data/spec/public/salog20.js +6 -0
  33. data/spec/public/sample.css +6 -0
  34. data/spec/public/seal.js +10 -0
  35. data/spec/public/set_cookies.js +8 -0
  36. data/spec/public/styles/boo.css +4 -0
  37. data/spec/public/styles/for_import.css +7 -0
  38. data/spec/public/temp.css +1 -0
  39. data/spec/public/test.css +2 -0
  40. data/spec/sample_block_helper.rb +81 -0
  41. data/spec/spec_helper.rb +82 -0
  42. data/spec/web_resource_bundler/content_management/block_data_spec.rb +33 -0
  43. data/spec/web_resource_bundler/content_management/block_parser_spec.rb +100 -0
  44. data/spec/web_resource_bundler/content_management/css_url_rewriter_spec.rb +27 -0
  45. data/spec/web_resource_bundler/content_management/resource_file_spec.rb +37 -0
  46. data/spec/web_resource_bundler/file_manager_spec.rb +60 -0
  47. data/spec/web_resource_bundler/filters/bundle_filter/filter_spec.rb +40 -0
  48. data/spec/web_resource_bundler/filters/bundle_filter/resource_packager_spec.rb +41 -0
  49. data/spec/web_resource_bundler/filters/cdn_filter_spec.rb +76 -0
  50. data/spec/web_resource_bundler/filters/image_encode_filter/css_generator_spec.rb +104 -0
  51. data/spec/web_resource_bundler/filters/image_encode_filter/filter_spec.rb +73 -0
  52. data/spec/web_resource_bundler/filters/image_encode_filter/image_data_spec.rb +53 -0
  53. data/spec/web_resource_bundler/settings_spec.rb +45 -0
  54. data/spec/web_resource_bundler/web_resource_bundler_spec.rb +90 -0
  55. data/web_resource_bundler.gemspec +111 -0
  56. metadata +146 -0
@@ -0,0 +1,51 @@
1
+ require 'base64'
2
+ module WebResourceBundler
3
+ module Filters
4
+ module ImageEncodeFilter
5
+ #ImageData contains info about image found in css files
6
+ class ImageData
7
+ MAX_RAND_FOR_ID = 10000
8
+ attr_reader :extension, :id, :path, :exist, :url
9
+
10
+ def initialize(url, folder)
11
+ @url = url
12
+ #computing absolute file path using folder of css file
13
+ @path = File.join(folder, url)
14
+ if File.file?(@path)
15
+ @exist = true
16
+ else
17
+ @exist = false
18
+ end
19
+ if WebResourceBundler::Bundler.logger and !@path.include?('://') and !@exist
20
+ WebResourceBundler::Bundler.logger.info("Image not found #{@path}")
21
+ end
22
+ if @exist
23
+ @size = File.size(@path)
24
+ name, @extension = File.basename(@path).split('.')
25
+ #id is a filename plus random number - to support uniqueness
26
+ @id = name + rand(MAX_RAND_FOR_ID).to_s
27
+ end
28
+ end
29
+
30
+ def size
31
+ @size / 1024
32
+ end
33
+
34
+ #constructs part of css header with data for current image
35
+ def construct_mhtml_image_data(separator)
36
+ if @exist
37
+ result = separator + "\n"
38
+ result += "Content-Location:" + @id + "\n"
39
+ result += "Content-Transfer-Encoding:base64" + "\n\n"
40
+ result += encoded + "\n\n"
41
+ end
42
+ end
43
+
44
+ def encoded
45
+ return nil unless @exist
46
+ Base64.encode64(File.read(@path)).gsub("\n", '')
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,65 @@
1
+ module WebResourceBundler::RailsAppHelpers
2
+
3
+ def web_resource_bundler_process(&block)
4
+ #getting ActionView::NonConcattingString
5
+ #but we want simple string to escape problems
6
+ result = String.new(capture(&block))
7
+ #result is original block content by default
8
+ version = Rails::VERSION::STRING
9
+ if !params['no_bundler'] and WebResourceBundler::Bundler.instance.settings_correct
10
+ #we want to keep original string unchanged so we can return same content on error
11
+ block_data = WebResourceBundler::Bundler.instance.process(result.dup)
12
+ #if everything ok with bundling we should construct resulted html content and change result
13
+ result = construct_block(block_data, WebResourceBundler::Bundler.instance.settings) if block_data
14
+ end
15
+ case
16
+ when version >= '3.0.0' then return raw(result)
17
+ when (version >= '2.2.0' and version < '2.4.0') then concat(result)
18
+ else
19
+ concat(result, block.binding)
20
+ end
21
+ end
22
+
23
+ def construct_block(block_data, settings)
24
+ result = ""
25
+ #we should include only mhtml files if browser IE 7 or 6
26
+ if mhtml_should_be_added?
27
+ styles = block_data.files.select {|f| [WebResourceBundler::ResourceFileType::MHTML, WebResourceBundler::ResourceFileType::IE_CSS].include?(f.type)}
28
+ else
29
+ #it normal browser - so just including base64 css
30
+ styles = block_data.files.select {|f| f.type == WebResourceBundler::ResourceFileType::CSS}
31
+ end
32
+ styles.each do |file|
33
+ url = File.join('/', file.path)
34
+ result << stylesheet_link_tag(url)
35
+ result << "\n"
36
+ end
37
+ block_data.scripts.each do |file|
38
+ url = File.join('/', file.path)
39
+ result << javascript_include_tag(url)
40
+ result << "\n"
41
+ end
42
+ result << block_data.inline_block unless block_data.inline_block.blank?
43
+ block_data.child_blocks.each do |block|
44
+ result << construct_block(block, settings)
45
+ end
46
+ unless block_data.condition.empty?
47
+ result = "<!--#{block_data.condition}>\n #{result}<![endif]-->\n"
48
+ end
49
+ #removing unnecessary new line symbols
50
+ result.gsub!(/\n(\s)+/, "\n")
51
+ result
52
+ end
53
+
54
+ def mhtml_should_be_added?
55
+ result = false
56
+ pattern = /MSIE (.*?);/
57
+ header = request.headers['HTTP_USER_AGENT']
58
+ match = pattern.match(header)
59
+ if match and match[1] <= '7.0'
60
+ result = true
61
+ end
62
+ return result
63
+ end
64
+
65
+ end
@@ -0,0 +1,46 @@
1
+ module WebResourceBundler
2
+ class Settings
3
+ @@defaults = {
4
+ :cache_dir => 'cache',
5
+ :base64_filter => {
6
+ :max_image_size => 23, #kbytes
7
+ :protocol => 'http',
8
+ :domain => 'localhost:3000'
9
+ },
10
+ :bundle_filter => {
11
+ :md5_additional_data => []
12
+ },
13
+ :cdn_filter => {
14
+ :http_hosts => ['http://localhost:3000'],
15
+ :https_hosts => ['https://localhost:3000']
16
+ }
17
+ }
18
+
19
+ def initialize(hash = {})
20
+ @settings = hash
21
+ end
22
+
23
+ def set(hash)
24
+ @settings.merge!(hash)
25
+ end
26
+
27
+ def [](i)
28
+ @settings[i]
29
+ end
30
+
31
+ def []=(i , v)
32
+ @settings[i] = v
33
+ end
34
+
35
+ def method_missing(m, *args, &block)
36
+ m=m.to_s
37
+ if /.*=\z/.match(m)
38
+ @settings[m[0..-2].to_sym] = args[0]
39
+ else
40
+ @settings[m.to_sym]
41
+ end
42
+ end
43
+
44
+
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ require 'web_resource_bundler'
2
+ require 'yaml'
3
+ root_dir = Rails.root #or RAILS_ROOT if you are using older rails version than 3
4
+ environment = Rails.env
5
+ settings = { }
6
+ settings_file_path = File.join(root_dir,'config', 'web_resource_bundler.yml')
7
+ if File.exist?(settings_file_path)
8
+ settings_file = File.open(settings_file_path)
9
+ all_settings = YAML::load(settings_file)
10
+ if all_settings[environment]
11
+ settings = all_settings[environment]
12
+ settings[:resource_dir] = File.join(root_dir, 'public')
13
+ end
14
+ end
15
+
16
+ WebResourceBundler::Bundler.instance.set_settings(settings)
17
+ ActionView::Base.send(:include, WebResourceBundler::RailsAppHelpers)
@@ -0,0 +1,4 @@
1
+ div {
2
+ margin-top: 10px;
3
+ }
4
+ h1 { font-family: sans-serif }
Binary file
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ function loadScript(scriptURL) {
2
+ var newScript = document.createElement("script");
3
+ newScript.src = scriptURL;
4
+ document.body.appendChild(newScript);
5
+ }
6
+
7
+ function setCookie (name, value, expires, path, domain, secure) {
8
+ var rateCookie = name + "=" + escape(value) +
9
+ ((expires) ? "; expires=" + expires.toGMTString() : "") +
10
+ ((path) ? "; path=" + path : "") +
11
+ ((domain) ? "; domain=" + domain : "") +
12
+ ((secure) ? "; secure" : "");
13
+ document.cookie = rateCookie;
14
+ }
@@ -0,0 +1,6 @@
1
+ window.onload = function() {
2
+ var linkWithAlert = document.getElementById("alertLink");
3
+ linkWithAlert.onclick = function() {
4
+ return confirm('Are you sure?');
5
+ };
6
+ };
@@ -0,0 +1,6 @@
1
+ .temp{margin:1px;background-image
2
+ : url( 'images/logo.jpg' ) ;width:300px ;} .sdg{padding:10px;background-image : url('images/logo.jpg');}
3
+ .fas{
4
+ margin: 10px;
5
+ background-image: url("images/good.jpg");
6
+ }
@@ -0,0 +1,10 @@
1
+ function fixPopupInIE() {
2
+ var style = document.createElement('style');
3
+ style.setAttribute("type", "text/css");
4
+ document.body.appendChild(style);
5
+
6
+ document.getElementById('wrapper').style.position = 'absolute';
7
+ document.getElementById('shadow').style.position = 'absolute';
8
+ document.getElementById('container').style.position = 'absolute';
9
+ document.getElementById('popup-loading').style.position = 'absolute';
10
+ }
@@ -0,0 +1,8 @@
1
+ function MyClass()
2
+ {
3
+ this.myValue1 = 1;
4
+ this.myValue2 = 2;
5
+ }
6
+
7
+ var mc = new MyClass();
8
+ mc.myValue1 = mc.myValue2 * 2;
@@ -0,0 +1,4 @@
1
+ .funky_class
2
+ {
3
+ background-image: url("../images/logo.jpg");
4
+ }
@@ -0,0 +1,7 @@
1
+ .test
2
+ {
3
+ background-color:Black;
4
+ width: 200px;
5
+ height :300px;
6
+ margin:100px;
7
+ }
@@ -0,0 +1 @@
1
+ background: url('./images/1.png');background-image: url('./images/1.png');
@@ -0,0 +1,2 @@
1
+ @import 'styles/for_import.css';
2
+ background: url('http://boogle.com/images/1.png');background-image: url('http://boogle.com/images/1.png');
@@ -0,0 +1,81 @@
1
+ class SampleBlockHelper
2
+ def initialize(styles, scripts, settings)
3
+ @styles = styles
4
+ @scripts = scripts
5
+ @settings = settings
6
+ end
7
+
8
+ def construct_js_link(path)
9
+ "<script src = \"#{path}\" type=\"text/javascript\"></script>"
10
+ end
11
+
12
+ def construct_css_link(path)
13
+ "<link href = \"#{path}\" media=\"screen\" rel=\"Stylesheet\" type=\"text/css\" />"
14
+ end
15
+
16
+ def sample_inline_block
17
+ "this is inline block content" +
18
+ "<script>abracadabra</script><style>abracadabra</style>"
19
+ end
20
+
21
+ def construct_links_block(styles, scripts)
22
+ block = ""
23
+ styles.each do |path|
24
+ block += construct_css_link(path)
25
+ end
26
+ scripts.each do |path|
27
+ block += construct_js_link(path)
28
+ end
29
+ block
30
+ end
31
+
32
+ def construct_resource_file(type, file, content = nil)
33
+ resource_file = WebResourceBundler::ResourceFile.new(type, file)
34
+ if content
35
+ resource_file.content = content
36
+ else
37
+ resource_file.content = File.read(File.join(@settings.resource_dir, file))
38
+ end
39
+ resource_file
40
+ end
41
+
42
+ def sample_cond_block
43
+ "<!-- [if IE 7] >" +
44
+ construct_links_block(@styles[(@styles.size / 2)..-1], @scripts[(@scripts.size / 2)..-1]) +
45
+ sample_inline_block +
46
+ "<! [endif] -->"
47
+ end
48
+
49
+ def sample_block
50
+ block = construct_links_block(@styles[0..(@styles.size / 2 - 1)], @scripts[0..(@scripts.size / 2 - 1)]) + "\n"
51
+ block += sample_inline_block
52
+ block += sample_cond_block
53
+ end
54
+
55
+ def sample_block_data
56
+ data = BlockData.new
57
+ @styles[0..(@styles.size / 2 - 1)].each do |file|
58
+ data.files << construct_resource_file(ResourceFileType::CSS, file)
59
+ end
60
+ @scripts[0..(@scripts.size / 2 - 1)].each do |file|
61
+ data.files << construct_resource_file(ResourceFileType::JS, file)
62
+ end
63
+ data.inline_block = sample_inline_block
64
+ data.child_blocks << child_block_data
65
+ data
66
+ end
67
+
68
+ def child_block_data
69
+ child = BlockData.new("[if IE 7]")
70
+ @styles[(@styles.size / 2)..(@styles.size - 1)].each do |file|
71
+ child.files << construct_resource_file(ResourceFileType::CSS, file)
72
+ end
73
+ @scripts[(@scripts.size / 2)..(@scripts.size - 1)].each do |file|
74
+ child.files << construct_resource_file(ResourceFileType::JS, file)
75
+ end
76
+ child.inline_block = sample_inline_block
77
+ child
78
+ end
79
+
80
+ end
81
+
@@ -0,0 +1,82 @@
1
+ #require 'simplecov'
2
+ #SimpleCov.start
3
+ require File.join(File.dirname(__FILE__), "../lib/web_resource_bundler")
4
+ require 'fileutils'
5
+ require File.join(File.dirname(__FILE__), 'sample_block_helper')
6
+ require 'logger'
7
+ include WebResourceBundler
8
+
9
+ def clean_cache_dir
10
+ cache_dir_path = File.join(File.dirname(__FILE__), '/public/cache')
11
+ FileUtils.rm_rf(cache_dir_path) if File.exist?(cache_dir_path)
12
+ end
13
+
14
+ def styles
15
+ ["/sample.css","/foo.css", "/test.css", "/styles/boo.css"]
16
+ end
17
+
18
+ def scripts
19
+ ["/set_cookies.js", "/seal.js", "/salog20.js", "/marketing.js"]
20
+ end
21
+
22
+ def settings
23
+ Settings.new(settings_hash)
24
+ end
25
+
26
+ def settings_hash
27
+ {
28
+ :resource_dir => File.join(File.dirname(__FILE__), '/public'),
29
+ :cache_dir => 'cache',
30
+ :log_path => File.join(File.dirname(__FILE__), '/bundler.log'),
31
+ :base64_filter => {
32
+ :use => true,
33
+ :max_image_size => 23, #kbytes
34
+ :protocol => 'http',
35
+ :domain => 'localhost:3000'
36
+ },
37
+ :bundle_filter => {
38
+ :use => true,
39
+ :md5_additional_data => ['localhost:3000', 'http'],
40
+ :filename_additional_data => ['en']
41
+ },
42
+ :cdn_filter => {
43
+ :use => true,
44
+ :http_hosts => ['http://localhost:3000'],
45
+ :https_hosts => ['https://localhost:3000']
46
+ }
47
+ }
48
+ end
49
+
50
+ def bundle_settings
51
+ settings.bundle_filter.merge(common_settings)
52
+ end
53
+
54
+ def cdn_settings
55
+ settings.cdn_filter.merge(common_settings)
56
+ end
57
+
58
+ def base64_settings
59
+ settings.base64_filter.merge(common_settings)
60
+ end
61
+
62
+ def common_settings
63
+ {:resource_dir => settings.resource_dir, :cache_dir => settings.cache_dir}
64
+ end
65
+
66
+
67
+ Spec::Runner.configure do |config|
68
+ config.before(:all) do
69
+ config.mock_with :rspec
70
+ end
71
+ config.before(:all) do
72
+ @sample_block_helper = SampleBlockHelper.new(styles, scripts, settings)
73
+ @logger = Logger.new(STDOUT)
74
+ end
75
+
76
+ config.after(:all) do
77
+ File.delete(settings.log_path) if File.exist?(settings.log_path)
78
+ log_path = File.expand_path('../log', settings.resource_dir)
79
+ FileUtils.rm_rf(log_path) if File.exist?(log_path)
80
+ clean_cache_dir
81
+ end
82
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "../../spec_helper"))
2
+ describe WebResourceBundler::BlockData do
3
+ describe "#apply_filter" do
4
+ it "applies filter to block_data, its childs, and theirs childs etc." do
5
+ filter = mock("filter")
6
+ block_data = @sample_block_helper.sample_block_data
7
+ filter.should_receive(:apply!).with(block_data)
8
+ filter.should_receive(:apply!).with(block_data.child_blocks.first)
9
+ filters = [filter]
10
+ block_data.apply_filters(filters)
11
+ end
12
+ end
13
+
14
+ describe "#all_childs" do
15
+ it "creates array of block data and all its childs recursively" do
16
+ block_data = @sample_block_helper.sample_block_data
17
+ BlockData.all_childs(block_data).size.should == 2
18
+ end
19
+ end
20
+
21
+ describe "#clone" do
22
+ it "creates deep clone of block data" do
23
+ block_data = @sample_block_helper.sample_block_data
24
+ clon = block_data.clone
25
+ block_data.object_id.should_not == clon.object_id
26
+ ((block_data.files.map { |f| f.object_id })& clon.files.map {|f| f.object_id}).should be_empty
27
+ child = block_data.child_blocks[0]
28
+ child_copy = clon.child_blocks[0]
29
+ child.object_id.should_not == child_copy.object_id
30
+ ((child.files.map { |f| f.object_id }) & child_copy.files.map {|f| f.object_id}).should be_empty
31
+ end
32
+ end
33
+ end