flame 2.2.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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