Skip to content

Commit

Permalink
Add Sorbet's typed sigil as a magic comment
Browse files Browse the repository at this point in the history
  • Loading branch information
zachahn authored and bbatsov committed May 15, 2022
1 parent 3b9f468 commit 58c56bf
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#10620](https://github.com/rubocop/rubocop/pull/10620): Add Sorbet's `typed` sigil as a magic comment. ([@zachahn][])
29 changes: 27 additions & 2 deletions lib/rubocop/magic_comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class MagicComment
KEYWORDS = {
encoding: '(?:en)?coding',
frozen_string_literal: 'frozen[_-]string[_-]literal',
shareable_constant_value: 'shareable[_-]constant[_-]value'
shareable_constant_value: 'shareable[_-]constant[_-]value',
typed: 'typed'
}.freeze

# Detect magic comment format and pass it to the appropriate wrapper.
Expand All @@ -33,7 +34,10 @@ def initialize(comment)
end

def any?
frozen_string_literal_specified? || encoding_specified? || shareable_constant_value_specified?
frozen_string_literal_specified? ||
encoding_specified? ||
shareable_constant_value_specified? ||
typed_specified?
end

def valid?
Expand Down Expand Up @@ -101,6 +105,17 @@ def encoding_specified?
specified?(encoding)
end

# Was the Sorbet `typed` sigil specified?
#
# @return [Boolean]
def typed_specified?
specified?(extract_typed)
end

def typed
extract_typed
end

private

def specified?(value)
Expand Down Expand Up @@ -187,6 +202,9 @@ def extract_frozen_string_literal
def extract_shareable_constant_value
match(KEYWORDS[:shareable_constant_value])
end

# Emacs comments cannot specify Sorbet typechecking behavior.
def extract_typed; end
end

# Wrapper for Vim style magic comments.
Expand Down Expand Up @@ -222,6 +240,9 @@ def frozen_string_literal; end

# Vim comments cannot specify shareable constant values behavior.
def shareable_constant_value; end

# Vim comments cannot specify Sorbet typechecking behavior.
def extract_typed; end
end

# Wrapper for regular magic comments not bound to an editor.
Expand Down Expand Up @@ -268,6 +289,10 @@ def extract_frozen_string_literal
def extract_shareable_constant_value
extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*(#{TOKEN})\s*\z/io)
end

def extract_typed
extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*(#{TOKEN})\s*\z/io)
end
end
end
end
30 changes: 30 additions & 0 deletions spec/rubocop/cop/layout/empty_line_after_magic_comment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ class Foo; end
RUBY
end

it 'registers an offense when code that immediately follows typed comment' do
expect_offense(<<~RUBY)
# typed: true
class Foo; end
^ Add an empty line after magic comments.
RUBY

expect_correction(<<~RUBY)
# typed: true
class Foo; end
RUBY
end

it 'registers an offense for documentation immediately following comment' do
expect_offense(<<~RUBY)
# frozen_string_literal: true
Expand Down Expand Up @@ -72,6 +86,22 @@ class Foo; end
RUBY
end

it 'accepts magic comment with typed' do
expect_no_offenses(<<~RUBY)
# frozen_string_literal: true
# typed: true
class Foo; end
RUBY

expect_no_offenses(<<~RUBY)
# typed: true
# frozen_string_literal: true
class Foo; end
RUBY
end

it 'registers offense when frozen_string_literal used with shareable_constant_value without empty line' do
expect_offense(<<~RUBY)
# frozen_string_literal: true
Expand Down
30 changes: 27 additions & 3 deletions spec/rubocop/magic_comment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
encoding = expectations[:encoding]
frozen_string = expectations[:frozen_string_literal]
shareable_constant_value = expectations[:shareable_constant_value]
typed = expectations[:typed]

it "returns #{encoding.inspect} for encoding when comment is #{comment}" do
expect(described_class.parse(comment).encoding).to eql(encoding)
Expand All @@ -19,6 +20,10 @@
expect(described_class.parse(comment)
.shareable_constant_value).to eql(shareable_constant_value)
end

it "returns #{typed.inspect} for typed when comment is #{comment}" do
expect(described_class.parse(comment).typed).to eql(typed)
end
end

include_examples 'magic comment', '#'
Expand Down Expand Up @@ -69,6 +74,22 @@

include_examples 'magic comment', '# xyz shareable_constant_value: literal xyz'

include_examples 'magic comment', '# typed: ignore', typed: 'ignore'

include_examples 'magic comment', '# typed: false', typed: 'false'

include_examples 'magic comment', '# typed: true', typed: 'true'

include_examples 'magic comment', '# typed: strict', typed: 'strict'

include_examples 'magic comment', '# typed: strong', typed: 'strong'

include_examples 'magic comment', '#typed:strict', typed: 'strict'

include_examples 'magic comment', '# typed:strict', typed: 'strict'

include_examples 'magic comment', '# @typed'

include_examples(
'magic comment',
'# shareable_constant_value: experimental_everything',
Expand Down Expand Up @@ -125,9 +146,8 @@

include_examples(
'magic comment',
'# -*- coding: ASCII-8BIT; frozen_string_literal: true -*-',
encoding: 'ascii-8bit',
frozen_string_literal: true
'# -*- coding: ASCII-8BIT; typed: strict -*-',
encoding: 'ascii-8bit'
)

include_examples 'magic comment',
Expand All @@ -144,6 +164,10 @@
'#vim: filetype=ruby, fileencoding=ascii-8bit',
encoding: 'ascii-8bit'

include_examples 'magic comment',
'#vim: filetype=ruby, fileencoding=ascii-8bit, typed=strict',
encoding: 'ascii-8bit'

include_examples(
'magic comment',
'# coding: utf-8 vim: filetype=ruby, fileencoding=ascii-8bit',
Expand Down

0 comments on commit 58c56bf

Please sign in to comment.