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.
- data/.bundle/config +2 -0
- data/.gitignore +21 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +10 -0
- data/README +118 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/lib/web_resource_bundler.rb +195 -0
- data/lib/web_resource_bundler/content_management/block_data.rb +57 -0
- data/lib/web_resource_bundler/content_management/block_parser.rb +63 -0
- data/lib/web_resource_bundler/content_management/css_url_rewriter.rb +23 -0
- data/lib/web_resource_bundler/content_management/resource_file.rb +35 -0
- data/lib/web_resource_bundler/exceptions.rb +26 -0
- data/lib/web_resource_bundler/file_manager.rb +30 -0
- data/lib/web_resource_bundler/filters.rb +9 -0
- data/lib/web_resource_bundler/filters/base_filter.rb +28 -0
- data/lib/web_resource_bundler/filters/bundle_filter.rb +58 -0
- data/lib/web_resource_bundler/filters/bundle_filter/resource_packager.rb +49 -0
- data/lib/web_resource_bundler/filters/cdn_filter.rb +48 -0
- data/lib/web_resource_bundler/filters/image_encode_filter.rb +56 -0
- data/lib/web_resource_bundler/filters/image_encode_filter/css_generator.rb +85 -0
- data/lib/web_resource_bundler/filters/image_encode_filter/image_data.rb +51 -0
- data/lib/web_resource_bundler/rails_app_helpers.rb +65 -0
- data/lib/web_resource_bundler/settings.rb +46 -0
- data/lib/web_resource_bundler/web_resource_bundler_init.rb +17 -0
- data/spec/public/foo.css +4 -0
- data/spec/public/images/good.jpg +0 -0
- data/spec/public/images/logo.jpg +0 -0
- data/spec/public/images/sdfo.jpg +0 -0
- data/spec/public/images/too_big_image.jpg +0 -0
- data/spec/public/marketing.js +14 -0
- data/spec/public/salog20.js +6 -0
- data/spec/public/sample.css +6 -0
- data/spec/public/seal.js +10 -0
- data/spec/public/set_cookies.js +8 -0
- data/spec/public/styles/boo.css +4 -0
- data/spec/public/styles/for_import.css +7 -0
- data/spec/public/temp.css +1 -0
- data/spec/public/test.css +2 -0
- data/spec/sample_block_helper.rb +81 -0
- data/spec/spec_helper.rb +82 -0
- data/spec/web_resource_bundler/content_management/block_data_spec.rb +33 -0
- data/spec/web_resource_bundler/content_management/block_parser_spec.rb +100 -0
- data/spec/web_resource_bundler/content_management/css_url_rewriter_spec.rb +27 -0
- data/spec/web_resource_bundler/content_management/resource_file_spec.rb +37 -0
- data/spec/web_resource_bundler/file_manager_spec.rb +60 -0
- data/spec/web_resource_bundler/filters/bundle_filter/filter_spec.rb +40 -0
- data/spec/web_resource_bundler/filters/bundle_filter/resource_packager_spec.rb +41 -0
- data/spec/web_resource_bundler/filters/cdn_filter_spec.rb +76 -0
- data/spec/web_resource_bundler/filters/image_encode_filter/css_generator_spec.rb +104 -0
- data/spec/web_resource_bundler/filters/image_encode_filter/filter_spec.rb +73 -0
- data/spec/web_resource_bundler/filters/image_encode_filter/image_data_spec.rb +53 -0
- data/spec/web_resource_bundler/settings_spec.rb +45 -0
- data/spec/web_resource_bundler/web_resource_bundler_spec.rb +90 -0
- data/web_resource_bundler.gemspec +111 -0
- 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)
|
data/spec/public/foo.css
ADDED
Binary file
|
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
|
+
}
|
data/spec/public/seal.js
ADDED
@@ -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 @@
|
|
1
|
+
background: url('./images/1.png');background-image: url('./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
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -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
|