lux-fw 0.2.3 → 0.5.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.version +1 -1
  3. data/bin/README.md +33 -0
  4. data/bin/build_gem +76 -0
  5. data/bin/cli/config.rb +44 -0
  6. data/bin/cli/console.rb +61 -0
  7. data/bin/cli/dbconsole.rb +8 -0
  8. data/bin/cli/eval.rb +32 -0
  9. data/bin/cli/generate.rb +88 -0
  10. data/bin/cli/get.rb +12 -0
  11. data/bin/cli/new.rb +22 -0
  12. data/bin/cli/routes.rb +90 -0
  13. data/bin/cli/secrets.rb +40 -0
  14. data/bin/cli/server.rb +24 -0
  15. data/bin/cli/stats.rb +133 -0
  16. data/bin/lux +24 -65
  17. data/lib/common/class_attributes.rb +40 -64
  18. data/lib/common/class_callbacks.rb +34 -51
  19. data/lib/common/crypt.rb +10 -8
  20. data/lib/common/free_struct.rb +42 -0
  21. data/lib/common/hash_with_indifferent_access.rb +1 -1
  22. data/lib/common/html_tag_builder.rb +26 -2
  23. data/lib/common/url.rb +58 -40
  24. data/lib/lux/application/application.rb +290 -117
  25. data/lib/lux/application/lib/nav.rb +64 -38
  26. data/lib/lux/application/lib/render.rb +2 -1
  27. data/lib/lux/cache/cache.rb +87 -62
  28. data/lib/lux/cache/lib/{ram.rb → memory.rb} +5 -7
  29. data/lib/lux/cache/lib/null.rb +6 -8
  30. data/lib/lux/config/config.rb +109 -52
  31. data/lib/lux/config/lib/plugin.rb +65 -0
  32. data/lib/lux/config/lib/secrets.rb +48 -0
  33. data/lib/lux/controller/controller.rb +241 -0
  34. data/lib/lux/current/current.rb +33 -47
  35. data/lib/lux/current/lib/session.rb +72 -0
  36. data/lib/lux/delayed_job/delayed_job.rb +14 -7
  37. data/lib/lux/delayed_job/lib/memory.rb +7 -5
  38. data/lib/lux/delayed_job/lib/redis.rb +1 -1
  39. data/lib/lux/error/error.rb +164 -62
  40. data/lib/lux/event_bus/event_bus.rb +27 -0
  41. data/lib/lux/lux.rb +103 -66
  42. data/lib/lux/mailer/mailer.rb +23 -25
  43. data/lib/lux/response/lib/file.rb +81 -0
  44. data/lib/lux/response/lib/header.rb +14 -1
  45. data/lib/lux/response/response.rb +64 -56
  46. data/lib/lux/view/cell.rb +102 -0
  47. data/lib/lux/{helper → view}/helper.rb +39 -23
  48. data/lib/lux/view/lib/cell_helpers.rb +29 -0
  49. data/lib/lux/{helper/helpers/mailer_helper.rb → view/lib/helper_modules.rb} +7 -1
  50. data/lib/lux/{template/template.rb → view/view.rb} +21 -24
  51. data/lib/lux-fw.rb +4 -2
  52. data/lib/overload/array.rb +12 -6
  53. data/lib/overload/blank.rb +0 -1
  54. data/lib/overload/dir.rb +18 -0
  55. data/lib/overload/file.rb +1 -6
  56. data/lib/overload/hash.rb +56 -13
  57. data/lib/overload/integer.rb +2 -2
  58. data/lib/overload/it.rb +4 -4
  59. data/lib/overload/object.rb +37 -8
  60. data/lib/overload/{r.rb → raise_variants.rb} +23 -4
  61. data/lib/overload/string.rb +22 -6
  62. data/misc/demo/app/cells/demo_cell.rb +12 -0
  63. data/misc/demo/app/controllers/application_controller.rb +7 -0
  64. data/misc/demo/app/controllers/main/root_controller.rb +9 -0
  65. data/misc/demo/app/routes.rb +5 -0
  66. data/misc/demo/config/application.rb +14 -0
  67. data/misc/demo/config/assets.rb +6 -0
  68. data/misc/demo/config/environment.rb +7 -0
  69. data/misc/puma_auto_tune.rb +43 -0
  70. data/misc/unicorn.rb +37 -0
  71. data/{lib/lux → plugins}/api/api.rb +46 -29
  72. data/plugins/api/lib/attr.rb +31 -0
  73. data/{lib/lux → plugins}/api/lib/dsl.rb +3 -6
  74. data/{lib/lux → plugins}/api/lib/error.rb +0 -0
  75. data/{lib/lux → plugins}/api/lib/model_api.rb +51 -12
  76. data/{lib/lux → plugins}/api/lib/response.rb +31 -17
  77. data/{bin/cli/am → plugins/db/auto_migrate/auto_migrate.rb} +18 -35
  78. data/plugins/db/helpers/array_search.rb +27 -0
  79. data/plugins/db/helpers/before_save_filters.rb +32 -0
  80. data/plugins/db/helpers/composite_primary_keys.rb +36 -0
  81. data/plugins/db/helpers/core.rb +94 -0
  82. data/plugins/db/helpers/dataset_methods.rb +138 -0
  83. data/plugins/db/helpers/enums_plugin.rb +52 -0
  84. data/plugins/db/helpers/find_precache.rb +31 -0
  85. data/plugins/db/helpers/link_objects.rb +84 -0
  86. data/plugins/db/helpers/schema_checks.rb +83 -0
  87. data/plugins/db/helpers/typero_adapter.rb +71 -0
  88. data/plugins/db/logger/config.rb +22 -0
  89. data/plugins/db/logger/lux_response_adapter.rb +10 -0
  90. data/plugins/db/paginate/helper.rb +32 -0
  91. data/plugins/db/paginate/sequel_adapter.rb +23 -0
  92. data/plugins/exceptions/simple_exception.rb +64 -0
  93. data/plugins/favicon/favicon.rb +10 -0
  94. data/plugins/html/html_form.rb +118 -0
  95. data/plugins/html/html_input.rb +98 -0
  96. data/plugins/html/html_menu.rb +79 -0
  97. data/plugins/html/input_types.rb +346 -0
  98. data/plugins/js_widgets/js_widgets.rb +15 -0
  99. data/plugins/oauth/lib/facebook.rb +35 -0
  100. data/plugins/oauth/lib/github.rb +38 -0
  101. data/plugins/oauth/lib/google.rb +41 -0
  102. data/plugins/oauth/lib/linkedin.rb +41 -0
  103. data/plugins/oauth/lib/stackexchange.rb +41 -0
  104. data/plugins/oauth/lib/twitter.rb +38 -0
  105. data/plugins/oauth/oauth.rb +42 -0
  106. data/{lib/common → plugins/policy}/policy.rb +6 -7
  107. data/tasks/loader.rb +49 -0
  108. metadata +151 -49
  109. data/bin/cli/assets +0 -41
  110. data/bin/cli/console +0 -51
  111. data/bin/cli/dev +0 -1
  112. data/bin/cli/eval +0 -24
  113. data/bin/cli/exceptions +0 -62
  114. data/bin/cli/generate +0 -86
  115. data/bin/cli/get +0 -5
  116. data/bin/cli/nginx +0 -34
  117. data/bin/cli/production +0 -1
  118. data/bin/cli/render +0 -18
  119. data/bin/cli/routes +0 -14
  120. data/bin/cli/server +0 -4
  121. data/bin/cli/stat +0 -1
  122. data/bin/cli/systemd +0 -36
  123. data/bin/txt/nginx.conf +0 -46
  124. data/bin/txt/siege-and-puma.txt +0 -3
  125. data/lib/common/base32.rb +0 -47
  126. data/lib/common/dynamic_class.rb +0 -28
  127. data/lib/common/folder_model.rb +0 -50
  128. data/lib/common/generic_model.rb +0 -62
  129. data/lib/lux/application/lib/plugs.rb +0 -10
  130. data/lib/lux/application/lib/route_test.rb +0 -64
  131. data/lib/lux/cache/lib/memcached.rb +0 -3
  132. data/lib/lux/cell/cell.rb +0 -261
  133. data/lib/lux/current/lib/static_file.rb +0 -103
  134. data/lib/lux/helper/helpers/application_helper.rb +0 -3
  135. data/lib/lux/helper/helpers/html_helper.rb +0 -3
  136. data/lib/overload/auto_loader.rb +0 -27
  137. data/lib/overload/module.rb +0 -10
  138. data/lib/overload/string_inflections.rb +0 -8
@@ -1,144 +1,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Main application router
4
+
1
5
  class Lux::Application
2
- ClassCallbacks.define self, :before, :after, :routes, :on_error
6
+ class_callback :config # pre boot app config
7
+ class_callback :web_boot # rack_handler is passed as argument
8
+ class_callback :info # called by "lux config" cli
9
+ class_callback :before # before any page load
10
+ class_callback :routes # routes resolve
11
+ class_callback :after # after any page load
12
+
13
+ web_boot do |rack_handler|
14
+ # deafult host is required
15
+ unless Lux.config.host.to_s.include?('http')
16
+ raise 'Invalid "Lux.config.host"'
17
+ end
3
18
 
4
- attr_reader :route_target
19
+ if Lux.config(:dump_errors)
20
+ require 'better_errors'
5
21
 
6
- # define common http methods as constants
7
- [:get, :head, :post, :delete, :put, :patch].map(&:to_s).map(&:upcase).each { |m| eval "#{m} ||= '#{m}'" }
22
+ rack_handler.use BetterErrors::Middleware
23
+ BetterErrors.editor = :sublime
24
+ end
25
+ end
8
26
 
9
27
  ###
10
28
 
11
- def initialize current
12
- @current = current
13
- @route_test = Lux::Application::RouteTest.new self
14
- end
29
+ attr_reader :route_target, :current
15
30
 
16
- def debug
17
- { :@locale=>@locale, :@nav=>nav, :@subdomain=>@subdomain, :@domain=>@domain }
31
+ # define common http methods as get? methods
32
+ [:get, :head, :post, :delete, :put, :patch].map(&:to_s).each do |m|
33
+ define_method('%s?' % m) { @current.request.request_method == m.upcase }
18
34
  end
19
35
 
20
- def body?
21
- @current.response.body ? true : false
22
- end
36
+ # simple one liners and delegates
37
+ define_method(:request) { @current.request }
38
+ define_method(:params) { @current.request.params }
39
+ define_method(:nav) { @current.nav }
40
+ define_method(:redirect) { |where, flash={}| @current.redirect where, flash }
41
+ define_method(:body?) { response.body? }
23
42
 
24
- def body data
25
- @current.response.body data
26
- end
43
+ def initialize current
44
+ raise 'Config is not loaded (Lux.start not called), cant render page' unless Lux.config.lux_config_loaded
27
45
 
28
- def current
29
- # Lux.current
30
- @current
46
+ @current = current
31
47
  end
32
48
 
33
- def nav
34
- @current.nav
49
+ # Triggers HTTP page error
50
+ # ```
51
+ # error.not_found
52
+ # error.not_found 'Doc not fount'
53
+ # error(404)
54
+ # error(404, 'Doc not fount')
55
+ # ```
56
+ def error code=nil, message=nil
57
+ if code
58
+ error = Lux::Error.new code
59
+ error.message = message if message
60
+ raise error
61
+ else
62
+ Lux::Error::AutoRaise
63
+ end
35
64
  end
36
65
 
37
- def params
38
- @current.params
39
- end
66
+ # Quick response to page body
67
+ # ```
68
+ # response 'ok' if nav.root == 'healthcheck'
69
+ # ```
70
+ def response body=nil, status=nil
71
+ return @current.response unless body
40
72
 
41
- def redirect where, msgs={}
42
- @current.redirect where, msgs
73
+ response.status status || 200
74
+ response.body body
43
75
  end
44
76
 
45
- def request
46
- @current.request
47
- end
77
+ # Tests current root against the string to get a mach.
78
+ # Used by map function
79
+ def test? route
80
+ root = nav.root.to_s
48
81
 
49
- # gets only root
50
- def root cell
51
- if RouteTest::LUX_PRINT_ROUTES
52
- @route_target = cell
53
- @route_test.print_route ''
82
+ ok = case route
83
+ when String
84
+ root == route.sub(/^\//,'')
85
+ when Symbol
86
+ route.to_s == root
87
+ when Regexp
88
+ !!(route =~ root)
89
+ when Array
90
+ !!route.map(&:to_s).include?(root)
91
+ else
92
+ raise 'Route type %s is not supported' % route.class
54
93
  end
55
94
 
56
- call cell unless nav.root
57
- end
95
+ nav.shift if ok
58
96
 
59
- def done?
60
- throw :done if @current.response.body
97
+ ok
61
98
  end
62
99
 
63
- def get?
64
- @current.request.request_method == 'GET'
100
+ # Matches if there is not root in nav
101
+ # Example calls MainController.action(:index) if in root
102
+ # ```
103
+ # root 'main#index'
104
+ # ```
105
+ def root target
106
+ call target unless nav.root
65
107
  end
66
108
 
67
- def post?
68
- @current.request.request_method == 'POST'
69
- end
109
+ # standard route match
110
+ # match '/:city/people', Main::PeopleController
111
+ def match base, target
112
+ base = base.split('/').slice(1, 100)
70
113
 
71
- def plug name, &block
72
- done?
114
+ base.each_with_index do |el, i|
115
+ if el[0,1] == ':'
116
+ params[el.sub(':','').to_sym] = nav.path[i]
117
+ else
118
+ return unless el == nav.path[i]
119
+ end
120
+ end
73
121
 
74
- m = "#{name}_plug".to_sym
75
- return Lux.error(%[Method "#{m}" not defined in #{self.class}]) unless respond_to?(m)
76
- send m, &block
122
+ call target
123
+ end
77
124
 
78
- done?
125
+ @@namespaces ||= {}
126
+ def self.namespace name, &block
127
+ @@namespaces[name] = block
79
128
  end
80
129
 
81
- # map Main::RootCell do
82
- # action :about
83
- # action '/verified-user'
130
+ # Matches namespace block in a path
131
+ # if returns true value, match is positive and nav is shifted
132
+ # if given `Symbol`, it will call the function to do a match
133
+ # if given `String`, it will match the string value
134
+ # ```
135
+ # self.namespace :city do
136
+ # @city = City.first slug: nav.root
137
+ # !!@city
84
138
  # end
85
- # map api: ApiCell
86
- def map route_object, &block
87
- done?
88
-
89
- if route_object.class == Hash
90
- @route_name = route_object.keys.first
91
- @route_target = route_object.values.first
139
+ # namespace 'dashboard' do
140
+ # map orgs: 'dashboard/orgs'
141
+ # end
142
+ # ```
143
+ def namespace name
144
+ if String === name
145
+ return unless test?(name.to_s)
92
146
  else
93
- @route_name = nav.root
94
- @route_target = route_object
95
-
96
- if block_given?
97
- # map :dashboard do
98
- # map o: DashboardOrgsCell
99
- # root DashboardCell
100
- # end
101
- if route_object.class == Symbol
102
- if test?(route_object)
103
- current.nav.shift_to_root
104
- instance_exec &block
105
- raise NotFoundError.new %[Route "#{route_object}" matched but nothing is called]
106
- end
107
-
108
- return
109
- end
147
+ if @@namespaces[name]
148
+ return unless instance_exec &@@namespaces[name]
149
+ nav.shift
110
150
  else
111
- @route_test.print_route '*'
112
- return route_object.call
151
+ raise ArgumentError.new('Namespace block :%s is not defined' % name)
113
152
  end
114
153
  end
115
154
 
155
+ yield
156
+
157
+ raise Lux::Error.not_found("Namespace <b>:#{name}</b> matched but nothing is called")
158
+ end
159
+
160
+ # Matches given subdomain name
161
+ def subdomain name
162
+ return unless nav.subdomain == name
163
+ error.not_found 'Subdomain "%s" matched but nothing called' % name
164
+ end
165
+
166
+ # Main routing object, maps path part to target
167
+ # if path part is positively matched with `test?` method, target is called with `call` method
168
+ # ```
169
+ # map api: ApiController
170
+ # map api: 'api'
171
+ # map [:api, ApiController]
172
+ # map 'main/root' do
173
+ # map [:login, :signup] => 'main/root'
174
+ # map Main::RootController do
175
+ # map :about
176
+ # map '/verified-user'
177
+ # end
178
+ # ```
179
+ def map route_object
180
+ klass = nil
181
+ route = nil
182
+ action = nil
183
+
184
+ # map 'root' do
185
+ # ...
116
186
  if block_given?
117
- @route_test.instance_exec &block
187
+ @lux_action_target = route_object
188
+ yield
189
+ @lux_action_target = nil
118
190
  return
119
- end
191
+ elsif @lux_action_target
192
+ klass = @lux_action_target
193
+ route = route_object
194
+ action = route_object
195
+
196
+ # map :foo => :some_action
197
+ if route_object.is_a?(Hash)
198
+ route = route_object.keys.first
199
+ action = route_object.values.first
200
+ end
120
201
 
121
- @route_test.print_route '%s/*' % @route_name
202
+ if test?(route)
203
+ call klass, action
204
+ else
205
+ return
206
+ end
207
+ end
122
208
 
123
- call @route_target if test? @route_name
124
- end
209
+ case route_object
210
+ when String
211
+ # map 'root#call'
212
+ call route_object
213
+ when Hash
214
+ route = route_object.keys.first
215
+ klass = route_object.values.first
216
+
217
+ if route.class == Array
218
+ # map [:foo, :bar] => 'root'
219
+ for route_action in route
220
+ if test?(route_action)
221
+ call klass, route_action
222
+ end
223
+ end
125
224
 
126
- def action route_object
127
- map route_object.values.first do
128
- action route_object.keys.first
225
+ return
226
+ elsif route.is_a?(String) && route[0,1] == '/'
227
+ # map '/skils/:skill' => 'main/skills#show'
228
+ return match route, klass
229
+ end
230
+ when Array
231
+ # map [:foo, 'main/root']
232
+ route, klass = *route_object
233
+ else
234
+ Lux.error 'Unsupported route type "%s"' % route_object.class
129
235
  end
130
- end
131
236
 
132
- def test? route
133
- @route_test.test? route
237
+ test?(route) ? call(klass) : nil
134
238
  end
135
239
 
240
+ # Calls target action in a controller, if no action is given, defaults to :index
241
+ # ```
136
242
  # call :api_router
137
- # call Main::UsersCell
138
- # call Main::UsersCell, :index
243
+ # call proc { 'string' }
244
+ # call proc { [400, {}, 'error: ...'] }
245
+ # call [200, {}, ['ok']]
246
+ # call Main::UsersController
247
+ # call Main::UsersController, :index
248
+ # call [Main::UsersController, :index]
139
249
  # call 'main/orgs#show'
250
+ # ```
140
251
  def call object=nil, action=nil
141
- done?
252
+ # log original app caller
253
+ root = Lux.root.join('app/').to_s
254
+ sources = caller.select { |it| it.include?(root) }.map { |it| 'app/' + it.sub(root, '').split(':in').first }
255
+ action = action.gsub('-', '_').to_sym if action && action.is_a?(String)
256
+
257
+ Lux.log ' Routed from: %s' % sources.join(' ') if sources.first
142
258
 
143
259
  case object
144
260
  when Symbol
@@ -146,49 +262,106 @@ class Lux::Application
146
262
  when Hash
147
263
  object = [object.keys.first, object.values.first]
148
264
  when String
149
- if object.include?('#')
150
- object = object.split('#')
151
- object[0] = ('%s_cell' % object[0]).classify.constantize
265
+ object, action = object.split('#') if object.include?('#')
266
+ when Array
267
+ if object[0].class == Integer && object[1].class == Hash
268
+ # [200, {}, 'ok']
269
+ for key, value in object[1]
270
+ response.header key, value
271
+ end
272
+
273
+ response.status object[0]
274
+ response.body object[2]
152
275
  else
153
- object = ('%s_cell' % object).classify.constantize
276
+ object, action = object
277
+ end
278
+ when Proc
279
+ case data = object.call
280
+ when Array
281
+ response.status = data.first
282
+ response.body data[2]
283
+ else
284
+ response.body data
154
285
  end
155
286
  end
156
287
 
157
- object, action = object if object.is_a? Array
288
+ # figure our action unless defined
289
+ unless action
290
+ id =
291
+ if respond_to?(:id?)
292
+ nav.root { |root_id| id?(root_id) }
293
+ else
294
+ nav.root { |root_id| root_id.is_numeric? ? root_id.to_i : nil }
295
+ end
158
296
 
159
- if action
160
- object.action action
161
- else
162
- object.call
297
+ if id
298
+ current.nav.id = id
299
+ action = nav.shift || :show
300
+ else
301
+ action = nav.shift || :index
302
+ end
163
303
  end
164
304
 
165
- if body?
166
- done?
167
- else
305
+ object = ('%s_controller' % object).classify.constantize if object.is_a?(String)
306
+
307
+ controller_name = "app/controllers/#{object.to_s.underscore}.rb"
308
+ Lux.log ' %s' % controller_name
309
+ current.files_in_use controller_name
310
+
311
+ object.action action.to_sym
312
+
313
+ unless response.body
168
314
  Lux.error 'Lux cell "%s" called via route "%s" but page body is not set' % [object, nav.root]
169
315
  end
170
316
  end
171
317
 
172
- def main
173
- catch(:done) do
174
- begin
175
- ClassCallbacks.execute self, :before
176
- ClassCallbacks.execute self, :routes
177
- ClassCallbacks.execute self, :after
178
- rescue => e
179
- ClassCallbacks.execute self, :on_error, e
180
- end
181
- end
318
+ # Action to do if there is an application error.
319
+ # You want to overload this in a production.
320
+ def on_error error
321
+ raise error
182
322
  end
183
323
 
184
324
  def render
185
- Lux.log "\n#{current.request.request_method.white} #{current.request.path.white}"
325
+ Lux.log "\n#{current.request.request_method.white} #{current.request.url}"
186
326
 
187
327
  Lux::Config.live_require_check! if Lux.config(:auto_code_reload)
188
328
 
189
329
  main
190
330
 
191
- current.response.render
331
+ response.render
332
+ end
333
+
334
+ private
335
+
336
+ # internall call to resolve the routes
337
+ def main
338
+ return if deliver_static_assets
339
+
340
+ catch(:done) do
341
+ class_callback :before
342
+ class_callback :routes unless body?
343
+ end
344
+
345
+ catch(:done) do
346
+ class_callback :after
347
+ end
348
+ rescue => e
349
+ response.body { nil }
350
+
351
+ catch(:done) do
352
+ on_error(e)
353
+ end
354
+ end
355
+
356
+ # Deliver static assets if `Lux.config.serve_static_files == true`
357
+ def deliver_static_assets
358
+ return if body? || !Lux.config(:serve_static_files)
359
+
360
+ ext = request.path.split('.').last
361
+ return unless ext.length > 1 && ext.length < 5
362
+ file = Lux::Response::File.new request.path.sub('/', ''), inline: true
363
+ file.send if file.is_static_file?
192
364
  end
193
365
 
194
- end
366
+ end
367
+
@@ -1,78 +1,104 @@
1
1
  # experiment for different nav in rooter
2
2
 
3
3
  class Lux::Application::Nav
4
- attr_reader :path, :subdomain, :domain, :id
4
+ attr_accessor :path, :id, :format
5
+ attr_reader :original, :subdomain, :domain
5
6
 
6
7
  # acepts path as a string
7
8
  def initialize request
8
9
  @path = request.path.split('/').slice(1, 100) || []
9
- shift_to_root if @path.first
10
+ @original = @path.dup
10
11
 
11
12
  @subdomain = request.host.split('.')
12
13
  @domain = @subdomain.pop(2).join('.')
14
+ @subdomain = @subdomain.join('.')
13
15
  @domain += ".#{@subdomain.pop}" if @domain.length < 6
14
- end
15
16
 
16
- def full
17
- @full = '/%s/%s' % [@root, @path.join('/')]
18
- @full = @full.sub(/\/$/, '')
17
+ set_format
19
18
  end
20
19
 
21
- def shift_to_root
22
- @root.tap do
23
- @root = @path.shift.to_s.gsub('-', '_')
24
- end
20
+ def set_format
21
+ return unless @path.last
22
+ parts = @path.last.split('.')
25
23
 
26
- @root = nil if @root.blank?
24
+ if parts[1]
25
+ @format = parts.pop.to_s.downcase.to_sym
26
+ @path.last = parts.join('.')
27
+ end
28
+ end
27
29
 
28
- @root
30
+ def active_shift
31
+ @active = @path.shift
29
32
  end
30
33
 
31
- def root sub_nav=nil
32
- sub_nav ? ('%s/%s' % [@root, sub_nav]) : @root
34
+ def shift
35
+ return unless @path[0].present?
36
+
37
+ if block_given?
38
+ result = yield(@path[0]) || return
39
+
40
+ result
41
+ else
42
+ active_shift
43
+ end
33
44
  end
34
45
 
35
46
  # used to make admin.lvm.me/users to lvh.me/admin/users
36
47
  def unshift name
37
- @path.unshift @root
38
- @root = name
48
+ @path.unshift name
39
49
  end
40
50
 
41
- def shift
42
- @path.shift
51
+ def root sub_nav=nil
52
+ if block_given?
53
+ return unless @path[0]
54
+
55
+ # shift root in place if yields not nil
56
+ result = yield(@path[0]) || return
57
+ active_shift
58
+ result
59
+ else
60
+ sub_nav ? ('%s/%s' % [@path.first, sub_nav]) : @path.first
61
+ end
43
62
  end
44
63
 
45
- def first
46
- @path.first
64
+ def root= value
65
+ @path[0] = value
47
66
  end
48
67
 
49
- def first= data
50
- @path[0] = data
68
+ def first
69
+ if block_given?
70
+ # shift first in place if yields not nil
71
+ return unless @path[1].present?
72
+ result = yield(@path[1]) || return
73
+ @path.slice!(1,1)
74
+ result
75
+ else
76
+ @path[1]
77
+ end
51
78
  end
52
79
 
53
- def second
54
- @path[1]
80
+ def last
81
+ if block_given?
82
+ # replace root in place if yields not nil
83
+ return unless @path.last.present?
84
+ result = yield(@path.last) || return
85
+ @path.pop
86
+ result
87
+ else
88
+ @path.last
89
+ end
55
90
  end
56
91
 
57
- def last
58
- @path.last
92
+ def second
93
+ @path[2]
59
94
  end
60
95
 
61
- def rest
62
- @path.slice(1, @path.length-1)
96
+ def active
97
+ @active
63
98
  end
64
99
 
65
100
  def to_s
66
- @full
101
+ @path.join('/').sub(/\/$/, '')
67
102
  end
68
103
 
69
- def id
70
- if first && block_given?
71
- if @id = yield(first)
72
- shift
73
- end
74
- end
75
-
76
- @id
77
- end
78
104
  end
@@ -18,6 +18,7 @@ Lux::Application.class_eval do
18
18
  def self.render path='/mock', in_opts={}, &block
19
19
  allowed_opts = [:qs, :post, :method, :session, :cookies]
20
20
  in_opts.keys.each { |k| die "#{k} is not allowed as opts param. allowed are #{allowed_opts}" unless allowed_opts.index(k) }
21
+ # in_opts[:session] = nil unless Hash == in_opts[:session].class
21
22
 
22
23
  opts = {}
23
24
 
@@ -61,7 +62,7 @@ Lux::Application.class_eval do
61
62
  time: response[1]['x-lux-speed'],
62
63
  status: response[0],
63
64
  headers: response[1],
64
- session: current.session,
65
+ session: current.session.hash,
65
66
  body: body
66
67
  }.h
67
68
  end