eitil 0.3.10 → 1.0.1.e.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -331
- data/eitil_core/README.md +288 -0
- data/eitil_core/lib/eitil_core.rb +24 -0
- data/eitil_core/lib/eitil_core/application_controller.rb +2 -0
- data/eitil_core/lib/eitil_core/application_controller/slice_params.rb +14 -0
- data/eitil_core/lib/eitil_core/application_record.rb +4 -0
- data/eitil_core/lib/eitil_core/application_record/all_associations.rb +16 -0
- data/eitil_core/lib/eitil_core/application_record/find_by_like.rb +15 -0
- data/eitil_core/lib/eitil_core/application_record/where_like.rb +15 -0
- data/eitil_core/lib/eitil_core/argument_helpers.rb +5 -0
- data/eitil_core/lib/eitil_core/argument_helpers/all_args_to_ivars.rb +12 -0
- data/eitil_core/lib/eitil_core/argument_helpers/all_kwargs_to_ivars.rb +12 -0
- data/eitil_core/lib/eitil_core/argument_helpers/args_to_ivars.rb +12 -0
- data/eitil_core/lib/eitil_core/concerns.rb +2 -0
- data/{config/initializers/monkeys/module.rb → eitil_core/lib/eitil_core/concerns/include_concerns_of.rb} +3 -0
- data/eitil_core/lib/eitil_core/datetime.rb +2 -0
- data/{config/initializers/monkeys/date_time.rb → eitil_core/lib/eitil_core/datetime/prettify.rb} +3 -0
- data/eitil_core/lib/eitil_core/errors.rb +2 -0
- data/eitil_core/lib/eitil_core/errors/raise_error.rb +11 -0
- data/eitil_core/lib/eitil_core/float.rb +2 -0
- data/{config/initializers/monkeys/float.rb → eitil_core/lib/eitil_core/float/safe_to_i.rb} +0 -0
- data/eitil_core/lib/eitil_core/hash.rb +2 -0
- data/{config/initializers/monkeys/hash.rb → eitil_core/lib/eitil_core/hash/auto_dig.rb} +3 -0
- data/eitil_core/lib/eitil_core/lookups.rb +2 -0
- data/{config/initializers/monkeys/object.rb → eitil_core/lib/eitil_core/lookups/all_methods.rb} +3 -0
- data/eitil_core/lib/eitil_core/railtie.rb +37 -0
- data/eitil_core/lib/eitil_core/safe_executions.rb +3 -0
- data/eitil_core/lib/eitil_core/safe_executions/safe_call.rb +12 -0
- data/eitil_core/lib/eitil_core/safe_executions/safe_send.rb +12 -0
- data/eitil_core/lib/eitil_core/setters.rb +2 -0
- data/eitil_core/lib/eitil_core/setters/set_ivars.rb +12 -0
- data/eitil_core/lib/eitil_core/type_checkers.rb +2 -0
- data/{config/initializers/monkeys/string.rb → eitil_core/lib/eitil_core/type_checkers/is_num_or_nan.rb} +5 -5
- data/eitil_core/lib/eitil_core/validations.rb +2 -0
- data/eitil_core/lib/eitil_core/validations/run_validations.rb +10 -0
- data/eitil_integrate/README.md +8 -0
- data/eitil_integrate/lib/eitil_integrate.rb +0 -0
- data/eitil_integrate/lib/eitil_integrate/railtie.rb +10 -0
- data/eitil_store/README.md +16 -0
- data/eitil_store/lib/eitil_store.rb +4 -0
- data/eitil_store/lib/eitil_store/railtie.rb +10 -0
- data/eitil_store/lib/eitil_store/regex.rb +4 -0
- data/eitil_store/lib/eitil_store/regex/regex.rb +41 -0
- data/eitil_support/README.md +78 -0
- data/eitil_support/lib/eitil_support.rb +5 -0
- data/eitil_support/lib/eitil_support/directory.rb +2 -0
- data/eitil_support/lib/eitil_support/directory/lookups.rb +23 -0
- data/eitil_support/lib/eitil_support/railtie.rb +10 -0
- data/eitil_support/lib/eitil_support/stacktrace.rb +4 -0
- data/{app/models/eitil/stack_trace → eitil_support/lib/eitil_support/stacktrace}/audit.rb +2 -2
- data/{app/models/eitil/stack_trace → eitil_support/lib/eitil_support/stacktrace}/call.rb +1 -1
- data/{app/models/eitil/stack_trace → eitil_support/lib/eitil_support/stacktrace}/stack.rb +2 -2
- data/eitil_wrapper/README.md +181 -0
- data/eitil_wrapper/lib/eitil_wrapper.rb +7 -0
- data/eitil_wrapper/lib/eitil_wrapper/decorators.rb +3 -0
- data/{config/initializers/wrappers → eitil_wrapper/lib/eitil_wrapper}/decorators/application_decorator.rb +1 -1
- data/eitil_wrapper/lib/eitil_wrapper/decorators/controller_decorator.rb +60 -0
- data/eitil_wrapper/lib/eitil_wrapper/jobs.rb +4 -0
- data/eitil_wrapper/lib/eitil_wrapper/jobs/new_job.rb +34 -0
- data/eitil_wrapper/lib/eitil_wrapper/jobs/new_job_debugger.rb +37 -0
- data/eitil_wrapper/lib/eitil_wrapper/jobs/single_method_job.rb +8 -0
- data/eitil_wrapper/lib/eitil_wrapper/railtie.rb +49 -0
- data/eitil_wrapper/lib/eitil_wrapper/routes.rb +2 -0
- data/{config/initializers/wrappers → eitil_wrapper/lib/eitil_wrapper}/routes/extended_resources.rb +2 -2
- data/eitil_wrapper/lib/eitil_wrapper/scopes.rb +2 -0
- data/eitil_wrapper/lib/eitil_wrapper/scopes/default_scopes.rb +80 -0
- data/lib/eitil.rb +1 -1
- data/lib/eitil/all.rb +18 -0
- data/lib/eitil/engine.rb +24 -0
- data/lib/eitil/railtie.rb +6 -0
- data/lib/eitil/version.rb +3 -1
- metadata +82 -34
- data/app/controllers/eitil/application_controller.rb +0 -4
- data/app/jobs/eitil/application_job.rb +0 -4
- data/app/mailers/eitil/application_mailer.rb +0 -6
- data/app/models/eitil/application_record.rb +0 -5
- data/config/initializers/modules/dir.rb +0 -21
- data/config/initializers/monkeys/application_controller.rb +0 -14
- data/config/initializers/monkeys/application_record.rb +0 -30
- data/config/initializers/monkeys/kernel.rb +0 -48
- data/config/initializers/wrappers/decorators/controller_decorator.rb +0 -63
- data/config/initializers/wrappers/jobs/active_job_macros.rb +0 -52
- data/config/initializers/wrappers/jobs/single_method_job.rb +0 -24
- data/config/initializers/wrappers/scopes/default_scopes.rb +0 -83
- data/config/routes.rb +0 -2
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
# EitilSupport
|
5
|
+
|
6
|
+
EitilSupport provides utility through stand-alone classes and modules.
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
## EitilSupport::Directory
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
|
14
|
+
require "eitil_support/directory"
|
15
|
+
|
16
|
+
```
|
17
|
+
|
18
|
+
The EitilSupport::Directory module provides methods which help you introspect your Rails project.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
EitilSupport::Directory.contents(directory='app')
|
22
|
+
# returns all files and subdirectories of a given directory
|
23
|
+
```
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
EitilSupport::Directory.files(directory='app')
|
27
|
+
# returns all files of a given directory
|
28
|
+
```
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
EitilSupport::Directory.subdirs(directory='app')
|
32
|
+
# returns all subdirectories of a given directory
|
33
|
+
```
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
EitilSupport::Directory.lines(directory='app')
|
37
|
+
# returns the total amount of lines of all files of a given directory
|
38
|
+
```
|
39
|
+
|
40
|
+
|
41
|
+
## EitilSupport::StackTrace
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
|
45
|
+
require "eitil_support/stacktrace"
|
46
|
+
|
47
|
+
```
|
48
|
+
|
49
|
+
The classes EitilSupport::Stack and EitilSupport::Call, and the module EitilSupport::Stack::Audit, provide the utility of easily viewing and storing the current stacktrace anywhere in your code – by initializing EitilSupport::Stack:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
stack = EitilSupport::Stack.new
|
53
|
+
```
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
stack.report
|
57
|
+
# returns the stacktrace as array, with each call being a stringified instance of EitilSupport::Call
|
58
|
+
```
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
stack.show
|
62
|
+
# pretty prints the stack.report stacktrace
|
63
|
+
```
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
stack.find
|
67
|
+
# accepts a block to find a specific call
|
68
|
+
```
|
69
|
+
|
70
|
+
You can also store the stacktrace of a record's update action into its audit. In order to do so, you need 1) to include EitilSupport::Stack::Audit into your model, and 2) add a :stacktrace column to your audits through the following migration.
|
71
|
+
|
72
|
+
### Migration
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
def change
|
76
|
+
add_column :audits, :stacktrace, :text, array: true, default: []
|
77
|
+
end
|
78
|
+
```
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module EitilSupport
|
2
|
+
module Directory
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def contents(directory='app')
|
6
|
+
Dir[File.join(directory, '**', '*')]
|
7
|
+
end
|
8
|
+
|
9
|
+
def files(directory='app')
|
10
|
+
contents(directory).select { |file| File.file?(file) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def subdirs(directory='app')
|
14
|
+
contents(directory).select { |file| File.directory?(file) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def lines(directory='app')
|
18
|
+
files(directory).map { |file| File.open(file).count }.sum
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module EitilSupport::Stack::Audit
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
included do
|
4
4
|
|
@@ -7,7 +7,7 @@ module Eitil::StackTrace::Audit
|
|
7
7
|
after_update :add_stacktrace_to_audit
|
8
8
|
|
9
9
|
def add_stacktrace_to_audit
|
10
|
-
stacktrace =
|
10
|
+
stacktrace = EitilSupport::Stack.new.report
|
11
11
|
self.audits.last.update(stacktrace: stacktrace)
|
12
12
|
end
|
13
13
|
|
@@ -1,11 +1,11 @@
|
|
1
|
-
module
|
1
|
+
module EitilSupport
|
2
2
|
class Stack
|
3
3
|
|
4
4
|
attr_reader :stack, :backtrace
|
5
5
|
|
6
6
|
def initialize
|
7
7
|
@stack = caller[1..]
|
8
|
-
@backtrace = stack.map { |call|
|
8
|
+
@backtrace = stack.map { |call| EitilSupport::Call.new(call) }
|
9
9
|
end
|
10
10
|
|
11
11
|
def report
|
@@ -0,0 +1,181 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
# EitilWrapper
|
5
|
+
|
6
|
+
EitilWrapper wraps core rails operations with extended utilities – such as routing, jobs and decoraters.
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## EitilWrapper::Decorators
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
|
16
|
+
require "eitil_wrapper/decorators"
|
17
|
+
|
18
|
+
```
|
19
|
+
|
20
|
+
The Eitil decorator wrappers help you to standardize the calling of the right decorator method from within your controller action. Basically it provides you with a decorate macro in each controller.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
decorate(dec_item, dec_method: nil, dec_class: nil, **dec_kwargs)
|
24
|
+
```
|
25
|
+
|
26
|
+
- dec_item is the instance that will be decorated
|
27
|
+
- dec_method enabled you to set the desired decorator method. If not provided, it will look into the request params: if params["isMobile"] is present it will call .app, if params["isWeb"] is present it will call :app. If neither is provided in the params, it will call the default method :base.
|
28
|
+
- dec_class enables you to overwrite the decorator class that will be called. If not provided, the decorator class will be inferred from the instance model's classname (User => UserDecorator).
|
29
|
+
- dec_kwargs enables you to provide additional arguments, which will be passed to your decorator method.
|
30
|
+
|
31
|
+
|
32
|
+
### Configuration
|
33
|
+
|
34
|
+
1. Your decorator classes should inherit from Eitil::ApplicationDecorator.
|
35
|
+
2. Your controllers should inherit the module Eitil::ControllerDecorator, through inclusion in a superclass.
|
36
|
+
3. If you set controller ivars for each request, you can make them available in your decorators by providing Eitil a method which returns the names of your ivars as an array of symbols:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# initializers/eitil.rb
|
40
|
+
|
41
|
+
Eitil.set_config do |config|
|
42
|
+
config.get_controller_ivars_method = 'API::BaseController.controller_ivars' # => [:user, :env]
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
## EitilWrapper::Jobs
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
|
54
|
+
require "eitil_wrapper/jobs"
|
55
|
+
|
56
|
+
```
|
57
|
+
|
58
|
+
The Eitil jobs wrapper enables you to create perform_now and perform_later jobs on the fly, without the need to create a new class and file.
|
59
|
+
|
60
|
+
The macro new_job accepts a :method as argument and defines a new method :method_job. The newly defined :method_job, when called, performs the orginal :method in the background. The new_job macro accepts both instance methods and singleton methods, which are defined within there own method scope.
|
61
|
+
|
62
|
+
In contrast, the new_job_debugger macro defines a new :method_job_debugger method, which performs in the foreground.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# require "eitil_wrapper/jobs/new_job"
|
66
|
+
|
67
|
+
new_job(_method, *args, **kwargs)
|
68
|
+
# assuming a method :hello_world, call as: new_job :hello_world
|
69
|
+
# => defines :hello_world_job
|
70
|
+
```
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# require "eitil_wrapper/jobs/new_job_debugger"
|
74
|
+
|
75
|
+
new_job_debugger(_method, *args, **kwargs)
|
76
|
+
# assuming a method :hello_world, call as: new_job_debugger :hello_world
|
77
|
+
# => defines :hello_world_job_debugger
|
78
|
+
```
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
## EitilWrapper::Routes
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
|
88
|
+
require "eitil_wrapper/routes"
|
89
|
+
|
90
|
+
```
|
91
|
+
|
92
|
+
The Eitil router wrapper enables you to easily create new routes that can be shared among controllers. In that sense, it is as a custom extension of the built-in resourceful routes.
|
93
|
+
|
94
|
+
### New route
|
95
|
+
|
96
|
+
The first macro, .new_route, enables you to create new route objects which may be called and used by different controllers.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
# require "eitil_wrapper/routes/extended_resources"
|
100
|
+
|
101
|
+
new_route(verb, _method, action, scope)
|
102
|
+
# call as: new_route :post, :attachment, "add_attachment", :member
|
103
|
+
```
|
104
|
+
|
105
|
+
- verb refers to the http_verb, e.g. :put.
|
106
|
+
- method refers to the given http method (e.g. 'users/:id'). Additionally, this is the name you will refer to in order to include the route into a controller. Therefore the argument should be unique among all other routes.
|
107
|
+
- action refers to the controller action to which you want to redirect to request, e.g. :update_user.
|
108
|
+
- scope refers to the url and can be set to either :member or :collection.
|
109
|
+
|
110
|
+
### Add route
|
111
|
+
|
112
|
+
The second macro, extended_resources, enables you to create all standard resources for a controller and add your own standardized routes. This macro works the same as the built-in :resources, except that you can pass more arguments to only: [], which adds the routes to your controller.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# require "eitil_wrapper/routes/extended_resources"
|
116
|
+
|
117
|
+
extended_resources(controller, **kwargs)
|
118
|
+
# call as: extended_resources :posts, only: [:create, :update, :attachment]
|
119
|
+
```
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
## EitilWrapper::Scopes
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
|
129
|
+
require "eitil_wrapper/scopes"
|
130
|
+
|
131
|
+
```
|
132
|
+
|
133
|
+
Scopes are generated through the columns of your model's database table. Which scopes are generated depends on the datatype of a column. For example, if your User model with table users has a column is_manager, a scope :is_manager_true is generated for your User model. A scope method is defined only if it does not already responds to another method of the same name. The scopes generated are:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# require "eitil_wrapper/scopes/default_scopes"
|
137
|
+
|
138
|
+
# columns of datatype: boolean
|
139
|
+
.{column_name}_true
|
140
|
+
.{column_name}_false
|
141
|
+
|
142
|
+
# columns of datatype: datetime
|
143
|
+
.{column_name}_today
|
144
|
+
.{column_name}_past
|
145
|
+
.{column_name}_future
|
146
|
+
.{column_name}_on_date(date)
|
147
|
+
.{column_name}_before_date(date)
|
148
|
+
.{column_name}_after_date(date)
|
149
|
+
.{column_name}_between_dates(start_date, end_date)
|
150
|
+
.{column_name}_oldest_first
|
151
|
+
.{column_name}_newest_first
|
152
|
+
|
153
|
+
# columns of datatype: date
|
154
|
+
.{column_name}_today
|
155
|
+
.{column_name}_past
|
156
|
+
.{column_name}_future
|
157
|
+
.{column_name}_on_date(date)
|
158
|
+
.{column_name}_before_date(date)
|
159
|
+
.{column_name}_after_date(date)
|
160
|
+
.{column_name}_between_dates(start_date, end_date)
|
161
|
+
.{column_name}_oldest_first
|
162
|
+
.{column_name}_newest_first
|
163
|
+
|
164
|
+
# columns of datatype: integer
|
165
|
+
.{column_name}_equal_to(number)
|
166
|
+
.{column_name}_lower_than(number)
|
167
|
+
.{column_name}_higher_than(number)
|
168
|
+
.{column_name}_between(min, max)
|
169
|
+
.{column_name}_ascending
|
170
|
+
.{column_name}_descending
|
171
|
+
|
172
|
+
# columns of datatype: float
|
173
|
+
.{column_name}_equal_to(number)
|
174
|
+
.{column_name}_lower_than(number)
|
175
|
+
.{column_name}_higher_than(number)
|
176
|
+
.{column_name}_between(min, max)
|
177
|
+
.{column_name}_ascending
|
178
|
+
.{column_name}_descending
|
179
|
+
```
|
180
|
+
|
181
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module EitilWrapper
|
2
|
+
module ControllerDecorator
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def decorate(dec_item, dec_method: nil, dec_class: nil, **dec_kwargs)
|
7
|
+
all_args_to_ivars binding
|
8
|
+
set_ivars :dec_class, :dec_method, :decorator
|
9
|
+
send_to_decorator
|
10
|
+
end
|
11
|
+
|
12
|
+
def send_to_decorator
|
13
|
+
@dec_kwargs.any? ? @decorator.send(@dec_method, @dec_item, @dec_kwargs)
|
14
|
+
: @decorator.send(@dec_method, @dec_item)
|
15
|
+
|
16
|
+
rescue NoMethodError => e
|
17
|
+
inform_no_method_for_decorator_error
|
18
|
+
@dec_item
|
19
|
+
end
|
20
|
+
|
21
|
+
def inform_no_method_for_decorator_error
|
22
|
+
message = "Warning: NoMethodError for #{@dec_class}.#{@dec_method}, returned @dec_item instead."
|
23
|
+
Logger.new("#{Rails.root}/log/decorator_log.log").warn message
|
24
|
+
warn message
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_dec_method
|
28
|
+
@dec_method = @dec_method || derived_dec_method || :base
|
29
|
+
end
|
30
|
+
|
31
|
+
def derived_dec_method
|
32
|
+
return unless respond_to? :params
|
33
|
+
return :app if params["isMobile"]
|
34
|
+
return :web if params["isWeb"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_dec_class
|
38
|
+
@dec_class = @dec_class ? manual_set_dec_class : derived_dec_class
|
39
|
+
end
|
40
|
+
|
41
|
+
def manual_set_dec_class
|
42
|
+
"#{@dec_class}Decorator".constantize
|
43
|
+
end
|
44
|
+
|
45
|
+
def derived_dec_class
|
46
|
+
"#{@dec_item.class.name}Decorator".constantize
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_decorator
|
50
|
+
@decorator = @dec_class.new controller_ivars
|
51
|
+
end
|
52
|
+
|
53
|
+
def controller_ivars
|
54
|
+
eval(Eitil.get_controller_ivars_method).map do |ivar|
|
55
|
+
{ ivar => instance_variable_get("@#{ivar.to_s}") }
|
56
|
+
end.inject &:merge
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
# require "eitil_wrapper/jobs/new_job"
|
3
|
+
|
4
|
+
require "eitil_wrapper/jobs/single_method_job"
|
5
|
+
|
6
|
+
Kernel.module_eval do
|
7
|
+
|
8
|
+
# BEWARE: _self is currently not accepted in perform_later jobs due to serialization errors
|
9
|
+
|
10
|
+
# The cases of 'id' and '_self' both handle instances, with the difference
|
11
|
+
# being that 'id' works for objects that have a database record, while '_self'
|
12
|
+
# works for non database supported instanes, such as an Exporter instance.
|
13
|
+
|
14
|
+
def new_job(_method, *args, **kwargs)
|
15
|
+
|
16
|
+
if instance_methods(false).include? _method
|
17
|
+
define_method "#{_method}_job" do |_self = nil, *args, **kwargs|
|
18
|
+
|
19
|
+
EitilWrapper::SingleMethodJob.perform_later(
|
20
|
+
*args, _class: self.class.to_s, _method: _method.to_s, id: safe_send(:id), _self: self.to_json, **kwargs
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
elsif singleton_methods(false).include? _method
|
25
|
+
define_singleton_method "#{_method}_job" do |*args, **kwargs|
|
26
|
+
|
27
|
+
EitilWrapper::SingleMethodJob.perform_later(
|
28
|
+
*args, _class: to_s, _method: _method.to_s, **kwargs
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|