flame 5.0.0.rc5 → 5.0.0.rc6
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 +5 -5
- data/CHANGELOG.md +921 -0
- data/LICENSE.txt +19 -0
- data/README.md +135 -0
- data/lib/flame.rb +12 -5
- data/lib/flame/application.rb +47 -46
- data/lib/flame/config.rb +73 -0
- data/lib/flame/controller.rb +45 -78
- data/lib/flame/controller/actions.rb +122 -0
- data/lib/flame/{dispatcher → controller}/cookies.rb +8 -3
- data/lib/flame/controller/path_to.rb +34 -10
- data/lib/flame/dispatcher.rb +14 -17
- data/lib/flame/dispatcher/request.rb +25 -6
- data/lib/flame/dispatcher/routes.rb +22 -14
- data/lib/flame/dispatcher/static.rb +13 -9
- data/lib/flame/errors/argument_not_assigned_error.rb +3 -8
- data/lib/flame/errors/config_file_not_found_error.rb +17 -0
- data/lib/flame/errors/controller_not_found_error.rb +19 -0
- data/lib/flame/errors/route_arguments_order_error.rb +5 -10
- data/lib/flame/errors/route_extra_arguments_error.rb +10 -20
- data/lib/flame/errors/route_not_found_error.rb +3 -8
- data/lib/flame/errors/template_not_found_error.rb +2 -8
- data/lib/flame/path.rb +36 -18
- data/lib/flame/render.rb +13 -5
- data/lib/flame/router.rb +7 -157
- data/lib/flame/router/controller_finder.rb +56 -0
- data/lib/flame/router/route.rb +9 -0
- data/lib/flame/router/routes.rb +58 -8
- data/lib/flame/router/routes_refine.rb +144 -0
- data/lib/flame/router/routes_refine/mounting.rb +57 -0
- data/lib/flame/validators.rb +14 -10
- data/lib/flame/version.rb +1 -1
- metadata +91 -99
- data/bin/flame +0 -16
- data/lib/flame/application/config.rb +0 -49
- data/template/.editorconfig +0 -15
- data/template/.gitignore +0 -28
- data/template/.rubocop.yml +0 -14
- data/template/Gemfile +0 -55
- data/template/Rakefile +0 -824
- data/template/application.rb.erb +0 -10
- data/template/config.ru.erb +0 -72
- data/template/config/config.rb.erb +0 -56
- data/template/config/database.example.yml +0 -5
- data/template/config/deploy.example.yml +0 -2
- data/template/config/puma.rb +0 -56
- data/template/config/sequel.rb.erb +0 -22
- data/template/config/server.example.yml +0 -32
- data/template/config/session.example.yml +0 -7
- data/template/controllers/_controller.rb.erb +0 -14
- data/template/controllers/site/_controller.rb.erb +0 -18
- data/template/controllers/site/index_controller.rb.erb +0 -12
- data/template/db/.keep +0 -0
- data/template/filewatchers.yml +0 -12
- data/template/helpers/.keep +0 -0
- data/template/lib/.keep +0 -0
- data/template/locales/en.yml +0 -0
- data/template/models/.keep +0 -0
- data/template/public/.keep +0 -0
- data/template/server +0 -200
- data/template/services/.keep +0 -0
- data/template/views/.keep +0 -0
- data/template/views/site/index.html.erb.erb +0 -1
- data/template/views/site/layout.html.erb.erb +0 -10
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2015-2017 Alexander Popov (AlexWayfer)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"),
|
5
|
+
to deal in the Software without restriction, including without limitation
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom
|
8
|
+
the Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included
|
11
|
+
in all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
14
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
15
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
16
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
17
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
18
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img
|
3
|
+
src="https://raw.githubusercontent.com/AlexWayfer/flame/master/public/favicon.ico"
|
4
|
+
height="150"
|
5
|
+
alt="Flame Logo"
|
6
|
+
title="Logo from open-source Elusive-Iconfont (https://github.com/reduxframework/elusive-iconfont)"
|
7
|
+
/>
|
8
|
+
</p>
|
9
|
+
|
10
|
+
<h1 align="center">Flame</h1>
|
11
|
+
|
12
|
+
<p align="center">
|
13
|
+
<a href="https://cirrus-ci.com/github/AlexWayfer/flame/master"><img
|
14
|
+
src="https://api.cirrus-ci.com/github/AlexWayfer/flame.svg?branch=master"
|
15
|
+
alt="Cirrus CI"
|
16
|
+
/></a>
|
17
|
+
<a href="https://codecov.io/gh/AlexWayfer/flame"><img
|
18
|
+
src="https://img.shields.io/codecov/c/github/AlexWayfer/flame.svg?style=flat-square"
|
19
|
+
alt="Codecov"
|
20
|
+
/></a>
|
21
|
+
<a href="https://codeclimate.com/github/AlexWayfer/flame"><img
|
22
|
+
src="https://img.shields.io/codeclimate/maintainability/AlexWayfer/flame.svg?style=flat-square"
|
23
|
+
alt="Code Climate"
|
24
|
+
/></a>
|
25
|
+
<a href="https://depfu.com/repos/AlexWayfer/flame"><img
|
26
|
+
src="https://img.shields.io/depfu/AlexWayfer/flame.svg?style=flat-square"
|
27
|
+
alt="Depfu"
|
28
|
+
/></a>
|
29
|
+
<a href="http://inch-ci.org/github/AlexWayfer/flame"><img
|
30
|
+
src="http://inch-ci.org/github/AlexWayfer/flame.svg?branch=master&style=flat-square"
|
31
|
+
alt="Docs"
|
32
|
+
/></a>
|
33
|
+
<a href="https://rubygems.org/gems/flame"><img
|
34
|
+
src="https://img.shields.io/gem/v/flame.svg?style=flat-square"
|
35
|
+
alt="Gem"
|
36
|
+
/></a>
|
37
|
+
<a href="https://github.com/AlexWayfer/flame/blob/master/LICENSE.txt"><img
|
38
|
+
src="https://img.shields.io/github/license/AlexWayfer/flame.svg?style=flat-square"
|
39
|
+
alt="MIT license"
|
40
|
+
/></a>
|
41
|
+
</p>
|
42
|
+
|
43
|
+
Flame is a small Ruby web framework, built on [Rack](https://github.com/rack/rack),
|
44
|
+
inspired by [Gin](https://github.com/0jcasts/gin) (which follows class-controllers style),
|
45
|
+
designed as a replacement [Sinatra](https://github.com/sinatra/sinatra)
|
46
|
+
or maybe even [Rails](https://github.com/rails/rails).
|
47
|
+
|
48
|
+
## Why?
|
49
|
+
|
50
|
+
I didn't like class methods, especially for controller's hooks — OOP is prettier without it.
|
51
|
+
And I found a way to implement controller's hooks without using class methods,
|
52
|
+
but with the inheritance (including the including of modules).
|
53
|
+
Moreover, with class methods an insufficiently obvious order of hooks (especially with inheritance)
|
54
|
+
and complicated implementation of conditions are obtained.
|
55
|
+
In this framework everything is Ruby-native as it can be.
|
56
|
+
|
57
|
+
## Installation
|
58
|
+
|
59
|
+
Using the built-in `gem`:
|
60
|
+
|
61
|
+
```bash
|
62
|
+
$ gem install flame
|
63
|
+
```
|
64
|
+
|
65
|
+
or with [Bundler](http://bundler.io/):
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# Gemfile
|
69
|
+
gem 'flame'
|
70
|
+
```
|
71
|
+
|
72
|
+
## Usage
|
73
|
+
|
74
|
+
The simplest example:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
# index_controller.rb
|
78
|
+
|
79
|
+
class IndexController < Flame::Controller
|
80
|
+
def index
|
81
|
+
view :index # or just `view`, Symbol as method-name by default
|
82
|
+
end
|
83
|
+
|
84
|
+
def hello_world
|
85
|
+
"Hello World!"
|
86
|
+
end
|
87
|
+
|
88
|
+
def goodbye
|
89
|
+
"Goodbye World!"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# app.rb
|
94
|
+
|
95
|
+
class App < Flame::Application
|
96
|
+
mount IndexController do
|
97
|
+
# all methods will be mounted automatically, it's just an example of refinement
|
98
|
+
get '/hello', :hello_world
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# config.ru
|
103
|
+
|
104
|
+
require_relative './index_controller'
|
105
|
+
|
106
|
+
require_relative './app'
|
107
|
+
|
108
|
+
run App.new # or `run App`
|
109
|
+
```
|
110
|
+
|
111
|
+
More at [Wiki](https://github.com/AlexWayfer/flame/wiki).
|
112
|
+
|
113
|
+
## Benchmark
|
114
|
+
|
115
|
+
The last benchmark can be viewed [here](https://github.com/luislavena/bench-micro).
|
116
|
+
|
117
|
+
## Development
|
118
|
+
|
119
|
+
After checking out the repo, run `bundle install` to install dependencies.
|
120
|
+
|
121
|
+
Then, run `toys rspec` to run the tests.
|
122
|
+
|
123
|
+
To install this gem onto your local machine, run `toys gem install`.
|
124
|
+
|
125
|
+
To release a new version, run `toys gem release %version%`.
|
126
|
+
See how it works [here](https://github.com/AlexWayfer/gem_toys#release).
|
127
|
+
|
128
|
+
## Contributing
|
129
|
+
|
130
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/AlexWayfer/flame).
|
131
|
+
|
132
|
+
## License
|
133
|
+
|
134
|
+
The gem is available as open source under the terms of the
|
135
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/lib/flame.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'rack'
|
3
|
+
require 'gorilla_patch/inflections'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
## Base module
|
6
|
+
module Flame
|
7
|
+
using GorillaPatch::Inflections
|
8
|
+
|
9
|
+
%i[Config Application Controller VERSION]
|
10
|
+
.each do |constant_name|
|
11
|
+
autoload(
|
12
|
+
constant_name, "#{__dir__}/flame/#{constant_name.to_s.underscore}"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
data/lib/flame/application.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'addressable'
|
4
|
+
|
4
5
|
require_relative 'router'
|
5
6
|
require_relative 'dispatcher'
|
6
7
|
|
@@ -8,15 +9,25 @@ module Flame
|
|
8
9
|
## Core class, like Framework::Application
|
9
10
|
class Application
|
10
11
|
class << self
|
11
|
-
|
12
|
+
include Memery
|
13
|
+
|
14
|
+
## Remember root directory when inherited
|
15
|
+
def inherited(app)
|
16
|
+
super
|
17
|
+
app.root_dir = File.dirname caller(2..2).first.split(':')[0]
|
18
|
+
end
|
19
|
+
|
20
|
+
memoize def config
|
21
|
+
Flame::Config.new root_dir
|
22
|
+
end
|
12
23
|
|
13
24
|
## Router for routing
|
14
|
-
def router
|
15
|
-
|
25
|
+
memoize def router
|
26
|
+
Flame::Router.new(self)
|
16
27
|
end
|
17
28
|
|
18
|
-
def cached_tilts
|
19
|
-
|
29
|
+
memoize def cached_tilts
|
30
|
+
{}
|
20
31
|
end
|
21
32
|
|
22
33
|
## Require project directories, exclude executable files
|
@@ -25,34 +36,20 @@ module Flame
|
|
25
36
|
## Flame::Application.require_dirs(
|
26
37
|
## %w[config lib models helpers mailers services controllers]
|
27
38
|
## )
|
28
|
-
def require_dirs(dirs)
|
29
|
-
caller_dir = File.dirname caller_file
|
39
|
+
def require_dirs(dirs, ignore: [])
|
30
40
|
dirs.each do |dir|
|
31
|
-
|
32
|
-
.reject { |file| File.executable?(file) }
|
33
|
-
.sort_by { |s| [File.basename(s)[0], s] }
|
34
|
-
.each { |file| require File.expand_path(file) }
|
41
|
+
require_dir File.join(root_dir, dir), ignore: ignore
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
38
|
-
## Generating application config when inherited
|
39
|
-
def inherited(app)
|
40
|
-
app.config = Config.new(
|
41
|
-
app,
|
42
|
-
default_config_dirs(
|
43
|
-
root_dir: File.dirname(caller_file)
|
44
|
-
).merge(
|
45
|
-
environment: ENV['RACK_ENV'] || 'development'
|
46
|
-
)
|
47
|
-
)
|
48
|
-
end
|
49
|
-
|
50
45
|
## Make available `run Application` without `.new` for `rackup`
|
51
46
|
def call(env)
|
52
47
|
@app ||= new
|
53
48
|
@app.call env
|
54
49
|
end
|
55
50
|
|
51
|
+
using GorillaPatch::DeepDup
|
52
|
+
|
56
53
|
## Build a path to the given controller and action
|
57
54
|
##
|
58
55
|
## @param ctrl [Flame::Controller] class of controller
|
@@ -61,32 +58,45 @@ module Flame
|
|
61
58
|
## @return [String] path for requested method, controller and parameters
|
62
59
|
## @example Path for `show(id)` method of `ArticlesController`
|
63
60
|
## path_to ArticlesController, :show, id: 2 # => "/articles/show/2"
|
64
|
-
## @example Path for `new` method of `ArticlesController` with
|
65
|
-
## path_to ArticlesController, :new,
|
61
|
+
## @example Path for `new` method of `ArticlesController` with query
|
62
|
+
## path_to ArticlesController, :new, author_id: 1
|
66
63
|
## # => "/articles/new?author_id=1"
|
67
64
|
def path_to(ctrl, action = :index, args = {})
|
68
65
|
path = router.path_of(ctrl, action)
|
66
|
+
|
69
67
|
raise Errors::RouteNotFoundError.new(ctrl, action) unless path
|
70
|
-
|
71
|
-
|
68
|
+
|
69
|
+
args = args.deep_dup
|
72
70
|
path = path.assign_arguments(args)
|
73
71
|
path = '/' if path.empty?
|
72
|
+
query = Rack::Utils.build_nested_query args unless args.empty?
|
74
73
|
Addressable::URI.new(path: path, query: query).to_s
|
75
74
|
end
|
76
75
|
|
76
|
+
protected
|
77
|
+
|
78
|
+
attr_accessor :root_dir
|
79
|
+
|
77
80
|
private
|
78
81
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
82
|
+
def require_dir(dir, ignore: [])
|
83
|
+
files =
|
84
|
+
Dir[File.join(dir, '**/*.rb')]
|
85
|
+
.reject do |file|
|
86
|
+
File.executable?(file) ||
|
87
|
+
ignore.any? { |regexp| regexp.match?(file) }
|
88
|
+
end
|
89
|
+
files.sort_by! do |file|
|
90
|
+
[File.basename(file).start_with?('_') ? 1 : 2, file]
|
91
|
+
end
|
92
|
+
files.each { |file| require File.expand_path(file) }
|
83
93
|
end
|
84
94
|
|
85
95
|
## Mount controller in application class
|
86
96
|
## @param controller [Symbol] the snake-cased name of mounted controller
|
87
97
|
## (without `Controller` or `::IndexController` for namespaces)
|
88
98
|
## @param path [String, nil] root path for the mounted controller
|
89
|
-
## @yield refine defaults
|
99
|
+
## @yield refine defaults paths for a methods of the mounted controller
|
90
100
|
## @example Mount controller with defaults
|
91
101
|
## mount :articles # ArticlesController
|
92
102
|
## @example Mount controller with specific path
|
@@ -101,38 +111,29 @@ module Flame
|
|
101
111
|
## mount :cabinet do # Cabinet::IndexController
|
102
112
|
## mount :articles # Cabinet::ArticlesController
|
103
113
|
## end
|
104
|
-
def mount(
|
114
|
+
def mount(controller, path = nil, nested: true, &block)
|
105
115
|
## Add routes from controller to glob array
|
106
116
|
router.add Router::RoutesRefine.new(
|
107
|
-
|
117
|
+
namespace_name, controller, path, nested: nested, &block
|
108
118
|
)
|
109
119
|
end
|
110
120
|
|
111
121
|
using GorillaPatch::Namespace
|
112
122
|
|
113
|
-
def
|
123
|
+
def namespace_name
|
114
124
|
namespace = self
|
115
125
|
while namespace.name.nil? && namespace.superclass != Flame::Application
|
116
126
|
namespace = superclass
|
117
127
|
end
|
118
128
|
namespace.deconstantize
|
119
129
|
end
|
120
|
-
|
121
|
-
## Initialize default for config directories
|
122
|
-
def default_config_dirs(root_dir:)
|
123
|
-
result = { root_dir: File.realpath(root_dir) }
|
124
|
-
%i[public views config tmp].each do |key|
|
125
|
-
result[:"#{key}_dir"] = proc { File.join(config[:root_dir], key.to_s) }
|
126
|
-
end
|
127
|
-
result
|
128
|
-
end
|
129
130
|
end
|
130
131
|
|
131
132
|
def initialize(app = nil)
|
132
133
|
@app = app
|
133
134
|
end
|
134
135
|
|
135
|
-
## Request
|
136
|
+
## Request receiving method
|
136
137
|
def call(env)
|
137
138
|
@app.call(env) if @app.respond_to? :call
|
138
139
|
Flame::Dispatcher.new(self.class, env).run!
|
data/lib/flame/config.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors/config_file_not_found_error'
|
4
|
+
|
5
|
+
module Flame
|
6
|
+
## Class for application configuration
|
7
|
+
class Config < Hash
|
8
|
+
DEFAULT_DIRS =
|
9
|
+
%i[config log public tmp views].each_with_object({}) do |key, result|
|
10
|
+
result[:"#{key}_dir"] = proc { File.join(self[:root_dir], key.to_s) }
|
11
|
+
end.freeze
|
12
|
+
|
13
|
+
## Create an instance of application config
|
14
|
+
## @param app [Flame::Application] application
|
15
|
+
## @param hash [Hash] config content
|
16
|
+
def initialize(root_dir)
|
17
|
+
super()
|
18
|
+
replace DEFAULT_DIRS.merge(
|
19
|
+
root_dir: File.realpath(root_dir),
|
20
|
+
environment: ENV['RACK_ENV'] || 'development'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
## Get config value by key
|
25
|
+
## @param key [Symbol] config key
|
26
|
+
## @return [Object] config value
|
27
|
+
def [](key)
|
28
|
+
result = super(key)
|
29
|
+
result = instance_exec(&result) if result.class <= Proc && result.parameters.empty?
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
## Method for loading YAML-files from config directory
|
34
|
+
## @param file [String, Symbol]
|
35
|
+
## file name (typecast to String with '.yaml')
|
36
|
+
## @param key [Symbol, String, nil]
|
37
|
+
## key for allocating YAML in config Hash (typecast to Symbol)
|
38
|
+
## @param set [Boolean] allocating YAML in Config Hash
|
39
|
+
## @param require [Boolean] don't raise an error if file not found and not required
|
40
|
+
## @example Load SMTP file from `config/smtp.yaml' to config[]
|
41
|
+
## config.load_yaml('smtp.yaml')
|
42
|
+
## @example Load SMTP file without extension, by Symbol
|
43
|
+
## config.load_yaml(:smtp)
|
44
|
+
## @example Load SMTP file with other key to config[:mail]
|
45
|
+
## config.load_yaml('smtp.yaml', key: :mail)
|
46
|
+
## @example Load SMTP file without allocating in config[]
|
47
|
+
## config.load_yaml('smtp.yaml', set: false)
|
48
|
+
## @example Try to load nonexistent SMTP file without raising an error
|
49
|
+
## config.load_yaml('smtp.yaml', require: false)
|
50
|
+
def load_yaml(file, key: nil, set: true, required: true)
|
51
|
+
file = "#{file}.y{a,}ml" if file.is_a? Symbol
|
52
|
+
|
53
|
+
file_path = find_config_file file, required: required
|
54
|
+
return unless file_path
|
55
|
+
|
56
|
+
yaml = YAML.load_file(file_path)
|
57
|
+
key ||= File.basename(file, '.*')
|
58
|
+
self[key.to_sym] = yaml if set
|
59
|
+
yaml
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def find_config_file(filename, required:)
|
65
|
+
file_path = Dir[File.join(self[:config_dir], filename)].first
|
66
|
+
return file_path if file_path || !required
|
67
|
+
|
68
|
+
raise Errors::ConfigFileNotFoundError.new(
|
69
|
+
filename, self[:config_dir].sub(self[:root_dir], '')
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/flame/controller.rb
CHANGED
@@ -3,65 +3,48 @@
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'gorilla_patch/namespace'
|
5
5
|
|
6
|
+
require_relative 'router'
|
7
|
+
|
8
|
+
require_relative 'controller/actions'
|
9
|
+
require_relative 'controller/cookies'
|
6
10
|
require_relative 'controller/path_to'
|
7
|
-
require_relative 'render'
|
8
11
|
|
12
|
+
## Just because of `autoload`
|
9
13
|
module Flame
|
14
|
+
autoload :Render, "#{__dir__}/render"
|
15
|
+
|
10
16
|
## Class initialize when Dispatcher found route with it
|
11
17
|
## For new request and response
|
12
18
|
class Controller
|
13
|
-
extend
|
19
|
+
extend Actions
|
20
|
+
include Memery
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
class << self
|
23
|
+
attr_accessor :path_arguments
|
24
|
+
|
25
|
+
def path
|
26
|
+
return self::PATH if const_defined?(:PATH)
|
20
27
|
|
21
|
-
|
22
|
-
## @param actions [Array<Symbol>] Actions for inheritance
|
23
|
-
## @param exclude [Array<Symbol>] Actions for excluding from inheritance
|
24
|
-
## @example Inherit all parent actions
|
25
|
-
## class MyController < BaseController
|
26
|
-
## inherit_actions
|
27
|
-
## end
|
28
|
-
## @example Inherit certain parent actions
|
29
|
-
## class MyController < BaseController
|
30
|
-
## inherit_actions :index, :show
|
31
|
-
## end
|
32
|
-
## @example Inherit all parent actions exclude certain
|
33
|
-
## class MyController < BaseController
|
34
|
-
## inherit_actions exclude: %i[edit update]
|
35
|
-
## end
|
36
|
-
def self.inherit_actions(actions = superclass.actions, exclude: [])
|
37
|
-
(actions - exclude).each do |public_method|
|
38
|
-
um = superclass.public_instance_method(public_method)
|
39
|
-
define_method public_method, um
|
28
|
+
default_path
|
40
29
|
end
|
41
|
-
end
|
42
30
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
def self.included(ctrl)
|
56
|
-
ctrl.include @mod
|
57
|
-
|
58
|
-
(@mod.public_instance_methods - @exclude).each do |meth|
|
59
|
-
ctrl.send :define_method, meth, @mod.public_instance_method(meth)
|
60
|
-
end
|
61
|
-
end
|
31
|
+
private
|
32
|
+
|
33
|
+
using GorillaPatch::Inflections
|
34
|
+
|
35
|
+
## Default root path of the controller for requests
|
36
|
+
def default_path
|
37
|
+
modules = underscore.split('/')
|
38
|
+
parts = modules.pop.split('_')
|
39
|
+
parts.shift if parts.first == 'index'
|
40
|
+
parts.pop if %w[controller ctrl].include? parts.last
|
41
|
+
parts = [modules.last] if parts.empty?
|
42
|
+
Flame::Path.merge nil, parts.join('_')
|
62
43
|
end
|
63
44
|
end
|
64
45
|
|
46
|
+
extend Forwardable
|
47
|
+
|
65
48
|
def_delegators(
|
66
49
|
:@dispatcher,
|
67
50
|
:config, :request, :params, :halt, :session, :response, :status, :body,
|
@@ -74,6 +57,11 @@ module Flame
|
|
74
57
|
@dispatcher = dispatcher
|
75
58
|
end
|
76
59
|
|
60
|
+
## Cookies object as Hash
|
61
|
+
memoize def cookies
|
62
|
+
Cookies.new(request.cookies, response)
|
63
|
+
end
|
64
|
+
|
77
65
|
include Flame::Controller::PathTo
|
78
66
|
|
79
67
|
## Redirect for response
|
@@ -127,6 +115,7 @@ module Flame
|
|
127
115
|
content_dis = 'Content-Disposition'
|
128
116
|
response[content_dis] = disposition.to_s
|
129
117
|
return unless filename
|
118
|
+
|
130
119
|
response[content_dis] << "; filename=\"#{File.basename(filename)}\""
|
131
120
|
ext = File.extname(filename)
|
132
121
|
response.content_type = ext unless ext.empty?
|
@@ -157,13 +146,15 @@ module Flame
|
|
157
146
|
end
|
158
147
|
|
159
148
|
def not_found
|
160
|
-
|
149
|
+
default_body
|
161
150
|
end
|
162
151
|
|
163
152
|
## Default method for Internal Server Error, can be inherited
|
164
153
|
## @param _exception [Exception] exception from code executing
|
165
154
|
## @return [String] content of exception page
|
166
|
-
def server_error(
|
155
|
+
def server_error(exception)
|
156
|
+
raise exception if Object.const_defined?(:BetterErrors)
|
157
|
+
|
167
158
|
body default_body
|
168
159
|
end
|
169
160
|
|
@@ -184,6 +175,12 @@ module Flame
|
|
184
175
|
body
|
185
176
|
end
|
186
177
|
|
178
|
+
using GorillaPatch::Slice
|
179
|
+
|
180
|
+
def controller_arguments
|
181
|
+
params.slice(*self.class.path_arguments)
|
182
|
+
end
|
183
|
+
|
187
184
|
def extract_params_for(action)
|
188
185
|
## Take parameters from action method
|
189
186
|
parameters = method(action).parameters
|
@@ -198,35 +195,5 @@ module Flame
|
|
198
195
|
## Concat values
|
199
196
|
req_values + opt_values
|
200
197
|
end
|
201
|
-
|
202
|
-
def add_controller_class(args)
|
203
|
-
args.unshift(self.class) if args[0].is_a?(Symbol)
|
204
|
-
args.insert(1, :index) if args[0].is_a?(Class) && !args[1].is_a?(Symbol)
|
205
|
-
end
|
206
|
-
|
207
|
-
class << self
|
208
|
-
using GorillaPatch::Inflections
|
209
|
-
|
210
|
-
## Default root path of the controller for requests
|
211
|
-
def default_path
|
212
|
-
modules = underscore.split('/')
|
213
|
-
parts = modules.pop.split('_')
|
214
|
-
parts.shift if parts.first == 'index'
|
215
|
-
parts.pop if %w[controller ctrl].include? parts.last
|
216
|
-
parts = [modules.last] if parts.empty?
|
217
|
-
Flame::Path.merge nil, parts.join('_')
|
218
|
-
end
|
219
|
-
|
220
|
-
def refined_http_methods
|
221
|
-
@refined_http_methods ||= []
|
222
|
-
end
|
223
|
-
|
224
|
-
Flame::Router::HTTP_METHODS.each do |http_method|
|
225
|
-
downcased_http_method = http_method.downcase
|
226
|
-
define_method(downcased_http_method) do |action_path, action = nil|
|
227
|
-
refined_http_methods << [downcased_http_method, action_path, action]
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
198
|
end
|
232
199
|
end
|