rubocop 0.36.0 → 0.37.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -2
  3. data/README.md +10 -1
  4. data/assets/output.html.erb +55 -1
  5. data/config/default.yml +9 -3
  6. data/config/disabled.yml +21 -0
  7. data/config/enabled.yml +11 -10
  8. data/lib/rubocop.rb +9 -2
  9. data/lib/rubocop/ast_node.rb +67 -19
  10. data/lib/rubocop/ast_node/builder.rb +1 -0
  11. data/lib/rubocop/ast_node/sexp.rb +1 -0
  12. data/lib/rubocop/ast_node/traversal.rb +171 -0
  13. data/lib/rubocop/cached_data.rb +4 -1
  14. data/lib/rubocop/cli.rb +1 -1
  15. data/lib/rubocop/config.rb +36 -20
  16. data/lib/rubocop/config_loader.rb +6 -5
  17. data/lib/rubocop/cop/commissioner.rb +27 -18
  18. data/lib/rubocop/cop/cop.rb +7 -6
  19. data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
  20. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  21. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  22. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  23. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  24. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
  25. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
  26. data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
  27. data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
  28. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
  29. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  30. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
  31. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
  32. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  33. data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
  34. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
  35. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  37. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
  38. data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
  39. data/lib/rubocop/cop/performance/casecmp.rb +56 -17
  40. data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
  41. data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
  42. data/lib/rubocop/cop/performance/times_map.rb +3 -4
  43. data/lib/rubocop/cop/severity.rb +1 -1
  44. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  45. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/and_or.rb +1 -1
  47. data/lib/rubocop/cop/style/block_comments.rb +2 -0
  48. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
  49. data/lib/rubocop/cop/style/copyright.rb +2 -2
  50. data/lib/rubocop/cop/style/documentation.rb +19 -29
  51. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  52. data/lib/rubocop/cop/style/else_alignment.rb +2 -2
  53. data/lib/rubocop/cop/style/encoding.rb +1 -1
  54. data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
  55. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
  56. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  57. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
  58. data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
  59. data/lib/rubocop/cop/style/indentation_width.rb +3 -7
  60. data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
  61. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  62. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
  63. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
  64. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
  65. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
  66. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
  67. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
  68. data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
  69. data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
  70. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
  71. data/lib/rubocop/cop/style/next.rb +32 -11
  72. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  73. data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
  74. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
  75. data/lib/rubocop/cop/style/send.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
  77. data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
  78. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  79. data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
  80. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  81. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  82. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
  83. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
  84. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  85. data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
  86. data/lib/rubocop/cop/team.rb +30 -5
  87. data/lib/rubocop/cop/util.rb +16 -1
  88. data/lib/rubocop/cop/variable_force.rb +3 -12
  89. data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
  90. data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
  91. data/lib/rubocop/cop/variable_force/reference.rb +3 -3
  92. data/lib/rubocop/cop/variable_force/scope.rb +8 -7
  93. data/lib/rubocop/cop/variable_force/variable.rb +3 -3
  94. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  95. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  96. data/lib/rubocop/node_pattern.rb +1 -1
  97. data/lib/rubocop/options.rb +10 -10
  98. data/lib/rubocop/path_util.rb +5 -0
  99. data/lib/rubocop/processed_source.rb +8 -2
  100. data/lib/rubocop/result_cache.rb +1 -1
  101. data/lib/rubocop/runner.rb +1 -1
  102. data/lib/rubocop/token.rb +2 -2
  103. data/lib/rubocop/version.rb +1 -1
  104. data/relnotes/v0.30.1.md +1 -0
  105. data/relnotes/v0.33.0.md +1 -1
  106. data/relnotes/v0.36.0.md +2 -1
  107. data/relnotes/v0.37.0.md +200 -0
  108. data/rubocop.gemspec +2 -1
  109. metadata +28 -7
  110. data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
  111. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -11,7 +11,7 @@ module RuboCop
11
11
 
12
12
  def on_send(node)
13
13
  _receiver, method_name, *args = *node
14
- return unless method_name == :send && args.length > 0
14
+ return unless method_name == :send && !args.empty?
15
15
  add_offense(node, :selector)
16
16
  end
17
17
  end
@@ -0,0 +1,198 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # Checks the spacing around the keywords.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # something 'test'do|x|
13
+ # end
14
+ #
15
+ # while(something)
16
+ # end
17
+ #
18
+ # something = 123if test
19
+ #
20
+ # # good
21
+ # something 'test' do |x|
22
+ # end
23
+ #
24
+ # while (something)
25
+ # end
26
+ #
27
+ # something = 123 if test
28
+ class SpaceAroundKeyword < Cop
29
+ MSG_BEFORE = 'Space before keyword `%s` is missing.'.freeze
30
+ MSG_AFTER = 'Space after keyword `%s` is missing.'.freeze
31
+
32
+ DO = 'do'.freeze
33
+ ACCEPT_LEFT_PAREN = %w(break next not return super yield).freeze
34
+
35
+ def on_and(node)
36
+ check(node, [:operator].freeze) if node.keyword?
37
+ end
38
+
39
+ def on_block(node)
40
+ check(node, [:begin, :end].freeze)
41
+ end
42
+
43
+ def on_break(node)
44
+ check(node, [:keyword].freeze)
45
+ end
46
+
47
+ def on_case(node)
48
+ check(node, [:keyword, :else].freeze)
49
+ end
50
+
51
+ def on_ensure(node)
52
+ check(node, [:keyword].freeze)
53
+ end
54
+
55
+ def on_for(node)
56
+ check(node, [:begin, :end].freeze)
57
+ end
58
+
59
+ def on_if(node)
60
+ check(node, [:keyword, :else, :begin, :end].freeze, 'then'.freeze)
61
+ end
62
+
63
+ def on_kwbegin(node)
64
+ check(node, [:begin, :end].freeze, nil)
65
+ end
66
+
67
+ def on_next(node)
68
+ check(node, [:keyword].freeze)
69
+ end
70
+
71
+ def on_or(node)
72
+ check(node, [:operator].freeze) if node.keyword?
73
+ end
74
+
75
+ def on_postexe(node)
76
+ check(node, [:keyword].freeze)
77
+ end
78
+
79
+ def on_preexe(node)
80
+ check(node, [:keyword].freeze)
81
+ end
82
+
83
+ def on_resbody(node)
84
+ check(node, [:keyword].freeze)
85
+ end
86
+
87
+ def on_rescue(node)
88
+ check(node, [:else].freeze)
89
+ end
90
+
91
+ def on_return(node)
92
+ check(node, [:keyword].freeze)
93
+ end
94
+
95
+ def on_send(node)
96
+ check(node, [:selector].freeze) if node.keyword_not?
97
+ end
98
+
99
+ def on_super(node)
100
+ check(node, [:keyword].freeze)
101
+ end
102
+
103
+ def on_until(node)
104
+ check(node, [:begin, :end, :keyword].freeze)
105
+ end
106
+
107
+ def on_when(node)
108
+ check(node, [:keyword].freeze)
109
+ end
110
+
111
+ def on_while(node)
112
+ check(node, [:begin, :end, :keyword].freeze)
113
+ end
114
+
115
+ def on_yield(node)
116
+ check(node, [:keyword].freeze)
117
+ end
118
+
119
+ private
120
+
121
+ def check(node, locations, begin_keyword = DO)
122
+ locations.each do |loc|
123
+ next unless node.loc.respond_to?(loc)
124
+ range = node.loc.public_send(loc)
125
+ next unless range
126
+
127
+ case loc
128
+ when :begin then check_begin(node, range, begin_keyword)
129
+ when :end then check_end(node, range, begin_keyword)
130
+ else check_keyword(node, range)
131
+ end
132
+ end
133
+ end
134
+
135
+ def check_begin(node, range, begin_keyword)
136
+ return if begin_keyword && !range.is?(begin_keyword)
137
+
138
+ check_keyword(node, range)
139
+ end
140
+
141
+ def check_end(node, range, begin_keyword)
142
+ return if begin_keyword == DO && !do?(node)
143
+
144
+ offense(range, MSG_BEFORE) if space_before_missing?(range)
145
+ end
146
+
147
+ def do?(node)
148
+ node.loc.begin && node.loc.begin.is?(DO)
149
+ end
150
+
151
+ def check_keyword(node, range)
152
+ offense(range, MSG_BEFORE) if space_before_missing?(range) &&
153
+ !preceded_by_operator?(node, range)
154
+ offense(range, MSG_AFTER) if space_after_missing?(range)
155
+ end
156
+
157
+ def offense(range, msg)
158
+ add_offense(range, range, msg % range.source)
159
+ end
160
+
161
+ def space_before_missing?(range)
162
+ pos = range.begin_pos - 1
163
+ return false if pos < 0
164
+ range.source_buffer.source[pos] !~ /[\s\(\|\{\[;,\*\=]/
165
+ end
166
+
167
+ def space_after_missing?(range)
168
+ pos = range.end_pos
169
+ char = range.source_buffer.source[pos]
170
+ return false unless range.source_buffer.source[pos]
171
+ return false if accept_left_parenthesis?(range) && char == '('.freeze
172
+
173
+ char !~ /[\s;,#\\\)\}\]]/
174
+ end
175
+
176
+ def accept_left_parenthesis?(range)
177
+ ACCEPT_LEFT_PAREN.include?(range.source)
178
+ end
179
+
180
+ def preceded_by_operator?(node, _range)
181
+ ancestor = node.ancestors.first
182
+ return false unless ancestor
183
+ return true if ancestor.and_type? || ancestor.or_type?
184
+ return false unless ancestor.send_type?
185
+ operator?(ancestor.loc.selector.source.to_sym)
186
+ end
187
+
188
+ def autocorrect(range)
189
+ if space_before_missing?(range)
190
+ ->(corrector) { corrector.insert_before(range, ' '.freeze) }
191
+ else
192
+ ->(corrector) { corrector.insert_after(range, ' '.freeze) }
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -39,9 +39,9 @@ module RuboCop
39
39
  def on_send(node)
40
40
  if node.loc.operator # aref assignment, attribute assignment
41
41
  on_special_asgn(node)
42
- elsif !unary_operation?(node) && !called_with_dot?(node)
42
+ elsif !node.unary_operation? && !called_with_dot?(node)
43
43
  op = node.loc.selector
44
- if operator?(op)
44
+ if operator?(op.source.to_sym)
45
45
  _, _, right, = *node
46
46
  check_operator(node.loc.selector, right.source_range)
47
47
  end
@@ -75,16 +75,6 @@ module RuboCop
75
75
 
76
76
  private
77
77
 
78
- def operator?(range)
79
- range.source !~ /^\[|\w/
80
- end
81
-
82
- def unary_operation?(node)
83
- return unless (selector = node.loc.selector)
84
- operator?(selector) &&
85
- node.source_range.begin_pos == selector.begin_pos
86
- end
87
-
88
78
  def called_with_dot?(node)
89
79
  node.loc.dot
90
80
  end
@@ -146,7 +146,7 @@ module RuboCop
146
146
  case cop_config['EnforcedStyleForEmptyBraces']
147
147
  when 'space' then :space
148
148
  when 'no_space' then :no_space
149
- else fail 'Unknown EnforcedStyleForEmptyBraces selected!'
149
+ else raise 'Unknown EnforcedStyleForEmptyBraces selected!'
150
150
  end
151
151
  end
152
152
 
@@ -82,14 +82,14 @@ module RuboCop
82
82
  regular_msg = regular.join('` or `')
83
83
  english_msg = english.join('` or `')
84
84
 
85
- if regular.length > 0 && english.length > 0
85
+ if !regular.empty? && !english.empty?
86
86
  format(MSG_BOTH, english_msg, regular_msg, global_var)
87
- elsif regular.length > 0
87
+ elsif !regular.empty?
88
88
  format(MSG_REGULAR, regular_msg, global_var)
89
- elsif english.length > 0
89
+ elsif !english.empty?
90
90
  format(MSG_ENGLISH, english_msg, global_var)
91
91
  else
92
- fail 'Bug in SpecialGlobalVars - global var w/o preferred vars!'
92
+ raise 'Bug in SpecialGlobalVars - global var w/o preferred vars!'
93
93
  end
94
94
  else
95
95
  format(MSG_REGULAR, preferred_names(global_var).first, global_var)
@@ -31,7 +31,7 @@ module RuboCop
31
31
 
32
32
  def validate_config
33
33
  if style == :percent && target_ruby_version < 2.0
34
- fail ValidationError, 'The default `percent` style for the ' \
34
+ raise ValidationError, 'The default `percent` style for the ' \
35
35
  '`Style/SymbolArray` cop is only compatible' \
36
36
  ' with Ruby 2.0 and up, but the target Ruby' \
37
37
  " version for your project is 1.9.\nPlease " \
@@ -36,7 +36,7 @@ module RuboCop
36
36
  begin_pos = sb.source.length - whitespace_at_end.length
37
37
  autocorrect_range = Parser::Source::Range.new(sb, begin_pos,
38
38
  sb.source.length)
39
- begin_pos += 1 unless whitespace_at_end.length == 0
39
+ begin_pos += 1 unless whitespace_at_end.empty?
40
40
  report_range = Parser::Source::Range.new(sb, begin_pos,
41
41
  sb.source.length)
42
42
  add_offense(autocorrect_range, report_range,
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -85,7 +85,7 @@ module RuboCop
85
85
  end
86
86
 
87
87
  def looks_like_trivial_reader?(args, body)
88
- args.children.size == 0 && body && body.type == :ivar
88
+ args.children.empty? && body && body.type == :ivar
89
89
  end
90
90
 
91
91
  def trivial_writer?(method_name, args, body)
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks for receiver.length == 0 predicates and the
8
+ # negated versions receiver.length > 0 and receiver.length != 0.
9
+ # These can be replaced with receiver.empty? and
10
+ # !receiver.empty? respectively.
11
+ #
12
+ # @example
13
+ #
14
+ # @bad
15
+ # [1, 2, 3].length == 0
16
+ # 0 == "foobar".length
17
+ # hash.size > 0
18
+ #
19
+ # @good
20
+ # [1, 2, 3].empty?
21
+ # "foobar".empty?
22
+ # !hash.empty?
23
+ class ZeroLengthPredicate < Cop
24
+ ZERO_MSG = 'Use `empty?` instead of `%s == 0`.'.freeze
25
+ NONZERO_MSG = 'Use `!empty?` instead of `%s %s %s`.'.freeze
26
+
27
+ def on_send(node)
28
+ zero_length_predicate = zero_length_predicate(node)
29
+
30
+ if zero_length_predicate
31
+ add_offense(node, :expression,
32
+ format(ZERO_MSG, *zero_length_predicate))
33
+ end
34
+
35
+ nonzero_length_predicate = nonzero_length_predicate(node)
36
+
37
+ if nonzero_length_predicate
38
+ add_offense(node, :expression,
39
+ format(NONZERO_MSG, *nonzero_length_predicate))
40
+ end
41
+ end
42
+
43
+ def_node_matcher :zero_length_predicate, <<-END
44
+ {(send (send _ ${:length :size}) :== (int 0))
45
+ (send (int 0) :== (send _ ${:length :size}))}
46
+ END
47
+
48
+ def_node_matcher :nonzero_length_predicate, <<-END
49
+ {(send (send _ ${:length :size}) ${:> :!=} (int $0))
50
+ (send (int $0) ${:< :!=} (send _ ${:length :size}))}
51
+ END
52
+ end
53
+ end
54
+ end
55
+ end
@@ -33,10 +33,31 @@ module RuboCop
33
33
  return Lint::Syntax.offenses_from_processed_source(processed_source)
34
34
  end
35
35
 
36
- commissioner = Commissioner.new(cops, forces)
37
- offenses = commissioner.investigate(processed_source)
38
- process_commissioner_errors(processed_source.path, commissioner.errors)
39
- autocorrect(processed_source.buffer, cops)
36
+ # The autocorrection process may have to be repeated multiple times
37
+ # until there are no corrections left to perform
38
+ # To speed things up, run auto-correcting cops by themselves, and only
39
+ # run the other cops when no corrections are left
40
+ autocorrect_cops, other_cops = cops.partition(&:autocorrect?)
41
+ offenses = []
42
+ errors = {}
43
+
44
+ if autocorrect_cops.any?
45
+ commissioner = Commissioner.new(autocorrect_cops,
46
+ forces_for(autocorrect_cops))
47
+ offenses = commissioner.investigate(processed_source)
48
+ if autocorrect(processed_source.buffer, autocorrect_cops)
49
+ # We corrected some errors. Another round of inspection will be
50
+ # done, and any other offenses will be caught then, so we don't
51
+ # need to continue.
52
+ return offenses
53
+ end
54
+ errors = commissioner.errors
55
+ end
56
+
57
+ commissioner = Commissioner.new(other_cops, forces_for(other_cops))
58
+ offenses.concat(commissioner.investigate(processed_source))
59
+ errors.merge!(commissioner.errors)
60
+ process_commissioner_errors(processed_source.path, errors)
40
61
  offenses
41
62
  end
42
63
 
@@ -47,7 +68,11 @@ module RuboCop
47
68
  end
48
69
 
49
70
  def forces
50
- @forces ||= Force.all.each_with_object([]) do |force_class, forces|
71
+ @forces ||= forces_for(cops)
72
+ end
73
+
74
+ def forces_for(cops)
75
+ Force.all.each_with_object([]) do |force_class, forces|
51
76
  joining_cops = cops.select { |cop| cop.join_force?(force_class) }
52
77
  next if joining_cops.empty?
53
78
  forces << force_class.new(joining_cops)
@@ -9,6 +9,8 @@ module RuboCop
9
9
  include PathUtil
10
10
  extend RuboCop::Sexp
11
11
 
12
+ BYTE_ORDER_MARK = 0xfeff # The Unicode codepoint
13
+
12
14
  EQUALS_ASGN_NODES = [:lvasgn, :ivasgn, :cvasgn, :gvasgn,
13
15
  :casgn, :masgn].freeze
14
16
  SHORTHAND_ASGN_NODES = [:op_asgn, :or_asgn, :and_asgn].freeze
@@ -71,7 +73,7 @@ module RuboCop
71
73
  when Parser::AST::Node
72
74
  arg.source_range
73
75
  else
74
- fail ArgumentError, "Invalid argument #{arg}"
76
+ raise ArgumentError, "Invalid argument #{arg}"
75
77
  end
76
78
 
77
79
  source_range.begin.line..source_range.end.line
@@ -114,6 +116,19 @@ module RuboCop
114
116
  Parser::Source::Range.new(source_buffer, begin_pos, end_pos)
115
117
  end
116
118
 
119
+ # Returns the column attribute of the range, except if the range is on
120
+ # the first line and there's a byte order mark at the beginning of that
121
+ # line, in which case 1 is subtracted from the column value. This gives
122
+ # the column as it appears when viewing the file in an editor.
123
+ def effective_column(range)
124
+ if range.line == 1 &&
125
+ @processed_source.raw_source.codepoints.first == BYTE_ORDER_MARK
126
+ range.column - 1
127
+ else
128
+ range.column
129
+ end
130
+ end
131
+
117
132
  def range_with_surrounding_comma(range, side = :both, buffer = nil)
118
133
  buffer ||= @processed_source.buffer
119
134
  src = buffer.source