el 0.5.0

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.
@@ -0,0 +1,180 @@
1
+ module EL
2
+ module TagFactory
3
+
4
+ # methods allowing to generate HTML tags using plain Ruby
5
+ #
6
+ # @example
7
+ # div_tag 'some <evil> string' #=> <div>some &lt;evil&gt; string</div>
8
+ #
9
+ # tag content will be escaped by default.
10
+ # to emit content as is, use bang methods!
11
+ #
12
+ # @example
13
+ # div_tag! 'some <evil> string' #=> <div>some <evil> string</div>
14
+ #
15
+ # also you'll want to use bang methods when you have some nested tags
16
+ #
17
+ # @example
18
+ # div_tag! do
19
+ # b_tag 'some <evil> string'
20
+ # end
21
+ # #=> <div><b>some &lt;evil&gt; string</b></div>
22
+ #
23
+ EConstants::GENERIC_TAGS.each do |tag|
24
+ define_method tag + '_tag' do |*args, &proc|
25
+ content, attrs = EUtils.html_tag_requisites(true, *args)
26
+ '<%s%s>%s</%s>' % [tag, attrs, (proc ? CGI.escapeHTML(proc.call.to_s) : content), tag]
27
+ end
28
+ define_method tag + '_tag!' do |*args, &proc|
29
+ content, attrs = EUtils.html_tag_requisites(false, *args)
30
+ '<%s%s>%s</%s>' % [tag, attrs, (proc ? proc.call : content), tag]
31
+ end
32
+ end
33
+
34
+ EConstants::EMPTY_TAGS.each do |tag|
35
+ define_method tag + '_tag' do |*args|
36
+ '<%s%s>' % [tag, EUtils.html_tag_requisites(true, *args).last]
37
+ end
38
+ end
39
+
40
+ # shorthand for `script_tag`
41
+ # so you can type `js_tag "file"` instead of
42
+ # `script_tag type: 'text/javascript', src: "file.js"`
43
+ #
44
+ # if URL given as first argument, it should not contain extension.
45
+ # also URL will be automatically modified if used within assets mapper.
46
+ #
47
+ # to set an URL that wont be modified in any way, use :src option.
48
+ #
49
+ def js_tag src, attrs = {}
50
+ src.is_a?(Hash) && (attrs = src) && (src = nil)
51
+ src = src ? assets_url(src) : attrs[:src]
52
+ suffix = attrs.delete(:suffix)
53
+ attrs[:src] = '%s.js%s' % [src, suffix]
54
+ attrs[:type] ||= 'text/javascript'
55
+ '<script%s></script>' % EUtils.html_tag_attrs(attrs)
56
+ end
57
+
58
+ # shorthand for `link_tag`
59
+ # so you can type `css_tag "file"` instead of
60
+ # `link_tag rel: 'stylesheet', href: "file.css"`
61
+ #
62
+ # URL are handled exactly as per `js_tag`
63
+ def css_tag src, attrs = {}
64
+ src.is_a?(Hash) && (attrs = src) && (src = nil)
65
+ src = src ? assets_url(src) : (attrs[:href] || attrs.delete(:src))
66
+ suffix = attrs.delete(:suffix)
67
+ attrs[:href] = '%s.css%s' % [src, suffix]
68
+ attrs[:media] ||= 'all'
69
+ attrs[:type] ||= 'text/css'
70
+ attrs[:rel] ||= 'stylesheet'
71
+ '<link%s>' % EUtils.html_tag_attrs(attrs)
72
+ end
73
+
74
+ # shorthands for `img_tag`
75
+ # so you can type `png_tag "file"` instead of `img_tag "file.png"`
76
+ #
77
+ # URL are handled exactly as per `js_tag`
78
+ EConstants::IMAGE_TAGS.each do |ext|
79
+ pattern = '%s.' + ext + '%s'
80
+ define_method(ext + '_tag') do |src, attrs = {}|
81
+ src.is_a?(Hash) && (attrs = src) && (src = nil)
82
+ src = src ? assets_url(src) : attrs[:src]
83
+ suffix = attrs.delete(:suffix)
84
+ attrs[:src] = pattern % [src, suffix]
85
+ '<img%s>' % EUtils.html_tag_attrs(attrs)
86
+ end
87
+ end
88
+
89
+ def doctype_tag &proc
90
+ "<!DOCTYPE html>\n%s" % (proc ? proc.call : '')
91
+ end
92
+
93
+ def comment_tag comment = nil
94
+ comment = yield if block_given?
95
+ '<!-- %s -->' % CGI.escapeHTML(comment.to_s)
96
+ end
97
+
98
+ # same as `comment_tag` except it wont escape comment!
99
+ def comment_tag! comment = nil
100
+ comment = yield if block_given?
101
+ '<!-- %s -->' % comment
102
+ end
103
+
104
+ private
105
+
106
+ # just a placeholder to work when used outside Espresso
107
+ def assets_url src
108
+ src
109
+ end
110
+
111
+ end
112
+ end
113
+
114
+ class E
115
+ include EL::TagFactory
116
+
117
+ # build a HTML <a> tag.
118
+ #
119
+ # if first param is a valid action, the URL of given action will be used.
120
+ # action accepted as a symbol or a string representing action name and format.
121
+ # action can also be passed in deRESTified form, eg. :read instead of :post_read
122
+ #
123
+ # @example
124
+ #
125
+ # class App < E
126
+ # format '.html'
127
+ #
128
+ # def read
129
+ # link_to :read #=> /app/read
130
+ # link_to 'read.html' #=> /app/read.html
131
+ # link_to 'read.xml' #=> read.xml - not translated, used as is
132
+ # end
133
+ #
134
+ # def post_write
135
+ # link_to :post_write #=> /app/write - works but it is tedious, use :write instead
136
+ # link_to :write #=> /app/write
137
+ # link_to 'write.html' #=> /app/write.html
138
+ # link_to '/something' #=> /something - not translated, used as is
139
+ # end
140
+ # end
141
+ #
142
+ # if `nil` passed as first argument, a void link will be created
143
+ #
144
+ # @example
145
+ #
146
+ # link_to nil, 'something' #=> <a href="javascript:void(null);">something</a>
147
+ #
148
+ # anchor can be passed via second argument.
149
+ # if it is missing, the link will be used as anchor
150
+ # @note the anchor will be HTML escaped
151
+ #
152
+ # @example
153
+ #
154
+ # link_to :something #=> <a href="/something">/something</a>
155
+ # link_to :foo, 'bar' #=> <a href="/foo">bar</a>
156
+ #
157
+ # anchor can also be passed as a block
158
+ #
159
+ # @example
160
+ #
161
+ # link_to(:foo) { 'bar' } #=> <a href="/foo">bar</a>
162
+ #
163
+ # attributes can be passed as a hash via last argument
164
+ #
165
+ # @example
166
+ #
167
+ # link_to :foo, target: '_blank' #=> <a href="/foo" target="_blank">/foo</a>
168
+ # link_to :foo, :bar, target: '_blank' #=> <a href="/foo" target="_blank">bar</a>
169
+ #
170
+ def link_to *args, &proc
171
+ '<a href="%s"%s>%s</a>' %
172
+ EUtils.requisites_for_link_to(true, self.class, *args, &proc)
173
+ end
174
+
175
+ # same as `link_to` except it wont escape the anchor
176
+ def link_to! *args, &proc
177
+ '<a href="%s"%s>%s</a>' %
178
+ EUtils.requisites_for_link_to(false, self.class, *args, &proc)
179
+ end
180
+ end
@@ -0,0 +1,37 @@
1
+ module EUtils
2
+ def html_tag_requisites escape, *args
3
+ content, attrs = nil, {}
4
+ args.each {|a| a.is_a?(Hash) ? attrs.update(a) : content = a}
5
+ [
6
+ escape && content ? CGI.escape_html(content.to_s) : content,
7
+ html_tag_attrs(attrs)
8
+ ]
9
+ end
10
+ module_function :html_tag_requisites
11
+
12
+ def html_tag_attrs attrs
13
+ attrs.inject('') do |s,kv|
14
+ s << ' %s="%s"' % kv.map {|x| CGI.escape_html(x.to_s)}
15
+ end
16
+ end
17
+ module_function :html_tag_attrs
18
+
19
+ def requisites_for_link_to escape, controller, action_or_link = nil, anchor = nil, attributes = {}, &proc
20
+ if action_or_link.is_a?(Hash)
21
+ attributes = action_or_link
22
+ action_or_link = nil
23
+ elsif anchor.is_a?(Hash)
24
+ attributes = anchor
25
+ anchor = nil
26
+ end
27
+ (route = controller[action_or_link]) && (action_or_link = route)
28
+ anchor ||= proc ? proc.call : action_or_link
29
+ [
30
+ action_or_link ? CGI.escapeHTML(action_or_link.to_s) : 'javascript:void(null);',
31
+ attributes.is_a?(Hash) ? EUtils.html_tag_attrs(attributes) : '',
32
+ escape && anchor ? CGI.escapeHTML(anchor.to_s) : anchor
33
+ ]
34
+ end
35
+ module_function :requisites_for_link_to
36
+
37
+ end
@@ -0,0 +1 @@
1
+ master.css
@@ -0,0 +1 @@
1
+ master.js
File without changes
@@ -0,0 +1,14 @@
1
+ module ELSpecHelper
2
+ def match? source, target
3
+ check(source) =~
4
+ (target.is_a?(Regexp) ? target : Regexp.new(Regexp.escape target))
5
+ end
6
+
7
+ def match_body? target
8
+ does(last_response.body).match? target
9
+ end
10
+
11
+ def current_body? body
12
+ is(last_response.body).eql? body
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path('../../setup', __FILE__)
2
+
3
+ class App < E
4
+ map :/
5
+ view_prefix '/'
6
+ before do
7
+ clear_cache! if params[:clear_cache]
8
+ clear_compiler! if params[:clear_compiler]
9
+ end
10
+
11
+ def cache_test body
12
+ cache { body }
13
+ end
14
+
15
+ def compiler_test body
16
+ File.open(app.root + 'view/compiler_test.erb', 'w') { |f| f << body }
17
+ render
18
+ end
19
+ end
20
+ run E.new {
21
+ mount App
22
+ pids do
23
+ Dir[File.expand_path('../tmp/pids/*.pid', __FILE__)].map { |f| File.read f }
24
+ end
25
+ }
@@ -0,0 +1 @@
1
+ 0.36913809814807674
@@ -0,0 +1,11 @@
1
+ require 'digest'
2
+ require 'stringio'
3
+
4
+ ENV['EL_DEV'] && $:.unshift(File.expand_path('../../../espresso/lib', __FILE__))
5
+ require 'e'
6
+
7
+ $:.unshift File.expand_path('../../lib', __FILE__)
8
+ require 'el'
9
+ require 'specular'
10
+ require 'sonar'
11
+ require File.expand_path('../helpers', __FILE__)
@@ -0,0 +1,5 @@
1
+ /*= require ui */
2
+
3
+ body {
4
+
5
+ }
@@ -0,0 +1,7 @@
1
+ //= require ui
2
+
3
+ AppClass = function() {
4
+
5
+ }
6
+
7
+ App = new AppClass();
@@ -0,0 +1,3 @@
1
+ div {
2
+
3
+ }
@@ -0,0 +1,5 @@
1
+ UIClass = function() {
2
+
3
+ }
4
+
5
+ UI = new UIClass();
@@ -0,0 +1,276 @@
1
+ module ELTest__assets
2
+
3
+ class TagHelpers < E
4
+
5
+ def js
6
+ (src = params[:src]) ?
7
+ js_tag(src: src) :
8
+ js_tag(params[:asset])
9
+ end
10
+
11
+ def css
12
+ return css_tag(href: params[:href]) if params[:href]
13
+ return css_tag(src: params[:src]) if params[:src]
14
+ css_tag(params[:asset])
15
+ end
16
+
17
+ def png
18
+ (src = params[:src]) ?
19
+ png_tag(src: src) :
20
+ png_tag(params[:asset])
21
+ end
22
+ end
23
+
24
+ Spec.new self do
25
+ app E.new {
26
+ assets_url '/assets'
27
+ mount TagHelpers
28
+ }
29
+ map TagHelpers.base_url
30
+
31
+ Testing :js_tag do
32
+ get :js, asset: :master
33
+ does(/src="\/assets\/master\.js"/).match_body?
34
+
35
+ Should 'ignore assets_url when :src given' do
36
+ get :js, src: 'master'
37
+ does(/src="master\.js"/).match_body?
38
+ end
39
+ end
40
+
41
+ Testing :css_tag do
42
+ get :css, asset: :master
43
+ does(/href="\/assets\/master\.css"/).match_body?
44
+
45
+ Should 'ignore assets_url when :href given' do
46
+ get :css, href: 'http://some.cdn/master'
47
+ does(/href="http:\/\/some.cdn\/master\.css"/).match_body?
48
+ end
49
+
50
+ Should 'also work with :src instead of :href' do
51
+ get :css, src: 'foo'
52
+ does(/href="foo\.css"/).match_body?
53
+ refute(last_response.body) =~ /src=/
54
+ end
55
+ end
56
+
57
+ Testing :png_tag do
58
+ get :png, asset: :master
59
+ does(/src="\/assets\/master\.png"/).match_body?
60
+
61
+ Should 'ignore assets_url when :src given' do
62
+ get :png, src: 'blah/master'
63
+ does(/src="blah\/master\.png"/).match_body?
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ class AssetsMapper < E
70
+
71
+ def get_assets_mapper type
72
+ html = ''
73
+ mapper = assets_mapper params[:baseurl]
74
+ if src = params[:src]
75
+ html << mapper.send(type, src: src)
76
+ elsif href = params[:href]
77
+ html << mapper.send(type, href: href)
78
+ else
79
+ html << mapper.send(type, params[:url])
80
+ end
81
+ html
82
+ end
83
+
84
+ def assets_mapper_chdir type
85
+ html = ''
86
+ mapper = assets_mapper params[:baseurl]
87
+ params[:scenario].each do |scenario|
88
+ path, file = scenario.split
89
+ if file.nil?
90
+ file = path
91
+ path = nil
92
+ end
93
+ mapper.cd path
94
+ html << mapper.send(type, file)
95
+ end
96
+ html
97
+ end
98
+
99
+ def assets_mapper_with_block type
100
+ html, url = '', params[:url]
101
+ assets_mapper params[:baseurl] do
102
+ html << send(type, url)
103
+ end
104
+ html
105
+ end
106
+
107
+ def assets_mapper_with_suffix type, suffix
108
+ html, url = '', params[:url]
109
+ assets_mapper params[:baseurl], suffix: suffix do
110
+ html << send(type, url)
111
+ end
112
+ html
113
+ end
114
+ end
115
+
116
+ Spec.new AssetsMapper do
117
+
118
+ Testing :js do
119
+ get :assets_mapper, :js_tag, baseurl: './', url: 'master'
120
+ does('src="./master.js"').match_body?
121
+
122
+ get :assets_mapper, :js_tag, baseurl: '/', url: 'master'
123
+ does('src="/master.js"').match_body?
124
+
125
+ get :assets_mapper, :js_tag, baseurl: 'http://some.cdn', url: 'master'
126
+ does('src="http://some.cdn/master.js"').match_body?
127
+
128
+ Should 'skip baseurl' do
129
+ get :assets_mapper, :js_tag, src: 'master', baseurl: 'skipit'
130
+ does('src="master.js"').match_body?
131
+ end
132
+ end
133
+
134
+ Testing :css do
135
+ get :assets_mapper, :css_tag, baseurl: './', url: 'master'
136
+ does('href="./master.css"').match_body?
137
+
138
+ get :assets_mapper, :css_tag, baseurl: '/', url: 'master'
139
+ does('href="/master.css"').match_body?
140
+
141
+ get :assets_mapper, :css_tag, baseurl: 'http://some.cdn', url: 'master'
142
+ does('href="http://some.cdn/master.css"').match_body?
143
+
144
+ Should 'skip baseurl' do
145
+ get :assets_mapper, :css_tag, href: 'master', baseurl: 'skipit'
146
+ does('href="master.css"').match_body?
147
+ end
148
+ end
149
+
150
+ Testing :png do
151
+ get :assets_mapper, :png_tag, baseurl: './', url: 'master'
152
+ does('src="./master.png"').match_body?
153
+
154
+ get :assets_mapper, :png_tag, baseurl: '/', url: 'master'
155
+ does('src="/master.png"').match_body?
156
+
157
+ get :assets_mapper, :png_tag, baseurl: 'http://some.cdn', url: 'master'
158
+ does('src="http://some.cdn/master.png"').match_body?
159
+
160
+ Should 'skip baseurl' do
161
+ get :assets_mapper, :png_tag, src: 'master', baseurl: 'skipit'
162
+ does('src="master.png"').match_body?
163
+ end
164
+ end
165
+
166
+ Testing :AssetsLoaderWithBlock do
167
+ get :assets_mapper_with_block, :js_tag, url: 'master'
168
+ does('src="master.js"').match_body?
169
+
170
+ get :assets_mapper_with_block, :css_tag, url: 'master', baseurl: '/'
171
+ does('href="/master.css"').match_body?
172
+
173
+ get :assets_mapper_with_block, :css_tag, url: 'master', baseurl: './'
174
+ does('href="./master.css"').match_body?
175
+
176
+ get :assets_mapper_with_block, :png_tag, url: 'master', baseurl: 'http://some.cdn'
177
+ does('src="http://some.cdn/master.png"').match_body?
178
+ end
179
+
180
+ Testing :AssetsLoaderWithSuffix do
181
+ get :assets_mapper_with_suffix, :js_tag, '-sfx', url: 'master'
182
+ does('src="master.js-sfx"').match_body?
183
+
184
+ get :assets_mapper_with_suffix, :css_tag, '-sfx', url: 'master', baseurl: '/'
185
+ does('href="/master.css-sfx"').match_body?
186
+
187
+ get :assets_mapper_with_suffix, :png_tag, '-sfx', url: 'master', baseurl: 'http://some.cdn'
188
+ does('src="http://some.cdn/master.png-sfx"').match_body?
189
+ end
190
+
191
+ Testing :AssetsLoaderChdir do
192
+ Should 'avoid redundant path traversal' do
193
+ get :assets_mapper_chdir, :js_tag, scenario: [ '../../etc/passwd jquery' ]
194
+ does('src="etc/passwd/jquery.js"').match_body?
195
+
196
+ get :assets_mapper_chdir, :js_tag, scenario: [ '../etc/passwd jquery' ]
197
+ does('src="etc/passwd/jquery.js"').match_body?
198
+
199
+ get :assets_mapper_chdir, :js_tag, scenario: ['vendor/jquery jquery', '../../../../ master']
200
+ does('src="master.js"').match_body?
201
+ end
202
+
203
+ Should 'cd to vendor/jquery and load jquery.js' do
204
+ get :assets_mapper_chdir, :js_tag, baseurl: '/assets', scenario: ['vendor/jquery jquery', '.. master', '/ master']
205
+ does('src="/assets/vendor/jquery/jquery.js"').match_body?
206
+
207
+ Then 'cd to .. and load vendor/master.js' do
208
+ does('src="/assets/vendor/master.js"').match_body?
209
+ end
210
+
211
+ Then 'cd to / and load master.js' do
212
+ does('src="/assets/master.js"').match_body?
213
+ end
214
+ end
215
+
216
+ Should 'cd to vendor/jquery and load vendor/jquery/jquery.js' do
217
+ get :assets_mapper_chdir, :js_tag, baseurl: '/assets', scenario: ['vendor/jquery jquery', '../.. master', '/scripts master']
218
+ does('src="/assets/vendor/jquery/jquery.js"').match_body?
219
+
220
+ Then 'cd to ../.. and load master.js' do
221
+ does('src="/assets/master.js"').match_body?
222
+ end
223
+
224
+ Then 'cd to /scripts and load master.js' do
225
+ does('src="/assets/scripts/master.js"').match_body?
226
+ end
227
+ end
228
+
229
+ Should 'cd to css/themes and load css/themes/black.css' do
230
+
231
+ get :assets_mapper_chdir, :css_tag, baseurl: '/assets', scenario: ['css/themes black', ' master', '/css master']
232
+ does('href="/assets/css/themes/black.css"').match_body?
233
+
234
+ Then 'cd to root and load master.css' do
235
+ does('href="/assets/master.css"').match_body?
236
+ end
237
+
238
+ Then 'cd to /css and load master.css' do
239
+ does('href="/assets/css/master.css"').match_body?
240
+ end
241
+ end
242
+
243
+ Should 'behave well with rooted baseurls' do
244
+ Should 'cd to vendor/icons/16x16 and load vendor/icons/16x16/file.png' do
245
+
246
+ get :assets_mapper_chdir, :png_tag, baseurl: '/public', scenario: ['vendor/icons/16x16 file', '../.. sprite', '/icons folder']
247
+ does('src="/public/vendor/icons/16x16/file.png"').match_body?
248
+
249
+ Then 'cd to ../.. and load vendor/sprite.png' do
250
+ does('src="/public/vendor/sprite.png"').match_body?
251
+ end
252
+
253
+ Then 'cd to /icons and load folder.png' do
254
+ does('src="/public/icons/folder.png"').match_body?
255
+ end
256
+ end
257
+ end
258
+
259
+ Should 'behave well with protocoled baseurls' do
260
+ Should 'cd to icons/16x16 and load icons/16x16/file.png' do
261
+
262
+ get :assets_mapper_chdir, :png_tag, baseurl: 'http://some.cdn', scenario: ['icons/16x16 file', '.. sprite', '/imgs img']
263
+ does('src="http://some.cdn/icons/16x16/file.png"').match_body?
264
+
265
+ Then 'cd to .. and load sprite.png' do
266
+ does('src="http://some.cdn/icons/sprite.png"').match_body?
267
+ end
268
+
269
+ Then 'cd to /imgs and load img.png' do
270
+ does('src="http://some.cdn/imgs/img.png"').match_body?
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end