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,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 &uarr;](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 &uarr;](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 &uarr;](https://github.com/espresso/espresso-lungo#use) ]**
@@ -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 &lt;evil&gt; 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 &lt;evil&gt; 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 &uarr;](https://github.com/espresso/espresso-lungo#use) ]**
80
+
81
+
82
+ ## link_to
83
+
84
+ `link_to` allow to build a HTML &lt;a&gt; 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 &lt;evil&gt;</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 &uarr;](https://github.com/espresso/espresso-lungo#use) ]**
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'e'
2
+ require 'sprockets'
3
+
4
+ require 'el/constants'
5
+ require 'el/tag_factory'
6
+ require 'el/content_helpers'
7
+ require 'el/assets'
8
+ require 'el/cache'
9
+ require 'el/crud'
10
+ require 'el/ipcm'
11
+ require 'el/utils'
@@ -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