rad_assets 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +11 -0
- data/lib/assets/assets.rb +18 -0
- data/lib/assets/compressor.rb +30 -0
- data/lib/assets/gems.rb +4 -0
- data/lib/assets/packaged_resource.rb +46 -0
- data/lib/assets/require.rb +16 -0
- data/lib/assets/resource.rb +22 -0
- data/lib/assets/vendor/jsmin.rb +211 -0
- data/lib/assets/view_helper.rb +9 -0
- data/lib/components/assets.rb +5 -0
- data/readme.md +4 -0
- data/spec/assets_spec/app.js +3 -0
- data/spec/assets_spec/lib/tools.js +2 -0
- data/spec/assets_spec/vendor/jquery.js +1 -0
- data/spec/assets_spec.rb +46 -0
- data/spec/spec_helper.rb +6 -0
- metadata +84 -0
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Assets
|
2
|
+
inject logger: :logger, config: :config
|
3
|
+
|
4
|
+
def resolved_http_paths http_path
|
5
|
+
resource = pack? ? PackagedResource.new(http_path) : Resource.new(http_path)
|
6
|
+
resource.resolved_http_paths
|
7
|
+
end
|
8
|
+
cache_method_with_params_in_production :resolved_http_paths
|
9
|
+
|
10
|
+
def fs_path http_path
|
11
|
+
http.fs_path http_path
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def pack?
|
16
|
+
rad.production?
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Assets::Compressor
|
2
|
+
COMPRESSORS = {
|
3
|
+
js: -> path, packaged_path {
|
4
|
+
jsmin = "#{__FILE__.dirname}/vendor/jsmin.rb"
|
5
|
+
`ruby #{jsmin} <#{path} >#{packaged_path} \n`
|
6
|
+
},
|
7
|
+
css: -> path, packaged_path {
|
8
|
+
data = path.to_file.read
|
9
|
+
data.gsub!(/\s+/, " ") # collapse space
|
10
|
+
data.gsub!(/\/\*(.*?)\*\//, "") # remove comments - caution, might want to remove this if using css hacks
|
11
|
+
data.gsub!(/\} /, "}\n") # add line breaks
|
12
|
+
data.gsub!(/\n$/, "") # remove last break
|
13
|
+
data.gsub!(/ \{ /, " {") # trim inside brackets
|
14
|
+
data.gsub!(/; \}/, "}") # trim inside brackets
|
15
|
+
packaged_path.to_file.write data
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
def self.pack! path
|
20
|
+
file = path.to_file.must.exist
|
21
|
+
packager = COMPRESSORS[file.extension.to_sym]
|
22
|
+
if packager
|
23
|
+
tmp = "#{path}.tmp"
|
24
|
+
tmp.to_file.destroy
|
25
|
+
packager.call file.path, tmp
|
26
|
+
file.destroy
|
27
|
+
FileUtils.mv tmp, file.path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/assets/gems.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Assets::PackagedResource < Assets::Resource
|
2
|
+
PACKAGED_POSTFIX = 'packaged'
|
3
|
+
inject config: :config
|
4
|
+
|
5
|
+
def resolved_http_paths
|
6
|
+
fs_path = assets.fs_path http_path
|
7
|
+
http_paths = []
|
8
|
+
fs_path.to_file.read.scan ASSET_REQUIRE_RE do |dependency_http_path|
|
9
|
+
res = Assets::PackagedResource.new(dependency_http_path.first)
|
10
|
+
http_paths.push *res.resolved_http_paths
|
11
|
+
end
|
12
|
+
http_paths << http_path
|
13
|
+
|
14
|
+
fs_paths = http_paths.collect{|path| "#{config.public_dir!}#{path}"}
|
15
|
+
packaged_file = "#{config.public_dir!}#{packaged_http_path}".to_file
|
16
|
+
|
17
|
+
rebuild = (
|
18
|
+
!packaged_file.exist? or
|
19
|
+
fs_paths.any?{|path| path.to_file.updated_at > packaged_file.updated_at}
|
20
|
+
)
|
21
|
+
rebuild! packaged_file, fs_paths if rebuild
|
22
|
+
|
23
|
+
[packaged_http_path]
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
def packaged_http_path
|
28
|
+
extension = File.extname(http_path)
|
29
|
+
base = http_path[0..(http_path.size - extension.size - 1)]
|
30
|
+
"#{base}.packaged#{extension}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def rebuild! packaged_file, fs_paths
|
34
|
+
# merging
|
35
|
+
packaged_file.write! do |writer|
|
36
|
+
fs_paths.each do |path|
|
37
|
+
path.to_file.read do |buff|
|
38
|
+
writer.call buff
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# packing
|
44
|
+
Assets::Compressor.pack! packaged_file.path
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'assets/gems'
|
2
|
+
|
3
|
+
require 'vfs'
|
4
|
+
require 'rad'
|
5
|
+
|
6
|
+
class Assets; end
|
7
|
+
|
8
|
+
%w(
|
9
|
+
compressor
|
10
|
+
assets
|
11
|
+
resource
|
12
|
+
packaged_resource
|
13
|
+
view_helper
|
14
|
+
).each{|f| require "assets/#{f}"}
|
15
|
+
|
16
|
+
Rad::Template::Context.include Assets::ViewHelper
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Assets::Resource
|
2
|
+
attr_reader :http_path
|
3
|
+
inject assets: :assets
|
4
|
+
|
5
|
+
ASSET_REQUIRE_RE = /rad\.assets\.require[ \t]+['"]([a-zA-Z0-9_\-\.\/]+)['"]/
|
6
|
+
|
7
|
+
def initialize http_path
|
8
|
+
raise "resources path should be absolute (#{http_path})!" unless http_path =~ /^\//
|
9
|
+
@http_path = http_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolved_http_paths
|
13
|
+
fs_path = assets.fs_path http_path
|
14
|
+
paths = []
|
15
|
+
fs_path.to_file.read.scan ASSET_REQUIRE_RE do |dependency_http_path|
|
16
|
+
res = Assets::Resource.new(dependency_http_path.first)
|
17
|
+
paths.push *res.resolved_http_paths
|
18
|
+
end
|
19
|
+
paths << http_path
|
20
|
+
paths.uniq
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,211 @@
|
|
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
|
+
# Ruby 1.9 Compatibility Fix - the below isAlphanum uses Fixnum#ord to be compatible with Ruby 1.9 and 1.8.7
|
35
|
+
# Fixnum#ord is not found by default in 1.8.6, so monkey patch it in:
|
36
|
+
if RUBY_VERSION == '1.8.6'
|
37
|
+
class Fixnum; def ord; return self; end; end
|
38
|
+
end
|
39
|
+
|
40
|
+
EOF = -1
|
41
|
+
$theA = ""
|
42
|
+
$theB = ""
|
43
|
+
|
44
|
+
# isAlphanum -- return true if the character is a letter, digit, underscore,
|
45
|
+
# dollar sign, or non-ASCII character
|
46
|
+
def isAlphanum(c)
|
47
|
+
return false if !c || c == EOF
|
48
|
+
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
49
|
+
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
50
|
+
c == '\\' || c[0].ord > 126)
|
51
|
+
end
|
52
|
+
|
53
|
+
# get -- return the next character from stdin. Watch out for lookahead. If
|
54
|
+
# the character is a control character, translate it to a space or linefeed.
|
55
|
+
def get()
|
56
|
+
c = $stdin.getc
|
57
|
+
return EOF if(!c)
|
58
|
+
c = c.chr
|
59
|
+
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
|
60
|
+
return "\n" if (c == "\r")
|
61
|
+
return " "
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get the next character without getting it.
|
65
|
+
def peek()
|
66
|
+
lookaheadChar = $stdin.getc
|
67
|
+
$stdin.ungetc(lookaheadChar)
|
68
|
+
return lookaheadChar.chr
|
69
|
+
end
|
70
|
+
|
71
|
+
# mynext -- get the next character, excluding comments.
|
72
|
+
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
73
|
+
def mynext()
|
74
|
+
c = get
|
75
|
+
if (c == "/")
|
76
|
+
if(peek == "/")
|
77
|
+
while(true)
|
78
|
+
c = get
|
79
|
+
if (c <= "\n")
|
80
|
+
return c
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
if(peek == "*")
|
85
|
+
get
|
86
|
+
while(true)
|
87
|
+
case get
|
88
|
+
when "*"
|
89
|
+
if (peek == "/")
|
90
|
+
get
|
91
|
+
return " "
|
92
|
+
end
|
93
|
+
when EOF
|
94
|
+
raise "Unterminated comment"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return c
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# action -- do something! What you do is determined by the argument: 1
|
104
|
+
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
105
|
+
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
106
|
+
# single character. Wow! action recognizes a regular expression if it is
|
107
|
+
# preceded by ( or , or =.
|
108
|
+
def action(a)
|
109
|
+
if(a==1)
|
110
|
+
$stdout.write $theA
|
111
|
+
end
|
112
|
+
if(a==1 || a==2)
|
113
|
+
$theA = $theB
|
114
|
+
if ($theA == "\'" || $theA == "\"")
|
115
|
+
while (true)
|
116
|
+
$stdout.write $theA
|
117
|
+
$theA = get
|
118
|
+
break if ($theA == $theB)
|
119
|
+
raise "Unterminated string literal" if ($theA <= "\n")
|
120
|
+
if ($theA == "\\")
|
121
|
+
$stdout.write $theA
|
122
|
+
$theA = get
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
if(a==1 || a==2 || a==3)
|
128
|
+
$theB = mynext
|
129
|
+
if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
|
130
|
+
$theA == ":" || $theA == "[" || $theA == "!" ||
|
131
|
+
$theA == "&" || $theA == "|" || $theA == "?" ||
|
132
|
+
$theA == "{" || $theA == "}" || $theA == ";" ||
|
133
|
+
$theA == "\n"))
|
134
|
+
$stdout.write $theA
|
135
|
+
$stdout.write $theB
|
136
|
+
while (true)
|
137
|
+
$theA = get
|
138
|
+
if ($theA == "/")
|
139
|
+
break
|
140
|
+
elsif ($theA == "\\")
|
141
|
+
$stdout.write $theA
|
142
|
+
$theA = get
|
143
|
+
elsif ($theA <= "\n")
|
144
|
+
raise "Unterminated RegExp Literal"
|
145
|
+
end
|
146
|
+
$stdout.write $theA
|
147
|
+
end
|
148
|
+
$theB = mynext
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# jsmin -- Copy the input to the output, deleting the characters which are
|
154
|
+
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
155
|
+
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
156
|
+
# Most spaces and linefeeds will be removed.
|
157
|
+
def jsmin
|
158
|
+
$theA = "\n"
|
159
|
+
action(3)
|
160
|
+
while ($theA != EOF)
|
161
|
+
case $theA
|
162
|
+
when " "
|
163
|
+
if (isAlphanum($theB))
|
164
|
+
action(1)
|
165
|
+
else
|
166
|
+
action(2)
|
167
|
+
end
|
168
|
+
when "\n"
|
169
|
+
case ($theB)
|
170
|
+
when "{","[","(","+","-"
|
171
|
+
action(1)
|
172
|
+
when " "
|
173
|
+
action(3)
|
174
|
+
else
|
175
|
+
if (isAlphanum($theB))
|
176
|
+
action(1)
|
177
|
+
else
|
178
|
+
action(2)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
else
|
182
|
+
case ($theB)
|
183
|
+
when " "
|
184
|
+
if (isAlphanum($theA))
|
185
|
+
action(1)
|
186
|
+
else
|
187
|
+
action(3)
|
188
|
+
end
|
189
|
+
when "\n"
|
190
|
+
case ($theA)
|
191
|
+
when "}","]",")","+","-","\"","\\", "'", '"'
|
192
|
+
action(1)
|
193
|
+
else
|
194
|
+
if (isAlphanum($theA))
|
195
|
+
action(1)
|
196
|
+
else
|
197
|
+
action(3)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
else
|
201
|
+
action(1)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
ARGV.each do |anArg|
|
208
|
+
$stdout.write "// #{anArg}\n"
|
209
|
+
end
|
210
|
+
|
211
|
+
jsmin
|
data/readme.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jQuery
|
data/spec/assets_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Assets' do
|
4
|
+
with_tmp_spec_dir
|
5
|
+
isolate :config
|
6
|
+
inject assets: :assets
|
7
|
+
|
8
|
+
before do
|
9
|
+
config.merge!({public_dir: spec_dir}, override: true)
|
10
|
+
assets.stub!(:fs_path){|http_path| "#{spec_dir}#{http_path}"}
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "development" do
|
14
|
+
before{assets.stub!(:pack?).and_return(false)}
|
15
|
+
|
16
|
+
it "resolved_http_paths" do
|
17
|
+
assets.resolved_http_paths('/app.js').should == %w(/vendor/jquery.js /lib/tools.js /app.js)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "production" do
|
22
|
+
before{assets.stub!(:pack?).and_return(true)}
|
23
|
+
|
24
|
+
it "resolved_http_paths" do
|
25
|
+
assets.resolved_http_paths('/app.js').should == %w(/app.packaged.js)
|
26
|
+
|
27
|
+
packaged_file = "#{spec_dir}/app.packaged.js".to_file
|
28
|
+
packaged_file.should exist
|
29
|
+
packaged_file.read.should =~ /jQuery.*Tools.*App/m
|
30
|
+
|
31
|
+
"#{spec_dir}/lib/tools.packaged.js".to_file.should exist
|
32
|
+
"#{spec_dir}/vendor/jquery.packaged.js".to_file.should exist
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should create new packed version if sources are updated" do
|
36
|
+
assets.resolved_http_paths('/app.js').should == %w(/app.packaged.js)
|
37
|
+
packaged_file = "#{spec_dir}/app.packaged.js".to_file
|
38
|
+
packaged_file.read.should =~ /jQuery.*Tools.*App/m
|
39
|
+
|
40
|
+
sleep 1.1 # file system can't notice smaller difference in file update time
|
41
|
+
"#{spec_dir}/vendor/jquery.js".to_file.write "newQuery"
|
42
|
+
assets.resolved_http_paths('/app.js').should == %w(/app.packaged.js)
|
43
|
+
packaged_file.read.should =~ /newQuery.*Tools.*App/m
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rad_assets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexey Petrushin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-17 00:00:00.000000000 +04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rad_core
|
17
|
+
requirement: &2763970 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2763970
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: vfs
|
28
|
+
requirement: &2763660 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2763660
|
37
|
+
description:
|
38
|
+
email:
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- Rakefile
|
44
|
+
- readme.md
|
45
|
+
- lib/assets/assets.rb
|
46
|
+
- lib/assets/compressor.rb
|
47
|
+
- lib/assets/gems.rb
|
48
|
+
- lib/assets/packaged_resource.rb
|
49
|
+
- lib/assets/require.rb
|
50
|
+
- lib/assets/resource.rb
|
51
|
+
- lib/assets/vendor/jsmin.rb
|
52
|
+
- lib/assets/view_helper.rb
|
53
|
+
- lib/components/assets.rb
|
54
|
+
- spec/assets_spec/app.js
|
55
|
+
- spec/assets_spec/lib/tools.js
|
56
|
+
- spec/assets_spec/vendor/jquery.js
|
57
|
+
- spec/assets_spec.rb
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://github.com/alexeypetrushin/rad_assets
|
61
|
+
licenses: []
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.5.1
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Assets for Rad Framework
|
84
|
+
test_files: []
|