activefunction 0.3.5 → 0.4.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/CHANGELOG.md +8 -1
- data/README.md +141 -72
- data/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb +44 -40
- data/lib/.rbnext/3.0/active_function/base.rb +38 -0
- data/lib/.rbnext/3.0/active_function/functions/response.rb +16 -19
- data/lib/.rbnext/3.0/active_function.rb +50 -0
- data/lib/.rbnext/3.1/active_function/functions/response.rb +27 -0
- data/lib/active_function/base.rb +32 -14
- data/lib/active_function/functions/callbacks.rb +5 -59
- data/lib/active_function/functions/rendering.rb +13 -9
- data/lib/active_function/functions/response.rb +16 -19
- data/lib/active_function/functions/strong_parameters.rb +44 -40
- data/lib/active_function/version.rb +1 -1
- data/lib/active_function.rb +41 -3
- metadata +24 -60
- data/lib/.rbnext/3.0/active_function/functions/core.rb +0 -49
- data/lib/active_function/functions/core.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f2bbae1e08a02af0dbabf4b235ece3823d17aec26e76b24ad7f4b514ea8526c
|
4
|
+
data.tar.gz: 6097f177bb4b5dff0583c21c40d45c67aeb4bd81eb6551b52e59c440b3e5e027
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51cfd314a65879813c1e8c8c23ea80b32621a1479a5c4ea09c789557ddcc80b05b29af2d84181fec90984c4137f8cc4735bd24e76a6eb2e38d81cfa543605ea7
|
7
|
+
data.tar.gz: 2ea0d89e66aa2a3c89f3b011a84bed5628a9e2e1de78c506f24d93393ab389922581ba1429509c3f8e30883a6788216069078aec3d38cd692c6eda1314b6a69f
|
data/CHANGELOG.md
CHANGED
@@ -46,4 +46,11 @@
|
|
46
46
|
|
47
47
|
- Start gem restructuring for modularizaition
|
48
48
|
- Introduce `activefunction-core` gem with RubyNext integration
|
49
|
-
|
49
|
+
|
50
|
+
# [0.4.0] - 2024-01-11
|
51
|
+
|
52
|
+
- Replace `ActiveFunction::Functions::Callbacks` with `ActiveFunctionCore::Plugins::Hooks`
|
53
|
+
- Introduce Plugin system
|
54
|
+
- Global refactoring
|
55
|
+
|
56
|
+
|
data/README.md
CHANGED
@@ -1,144 +1,213 @@
|
|
1
1
|
# ActiveFunction
|
2
2
|
|
3
|
-
|
3
|
+
Playground gem for Ruby 3.2+ features and more.
|
4
4
|
|
5
|
-
|
5
|
+
Collection of gems designed to be used with FaaS (Function as a Service) computing instances. Inspired by aws-sdk v3 gem structure & rails/activesupport.
|
6
6
|
|
7
|
+
## Features
|
7
8
|
|
9
|
+
- **Ruby Version Compatibility:** Implemented with most of ruby 3.2+ features, BUT supports Ruby versions >= 2.6 through the use of the [RubyNext](https://github.com/ruby-next/ruby-next) transpiler. (CI'ed)
|
10
|
+
- **Type Safety:** Achieves type safety through the use of RBS and [Steep](https://github.com/soutaro/steep). (CI'ed)
|
11
|
+
- Note: disabled due to the presence of Ruby::UnsupportedSyntax errors.
|
12
|
+
- **Plugins System:** Provides a simple Plugin system (inspired by [Polishing Ruby Programming by Jeremy Evans](https://github.com/PacktPublishing/Polished-Ruby-Programming)) to load gem plugins as well as self-defined plugins.
|
13
|
+
- **Gem Collection** Provides a collection of gems designed to be used within ActiveFunction or standalone.
|
8
14
|
|
9
|
-
|
15
|
+
# Gems
|
16
|
+
|
17
|
+
- [activefunction](/) - Main gem, provides rails/action-controller like API with callbacks, strong parameters and rendering under plugins.
|
18
|
+
- [activefunction-core](/gems/activefunction-core/README.md) - Provides RubyNext integration and External Standalone Plugins
|
19
|
+
- activefunction-orm - WIP (ORM around AWS PartiQL)
|
20
|
+
|
21
|
+
## Quick Start
|
10
22
|
|
11
23
|
Here's a simple example of a function that uses ActiveFunction:
|
12
24
|
|
13
25
|
```ruby
|
14
|
-
require
|
26
|
+
require "active_function"
|
15
27
|
|
16
28
|
class AppFunction < ActiveFunction::Base
|
17
|
-
def index
|
18
|
-
|
19
|
-
|
29
|
+
def index
|
30
|
+
response_with_error if @request[:data].nil?
|
31
|
+
|
32
|
+
return if performed?
|
33
|
+
|
34
|
+
@response.status = 200
|
35
|
+
@response.headers = {"Content-Type" => "application/json"}
|
36
|
+
@response.body = @request[:data]
|
37
|
+
end
|
38
|
+
|
39
|
+
private def response_with_error
|
40
|
+
@response.status = 400
|
41
|
+
@response.commit!
|
42
|
+
end
|
20
43
|
end
|
44
|
+
|
45
|
+
AppFunction.process(:index, {data: {id: 1}}) # => { :statusCode=>200, :headers=> {"Content-Type"=>"application/json"}, :body=>{id: 1}"}
|
21
46
|
```
|
22
47
|
|
23
|
-
|
48
|
+
## Plugins
|
24
49
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
50
|
+
ActiveFunction supports plugins which can be loaded by `ActiveFunction.config` method. Currently, there are 3 plugins available:
|
51
|
+
- [:callbacks](#callbacks) - provides `:before_action` and `:after_action` callbacks with `:if`, `:unless` & `:only` options.
|
52
|
+
- [:strong_parameters](#strong-parameters) - provides strong parameters support via `#params` instance method.
|
53
|
+
- [:rendering](#rendering) - provides rendering support via `#render` instance method.
|
54
|
+
|
55
|
+
## Configuration
|
56
|
+
|
57
|
+
To configure ActiveFunction with plugins, use the `ActiveFunction.config` method.
|
31
58
|
|
32
59
|
```ruby
|
33
|
-
|
34
|
-
|
35
|
-
after_action :log_response
|
36
|
-
|
37
|
-
# some action ...
|
60
|
+
# config/initializers/active_function.rb
|
61
|
+
require "active_function"
|
38
62
|
|
39
|
-
|
63
|
+
ActiveFunction.config do
|
64
|
+
plugin :callbacks
|
65
|
+
plugin :strong_parameters
|
66
|
+
plugin :rendering
|
67
|
+
end
|
68
|
+
```
|
40
69
|
|
41
|
-
|
42
|
-
|
43
|
-
|
70
|
+
```ruby
|
71
|
+
# app/functions/app_function.rb
|
72
|
+
class AppFunction < ActiveFunction::Base
|
73
|
+
before_action :parse_user_data
|
44
74
|
|
45
|
-
def
|
46
|
-
|
75
|
+
def index
|
76
|
+
render json: @user_data
|
47
77
|
end
|
78
|
+
|
79
|
+
private def parse_user_data = @user_data = params.require(:data).permit(:id, :name).to_h
|
48
80
|
end
|
49
81
|
```
|
50
82
|
|
51
|
-
|
83
|
+
Use `#process` method to proceed the request:
|
52
84
|
|
53
85
|
```ruby
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# some actions ...
|
58
|
-
|
59
|
-
private def request_valid? = true
|
60
|
-
end
|
86
|
+
# handler.rb
|
87
|
+
AppFunction.process(:index, {data: { id: 1, name: 2}}) # => { :statusCode=>200, :headers=> {"Content-Type"=>"application/json"}, :body=>"{\"id\":1,\"name\":2}"}
|
61
88
|
```
|
62
89
|
|
63
|
-
|
90
|
+
|
91
|
+
## Callbacks
|
92
|
+
|
93
|
+
Simple callbacks engined by [ActiveFunctionCore::Plugins::Hooks](https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core#hooks) external plugin and provides `:before_action` and `:after_action` which runs around provided action in `#process`.
|
94
|
+
|
64
95
|
```ruby
|
65
|
-
|
66
|
-
before_action :set_current_user
|
96
|
+
require "active_function"
|
67
97
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
98
|
+
ActiveFunction.config do
|
99
|
+
plugin :callbacks
|
71
100
|
end
|
72
101
|
|
73
|
-
class
|
102
|
+
class AppFunction < ActiveFunction::Base
|
103
|
+
before_action :set_user
|
104
|
+
after_action :log_response
|
105
|
+
|
74
106
|
def index
|
75
|
-
|
107
|
+
# some actions ...
|
76
108
|
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def set_user = @_user ||= User.find(@request[:id])
|
113
|
+
def log_response = Logger.info(@response)
|
77
114
|
end
|
78
115
|
```
|
79
|
-
|
80
|
-
|
116
|
+
|
117
|
+
### Callbacks options
|
118
|
+
|
119
|
+
Supports default [ActiveFunctionCore::Plugins::Hooks::Hook::Callback options](https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core#options) `:if => Symbol` & `:unless => Symbol` options.
|
120
|
+
|
121
|
+
Support custom defined in ActiveFunction::Function::Callbacks `only: Array[Symbol]` option.
|
81
122
|
|
82
123
|
```ruby
|
83
|
-
|
124
|
+
class AppFunction < ActiveFunction::Base
|
125
|
+
before_action :set_user, only: %i[show update destroy], if: :request_valid?
|
126
|
+
|
127
|
+
# some actions ...
|
128
|
+
|
129
|
+
private def request_valid? = true
|
130
|
+
end
|
84
131
|
```
|
132
|
+
More details in [ActiveFunctionCore::Plugins::Hooks readme](https://github.com/DanilMaximov/activefunction/tree/master/gems/activefunction-core#hooks)
|
133
|
+
|
134
|
+
## Strong Parameters
|
135
|
+
|
136
|
+
ActiveFunction supports strong parameters which can be accessed by `#params` instance method.
|
137
|
+
|
138
|
+
The `#params` method represents a Ruby 3.2 Data class that allows the manipulation of request parameters. It supports the following methods:
|
139
|
+
|
140
|
+
- `[]`: Access parameters by key.
|
141
|
+
- `permit`: Specify the allowed parameters.
|
142
|
+
- `require`: Ensure the presence of a specific parameter.
|
143
|
+
- `to_h`: Convert the parameters to a hash.
|
144
|
+
|
145
|
+
Usage Example:
|
85
146
|
|
86
|
-
Simple usage:
|
87
147
|
```ruby
|
148
|
+
require "active_function"
|
149
|
+
|
150
|
+
ActiveFunction.config do
|
151
|
+
plugin :strong_parameters
|
152
|
+
end
|
153
|
+
|
88
154
|
class PostsFunction < ActiveFunction::Base
|
89
|
-
def index
|
90
|
-
|
91
|
-
end
|
155
|
+
def index
|
156
|
+
@response.body = permitted_params
|
157
|
+
end
|
92
158
|
|
93
159
|
def permitted_params = params
|
94
160
|
.require(:data)
|
95
161
|
.permit(:id, :name)
|
96
162
|
.to_h
|
97
|
-
end
|
163
|
+
end
|
164
|
+
|
165
|
+
PostFunction.process(:index, data: {id: 1, name: "Pupa"})
|
98
166
|
```
|
167
|
+
|
99
168
|
Strong params supports nested attributes
|
100
|
-
```ruby
|
169
|
+
```ruby
|
101
170
|
params.permit(:id, :name, :address => [:city, :street])
|
102
171
|
```
|
103
172
|
|
104
173
|
## Rendering
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
174
|
+
|
175
|
+
ActiveFunction supports rendering of JSON. The #render method is used for rendering responses. It accepts the following options:
|
176
|
+
|
177
|
+
- `head`: Set response headers. Defaults to `{ "Content-Type" => "application/json" }`.
|
178
|
+
- `json`: Set the response body with a JSON-like object. Defaults to `{}`.
|
179
|
+
- `status`: Set the HTTP status code. Defaults to `200`.
|
180
|
+
|
181
|
+
Additionally, the method automatically commits the response and JSONifies the body.
|
182
|
+
|
183
|
+
Usage Example:
|
114
184
|
```ruby
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
185
|
+
require "active_function"
|
186
|
+
|
187
|
+
ActiveFunction.config do
|
188
|
+
plugin :rendering
|
119
189
|
end
|
120
|
-
|
121
|
-
Headers can be passed by `:headers` option. Default headers are `{"Content-Type" => "application/json"}`.
|
122
|
-
```ruby
|
190
|
+
|
123
191
|
class PostsFunction < ActiveFunction::Base
|
124
|
-
def index
|
125
|
-
render json: {
|
126
|
-
end
|
192
|
+
def index
|
193
|
+
render json: {id: 1, name: "Pupa"}, status: 200, head: {"Some-Header" => "Some-Value"}
|
194
|
+
end
|
127
195
|
end
|
128
|
-
```
|
129
196
|
|
197
|
+
PostFunction.process(:index) # => { :statusCode=>200, :headers=> {"Content-Type"=>"application/json", "Some-Header" => "Some-Value"}, :body=>"{\"id\":1,\"name\":\"Pupa\"}"}
|
198
|
+
```
|
130
199
|
|
131
200
|
## Installation
|
132
201
|
|
133
202
|
Add this line to your application's Gemfile:
|
134
203
|
|
135
204
|
```ruby
|
136
|
-
gem
|
205
|
+
gem "activefunction"
|
137
206
|
```
|
138
207
|
|
139
208
|
## Development
|
140
209
|
|
141
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake test` to run the tests and `bin/rake steep` to run type checker.
|
210
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake test` to run the tests and `bin/rake steep` to run type checker.
|
142
211
|
|
143
212
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
144
213
|
|
@@ -3,52 +3,45 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
5
|
module ActiveFunction
|
6
|
-
|
7
|
-
|
6
|
+
module Functions
|
7
|
+
module StrongParameters
|
8
|
+
ActiveFunction.register_plugin :strong_parameters, self
|
8
9
|
|
9
|
-
|
10
|
+
Error = Class.new(StandardError)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
12
|
+
class Parameters < Data.define(:params, :permitted)
|
13
|
+
class ParameterMissingError < Error
|
14
|
+
MESSAGE_TEMPLATE = "Missing parameter: %s"
|
15
15
|
|
16
|
-
|
17
|
-
MESSAGE_TEMPLATE = "Unpermitted parameter: %s"
|
16
|
+
attr_reader :message
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
18
|
+
def initialize(param)
|
19
|
+
MESSAGE_TEMPLATE % param
|
20
|
+
end
|
21
|
+
end
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
def params
|
29
|
-
@_params ||= Parameters.new(@request)
|
30
|
-
end
|
23
|
+
class UnpermittedParameterError < Error
|
24
|
+
MESSAGE_TEMPLATE = "Unpermitted parameter: %s"
|
31
25
|
|
32
|
-
|
33
|
-
extend Forwardable
|
34
|
-
def_delegators :@parameters, :each, :map
|
35
|
-
include Enumerable
|
26
|
+
attr_reader :message
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
def initialize(param)
|
29
|
+
MESSAGE_TEMPLATE % param
|
30
|
+
end
|
40
31
|
end
|
41
32
|
|
33
|
+
protected :params
|
34
|
+
|
42
35
|
def [](attribute)
|
43
|
-
nested_attribute(
|
36
|
+
nested_attribute(params[attribute])
|
44
37
|
end
|
45
38
|
|
46
39
|
def require(attribute)
|
47
|
-
value = self[attribute]
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
if (value = self[attribute])
|
41
|
+
value
|
42
|
+
else
|
43
|
+
raise ParameterMissingError, attribute
|
44
|
+
end
|
52
45
|
end
|
53
46
|
|
54
47
|
def permit(*attributes)
|
@@ -60,28 +53,37 @@ module ActiveFunction
|
|
60
53
|
pparams[k] = process_nested(self[k], :permit, v)
|
61
54
|
end
|
62
55
|
else
|
63
|
-
next unless
|
56
|
+
next unless params.key?(attribute)
|
64
57
|
|
65
58
|
pparams[attribute] = self[attribute]
|
66
59
|
end
|
67
60
|
end
|
68
61
|
|
69
|
-
|
62
|
+
with(params: pparams, permitted: true)
|
70
63
|
end
|
71
64
|
|
65
|
+
# Redefines RubyNext::Core::Data instance methods
|
72
66
|
def to_h
|
73
|
-
raise UnpermittedParameterError,
|
67
|
+
raise UnpermittedParameterError, params.keys unless permitted
|
74
68
|
|
75
|
-
|
69
|
+
params.transform_values { |_1| process_nested(_1, :to_h) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def hash
|
73
|
+
@attributes.to_h.hash
|
74
|
+
end
|
75
|
+
|
76
|
+
def with(params:, permitted: false)
|
77
|
+
self.class.new(params, permitted)
|
76
78
|
end
|
77
79
|
|
78
80
|
private
|
79
81
|
|
80
82
|
def nested_attribute(attribute)
|
81
83
|
if attribute.is_a? Hash
|
82
|
-
|
84
|
+
with(params: attribute)
|
83
85
|
elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash)
|
84
|
-
attribute.map { |
|
86
|
+
attribute.map { |it| with(params: it) }
|
85
87
|
else
|
86
88
|
attribute
|
87
89
|
end
|
@@ -96,8 +98,10 @@ module ActiveFunction
|
|
96
98
|
attribute
|
97
99
|
end
|
98
100
|
end
|
101
|
+
end
|
99
102
|
|
100
|
-
|
103
|
+
def params
|
104
|
+
@_params ||= Parameters.new(@request, false)
|
101
105
|
end
|
102
106
|
end
|
103
107
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFunction
|
4
|
+
class SuperBase
|
5
|
+
attr_reader :action_name, :request, :response
|
6
|
+
|
7
|
+
def initialize(action_name, request, response)
|
8
|
+
@action_name = action_name
|
9
|
+
@request = request
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
process(action_name)
|
15
|
+
|
16
|
+
@response.commit! unless performed?
|
17
|
+
|
18
|
+
@response.to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(action) ; public_send(action); end
|
22
|
+
|
23
|
+
private def performed? ; @response.committed?; end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Base < SuperBase
|
27
|
+
Error = Class.new(StandardError)
|
28
|
+
|
29
|
+
# @param [String, Symbol] action_name - name of method to call
|
30
|
+
# @param [Hash] request - request params, accessible through `#params` method
|
31
|
+
# @param [Response] response - response object
|
32
|
+
def self.process(action_name, request = {}, response = Response.new)
|
33
|
+
raise ArgumentError, "Action method #{action_name} is not defined" unless method_defined?(action_name)
|
34
|
+
|
35
|
+
new(action_name, request, response).dispatch
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -2,29 +2,26 @@
|
|
2
2
|
|
3
3
|
module ActiveFunction
|
4
4
|
module Functions
|
5
|
-
|
6
|
-
|
5
|
+
module Response
|
6
|
+
ActiveFunction.register_plugin :response, self
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
@headers = headers
|
11
|
-
@body = body
|
12
|
-
@committed = false
|
13
|
-
end
|
8
|
+
class Response < Struct.new(:status, :headers, :body, :committed)
|
9
|
+
def initialize(status: 200, headers: {}, body: nil, committed: false) ; super(status, headers, body, committed); end
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
def to_h
|
12
|
+
{
|
13
|
+
statusCode: status,
|
14
|
+
headers: headers,
|
15
|
+
body: body
|
16
|
+
}
|
17
|
+
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
def commit!
|
20
|
+
self.committed = true
|
21
|
+
end
|
26
22
|
|
27
|
-
|
23
|
+
alias_method :committed?, :committed
|
24
|
+
end
|
28
25
|
end
|
29
26
|
end
|
30
27
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_function_core"
|
4
|
+
require "active_function/version"
|
5
|
+
require "active_function/base"
|
6
|
+
|
7
|
+
RubyNext::Language.setup_gem_load_path(transpile: true)
|
8
|
+
|
9
|
+
module ActiveFunction
|
10
|
+
class << self
|
11
|
+
# Configure ActiveFunction.
|
12
|
+
#
|
13
|
+
# @param block [Proc]
|
14
|
+
# @return [void]
|
15
|
+
def config(&block)
|
16
|
+
class_eval(&block)
|
17
|
+
@_plugins.freeze
|
18
|
+
self::Base.freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def plugins ; @_plugins ||= {}; end
|
22
|
+
|
23
|
+
# Register plugin.
|
24
|
+
#
|
25
|
+
# @param symbol [Symbol]
|
26
|
+
# @param mod [Module]
|
27
|
+
def register_plugin(symbol, mod)
|
28
|
+
plugins[symbol] = mod
|
29
|
+
end
|
30
|
+
|
31
|
+
# Monkey patch ActiveFunction::Base with provided plugin.
|
32
|
+
#
|
33
|
+
# @param mod [Symbol, Module]
|
34
|
+
# @return [void]
|
35
|
+
def plugin(mod)
|
36
|
+
if mod.is_a? Symbol
|
37
|
+
begin
|
38
|
+
require "active_function/functions/#{mod}"
|
39
|
+
mod = plugins.fetch(mod)
|
40
|
+
rescue LoadError
|
41
|
+
raise ArgumentError, "Unknown plugin #{mod}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
self::Base.include(mod)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
plugin :response
|
50
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFunction
|
4
|
+
module Functions
|
5
|
+
module Response
|
6
|
+
ActiveFunction.register_plugin :response, self
|
7
|
+
|
8
|
+
class Response < Struct.new(:status, :headers, :body, :committed)
|
9
|
+
def initialize(status: 200, headers: {}, body: nil, committed: false) = super(status, headers, body, committed)
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
{
|
13
|
+
statusCode: status,
|
14
|
+
headers: headers,
|
15
|
+
body: body
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def commit!
|
20
|
+
self.committed = true
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :committed?, :committed
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/active_function/base.rb
CHANGED
@@ -1,20 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveFunction
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
class SuperBase
|
5
|
+
attr_reader :action_name, :request, :response
|
6
|
+
|
7
|
+
def initialize(action_name, request, response)
|
8
|
+
@action_name = action_name
|
9
|
+
@request = request
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
process(action_name)
|
15
|
+
|
16
|
+
@response.commit! unless performed?
|
17
|
+
|
18
|
+
@response.to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(action) = public_send(action)
|
22
|
+
|
23
|
+
private def performed? = @response.committed?
|
24
|
+
end
|
25
|
+
|
26
|
+
class Base < SuperBase
|
27
|
+
Error = Class.new(StandardError)
|
28
|
+
|
29
|
+
# @param [String, Symbol] action_name - name of method to call
|
30
|
+
# @param [Hash] request - request params, accessible through `#params` method
|
31
|
+
# @param [Response] response - response object
|
32
|
+
def self.process(action_name, request = {}, response = Response.new)
|
33
|
+
raise ArgumentError, "Action method #{action_name} is not defined" unless method_defined?(action_name)
|
34
|
+
|
35
|
+
new(action_name, request, response).dispatch
|
18
36
|
end
|
19
37
|
end
|
20
38
|
end
|
@@ -1,68 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveFunction
|
4
|
-
class MissingCallbackContext < Error
|
5
|
-
MESSAGE_TEMPLATE = "Missing callback context: %s"
|
6
|
-
|
7
|
-
attr_reader :message
|
8
|
-
|
9
|
-
def initialize(context)
|
10
|
-
@message = MESSAGE_TEMPLATE % context
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
4
|
module Functions
|
15
5
|
module Callbacks
|
16
|
-
|
17
|
-
base.extend(ClassMethods)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def process(*)
|
23
|
-
_run_callbacks :before
|
24
|
-
|
25
|
-
super
|
26
|
-
|
27
|
-
_run_callbacks :after
|
28
|
-
end
|
6
|
+
ActiveFunction.register_plugin :callbacks, self
|
29
7
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
send(callback_method) if _executable?(options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def _executable?(options)
|
39
|
-
return false if options[:only] && !options[:only].include?(@action_name)
|
40
|
-
return false if options[:if] && !send(options[:if])
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
module ClassMethods
|
45
|
-
def inherited(subclass)
|
46
|
-
subclass.instance_variable_set(:@__callbacks, @__callbacks)
|
47
|
-
end
|
48
|
-
|
49
|
-
def before_action(method, options = {})
|
50
|
-
set_callback :before, method, options
|
51
|
-
end
|
52
|
-
|
53
|
-
def after_action(method, options = {})
|
54
|
-
set_callback :after, method, options
|
55
|
-
end
|
56
|
-
|
57
|
-
def set_callback(type, method, options = {})
|
58
|
-
callbacks[type][method] = options
|
59
|
-
end
|
60
|
-
|
61
|
-
def callbacks
|
62
|
-
@__callbacks ||= {before: {}, after: {}}
|
63
|
-
|
64
|
-
@__callbacks
|
65
|
-
end
|
8
|
+
def self.included(base)
|
9
|
+
base.include ActiveFunctionCore::Plugins::Hooks
|
10
|
+
base.define_hooks_for :process, name: :action
|
11
|
+
base.set_callback_options only: ->(args, context:) { args.to_set === context.action_name }
|
66
12
|
end
|
67
13
|
end
|
68
14
|
end
|
@@ -3,18 +3,22 @@
|
|
3
3
|
require "json"
|
4
4
|
|
5
5
|
module ActiveFunction
|
6
|
-
|
7
|
-
|
6
|
+
module Functions
|
7
|
+
module Rendering
|
8
|
+
ActiveFunction.register_plugin :rendering, self
|
8
9
|
|
9
|
-
|
10
|
+
Error = Class.new(StandardError)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
class DoubleRenderError < Error
|
13
|
+
MESSAGE_TEMPLATE = "#render was called multiple times in action: %s"
|
14
|
+
|
15
|
+
attr_reader :message
|
16
|
+
|
17
|
+
def initialize(context)
|
18
|
+
@message = MESSAGE_TEMPLATE % context
|
19
|
+
end
|
20
|
+
end
|
15
21
|
|
16
|
-
module Functions
|
17
|
-
module Rendering
|
18
22
|
DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze
|
19
23
|
|
20
24
|
def render(status: 200, json: {}, head: {})
|
@@ -2,29 +2,26 @@
|
|
2
2
|
|
3
3
|
module ActiveFunction
|
4
4
|
module Functions
|
5
|
-
|
6
|
-
|
5
|
+
module Response
|
6
|
+
ActiveFunction.register_plugin :response, self
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
@headers = headers
|
11
|
-
@body = body
|
12
|
-
@committed = false
|
13
|
-
end
|
8
|
+
class Response < Struct.new(:status, :headers, :body, :committed)
|
9
|
+
def initialize(status: 200, headers: {}, body: nil, committed: false) = super(status, headers, body, committed)
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
def to_h
|
12
|
+
{
|
13
|
+
statusCode: status,
|
14
|
+
headers:,
|
15
|
+
body:
|
16
|
+
}
|
17
|
+
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
def commit!
|
20
|
+
self.committed = true
|
21
|
+
end
|
26
22
|
|
27
|
-
|
23
|
+
alias_method :committed?, :committed
|
24
|
+
end
|
28
25
|
end
|
29
26
|
end
|
30
27
|
end
|
@@ -3,52 +3,45 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
5
|
module ActiveFunction
|
6
|
-
|
7
|
-
|
6
|
+
module Functions
|
7
|
+
module StrongParameters
|
8
|
+
ActiveFunction.register_plugin :strong_parameters, self
|
8
9
|
|
9
|
-
|
10
|
+
Error = Class.new(StandardError)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
12
|
+
class Parameters < Data.define(:params, :permitted)
|
13
|
+
class ParameterMissingError < Error
|
14
|
+
MESSAGE_TEMPLATE = "Missing parameter: %s"
|
15
15
|
|
16
|
-
|
17
|
-
MESSAGE_TEMPLATE = "Unpermitted parameter: %s"
|
16
|
+
attr_reader :message
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
18
|
+
def initialize(param)
|
19
|
+
MESSAGE_TEMPLATE % param
|
20
|
+
end
|
21
|
+
end
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
def params
|
29
|
-
@_params ||= Parameters.new(@request)
|
30
|
-
end
|
23
|
+
class UnpermittedParameterError < Error
|
24
|
+
MESSAGE_TEMPLATE = "Unpermitted parameter: %s"
|
31
25
|
|
32
|
-
|
33
|
-
extend Forwardable
|
34
|
-
def_delegators :@parameters, :each, :map
|
35
|
-
include Enumerable
|
26
|
+
attr_reader :message
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
def initialize(param)
|
29
|
+
MESSAGE_TEMPLATE % param
|
30
|
+
end
|
40
31
|
end
|
41
32
|
|
33
|
+
protected :params
|
34
|
+
|
42
35
|
def [](attribute)
|
43
|
-
nested_attribute(
|
36
|
+
nested_attribute(params[attribute])
|
44
37
|
end
|
45
38
|
|
46
39
|
def require(attribute)
|
47
|
-
value = self[attribute]
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
if (value = self[attribute])
|
41
|
+
value
|
42
|
+
else
|
43
|
+
raise ParameterMissingError, attribute
|
44
|
+
end
|
52
45
|
end
|
53
46
|
|
54
47
|
def permit(*attributes)
|
@@ -60,28 +53,37 @@ module ActiveFunction
|
|
60
53
|
pparams[k] = process_nested(self[k], :permit, v)
|
61
54
|
end
|
62
55
|
else
|
63
|
-
next unless
|
56
|
+
next unless params.key?(attribute)
|
64
57
|
|
65
58
|
pparams[attribute] = self[attribute]
|
66
59
|
end
|
67
60
|
end
|
68
61
|
|
69
|
-
|
62
|
+
with(params: pparams, permitted: true)
|
70
63
|
end
|
71
64
|
|
65
|
+
# Redefines RubyNext::Core::Data instance methods
|
72
66
|
def to_h
|
73
|
-
raise UnpermittedParameterError,
|
67
|
+
raise UnpermittedParameterError, params.keys unless permitted
|
74
68
|
|
75
|
-
|
69
|
+
params.transform_values { process_nested(_1, :to_h) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def hash
|
73
|
+
@attributes.to_h.hash
|
74
|
+
end
|
75
|
+
|
76
|
+
def with(params:, permitted: false)
|
77
|
+
self.class.new(params, permitted)
|
76
78
|
end
|
77
79
|
|
78
80
|
private
|
79
81
|
|
80
82
|
def nested_attribute(attribute)
|
81
83
|
if attribute.is_a? Hash
|
82
|
-
|
84
|
+
with(params: attribute)
|
83
85
|
elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash)
|
84
|
-
attribute.map {
|
86
|
+
attribute.map { |it| with(params: it) }
|
85
87
|
else
|
86
88
|
attribute
|
87
89
|
end
|
@@ -96,8 +98,10 @@ module ActiveFunction
|
|
96
98
|
attribute
|
97
99
|
end
|
98
100
|
end
|
101
|
+
end
|
99
102
|
|
100
|
-
|
103
|
+
def params
|
104
|
+
@_params ||= Parameters.new(@request, false)
|
101
105
|
end
|
102
106
|
end
|
103
107
|
end
|
data/lib/active_function.rb
CHANGED
@@ -1,12 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_function_core"
|
4
|
+
require "active_function/version"
|
5
|
+
require "active_function/base"
|
4
6
|
|
5
7
|
RubyNext::Language.setup_gem_load_path(transpile: true)
|
6
8
|
|
7
9
|
module ActiveFunction
|
8
|
-
class
|
10
|
+
class << self
|
11
|
+
# Configure ActiveFunction.
|
12
|
+
#
|
13
|
+
# @param block [Proc]
|
14
|
+
# @return [void]
|
15
|
+
def config(&block)
|
16
|
+
class_eval(&block)
|
17
|
+
@_plugins.freeze
|
18
|
+
self::Base.freeze
|
19
|
+
end
|
9
20
|
|
10
|
-
|
11
|
-
|
21
|
+
def plugins = @_plugins ||= {}
|
22
|
+
|
23
|
+
# Register plugin.
|
24
|
+
#
|
25
|
+
# @param symbol [Symbol]
|
26
|
+
# @param mod [Module]
|
27
|
+
def register_plugin(symbol, mod)
|
28
|
+
plugins[symbol] = mod
|
29
|
+
end
|
30
|
+
|
31
|
+
# Monkey patch ActiveFunction::Base with provided plugin.
|
32
|
+
#
|
33
|
+
# @param mod [Symbol, Module]
|
34
|
+
# @return [void]
|
35
|
+
def plugin(mod)
|
36
|
+
if mod.is_a? Symbol
|
37
|
+
begin
|
38
|
+
require "active_function/functions/#{mod}"
|
39
|
+
mod = plugins.fetch(mod)
|
40
|
+
rescue LoadError
|
41
|
+
raise ArgumentError, "Unknown plugin #{mod}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
self::Base.include(mod)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
plugin :response
|
12
50
|
end
|
metadata
CHANGED
@@ -1,76 +1,39 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefunction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nerbyk
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activefunction-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.1
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0.1
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '13.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '13.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitest
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 5.15.0
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
16
|
requirements:
|
52
17
|
- - "~>"
|
53
18
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
|
56
|
-
name: minitest-reporters
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.4.3
|
62
|
-
type: :development
|
19
|
+
version: 0.2.2
|
20
|
+
type: :runtime
|
63
21
|
prerelease: false
|
64
22
|
version_requirements: !ruby/object:Gem::Requirement
|
65
23
|
requirements:
|
66
24
|
- - "~>"
|
67
25
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
69
|
-
description: "\n
|
70
|
-
|
71
|
-
|
72
|
-
with
|
73
|
-
transpiler
|
26
|
+
version: 0.2.2
|
27
|
+
description: "\n ActiveFunction is a collection of gems designed to be used with
|
28
|
+
Function as a Service (FaaS) computing instances. Inspired by aws-sdk v3 gem structure
|
29
|
+
and rails/activesupport.\n\n Features:\n - Ruby Version Compatibility: Implemented
|
30
|
+
with most of Ruby 3.2+ features, with support for Ruby versions >= 2.6 through the
|
31
|
+
RubyNext transpiler (CI'ed).\n - Type Safety: Achieves type safety through the
|
32
|
+
use of RBS and Steep (CI'ed) [Note: disabled due to the presence of Ruby::UnsupportedSyntax
|
33
|
+
errors].\n - Plugins System: Provides a simple Plugin system inspired by Polishing
|
34
|
+
Ruby Programming by Jeremy Evans to load gem plugins and self-defined plugins.\n
|
35
|
+
\ - Gem Collection: Offers a collection of gems designed for use within ActiveFunction
|
36
|
+
or as standalone components.\n "
|
74
37
|
email:
|
75
38
|
- danil.maximov2000@gmail.com
|
76
39
|
executables: []
|
@@ -86,12 +49,13 @@ files:
|
|
86
49
|
- bin/ruby-next
|
87
50
|
- bin/setup
|
88
51
|
- lib/.rbnext/2.7/active_function/functions/strong_parameters.rb
|
89
|
-
- lib/.rbnext/3.0/active_function
|
52
|
+
- lib/.rbnext/3.0/active_function.rb
|
53
|
+
- lib/.rbnext/3.0/active_function/base.rb
|
90
54
|
- lib/.rbnext/3.0/active_function/functions/response.rb
|
55
|
+
- lib/.rbnext/3.1/active_function/functions/response.rb
|
91
56
|
- lib/active_function.rb
|
92
57
|
- lib/active_function/base.rb
|
93
58
|
- lib/active_function/functions/callbacks.rb
|
94
|
-
- lib/active_function/functions/core.rb
|
95
59
|
- lib/active_function/functions/rendering.rb
|
96
60
|
- lib/active_function/functions/response.rb
|
97
61
|
- lib/active_function/functions/strong_parameters.rb
|
@@ -105,7 +69,7 @@ metadata:
|
|
105
69
|
homepage_uri: https://github.com/DanilMaximov/activefunction
|
106
70
|
source_code_uri: https://github.com/DanilMaximov/activefunction
|
107
71
|
changelog_uri: https://github.com/DanilMaximov/activefunction/CHANGELOG.md
|
108
|
-
post_install_message:
|
72
|
+
post_install_message:
|
109
73
|
rdoc_options: []
|
110
74
|
require_paths:
|
111
75
|
- lib
|
@@ -120,9 +84,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
84
|
- !ruby/object:Gem::Version
|
121
85
|
version: '0'
|
122
86
|
requirements: []
|
123
|
-
rubygems_version: 3.4
|
124
|
-
signing_key:
|
87
|
+
rubygems_version: 3.5.4
|
88
|
+
signing_key:
|
125
89
|
specification_version: 4
|
126
|
-
summary:
|
127
|
-
|
90
|
+
summary: Playground gem for Ruby 3.2+ features and more, designed for FaaS computing
|
91
|
+
instances, but mostly used for experiments.
|
128
92
|
test_files: []
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveFunction
|
4
|
-
class MissingRouteMethod < Error
|
5
|
-
MESSAGE_TEMPLATE = "Missing function route: %s"
|
6
|
-
|
7
|
-
attr_reader :message
|
8
|
-
|
9
|
-
def initialize(context)
|
10
|
-
@message = MESSAGE_TEMPLATE % context
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class NotRenderedError < Error
|
15
|
-
MESSAGE_TEMPLATE = "render was not called: %s"
|
16
|
-
|
17
|
-
attr_reader :message
|
18
|
-
|
19
|
-
def initialize(context)
|
20
|
-
@message = MESSAGE_TEMPLATE % context
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module Functions
|
25
|
-
module Core
|
26
|
-
attr_reader :action_name, :request, :response
|
27
|
-
|
28
|
-
def dispatch(action_name, request, response)
|
29
|
-
@action_name = action_name
|
30
|
-
@request = request
|
31
|
-
@response = response
|
32
|
-
|
33
|
-
raise MissingRouteMethod, @action_name unless respond_to?(action_name)
|
34
|
-
|
35
|
-
process(@action_name)
|
36
|
-
|
37
|
-
raise NotRenderedError, @action_name unless performed?
|
38
|
-
|
39
|
-
@response.to_h
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def process(action) ; public_send(action); end
|
45
|
-
|
46
|
-
def performed? ; @response.committed?; end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveFunction
|
4
|
-
class MissingRouteMethod < Error
|
5
|
-
MESSAGE_TEMPLATE = "Missing function route: %s"
|
6
|
-
|
7
|
-
attr_reader :message
|
8
|
-
|
9
|
-
def initialize(context)
|
10
|
-
@message = MESSAGE_TEMPLATE % context
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class NotRenderedError < Error
|
15
|
-
MESSAGE_TEMPLATE = "render was not called: %s"
|
16
|
-
|
17
|
-
attr_reader :message
|
18
|
-
|
19
|
-
def initialize(context)
|
20
|
-
@message = MESSAGE_TEMPLATE % context
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module Functions
|
25
|
-
module Core
|
26
|
-
attr_reader :action_name, :request, :response
|
27
|
-
|
28
|
-
def dispatch(action_name, request, response)
|
29
|
-
@action_name = action_name
|
30
|
-
@request = request
|
31
|
-
@response = response
|
32
|
-
|
33
|
-
raise MissingRouteMethod, @action_name unless respond_to?(action_name)
|
34
|
-
|
35
|
-
process(@action_name)
|
36
|
-
|
37
|
-
raise NotRenderedError, @action_name unless performed?
|
38
|
-
|
39
|
-
@response.to_h
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def process(action) = public_send(action)
|
45
|
-
|
46
|
-
def performed? = @response.committed?
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|