leanweb 0.1.1 → 0.2.0
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 +4 -4
- data/bin/leanweb +17 -13
- data/lib/leanweb/app.rb +16 -28
- data/lib/leanweb/controller.rb +54 -53
- data/lib/leanweb/helpers.rb +24 -0
- data/lib/leanweb/route.rb +48 -27
- data/lib/leanweb.rb +13 -5
- metadata +68 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da54199f1863128e9bb23baf728dff6be60123b9cf44947370293222816da122
|
|
4
|
+
data.tar.gz: 60e11d76704347858cdffbde24d17b5d0edf1061ea91ef158dd5a6928e48bc4c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3b3abccd00de5d76a06513c021b409d19073c911f3d236b7c7412c42e723bad9e616514a02e278e55271d5faf5709f94fb283af6fa93aa873e2144ff0d3211b
|
|
7
|
+
data.tar.gz: a366dce05e7a8108e7b3ca4096112a3567e8082a0934e64d323401a938dceb24bfdc6c03dd53193827800b04a05c1c4c9ab53189cc45453e7925422dfb58535b
|
data/bin/leanweb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
4
5
|
#
|
|
@@ -7,8 +8,6 @@
|
|
|
7
8
|
# should have received a copy of this license along with the software. If not,
|
|
8
9
|
# see <https://hacktivista.org/licenses/>.
|
|
9
10
|
|
|
10
|
-
# frozen_string_literal: true
|
|
11
|
-
|
|
12
11
|
require 'fileutils'
|
|
13
12
|
require 'leanweb'
|
|
14
13
|
|
|
@@ -17,12 +16,15 @@ require 'leanweb'
|
|
|
17
16
|
files = [
|
|
18
17
|
{
|
|
19
18
|
filename: 'Gemfile',
|
|
19
|
+
# TODO: Use {LeanWeb::VERSION} when v1 is reached.
|
|
20
20
|
content: <<~RUBY
|
|
21
21
|
# frozen_string_literal: true
|
|
22
22
|
|
|
23
23
|
source 'https://rubygems.org'
|
|
24
24
|
|
|
25
|
-
gem 'leanweb', '~>
|
|
25
|
+
gem 'leanweb', '~> 0.2'
|
|
26
|
+
gem 'haml'
|
|
27
|
+
gem 'rake'
|
|
26
28
|
RUBY
|
|
27
29
|
}, {
|
|
28
30
|
filename: 'config.ru',
|
|
@@ -30,21 +32,21 @@ files = [
|
|
|
30
32
|
# frozen_string_literal: true
|
|
31
33
|
|
|
32
34
|
require 'leanweb'
|
|
35
|
+
require_relative 'routes'
|
|
33
36
|
|
|
34
37
|
if ENV['RACK_ENV'] == 'development'
|
|
35
38
|
use(Rack::Reloader, 0)
|
|
36
|
-
use(Rack::Static, urls: [''], root: 'public', cascade: true)
|
|
39
|
+
use(Rack::Static, urls: ['/assets'], root: 'public', cascade: true)
|
|
37
40
|
end
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
run app
|
|
42
|
+
run LeanWeb::App.new(ROUTES)
|
|
41
43
|
RUBY
|
|
42
44
|
}, {
|
|
43
45
|
filename: 'routes.rb',
|
|
44
46
|
content: <<~RUBY
|
|
45
47
|
# frozen_string_literal: true
|
|
46
48
|
|
|
47
|
-
[{ path: '/' }]
|
|
49
|
+
ROUTES = [{ path: '/' }].freeze
|
|
48
50
|
RUBY
|
|
49
51
|
}, {
|
|
50
52
|
filename: 'Rakefile',
|
|
@@ -55,8 +57,9 @@ files = [
|
|
|
55
57
|
|
|
56
58
|
task default: %w[build]
|
|
57
59
|
|
|
58
|
-
task :
|
|
59
|
-
|
|
60
|
+
task :build_static do
|
|
61
|
+
require_relative 'routes'
|
|
62
|
+
LeanWeb::App.new(ROUTES).build_static
|
|
60
63
|
end
|
|
61
64
|
RUBY
|
|
62
65
|
}, {
|
|
@@ -66,10 +69,10 @@ files = [
|
|
|
66
69
|
|
|
67
70
|
require 'leanweb'
|
|
68
71
|
|
|
69
|
-
# Main controller is the default controller
|
|
72
|
+
# Main controller is the default controller.
|
|
70
73
|
class MainController < LeanWeb::Controller
|
|
71
74
|
def index_get
|
|
72
|
-
|
|
75
|
+
render_response 'index.haml'
|
|
73
76
|
end
|
|
74
77
|
end
|
|
75
78
|
RUBY
|
|
@@ -97,9 +100,10 @@ begin
|
|
|
97
100
|
path = ARGV[1] || '.'
|
|
98
101
|
FileUtils.mkdir_p(path)
|
|
99
102
|
FileUtils.cd(path)
|
|
100
|
-
FileUtils.mkdir_p(['public', 'src/controllers', 'src/views'])
|
|
101
|
-
files.each
|
|
103
|
+
FileUtils.mkdir_p(['public/assets', 'src/controllers', 'src/views'])
|
|
104
|
+
files.each{ |file| File.write(file[:filename], file[:content]) }
|
|
102
105
|
`git init`
|
|
106
|
+
`bundle install`
|
|
103
107
|
puts("Project '#{File.basename(Dir.getwd)}' successfully created.")
|
|
104
108
|
rescue # rubocop:disable Style/RescueStandardError
|
|
105
109
|
puts('Woops! Something went wrong.')
|
data/lib/leanweb/app.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
2
4
|
#
|
|
3
5
|
# This file is part of "LeanWeb" and licensed under the terms of the Hacktivista
|
|
@@ -5,8 +7,6 @@
|
|
|
5
7
|
# should have received a copy of this license along with the software. If not,
|
|
6
8
|
# see <https://hacktivista.org/licenses/>.
|
|
7
9
|
|
|
8
|
-
# frozen_string_literal: true
|
|
9
|
-
|
|
10
10
|
require 'rack'
|
|
11
11
|
|
|
12
12
|
module LeanWeb
|
|
@@ -20,19 +20,15 @@ module LeanWeb
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# Entry point for dynamic routes (Rack).
|
|
23
|
+
#
|
|
23
24
|
# @param env [Hash] `env` for Rack.
|
|
24
25
|
def call(env)
|
|
25
26
|
request = Rack::Request.new(env)
|
|
26
|
-
route =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
rescue TypeError
|
|
30
|
-
r[:path] == request.path
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
return [404, {}, ['Not found']] unless route_exists?(route)
|
|
27
|
+
route = find_route(request)
|
|
28
|
+
route = Route.new(**route) unless route.nil?
|
|
29
|
+
return [404, {}, ['Not found']] unless route&.available?
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
route.respond(request)
|
|
36
32
|
end
|
|
37
33
|
|
|
38
34
|
# Build static routes to files.
|
|
@@ -42,31 +38,23 @@ module LeanWeb
|
|
|
42
38
|
next unless route.static
|
|
43
39
|
|
|
44
40
|
begin
|
|
45
|
-
route.static.each
|
|
41
|
+
route.static.each{ |seed| route.build(route.seed_path(seed)) }
|
|
46
42
|
rescue NoMethodError
|
|
47
43
|
route.build
|
|
48
44
|
end
|
|
49
45
|
end
|
|
50
46
|
end
|
|
51
47
|
|
|
52
|
-
# Initialize by evaluating the routes file.
|
|
53
|
-
# Do this here so users don't freak out for using eval and rubocop is happy
|
|
54
|
-
# on client side.
|
|
55
|
-
# @param file [String] Routes file.
|
|
56
|
-
def self.init(file = 'routes.rb')
|
|
57
|
-
new(eval(File.read(file))) # rubocop:disable Security/Eval
|
|
58
|
-
end
|
|
59
|
-
|
|
60
48
|
protected
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
50
|
+
def find_route(request)
|
|
51
|
+
@routes.find do |r|
|
|
52
|
+
(r[:method] || 'GET') == request.request_method && begin
|
|
53
|
+
r[:path] =~ request.path
|
|
54
|
+
rescue TypeError
|
|
55
|
+
r[:path] == request.path
|
|
56
|
+
end
|
|
57
|
+
end
|
|
70
58
|
end
|
|
71
59
|
end
|
|
72
60
|
end
|
data/lib/leanweb/controller.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
2
4
|
#
|
|
3
5
|
# This file is part of "LeanWeb" and licensed under the terms of the Hacktivista
|
|
@@ -5,16 +7,15 @@
|
|
|
5
7
|
# should have received a copy of this license along with the software. If not,
|
|
6
8
|
# see <https://hacktivista.org/licenses/>.
|
|
7
9
|
|
|
8
|
-
# frozen_string_literal: true
|
|
9
|
-
|
|
10
10
|
require 'rack'
|
|
11
|
+
require 'tilt'
|
|
11
12
|
|
|
12
13
|
module LeanWeb
|
|
13
14
|
# Controller is a base controller with `@route`, `@request` and `@response`
|
|
14
|
-
# private attributes that will be shared with your views when you
|
|
15
|
-
#
|
|
15
|
+
# private attributes that will be shared with your views when you
|
|
16
|
+
# {#render_response}.
|
|
16
17
|
#
|
|
17
|
-
# Even if you don't {
|
|
18
|
+
# Even if you don't {#render_response}, you can use the `.finish` method from
|
|
18
19
|
# `Rack::Response` on `@response` to return a proper `Rack` response.
|
|
19
20
|
class Controller
|
|
20
21
|
# @param route [Route]
|
|
@@ -25,65 +26,65 @@ module LeanWeb
|
|
|
25
26
|
@response = Rack::Response.new(nil, 200)
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
# Render magic. Supports
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# Depending on {Route#path} and {#render} `path` you will render different
|
|
32
|
-
# documents:
|
|
33
|
-
#
|
|
34
|
-
# - {Route#path} `/a/b/c` and `render('d')` will render `src/views/a/b/d`
|
|
35
|
-
# - {Route#path} `/a/b/c/` and `render('d')` will render `src/views/a/b/c/d`
|
|
36
|
-
# - `render('~/custom')` will render `src/views/custom`.
|
|
37
|
-
# - `render('/custom')` will render `/custom`.
|
|
29
|
+
# Render magic. Supports every file extension that Tilt supports. Defaults
|
|
30
|
+
# to ERB when file extension is unknown.
|
|
38
31
|
#
|
|
39
32
|
# @param path [String] Might be an absolute path or a relative path to
|
|
40
|
-
# `src/views
|
|
41
|
-
# `@route.path`. You can also make it relative to {LeanWeb::VIEW_PATH} by
|
|
42
|
-
# prepending `~`.
|
|
33
|
+
# `src/views/`.
|
|
43
34
|
# @param content_type [String] Defaults to the proper Content-Type for file
|
|
44
|
-
#
|
|
35
|
+
# extension, `text/plain` on unknown files.
|
|
36
|
+
# @yield Optionally pass a block for nested rendering.
|
|
37
|
+
# @return [Rack::Request#finish] A valid Rack response.
|
|
38
|
+
def render_response(path, content_type = nil, &block)
|
|
39
|
+
template = create_template(path)
|
|
40
|
+
@response.set_header(
|
|
41
|
+
'Content-Type',
|
|
42
|
+
content_type || template.class.metadata[:mime_type] || 'text/plain'
|
|
43
|
+
)
|
|
44
|
+
@response.write(template.render(self){ block.call if block_given? })
|
|
45
|
+
@response.finish
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Template rendering engine. Useful for partials / nested views.
|
|
45
49
|
#
|
|
46
|
-
# @
|
|
47
|
-
|
|
50
|
+
# @param path [String] Same as on {#render_response}.
|
|
51
|
+
# @param options [Hash] Options for Tilt, defaults to
|
|
52
|
+
# template_defaults[extension].
|
|
53
|
+
# @return [String] Rendered `path`.
|
|
54
|
+
def create_template(path, options = nil)
|
|
48
55
|
path = absolute_view_path(path)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
ext = File.extname(path)[1..] || ''
|
|
57
|
+
ext = 'erb' unless Tilt.registered?(ext)
|
|
58
|
+
Tilt[ext].new(path, 1, options || template_defaults[ext] || {})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Relative route to path from public directory considering current route.
|
|
62
|
+
#
|
|
63
|
+
# @param path [String] path from public directory, never begins with `/`.
|
|
64
|
+
def base_url(path = '.')
|
|
65
|
+
@base_url ||= @route.str_path[1..]
|
|
66
|
+
.sub(%r{[^/]*$}, '')
|
|
67
|
+
.gsub(%r{[^/]+}, '..')
|
|
68
|
+
|
|
69
|
+
@base_url + path
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Request params.
|
|
73
|
+
def params
|
|
74
|
+
@request.params
|
|
61
75
|
end
|
|
62
76
|
|
|
63
77
|
protected
|
|
64
78
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case relative_path[0]
|
|
69
|
-
when '/'
|
|
70
|
-
relative_path
|
|
71
|
-
when '~'
|
|
72
|
-
relative_path.sub('~', LeanWeb::VIEW_PATH)
|
|
73
|
-
else
|
|
74
|
-
"#{view_path_by_route_path}/#{relative_path}"
|
|
75
|
-
end
|
|
79
|
+
# Set default options for Tilt in the format 'extension' => { options }.
|
|
80
|
+
def template_defaults
|
|
81
|
+
{}
|
|
76
82
|
end
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
elsif @route.path[-1] != '/'
|
|
83
|
-
File.dirname(@route.path)
|
|
84
|
-
else
|
|
85
|
-
@route.path.chomp('/')
|
|
86
|
-
end
|
|
84
|
+
# @param path [String]
|
|
85
|
+
# @return [String] Full path.
|
|
86
|
+
def absolute_view_path(path)
|
|
87
|
+
path[0] == '/' ? path : "#{LeanWeb::VIEW_PATH}/#{path}"
|
|
87
88
|
end
|
|
88
89
|
end
|
|
89
90
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
4
|
+
#
|
|
5
|
+
# This file is part of "LeanWeb" and licensed under the terms of the Hacktivista
|
|
6
|
+
# General Public License version 0.1 or (at your option) any later version. You
|
|
7
|
+
# should have received a copy of this license along with the software. If not,
|
|
8
|
+
# see <https://hacktivista.org/licenses/>.
|
|
9
|
+
|
|
10
|
+
# String helpers.
|
|
11
|
+
class String
|
|
12
|
+
# String to PascalCase.
|
|
13
|
+
def pascalize
|
|
14
|
+
camelize(pascal: true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# String to camelCase.
|
|
18
|
+
# @param pascal [Boolean] If true first letter is uppercase.
|
|
19
|
+
def camelize(pascal: false)
|
|
20
|
+
str = gsub(/[-_\s]+(.?)/){ |match| match[1].upcase }
|
|
21
|
+
str[0] = pascal ? str[0].upcase : str[0].downcase
|
|
22
|
+
str
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/leanweb/route.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
2
4
|
#
|
|
3
5
|
# This file is part of "LeanWeb" and licensed under the terms of the Hacktivista
|
|
@@ -5,7 +7,7 @@
|
|
|
5
7
|
# should have received a copy of this license along with the software. If not,
|
|
6
8
|
# see <https://hacktivista.org/licenses/>.
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
require 'rack/mock'
|
|
9
11
|
|
|
10
12
|
module LeanWeb
|
|
11
13
|
# Action for {Route#action}.
|
|
@@ -20,7 +22,7 @@ module LeanWeb
|
|
|
20
22
|
#
|
|
21
23
|
# @param path [String, Regexp] Path matcher, can be an String or Regexp with
|
|
22
24
|
# positional or named capture groups, `@action` will receive these as
|
|
23
|
-
# positional or named arguments.
|
|
25
|
+
# positional or named arguments. Always begins with `/`.
|
|
24
26
|
# @param method [String, nil] Must be an HTTP verb such as `GET` or `POST`.
|
|
25
27
|
# @param action [Proc, Hash, String, nil] References a Method/Proc to be
|
|
26
28
|
# triggered. It can be:
|
|
@@ -29,19 +31,29 @@ module LeanWeb
|
|
|
29
31
|
# - A hash with `{ 'file' => 'action' }` only (which has a controller
|
|
30
32
|
# class name `{File}Controller`).
|
|
31
33
|
# - A simple string (which will consider file `main.rb` and controller
|
|
32
|
-
# `MainController`). Defaults to "{path_basename}_{method}", (ex:
|
|
34
|
+
# `MainController`). Defaults to "{#path_basename}_{#method}", (ex:
|
|
33
35
|
# `index_get`).
|
|
34
36
|
# - It can also be a `Proc`.
|
|
35
37
|
#
|
|
36
|
-
# @param static [Boolean|Array] Defines a route as static.
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# params.
|
|
40
|
-
def initialize(path:, method: 'GET', action: nil, static:
|
|
38
|
+
# @param static [Boolean|Array] Defines a route as static. Defaults true for
|
|
39
|
+
# GET method, false otherwise. Set to `false` to say it can only work
|
|
40
|
+
# dynamically. You can also supply an array of arrays or hashes to
|
|
41
|
+
# generate static files based on that positional or keyword params.
|
|
42
|
+
def initialize(path:, method: 'GET', action: nil, static: nil)
|
|
41
43
|
@path = path
|
|
42
44
|
@method = method
|
|
43
45
|
self.action = action
|
|
44
|
-
@static = static
|
|
46
|
+
@static = static.nil? ? @method == 'GET' : static
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Check if route is available.
|
|
50
|
+
#
|
|
51
|
+
# If on production environment (not `development`), should serve only
|
|
52
|
+
# dynamic (not `static`) routes.
|
|
53
|
+
def available?
|
|
54
|
+
return @static == false if ENV['RACK_ENV'] != 'development'
|
|
55
|
+
|
|
56
|
+
true
|
|
45
57
|
end
|
|
46
58
|
|
|
47
59
|
# Last identifier on a path, returns `index` for `/`.
|
|
@@ -50,14 +62,14 @@ module LeanWeb
|
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
# @param request [Rack::Request]
|
|
53
|
-
# @return a valid rack response.
|
|
65
|
+
# @return [Array] a valid rack response.
|
|
54
66
|
def respond(request)
|
|
55
67
|
return respond_proc(request) if @action.instance_of?(Proc)
|
|
56
68
|
|
|
57
69
|
respond_method(request)
|
|
58
70
|
end
|
|
59
71
|
|
|
60
|
-
# String path, independent if {path} is Regexp or String.
|
|
72
|
+
# String path, independent if {#path} is Regexp or String.
|
|
61
73
|
def str_path
|
|
62
74
|
@path.source.gsub(/[\^$]/, '')
|
|
63
75
|
rescue NoMethodError
|
|
@@ -65,26 +77,26 @@ module LeanWeb
|
|
|
65
77
|
end
|
|
66
78
|
|
|
67
79
|
# On Regexp paths, return a string valid for making a request to this route.
|
|
80
|
+
#
|
|
68
81
|
# @param seed [Array, Hash] Seeds to use as replacement on capture groups.
|
|
69
82
|
# @return [String] sown path.
|
|
70
83
|
def seed_path(seed)
|
|
71
84
|
sown_path = str_path
|
|
72
85
|
if seed.instance_of?(Hash)
|
|
73
|
-
seed.each
|
|
86
|
+
seed.each{ |key, val| sown_path.sub!(/\(\?<#{key}>[^)]+\)/, val) }
|
|
74
87
|
else
|
|
75
|
-
seed.each
|
|
88
|
+
seed.each{ |val| sown_path.sub!(/\([^)]+\)/, val) }
|
|
76
89
|
end
|
|
77
90
|
sown_path
|
|
78
91
|
end
|
|
79
92
|
|
|
80
93
|
# Build this route as an static file and place it relative to
|
|
81
94
|
# {LeanWeb::PUBLIC_PATH}.
|
|
95
|
+
#
|
|
82
96
|
# @param request_path [String] Request path for dynamic (regex) routes.
|
|
83
97
|
def build(request_path = @path)
|
|
84
98
|
response = respond(
|
|
85
|
-
Rack::Request.new(
|
|
86
|
-
{ 'PATH_INFO' => request_path, 'REQUEST_METHOD' => 'GET' }
|
|
87
|
-
)
|
|
99
|
+
Rack::Request.new(Rack::MockRequest.env_for(request_path))
|
|
88
100
|
)
|
|
89
101
|
out_path = output_path(request_path, response[1]['Content-Type'] || nil)
|
|
90
102
|
FileUtils.mkdir_p(File.dirname(out_path))
|
|
@@ -103,36 +115,44 @@ module LeanWeb
|
|
|
103
115
|
end
|
|
104
116
|
end
|
|
105
117
|
|
|
106
|
-
# @param
|
|
118
|
+
# @param src_value [Hash, String, nil] Check {#initialize} action param for
|
|
107
119
|
# valid input.
|
|
108
120
|
# @return [Hash] valid hash for {Action}.
|
|
109
|
-
def prepare_action_hash(
|
|
121
|
+
def prepare_action_hash(src_value) # rubocop:disable Metrics/MethodLength
|
|
110
122
|
begin
|
|
111
|
-
|
|
112
|
-
|
|
123
|
+
if %i[file controller action].include?(src_value.keys.first)
|
|
124
|
+
value = src_value
|
|
125
|
+
else
|
|
126
|
+
value = {}
|
|
127
|
+
value[:file], value[:action] = src_value.first
|
|
128
|
+
end
|
|
113
129
|
rescue NoMethodError
|
|
114
|
-
value = { action:
|
|
130
|
+
value = { action: src_value }
|
|
115
131
|
end
|
|
116
132
|
value[:file] ||= 'main'
|
|
117
|
-
value[:controller] ||= "#{value[:file].
|
|
118
|
-
value[:action] ||=
|
|
133
|
+
value[:controller] ||= "#{value[:file].pascalize}Controller"
|
|
134
|
+
value[:action] ||= default_action_name
|
|
119
135
|
value
|
|
120
136
|
end
|
|
121
137
|
|
|
138
|
+
def default_action_name
|
|
139
|
+
"#{path_basename.gsub('-', '_')}_#{@method.downcase}"
|
|
140
|
+
end
|
|
141
|
+
|
|
122
142
|
# @param request [Rack::Request]
|
|
123
|
-
# @return a valid
|
|
143
|
+
# @return [Array] a valid Rack response.
|
|
124
144
|
def respond_method(request)
|
|
125
145
|
params = action_params(request.path)
|
|
126
146
|
require_relative("#{LeanWeb::CONTROLLER_PATH}/#{@action.file}")
|
|
127
147
|
controller = Object.const_get(@action.controller).new(self, request)
|
|
128
|
-
return controller.public_send(@action.action, **params)\
|
|
148
|
+
return controller.public_send(@action.action, **params) \
|
|
129
149
|
if params.instance_of?(Hash)
|
|
130
150
|
|
|
131
151
|
controller.public_send(@action.action, *params)
|
|
132
152
|
end
|
|
133
153
|
|
|
134
154
|
# @param request [Rack::Request]
|
|
135
|
-
# @return a valid
|
|
155
|
+
# @return [Array] a valid Rack response.
|
|
136
156
|
def respond_proc(request)
|
|
137
157
|
params = action_params(request.path)
|
|
138
158
|
return @action.call(**params) if params.instance_of?(Hash)
|
|
@@ -146,13 +166,14 @@ module LeanWeb
|
|
|
146
166
|
return nil unless @path.instance_of?(Regexp)
|
|
147
167
|
|
|
148
168
|
matches = @path.match(request_path)
|
|
149
|
-
return matches.named_captures.transform_keys(&:to_sym)\
|
|
169
|
+
return matches.named_captures.transform_keys(&:to_sym) \
|
|
150
170
|
if matches.named_captures != {}
|
|
151
171
|
|
|
152
172
|
matches.captures
|
|
153
173
|
end
|
|
154
174
|
|
|
155
175
|
# Output path for public file.
|
|
176
|
+
#
|
|
156
177
|
# @param path [String]
|
|
157
178
|
# @param content_type [String]
|
|
158
179
|
# @return [String] absolute route to path + extension based on content_type.
|
data/lib/leanweb.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright 2022 Felix Freeman <libsys@hacktivista.org>
|
|
2
4
|
#
|
|
3
5
|
# This file is part of "LeanWeb" and licensed under the terms of the Hacktivista
|
|
@@ -5,13 +7,11 @@
|
|
|
5
7
|
# should have received a copy of this license along with the software. If not,
|
|
6
8
|
# see <https://hacktivista.org/licenses/>.
|
|
7
9
|
|
|
8
|
-
# frozen_string_literal: true
|
|
9
|
-
|
|
10
10
|
# LeanWeb is a minimal hybrid static / dynamic web framework.
|
|
11
11
|
module LeanWeb
|
|
12
|
-
VERSION = '0.
|
|
12
|
+
VERSION = '0.2.0'
|
|
13
13
|
|
|
14
|
-
ROOT_PATH = ENV
|
|
14
|
+
ROOT_PATH = ENV.fetch('LEANWEB_ROOT_PATH', Dir.pwd)
|
|
15
15
|
CONTROLLER_PATH = "#{ROOT_PATH}/src/controllers"
|
|
16
16
|
VIEW_PATH = "#{ROOT_PATH}/src/views"
|
|
17
17
|
PUBLIC_PATH = "#{ROOT_PATH}/public"
|
|
@@ -21,10 +21,18 @@ module LeanWeb
|
|
|
21
21
|
'application/javascript' => '.js',
|
|
22
22
|
'application/json' => '.json',
|
|
23
23
|
'text/html' => '.html',
|
|
24
|
-
'text/plain' => '.txt'
|
|
24
|
+
'text/plain' => '.txt',
|
|
25
|
+
'text/css' => '.css',
|
|
26
|
+
'text/csv' => '.csv'
|
|
25
27
|
}.freeze
|
|
26
28
|
|
|
27
29
|
autoload :Route, 'leanweb/route.rb'
|
|
28
30
|
autoload :Controller, 'leanweb/controller.rb'
|
|
29
31
|
autoload :App, 'leanweb/app.rb'
|
|
30
32
|
end
|
|
33
|
+
|
|
34
|
+
require_relative 'leanweb/helpers'
|
|
35
|
+
|
|
36
|
+
# TODO: Remove if/when tilt-emacs_org gets merged on a Tilt release.
|
|
37
|
+
require 'tilt'
|
|
38
|
+
Tilt.register_lazy(:EmacsOrgTemplate, 'tilt/emacs_org', 'org')
|
metadata
CHANGED
|
@@ -1,113 +1,141 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leanweb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Felix Freeman
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-01
|
|
11
|
+
date: 2022-08-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: rack
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 2.2.4
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 2.2.4
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: tilt
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 2.0.10
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 2.0.10
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: haml
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
48
|
-
type: :
|
|
47
|
+
version: 5.2.2
|
|
48
|
+
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 5.2.2
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: minitest
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 5.16.2
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 5.16.2
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rake
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 13.0.6
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 13.0.6
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: redcarpet
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
60
88
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
89
|
+
version: 3.5.1
|
|
62
90
|
type: :development
|
|
63
91
|
prerelease: false
|
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
93
|
requirements:
|
|
66
|
-
- - "
|
|
94
|
+
- - "~>"
|
|
67
95
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
96
|
+
version: 3.5.1
|
|
69
97
|
- !ruby/object:Gem::Dependency
|
|
70
98
|
name: rubocop
|
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
|
72
100
|
requirements:
|
|
73
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
74
102
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
103
|
+
version: 1.31.2
|
|
76
104
|
type: :development
|
|
77
105
|
prerelease: false
|
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
107
|
requirements:
|
|
80
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
81
109
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
110
|
+
version: 1.31.2
|
|
83
111
|
- !ruby/object:Gem::Dependency
|
|
84
112
|
name: rubocop-minitest
|
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
|
86
114
|
requirements:
|
|
87
|
-
- - "
|
|
115
|
+
- - "~>"
|
|
88
116
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
117
|
+
version: 0.20.1
|
|
90
118
|
type: :development
|
|
91
119
|
prerelease: false
|
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
121
|
requirements:
|
|
94
|
-
- - "
|
|
122
|
+
- - "~>"
|
|
95
123
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
124
|
+
version: 0.20.1
|
|
97
125
|
- !ruby/object:Gem::Dependency
|
|
98
126
|
name: yard
|
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
|
100
128
|
requirements:
|
|
101
|
-
- - "
|
|
129
|
+
- - "~>"
|
|
102
130
|
- !ruby/object:Gem::Version
|
|
103
|
-
version:
|
|
131
|
+
version: 0.9.28
|
|
104
132
|
type: :development
|
|
105
133
|
prerelease: false
|
|
106
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
135
|
requirements:
|
|
108
|
-
- - "
|
|
136
|
+
- - "~>"
|
|
109
137
|
- !ruby/object:Gem::Version
|
|
110
|
-
version:
|
|
138
|
+
version: 0.9.28
|
|
111
139
|
description:
|
|
112
140
|
email:
|
|
113
141
|
- libsys@hacktivista.org
|
|
@@ -120,14 +148,17 @@ files:
|
|
|
120
148
|
- lib/leanweb.rb
|
|
121
149
|
- lib/leanweb/app.rb
|
|
122
150
|
- lib/leanweb/controller.rb
|
|
151
|
+
- lib/leanweb/helpers.rb
|
|
123
152
|
- lib/leanweb/route.rb
|
|
124
|
-
homepage: https://
|
|
153
|
+
homepage: https://leanweb.hacktivista.org
|
|
125
154
|
licenses:
|
|
126
155
|
- LicenseRef-LICENSE
|
|
127
156
|
metadata:
|
|
128
|
-
homepage_uri: https://
|
|
157
|
+
homepage_uri: https://leanweb.hacktivista.org
|
|
129
158
|
source_code_uri: https://git.hacktivista.org/leanweb
|
|
159
|
+
changelog_uri: https://leanweb.hacktivista.org/file.CHANGELOG.html
|
|
130
160
|
rubygems_mfa_required: 'true'
|
|
161
|
+
yard.run: yri
|
|
131
162
|
post_install_message:
|
|
132
163
|
rdoc_options: []
|
|
133
164
|
require_paths:
|
|
@@ -136,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
136
167
|
requirements:
|
|
137
168
|
- - ">="
|
|
138
169
|
- !ruby/object:Gem::Version
|
|
139
|
-
version: 2.
|
|
170
|
+
version: 2.7.4
|
|
140
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
172
|
requirements:
|
|
142
173
|
- - ">="
|