asset-packager 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ Dir.chdir File.dirname(__FILE__)
5
+
6
+ # Specs
7
+ task :default => :spec
8
+
9
+ Spec::Rake::SpecTask.new('spec') do |t|
10
+ t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
11
+ t.libs = ['lib'].collect{|f| "#{File.dirname __FILE__}/#{f}"}
12
+ end
13
+
14
+ # Gem
15
+ require 'rake/clean'
16
+ require 'rake/gempackagetask'
17
+ require 'fileutils'
18
+
19
+ spec = Gem::Specification.new do |s|
20
+ s.name = "asset-packager"
21
+ s.version = "0.0.1"
22
+ s.summary = "Asset Packager for the Crystal framework"
23
+ s.description = "Asset Packager for the Crystal framework"
24
+ s.author = "Alexey Petrushin"
25
+ # s.email = ""
26
+ s.homepage = "http://github.com/alexeypetrushin/asset-packager"
27
+
28
+ s.platform = Gem::Platform::RUBY
29
+ s.has_rdoc = true
30
+ # s.extra_rdoc_files = ["README.rdoc"]
31
+
32
+ # s.files = (%w{rakefile readme.md .gitignore} + Dir.glob("{app,lib,spec,.git}/**/*"))
33
+ s.files = (['Rakefile', 'readme.md'] + Dir.glob("{lib,spec}/**/*"))
34
+
35
+ s.require_paths = ["lib"]
36
+
37
+ [
38
+ 'crystal',
39
+ ].each{|name| s.add_dependency(name)}
40
+
41
+ end
42
+
43
+ PACKAGE_DIR = "#{File.expand_path File.dirname(__FILE__)}/build"
44
+
45
+ Rake::GemPackageTask.new(spec) do |p|
46
+ package_dir = PACKAGE_DIR
47
+ # FileUtils.mkdir package_dir unless File.exist? package_dir
48
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
49
+ p.need_zip = true
50
+ p.package_dir = package_dir
51
+ end
52
+
53
+ # CLEAN.include [ 'pkg', '*.gem']
54
+
55
+ task :push do
56
+ dir = Dir.chdir PACKAGE_DIR do
57
+ gem_file = Dir.glob("asset-packager*.gem").first
58
+ system "gem push #{gem_file}"
59
+ end
60
+ end
61
+
62
+ task :clean do
63
+ system "rm -r #{PACKAGE_DIR}"
64
+ end
65
+
66
+ task :release => [:gem, :push, :clean]
@@ -0,0 +1,159 @@
1
+ module AssetPackager
2
+ class << self
3
+ inject :config => :config
4
+
5
+ def merged_javascripts *package_names
6
+ merged_packages 'javascripts', package_names
7
+ end
8
+
9
+ def merged_stylesheets *package_names
10
+ merged_packages 'stylesheets', package_names
11
+ end
12
+
13
+ def add yaml_file_path, asset_path
14
+ definition = YAML.load File.read(yaml_file_path)
15
+ definition.must_be.a Hash
16
+ self.definitions[asset_path] = definition
17
+ end
18
+
19
+ def build_all
20
+ definitions.each do |path, package_types|
21
+ package_types.each do |type, package|
22
+ package.each do |name, files|
23
+ build = self.send "build_#{type}", path, name, files
24
+ dir = "#{public_root}/#{type}"
25
+ FileUtils.mkdir_p dir unless File.exist? dir
26
+ fname = public_root + filename_for_builded_package(type, name)
27
+ File.open(fname, "w"){|f| f.write(build)}
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def delete_all
34
+ definitions.each do |path, package_types|
35
+ package_types.each do |type, package|
36
+ package.each do |name, files|
37
+ fname = public_root + filename_for_builded_package(type, name)
38
+ File.delete fname if File.exist? fname
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ def filename_for_builded_package type, package
45
+ type = type.to_s
46
+ "/#{type}/#{package}_packaged.#{AssetPackager.resources_extensions[type]}"
47
+ end
48
+
49
+ def definitions
50
+ @definitions ||= {}
51
+ end
52
+
53
+ def merge_environments
54
+ @merge_environments ||= ["production"]
55
+ end
56
+
57
+ protected
58
+ def public_root
59
+ "#{config.root}/public"
60
+ end
61
+
62
+ def tmp_path
63
+ "#{config.root}/tmp"
64
+ end
65
+
66
+ def resources_extensions
67
+ @resources_extensions ||= {
68
+ 'javascripts' => 'js',
69
+ 'stylesheets' => 'css'
70
+ }
71
+ end
72
+
73
+ def build_javascripts path_to_files, package, files
74
+ merged = merge_file path_to_files, files
75
+
76
+ # write out to a temp file
77
+ tmp_file = "#{tmp_path}/#{package}_packaged"
78
+ File.open("#{tmp_file}_uncompressed.js", "w"){|f| f.write(merged)}
79
+
80
+ # compress file with JSMin library
81
+ jsmin = "#{File.dirname(__FILE__)}/jsmin.rb"
82
+ `ruby #{jsmin} <#{tmp_file}_uncompressed.js >#{tmp_file}_compressed.js \n`
83
+
84
+ # read it back in and trim it
85
+ result = ""
86
+ File.open("#{tmp_file}_compressed.js", "r") { |f| result += f.read.strip }
87
+
88
+ # delete temp files if they exist
89
+ File.delete("#{tmp_file}_uncompressed.js") if File.exists?("#{tmp_file}_uncompressed.js")
90
+ File.delete("#{tmp_file}_compressed.js") if File.exists?("#{tmp_file}_compressed.js")
91
+
92
+ result
93
+ end
94
+
95
+ def build_stylesheets path_to_files, package, files
96
+ merged = merge_file path_to_files, files
97
+
98
+ merged.gsub!(/\s+/, " ") # collapse space
99
+ merged.gsub!(/\/\*(.*?)\*\//, "") # remove comments - caution, might want to remove this if using css hacks
100
+ merged.gsub!(/\} /, "}\n") # add line breaks
101
+ merged.gsub!(/\n$/, "") # remove last break
102
+ merged.gsub!(/ \{ /, " {") # trim inside brackets
103
+ merged.gsub!(/; \}/, "}") # trim inside brackets
104
+ merged
105
+ end
106
+
107
+ def merge_file path_to_files, files
108
+ merged_file = ""
109
+ files.each do |fname|
110
+ full_path = if fname =~ /\A\//
111
+ "#{public_root}#{fname}"
112
+ else
113
+ "#{path_to_files}/#{fname}"
114
+ end
115
+ File.open(full_path, "r") do |f|
116
+ merged_file += f.read + "\n"
117
+ end
118
+ end
119
+ merged_file
120
+ end
121
+
122
+ # TODO3 cache it
123
+ def merged_packages thetype, package_names
124
+ found_packages = {}
125
+
126
+ package_names.each do |pname|
127
+ AssetPackager.definitions.each do |path, package_types|
128
+ package_types.each do |type, packages|
129
+ next unless type == thetype
130
+ packages.each do |name, files|
131
+ found_packages[name] = files if name == pname.to_s
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ package_names.each{|name| found_packages.must.include name.to_s}
138
+
139
+ if AssetPackager.merge_environments.include? config.environment
140
+ found_packages.collect do |name, files|
141
+ AssetPackager.filename_for_builded_package thetype, name
142
+ end
143
+ else
144
+ list = []
145
+ found_packages.each do |name, files|
146
+ files.each do |fname|
147
+ fname = if fname =~ /\A\//
148
+ fname
149
+ else
150
+ "/#{fname}"
151
+ end
152
+ list.push fname
153
+ end
154
+ end
155
+ list
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/ruby
2
+ # jsmin.rb 2007-07-20
3
+ # Author: Uladzislau Latynski
4
+ # This work is a translation from C to Ruby of jsmin.c published by
5
+ # Douglas Crockford. Permission is hereby granted to use the Ruby
6
+ # version under the same conditions as the jsmin.c on which it is
7
+ # based.
8
+ #
9
+ # /* jsmin.c
10
+ # 2003-04-21
11
+ #
12
+ # Copyright (c) 2002 Douglas Crockford (www.crockford.com)
13
+ #
14
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
15
+ # this software and associated documentation files (the "Software"), to deal in
16
+ # the Software without restriction, including without limitation the rights to
17
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
18
+ # of the Software, and to permit persons to whom the Software is furnished to do
19
+ # so, subject to the following conditions:
20
+ #
21
+ # The above copyright notice and this permission notice shall be included in all
22
+ # copies or substantial portions of the Software.
23
+ #
24
+ # The Software shall be used for Good, not Evil.
25
+ #
26
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
+ # SOFTWARE.
33
+
34
+ EOF = -1
35
+ $theA = ""
36
+ $theB = ""
37
+
38
+ # isAlphanum -- return true if the character is a letter, digit, underscore,
39
+ # dollar sign, or non-ASCII character
40
+ def isAlphanum(c)
41
+ return false if !c || c == EOF
42
+ return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
43
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
44
+ c == '\\' || c[0] > 126)
45
+ end
46
+
47
+ # get -- return the next character from stdin. Watch out for lookahead. If
48
+ # the character is a control character, translate it to a space or linefeed.
49
+ def get()
50
+ c = $stdin.getc
51
+ return EOF if(!c)
52
+ c = c.chr
53
+ return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
54
+ return "\n" if (c == "\r")
55
+ return " "
56
+ end
57
+
58
+ # Get the next character without getting it.
59
+ def peek()
60
+ lookaheadChar = $stdin.getc
61
+ $stdin.ungetc(lookaheadChar)
62
+ return lookaheadChar.chr
63
+ end
64
+
65
+ # mynext -- get the next character, excluding comments.
66
+ # peek() is used to see if a '/' is followed by a '/' or '*'.
67
+ def mynext()
68
+ c = get
69
+ if (c == "/")
70
+ if(peek == "/")
71
+ while(true)
72
+ c = get
73
+ if (c <= "\n")
74
+ return c
75
+ end
76
+ end
77
+ end
78
+ if(peek == "*")
79
+ get
80
+ while(true)
81
+ case get
82
+ when "*"
83
+ if (peek == "/")
84
+ get
85
+ return " "
86
+ end
87
+ when EOF
88
+ raise "Unterminated comment"
89
+ end
90
+ end
91
+ end
92
+ end
93
+ return c
94
+ end
95
+
96
+
97
+ # action -- do something! What you do is determined by the argument: 1
98
+ # Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
99
+ # (Delete A). 3 Get the next B. (Delete B). action treats a string as a
100
+ # single character. Wow! action recognizes a regular expression if it is
101
+ # preceded by ( or , or =.
102
+ def action(a)
103
+ if(a==1)
104
+ $stdout.write $theA
105
+ end
106
+ if(a==1 || a==2)
107
+ $theA = $theB
108
+ if ($theA == "\'" || $theA == "\"")
109
+ while (true)
110
+ $stdout.write $theA
111
+ $theA = get
112
+ break if ($theA == $theB)
113
+ raise "Unterminated string literal" if ($theA <= "\n")
114
+ if ($theA == "\\")
115
+ $stdout.write $theA
116
+ $theA = get
117
+ end
118
+ end
119
+ end
120
+ end
121
+ if(a==1 || a==2 || a==3)
122
+ $theB = mynext
123
+ if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
124
+ $theA == ":" || $theA == "[" || $theA == "!" ||
125
+ $theA == "&" || $theA == "|" || $theA == "?" ||
126
+ $theA == "{" || $theA == "}" || $theA == ";" ||
127
+ $theA == "\n"))
128
+ $stdout.write $theA
129
+ $stdout.write $theB
130
+ while (true)
131
+ $theA = get
132
+ if ($theA == "/")
133
+ break
134
+ elsif ($theA == "\\")
135
+ $stdout.write $theA
136
+ $theA = get
137
+ elsif ($theA <= "\n")
138
+ raise "Unterminated RegExp Literal"
139
+ end
140
+ $stdout.write $theA
141
+ end
142
+ $theB = mynext
143
+ end
144
+ end
145
+ end
146
+
147
+ # jsmin -- Copy the input to the output, deleting the characters which are
148
+ # insignificant to JavaScript. Comments will be removed. Tabs will be
149
+ # replaced with spaces. Carriage returns will be replaced with linefeeds.
150
+ # Most spaces and linefeeds will be removed.
151
+ def jsmin
152
+ $theA = "\n"
153
+ action(3)
154
+ while ($theA != EOF)
155
+ case $theA
156
+ when " "
157
+ if (isAlphanum($theB))
158
+ action(1)
159
+ else
160
+ action(2)
161
+ end
162
+ when "\n"
163
+ case ($theB)
164
+ when "{","[","(","+","-"
165
+ action(1)
166
+ when " "
167
+ action(3)
168
+ else
169
+ if (isAlphanum($theB))
170
+ action(1)
171
+ else
172
+ action(2)
173
+ end
174
+ end
175
+ else
176
+ case ($theB)
177
+ when " "
178
+ if (isAlphanum($theA))
179
+ action(1)
180
+ else
181
+ action(3)
182
+ end
183
+ when "\n"
184
+ case ($theA)
185
+ when "}","]",")","+","-","\"","\\", "'", '"'
186
+ action(1)
187
+ else
188
+ if (isAlphanum($theA))
189
+ action(1)
190
+ else
191
+ action(3)
192
+ end
193
+ end
194
+ else
195
+ action(1)
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ ARGV.each do |anArg|
202
+ $stdout.write "// #{anArg}\n"
203
+ end
204
+
205
+ jsmin
@@ -0,0 +1,25 @@
1
+ namespace :asset do
2
+ namespace :packager do
3
+
4
+ desc "Merge and compress assets"
5
+ task :build_all => :environment do
6
+ require 'yaml'
7
+ require 'asset_packager/asset_packager'
8
+
9
+ AssetPackager.build_all
10
+
11
+ puts "Asset builded"
12
+ end
13
+
14
+ desc "Delete all asset builds"
15
+ task :delete_all do
16
+ require 'yaml'
17
+ require 'asset_packager/asset_packager'
18
+
19
+ AssetPackager.delete_all
20
+
21
+ puts "Asset Builds deleted"
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ module AssetPackager
2
+ module ViewHelper
3
+ delegate :merged_javascripts, :merged_stylesheets, :to => AssetPackager
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ raise "Asset packager must be used with Crystal::AbstractController!" unless defined? Crystal::AbstractController
2
+
3
+ require 'asset_packager/asset_packager'
4
+ require 'asset_packager/view_helper'
5
+
6
+ Crystal::ControllerContext.include AssetPackager::ViewHelper
7
+
8
+ # Use asset_packager/tasks for Rake tasks
data/readme.md ADDED
@@ -0,0 +1,4 @@
1
+ # Asset Packager for the Crystal framework
2
+
3
+ TODO add readme
4
+
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asset-packager
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Alexey Petrushin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-11 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: crystal
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Asset Packager for the Crystal framework
36
+ email:
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - Rakefile
45
+ - readme.md
46
+ - lib/asset_packager/asset_packager.rb
47
+ - lib/asset_packager/jsmin.rb
48
+ - lib/asset_packager/tasks.rb
49
+ - lib/asset_packager/view_helper.rb
50
+ - lib/asset_packager.rb
51
+ - spec/spec.opts
52
+ has_rdoc: true
53
+ homepage: http://github.com/alexeypetrushin/asset-packager
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Asset Packager for the Crystal framework
86
+ test_files: []
87
+