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,104 +1,223 @@
1
1
  # experiment for different nav in rooter
2
2
 
3
- class Lux::Application::Nav
4
- attr_accessor :path, :id, :format
5
- attr_reader :original, :subdomain, :domain
6
-
7
- # acepts path as a string
8
- def initialize request
9
- @path = request.path.split('/').slice(1, 100) || []
10
- @original = @path.dup
11
-
12
- @subdomain = request.host.split('.')
13
- @domain = @subdomain.pop(2).join('.')
14
- @subdomain = @subdomain.join('.')
15
- @domain += ".#{@subdomain.pop}" if @domain.length < 6
16
-
17
- set_format
18
- end
19
-
20
- def set_format
21
- return unless @path.last
22
- parts = @path.last.split('.')
23
-
24
- if parts[1]
25
- @format = parts.pop.to_s.downcase.to_sym
26
- @path.last = parts.join('.')
27
- end
28
- end
29
-
30
- def active_shift
31
- @active = @path.shift
32
- end
33
-
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
44
- end
45
-
46
- # used to make admin.lvm.me/users to lvh.me/admin/users
47
- def unshift name
48
- @path.unshift name
49
- end
50
-
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
3
+ module Lux
4
+ class Application
5
+ class Nav
6
+ attr_accessor :format
7
+ attr_reader :original, :domain, :subdomain, :querystring, :ids
8
+
9
+ # acepts path as a string
10
+ def initialize request
11
+ @path = request.path.split('/').slice(1, 100) || []
12
+ @original = @path.dup
13
+ @request = request
14
+ @querystring = {}.to_hwia
15
+ @ids = []
16
+ @shifted = []
17
+
18
+ set_variables
19
+ set_domain request
20
+ set_format
21
+ end
22
+
23
+ def root
24
+ @path.first
25
+ end
26
+
27
+ def root= value
28
+ @path[0] = value
29
+ end
30
+
31
+ def shift
32
+ @path.shift.tap do |value|
33
+ @shifted.push value
34
+ end
35
+ end
36
+
37
+ # used to make admin.lvm.me/users to lvh.me/admin/users
38
+ def unshift name = nil
39
+ if name
40
+ @path.unshift name
41
+ @path = @path.flatten
42
+ name
43
+ else
44
+ @path.unshift @shifted.pop
45
+ end
46
+ end
47
+
48
+ # pop element of the path
49
+ def pop replace_with = nil
50
+ if block_given?
51
+ if result = yield(@path.last)
52
+ @path.pop
53
+ @path.unshift replace_with if replace_with
54
+ result
55
+ end
56
+ else
57
+ @path.shift
58
+ end
59
+ end
60
+
61
+ def last
62
+ # if block_given?
63
+ # # replace root in place if yields not nil
64
+ # return unless @path.last.present?
65
+ # result = yield(@path.last) || return
66
+ # @path.pop
67
+ # result
68
+ # else
69
+ @path.last
70
+ # end
71
+ end
72
+
73
+ # get Url object initialized with request.url - relative
74
+ # current.nav.url(:foo, 1).to_s # /path?foo=1
75
+ def url *args
76
+ if args.first
77
+ Url.current.qs(*args)
78
+ else
79
+ Url.current
80
+ end
81
+ end
82
+
83
+ def path *args
84
+ if args.first
85
+ # contruct path
86
+ # /upload_dialog/is_image:true/model:posts/id:2/field:image_url
87
+ # = nav.path :model, :id, :field -> /upload_dialog/model:posts/id:2/field:image_url
88
+ parts = @original.select {|el| !el.include?(':') }
89
+ parts += args.map do |el|
90
+ if value = Lux.current.params[el]
91
+ [el, value].join(':')
92
+ end
93
+ end.compact
94
+ '/' + parts.join('/')
95
+ elsif block_given?
96
+ @path = @path.map { _1.gsub('-', '_') }
97
+ else
98
+ @path
99
+ end
100
+ end
101
+
102
+ def path= list
103
+ @path = list
104
+ end
105
+
106
+ # removes leading www.
107
+ # https://www.foo.bar/path -> https://foo.bar/path
108
+ def remove_www
109
+ url = Lux.current.request.url
110
+
111
+ if url.include?('://www.')
112
+ Lux.current.response.redirect_to url.sub('://www.', '://')
113
+ end
114
+ end
115
+
116
+ # nav.rename_domain 'localhost', 'lvh.me'
117
+ # http://localhost:3000/foo?bar=123 -> http://lvh.me:3000/foo?bar=123
118
+ def rename_domain from_domain, to_domain
119
+ if from_domain == @domain
120
+ url = Url.new Lux.current.request.url
121
+ Lux.current.response.redirect_to url.domain(to_domain).to_s
122
+ end
123
+ end
124
+
125
+ # http://tiger.lvh.me:3000/foo?bar=1 -> http://tiger.lvh.me:3000
126
+ def base
127
+ @base ||= Lux.current.request.url.split('/').first(3).join('/')
128
+ end
129
+
130
+ def to_s
131
+ @path.join('/').sub(/\/$/, '')
132
+ end
133
+
134
+ # accept only two strings locale
135
+ # nav.locale { _1.length == 2 ? _1 : nil }
136
+ def locale
137
+ if @locale
138
+ return @locale.to_s == '' ? nil : @locale
139
+ end
140
+
141
+ if @path[0].to_s.downcase =~ /^[a-z]{2}(-[a-z]{2})?$/
142
+ if @locale = yield(@path[0])
143
+ @path.shift
144
+ else
145
+ @locale = ''
146
+ end
147
+ end
148
+
149
+ @locale
150
+ end
151
+
152
+ def locale= name
153
+ @locale = name.present? ? name.to_s : nil
154
+ end
155
+
156
+ def id
157
+ @ids.last
158
+ end
159
+
160
+ # replace nav path with id, when mached (works with resourceful routes map 'controler')
161
+ # nav.path_id { _1.split('-').last.string_id rescue nil }
162
+ # /foo/test-cbjy/bar -> ['foo', :id, 'bar]
163
+ def path_id
164
+ @path = @path.map do |el|
165
+ if result = yield(el)
166
+ @ids.push result
167
+ :id
168
+ else
169
+ el
170
+ end
171
+ end
172
+
173
+ @ids.last
174
+ end
175
+
176
+ private
177
+
178
+ def set_variables
179
+ # convert /foo/bar:baz to /foo?bar=baz
180
+ while @path.last&.include?(':')
181
+ key, val = @path.pop.split(':', 2)
182
+ @querystring[key] = val
183
+ Lux.current.params[key.to_sym] ||= val
184
+ end
185
+ end
186
+
187
+ def set_domain request
188
+ begin
189
+ # NoMethodError
190
+ # Message undefined method `start_with?' for nil:NilClass
191
+ # gems/rack-2.2.4/lib/rack/request.rb:567:in `wrap_ipv6'
192
+ parts = request.host.to_s.split('.')
193
+ rescue NoMethodError
194
+ raise Lux::Error.bad_request('Host name error')
195
+ end
196
+
197
+ if parts.last.is_numeric?
198
+ @domain = request.host
199
+ else
200
+ count = 2
201
+ count = 1 if parts.last == 'localhost'
202
+ count = 3 if parts.last(2).join('.') == 5 # foo.co.uk
203
+
204
+ @domain = parts.pop(count).join('.')
205
+ @domain += ".#{parts.pop}" if @domain.length < 6
206
+ @subdomain = parts.join('.')
207
+ end
208
+ end
209
+
210
+ def set_format
211
+ return unless @path.last
212
+ parts = @path.last.split('.')
213
+
214
+ if parts[1]
215
+ @format = parts.pop.to_s.downcase.to_sym
216
+ @path.last = parts.join('.')
217
+ end
218
+
219
+ @path.shift if @path[0] == ''
220
+ end
61
221
  end
62
222
  end
63
-
64
- def root= value
65
- @path[0] = value
66
- end
67
-
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
78
- end
79
-
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
90
- end
91
-
92
- def second
93
- @path[2]
94
- end
95
-
96
- def active
97
- @active
98
- end
99
-
100
- def to_s
101
- @path.join('/').sub(/\/$/, '')
102
- end
103
-
104
223
  end
@@ -1,69 +1,49 @@
1
- # handy :)
2
- # renders full pages and exposes page object (req, res) in yiled
3
- # for easy and powerful testing
4
- # Hash :qs, Hash :post, String :method, Hash :cookies, Hash :session
5
- # https://github.com/rack/rack/blob/master/test/spec_request.rb
6
-
7
- # Lux.app.render('/admin') -> { status: 403, ... }
8
- # Lux.app.render('/admin', session: { user_id: User.is_admin.first.id })
9
- # {
10
- # time: '1ms'
11
- # status: 200,
12
- # headers: {...},
13
- # session: {...},
14
- # body: '<html> ...'
15
- # }.h
16
-
17
- Lux::Application.class_eval do
18
- def self.render path='/mock', in_opts={}, &block
19
- allowed_opts = [:qs, :post, :method, :session, :cookies]
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
22
-
23
- opts = {}
24
-
25
- if in_opts[:post]
26
- opts[:query_string] = in_opts[:post]
27
- opts[:request_method] = :post
28
- else
29
- opts[:query_string] = in_opts[:qs] || {}
30
- opts[:request_method] ||= in_opts[:method] || :get
31
- end
32
-
33
- opts[:request_method] = opts[:request_method].to_s.upcase
34
- opts[:query_string] = opts[:query_string].to_query if opts[:query_string].class.to_s == 'Hash'
35
-
36
- if path[0,4] == 'http'
37
- parsed = URI.parse(path)
38
- opts[:server_name] = parsed.host
39
- opts[:server_port] = parsed.port
40
- path = '/'+path.split('/', 4).last
41
- end
42
-
43
- env = Rack::MockRequest.env_for(path)
44
- env[:input] = opts[:post] if opts[:post]
45
- for k,v in opts
46
- env[k.to_s.upcase] = v
1
+ # renders pages without server
2
+
3
+ module Lux
4
+ class Application
5
+ module Render
6
+ extend self
7
+
8
+ # Alternative was to call render action
9
+ # `Lux.app.new(path, full_opts).render.headers`
10
+ # `Lux.render.post(path, params, rest_of_opts).headers`
11
+ # `Lux.render.get('/search', params: { q: 'london' }, session: {user_id: 1} }).body`
12
+ %i(get post delete patch put).each do |req_method|
13
+ define_method req_method do |path, opts={}|
14
+ Lux.app.new(path, opts.merge(method: req_method)).render
15
+ end
16
+ end
17
+
18
+ # Render controller action without routes, pass a block to yield before action call.
19
+ # `Lux.render.controller('main/cities#foo').body`
20
+ # `Lux.render.controller('main/cities#foo') { @city = City.last_updated }.body`
21
+ def controller klass, &block
22
+ klass, action = klass.split('#')
23
+
24
+ klass = (klass+'Controller').classify.constantize if klass.is_a?(String)
25
+ c = klass.new
26
+ c.instance_exec &block if block
27
+ c.send action
28
+
29
+ Lux.current.response
30
+ end
31
+
32
+ # Lux.render.controller('main/cities#bar') { @city = City.last_updated }.body
33
+ def template *args
34
+ Lux::Template.render *args
35
+ end
36
+
37
+ # Lux.render.cell(:user, self, { product: @bar }).foo
38
+ # Lux.render.cell(:user, self).foo
39
+ # Lux.render.cell(:user, { product: @bar }).foo
40
+ # Lux.render.cell(:user).foo @arg
41
+ def cell name, *args
42
+ opts = args.last.is_a?(Hash) ? args.pop : {}
43
+ context = args.shift
44
+ Lux::ViewCell.get(name, context, opts)
45
+ end
47
46
  end
48
-
49
- current = Lux::Current.new(env)
50
- current.session.merge!(in_opts[:session]) if in_opts[:session]
51
-
52
- app = new current
53
-
54
- return app.instance_exec &block if block_given?
55
-
56
- response = app.render
57
-
58
- body = response[2].join('')
59
- body = JSON.parse body if response[1]['content-type'].index('/json')
60
-
61
- {
62
- time: response[1]['x-lux-speed'],
63
- status: response[0],
64
- headers: response[1],
65
- session: current.session.hash,
66
- body: body
67
- }.h
68
47
  end
69
- end
48
+ end
49
+
@@ -0,0 +1,242 @@
1
+ module Lux
2
+ class Application
3
+ module Routes
4
+ # generate get, get?, post, post? ...
5
+ # get {}
6
+ # get foo: 'main/bar', only: [:show], except: [:index]
7
+ %w{get head post delete put patch}.each do |m|
8
+ define_method('%s?' % m) do |*args, &block|
9
+ cm = current.request.request_method
10
+ cm = 'GET' if cm == 'HEAD'
11
+ return unless cm == m.upcase
12
+
13
+ if block
14
+ # get? { ... }
15
+ block.call
16
+ elsif args.first
17
+ # post api: 'api#call'
18
+ map *args
19
+ else
20
+ true
21
+ end
22
+ end
23
+ end
24
+
25
+ # Matches if there is not root in nav
26
+ # Example calls MainController.action(:index) if in root
27
+ # ```
28
+ # root 'main#index'
29
+ # ```
30
+ def root target
31
+ call target unless nav.root
32
+ end
33
+
34
+ # standard route match
35
+ # match '/:city/people', Main::PeopleController
36
+ def match base, target
37
+ base = base.split('/').slice(1, 100)
38
+
39
+ base.each_with_index do |el, i|
40
+ if el[0,1] == ':'
41
+ params[el.sub(':','').to_sym] = nav.path[i]
42
+ else
43
+ return unless el == nav.path[i]
44
+ end
45
+ end
46
+
47
+ call target
48
+ end
49
+
50
+ # Matches given subdomain name
51
+ def subdomain name
52
+ return unless nav.subdomain == name.to_s
53
+ yield
54
+ Lux.error.not_found 'Subdomain "%s" matched but nothing called' % name
55
+ end
56
+
57
+ # Main routing object, maps path part to target
58
+ # if path part is positively matched with `test?` method, target is called with `call` method
59
+ # ```
60
+ # map api: ApiController
61
+ # map api: 'api'
62
+ # map [:api, ApiController]
63
+ # map 'main/root' do
64
+ # map [:login, :signup] => 'main/root'
65
+ # map :city do
66
+ # map 'city' do
67
+ # map :about
68
+ # end
69
+ # ```
70
+ def map route_object = nil, target = nil &block
71
+ return @magic unless route_object
72
+ return if response.body?
73
+
74
+ route_object = [route_object, target] if target
75
+
76
+ if block_given?
77
+ # map 'admin' do ...
78
+ if test?(route_object)
79
+ yield nav.root
80
+ nav.unshift
81
+ end
82
+
83
+ return
84
+ end
85
+
86
+ klass = nil
87
+ route = nil
88
+ action = nil
89
+ opts = {}
90
+
91
+ case route_object
92
+ when String
93
+ # map 'root#call'
94
+ nav.shift
95
+ catch(:done) { call route_object }
96
+ when Hash
97
+ route = route_object.keys.first
98
+ klass = route_object.values.first
99
+
100
+ if route_object.keys.length > 1
101
+ opts = route_object.dup
102
+ opts.delete route
103
+ end
104
+
105
+ if route.class == Array
106
+ # map [:foo, :bar] => 'root'
107
+ for route_action in route
108
+ if test?(route_action)
109
+ call klass, route_action
110
+ end
111
+ end
112
+
113
+ return
114
+ elsif route.is_a?(String) && route[0,1] == '/'
115
+ # map '/skils/:skill' => 'main/skills#show'
116
+ return match route, klass
117
+ end
118
+ when Array
119
+ # map [:foo, 'main/root']
120
+ route, klass, opts = *route_object
121
+ else
122
+ Lux.error 'Unsupported route type "%s"' % route_object.class
123
+ end
124
+
125
+ test?(route) ? call(klass, nil, opts) : nil
126
+ end
127
+
128
+ # Calls target action in a controller, if no action is given, defaults to :call
129
+ # ```
130
+ # call :api_router
131
+ # call { 'string' }
132
+ # call proc { [400, {}, 'error: ...'] }
133
+ # call [200, {}, ['ok']]
134
+ # call Main::UsersController
135
+ # call Main::UsersController, :index
136
+ # call [Main::UsersController, :index]
137
+ # call 'main/orgs' -> index, show
138
+ # call 'main/orgs#show' -> show
139
+ # call 'main/orgs?list' -> list_index, list_show # provies namespace in controller
140
+ # ```
141
+ def call object=nil, action=nil, opts=nil, &block
142
+ # log original app caller
143
+ root = Lux.root.join('app/').to_s
144
+ sources = caller.select { |it| it.include?(root) }.map { |it| 'app/' + it.sub(root, '').split(':in').first }
145
+ action = action.gsub('-', '_').to_sym if action && action.is_a?(String)
146
+ namespace = nil
147
+ object ||= block if block_given?
148
+
149
+ Lux.log { ' Routed from: %s' % sources.join(' ') } if sources.first
150
+
151
+ case object
152
+ when Symbol
153
+ return send(object)
154
+ when Hash
155
+ object = [object.keys.first, object.values.first]
156
+ when String
157
+ if object.include?('#')
158
+ object, action = object.split('#')
159
+ else
160
+ action = if nav.root == :id
161
+ nav.path[1] || :show
162
+ else
163
+ nav.path[0] || :index
164
+ end
165
+ end
166
+ when Array
167
+ if object[0].class == Integer && object[1].class == Hash
168
+ # [200, {}, 'ok']
169
+ for key, value in object[1]
170
+ response.header key, value
171
+ end
172
+
173
+ response.status object[0]
174
+ response.body object[2].is_a?(Array) ? object[2].first : object[2]
175
+ else
176
+ object, action = object
177
+ end
178
+ when Proc
179
+ case data = object.call
180
+ when Array
181
+ response.status = data.first
182
+ response.body data[2].is_a?(Array) ? data[2][0] : data[2]
183
+ else
184
+ response.body data
185
+ end
186
+ end
187
+
188
+ if object.is_a?(String)
189
+ object = ('%s_controller' % object).classify.constantize
190
+ end
191
+
192
+ if [Module, Class].include?(object.class) && object.respond_to?(:call)
193
+ response.rack object
194
+ end
195
+
196
+ if object.respond_to?(:source_location)
197
+ current.files_in_use object.source_location
198
+ end
199
+
200
+ opts ||= {}
201
+ action ||= nav.path.last || :index
202
+
203
+ if opts[:only] && !opts[:only].include?(action.to_sym)
204
+ Lux.error.not_found Lux.env.show_errors? ? "Action :#{action} not allowed on #{object}, allowed are: #{opts[:only]}" : nil
205
+ end
206
+
207
+ if opts[:except] && opts[:except].include?(action.to_sym)
208
+ Lux.error.not_found Lux.env.show_errors? ? "Action :#{action} not allowed on #{object}, forbidden are: #{opts[:except]}" : nil
209
+ end
210
+
211
+ if object.respond_to?(:action)
212
+ object.action action.to_sym
213
+ end
214
+
215
+ throw :done if response.body?
216
+ end
217
+
218
+ # Tests current root against the string to get a mach.
219
+ # Used by map function
220
+ def test? route
221
+ root = nav.root.to_s
222
+
223
+ ok = case route
224
+ when String
225
+ root == route.sub(/^\//,'')
226
+ when Symbol
227
+ route.to_s == root
228
+ when Regexp
229
+ !!(route =~ root)
230
+ when Array
231
+ !!route.map(&:to_s).include?(root)
232
+ else
233
+ false
234
+ end
235
+
236
+ nav.shift if ok
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+