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
@@ -1,370 +1,128 @@
1
- # frozen_string_literal: true
2
-
3
1
  # Main application router
4
2
 
5
- class Lux::Application
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
18
-
19
- if Lux.config(:dump_errors)
20
- require 'better_errors'
21
-
22
- rack_handler.use BetterErrors::Middleware
23
- BetterErrors.editor = :sublime
24
- end
25
- end
26
-
27
- ###
28
-
29
- attr_reader :route_target, :current
30
-
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 }
34
- end
35
-
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? }
3
+ require_relative './lib/shared'
4
+ require_relative './lib/routes'
42
5
 
43
- def initialize current
44
- raise 'Config is not loaded (Lux.start not called), cant render page' unless Lux.config.lux_config_loaded
6
+ module Lux
7
+ class Application
8
+ include ClassCallbacks
9
+ include Routes
10
+ include Shared
45
11
 
46
- @current = current
47
- end
12
+ define_callback :before # before any page load
13
+ define_callback :routes # routes resolve
14
+ define_callback :after # after any page load
48
15
 
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
16
+ def initialize env, opts={}
17
+ Lux::Current.new env, opts
63
18
  end
64
- end
65
-
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
72
19
 
73
- response.status status || 200
74
- response.body body
75
- throw :done
76
- end
77
-
78
- # Tests current root against the string to get a mach.
79
- # Used by map function
80
- def test? route
81
- root = nav.root.to_s
82
-
83
- ok = case route
84
- when String
85
- root == route.sub(/^\//,'')
86
- when Symbol
87
- route.to_s == root
88
- when Regexp
89
- !!(route =~ root)
90
- when Array
91
- !!route.map(&:to_s).include?(root)
92
- else
93
- raise 'Route type %s is not supported' % route.class
94
- end
95
-
96
- nav.shift if ok
97
-
98
- ok
99
- end
100
-
101
- # Matches if there is not root in nav
102
- # Example calls MainController.action(:index) if in root
103
- # ```
104
- # root 'main#index'
105
- # ```
106
- def root target
107
- call target unless nav.root
108
- end
109
-
110
- # standard route match
111
- # match '/:city/people', Main::PeopleController
112
- def match base, target
113
- base = base.split('/').slice(1, 100)
114
-
115
- base.each_with_index do |el, i|
116
- if el[0,1] == ':'
117
- params[el.sub(':','').to_sym] = nav.path[i]
118
- else
119
- return unless el == nav.path[i]
20
+ # main render called by Lux.call
21
+ def render_base
22
+ if Lux.env.reload_code? && Lux.env.web?
23
+ Lux.config.on_reload_code.call
120
24
  end
121
- end
122
25
 
123
- call target
124
- end
26
+ request_method = request.request_method
125
27
 
126
- @@namespaces ||= {}
127
- def self.namespace name, &block
128
- @@namespaces[name] = block
129
- end
28
+ Lux.log ''
29
+ Lux.log { [request_method.white, request.url].join(' ') }
130
30
 
131
- # Matches namespace block in a path
132
- # if returns true value, match is positive and nav is shifted
133
- # if given `Symbol`, it will call the function to do a match
134
- # if given `String`, it will match the string value
135
- # ```
136
- # self.namespace :city do
137
- # @city = City.first slug: nav.root
138
- # !!@city
139
- # end
140
- # namespace 'dashboard' do
141
- # map orgs: 'dashboard/orgs'
142
- # end
143
- # ```
144
- def namespace name
145
- if String === name
146
- return unless test?(name.to_s)
147
- else
148
- if @@namespaces[name]
149
- return unless instance_exec &@@namespaces[name]
150
- nav.shift
151
- else
152
- raise ArgumentError.new('Namespace block :%s is not defined' % name)
31
+ if request.post?
32
+ Lux.log { request.params.to_h.to_jsonp }
153
33
  end
154
- end
155
-
156
- yield
157
-
158
- raise Lux::Error.not_found("Namespace <b>:#{name}</b> matched but nothing is called")
159
- end
160
-
161
- # Matches given subdomain name
162
- def subdomain name
163
- return unless nav.subdomain == name
164
- error.not_found 'Subdomain "%s" matched but nothing called' % name
165
- end
166
-
167
- # Main routing object, maps path part to target
168
- # if path part is positively matched with `test?` method, target is called with `call` method
169
- # ```
170
- # map api: ApiController
171
- # map api: 'api'
172
- # map [:api, ApiController]
173
- # map 'main/root' do
174
- # map [:login, :signup] => 'main/root'
175
- # map Main::RootController do
176
- # map :about
177
- # map '/verified-user'
178
- # end
179
- # ```
180
- def map route_object
181
- klass = nil
182
- route = nil
183
- action = nil
184
34
 
185
- # map 'root' do
186
- # ...
187
- if block_given?
188
- @lux_action_target = route_object
189
- yield
190
- @lux_action_target = nil
191
- return
192
- elsif @lux_action_target
193
- klass = @lux_action_target
194
- route = route_object
195
- action = route_object
196
-
197
- # map :foo => :some_action
198
- if route_object.is_a?(Hash)
199
- route = route_object.keys.first
200
- action = route_object.values.first
35
+ if request_method == 'OPTIONS'
36
+ return [204, {
37
+ 'allow' => Lux.config[:request_options] || 'OPTIONS, GET, HEAD, POST',
38
+ 'cache-control' => 'max-age=604800',
39
+ }, ['']]
201
40
  end
202
41
 
203
- if test?(route)
204
- call klass, action
205
- else
206
- return
207
- end
208
- end
209
-
210
- case route_object
211
- when String
212
- # map 'root#call'
213
- call route_object
214
- when Hash
215
- route = route_object.keys.first
216
- klass = route_object.values.first
217
-
218
- if route.class == Array
219
- # map [:foo, :bar] => 'root'
220
- for route_action in route
221
- if test?(route_action)
222
- call klass, route_action
223
- end
42
+ catch :done do
43
+ if Lux.config.serve_static_files
44
+ Lux::Response::File.deliver_from_current
224
45
  end
225
46
 
226
- return
227
- elsif route.is_a?(String) && route[0,1] == '/'
228
- # map '/skils/:skill' => 'main/skills#show'
229
- return match route, klass
47
+ resolve_routes unless response.body?
230
48
  end
231
- when Array
232
- # map [:foo, 'main/root']
233
- route, klass = *route_object
234
- else
235
- Lux.error 'Unsupported route type "%s"' % route_object.class
236
- end
237
-
238
- test?(route) ? call(klass) : nil
239
- end
240
-
241
- # Calls target action in a controller, if no action is given, defaults to :index
242
- # ```
243
- # call :api_router
244
- # call proc { 'string' }
245
- # call proc { [400, {}, 'error: ...'] }
246
- # call [200, {}, ['ok']]
247
- # call Main::UsersController
248
- # call Main::UsersController, :index
249
- # call [Main::UsersController, :index]
250
- # call 'main/orgs#show'
251
- # ```
252
- def call object=nil, action=nil
253
- # log original app caller
254
- root = Lux.root.join('app/').to_s
255
- sources = caller.select { |it| it.include?(root) }.map { |it| 'app/' + it.sub(root, '').split(':in').first }
256
- action = action.gsub('-', '_').to_sym if action && action.is_a?(String)
257
49
 
258
- Lux.log ' Routed from: %s' % sources.join(' ') if sources.first
259
-
260
- case object
261
- when Symbol
262
- return send(object)
263
- when Hash
264
- object = [object.keys.first, object.values.first]
265
- when String
266
- object, action = object.split('#') if object.include?('#')
267
- when Array
268
- if object[0].class == Integer && object[1].class == Hash
269
- # [200, {}, 'ok']
270
- for key, value in object[1]
271
- response.header key, value
272
- end
50
+ catch :done do
51
+ Lux.error.not_found unless response.body?
52
+ end
273
53
 
274
- response.status object[0]
275
- response.body object[2]
276
- else
277
- object, action = object
54
+ response.render
55
+ rescue => error
56
+ if respond_to?(:rescue_from)
57
+ catch :done do
58
+ rescue_from error
278
59
  end
279
- when Proc
280
- case data = object.call
281
- when Array
282
- response.status = data.first
283
- response.body data[2]
284
- else
285
- response.body data
286
- end
287
- end
288
-
289
- throw :done if body?
290
-
291
- # figure our action unless defined
292
- unless action
293
- id =
294
- if respond_to?(:id?)
295
- nav.root { |root_id| id?(root_id) }
296
- else
297
- nav.root { |root_id| root_id.is_numeric? ? root_id.to_i : nil }
298
- end
299
60
 
300
- if id
301
- current.nav.id = id
302
- action = nav.shift || :show
61
+ response.render
303
62
  else
304
- action = nav.shift || :index
63
+ raise error
305
64
  end
306
65
  end
307
66
 
308
- object = ('%s_controller' % object).classify.constantize if object.is_a?(String)
309
-
310
- controller_name = "app/controllers/#{object.to_s.underscore}.rb"
311
- Lux.log ' %s' % controller_name
312
- current.files_in_use controller_name
313
-
314
- object.action action.to_sym
315
-
316
- unless response.body
317
- Lux.error 'Lux cell "%s" called via route "%s" but page body is not set' % [object, nav.root]
67
+ # to get root page body
68
+ # Lux.app.new('/').render.body
69
+ def render
70
+ out = @response_render ||= render_base
71
+ body = out[2].join('')
72
+ body = JSON.parse body if out[1]['content-type'].index('/json')
73
+
74
+ {
75
+ body: body,
76
+ time: out[1]['x-lux-speed'],
77
+ status: out[0],
78
+ session: current.session.hash,
79
+ headers: out[1]
80
+ }.to_hwia
318
81
  end
319
- end
320
-
321
- # Action to do if there is an application error.
322
- # You want to overload this in a production.
323
- def on_error error
324
- raise error
325
- end
326
82
 
327
- def render
328
- Lux.log "\n#{current.request.request_method.white} #{current.request.url}"
83
+ def mount opts
84
+ target = opts.keys.first
85
+ value = opts.values.first
329
86
 
330
- Lux::Config.live_require_check! if Lux.config(:auto_code_reload)
87
+ return unless request.path.to_s.starts_with?(value)
331
88
 
332
- main
89
+ call target.call current.env
90
+ end
333
91
 
334
- response.render
335
- end
92
+ def render_error
93
+ err = Lux.current.error ||= $!
94
+ Lux.info "Unhandled error (define render_error in routes): [#{err.class}] #{err.message}"
95
+ Lux.error.log err
96
+ raise err
97
+ end
336
98
 
337
- private
99
+ def favicon path
100
+ cpath = request.path.downcase
338
101
 
339
- # internall call to resolve the routes
340
- def main
341
- return if deliver_static_assets
102
+ if !response.body? && cpath.start_with?('/favicon') || cpath.start_with?('/apple-touch-icon')
103
+ response.max_age = 600 if response.max_age.to_i == 0
342
104
 
343
- catch(:done) do
344
- class_callback :before
345
- class_callback :routes unless body?
105
+ icon = Lux.root.join(path)
106
+ if icon.exist?
107
+ response.send_file(icon, inline: true)
108
+ else
109
+ Lux.error.not_found '%s not found' % path
110
+ end
111
+ end
346
112
  end
347
113
 
348
- catch(:done) do
349
- class_callback :after
350
- end
351
- rescue => e
352
- response.body { nil }
114
+ # internall call to resolve the routes
115
+ def resolve_routes
116
+ @magic = MagicRoutes.new self
353
117
 
354
- catch(:done) do
355
- on_error(e)
356
- end
357
- end
118
+ run_callback :before, nav.path
119
+ run_callback :routes, nav.path
358
120
 
359
- # Deliver static assets if `Lux.config.serve_static_files == true`
360
- def deliver_static_assets
361
- return if body? || !Lux.config(:serve_static_files)
121
+ unless response.body?
122
+ Lux.error.not_found 'Document not found'
123
+ end
362
124
 
363
- ext = request.path.split('.').last
364
- return unless ext.length > 1 && ext.length < 5
365
- file = Lux::Response::File.new request.path.sub('/', ''), inline: true
366
- file.send if file.is_static_file?
125
+ run_callback :after, nav.path
126
+ end
367
127
  end
368
-
369
128
  end
370
-
@@ -0,0 +1,22 @@
1
+ # Maps routes to method missing for cleaner interface
2
+ # routes do |r|
3
+ # map :about => 'root#about'
4
+ # r.about 'root#about'
5
+ module Lux
6
+ class Application
7
+ module Routes
8
+ class MagicRoutes
9
+
10
+ def initialize app
11
+ @app = app
12
+ end
13
+
14
+ def method_missing route, *args, &block
15
+ @app.map [route, *args, block]
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+