web_resource_bundler 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
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