rad_assets 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake_ext'
2
+
3
+ project(
4
+ name: "assets",
5
+ official_name: "rad_assets",
6
+ version: "0.2.0",
7
+ summary: "Assets for Rad Framework",
8
+
9
+ author: "Alexey Petrushin",
10
+ homepage: "http://github.com/alexeypetrushin/rad_assets"
11
+ )
@@ -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
@@ -0,0 +1,4 @@
1
+ if respond_to? :fake_gem
2
+ fake_gem 'rad_core'
3
+ fake_gem 'vfs'
4
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ module Assets::ViewHelper
2
+ def packaged_assets *http_paths
3
+ resolved_http_paths = []
4
+ http_paths.each do |http_path|
5
+ resolved_http_paths.push *rad.assets.resolved_http_paths(http_path)
6
+ end
7
+ resolved_http_paths
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ rad.register :assets do
2
+ require 'assets/require'
3
+
4
+ Assets.new
5
+ end
data/readme.md ADDED
@@ -0,0 +1,4 @@
1
+ # Asset Packager for the Rad framework
2
+
3
+ TODO add readme
4
+
@@ -0,0 +1,3 @@
1
+ // rad.assets.require '/vendor/jquery.js'
2
+ // rad.assets.require '/lib/tools.js'
3
+ App
@@ -0,0 +1,2 @@
1
+ // rad.assets.require '/vendor/jquery.js'
2
+ Tools
@@ -0,0 +1 @@
1
+ jQuery
@@ -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
@@ -0,0 +1,6 @@
1
+ require 'assets/require'
2
+
3
+ require 'rspec_ext'
4
+ require 'rad/spec'
5
+
6
+ rad.assets
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: []