sevencop 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed778fc5bb1459cd5c3c35812b5274177e48515b434b2581c897f40ae6d47448
4
- data.tar.gz: 179393f59351517e7d510cdf5a1a4c0762d2b2f64186f0f8470017125ae42d77
3
+ metadata.gz: 5b95d5ba5dafb534e8e3a9e5c49bd9724db92840e1ca00543251c48a6b0f74f5
4
+ data.tar.gz: c6f7822017c94416417238387b5e16b76b00e401a8819a27c0d6df40ac1373c2
5
5
  SHA512:
6
- metadata.gz: cc12be9dc75e7507094a9349560ce08f8e9d5e61755837d2747fd101763b51885383b4d4f3416571303ea9e8e593ed0dc99cc6581206c248a82a41c5ce53a874
7
- data.tar.gz: 96286dac7849f571eac18cfde45e76b81044f0381246943082f003abab28109b9f1b19c9127e013a260d1deb7654b6e67a03133714caa9d86b02dc6830645660
6
+ metadata.gz: 131bb0495d50ebd37c0c03aa81b22d79d3488d8428697cd3af4263342f884b1857363920c40fa6794ba99e1de3e118bf94cf205cee96cc0aad77525f040072ee
7
+ data.tar.gz: f49be306dde9d6fda9db8d79a653c7814a4b43059265ceaf42fb4bbad2eee61fe112cb0ad56cdb152f626c26da9b54302f89f51f98652aa5ef37574ffcb06d45
data/.rubocop.yml CHANGED
@@ -3,6 +3,7 @@ require:
3
3
  - rubocop-performance
4
4
  - rubocop-rake
5
5
  - rubocop-rspec
6
+ - sevencop
6
7
 
7
8
  AllCops:
8
9
  NewCops: enable
@@ -25,5 +26,11 @@ RSpec/ExampleLength:
25
26
  RSpec/MultipleExpectations:
26
27
  Enabled: false
27
28
 
29
+ Sevencop/MethodDefinitionOrdered:
30
+ Enabled: true
31
+
28
32
  Style/Documentation:
29
33
  Enabled: false
34
+
35
+ Style/MultilineBlockChain:
36
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sevencop (0.13.0)
4
+ sevencop (0.14.0)
5
5
  rubocop
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # sevencop
2
2
 
3
3
  [![test](https://github.com/r7kamura/sevencop/actions/workflows/test.yml/badge.svg)](https://github.com/r7kamura/sevencop/actions/workflows/test.yml)
4
- [![Gem Version](https://badge.fury.io/rb/sevencop.svg)](https://rubygems.org/gems/sevencop)
5
4
 
6
5
  Custom cops for [RuboCop](https://github.com/rubocop/rubocop).
7
6
 
@@ -45,174 +44,16 @@ Sevencop/BelongsToOptional:
45
44
 
46
45
  ## Cops
47
46
 
48
- All cops are `Enabled: false` by default.
47
+ See YARD comments in each cop class for details:
49
48
 
50
- ### Sevencop/AutoloadOrdered
49
+ - [Sevencop/BelongsToOptional](lib/rubocop/cop/sevencop/belongs_to_optional.rb)
50
+ - [Sevencop/HashElementOrdered](lib/rubocop/cop/sevencop/hash_element_ordered.rb)
51
+ - [Sevencop/InferredSpecType](lib/rubocop/cop/sevencop/inferred_spec_type.rb)
52
+ - [Sevencop/MethodDefinitionArgumentsMultiline](lib/rubocop/cop/sevencop/method_definition_arguments_multiline.rb)
53
+ - [Sevencop/MethodDefinitionKeywordArgumentsOrdered](lib/rubocop/cop/sevencop/method_definition_keyword_arguments_ordered.rb)
54
+ - [Sevencop/MethodDefinitionOrdered](lib/rubocop/cop/sevencop/method_definition_ordered.rb)
55
+ - [Sevencop/OrderField](lib/rubocop/cop/sevencop/order_field.rb)
56
+ - [Sevencop/UniquenessValidatorExplicitCaseSensitivity](lib/rubocop/cop/sevencop/uniqueness_validator_explicit_case_sensitivity.rb)
57
+ - [Sevencop/WhereNot](lib/rubocop/cop/sevencop/where_not.rb)
51
58
 
52
- Sort `autoload` in alphabetical order within their section.
53
-
54
- ```ruby
55
- # bad
56
- autoload :B, 'b'
57
- autoload :A, 'a'
58
-
59
- # good
60
- autoload :A, 'a'
61
- autoload :B, 'b'
62
-
63
- # good
64
- autoload :B, 'b'
65
- autoload :D, 'd'
66
-
67
- autoload :A, 'a'
68
- autoload :C, 'a'
69
- ```
70
-
71
- ### Sevencop/BelongsToOptional
72
-
73
- Force `belongs_to` with `optional: true` option.
74
-
75
- ```ruby
76
- # bad
77
- belongs_to :group
78
-
79
- # good
80
- belongs_to :group, optional: true
81
-
82
- # good
83
- belongs_to :group, optional: false
84
-
85
- # good
86
- belongs_to :group, options
87
- ```
88
-
89
- This is useful for migration of `config.active_record.belongs_to_required_by_default`.
90
-
91
- ### Sevencop/HashLiteralOrder
92
-
93
- Sort Hash literal entries by key.
94
-
95
- ```ruby
96
- # bad
97
- {
98
- b: 1,
99
- a: 1,
100
- c: 1
101
- }
102
-
103
- # good
104
- {
105
- a: 1,
106
- b: 1,
107
- c: 1
108
- }
109
- ```
110
-
111
- ### Sevencop/InferredSpecType
112
-
113
- Identifies redundant spec type.
114
-
115
- ```ruby
116
- # bad
117
- # spec/models/user_spec.rb
118
- RSpec.describe User, type: :model
119
-
120
- # good
121
- # spec/models/user_spec.rb
122
- RSpec.describe User
123
-
124
- # good
125
- # spec/models/user_spec.rb
126
- RSpec.describe User, type: :request
127
- ```
128
-
129
- ### Sevencop/MethodDefinitionKeywordArgumentsOrdered
130
-
131
- Sort method definition keyword arguments in alphabetical order.
132
-
133
- ```ruby
134
- # bad
135
- def foo(b:, a:); end
136
-
137
- # good
138
- def foo(a:, b:); end
139
-
140
- # bad
141
- def foo(c:, d:, b: 1, a: 2); end
142
-
143
- # good
144
- def foo(c:, d:, a: 2, b: 1); end
145
- ```
146
-
147
- ### Sevencop/MethodDefinitionMultilineArguments
148
-
149
- Inserts new lines between method definition parameters.
150
-
151
- ```ruby
152
- # bad
153
- def foo(a, b)
154
- end
155
-
156
- # good
157
- def foo(
158
- a,
159
- b
160
- )
161
-
162
- # good
163
- def foo(a)
164
- end
165
- ```
166
-
167
- ### Sevencop/OrderField
168
-
169
- Identifies a String including "field" is passed to `order` or `reorder`.
170
-
171
- ```ruby
172
- # bad
173
- articles.order('field(id, ?)', a)
174
-
175
- # good
176
- articles.order(Arel.sql('field(id, ?)'), a)
177
-
178
- # bad
179
- reorder('field(id, ?)', a)
180
-
181
- # good
182
- reorder(Arel.sql('field(id, ?)'), a)
183
- ```
184
-
185
- ### Sevencop/UniquenessValidatorExplicitCaseSensitivity
186
-
187
- Identifies use of UniquenessValidator without :case_sensitive option.
188
-
189
- ```ruby
190
- # bad
191
- validates :name, uniqueness: true
192
-
193
- # good
194
- validates :name, uniqueness: { case_sensitive: true }
195
-
196
- # good
197
- validates :name, uniqueness: { case_sensitive: false }
198
-
199
- # bad
200
- validates :name, uniqueness: { allow_nil: true, scope: :user_id }
201
-
202
- # good
203
- validates :name, uniqueness: { allow_nil: true, scope: :user_id, case_sensitive: true }
204
- ```
205
-
206
- Useful to keep the same behavior between Rails 6.0 and 6.1 where case insensitive collation is used in MySQL.
207
-
208
- ### Sevencop/WhereNot
209
-
210
- Identifies passing multi-elements Hash literal to `where.not`.
211
-
212
- ```ruby
213
- # bad
214
- where.not(key1: value1, key2: value2)
215
-
216
- # good
217
- where.not(key1: value1).where.not(key2: value2)
218
- ```
59
+ Note that all cops are `Enabled: false` by default.
data/config/default.yml CHANGED
@@ -11,9 +11,9 @@ Sevencop/BelongsToOptional:
11
11
  Safe: false
12
12
  VersionAdded: '0.5'
13
13
 
14
- Sevencop/HashLiteralOrder:
14
+ Sevencop/HashElementOrdered:
15
15
  Description: |
16
- Sort Hash literal entries by key.
16
+ Sort Hash elements by key.
17
17
  Enabled: false
18
18
  VersionAdded: '0.6'
19
19
 
@@ -23,31 +23,30 @@ Sevencop/InferredSpecType:
23
23
  Enabled: false
24
24
  VersionAdded: '0.9'
25
25
 
26
- Sevencop/MethodDefinitionKeywordArgumentsOrdered:
26
+ Sevencop/MethodDefinitionArgumentsMultiline:
27
27
  Description: |
28
- Sort method definition keyword arguments in alphabetical order.
28
+ Inserts new lines between method definition arguments.
29
29
  Enabled: false
30
- VersionAdded: '0.13'
30
+ VersionAdded: '0.11'
31
31
 
32
- Sevencop/MethodDefinitionMultilineArguments:
32
+ Sevencop/MethodDefinitionOrdered:
33
33
  Description: |
34
- Inserts new lines between method definition parameters.
34
+ Sort method definitions in alphabetical order.
35
35
  Enabled: false
36
- VersionAdded: '0.11'
36
+ VersionAdded: '0.14'
37
37
 
38
- Sevencop/OrderField:
38
+ Sevencop/MethodDefinitionKeywordArgumentsOrdered:
39
39
  Description: |
40
- Wrap safe SQL String by `Arel.sql`.
40
+ Sort method definition keyword arguments in alphabetical order.
41
41
  Enabled: false
42
- Safe: false
43
- VersionAdded: '0.4'
42
+ VersionAdded: '0.13'
44
43
 
45
- Sevencop/ToSWithArgument:
44
+ Sevencop/OrderField:
46
45
  Description: |
47
- Identifies passing any argument to `#to_s`.
46
+ Wrap safe SQL String by `Arel.sql`.
48
47
  Enabled: false
49
48
  Safe: false
50
- VersionAdded: '0.8'
49
+ VersionAdded: '0.4'
51
50
 
52
51
  Sevencop/UniquenessValidatorExplicitCaseSensitivity:
53
52
  Description: |
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Sevencop
6
- # Sort `autoload` in alphabetical order within their section.
6
+ # Sort `autoload` in alphabetical order.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -25,7 +25,7 @@ module RuboCop
25
25
 
26
26
  include RangeHelp
27
27
 
28
- MSG = 'Sort `autoload` in alphabetical order within their section.'
28
+ MSG = 'Sort `autoload` in alphabetical order.'
29
29
 
30
30
  RESTRICT_ON_SEND = %i[
31
31
  autoload
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Sevencop
6
- # Sort Hash literal entries by key.
6
+ # Sort Hash elements by key.
7
7
  #
8
8
  # @example
9
9
  #
@@ -21,10 +21,10 @@ module RuboCop
21
21
  # c: 1
22
22
  # }
23
23
  #
24
- class HashLiteralOrder < Base
24
+ class HashElementOrdered < Base
25
25
  extend AutoCorrector
26
26
 
27
- MSG = 'Sort Hash literal entries by key.'
27
+ MSG = 'Sort Hash elements by key.'
28
28
 
29
29
  # @!method hash_literal?(node)
30
30
  def_node_matcher :hash_literal?, <<~PATTERN
@@ -64,6 +64,16 @@ module RuboCop
64
64
  parts.join
65
65
  end
66
66
 
67
+ # @param [RuboCop::AST::HashNode] node
68
+ # @return [Integer]
69
+ def offset_for(node)
70
+ if node.braces?
71
+ 1
72
+ else
73
+ 0
74
+ end
75
+ end
76
+
67
77
  # @param [Array<RuboCop::AST::PairNode>] pairs
68
78
  # @return [Array<RuboCop::AST::PairNode>]
69
79
  def sort(pairs)
@@ -95,32 +105,22 @@ module RuboCop
95
105
  # @param [RuboCop::AST::HashNode] node
96
106
  # @return [String]
97
107
  # { a: 1, b: 1 }
98
- # ^^
99
- def whitespace_trailing(node)
108
+ # ^^^^
109
+ def whitespace_leading(node)
100
110
  processed_source.raw_source[
101
- node.pairs[-1].location.expression.end_pos...node.location.expression.end.begin_pos - offset_for(node)
111
+ node.location.expression.begin.end_pos + offset_for(node)...node.pairs[0].location.expression.begin_pos
102
112
  ]
103
113
  end
104
114
 
105
115
  # @param [RuboCop::AST::HashNode] node
106
116
  # @return [String]
107
117
  # { a: 1, b: 1 }
108
- # ^^^^
109
- def whitespace_leading(node)
118
+ # ^^
119
+ def whitespace_trailing(node)
110
120
  processed_source.raw_source[
111
- node.location.expression.begin.end_pos + offset_for(node)...node.pairs[0].location.expression.begin_pos
121
+ node.pairs[-1].location.expression.end_pos...node.location.expression.end.begin_pos - offset_for(node)
112
122
  ]
113
123
  end
114
-
115
- # @param [RuboCop::AST::HashNode] node
116
- # @return [Integer]
117
- def offset_for(node)
118
- if node.braces?
119
- 1
120
- else
121
- 0
122
- end
123
- end
124
124
  end
125
125
  end
126
126
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Sevencop
6
- # Inserts new lines between method definition parameters.
6
+ # Inserts new lines between method definition arguments.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -19,10 +19,10 @@ module RuboCop
19
19
  # # good
20
20
  # def foo(a)
21
21
  # end
22
- class MethodDefinitionMultilineArguments < Base
22
+ class MethodDefinitionArgumentsMultiline < Base
23
23
  extend AutoCorrector
24
24
 
25
- MSG = 'Insert new lines between method definition parameters.'
25
+ MSG = 'Insert new lines between method definition arguments.'
26
26
 
27
27
  # @param node [RuboCop::AST::ArgsNode]
28
28
  def on_args(node)
@@ -54,6 +54,11 @@ module RuboCop
54
54
  )
55
55
  end
56
56
 
57
+ # @return [Boolean]
58
+ def method_args?(node)
59
+ !node.parent.nil? && node.parent.def_type?
60
+ end
61
+
57
62
  # @param node [RuboCop::AST::ArgsNode]
58
63
  # @return [Boolean]
59
64
  def multilined?(node)
@@ -61,11 +66,6 @@ module RuboCop
61
66
  child.location.expression.line
62
67
  end.uniq.length == node.children.length
63
68
  end
64
-
65
- # @return [Boolean]
66
- def method_args?(node)
67
- !node.parent.nil? && node.parent.def_type?
68
- end
69
69
  end
70
70
  end
71
71
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sevencop
6
+ # Sort method definition in alphabetical order.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # def b; end
11
+ # def a; end
12
+ #
13
+ # # good
14
+ # def a; end
15
+ # def b; end
16
+ #
17
+ # # good
18
+ # def b; end
19
+ # def c; end
20
+ # private
21
+ # def a; end
22
+ # def d; end
23
+ #
24
+ # # good
25
+ # def initialize; end
26
+ # def a; end
27
+ class MethodDefinitionOrdered < Base
28
+ extend AutoCorrector
29
+
30
+ include RangeHelp
31
+ include VisibilityHelp
32
+
33
+ MSG = 'Sort method definition in alphabetical order.'
34
+
35
+ # @param node [RuboCop::AST::DefNode]
36
+ def on_def(node)
37
+ previous_older_sibling = find_previous_older_sibling(node)
38
+ return unless previous_older_sibling
39
+
40
+ add_offense(node) do |corrector|
41
+ swap(
42
+ range_by_whole_lines(
43
+ range_with_comments(previous_older_sibling),
44
+ include_final_newline: true
45
+ ),
46
+ range_by_whole_lines(
47
+ range_with_comments(node),
48
+ include_final_newline: true
49
+ ),
50
+ corrector: corrector
51
+ )
52
+ end
53
+ end
54
+ alias on_defs on_def
55
+
56
+ private
57
+
58
+ # @param node [RuboCop::AST::DefNode]
59
+ # @return [RuboCop::AST::DefNode]
60
+ def find_previous_older_sibling(node)
61
+ previous_siblings_in_same_section_of(node).find do |sibling|
62
+ next if sibling.type != node.type
63
+
64
+ (sort_key_of(sibling) <=> sort_key_of(node)) == 1
65
+ end
66
+ end
67
+
68
+ # @param node [RuboCop::AST::Node]
69
+ # @return [Array<RuboCop::AST::Node>]
70
+ def previous_siblings_in_same_section_of(node)
71
+ return node.left_siblings if node.defs_type?
72
+
73
+ node.left_siblings.reverse.take_while do |sibling|
74
+ !visibility_block?(sibling)
75
+ end.reverse
76
+ end
77
+
78
+ # @param node [RuboCop::AST::Node]
79
+ # @return [Paresr::Source::Range]
80
+ def range_with_comments(node)
81
+ comment = processed_source.ast_with_comments[node].first
82
+ if comment
83
+ node.location.expression.with(begin_pos: comment.location.expression.begin_pos)
84
+ else
85
+ node.location.expression
86
+ end
87
+ end
88
+
89
+ # @param node [RuboCop::AST::DefNode]
90
+ # @return [#<=>]
91
+ def sort_key_of(node)
92
+ [
93
+ node.method?(:initialize) ? 0 : 1,
94
+ node.method_name
95
+ ]
96
+ end
97
+
98
+ # @param range1 [Paresr::Source::Range]
99
+ # @param range2 [Paresr::Source::Range]
100
+ # @param corrector [RuboCop::AST::Corrector]
101
+ def swap(range1, range2, corrector:)
102
+ corrector.insert_before(
103
+ range1,
104
+ "#{range2.source}\n"
105
+ )
106
+ corrector.remove(range2)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -65,6 +65,11 @@ module RuboCop
65
65
  )
66
66
  PATTERN
67
67
 
68
+ # @param [RuboCop::AST::SendNode] node
69
+ def find_uniqueness_value(node)
70
+ node.arguments[1].pairs.find { |pair| pair.key.value == :uniqueness }.value
71
+ end
72
+
68
73
  # @param [RuboCop::AST::SendNode] node
69
74
  def on_send(node)
70
75
  return unless validates_uniqueness?(node) && !validates_uniqueness_with_case_sensitivity?(node)
@@ -84,11 +89,6 @@ module RuboCop
84
89
  end
85
90
  end
86
91
  end
87
-
88
- # @param [RuboCop::AST::SendNode] node
89
- def find_uniqueness_value(node)
90
- node.arguments[1].pairs.find { |pair| pair.key.value == :uniqueness }.value
91
- end
92
92
  end
93
93
  end
94
94
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sevencop
4
- VERSION = '0.13.0'
4
+ VERSION = '0.14.0'
5
5
  end
data/lib/sevencop.rb CHANGED
@@ -5,11 +5,11 @@ require_relative 'sevencop/version'
5
5
 
6
6
  require_relative 'rubocop/cop/sevencop/autoload_ordered'
7
7
  require_relative 'rubocop/cop/sevencop/belongs_to_optional'
8
- require_relative 'rubocop/cop/sevencop/hash_literal_order'
8
+ require_relative 'rubocop/cop/sevencop/hash_element_ordered'
9
9
  require_relative 'rubocop/cop/sevencop/inferred_spec_type'
10
+ require_relative 'rubocop/cop/sevencop/method_definition_arguments_multiline'
10
11
  require_relative 'rubocop/cop/sevencop/method_definition_keyword_arguments_ordered'
11
- require_relative 'rubocop/cop/sevencop/method_definition_multiline_arguments'
12
+ require_relative 'rubocop/cop/sevencop/method_definition_ordered'
12
13
  require_relative 'rubocop/cop/sevencop/order_field'
13
- require_relative 'rubocop/cop/sevencop/to_s_with_argument'
14
14
  require_relative 'rubocop/cop/sevencop/uniqueness_validator_explicit_case_sensitivity'
15
15
  require_relative 'rubocop/cop/sevencop/where_not'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sevencop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-24 00:00:00.000000000 Z
11
+ date: 2022-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -43,12 +43,12 @@ files:
43
43
  - config/default.yml
44
44
  - lib/rubocop/cop/sevencop/autoload_ordered.rb
45
45
  - lib/rubocop/cop/sevencop/belongs_to_optional.rb
46
- - lib/rubocop/cop/sevencop/hash_literal_order.rb
46
+ - lib/rubocop/cop/sevencop/hash_element_ordered.rb
47
47
  - lib/rubocop/cop/sevencop/inferred_spec_type.rb
48
+ - lib/rubocop/cop/sevencop/method_definition_arguments_multiline.rb
48
49
  - lib/rubocop/cop/sevencop/method_definition_keyword_arguments_ordered.rb
49
- - lib/rubocop/cop/sevencop/method_definition_multiline_arguments.rb
50
+ - lib/rubocop/cop/sevencop/method_definition_ordered.rb
50
51
  - lib/rubocop/cop/sevencop/order_field.rb
51
- - lib/rubocop/cop/sevencop/to_s_with_argument.rb
52
52
  - lib/rubocop/cop/sevencop/uniqueness_validator_explicit_case_sensitivity.rb
53
53
  - lib/rubocop/cop/sevencop/where_not.rb
54
54
  - lib/sevencop.rb
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Sevencop
6
- # Identifies passing any argument to `#to_s`.
7
- #
8
- # @example
9
- #
10
- # # bad
11
- # to_s(:delimited)
12
- #
13
- # # good
14
- # to_formatted_s(:delimited)
15
- #
16
- class ToSWithArgument < Base
17
- extend AutoCorrector
18
-
19
- MSG = 'Use `to_formatted_s(...)` instead of `to_s(...)`.'
20
-
21
- RESTRICT_ON_SEND = %i[to_s].freeze
22
-
23
- # @!method to_s_with_any_argument?(node)
24
- def_node_matcher :to_s_with_any_argument?, <<~PATTERN
25
- (call _ :to_s _+)
26
- PATTERN
27
-
28
- def on_send(node)
29
- return unless to_s_with_any_argument?(node)
30
-
31
- add_offense(node) do |rewriter|
32
- rewriter.replace(
33
- node.loc.selector,
34
- 'to_formatted_s'
35
- )
36
- end
37
- end
38
- alias on_csend on_send
39
- end
40
- end
41
- end
42
- end