rage-rb 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +0 -3
- data/README.md +1 -1
- data/lib/rage/application.rb +1 -1
- data/lib/rage/cli.rb +72 -2
- data/lib/rage/controller/api.rb +68 -17
- data/lib/rage/router/backend.rb +6 -3
- data/lib/rage/setup.rb +20 -4
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +5 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7684c979952ee81bee165b9b667dea87199f3fa28dadadc4878b29a12211fdac
|
4
|
+
data.tar.gz: 2428443ee2456ef375990decfbf36a2952670ee517ac07cf4c994f5b9b7076f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f59da6b77e69fa2b89761b30a497b4c0fa8f02cbabeed65c953b0f5e807b349e5b305bf31564bcc3eaeed4957215766e8781af5a5b8bbd9754e0461fa18f7b87
|
7
|
+
data.tar.gz: 733a15ef91abcbfc079a3bbbb83f82686038059b3c518c1c0a279e8000ad885c65cc5019cc691e2731fa1e59ca1f62e8fe95c8f454837ed0bdc65e181157ffc7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.0] - 2023-10-08
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- CLI `routes` task.
|
8
|
+
- CLI `console` task.
|
9
|
+
- `:if` and `:unless` options in `before_action`.
|
10
|
+
- Allow to set response headers.
|
11
|
+
- Block version of `before_action`.
|
12
|
+
|
3
13
|
## [0.2.0] - 2023-09-27
|
4
14
|
|
5
15
|
### Added
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -142,7 +142,7 @@ end
|
|
142
142
|
Version | Changes
|
143
143
|
------- |------------
|
144
144
|
0.2 :white_check_mark: | ~~Gem configuration by env.<br>Add `skip_before_action`.<br>Add `rescue_from`.<br>Router updates:<br> • make the `root` helper work correctly with `scope`;<br> • support the `defaults` option;~~
|
145
|
-
0.3 | CLI updates:<br> • `routes` task;<br> • `console` task;<br>Support the `:if` and `:unless` options in `before_action`.<br>Allow to set response headers
|
145
|
+
0.3 :white_check_mark: | ~~CLI updates:<br> • `routes` task;<br> • `console` task;<br>Support the `:if` and `:unless` options in `before_action`.<br>Allow to set response headers.~~
|
146
146
|
0.4 | Expose the `params` object.<br>Support header authentication with `authenticate_with_http_token`.<br>Router updates:<br> • add the `resources` route helper;<br> • add the `namespace` route helper;<br> • support regexp constraints;
|
147
147
|
0.5 | Implement Iodine-based equivalent of `ActionController::Live`.<br>Use `ActionDispatch::RemoteIp`.
|
148
148
|
0.6 | Expose the `cookies` object.<br>Expose the `send_data` and `send_file` methods.<br>Support conditional get with `etag` and `last_modified`.
|
data/lib/rage/application.rb
CHANGED
@@ -19,7 +19,7 @@ class Rage::Application
|
|
19
19
|
end
|
20
20
|
|
21
21
|
rescue => e
|
22
|
-
[500, {}, ["#{e.class}:#{e.message}\n\n#{e.backtrace.join("\n")}"]]
|
22
|
+
[500, {}, ["#{e.class}:#{e.message}\n\n#{e.backtrace.join("\n")}"]]
|
23
23
|
|
24
24
|
ensure
|
25
25
|
# notify Iodine the request can now be served
|
data/lib/rage/cli.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
2
|
require "thor"
|
4
3
|
require "rage"
|
4
|
+
require "irb"
|
5
5
|
|
6
6
|
module Rage
|
7
7
|
class CLI < Thor
|
@@ -25,11 +25,81 @@ module Rage
|
|
25
25
|
|
26
26
|
::Iodine.start
|
27
27
|
end
|
28
|
+
|
29
|
+
desc 'routes', 'List all routes.'
|
30
|
+
option :grep, aliases: "-g", desc: "Filter routes by pattern"
|
31
|
+
def routes
|
32
|
+
# the result would be something like this:
|
33
|
+
# Action Verb Path Controller#Action
|
34
|
+
# index GET / application#index
|
35
|
+
|
36
|
+
# load config/application.rb
|
37
|
+
environment
|
38
|
+
|
39
|
+
routes = Rage.__router.routes
|
40
|
+
|
41
|
+
pattern = options[:grep]
|
42
|
+
|
43
|
+
if pattern
|
44
|
+
routes = routes.select do |route|
|
45
|
+
route[:path].match?(pattern) || route[:raw_handler].to_s.match?(pattern) || route[:method].match?(pattern)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return puts 'Action Verb Path Controller#Action' if routes.empty?
|
50
|
+
|
51
|
+
# construct a table
|
52
|
+
table = []
|
53
|
+
|
54
|
+
# longest_path is either the length of the longest path or 5
|
55
|
+
longest_path = routes.map { |route| route[:path].length }.max + 3
|
56
|
+
longest_path = longest_path > 5 ? longest_path : 5
|
57
|
+
|
58
|
+
longest_verb = routes.map { |route| route[:method].length }.max + 3
|
59
|
+
longest_verb = longest_verb > 4 ? longest_verb : 7
|
60
|
+
|
61
|
+
# longest_handler is either the length of the longest handler or 7, since DELETE is the longest HTTP method
|
62
|
+
longest_handler = routes.map { |route| route[:raw_handler].is_a?(Proc) ? 7 : route[:raw_handler].split('#').last.length }.max + 3
|
63
|
+
longest_handler = longest_handler > 7 ? longest_handler : 7
|
64
|
+
|
65
|
+
# longest_controller is either the length of the longest controller or 12, since Controller#{length} is the longest controller
|
66
|
+
longest_controller = routes.map { |route| route[:raw_handler].is_a?(Proc) ? 7 : route[:raw_handler].to_s.length }.max + 3
|
67
|
+
longest_controller = longest_controller > 12 ? longest_controller : 12
|
68
|
+
|
69
|
+
routes.each do |route|
|
70
|
+
table << [
|
71
|
+
format("%- #{longest_handler}s", route[:raw_handler].is_a?(Proc) ? 'Lambda' : route[:raw_handler].split('#').last),
|
72
|
+
format("%- #{longest_verb}s", route[:method]),
|
73
|
+
format("%- #{longest_path}s", route[:path]),
|
74
|
+
format("%- #{longest_controller}s", route[:raw_handler].is_a?(Proc) ? 'Lambda' : route[:raw_handler])
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
table.unshift([format("%- #{longest_handler}s", 'Action'), format("%- #{longest_verb}s", 'Verb'), format("%- #{longest_path}s", 'Path'),
|
79
|
+
format("%- #{longest_path}s", "Controller#Action\n")])
|
80
|
+
# print the table
|
81
|
+
table.each do |row|
|
82
|
+
# this should be changed to use the main logger when added
|
83
|
+
puts row.join
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "c", "Start the app console."
|
88
|
+
def console
|
89
|
+
environment
|
90
|
+
ARGV.clear
|
91
|
+
IRB.start
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def environment
|
97
|
+
require File.expand_path("config/application.rb", Dir.pwd)
|
98
|
+
end
|
28
99
|
end
|
29
100
|
|
30
101
|
class NewAppGenerator < Thor::Group
|
31
102
|
include Thor::Actions
|
32
|
-
|
33
103
|
argument :path, type: :string
|
34
104
|
|
35
105
|
def self.source_root
|
data/lib/rage/controller/api.rb
CHANGED
@@ -12,13 +12,21 @@ class RageController::API
|
|
12
12
|
|
13
13
|
before_actions_chunk = if @__before_actions
|
14
14
|
filtered_before_actions = @__before_actions.select do |h|
|
15
|
-
(h[:only]
|
16
|
-
(h[:except]
|
15
|
+
(!h[:only] || h[:only].include?(action)) &&
|
16
|
+
(!h[:except] || !h[:except].include?(action))
|
17
17
|
end
|
18
18
|
|
19
19
|
lines = filtered_before_actions.map do |h|
|
20
|
+
condition = if h[:if] && h[:unless]
|
21
|
+
"if #{h[:if]} && !#{h[:unless]}"
|
22
|
+
elsif h[:if]
|
23
|
+
"if #{h[:if]}"
|
24
|
+
elsif h[:unless]
|
25
|
+
"unless #{h[:unless]}"
|
26
|
+
end
|
27
|
+
|
20
28
|
<<-RUBY
|
21
|
-
#{h[:name]}
|
29
|
+
#{h[:name]} #{condition}
|
22
30
|
return [@__status, @__headers, @__body] if @__rendered
|
23
31
|
RUBY
|
24
32
|
end
|
@@ -65,6 +73,16 @@ class RageController::API
|
|
65
73
|
klass.__rescue_handlers = @__rescue_handlers.freeze
|
66
74
|
end
|
67
75
|
|
76
|
+
# @private
|
77
|
+
@@__tmp_name_seed = ("a".."i").to_a.permutation
|
78
|
+
|
79
|
+
# @private
|
80
|
+
# define temporary method based on a block
|
81
|
+
def define_tmp_method(block)
|
82
|
+
name = @@__tmp_name_seed.next.join
|
83
|
+
define_method("__rage_tmp_#{name}", block)
|
84
|
+
end
|
85
|
+
|
68
86
|
############
|
69
87
|
#
|
70
88
|
# PUBLIC API
|
@@ -89,8 +107,7 @@ class RageController::API
|
|
89
107
|
def rescue_from(*klasses, with: nil, &block)
|
90
108
|
unless with
|
91
109
|
if block_given?
|
92
|
-
|
93
|
-
with = define_method("__#{name}", &block)
|
110
|
+
with = define_tmp_method(block)
|
94
111
|
else
|
95
112
|
raise "No handler provided. Pass the `with` keyword argument or provide a block."
|
96
113
|
end
|
@@ -107,21 +124,53 @@ class RageController::API
|
|
107
124
|
|
108
125
|
# Register a new `before_action` hook. Calls with the same `action_name` will overwrite the previous ones.
|
109
126
|
#
|
110
|
-
# @param action_name [String] the name of the callback to add
|
111
|
-
# @param
|
112
|
-
# @
|
127
|
+
# @param action_name [String, nil] the name of the callback to add
|
128
|
+
# @param [Hash] opts action options
|
129
|
+
# @option opts [Symbol, Array<Symbol>] :only restrict the callback to run only for specific actions
|
130
|
+
# @option opts [Symbol, Array<Symbol>] :except restrict the callback to run for all actions except specified
|
131
|
+
# @option opts [Symbol, Proc] :if only run the callback if the condition is true
|
132
|
+
# @option opts [Symbol, Proc] :unless only run the callback if the condition is false
|
113
133
|
# @example
|
114
134
|
# before_action :find_photo, only: :show
|
115
135
|
#
|
116
136
|
# def find_photo
|
117
137
|
# Photo.first
|
118
138
|
# end
|
119
|
-
|
139
|
+
# @example
|
140
|
+
# before_action :require_user, unless: :logged_in?
|
141
|
+
# @example
|
142
|
+
# before_action :set_locale, if: -> { params[:locale] != "en-US" }
|
143
|
+
# @example
|
144
|
+
# before_action do
|
145
|
+
# unless logged_in? # would be `controller.send(:logged_in?)` in Rails
|
146
|
+
# head :unauthorized
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
# @note The block form doesn't receive an argument and is executed on the controller level as if it was a regular method.
|
150
|
+
def before_action(action_name = nil, **opts, &block)
|
151
|
+
if block_given?
|
152
|
+
action_name = define_tmp_method(block)
|
153
|
+
elsif action_name.nil?
|
154
|
+
raise "No handler provided. Pass the `action_name` parameter or provide a block."
|
155
|
+
end
|
156
|
+
|
157
|
+
_only, _except, _if, _unless = opts.values_at(:only, :except, :if, :unless)
|
158
|
+
|
120
159
|
if @__before_actions && @__before_actions.frozen?
|
121
160
|
@__before_actions = @__before_actions.dup
|
122
161
|
end
|
123
162
|
|
124
|
-
action = {
|
163
|
+
action = {
|
164
|
+
name: action_name,
|
165
|
+
only: _only && Array(_only),
|
166
|
+
except: _except && Array(_except),
|
167
|
+
if: _if,
|
168
|
+
unless: _unless
|
169
|
+
}
|
170
|
+
|
171
|
+
action[:if] = define_tmp_method(action[:if]) if action[:if].is_a?(Proc)
|
172
|
+
action[:unless] = define_tmp_method(action[:unless]) if action[:unless].is_a?(Proc)
|
173
|
+
|
125
174
|
if @__before_actions.nil?
|
126
175
|
@__before_actions = [action]
|
127
176
|
elsif i = @__before_actions.find_index { |a| a[:name] == action_name }
|
@@ -192,7 +241,7 @@ class RageController::API
|
|
192
241
|
@__body << if json
|
193
242
|
json.is_a?(String) ? json : json.to_json
|
194
243
|
else
|
195
|
-
|
244
|
+
headers["content-type"] = "text/plain; charset=utf-8"
|
196
245
|
plain.to_s
|
197
246
|
end
|
198
247
|
|
@@ -225,11 +274,13 @@ class RageController::API
|
|
225
274
|
end
|
226
275
|
end
|
227
276
|
|
228
|
-
|
229
|
-
|
230
|
-
#
|
231
|
-
|
232
|
-
|
233
|
-
|
277
|
+
# Set response headers.
|
278
|
+
#
|
279
|
+
# @example
|
280
|
+
# headers["Content-Type"] = "application/pdf"
|
281
|
+
def headers
|
282
|
+
# copy-on-write implementation for the headers object
|
283
|
+
@__headers = {}.merge!(@__headers) if DEFAULT_HEADERS.equal?(@__headers)
|
284
|
+
@__headers
|
234
285
|
end
|
235
286
|
end
|
data/lib/rage/router/backend.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "uri"
|
4
4
|
|
5
5
|
class Rage::Router::Backend
|
6
|
+
attr_reader :routes
|
7
|
+
|
6
8
|
OPTIONAL_PARAM_REGEXP = /\/?\(\/?(:\w+)\/?\)/
|
7
9
|
STRING_HANDLER_REGEXP = /^([a-z0-9_\/]+)#([a-z_]+)$/
|
8
10
|
|
@@ -13,6 +15,7 @@ class Rage::Router::Backend
|
|
13
15
|
end
|
14
16
|
|
15
17
|
def on(method, path, handler, constraints: {}, defaults: nil)
|
18
|
+
raw_handler = handler
|
16
19
|
raise "Path could not be empty" if path&.empty?
|
17
20
|
|
18
21
|
if match_index = (path =~ OPTIONAL_PARAM_REGEXP)
|
@@ -42,7 +45,7 @@ class Rage::Router::Backend
|
|
42
45
|
handler = ->(env, _params) { orig_handler.call(env) }
|
43
46
|
end
|
44
47
|
|
45
|
-
__on(method, path, handler, constraints, defaults)
|
48
|
+
__on(method, path, handler, raw_handler, constraints, defaults)
|
46
49
|
end
|
47
50
|
|
48
51
|
def lookup(env)
|
@@ -52,7 +55,7 @@ class Rage::Router::Backend
|
|
52
55
|
|
53
56
|
private
|
54
57
|
|
55
|
-
def __on(method, path, handler, constraints, defaults)
|
58
|
+
def __on(method, path, handler, raw_handler, constraints, defaults)
|
56
59
|
@constrainer.validate_constraints(constraints)
|
57
60
|
# Let the constrainer know if any constraints are being used now
|
58
61
|
@constrainer.note_usage(constraints)
|
@@ -159,7 +162,7 @@ class Rage::Router::Backend
|
|
159
162
|
end
|
160
163
|
end
|
161
164
|
|
162
|
-
route = { method: method, path: path, pattern: pattern, params: params, constraints: constraints, handler: handler, defaults: defaults }
|
165
|
+
route = { method: method, path: path, pattern: pattern, params: params, constraints: constraints, handler: handler, raw_handler: raw_handler, defaults: defaults }
|
163
166
|
@routes << route
|
164
167
|
current_node.add_route(route, @constrainer)
|
165
168
|
end
|
data/lib/rage/setup.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
1
|
Iodine.patch_rack
|
2
2
|
|
3
|
-
|
3
|
+
require_relative "#{Rage.root}/config/environments/#{Rage.env}"
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
|
6
|
+
# load application files
|
7
|
+
app, bad = Dir["#{Rage.root}/app/**/*.rb"], []
|
8
|
+
|
9
|
+
loop do
|
10
|
+
path = app.shift
|
11
|
+
break if path.nil?
|
12
|
+
|
13
|
+
require_relative path
|
14
|
+
|
15
|
+
# push the file to the end of the list in case it depends on another file that has not yet been required;
|
16
|
+
# re-raise if only errored out files are left
|
17
|
+
rescue NameError
|
18
|
+
raise if (app - bad).empty?
|
19
|
+
app << path
|
20
|
+
bad << path
|
21
|
+
end
|
22
|
+
|
23
|
+
require_relative "#{Rage.root}/config/routes"
|
data/lib/rage/version.rb
CHANGED
data/lib/rage-rb.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "rack"
|
4
4
|
require "json"
|
5
5
|
require "iodine"
|
6
|
+
require "pathname"
|
6
7
|
|
7
8
|
module Rage
|
8
9
|
def self.application
|
@@ -33,6 +34,10 @@ module Rage
|
|
33
34
|
[:default, Rage.env.to_sym]
|
34
35
|
end
|
35
36
|
|
37
|
+
def self.root
|
38
|
+
@root ||= Pathname.new(".").expand_path
|
39
|
+
end
|
40
|
+
|
36
41
|
module Router
|
37
42
|
module Strategies
|
38
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rage-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Samoilov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|