activefunction 0.3.5 → 0.4.1
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 -1
- data/README.md +182 -69
- data/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb +84 -41
- data/lib/.rbnext/3.0/active_function/base.rb +58 -0
- data/lib/.rbnext/3.0/active_function/functions/response.rb +38 -19
- data/lib/.rbnext/3.0/active_function.rb +63 -0
- data/lib/.rbnext/3.1/active_function/functions/response.rb +49 -0
- data/lib/active_function/base.rb +52 -14
- data/lib/active_function/functions/callbacks.rb +58 -58
- data/lib/active_function/functions/rendering.rb +36 -9
- data/lib/active_function/functions/response.rb +38 -19
- data/lib/active_function/functions/strong_parameters.rb +84 -41
- data/lib/active_function/version.rb +1 -1
- data/lib/active_function.rb +54 -3
- metadata +55 -26
- data/bin/console +0 -15
- data/bin/rake +0 -27
- data/bin/rubocop +0 -27
- data/bin/ruby-next +0 -16
- data/bin/setup +0 -8
- data/lib/.rbnext/3.0/active_function/functions/core.rb +0 -49
- data/lib/active_function/functions/core.rb +0 -49
@@ -0,0 +1,63 @@
|
|
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 through DSL method calls.
|
12
|
+
# Setups {ActiveFunction::Base} with provided internal and custom plugins.
|
13
|
+
# Also freezes plugins and {ActiveFunction::Base}.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# ActiveFunction.config do
|
17
|
+
# plugin :callbacks
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @param block [Proc] class_eval'ed block in ActiveFunction module.
|
21
|
+
# @return [void]
|
22
|
+
def config(&block)
|
23
|
+
class_eval(&block)
|
24
|
+
@_plugins.freeze
|
25
|
+
self::Base.freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
# List of registered internal plugins.
|
29
|
+
def plugins ; @_plugins ||= {}; end
|
30
|
+
|
31
|
+
# Register internal Symbol'ed plugin.
|
32
|
+
#
|
33
|
+
# @param [Symbol] symbol name of internal plugin,
|
34
|
+
# should match file name in ./lib/active_function/functions/*.rb
|
35
|
+
# @param [Module] mod module to register.
|
36
|
+
def register_plugin(symbol, mod)
|
37
|
+
plugins[symbol] = mod
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add plugin to ActiveFunction::Base.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# ActiveFunction.plugin :callbacks
|
44
|
+
# ActiveFunction.plugin CustomPlugin
|
45
|
+
#
|
46
|
+
# @param [Symbol, Module] mod
|
47
|
+
# @return [void]
|
48
|
+
def plugin(mod)
|
49
|
+
if mod.is_a? Symbol
|
50
|
+
begin
|
51
|
+
require "active_function/functions/#{mod}"
|
52
|
+
mod = plugins.fetch(mod)
|
53
|
+
rescue LoadError
|
54
|
+
raise ArgumentError, "Unknown plugin #{mod}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
self::Base.include(mod)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
plugin :response
|
63
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFunction
|
4
|
+
module Functions
|
5
|
+
# The only required plugin for {ActiveFunction::Base} to work.
|
6
|
+
# Provides a simple {Response} object to manage response details.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# response = Response.new.tap do |r|
|
10
|
+
# r.body = "Hello World!"
|
11
|
+
# r.headers = {"Content-Type" => "text/plain"}
|
12
|
+
# r.commit!
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# response.performed? # => true
|
16
|
+
# response.to_h # => { statusCode: 200, headers: { "Content-Type" => "text/plain" }, body: "Hello World!" }
|
17
|
+
module Response
|
18
|
+
ActiveFunction.register_plugin :response, self
|
19
|
+
|
20
|
+
class Response < Struct.new(:status, :headers, :body, :committed)
|
21
|
+
# Initializes a new Response instance with default values.
|
22
|
+
#
|
23
|
+
# @param status [Integer] HTTP status code.
|
24
|
+
# @param headers [Hash] HTTP headers.
|
25
|
+
# @param body [Object] Response body.
|
26
|
+
# @param committed [Boolean] Indicates whether the response has been committed (default is false).
|
27
|
+
def initialize(status: 200, headers: {}, body: nil, committed: false) = super(status, headers, body, committed)
|
28
|
+
|
29
|
+
# Converts the Response instance to a hash for JSON serialization.
|
30
|
+
#
|
31
|
+
# @return [Hash{statusCode: Integer, headers: Hash, body: Object}]
|
32
|
+
def to_h
|
33
|
+
{
|
34
|
+
statusCode: status,
|
35
|
+
headers: headers,
|
36
|
+
body: body
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Marks the response as committed.
|
41
|
+
def commit!
|
42
|
+
self.committed = true
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :committed?, :committed
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/active_function/base.rb
CHANGED
@@ -1,20 +1,58 @@
|
|
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
|
+
# Abstract base class with request processing logic.
|
5
|
+
class SuperBase
|
6
|
+
attr_reader :action_name, :request, :response
|
7
|
+
|
8
|
+
def initialize(action_name, request, response)
|
9
|
+
@action_name = action_name
|
10
|
+
@request = request
|
11
|
+
@response = response
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executes specified @action_name instance method and returns Hash'ed response object
|
15
|
+
def dispatch
|
16
|
+
process(action_name)
|
17
|
+
|
18
|
+
@response.commit! unless performed?
|
19
|
+
|
20
|
+
@response.to_h
|
21
|
+
end
|
22
|
+
|
23
|
+
def process(action) = public_send(action)
|
24
|
+
|
25
|
+
private def performed? = @response.committed?
|
26
|
+
end
|
27
|
+
|
28
|
+
# The main base class for defining functions using the ActiveFunction framework.
|
29
|
+
# Public methods of this class are considered as actions and be proceeded on {ActiveFunction::Base.process} call.
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# class MyFunction < ActiveFunction::Base
|
33
|
+
# def index
|
34
|
+
# if user = User.find(@request.dig(:data, :user, :id))
|
35
|
+
# @response.body = user.to_h
|
36
|
+
# else
|
37
|
+
# @response.status = 404
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
class Base < SuperBase
|
42
|
+
Error = Class.new(StandardError)
|
43
|
+
|
44
|
+
# Processes specified action and returns Hash'ed {ActiveFunction::Functions::Response::Response} object.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# MyFunction.process :index, { data: { user: { id: 1 } } } # => { statusCode: 200, body: { id: 1, name: "Pupa" }, headers: {} }
|
48
|
+
#
|
49
|
+
# @param [String, Symbol] action_name - name of method to call
|
50
|
+
# @param [Hash] request - request parameters.
|
51
|
+
# @param [Response] response - Functions::Response response object.
|
52
|
+
def self.process(action_name, request = {}, response = Response.new)
|
53
|
+
raise ArgumentError, "Action method #{action_name} is not defined" unless method_defined?(action_name)
|
54
|
+
|
55
|
+
new(action_name, request, response).dispatch
|
18
56
|
end
|
19
57
|
end
|
20
58
|
end
|
@@ -1,69 +1,69 @@
|
|
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
|
5
|
+
# Setups {before_action} and {after_action} callbacks around {ActiveFunction::SuperBase#process}
|
6
|
+
# using {ActiveFunctionCore::Plugins::Hooks}. Also provides {define_hooks_for} and {set_callback_options} for
|
7
|
+
# defining custom hooks & options.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# ActiveFunction.plugin :callbacks
|
11
|
+
#
|
12
|
+
# class MessagingApp < ActiveFunction::Base
|
13
|
+
# set_callback_options retries: ->(times, context:) { context.retry if context.retries < times }
|
14
|
+
# define_hooks_for :retry
|
15
|
+
#
|
16
|
+
# after_action :retry, if: :failed?, only: %i[send_message], retries: 3
|
17
|
+
# after_retry :increment_retries
|
18
|
+
#
|
19
|
+
# def send_message
|
20
|
+
# @response.status = 200 if SomeApi.send(@request[:message_content]).success?
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def retry
|
24
|
+
# @response.committed = false
|
25
|
+
# process
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# private def increment_retries = @response.body[:tries] += 1
|
29
|
+
# private def failed? = @response.status != 200
|
30
|
+
# private def retries = @response.body[:tries] ||= 0
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# MessagingApp.process(:send_message, { sender_name: "Alice", message_content: "How are you?" })
|
34
|
+
# defining custom hooks & options.
|
15
35
|
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
|
29
|
-
|
30
|
-
def _run_callbacks(type)
|
31
|
-
self.class.callbacks[type].each do |callback_method, options|
|
32
|
-
raise MissingCallbackContext, callback_method unless respond_to?(callback_method, true)
|
33
|
-
|
34
|
-
send(callback_method) if _executable?(options)
|
35
|
-
end
|
36
|
-
end
|
36
|
+
ActiveFunction.register_plugin :callbacks, self
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
# Setup callbacks around {ActiveFunction::Base#process} method using {ActiveFunctionCore::Plugins::Hooks}.
|
39
|
+
# Also provides :only option for filtering callbacks by action name.
|
40
|
+
def self.included(base)
|
41
|
+
base.include ActiveFunctionCore::Plugins::Hooks
|
42
|
+
base.define_hooks_for :process, name: :action
|
43
|
+
base.set_callback_options only: ->(args, context:) { args.to_set === context.action_name }
|
42
44
|
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
end
|
46
|
+
# @!method before_action(target, options)
|
47
|
+
# @param [Symbol, String] target - method name to call
|
48
|
+
# @option options [Symbol, String] :if - method name to check before executing the callback.
|
49
|
+
# @option options [Symbol, String] :unless - method name to check before executing the callback.
|
50
|
+
# @option options [Array<Symbol, String>] :only - array of action names.
|
51
|
+
# @see ActiveFunctionCore::Plugins::Hooks::ClassMethods#set_callback
|
52
|
+
# @!method after_action(target, options)
|
53
|
+
# @param [Symbol, String] target - method name to call
|
54
|
+
# @option options [Symbol, String] :if - method name to check before executing the callback.
|
55
|
+
# @option options [Symbol, String] :unless - method name to check before executing the callback.
|
56
|
+
# @option options [Array<Symbol, String>] :only - array of action names.
|
57
|
+
# @see ActiveFunctionCore::Plugins::Hooks::ClassMethods#set_callback
|
58
|
+
|
59
|
+
# @!method set_callback(type, hook_name, target, options)
|
60
|
+
# @see ActiveFunctionCore::Plugins::Hooks::ClassMethods#set_callback
|
61
|
+
|
62
|
+
# @!method define_hooks_for(method_name, name: method_name)
|
63
|
+
# @see ActiveFunctionCore::Plugins::Hooks::ClassMethods#define_hooks_for
|
64
|
+
|
65
|
+
# @!method set_callback_options(options)
|
66
|
+
# @see ActiveFunctionCore::Plugins::Hooks::ClassMethods#set_callback_options
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -3,20 +3,47 @@
|
|
3
3
|
require "json"
|
4
4
|
|
5
5
|
module ActiveFunction
|
6
|
-
|
7
|
-
|
6
|
+
module Functions
|
7
|
+
# Allows manipulations with {ActiveFunction::SuperBase#response} via {render} instance method.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# require "active_function"
|
11
|
+
#
|
12
|
+
# ActiveFunction.config do
|
13
|
+
# plugin :rendering
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class PostsFunction < ActiveFunction::Base
|
17
|
+
# def index
|
18
|
+
# render json: {id: 1, name: "Pupa"}, status: 200, head: {"Some-Header" => "Some-Value"}
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# PostFunction.process(:index) # => { :statusCode=>200, :headers=> {"Content-Type"=>"application/json", "Some-Header" => "Some-Value"}, :body=>"{\"id\":1,\"name\":\"Pupa\"}" }
|
23
|
+
module Rendering
|
24
|
+
ActiveFunction.register_plugin :rendering, self
|
8
25
|
|
9
|
-
|
26
|
+
Error = Class.new(StandardError)
|
10
27
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
28
|
+
class DoubleRenderError < Error
|
29
|
+
MESSAGE_TEMPLATE = "#render was called multiple times in action: %s"
|
30
|
+
|
31
|
+
attr_reader :message
|
32
|
+
|
33
|
+
def initialize(context)
|
34
|
+
@message = MESSAGE_TEMPLATE % context
|
35
|
+
end
|
36
|
+
end
|
15
37
|
|
16
|
-
module Functions
|
17
|
-
module Rendering
|
18
38
|
DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze
|
19
39
|
|
40
|
+
# Render JSON response.
|
41
|
+
#
|
42
|
+
# @param status [Integer] HTTP status code (default is 200).
|
43
|
+
# @param json [Hash] JSON data to be rendered (default is an empty hash).
|
44
|
+
# @param head [Hash] Additional headers to be included in the response (default is an empty hash).
|
45
|
+
#
|
46
|
+
# @raise [DoubleRenderError] Raised if #render is called multiple times in the same action.
|
20
47
|
def render(status: 200, json: {}, head: {})
|
21
48
|
raise DoubleRenderError, @action_name if performed?
|
22
49
|
|
@@ -2,29 +2,48 @@
|
|
2
2
|
|
3
3
|
module ActiveFunction
|
4
4
|
module Functions
|
5
|
-
|
6
|
-
|
5
|
+
# The only required plugin for {ActiveFunction::Base} to work.
|
6
|
+
# Provides a simple {Response} object to manage response details.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# response = Response.new.tap do |r|
|
10
|
+
# r.body = "Hello World!"
|
11
|
+
# r.headers = {"Content-Type" => "text/plain"}
|
12
|
+
# r.commit!
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# response.performed? # => true
|
16
|
+
# response.to_h # => { statusCode: 200, headers: { "Content-Type" => "text/plain" }, body: "Hello World!" }
|
17
|
+
module Response
|
18
|
+
ActiveFunction.register_plugin :response, self
|
7
19
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@
|
12
|
-
@
|
13
|
-
|
20
|
+
class Response < Struct.new(:status, :headers, :body, :committed)
|
21
|
+
# Initializes a new Response instance with default values.
|
22
|
+
#
|
23
|
+
# @param status [Integer] HTTP status code.
|
24
|
+
# @param headers [Hash] HTTP headers.
|
25
|
+
# @param body [Object] Response body.
|
26
|
+
# @param committed [Boolean] Indicates whether the response has been committed (default is false).
|
27
|
+
def initialize(status: 200, headers: {}, body: nil, committed: false) = super(status, headers, body, committed)
|
14
28
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
29
|
+
# Converts the Response instance to a hash for JSON serialization.
|
30
|
+
#
|
31
|
+
# @return [Hash{statusCode: Integer, headers: Hash, body: Object}]
|
32
|
+
def to_h
|
33
|
+
{
|
34
|
+
statusCode: status,
|
35
|
+
headers:,
|
36
|
+
body:
|
37
|
+
}
|
38
|
+
end
|
22
39
|
|
23
|
-
|
24
|
-
|
25
|
-
|
40
|
+
# Marks the response as committed.
|
41
|
+
def commit!
|
42
|
+
self.committed = true
|
43
|
+
end
|
26
44
|
|
27
|
-
|
45
|
+
alias_method :committed?, :committed
|
46
|
+
end
|
28
47
|
end
|
29
48
|
end
|
30
49
|
end
|
@@ -3,54 +3,80 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
5
|
module ActiveFunction
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
module Functions
|
7
|
+
# Allows manipulations with {ActiveFunction::SuperBase#request} via {params} instance method and {Parameters} object.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# require "active_function"
|
11
|
+
#
|
12
|
+
# ActiveFunction.config do
|
13
|
+
# plugin :strong_parameters
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class PostsFunction < ActiveFunction::Base
|
17
|
+
# def index
|
18
|
+
# @response.body = permitted_params
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def permitted_params
|
22
|
+
# params.require(:data).permit(:id, :name).to_h
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# PostsFunction.process(:index, data: { id: 1, name: "Pupa" })
|
27
|
+
module StrongParameters
|
28
|
+
ActiveFunction.register_plugin :strong_parameters, self
|
15
29
|
|
16
|
-
|
17
|
-
|
30
|
+
Error = Class.new(StandardError)
|
31
|
+
# The Parameters class encapsulates the parameter handling logic.
|
32
|
+
class Parameters < Data.define(:params, :permitted)
|
33
|
+
class ParameterMissingError < Error
|
34
|
+
MESSAGE_TEMPLATE = "Missing parameter: %s"
|
18
35
|
|
19
|
-
|
36
|
+
attr_reader :message
|
20
37
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
38
|
+
def initialize(param)
|
39
|
+
MESSAGE_TEMPLATE % param
|
40
|
+
end
|
41
|
+
end
|
25
42
|
|
26
|
-
|
27
|
-
|
28
|
-
def params
|
29
|
-
@_params ||= Parameters.new(@request)
|
30
|
-
end
|
43
|
+
class UnpermittedParameterError < Error
|
44
|
+
MESSAGE_TEMPLATE = "Unpermitted parameter: %s"
|
31
45
|
|
32
|
-
|
33
|
-
extend Forwardable
|
34
|
-
def_delegators :@parameters, :each, :map
|
35
|
-
include Enumerable
|
46
|
+
attr_reader :message
|
36
47
|
|
37
|
-
|
38
|
-
|
39
|
-
|
48
|
+
def initialize(param)
|
49
|
+
MESSAGE_TEMPLATE % param
|
50
|
+
end
|
40
51
|
end
|
41
52
|
|
53
|
+
protected :params
|
54
|
+
|
55
|
+
# Allows access to parameters by key.
|
56
|
+
#
|
57
|
+
# @param attribute [Symbol] The key of the parameter.
|
58
|
+
# @return [Parameters, Object] The value of the parameter.
|
42
59
|
def [](attribute)
|
43
|
-
nested_attribute(
|
60
|
+
nested_attribute(params[attribute])
|
44
61
|
end
|
45
62
|
|
63
|
+
# Requires the presence of a specific parameter.
|
64
|
+
#
|
65
|
+
# @param attribute [Symbol] The key of the required parameter.
|
66
|
+
# @return [Parameters, Object] The value of the required parameter.
|
67
|
+
# @raise [ParameterMissingError] if the required parameter is missing.
|
46
68
|
def require(attribute)
|
47
|
-
value = self[attribute]
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
69
|
+
if (value = self[attribute])
|
70
|
+
value
|
71
|
+
else
|
72
|
+
raise ParameterMissingError, attribute
|
73
|
+
end
|
52
74
|
end
|
53
75
|
|
76
|
+
# Specifies the allowed parameters.
|
77
|
+
#
|
78
|
+
# @param attributes [Array<Symbol, Hash<Symbol, Array<Symbol>>>] The attributes to permit.
|
79
|
+
# @return [Parameters] A new instance with permitted parameters.
|
54
80
|
def permit(*attributes)
|
55
81
|
pparams = {}
|
56
82
|
|
@@ -60,28 +86,40 @@ module ActiveFunction
|
|
60
86
|
pparams[k] = process_nested(self[k], :permit, v)
|
61
87
|
end
|
62
88
|
else
|
63
|
-
next unless
|
89
|
+
next unless params.key?(attribute)
|
64
90
|
|
65
91
|
pparams[attribute] = self[attribute]
|
66
92
|
end
|
67
93
|
end
|
68
94
|
|
69
|
-
|
95
|
+
with(params: pparams, permitted: true)
|
70
96
|
end
|
71
97
|
|
98
|
+
# Converts parameters to a hash.
|
99
|
+
#
|
100
|
+
# @return [Hash] The hash representation of the parameters.
|
101
|
+
# @raise [UnpermittedParameterError] if any parameters are unpermitted.
|
72
102
|
def to_h
|
73
|
-
raise UnpermittedParameterError,
|
103
|
+
raise UnpermittedParameterError, params.keys unless permitted
|
74
104
|
|
75
|
-
|
105
|
+
params.transform_values { process_nested(_1, :to_h) }
|
106
|
+
end
|
107
|
+
|
108
|
+
def hash
|
109
|
+
@attributes.to_h.hash
|
110
|
+
end
|
111
|
+
|
112
|
+
def with(params:, permitted: false)
|
113
|
+
self.class.new(params, permitted)
|
76
114
|
end
|
77
115
|
|
78
116
|
private
|
79
117
|
|
80
118
|
def nested_attribute(attribute)
|
81
119
|
if attribute.is_a? Hash
|
82
|
-
|
120
|
+
with(params: attribute)
|
83
121
|
elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash)
|
84
|
-
attribute.map {
|
122
|
+
attribute.map { |it| with(params: it) }
|
85
123
|
else
|
86
124
|
attribute
|
87
125
|
end
|
@@ -96,8 +134,13 @@ module ActiveFunction
|
|
96
134
|
attribute
|
97
135
|
end
|
98
136
|
end
|
137
|
+
end
|
99
138
|
|
100
|
-
|
139
|
+
# Return params object with {ActiveFunction::SuperBase#request}.
|
140
|
+
#
|
141
|
+
# @return [Parameters] instance of {Parameters} class.
|
142
|
+
def params
|
143
|
+
@_params ||= Parameters.new(@request, false)
|
101
144
|
end
|
102
145
|
end
|
103
146
|
end
|