flame 2.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 132a976db3536271fcd021dea1158925d8d61db6
4
- data.tar.gz: 413e4476ce2a9d76b52894d03088945a389eb299
3
+ metadata.gz: c72f15f6e82b2b169b8e8db77fe10d1d3674e217
4
+ data.tar.gz: 319e24d36eacdbda8cd2454270cf6dea293d9d55
5
5
  SHA512:
6
- metadata.gz: e71747e2c149f2e06a8e3760e8dcef947e4c34ca4a26105a572fcaf2bd9651229264f08d05a5d7dfc2d4b813a2d69cf049fa56706d495ee5a03f33b1a2c6806f
7
- data.tar.gz: ebeac2eb2732bcac1530a3b8c0d6994060696de7d82679c4073a23611460f047688c7f2146711a0b1b10082ee84468e01059f3da0609fdd9c2e0b5093a29c3fc
6
+ metadata.gz: 414b88f416bc9ba7d7723d5df9d419c36865f3c08ce55f7f800e52f4b0371f8243d19800ccc37ef9194080be88296e0d832f0a95e3a4e4d76ddfcc6842b1b581
7
+ data.tar.gz: 96c70734f79a4a12040a3895445d18d97cad4a858b093a858d9f46399ebcf9aeb028526840238e5b9e860f4491263c2ace2368d36460fef9858fe8dc48916e61
@@ -1,32 +1,35 @@
1
1
  require_relative 'router'
2
+ require_relative 'request'
2
3
  require_relative 'dispatcher'
3
4
 
4
5
  module Flame
5
6
  ## Core class, like Framework::Application
6
7
  class Application
7
- ## Framework configuration
8
- def self.config
9
- @config ||= {}
8
+ class << self
9
+ attr_accessor :config
10
10
  end
11
11
 
12
+ ## Framework configuration
12
13
  def config
13
14
  self.class.config
14
15
  end
15
16
 
16
17
  def self.inherited(app)
17
- root_dir = File.dirname(caller[0].split(':')[0])
18
- app.config.merge!(
19
- root_dir: root_dir,
20
- public_dir: File.join(root_dir, 'public'),
21
- views_dir: File.join(root_dir, 'views')
18
+ app.config = Config.new(
19
+ app,
20
+ default_config_dirs(
21
+ root_dir: File.dirname(caller[0].split(':')[0])
22
+ )
22
23
  )
23
- app.use Rack::Session::Pool
24
+ # app.use Rack::Session::Pool
24
25
  end
25
26
 
26
27
  def initialize
27
28
  app = self
28
29
  @builder = Rack::Builder.new do
29
- app.class.middlewares.each { |m| use m[:class], *m[:args], &m[:block] }
30
+ app.class.middlewares.each do |m|
31
+ use m[:class], *m[:args], &m[:block]
32
+ end
30
33
  run app
31
34
  end
32
35
  end
@@ -34,7 +37,7 @@ module Flame
34
37
  ## Init function
35
38
  def call(env)
36
39
  if env[:FLAME_CALL]
37
- Dispatcher.new(self, env).run!
40
+ Flame::Dispatcher.new(self, env).run!
38
41
  else
39
42
  env[:FLAME_CALL] = true
40
43
  @builder.call env
@@ -45,21 +48,46 @@ module Flame
45
48
  router.add_controller(ctrl, path, block)
46
49
  end
47
50
 
51
+ def self.middlewares
52
+ @middlewares ||= []
53
+ end
54
+
48
55
  def self.use(middleware, *args, &block)
49
56
  middlewares << { class: middleware, args: args, block: block }
50
57
  end
51
58
 
52
- def self.middlewares
53
- @middlewares ||= []
59
+ def self.helpers(*modules)
60
+ modules.empty? ? (@helpers ||= []) : @helpers = modules
54
61
  end
55
62
 
56
63
  ## Router for routing
57
64
  def self.router
58
- @router ||= Flame::Router.new
65
+ @router ||= Flame::Router.new(self)
66
+ end
67
+
68
+ def self.default_config_dirs(root_dir:)
69
+ {
70
+ root_dir: File.realpath(root_dir),
71
+ public_dir: proc { File.join(config[:root_dir], 'public') },
72
+ views_dir: proc { File.join(config[:root_dir], 'views') },
73
+ config_dir: proc { File.join(config[:root_dir], 'config') }
74
+ }
59
75
  end
60
76
 
61
- def router
62
- self.class.router
77
+ ## Class for Flame::Application.config
78
+ class Config < Hash
79
+ def initialize(app, hash = {})
80
+ @app = app
81
+ replace(hash)
82
+ end
83
+
84
+ def [](key)
85
+ result = super(key)
86
+ if result.class <= Proc && result.parameters.empty?
87
+ result = @app.class_exec(&result)
88
+ end
89
+ result
90
+ end
63
91
  end
64
92
  end
65
93
  end
@@ -0,0 +1,49 @@
1
+ require 'rack'
2
+ require_relative 'render'
3
+
4
+ module Flame
5
+ ## Class initialize when Dispatcher found route with it
6
+ ## For new request and response
7
+ class Controller
8
+ def initialize(dispatcher)
9
+ @dispatcher = dispatcher
10
+ end
11
+
12
+ ## Helpers
13
+ def path_to(*args)
14
+ args.unshift self.class if args[0].is_a? Symbol
15
+ @dispatcher.path_to(*args)
16
+ end
17
+
18
+ def redirect(*params)
19
+ response.redirect(
20
+ params[0].is_a?(String) ? params[0] : path_to(*params)
21
+ )
22
+ end
23
+
24
+ def view(path = nil, options = {})
25
+ Flame::Render.new(
26
+ self,
27
+ (path || caller_locations(1, 1)[0].label.to_sym),
28
+ options
29
+ ).render
30
+ end
31
+ alias_method :render, :view
32
+
33
+ ## Helpers from Flame::Dispatcher
34
+ def method_missing(m, *args, &block)
35
+ return super unless @dispatcher.respond_to?(m)
36
+ @dispatcher.send(m, *args, &block)
37
+ end
38
+
39
+ private
40
+
41
+ using GorillaPatch::StringExt
42
+
43
+ def self.default_path(last = false)
44
+ (name.split('::').last.underscore.split('_') - %w(controller ctrl))
45
+ .join('/').split('/')
46
+ .unshift(nil)[(last ? -1 : 0)..-1].join('/')
47
+ end
48
+ end
49
+ end
@@ -1,14 +1,12 @@
1
- require 'rack'
2
- require_relative 'request'
3
- require_relative 'render'
4
-
5
1
  module Flame
6
- ## Class initialize when Application.call(env) invoked
7
- ## For new request and response
2
+ ## Helpers for dispatch Flame::Application#call
8
3
  class Dispatcher
4
+ attr_reader :request, :response
5
+
9
6
  def initialize(app, env)
10
7
  @app = app
11
- @env = env
8
+ @request = Flame::Request.new(env)
9
+ @response = Rack::Response.new
12
10
  end
13
11
 
14
12
  def run!
@@ -18,38 +16,41 @@ module Flame
18
16
  try_static(File.join(__dir__, '..', '..', 'public')) ||
19
17
  halt(404)
20
18
  end
19
+ # p body
21
20
  response.write body
22
21
  response.finish
23
22
  end
24
23
 
25
- ## Helpers
26
- def config
27
- @app.config
24
+ def status(value = nil)
25
+ response.status ||= 200
26
+ value ? response.status = value : response.status
28
27
  end
29
28
 
30
- def router
31
- @app.router
29
+ def params
30
+ request.params
32
31
  end
33
32
 
34
- def request
35
- @request ||= Flame::Request.new(@env)
33
+ def session
34
+ request.session
36
35
  end
37
36
 
38
- def params
39
- request.params
37
+ def cookies
38
+ @cookies ||= Cookies.new(request.cookies, response)
40
39
  end
41
40
 
42
- def response
43
- @response ||= Rack::Response.new
41
+ def config
42
+ @app.config
44
43
  end
45
44
 
46
- def status(value = nil)
47
- response.status ||= 200
48
- value ? response.status = value : response.status
45
+ def path_to(ctrl, action, args = {})
46
+ route = @app.class.router.find_route(controller: ctrl, action: action)
47
+ fail RouteNotFoundError.new(ctrl, action) unless route
48
+ path = route.assign_arguments(args)
49
+ path.empty? ? '/' : path
49
50
  end
50
51
 
51
52
  def halt(new_status, body = '', new_headers = {})
52
- status new_status
53
+ new_status.is_a?(String) ? (body = new_status) : (status new_status)
53
54
  response.headers.merge!(new_headers)
54
55
  # p response.body
55
56
  if body.empty? &&
@@ -59,36 +60,11 @@ module Flame
59
60
  throw :halt, body
60
61
  end
61
62
 
62
- def path_to(ctrl, action, args = {})
63
- route = router.find_route(controller: ctrl, action: action)
64
- fail RouteNotFoundError.new(ctrl, action) unless route
65
- path = route.assign_arguments(args)
66
- path.empty? ? '/' : path
67
- end
68
-
69
- def redirect(*params)
70
- throw :halt, response.redirect(
71
- params[0].is_a?(String) ? params[0] : path_to(*params)
72
- )
73
- end
74
-
75
- def session
76
- request.session
77
- end
78
-
79
- def cookies
80
- @cookies ||= Cookies.new(request.cookies, response)
81
- end
82
-
83
- def view(path, options = {})
84
- Flame::Render.new(self, path, options).render
85
- end
86
- alias_method :render, :view
87
-
88
63
  private
89
64
 
65
+ ## Find route and try execute it
90
66
  def try_route
91
- route = router.find_route(
67
+ route = @app.class.router.find_route(
92
68
  method: request.http_method,
93
69
  path_parts: request.path_parts
94
70
  )
@@ -101,28 +77,44 @@ module Flame
101
77
  end
102
78
 
103
79
  def execute_route(route)
104
- singleton_class.include route[:controller]
105
- router.find_befores(route).each { |before| send(before) }
106
- result = send(route[:action], *route.arranged_params(params))
107
- router.find_afters(route).each do |after|
108
- result = send(after, result)
80
+ ctrl = route[:controller].new(self)
81
+ route[:befores].each { |before| ctrl.send(before) }
82
+ result = ctrl.send(route[:action], *route.arranged_params(params))
83
+ route[:afters].each { |after| result = execute_after(ctrl, after, result) }
84
+ result
85
+ end
86
+
87
+ def execute_after(ctrl, after, result)
88
+ case after.class.to_s.to_sym
89
+ when :Symbol, :String
90
+ result = ctrl.send(after.to_sym, result)
91
+ when :Proc
92
+ ctrl.instance_exec(result, &after)
93
+ else
94
+ fail UnexpectedTypeOfAfterError.new(after, route)
109
95
  end
110
96
  result
111
97
  end
112
98
 
99
+ ## Find static files and try return it
113
100
  def try_static(dir = config[:public_dir])
114
- static_file = File.join(dir, request.path_info)
101
+ file = File.join(dir, request.path_info)
115
102
  # p static_file
116
- return nil unless File.exist?(static_file) && File.file?(static_file)
117
- return_static(static_file)
103
+ return nil unless File.exist?(file) && File.file?(file)
104
+ return_static(file)
105
+ end
106
+
107
+ def static_cached?(file_time)
108
+ since = request.env['HTTP_IF_MODIFIED_SINCE']
109
+ since && Time.httpdate(since).to_i >= file_time.to_i
118
110
  end
119
111
 
120
112
  def return_static(file)
121
- since = @env['HTTP_IF_MODIFIED_SINCE']
122
113
  file_time = File.mtime(file)
123
- halt 304 if since && Time.httpdate(since).to_i >= file_time.to_i
114
+ halt 304 if static_cached?(file_time)
115
+ mime_type = Rack::Mime.mime_type(File.extname(file))
124
116
  response.headers.merge!(
125
- 'Content-Type' => file_mime_type(file),
117
+ 'Content-Type' => mime_type,
126
118
  'Last-Modified' => file_time.httpdate
127
119
  # 'Content-Disposition' => 'attachment;' \
128
120
  # "filename=\"#{File.basename(static_file)}\"",
@@ -131,10 +123,6 @@ module Flame
131
123
  halt 200, File.read(file)
132
124
  end
133
125
 
134
- def file_mime_type(file)
135
- Rack::Mime.mime_type(File.extname(file))
136
- end
137
-
138
126
  ## Helper class for cookies
139
127
  class Cookies
140
128
  def initialize(request_cookies, response)
data/lib/flame/errors.rb CHANGED
@@ -67,14 +67,27 @@ module Flame
67
67
  end
68
68
 
69
69
  ## Error for Flame::Controller.path_to
70
- class ArgumentNotAssigned < StandardError
70
+ class ArgumentNotAssignedError < StandardError
71
71
  def initialize(path, path_part)
72
72
  @path = path
73
73
  @path_part = path_part
74
74
  end
75
75
 
76
76
  def message
77
- "Argument '#{@path_part}' for '#{@path}' is not assigned"
77
+ "Argument '#{@path_part}' for path '#{@path}' is not assigned"
78
+ end
79
+ end
80
+
81
+ ## Error for Flame::Router.find_path
82
+ class UnexpectedTypeOfAfterError < StandardError
83
+ def initialize(after, route)
84
+ @after = after
85
+ @route = route
86
+ end
87
+
88
+ def message
89
+ "Unexpected after-block class '#{@after.class}'" \
90
+ " in route '#{@route}'"
78
91
  end
79
92
  end
80
93
  end
data/lib/flame/render.rb CHANGED
@@ -52,9 +52,13 @@ module Flame
52
52
  def controller_dirs
53
53
  ## Build controller_dirs
54
54
  controller_dir = (
55
- @ctrl.controller.name.underscore.split('_') - %w(controller ctrl)
55
+ @ctrl.class.name.underscore.split('_') - %w(controller ctrl)
56
56
  ).join('_')
57
- [controller_dir, controller_dir.split('/').last]
57
+ controller_dir_parts = controller_dir.split('/')
58
+ [controller_dir,
59
+ controller_dir_parts[1..-1].join('/'),
60
+ controller_dir_parts[1..-2].join('/'),
61
+ controller_dir_parts.last]
58
62
  end
59
63
 
60
64
  def layout_render(result)
data/lib/flame/route.rb CHANGED
@@ -13,6 +13,11 @@ module Flame
13
13
  @attributes[attribute]
14
14
  end
15
15
 
16
+ def merge(attrs)
17
+ dup.attributes.merge!(attrs)
18
+ self
19
+ end
20
+
16
21
  ## Compare attributes for `Router.find_route`
17
22
  def compare_attributes(attrs)
18
23
  attrs.each do |name, value|
@@ -90,7 +95,7 @@ module Flame
90
95
  ## Required argument
91
96
  param = args[path_part[1..-1].to_sym]
92
97
  ## Required argument is nil
93
- fail ArgumentNotAssigned.new(self[:path], path_part) if param.nil?
98
+ fail ArgumentNotAssignedError.new(self[:path], path_part) if param.nil?
94
99
  ## All is ok
95
100
  param
96
101
  end
data/lib/flame/router.rb CHANGED
@@ -4,28 +4,31 @@ require_relative 'validators'
4
4
  module Flame
5
5
  ## Router class for routing
6
6
  class Router
7
- attr_accessor :routes, :befores, :afters
7
+ attr_reader :app, :routes, :befores, :afters
8
8
 
9
- def initialize
9
+ def initialize(app)
10
+ @app = app
10
11
  @routes = []
11
12
  @befores, @afters = Array.new(2) { {} }
12
13
  end
13
14
 
14
15
  def add_controller(ctrl, path, block = nil)
15
16
  ## TODO: Add Regexp paths
16
- ## TODO: Add `before` and `after` methods
17
17
 
18
18
  ## Add routes from controller to glob array
19
- ctrl_routes = RouteRefine.new(ctrl, path, block)
20
- ActionsValidator.new(ctrl_routes.routes, ctrl).valid?
21
- routes.concat(ctrl_routes.routes)
22
- befores[ctrl] = ctrl_routes.befores
23
- afters[ctrl] = ctrl_routes.afters
19
+ ctrl.include(*@app.helpers)
20
+ route_refine = RouteRefine.new(self, ctrl, path, block)
21
+ concat_routes(route_refine) if ActionsValidator.new(route_refine).valid?
24
22
  end
25
23
 
26
24
  ## Find route by any attributes
27
- def find_route(attrs)
28
- routes.find { |route| route.compare_attributes(attrs) }
25
+ def find_route(attrs, with_hooks = true)
26
+ route = routes.find { |r| r.compare_attributes(attrs) }
27
+ return route unless route && with_hooks
28
+ route.merge(
29
+ befores: find_befores(route),
30
+ afters: find_afters(route)
31
+ )
29
32
  end
30
33
 
31
34
  ## Find before hook by Route
@@ -42,10 +45,16 @@ module Flame
42
45
 
43
46
  private
44
47
 
48
+ def concat_routes(route_refine)
49
+ routes.concat(route_refine.routes)
50
+ befores[route_refine.ctrl] = route_refine.befores
51
+ afters[route_refine.ctrl] = route_refine.afters
52
+ end
53
+
45
54
  ## Helper module for routing refine
46
55
  class RouteRefine
47
56
  attr_accessor :rest_routes
48
- attr_reader :routes, :befores, :afters
57
+ attr_reader :ctrl, :routes, :befores, :afters
49
58
 
50
59
  def self.http_methods
51
60
  [:GET, :POST, :PUT, :DELETE]
@@ -61,31 +70,34 @@ module Flame
61
70
  ]
62
71
  end
63
72
 
64
- def initialize(ctrl, path, block)
73
+ def initialize(router, ctrl, path, block)
74
+ @router = router
65
75
  @ctrl = ctrl
66
- @path = path || default_controller_path
76
+ @path = path || @ctrl.default_path
67
77
  @routes = []
68
78
  @befores, @afters = Array.new(2) { {} }
69
- block.nil? ? defaults : instance_exec(&block)
70
- # p @routes
71
- @routes.sort! { |a, b| b[:path] <=> a[:path] }
79
+ execute(&block)
72
80
  end
73
81
 
74
82
  http_methods.each do |request_method|
75
- define_method(request_method.downcase) do |path, action|
83
+ define_method(request_method.downcase) do |path, action = nil|
84
+ if action.nil?
85
+ action = path.to_sym
86
+ path = "/#{path}"
87
+ end
76
88
  ArgumentsValidator.new(@ctrl, path, action).valid?
77
89
  add_route(request_method, path, action)
78
90
  end
79
91
  end
80
92
 
81
- def before(actions, action)
93
+ def before(actions, action = nil, &block)
82
94
  actions = [actions] unless actions.is_a?(Array)
83
- actions.each { |a| (@befores[a] ||= []).push(action) }
95
+ actions.each { |a| (@befores[a] ||= []).push(action || block) }
84
96
  end
85
97
 
86
- def after(actions, action)
98
+ def after(actions, action = nil, &block)
87
99
  actions = [actions] unless actions.is_a?(Array)
88
- actions.each { |a| (@afters[a] ||= []).push(action) }
100
+ actions.each { |a| (@afters[a] ||= []).push(action || block) }
89
101
  end
90
102
 
91
103
  def defaults
@@ -106,13 +118,23 @@ module Flame
106
118
  end
107
119
  end
108
120
 
109
- private
121
+ def mount(ctrl, path = nil, &block)
122
+ path = path_merge(
123
+ @path,
124
+ (path || ctrl.default_path(true))
125
+ )
126
+ @router.add_controller(ctrl, path, block)
127
+ end
110
128
 
111
- using GorillaPatch::StringExt
129
+ private
112
130
 
113
- def default_controller_path
114
- (@ctrl.name.underscore.split('_') - %w(controller ctrl))
115
- .unshift(nil).join('/')
131
+ def execute(&block)
132
+ block.nil? ? defaults : instance_exec(&block)
133
+ @router.app.helpers.each do |helper|
134
+ instance_exec(&helper.mount) if helper.respond_to?(:mount)
135
+ end
136
+ # p @routes
137
+ @routes.sort! { |a, b| b[:path] <=> a[:path] }
116
138
  end
117
139
 
118
140
  def make_path(path, action = nil, force_params = false)
@@ -124,13 +146,17 @@ module Flame
124
146
  .unshift(unshifted)
125
147
  .join('/')
126
148
  end
127
- "#{@path}/#{path}".gsub(%r{\/{2,}}, '/')
149
+ path_merge(@path, path)
128
150
  end
129
151
 
130
152
  def action_path(action)
131
153
  action == :index ? '/' : action
132
154
  end
133
155
 
156
+ def path_merge(*parts)
157
+ parts.join('/').gsub(%r{\/{2,}}, '/')
158
+ end
159
+
134
160
  def add_route(method, path, action, force_params = false)
135
161
  route = Route.new(
136
162
  method: method,
@@ -57,9 +57,9 @@ module Flame
57
57
 
58
58
  ## Compare actions from routes and from controller
59
59
  class ActionsValidator
60
- def initialize(routes, ctrl)
61
- @routes = routes
62
- @ctrl = ctrl
60
+ def initialize(route_refine)
61
+ @routes = route_refine.routes
62
+ @ctrl = route_refine.ctrl
63
63
  end
64
64
 
65
65
  def valid?
data/lib/flame.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require 'gorilla-patch/string'
2
2
 
3
3
  require_relative 'flame/application'
4
+ require_relative 'flame/controller'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flame
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Popov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-06 00:00:00.000000000 Z
11
+ date: 2015-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -74,6 +74,7 @@ extra_rdoc_files: []
74
74
  files:
75
75
  - lib/flame.rb
76
76
  - lib/flame/application.rb
77
+ - lib/flame/controller.rb
77
78
  - lib/flame/dispatcher.rb
78
79
  - lib/flame/errors.rb
79
80
  - lib/flame/render.rb