el 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.travis.yml +6 -0
- data/Gemfile +5 -0
- data/LICENSE +19 -0
- data/README.md +77 -0
- data/Rakefile +47 -0
- data/docs/Assets.md +157 -0
- data/docs/CRUD.md +255 -0
- data/docs/CacheManager.md +66 -0
- data/docs/ContentHelpers.md +64 -0
- data/docs/TagFactory.md +201 -0
- data/el.gemspec +23 -0
- data/lib/el.rb +11 -0
- data/lib/el/assets.rb +126 -0
- data/lib/el/cache.rb +96 -0
- data/lib/el/constants.rb +21 -0
- data/lib/el/content_helpers.rb +61 -0
- data/lib/el/crud.rb +239 -0
- data/lib/el/ipcm.rb +67 -0
- data/lib/el/tag_factory.rb +180 -0
- data/lib/el/utils.rb +37 -0
- data/test/assets/master.css +1 -0
- data/test/assets/master.js +1 -0
- data/test/assets/master.png +0 -0
- data/test/helpers.rb +14 -0
- data/test/ipcm/config.ru +25 -0
- data/test/ipcm/view/compiler_test.erb +1 -0
- data/test/setup.rb +11 -0
- data/test/sprockets/app.css +5 -0
- data/test/sprockets/app.js +7 -0
- data/test/sprockets/ui.css +3 -0
- data/test/sprockets/ui.js +5 -0
- data/test/test__assets.rb +276 -0
- data/test/test__cache.rb +145 -0
- data/test/test__content_helpers.rb +41 -0
- data/test/test__crud.rb +269 -0
- data/test/test__ipcm.rb +127 -0
- data/test/test__sprockets.rb +101 -0
- data/test/test__tag_factory.rb +170 -0
- metadata +124 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
## Cache Manager
|
3
|
+
|
4
|
+
Allows to cache the result of an arbitrary block and use the result on consequent requests.
|
5
|
+
|
6
|
+
*Note: Value is not stored if block returns false or nil.*
|
7
|
+
|
8
|
+
Cache can be cleared by calling `clear_cache!` method.
|
9
|
+
|
10
|
+
If called without params, all cache will be cleared.
|
11
|
+
|
12
|
+
To clear only specific blocks, pass their IDs as params.
|
13
|
+
|
14
|
+
**Example:**
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
class App < E
|
18
|
+
|
19
|
+
def index
|
20
|
+
@db_items = cache :db_items do
|
21
|
+
# fetching items
|
22
|
+
end
|
23
|
+
@banners = cache :banners do
|
24
|
+
# render banners partial
|
25
|
+
end
|
26
|
+
# ...
|
27
|
+
end
|
28
|
+
|
29
|
+
def products
|
30
|
+
cache do
|
31
|
+
# fetch and render products
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
after do
|
36
|
+
if 'some condition occurred'
|
37
|
+
# clearing cache only for @banners and @db_items
|
38
|
+
clear_cache! :banners, :db_items
|
39
|
+
end
|
40
|
+
if 'some another condition occurred'
|
41
|
+
# clearing all cache
|
42
|
+
clear_cache!
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
|
49
|
+
By default, the cache will be kept in memory.<br>
|
50
|
+
If you want to use a different pool, set it by using `cache_pool` at app level.
|
51
|
+
|
52
|
+
Just make sure your pool behaves like a Hash,
|
53
|
+
Meant it should respond to `[]=`, `[]`, `delete` and `clear`.
|
54
|
+
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# controllers...
|
58
|
+
|
59
|
+
app = E.new do
|
60
|
+
cache_pool SomePool
|
61
|
+
mount Something
|
62
|
+
end
|
63
|
+
app.run
|
64
|
+
```
|
65
|
+
|
66
|
+
**[ [contents ↑](https://github.com/espresso/espresso-lungo#use) ]**
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
## content_for
|
3
|
+
|
4
|
+
Allow to capture content and then render it into a different place:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
content_for :assets do
|
8
|
+
js_tag :jquery
|
9
|
+
end
|
10
|
+
|
11
|
+
# later in views
|
12
|
+
yield_content :assets
|
13
|
+
#=> '<script src="jquery.js" type="text/javascript"></script>'
|
14
|
+
```
|
15
|
+
|
16
|
+
Use `content_for?` to check whether content block exists for some key:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
p content_for?(:assets)
|
20
|
+
#=> #<Proc:0x00...
|
21
|
+
|
22
|
+
p content_for?(:blah)
|
23
|
+
#=> nil
|
24
|
+
```
|
25
|
+
|
26
|
+
It is also possible to pass any variables into content block:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
content_for :account do |name, email|
|
30
|
+
form_tag! do
|
31
|
+
input_tag(value: name) +
|
32
|
+
input_tag(value: email)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# somewhere in views
|
37
|
+
yield_content :account, :foo, 'foo@bar.com'
|
38
|
+
#=> '<form><input value="foo"><input value="foo@bar.com"></form>'
|
39
|
+
```
|
40
|
+
|
41
|
+
Please note that content block will be executed every time you call `yield_content`.
|
42
|
+
|
43
|
+
If you are using same content block multiple times on same page please consider to assign the result to a variable and use it repeatedly to avoid performance decreasing.
|
44
|
+
|
45
|
+
**[ [contents ↑](https://github.com/espresso/espresso-lungo#use) ]**
|
46
|
+
|
47
|
+
## capture_html
|
48
|
+
|
49
|
+
Execute given content block and return the result.
|
50
|
+
|
51
|
+
Useful when you need to display same snippet multiple times and want it rendered only once.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
html = capture_html do
|
55
|
+
js_tag(:jquery) +
|
56
|
+
css_tag(:ui)
|
57
|
+
end
|
58
|
+
|
59
|
+
puts html
|
60
|
+
#=> <script src="jquery.js" type="text/javascript"></script>
|
61
|
+
#=> <link href="ui.css" media="all" type="text/css" rel="stylesheet">
|
62
|
+
```
|
63
|
+
|
64
|
+
**[ [contents ↑](https://github.com/espresso/espresso-lungo#use) ]**
|
data/docs/TagFactory.md
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
|
2
|
+
## Generic Tags
|
3
|
+
|
4
|
+
`Espresso Lungo` comes with a set of useful helpers aimed at generating HTML in plain Ruby:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
div_tag 'some text'
|
8
|
+
#=> <div>some text</div>
|
9
|
+
```
|
10
|
+
|
11
|
+
HTML attributes can be passed via options Hash:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
h1_tag 'Welcome!', class: 'well'
|
15
|
+
#=> <h1 class="well">Welcome!</h1>
|
16
|
+
```
|
17
|
+
|
18
|
+
Content can be provided via block:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
script_tag do
|
22
|
+
// some js here
|
23
|
+
end
|
24
|
+
#=> <script>
|
25
|
+
#=> // some js here
|
26
|
+
#=> </script>
|
27
|
+
```
|
28
|
+
|
29
|
+
**Important!** Any content, provided via first argument or block, will be HTML escaped!
|
30
|
+
To emit content as is, use bang methods and MAKE SURE you do not pass any untrusted input into HTML helpers!
|
31
|
+
|
32
|
+
**Default Behavior:**
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
div_tag 'some <evil> string'
|
36
|
+
#=> <div>some <evil> string</div>
|
37
|
+
```
|
38
|
+
|
39
|
+
**Bang helpers wont escape output! Use with care!**
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
div_tag! 'some <evil> string'
|
43
|
+
#=> <div>some <evil> string</div>
|
44
|
+
```
|
45
|
+
|
46
|
+
Though bang methods are mostly dangerous, they are necessary when using nested tags:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
div_tag! do # without bang <b> tag will be escaped
|
50
|
+
b_tag 'some <evil> string'
|
51
|
+
end
|
52
|
+
#=> <div><b>some <evil> string</b></div>
|
53
|
+
```
|
54
|
+
|
55
|
+
The main concern when using nested tags is to not mix helpers with any untrusted input.
|
56
|
+
|
57
|
+
**Note:** when using multiple tags you have to concat them, otherwise only the last one will be shown:
|
58
|
+
|
59
|
+
**Wrong:**
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
form_tag! do
|
63
|
+
input_tag(name: :name)
|
64
|
+
input_tag(name: :email)
|
65
|
+
end
|
66
|
+
#=> <form><input name="email"></form>
|
67
|
+
```
|
68
|
+
|
69
|
+
**Correct:**
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
form_tag! do
|
73
|
+
input_tag(name: :name) + # or <<
|
74
|
+
input_tag(name: :email)
|
75
|
+
end
|
76
|
+
#=> <form><input name="name"><input name="email"></form>
|
77
|
+
```
|
78
|
+
|
79
|
+
**[ [contents ↑](https://github.com/espresso/espresso-lungo#use) ]**
|
80
|
+
|
81
|
+
|
82
|
+
## link_to
|
83
|
+
|
84
|
+
`link_to` allow to build a HTML <a> tag.
|
85
|
+
|
86
|
+
If first param is a valid action, the URL of given action will be used.
|
87
|
+
|
88
|
+
Action accepted as a symbol or a string representing action name and format.
|
89
|
+
|
90
|
+
Action can also be passed in deRESTified form, eg. `:read` instead of `:post_read`
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class App < E
|
94
|
+
format '.html'
|
95
|
+
|
96
|
+
def read
|
97
|
+
link_to :read #=> <a href="/app/read" ...
|
98
|
+
link_to 'read.html' #=> <a href="/app/read.html" ...
|
99
|
+
link_to 'read.xml' #=> <a href="read.xml" ... - not translated, used as is
|
100
|
+
end
|
101
|
+
|
102
|
+
def post_write
|
103
|
+
link_to :post_write #=> <a href="/app/write" ... - works but it is tedious, use :write instead
|
104
|
+
link_to :write #=> <a href="/app/write" ...
|
105
|
+
link_to 'write.html' #=> <a href="/app/write.html" ...
|
106
|
+
link_to '/something' #=> <a href="/something" ... - not translated, used as is
|
107
|
+
end
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
When you need to create a link to an arbitrary controller, use `base_url`, `route` or `[]` of target controller:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
class News < E
|
115
|
+
format '.html'
|
116
|
+
|
117
|
+
def home
|
118
|
+
# ...
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_read id = nil
|
122
|
+
# ...
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
link_to News.base_url #=> <a href="/news" ...
|
128
|
+
link_to News[:home] #=> <a href="/news/home" ...
|
129
|
+
link_to News['home.html'] #=> <a href="/news/home.html" ...
|
130
|
+
link_to News[:get_read] #=> <a href="/news/read" ...
|
131
|
+
link_to News[:read] #=> <a href="/news/read" ...
|
132
|
+
link_to News['read.html'] #=> <a href="/news/read.html" ...
|
133
|
+
|
134
|
+
link_to News.route(:read, 100) #=> <a href="/news/read/100" ...
|
135
|
+
link_to News.route(:read, '100.html') #=> <a href="/news/read/100.html" ...
|
136
|
+
```
|
137
|
+
|
138
|
+
|
139
|
+
If `nil` passed as first argument, a void link will be created:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
link_to nil, 'something'
|
143
|
+
#=> <a href="javascript:void(null);>something</a>
|
144
|
+
```
|
145
|
+
|
146
|
+
Anchor can be passed via second argument.
|
147
|
+
|
148
|
+
If it is missing, the link will be used as anchor:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
link_to :something
|
152
|
+
#=> <a href="/something">/something</a>
|
153
|
+
|
154
|
+
link_to :foo, 'bar'
|
155
|
+
#=> <a href="/foo">bar</a>
|
156
|
+
```
|
157
|
+
|
158
|
+
Anchor can also be passed as a block:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
link_to(:foo) { 'bar' }
|
162
|
+
#=> <a href="/foo>bar</a>
|
163
|
+
```
|
164
|
+
|
165
|
+
|
166
|
+
**Important!** Anchor will be HTML escaped:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
link_to(:foo) { 'some <evil>' }
|
170
|
+
#=> <a href="/foo>some <evil></a>
|
171
|
+
```
|
172
|
+
|
173
|
+
To emit content as is, use bang method instead and make sure you do not pass any untrusted content to `link_to` helper:
|
174
|
+
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
link_to! :foo, 'some <evil>'
|
178
|
+
#=> <a href="/foo>some <evil></a>
|
179
|
+
```
|
180
|
+
|
181
|
+
Also you'll need bang helper when you build nested tags:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
link_to! :foo do
|
185
|
+
b_tag 'some text'
|
186
|
+
end
|
187
|
+
#=> <a href="/foo><b>some text</b></a>
|
188
|
+
```
|
189
|
+
|
190
|
+
|
191
|
+
Attributes can be passed as a hash via last argument:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
link_to :foo, target: '_blank'
|
195
|
+
#=> <a href="/foo" target="_blank">/foo</a>
|
196
|
+
|
197
|
+
link_to :foo, :bar, target: '_blank'
|
198
|
+
#=> <a href="/foo" target="_blank">bar</a>
|
199
|
+
```
|
200
|
+
|
201
|
+
**[ [contents ↑](https://github.com/espresso/espresso-lungo#use) ]**
|
data/el.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
version = '0.5.0'
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
|
6
|
+
s.name = 'el'
|
7
|
+
s.version = version
|
8
|
+
s.authors = ['Silviu Rusu']
|
9
|
+
s.email = ['slivuz@gmail.com']
|
10
|
+
s.homepage = 'https://github.com/espresso/espresso-lungo'
|
11
|
+
s.summary = 'el-%s' % version
|
12
|
+
s.description = 'Espresso Lungo - Extra Libs for Espresso Framework'
|
13
|
+
|
14
|
+
s.required_ruby_version = '>= 1.9.2'
|
15
|
+
s.add_dependency 'e', '>= 0.4.8'
|
16
|
+
s.add_dependency 'sprockets'
|
17
|
+
|
18
|
+
s.add_development_dependency 'bundler'
|
19
|
+
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
s.files = Dir['**/{*,.[a-z]*}'].reject {|e| e =~ /\.(gem|lock)\Z/}
|
22
|
+
s.licenses = ['MIT']
|
23
|
+
end
|
data/lib/el.rb
ADDED
data/lib/el/assets.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module EL
|
2
|
+
class AssetsMapper
|
3
|
+
include TagFactory
|
4
|
+
|
5
|
+
attr_reader :baseurl, :wd
|
6
|
+
|
7
|
+
# @example
|
8
|
+
#
|
9
|
+
# assets_mapper :vendor do
|
10
|
+
#
|
11
|
+
# js_tag :jquery
|
12
|
+
#
|
13
|
+
# chdir 'jquery-ui'
|
14
|
+
# js_tag 'js/jquery-ui.min'
|
15
|
+
# css_tag 'css/jquery-ui.min'
|
16
|
+
#
|
17
|
+
# cd '../bootstrap'
|
18
|
+
# js_tag 'js/bootstrap.min'
|
19
|
+
# css_tag 'css/bootstrap'
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# #=> <script src="/vendor/jquery.js" ...
|
23
|
+
# #=> <script src="/vendor/jquery-ui/js/jquery-ui.min.js" ...
|
24
|
+
# #=> <link href="/vendor/jquery-ui/css/jquery-ui.min.css" ...
|
25
|
+
# #=> <script src="/vendor/bootstrap/js/bootstrap.min.js" ...
|
26
|
+
# #=> <link href="/vendor/bootstrap/css/bootstrap.css" ...
|
27
|
+
#
|
28
|
+
def initialize baseurl, opts = {}, &proc
|
29
|
+
@opts = Hash[opts]
|
30
|
+
@suffix = @opts.delete(:suffix) || ''
|
31
|
+
baseurl = baseurl.to_s.dup.strip
|
32
|
+
baseurl.empty? ? baseurl = nil : (baseurl =~ /\/\Z/ || baseurl << '/')
|
33
|
+
@baseurl, @wd = baseurl.freeze, nil
|
34
|
+
proc && self.instance_exec(&proc)
|
35
|
+
end
|
36
|
+
|
37
|
+
(%w[js css] + EConstants::IMAGE_TAGS).each do |tag|
|
38
|
+
define_method tag + '_tag' do |src, attrs={}|
|
39
|
+
super src, attrs.merge(suffix: @suffix)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def chdir path = nil
|
44
|
+
return @wd = nil unless path
|
45
|
+
wd = []
|
46
|
+
if (path = path.to_s) =~ /\A\//
|
47
|
+
path = path.sub(/\A\/+/, '')
|
48
|
+
path = path.empty? ? [] : [path]
|
49
|
+
else
|
50
|
+
dirs_back, path = path.split(/\/+/).partition { |c| c == '..' }
|
51
|
+
if @wd
|
52
|
+
wd_chunks = @wd.split(/\/+/)
|
53
|
+
wd = wd_chunks[0, wd_chunks.size - dirs_back.size] || []
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@wd = (wd + path << '').compact.join('/').freeze
|
57
|
+
end
|
58
|
+
alias :cd :chdir
|
59
|
+
|
60
|
+
private
|
61
|
+
def assets_url path = nil
|
62
|
+
chunks = [baseurl, wd, path] # assigning array to a variable
|
63
|
+
chunks.select! {|c| c && c.size > 0} # and work on it
|
64
|
+
File.join(*chunks) # is 2x faster than array#select {...}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class E
|
71
|
+
include EL::TagFactory
|
72
|
+
|
73
|
+
def assets *args, &proc
|
74
|
+
app.assets *args, &proc
|
75
|
+
end
|
76
|
+
|
77
|
+
def assets_mapper *args, &proc
|
78
|
+
EL::AssetsMapper.new *args, &proc
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def assets_url path = nil
|
83
|
+
path ?
|
84
|
+
(app.assets_url ? File.join(app.assets_url, path.to_s) : path.to_s) :
|
85
|
+
(app.assets_url ? app.assets_url : '')
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
class EBuilder
|
91
|
+
|
92
|
+
# set the baseurl for assets.
|
93
|
+
# by default, assets URL is empty.
|
94
|
+
#
|
95
|
+
# @example assets_url not set
|
96
|
+
# script_tag 'master.js'
|
97
|
+
# => <script src="master.js"
|
98
|
+
# style_tag 'theme.css'
|
99
|
+
# => <link href="theme.css"
|
100
|
+
#
|
101
|
+
# @example assets_url set to /assets
|
102
|
+
#
|
103
|
+
# script_tag 'master.js'
|
104
|
+
# => <script src="/assets/master.js"
|
105
|
+
# style_tag 'theme.css'
|
106
|
+
# => <link href="/assets/theme.css"
|
107
|
+
#
|
108
|
+
# @note
|
109
|
+
# by default, Sprockets will be used to serve static files.
|
110
|
+
# to disable this, set second argument to false.
|
111
|
+
#
|
112
|
+
def assets_url url = nil, server = true
|
113
|
+
return @assets_url if @assets_url
|
114
|
+
url = url.to_s.dup.strip
|
115
|
+
url = url =~ /\A[\w|\d]+\:\/\//i ? url : EUtils.rootify_url(url)
|
116
|
+
@assets_url = (url =~ /\/\Z/ ? url : String.new(url) << '/').freeze
|
117
|
+
return unless server
|
118
|
+
mount_application(assets, @assets_url, on: :GET)
|
119
|
+
end
|
120
|
+
alias assets_map assets_url
|
121
|
+
|
122
|
+
def assets
|
123
|
+
@sprockets_env ||= Sprockets::Environment.new(root)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|