lux-fw 0.5.36 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.version +1 -1
  3. data/bin/README.md +26 -13
  4. data/bin/cli/benchmark.rb +18 -0
  5. data/bin/cli/cerb.rb +90 -0
  6. data/bin/cli/config.rb +4 -11
  7. data/bin/cli/console.rb +72 -30
  8. data/bin/cli/eval.rb +5 -27
  9. data/bin/cli/generate.rb +9 -11
  10. data/bin/cli/get.rb +14 -6
  11. data/bin/cli/memory.rb +12 -0
  12. data/bin/cli/new.rb +2 -0
  13. data/bin/cli/secrets.rb +3 -31
  14. data/bin/cli/server.rb +28 -9
  15. data/bin/cli/stats.rb +26 -20
  16. data/bin/cli/template.rb +10 -0
  17. data/bin/generate_doc +168 -0
  18. data/bin/lux +73 -10
  19. data/lib/README.md +18 -8
  20. data/lib/common/crypt.rb +60 -9
  21. data/lib/common/string_base.rb +54 -15
  22. data/lib/common/struct_opts.rb +30 -0
  23. data/lib/common/time_difference.rb +75 -0
  24. data/lib/loader.rb +41 -0
  25. data/lib/lux/application/README.md +67 -105
  26. data/lib/lux/application/application.rb +87 -329
  27. data/lib/lux/application/lib/magic_routes.rb +22 -0
  28. data/lib/lux/application/lib/nav.rb +218 -99
  29. data/lib/lux/application/lib/render.rb +47 -67
  30. data/lib/lux/application/lib/routes.rb +242 -0
  31. data/lib/lux/application/lib/shared.rb +47 -0
  32. data/lib/lux/application/lux_adapter.rb +6 -0
  33. data/lib/lux/application/lux_config.rb +26 -0
  34. data/lib/lux/cache/Find Results +24 -0
  35. data/lib/lux/cache/README.md +28 -35
  36. data/lib/lux/cache/cache.rb +78 -26
  37. data/lib/lux/cache/lib/memcached_server.rb +36 -0
  38. data/lib/lux/cache/lib/memory_server.rb +44 -0
  39. data/lib/lux/cache/lib/null_server.rb +33 -0
  40. data/lib/lux/cache/lib/sqlite_server.rb +62 -0
  41. data/lib/lux/cache/lux_adapter.rb +19 -0
  42. data/lib/lux/config/config.rb +93 -144
  43. data/lib/lux/config/lux_adapter.rb +27 -0
  44. data/lib/lux/controller/README.md +67 -12
  45. data/lib/lux/controller/controller.rb +237 -187
  46. data/lib/lux/current/README.md +29 -10
  47. data/lib/lux/current/current.rb +166 -77
  48. data/lib/lux/current/lib/current.rb +6 -0
  49. data/lib/lux/current/lib/encrypt_params.rb +38 -36
  50. data/lib/lux/current/lib/session.rb +86 -65
  51. data/lib/lux/current/lux_adapter.rb +5 -0
  52. data/lib/lux/environment/README.md +24 -0
  53. data/lib/lux/environment/environment.rb +91 -0
  54. data/lib/lux/environment/lux_adapter.rb +13 -0
  55. data/lib/lux/error/README.md +18 -19
  56. data/lib/lux/error/error.rb +207 -152
  57. data/lib/lux/error/lux_adapter.rb +9 -0
  58. data/lib/lux/logger/README.md +45 -0
  59. data/lib/lux/logger/lux_adapter.rb +27 -0
  60. data/lib/lux/lux.rb +72 -129
  61. data/lib/lux/mailer/README.md +12 -5
  62. data/lib/lux/mailer/lux_config.rb +4 -0
  63. data/lib/lux/mailer/mailer.rb +81 -59
  64. data/lib/lux/plugin/README.md +19 -0
  65. data/lib/lux/plugin/lux_adapter.rb +8 -0
  66. data/lib/lux/plugin/plugin.rb +65 -0
  67. data/lib/lux/render/README.md +100 -0
  68. data/lib/lux/render/render.rb +12 -0
  69. data/lib/lux/response/README.md +57 -1
  70. data/lib/lux/response/lib/file.rb +87 -65
  71. data/lib/lux/response/lib/flash.rb +49 -34
  72. data/lib/lux/response/lib/header.rb +34 -33
  73. data/lib/lux/response/response.rb +252 -164
  74. data/lib/lux/template/helper.rb +130 -0
  75. data/lib/lux/template/inline_render_proxy.rb +31 -0
  76. data/lib/lux/template/lux_adapter.rb +5 -0
  77. data/lib/lux/template/template.rb +127 -0
  78. data/lib/lux-fw.rb +15 -33
  79. data/lib/overload/array.rb +33 -7
  80. data/lib/overload/blank.rb +8 -3
  81. data/lib/overload/boolean.rb +46 -0
  82. data/lib/overload/class.rb +28 -0
  83. data/lib/overload/dir.rb +117 -7
  84. data/lib/overload/file.rb +40 -5
  85. data/lib/overload/float.rb +38 -3
  86. data/lib/overload/hash.rb +81 -91
  87. data/lib/overload/integer.rb +15 -0
  88. data/lib/overload/json.rb +26 -0
  89. data/lib/overload/nil.rb +4 -8
  90. data/lib/overload/object.rb +91 -24
  91. data/lib/overload/pathname.rb +11 -0
  92. data/lib/overload/raise_variants.rb +26 -36
  93. data/lib/overload/string.rb +100 -27
  94. data/lib/overload/thread_simple.rb +100 -0
  95. data/lib/overload/time.rb +60 -38
  96. data/tasks/loader.rb +20 -7
  97. metadata +170 -169
  98. data/bin/.DS_Store +0 -0
  99. data/bin/build_gem +0 -77
  100. data/bin/cli/dbconsole.rb +0 -8
  101. data/bin/cli/routes.rb +0 -90
  102. data/lib/.DS_Store +0 -0
  103. data/lib/common/.DS_Store +0 -0
  104. data/lib/common/class_attributes.rb +0 -51
  105. data/lib/common/class_callbacks.rb +0 -47
  106. data/lib/common/free_struct.rb +0 -42
  107. data/lib/common/hash_with_indifferent_access.rb +0 -74
  108. data/lib/common/html_tag_builder.rb +0 -91
  109. data/lib/common/method_attr.rb +0 -69
  110. data/lib/common/url.rb +0 -191
  111. data/lib/lux/.DS_Store +0 -0
  112. data/lib/lux/README.md +0 -10
  113. data/lib/lux/cache/.DS_Store +0 -0
  114. data/lib/lux/cache/lib/memory.rb +0 -36
  115. data/lib/lux/cache/lib/null.rb +0 -21
  116. data/lib/lux/config/README.md +0 -63
  117. data/lib/lux/config/lib/plugin.rb +0 -65
  118. data/lib/lux/config/lib/secrets.rb +0 -48
  119. data/lib/lux/current/.DS_Store +0 -0
  120. data/lib/lux/delayed_job/.DS_Store +0 -0
  121. data/lib/lux/delayed_job/README.md +0 -3
  122. data/lib/lux/delayed_job/delayed_job.rb +0 -51
  123. data/lib/lux/delayed_job/lib/memory.rb +0 -16
  124. data/lib/lux/delayed_job/lib/nsq.rb +0 -3
  125. data/lib/lux/delayed_job/lib/postgre.rb +0 -6
  126. data/lib/lux/delayed_job/lib/redis.rb +0 -19
  127. data/lib/lux/event_bus/README.md +0 -36
  128. data/lib/lux/event_bus/event_bus.rb +0 -27
  129. data/lib/lux/view/README.md +0 -85
  130. data/lib/lux/view/cell.rb +0 -102
  131. data/lib/lux/view/helper.rb +0 -120
  132. data/lib/lux/view/lib/cell_helpers.rb +0 -29
  133. data/lib/lux/view/view.rb +0 -95
  134. data/lib/overload/it.rb +0 -29
  135. data/plugins/api/README.md +0 -49
  136. data/plugins/api/api.rb +0 -153
  137. data/plugins/api/lib/attr.rb +0 -31
  138. data/plugins/api/lib/dsl.rb +0 -52
  139. data/plugins/api/lib/error.rb +0 -3
  140. data/plugins/api/lib/model_api.rb +0 -203
  141. data/plugins/api/lib/response.rb +0 -85
  142. data/plugins/db/.DS_Store +0 -0
  143. data/plugins/db/README.md +0 -29
  144. data/plugins/db/auto_migrate/auto_migrate.rb +0 -268
  145. data/plugins/db/auto_migrate/db.rake +0 -15
  146. data/plugins/db/helpers/array_search.rb +0 -27
  147. data/plugins/db/helpers/before_save_filters.rb +0 -32
  148. data/plugins/db/helpers/composite_primary_keys.rb +0 -36
  149. data/plugins/db/helpers/core.rb +0 -94
  150. data/plugins/db/helpers/dataset_methods.rb +0 -138
  151. data/plugins/db/helpers/enums_plugin.rb +0 -52
  152. data/plugins/db/helpers/find_precache.rb +0 -31
  153. data/plugins/db/helpers/link_objects.rb +0 -84
  154. data/plugins/db/helpers/schema_checks.rb +0 -83
  155. data/plugins/db/helpers/typero_adapter.rb +0 -71
  156. data/plugins/db/logger/config.rb +0 -22
  157. data/plugins/db/logger/lux_response_adapter.rb +0 -10
  158. data/plugins/db/paginate/helper.rb +0 -32
  159. data/plugins/db/paginate/sequel_adapter.rb +0 -23
  160. data/plugins/exceptions/exceptions.rake +0 -43
  161. data/plugins/exceptions/simple_exception.rb +0 -64
  162. data/plugins/favicon/favicon.rb +0 -10
  163. data/plugins/html/README.md +0 -3
  164. data/plugins/html/html_form.rb +0 -118
  165. data/plugins/html/html_input.rb +0 -98
  166. data/plugins/html/html_menu.rb +0 -79
  167. data/plugins/html/input_types.rb +0 -346
  168. data/plugins/js_widgets/README.md +0 -5
  169. data/plugins/js_widgets/js/html_tag.coffee +0 -42
  170. data/plugins/js_widgets/js/widgets.coffee +0 -161
  171. data/plugins/js_widgets/js_widgets.rb +0 -15
  172. data/plugins/oauth/lib/facebook.rb +0 -35
  173. data/plugins/oauth/lib/github.rb +0 -38
  174. data/plugins/oauth/lib/google.rb +0 -41
  175. data/plugins/oauth/lib/linkedin.rb +0 -41
  176. data/plugins/oauth/lib/stackexchange.rb +0 -41
  177. data/plugins/oauth/lib/twitter.rb +0 -38
  178. data/plugins/oauth/oauth.rb +0 -42
  179. data/plugins/policy/policy.rb +0 -53
  180. data/tasks/nginx.rake +0 -23
  181. /data/lib/lux/{view/lib → mailer}/helper_modules.rb +0 -0
@@ -2,223 +2,311 @@
2
2
  # response.max_age = 10
3
3
  # response.public = true
4
4
  # response.status = 500
5
- class Lux::Response
6
- # define in seconds, how long should page be accessible in client cache
7
- # if defined, cache becomes public and can be cache by proxies
8
- # use with care.only for static resources and
9
- attr_reader :max_age
10
- attr_accessor :headers, :cookies, :content_type, :status
11
-
12
- def initialize
13
- @render_start = Time.monotonic
14
- @headers = Lux::Response::Header.new
15
- @max_age = 0
16
- end
17
-
18
- def current
19
- Lux.current
20
- end
21
-
22
- def header name, value=:_
23
- @headers[name] = value if value != :_
24
- @headers[name]
25
- end
26
-
27
- def max_age= age
28
- @max_age = age.to_i
29
- end
30
-
31
- # http 103
32
- def early_hints link=nil, type=nil
33
- @early_hints ||= []
34
- @early_hints.push [link, type] if type && !@early_hints.include?(link)
35
- @early_hints
36
- end
5
+ module Lux
6
+ class Response
7
+ # define in seconds, how long should page be accessible in client cache
8
+ # if defined, cache becomes public and can be cache by proxies
9
+ # use with care.only for static resources and
10
+ attr_reader :max_age, :render_start
11
+ attr_accessor :headers, :cookies, :content_type, :status
12
+
13
+ def initialize
14
+ @render_start = Time.monotonic
15
+ @headers = Lux::Response::Header.new
16
+ @max_age = 0
17
+ end
37
18
 
38
- def etag *args
39
- unless @headers['etag']
40
- args.push current.request.url
19
+ def current
20
+ Lux.current
21
+ end
41
22
 
42
- key = '"%s"' % Lux.cache.generate_key(args)
43
- key = 'W/%s' % key unless max_age > 0
23
+ # header['x-foo']
24
+ # header 'x-foo', 'bar'
25
+ # header @hash
26
+ def header *args
27
+ if args.first
28
+ if args.first.class == Hash
29
+ args.each{|k,v| header k, v.to_s if k && v }
30
+ else
31
+ key = args.first.to_s.downcase
32
+ @headers[key] = args[1].to_s if args[1] != :_
33
+ @headers[key]
34
+ end
35
+ end
44
36
 
45
- @headers['etag'] = key
37
+ @headers
46
38
  end
47
39
 
48
- if !@body && current.request.env['HTTP_IF_NONE_MATCH'] == @headers['etag']
49
- status 304
50
- body 'not-modified'
40
+ def max_age= age, stale_while_revalidate = nil
41
+ @max_age = age.to_i
42
+ @stale_while_revalidate = stale_while_revalidate
51
43
  end
52
- end
53
44
 
54
- def status num=nil
55
- return @status unless num
56
- raise 'Bad status value [%s]' % num unless num.is_numeric?
45
+ # http 103
46
+ def early_hints link=nil, type=nil
47
+ @early_hints ||= []
48
+ @early_hints.push [link, type] if type && !@early_hints.include?(link)
49
+ @early_hints
50
+ end
57
51
 
58
- @status ||= num
59
- @status
60
- end
61
- alias :status= :status
52
+ def etag *args
53
+ unless @headers['etag']
54
+ key = '"%s"' % Lux.cache.generate_key(current.request.url, args)
55
+ key = 'W/%s' % key unless max_age > 0
56
+ @headers['etag'] = key
57
+ end
62
58
 
63
- def halt status=nil, msg=nil
64
- @status = status || 400
65
- @body = msg if msg
59
+ if !status && !current.no_cache?(true) && current.request.env['HTTP_IF_NONE_MATCH'] == @headers['etag']
60
+ if Lux.env.no_cache?
61
+ Lux.log ' * etag match (skiping for env.no_cache)' unless current.nav.format
62
+ else
63
+ Lux.log ' * etag match'
64
+ body 'not-modified', status: 304
65
+ true
66
+ end
67
+ else
68
+ false
69
+ end
70
+ end
66
71
 
67
- throw :done
68
- end
72
+ def status num = nil
73
+ return @status unless num
69
74
 
70
- def body body_data=nil, status=nil
71
- @status = status if status
72
- @body = body_data if body_data
73
- @body = yield @body if block_given?
74
- @body
75
- end
75
+ unless num.is_numeric?
76
+ Lux.info %[LUX error: Not numeric status code "#{num}", reverting to 400]
77
+ num = 400
78
+ end
76
79
 
77
- def body?
78
- !!@body
79
- end
80
+ @status ||= num
81
+ @status
82
+ end
83
+ alias :status= :status
80
84
 
81
- def content_type type=nil
82
- return @content_type unless type
85
+ def halt status = nil, msg = nil
86
+ @status = status || 400
87
+ @body = msg if msg
88
+ end
83
89
 
84
- if type.is_a?(Symbol)
85
- case type
86
- when :javascript then 'application/javascript'
87
- when :json then 'application/json'
88
- when :text then 'text/plain'
89
- when :html then 'text/html'
90
+ # response.body 'foo'
91
+ # response.body 'foo', status: 400, content_type: :js
92
+ # response.body { 'foo' }
93
+ # response.body({...}) { 'foo' }
94
+ def body data = nil, opts = nil
95
+ if block_given?
96
+ # block can override data set
97
+ opts = data || {}
98
+ @body = yield @body
99
+ @body
100
+ elsif data
101
+ unless @body
102
+ opts ||= {}
103
+ opts.is!(Hash).each {|k,v| self.send k, *v }
104
+ @body = data
105
+ end
106
+ throw :done
90
107
  else
91
- raise ArgumentError.new('Bad content type')
108
+ @body
92
109
  end
93
110
  end
111
+ alias :body= :body
94
112
 
95
- @content_type = type
96
- end
113
+ def body?
114
+ !!@body
115
+ end
97
116
 
98
- def content_type= type
99
- content_type type
100
- end
117
+ def content_type in_type = nil
118
+ return @content_type unless in_type
101
119
 
102
- def flash message=nil
103
- @flash ||= Flash.new current.session[:lux_flash]
120
+ in_type = :js if in_type == :javascript
104
121
 
105
- message ? @flash.error(message) : @flash
106
- end
122
+ if in_type.is_a?(Symbol)
123
+ type = Lux::Response::File::MIMME_TYPES[in_type]
124
+ raise ArgumentError.new('Bad content type: %s' % in_type) unless type
125
+ else
126
+ type = in_type
127
+ end
107
128
 
108
- def send_file file, opts={}
109
- ::Lux::Response::File.new(file, opts).send
110
- end
129
+ @content_type ||= type
130
+ end
111
131
 
112
- # redirect '/foo'
113
- # redirect :back, info: 'bar ...'
114
- def redirect where, opts={}
115
- where = current.request.env['HTTP_REFERER'].or('/') if where == :back
116
- where = "#{current.request.path}#{where}" if where[0,1] == '?'
117
- where = current.host + where unless where.include?('://')
132
+ def content_type= type
133
+ content_type type
134
+ end
118
135
 
119
- # local redirect
120
- if where.include?(current.host)
121
- redirect_var = Lux.config.redirect_var || :_r
136
+ def flash message = nil
137
+ @flash ||= Flash.new current.session[:lux_flash]
138
+ message ? @flash.error(message) : @flash
139
+ end
140
+
141
+ def send_file file, opts = {}
142
+ ::Lux::Response::File.new(opts.merge(file: file)).send
143
+ end
144
+
145
+ # redirect_to '/foo'
146
+ # redirect_to :back, info: 'bar ...'
147
+ def redirect_to where, opts = {}
148
+ Lux.log { ' Redirected to "%s" from: %s' % [where, Lux.app_caller] }
149
+
150
+ opts = { info: opts } if opts.is_a?(String)
151
+
152
+ if where == :self
153
+ where = current.request.path
154
+ elsif where == :back
155
+ where = current.request.env['HTTP_REFERER'].or('/')
156
+ elsif where[0,1] == '?'
157
+ where = "#{current.request.path}#{where}"
158
+ # elsif !where.include?('://')
159
+ # where = current.host + where
160
+ end
122
161
 
123
- url = Url.new where
124
- url[redirect_var] = current.request.params[redirect_var].to_i + 1
162
+ if where.start_with?('/') || opts.delete(:redirect_tracker)
163
+ redirect_var = Lux.config[:redirect_var] || :_r
164
+ url = Url.new where
165
+ url[redirect_var] = current.request.params[redirect_var].to_i + 1
125
166
 
126
- where =
127
- if opts.delete(:silent)
167
+ where = if opts.delete(:silent)
128
168
  url.delete redirect_var
129
169
  url.to_s
130
170
  else
131
- url[redirect_var] > 3 ? '/' : url.to_s
171
+ url[redirect_var].to_i > 3 ? '/' : url.to_s
132
172
  end
173
+ end
174
+
175
+ @status = opts.delete(:status) || 302
176
+ opts.map { |k,v| flash.send(k, v) }
177
+
178
+ @body = <<~PAGE
179
+ <html>
180
+ <head>
181
+ <title>redirecting</title>
182
+ </head>
183
+ <body>
184
+ <p>redirecting to #{where}</p>
185
+ <p>#{opts.values.join("\n")}</p>
186
+ <script>location.href = '#{where}'</script>
187
+ </body>
188
+ </html>
189
+ PAGE
190
+
191
+ @headers['location'] = where
192
+ @headers['access-control-expose-headers'] ||= 'Location'
193
+
194
+ # if we do not have this here, controller will proceed executing code after redirect_to
195
+ throw :done
133
196
  end
134
197
 
135
- @status = opts.delete(:status) || 302
136
- opts.map { |k,v| flash.send(k, v) }
198
+ def permanent_redirect_to where
199
+ redirect_to where, status: 301
200
+ end
137
201
 
138
- @body = %[redirecting to #{where}\n\n#{opts.values.join("\n")}]
202
+ # auth { |user, pass| [user, pass] == ['foo', 'bar'] }
203
+ def auth realm: nil, message: nil
204
+ if auth = current.request.env['HTTP_AUTHORIZATION']
205
+ credentials = auth.to_s.split('Basic ', 2)[1].unpack("m*").first.split(':', 2)
206
+ return true if yield *credentials
207
+ end
139
208
 
140
- @headers['location'] = where
141
- @headers['access-control-expose-headers'] ||= 'Location'
209
+ header('WWW-Authenticate', 'Basic realm="%s"' % realm.or('default'))
210
+ body message || 'HTTP 401 Authorization needed', status: 401
211
+ end
142
212
 
143
- throw :done
144
- end
213
+ def render
214
+ write_response_body
215
+ write_response_header
145
216
 
146
- def permanent_redirect where
147
- redirect where, status:301
148
- end
217
+ @status ||= 200
149
218
 
150
- # auth { |user, pass| [user, pass] == ['foo', 'bar'] }
151
- def auth relam=nil
152
- if auth = current.request.env['HTTP_AUTHORIZATION']
153
- credentials = auth.to_s.split('Basic ', 2)[1].unpack("m*").first.split(':', 2)
154
- return true if yield *credentials
155
- end
219
+ Lux.log do
220
+ log_data = " #{@status}, #{@data.to_s.length}, #{(@body.bytesize.to_f/1024).round(1)}kb, #{@headers['x-lux-speed']}"
221
+ log_data += " (#{current.request.url})" if current.nav.format
156
222
 
157
- status 401
158
- header('WWW-Authenticate', 'Basic realm="%s"' % relam.or('default'))
159
- body 'HTTP 401 Authorization needed'
160
- throw :done
161
- end
223
+ [200, 304].include?(@status) ? log_data : log_data.magenta
224
+ end
162
225
 
163
- def write_response_body
164
- unless @body
165
- @status = 204
166
- @body = 'Lux HTTP ERROR 204: NO CONTENT'
226
+ if current.request.request_method == 'HEAD'
227
+ @body = ''
228
+ end
229
+
230
+ [@status, @headers.to_h, [@body]]
167
231
  end
168
232
 
169
- # respond as JSON if we recive hash
170
- if @body.kind_of?(Hash)
171
- @body = Lux.dev? ? JSON.pretty_generate(@body) : JSON.generate(@body)
233
+ def rack klass
234
+ data = klass.call current.env
235
+ @headers.merge data[1]
236
+ body data[2].first, status:data[0]
237
+ end
172
238
 
173
- if current.request.params[:callback]
174
- @body = "#{current.request.params[:callback]}(#{ret})"
175
- @content_type ||= 'text/javascript'
176
- else
177
- @content_type ||= 'application/json'
178
- end
239
+ def public?
240
+ @headers['cache-control'].to_s.include?('public')
241
+ end
179
242
 
180
- @body += "\n"
181
- else
182
- # if somebody sets @content_type, respect that
183
- @body = @body.to_s unless @body.kind_of?(String)
184
- @content_type ||= 'text/plain' if @body[0,1] != '<'
185
- @content_type ||= 'text/html'
243
+ def cached?
244
+ @max_age > 0
245
+ end
246
+
247
+ def is_bot?
248
+ current.request.user_agent.to_s.include?('Googlebot')
186
249
  end
187
- end
188
250
 
189
- def write_response_header
190
- # cache-control
191
- @headers['cache-control'] ||= Proc.new do
192
- cc = ['max-age=%d' % max_age]
193
- cc.push max_age > 0 ? 'public, no-cache' : 'private, must-revalidate'
194
- cc.join(', ')
195
- end.call
251
+ private
196
252
 
197
- current.session[:lux_flash] = flash.to_h
253
+ def write_response_body
254
+ unless @body
255
+ @status = 204
256
+ @body = 'Lux HTTP ERROR 204: NO CONTENT'
257
+ end
258
+
259
+ # respond as JSON if we recive hash
260
+ if @body.kind_of?(Hash)
261
+ @body = Lux.env.screen_log? ? JSON.pretty_generate(@body) : JSON.generate(@body)
262
+
263
+ if current.request.params[:callback]
264
+ @body = "#{current.request.params[:callback]}(#{ret})"
265
+ @content_type ||= 'text/javascript'
266
+ else
267
+ @content_type ||= 'application/json'
268
+ end
198
269
 
199
- # dont annd cookies to public pages (images, etc..)
200
- unless @headers['cache-control'].index('public')
201
- cookie = current.session.generate_cookie
202
- @headers['set-cookie'] = cookie if cookie
270
+ @body += "\n"
271
+ else
272
+ # if somebody sets @content_type, respect that
273
+ # @body = @body.to_s unless @body.kind_of?(String)
274
+ @content_type ||= 'text/plain' if @body[0,1] != '<'
275
+ @content_type ||= 'text/html'
276
+ end
203
277
  end
204
278
 
205
- etag(@body) if current.request.request_method == 'GET'
279
+ def write_response_header
280
+ current.session[:lux_flash] = flash.to_h
206
281
 
207
- @headers['x-lux-speed'] = "#{((Time.monotonic - @render_start)*1000).round(1)} ms"
208
- @headers['content-type'] ||= "#{@content_type}; charset=utf-8"
209
- @headers['content-length'] = @body.bytesize.to_s
282
+ if current.session[:lux_flash].keys.length != 0
283
+ self.max_age = 0
284
+ end
210
285
 
211
- # if "no-store" is present then HTTP_IF_NONE_MATCH is not sent from browser
212
- end
286
+ # cache-control
287
+ @headers['cache-control'] ||= begin
288
+ cc = []
289
+ cc.push max_age > 0 ? 'public' : 'private, must-revalidate'
290
+ cc.push 'max-age=%d' % max_age
291
+ cc.push 'stale-while-revalidate=%d' % @stale_while_revalidate if @stale_while_revalidate
292
+ cc.join(', ')
293
+ end
213
294
 
214
- def render
215
- write_response_body
216
- write_response_header
295
+ if self.max_age == 0 && !self.is_bot?
296
+ cookie = current.session.generate_cookie
297
+ @headers['set-cookie'] = cookie if cookie
298
+ end
217
299
 
218
- @status ||= 200
219
- Lux.log " #{@status}, #{@headers['x-lux-speed']}"
300
+ if current.request.request_method == 'GET'
301
+ catch(:done) { etag(@body) }
302
+ end
220
303
 
221
- [@status, @headers.to_h, [@body]]
304
+ # @headers['access-control-allow-credentials'] = 'true'
305
+ # if "no-store" is present then HTTP_IF_NONE_MATCH is not sent from browser
306
+ @headers['x-lux-speed'] = "#{((Time.monotonic - @render_start)*1000).round(1)}ms"
307
+ @headers['content-type'] ||= "#{@content_type}; charset=utf-8"
308
+ @headers['content-length'] = @body.bytesize.to_s
309
+ @headers['content-length'] = @body.bytesize.to_s
310
+ end
222
311
  end
223
-
224
312
  end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lux
4
+ class Template
5
+ class Helper
6
+ attr_reader :_source_object
7
+
8
+ # create helper object that cah be used in template render
9
+ def initialize instance, *list
10
+ extend ApplicationHelper
11
+
12
+ @_source_object = instance
13
+
14
+ list.flatten.compact.each do |el|
15
+ el = el.to_s.classify+'Helper'
16
+ extend el.constantize
17
+ end
18
+
19
+ local_vars = instance.class == Hash ? instance : instance.instance_variables_hash
20
+
21
+ # locals overide globals
22
+ for k, v in local_vars
23
+ instance_variable_set("@#{k.to_s.sub('@','')}", v)
24
+ end
25
+
26
+ # helper.instance_exec &block if block
27
+ end
28
+
29
+ define_method(:current) { Lux.current }
30
+ define_method(:request) { Lux.current.request }
31
+ define_method(:params) { Lux.current.params }
32
+ define_method(:nav) { Lux.current.nav }
33
+ define_method(:get) { |name| instance_variable_get('@%s' % name) }
34
+
35
+ def no_white_space
36
+ yield.gsub(/>\s+</,'><')
37
+ end
38
+
39
+ # = content :foo do ... # define
40
+ # = content :foo? ? true : false # ceheck existance
41
+ # = content :foo # get content
42
+ def content key
43
+ name = 'haml_content_%s' % key
44
+
45
+ if name.end_with?('?')
46
+ haz = !!Lux.current.var[name.sub(/\?$/, '')]
47
+ if block_given?
48
+ haz ? "#{yield}" : ''
49
+ else
50
+ haz
51
+ end
52
+ elsif block_given?
53
+ Lux.current.var[name] = "#{yield}"
54
+ nil
55
+ else
56
+ Lux.current.var[name]
57
+ end
58
+ end
59
+
60
+ def capture_proc
61
+ proc { |*args| "#{yield(*args)}" }
62
+ end
63
+
64
+ # renders just template but it is called
65
+ # = render :_link, link:link
66
+ # = render 'main/links/_link', link:link
67
+ def render name = nil, locals = {}
68
+ if !name
69
+ return InlineRenderProxy.new(self)
70
+ elsif name.is_array?
71
+ return name.map { |b| render(b) }.join("\n")
72
+ elsif name.respond_to?(:db_schema)
73
+ raise 'not supported'
74
+ path = Lux.current.var.root_template_path.split('/')[1]
75
+ table_name = name.class.name.tableize
76
+ locals[table_name.singularize.to_sym] = name
77
+ eval "@_#{table_name.singularize} = name"
78
+ name = "#{path}/#{table_name}/_#{table_name.singularize}"
79
+ elsif !name.to_s.start_with?('./')
80
+ template_path = Lux.current.var.root_template_path || './app/views'
81
+ name = Pathname.new(template_path).join(name.to_s).to_s
82
+ name = './app/views' + name if name.starts_with?('/')
83
+ end
84
+
85
+ for k, v in locals
86
+ instance_variable_set("@_#{k}", v)
87
+ end
88
+
89
+ if block_given?
90
+ name = "#{name}/layout" unless name.index('/')
91
+
92
+ Lux::Template.render(self, name) { yield() }
93
+ else
94
+ Lux::Template.render(self, name)
95
+ end
96
+ end
97
+
98
+ def cache name = nil, opts = {}, &block
99
+ if opts.class == Integer
100
+ opts = { ttl: opts }
101
+ elsif name.is_a?(Hash)
102
+ opts = name
103
+ name = ''
104
+ else
105
+ name = Lux.cache.generate_key(name)
106
+ end
107
+
108
+ opts[:ttl] ||= 1.hour
109
+ key = 'view:'+name+block.source_location.join(':')+Lux.config.deploy_timestamp.to_s
110
+ Lux.cache.fetch(key, opts) { yield }
111
+ end
112
+
113
+ # helper(:main).method
114
+ def helper *names
115
+ Lux::Template::Helper.new(self, *names)
116
+ end
117
+
118
+ def once id = nil
119
+ Lux.current.once("template-#{id || caller[0]}") do
120
+ block_given? ? yield : true
121
+ end
122
+ end
123
+
124
+ def flash
125
+ Lux.current.response.flash
126
+ end
127
+ end
128
+ end
129
+ end
130
+
@@ -0,0 +1,31 @@
1
+ # enables variable access as a method call to render helper
2
+ # = render :_menu, foo: 123, bar: nil
3
+ # render.foo # 123
4
+ # render.bar ||= 456
5
+ # render.bar # 456
6
+ module Lux
7
+ class InlineRenderProxy
8
+ def initialize context, &block
9
+ @context = context
10
+ @block = block
11
+ end
12
+
13
+ def method_missing name, value=nil
14
+ name = name.to_s
15
+
16
+ if name.sub!('=', '')
17
+ @context.instance_variable_set("@_#{name}", value)
18
+ end
19
+
20
+ @context.instance_variable_get("@_#{name}")
21
+ end
22
+ end
23
+
24
+ def [] name
25
+ @context.instance_variable_get("@_#{name}")
26
+ end
27
+
28
+ def []= name, value
29
+ @context.instance_variable_set("@_#{name}", value)
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module Lux
2
+ def template
3
+ Lux::Template
4
+ end
5
+ end