verifly 0.1.0.0 → 0.2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/verifly.rb +3 -3
- data/lib/verifly/applicator.rb +20 -20
- data/lib/verifly/applicator_with_options.rb +14 -7
- data/lib/verifly/class_builder.rb +8 -7
- data/lib/verifly/verifier.rb +40 -20
- data/lib/verifly/version.rb +6 -6
- metadata +14 -13
- data/lib/verifly/verifier/applicator_with_options_builder.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb480769ef6ceb801e8d09f52eb9eab8a31bd356
|
4
|
+
data.tar.gz: fb911427e5d26cb1f10ae5142af217aae51110fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e22e09f78908ed3e451c3ce90d1e1c7d439cb1c69c8c356c4fd858ea2bbd3a071713c62666d6c74e364bc57faa61207cd3425e897b76fc834a1394f2bbe8bcb5
|
7
|
+
data.tar.gz: c5f4a1fd4a51b470cc12c5b4f57086a0e526919abbbbb949ef6781d3efb2e2b6645b879a14a4866ebeecb9ffaf4bb504ab2607e6f4258d0f61aa642ef1016c39
|
data/lib/verifly.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Verifly provides several
|
4
|
-
#
|
5
|
-
# See README.md or
|
3
|
+
# Verifly provides several useful classes, but Verifier is the most
|
4
|
+
# important one, while others depend on it.
|
5
|
+
# See README.md or in-code documentation for more info.
|
6
6
|
module Verifly
|
7
7
|
autoload :VERSION, 'verifly/version'
|
8
8
|
|
data/lib/verifly/applicator.rb
CHANGED
@@ -33,7 +33,7 @@ module Verifly
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# MethodExtractor is used when applicable is a symbol.
|
36
|
-
# It extracts
|
36
|
+
# It extracts a method from binding_ and executes it on binding_
|
37
37
|
# (so it works just like send except it sends nothing
|
38
38
|
# when method arity is zero).
|
39
39
|
# @example
|
@@ -42,14 +42,14 @@ module Verifly
|
|
42
42
|
# # or => User.new.foo, if it does not accept context
|
43
43
|
class MethodExtractor < self
|
44
44
|
# @param applicable [Symbol]
|
45
|
-
# @return MethodExtractor if applicable is Symbol
|
45
|
+
# @return MethodExtractor if applicable is a Symbol
|
46
46
|
# @return [nil] otherwise
|
47
47
|
def self.build_class(applicable)
|
48
48
|
self if applicable.is_a?(Symbol)
|
49
49
|
end
|
50
50
|
|
51
|
-
# @param binding_ [#instance_exec] target to apply applicable
|
52
|
-
# @param context additional info to send
|
51
|
+
# @param binding_ [#instance_exec] target to apply applicable to
|
52
|
+
# @param context additional info to send to applicable
|
53
53
|
# @return application result
|
54
54
|
def call(binding_, context)
|
55
55
|
if binding_.is_a?(Binding)
|
@@ -61,9 +61,9 @@ module Verifly
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
-
# When Binding is target, we have to respect both methods and variables
|
65
|
-
# @param binding_ [Binding] target to apply applicable
|
66
|
-
# @param context additional info to send
|
64
|
+
# When Binding is a target, we have to respect both methods and variables
|
65
|
+
# @param binding_ [Binding] target to apply applicable to
|
66
|
+
# @param context additional info to send to applicable
|
67
67
|
# @return application result
|
68
68
|
def call_on_binding(binding_, context)
|
69
69
|
if binding_.receiver.respond_to?(applicable)
|
@@ -74,21 +74,21 @@ module Verifly
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# InstanceEvaluator is used for
|
77
|
+
# InstanceEvaluator is used for strings. It works like instance_eval or
|
78
78
|
# Binding#eval depending on binding_ class
|
79
79
|
# @example
|
80
80
|
# Applicator.call('foo if context[:foo]', binding_, context)
|
81
81
|
# # => foo if context[:foo]
|
82
82
|
class InstanceEvaluator < self
|
83
83
|
# @param applicable [String]
|
84
|
-
# @return InstanceEvaluator if applicable is String
|
84
|
+
# @return InstanceEvaluator if applicable is a String
|
85
85
|
# @return [nil] otherwise
|
86
86
|
def self.build_class(applicable)
|
87
87
|
self if applicable.is_a?(String)
|
88
88
|
end
|
89
89
|
|
90
|
-
# @param binding_ [#instance_exec] target to apply applicable
|
91
|
-
# @param context additional info to send
|
90
|
+
# @param binding_ [#instance_exec] target to apply applicable to
|
91
|
+
# @param context additional info to send to applicable
|
92
92
|
# @return application result
|
93
93
|
def call(binding_, context)
|
94
94
|
if binding_.is_a?(Binding)
|
@@ -111,10 +111,10 @@ module Verifly
|
|
111
111
|
end
|
112
112
|
|
113
113
|
# ProcApplicatior is used when #to_proc is available.
|
114
|
-
# It works not
|
115
|
-
# @example with proc
|
114
|
+
# It works not only with procs, but also with hashes etc
|
115
|
+
# @example with a proc
|
116
116
|
# Applicator.call(-> { foo }, binding_, context) # => foo
|
117
|
-
# @example with hash
|
117
|
+
# @example with a hash
|
118
118
|
# Applicator.call(Hash[foo: true], binding_, :foo) # => true
|
119
119
|
# Applicator.call(Hash[foo: true], binding_, :bar) # => nil
|
120
120
|
class ProcApplicatior < self
|
@@ -125,8 +125,8 @@ module Verifly
|
|
125
125
|
self if applicable.respond_to?(:to_proc)
|
126
126
|
end
|
127
127
|
|
128
|
-
# @param binding_ [#instance_exec] target to apply applicable
|
129
|
-
# @param context additional info to send
|
128
|
+
# @param binding_ [#instance_exec] target to apply applicable to
|
129
|
+
# @param context additional info to send to applicable
|
130
130
|
# @return application result
|
131
131
|
def call(binding_, context)
|
132
132
|
invoke_lambda(applicable.to_proc, binding_, context)
|
@@ -151,9 +151,9 @@ module Verifly
|
|
151
151
|
attr_accessor :applicable
|
152
152
|
|
153
153
|
# Applies applicable on binding_ with context
|
154
|
-
# @todo add @see #initialize when
|
154
|
+
# @todo add @see #initialize when its todo is done
|
155
155
|
# @param applicable [applicable]
|
156
|
-
# see examples in
|
156
|
+
# see examples in definitions of subclasses
|
157
157
|
# @param binding_ [#instance_exec]
|
158
158
|
# where should applicable be applied. It could be either a generic object,
|
159
159
|
# where it would be `instance_exec`uted, or a binding_
|
@@ -168,7 +168,7 @@ module Verifly
|
|
168
168
|
# Always use build instead of new
|
169
169
|
# @todo add more examples right here
|
170
170
|
# @param applicable [applicable]
|
171
|
-
# see examples in
|
171
|
+
# see examples in definitions of sublclasses
|
172
172
|
# @api private
|
173
173
|
def initialize(applicable)
|
174
174
|
self.applicable = applicable
|
@@ -189,7 +189,7 @@ module Verifly
|
|
189
189
|
|
190
190
|
private
|
191
191
|
|
192
|
-
# invokes lambda respecting
|
192
|
+
# invokes lambda respecting its arity
|
193
193
|
# @param [Proc] lambda
|
194
194
|
# @param binding_ [#instance_exec] binding_ would be used in application
|
195
195
|
# @param context param would be passed if lambda arity > 0
|
@@ -9,25 +9,32 @@ module Verifly
|
|
9
9
|
# @attr action [Applicator]
|
10
10
|
# main action to apply on call
|
11
11
|
# @attr if_condition [Applicator]
|
12
|
-
# main action only apply if
|
12
|
+
# main action only apply if condition evaluates to truthy value
|
13
13
|
# @attr unless_condition [Applicator]
|
14
|
-
# main action only apply if
|
14
|
+
# main action only apply if condition evaluates to falsey value
|
15
15
|
class ApplicatorWithOptions
|
16
16
|
attr_accessor :action, :if_condition, :unless_condition
|
17
17
|
|
18
|
+
# @!method initialize(action = block, options = {}, &block)
|
18
19
|
# @param action [applicable] main action
|
19
20
|
# @option options [applicable] :if
|
20
|
-
# main action only
|
21
|
+
# main action is only applied if this evaluates to truthy value
|
21
22
|
# @option options [applicable] :unless
|
22
|
-
# main action only
|
23
|
-
|
23
|
+
# main action is only applied if this evaluates to falsey value
|
24
|
+
# @raise [ArgumentError] if there is more than two arguments and block
|
25
|
+
# @raise [ArgumentError] if there is zero arguments and no block
|
26
|
+
def initialize(*args, &block)
|
27
|
+
action, options, *rest = block ? [block, *args] : args
|
28
|
+
options ||= {}
|
29
|
+
raise ArgumentError unless action && rest.empty?
|
30
|
+
|
24
31
|
self.action = Applicator.build(action)
|
25
32
|
self.if_condition = Applicator.build(options.fetch(:if, true))
|
26
33
|
self.unless_condition = Applicator.build(options.fetch(:unless, false))
|
27
34
|
end
|
28
35
|
|
29
|
-
# Applies main action if if_condition
|
30
|
-
# and unless_condition
|
36
|
+
# Applies main action if if_condition is evaluated to truthy value
|
37
|
+
# and unless_condition is evaluated to falsey value
|
31
38
|
# @param binding_ [#instance_exec]
|
32
39
|
# binding to apply (see Applicator)
|
33
40
|
# @param context
|
@@ -1,27 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Verifly
|
4
|
-
# ClassBuilder is
|
5
|
-
# allows
|
6
|
-
# I find it much more
|
4
|
+
# ClassBuilder is similar to Uber::Builder, but it
|
5
|
+
# allows child classes to decide whether they will be used.
|
6
|
+
# I find it much more object-oriented
|
7
7
|
# @attr klasses [Array(Class)]
|
8
8
|
# classes to iterate during search of most suitable
|
9
9
|
class ClassBuilder
|
10
|
-
# Mixin provides useful methods to integrate builder subsystem.
|
10
|
+
# Mixin provides useful methods to integrate into builder subsystem.
|
11
11
|
# Feel free to override or just never include it.
|
12
12
|
# @attr_writer [Array(Class)] buildable_classes
|
13
13
|
# Array of classes which will be checked if they
|
14
14
|
# suite constructor arguments. Order matters
|
15
15
|
module Mixin
|
16
|
-
# Array of classes which
|
16
|
+
# Array of classes which will be checked if they
|
17
17
|
# suite constructor arguments. Order matters
|
18
18
|
# @param klasses [Array(Class)]
|
19
19
|
def buildable_classes=(klasses)
|
20
20
|
@class_builder = ClassBuilder.new(klasses).freeze
|
21
21
|
end
|
22
22
|
|
23
|
-
# Default implementation of build_class.
|
24
|
-
#
|
23
|
+
# Default implementation of build_class.
|
24
|
+
# Feel free to change it, but you'll have to override it in
|
25
|
+
# buildable_classes
|
25
26
|
def build_class(*args, &block)
|
26
27
|
if @class_builder
|
27
28
|
@class_builder.call(*args, &block)
|
data/lib/verifly/verifier.rb
CHANGED
@@ -15,35 +15,54 @@ module Verifly
|
|
15
15
|
|
16
16
|
attr_accessor :model, :messages
|
17
17
|
|
18
|
-
#
|
18
|
+
# @!method self.verify(action = block, options = {}, &block)
|
19
|
+
# @example with a block
|
19
20
|
# verify { |context| message!() if context[:foo] }
|
20
|
-
# @example with proc
|
21
|
+
# @example with a proc
|
21
22
|
# verify -> (context) { message!() if context[:foo] }
|
22
|
-
# @example with hash
|
23
|
+
# @example with a hash
|
23
24
|
# verify -> { message!() } if: { foo: true }
|
24
|
-
# @example
|
25
|
+
# @example context can be provided as a lambda param
|
25
26
|
# verify -> { message!() }, if: -> (context) { context[:foo] }
|
26
|
-
# @example with symbol
|
27
|
+
# @example with a symbol
|
27
28
|
# verify :foo, if: :bar
|
28
29
|
# # calls #foo if #bar is true
|
29
|
-
# # bar
|
30
|
-
# @example with string
|
30
|
+
# # bar can accept context if desired
|
31
|
+
# @example with a string
|
31
32
|
# verify 'message!() if context[:foo]'
|
32
33
|
# verify 'message!()', if: 'context[:foo]'
|
33
|
-
# @
|
34
|
-
# verify DescendantClass
|
35
|
-
# # calls DescendantClass.call(model, context) and merges it's messages
|
36
|
-
# @param verifier [#to_proc|Symbol|String|Class|nil]
|
34
|
+
# @param action [#to_proc|Symbol|String|nil]
|
37
35
|
# verifier defenition, see examples
|
38
36
|
# @option options [#to_proc|Symbol|String|nil] if (true)
|
37
|
+
# call verifier only if block invocation result is truthy
|
38
|
+
# @option options [#to_proc|Symbol|String|nil] unless (false)
|
39
|
+
# call verifier only if block invocation result is falsey
|
40
|
+
# @yield [context] yields on `#verfify!` calls
|
41
|
+
# @raise [ArgumentError] if there is more than two arguments and block
|
42
|
+
# @raise [ArgumentError] if there is zero arguments and no block
|
43
|
+
# @return [Array] list of all defined verifiers
|
44
|
+
def self.verify(*args, &block)
|
45
|
+
bound_applicators << ApplicatorWithOptions.new(*args, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Calls DescendantClass.call(model, context) and merges its messages.
|
49
|
+
# DescendantClass should be a descendant of current class
|
50
|
+
# @param name [String, Class]
|
51
|
+
# name of descendant class or descendant class itself
|
52
|
+
# @option options [#to_proc|Symbol|String|nil] if (true)
|
39
53
|
# call verifier if only block invocation result is truthy
|
40
54
|
# @option options [#to_proc|Symbol|String|nil] unless (false)
|
41
55
|
# call verifier if only block invocation result is falsey
|
42
|
-
# @yield context on `#verfify!` calls
|
43
56
|
# @return [Array] list of all verifiers already defined
|
44
|
-
def self.
|
45
|
-
|
46
|
-
|
57
|
+
def self.verify_with(name, options = {})
|
58
|
+
verify(options) do |context|
|
59
|
+
verifier = name.is_a?(String) ? Object.const_get(name, false) : name
|
60
|
+
raise ArgumentError, <<~ERROR unless verifier < self.class
|
61
|
+
Nested verifiers should be inherited from verifier they nested are in
|
62
|
+
ERROR
|
63
|
+
|
64
|
+
messages.concat(verifier.call(model, context))
|
65
|
+
end
|
47
66
|
end
|
48
67
|
|
49
68
|
# @return [Array(ApplicatorWithOptions)]
|
@@ -53,8 +72,8 @@ module Verifly
|
|
53
72
|
end
|
54
73
|
|
55
74
|
# @param model generic model to validate
|
56
|
-
# @param context context in which it
|
57
|
-
# @return [Array] list of messages yielded by verifier
|
75
|
+
# @param context context in which it is valdiated
|
76
|
+
# @return [Array] list of messages yielded by the verifier
|
58
77
|
def self.call(model, context = {})
|
59
78
|
new(model).verify!(context)
|
60
79
|
end
|
@@ -65,8 +84,8 @@ module Verifly
|
|
65
84
|
self.messages = []
|
66
85
|
end
|
67
86
|
|
68
|
-
# @param context context in which model
|
69
|
-
# @return [Array] list of messages yielded by verifier
|
87
|
+
# @param context context in which model is valdiated
|
88
|
+
# @return [Array] list of messages yielded by the verifier
|
70
89
|
def verify!(context = {})
|
71
90
|
self.messages = []
|
72
91
|
|
@@ -80,7 +99,8 @@ module Verifly
|
|
80
99
|
private
|
81
100
|
|
82
101
|
# @abstract
|
83
|
-
#
|
102
|
+
# implementation example:
|
103
|
+
# `super { Message.new(status, text, description) }`
|
84
104
|
# @return new message (yield result)
|
85
105
|
def message!(*)
|
86
106
|
new_message = yield
|
data/lib/verifly/version.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
module Verifly
|
4
4
|
# Specifies Verifly version
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# * 0
|
8
|
-
# * a
|
9
|
-
# * b
|
10
|
-
# * c
|
11
|
-
VERSION = '0.
|
6
|
+
# Semantic versioning: 0.a.b.c where
|
7
|
+
# * 0 stands for unreleased
|
8
|
+
# * a stands for public api changes
|
9
|
+
# * b stands for private api changes
|
10
|
+
# * c stands for patch changes (not touching public or private api)
|
11
|
+
VERSION = '0.2.0.0'
|
12
12
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: verifly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Smirnov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.10'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '0.10'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,7 +150,7 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '1.1'
|
153
|
-
description: ''
|
153
|
+
description: 'See more info at http://www.rubydoc.info/gems/verifly/0.2.0.0 '
|
154
154
|
email:
|
155
155
|
- begdory4@gmail.com
|
156
156
|
executables: []
|
@@ -162,10 +162,10 @@ files:
|
|
162
162
|
- lib/verifly/applicator_with_options.rb
|
163
163
|
- lib/verifly/class_builder.rb
|
164
164
|
- lib/verifly/verifier.rb
|
165
|
-
- lib/verifly/verifier/applicator_with_options_builder.rb
|
166
165
|
- lib/verifly/version.rb
|
167
|
-
homepage:
|
168
|
-
licenses:
|
166
|
+
homepage: https://github.com/umbrellio/verifly
|
167
|
+
licenses:
|
168
|
+
- MIT
|
169
169
|
metadata: {}
|
170
170
|
post_install_message:
|
171
171
|
rdoc_options: []
|
@@ -173,9 +173,9 @@ require_paths:
|
|
173
173
|
- lib
|
174
174
|
required_ruby_version: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
|
-
- - "
|
176
|
+
- - "~>"
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: '
|
178
|
+
version: '2.3'
|
179
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
180
|
requirements:
|
181
181
|
- - ">="
|
@@ -186,5 +186,6 @@ rubyforge_project:
|
|
186
186
|
rubygems_version: 2.5.2
|
187
187
|
signing_key:
|
188
188
|
specification_version: 4
|
189
|
-
summary: ''
|
189
|
+
summary: An api to run sequential checks like 'ActiveModel::Validations' do, but with
|
190
|
+
generic messages instead of errors
|
190
191
|
test_files: []
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Verifly
|
4
|
-
class Verifier
|
5
|
-
# Builds ApplicatorWithOptions from different invocation styles.
|
6
|
-
# @api private
|
7
|
-
# @attr base [Class]
|
8
|
-
# class for which applicator_with_options should be built
|
9
|
-
# @attr args [Array]
|
10
|
-
# array of arguments Verifier.verify invoked with
|
11
|
-
# @attr block [Proc]
|
12
|
-
# block Verifier.verify invoked with
|
13
|
-
ApplicatorWithOptionsBuilder = Struct.new(:base, :args, :block)
|
14
|
-
class ApplicatorWithOptionsBuilder
|
15
|
-
# @!method self.call(base)
|
16
|
-
# transforms `verify` arguments to class attributes
|
17
|
-
# and invokes calculation
|
18
|
-
# @raise [ArgumentError]
|
19
|
-
# @return [ApplicatorWithOptions] resulting applicator_with_options
|
20
|
-
def self.call(base, *args, &block)
|
21
|
-
new(base, args, block).call
|
22
|
-
end
|
23
|
-
|
24
|
-
# Tries different invocation styles until one matches
|
25
|
-
# @see #try_block
|
26
|
-
# @see #try_nesting
|
27
|
-
# @see #default
|
28
|
-
# @raise [ArgumentError]
|
29
|
-
# @return [ApplicatorWithOptions] resulting applicator_with_options
|
30
|
-
def call
|
31
|
-
try_block || try_nesting || default
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
# @example with options
|
37
|
-
# verify(if: true) { ... }
|
38
|
-
# @example without options
|
39
|
-
# verify { ... }
|
40
|
-
# @return [ApplicatorWithOptions]
|
41
|
-
def try_block
|
42
|
-
ApplicatorWithOptions.new(block, *args) if block
|
43
|
-
end
|
44
|
-
|
45
|
-
# @example correct
|
46
|
-
# verify SubVerifier
|
47
|
-
# @example incorrect
|
48
|
-
# verify Class
|
49
|
-
# @raise [ArgumentError]
|
50
|
-
# @return [ApplicatorWithOptions]
|
51
|
-
def try_nesting
|
52
|
-
verifier, *rest = args
|
53
|
-
return unless verifier.is_a?(Class)
|
54
|
-
raise ArgumentError, <<~ERROR unless verifier < base
|
55
|
-
Nested verifiers should be inherited from verifier they nested are in
|
56
|
-
ERROR
|
57
|
-
|
58
|
-
applicable = lambda do |context|
|
59
|
-
messages.concat(verifier.call(model, context))
|
60
|
-
end
|
61
|
-
|
62
|
-
ApplicatorWithOptions.new(applicable, *rest)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Simply passes args to ApplicatorWithOptions
|
66
|
-
# @example
|
67
|
-
# verify(:foo, unless: false)
|
68
|
-
# @return [ApplicatorWithOptions]
|
69
|
-
def default
|
70
|
-
ApplicatorWithOptions.new(*args)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|