yard-sorbet 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +9 -0
  3. data/.gitignore +40 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +47 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +10 -0
  8. data/Gemfile +14 -0
  9. data/LICENSE +201 -0
  10. data/README.md +17 -0
  11. data/Rakefile +11 -0
  12. data/lib/yard-sorbet.rb +12 -0
  13. data/lib/yard-sorbet/directives.rb +24 -0
  14. data/lib/yard-sorbet/sig_handler.rb +131 -0
  15. data/lib/yard-sorbet/sig_to_yard.rb +91 -0
  16. data/lib/yard-sorbet/struct_handler.rb +94 -0
  17. data/lib/yard-sorbet/version.rb +6 -0
  18. data/sorbet/config +2 -0
  19. data/sorbet/rbi/gems/ast.rbi +47 -0
  20. data/sorbet/rbi/gems/byebug.rbi +1039 -0
  21. data/sorbet/rbi/gems/codecov.rbi +19 -0
  22. data/sorbet/rbi/gems/coderay.rbi +91 -0
  23. data/sorbet/rbi/gems/docile.rbi +31 -0
  24. data/sorbet/rbi/gems/jaro_winkler.rbi +14 -0
  25. data/sorbet/rbi/gems/method_source.rbi +63 -0
  26. data/sorbet/rbi/gems/parallel.rbi +81 -0
  27. data/sorbet/rbi/gems/parser.rbi +920 -0
  28. data/sorbet/rbi/gems/pry-byebug.rbi +149 -0
  29. data/sorbet/rbi/gems/pry.rbi +1964 -0
  30. data/sorbet/rbi/gems/rainbow.rbi +117 -0
  31. data/sorbet/rbi/gems/rake.rbi +635 -0
  32. data/sorbet/rbi/gems/rspec-core.rbi +1686 -0
  33. data/sorbet/rbi/gems/rspec-expectations.rbi +387 -0
  34. data/sorbet/rbi/gems/rspec-mocks.rbi +819 -0
  35. data/sorbet/rbi/gems/rspec-support.rbi +270 -0
  36. data/sorbet/rbi/gems/rspec.rbi +14 -0
  37. data/sorbet/rbi/gems/rubocop-rspec.rbi +889 -0
  38. data/sorbet/rbi/gems/rubocop.rbi +7139 -0
  39. data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
  40. data/sorbet/rbi/gems/simplecov-html.rbi +30 -0
  41. data/sorbet/rbi/gems/simplecov.rbi +225 -0
  42. data/sorbet/rbi/gems/site_ruby.rbi +114 -0
  43. data/sorbet/rbi/gems/unicode-display_width.rbi +16 -0
  44. data/sorbet/rbi/gems/yard.rbi +1181 -0
  45. data/sorbet/rbi/hidden-definitions/errors.txt +3045 -0
  46. data/sorbet/rbi/hidden-definitions/hidden.rbi +4469 -0
  47. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
  48. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
  49. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
  50. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
  51. data/spec/data/sig_handler.rb.txt +196 -0
  52. data/spec/data/struct_handler.rb.txt +25 -0
  53. data/spec/spec_helper.rb +111 -0
  54. data/spec/yard_sorbet/sig_handler_spec.rb +233 -0
  55. data/spec/yard_sorbet/struct_handler_spec.rb +48 -0
  56. data/yard-sorbet.gemspec +27 -0
  57. metadata +159 -6
@@ -0,0 +1,196 @@
1
+ class Signatures
2
+ # comment sig_void
3
+ sig {void}
4
+ def sig_void; end
5
+
6
+ # comment sig_override_void
7
+ sig.override.void
8
+ def sig_override_void; end
9
+
10
+ # comment sig_arguments
11
+ sig {params(a: Integer, b: Integer).void}
12
+ def sig_arguments(a, b); end
13
+
14
+ # comment sig_multiline_arguments
15
+ sig do
16
+ params(
17
+ a: Integer,
18
+ b: Integer,
19
+ ).void
20
+ end
21
+ def sig_multiline_arguments(a, b); end
22
+
23
+ # comment sig_multiline_comments
24
+ # comment sig_multiline_comments
25
+ sig {void}
26
+ def sig_multiline_comments; end
27
+
28
+ # comment sig_class_method
29
+ sig {void}
30
+ def self.sig_class_method; end
31
+
32
+ class << self
33
+ # comment reopening
34
+ sig {void}
35
+ def reopening; end
36
+ end
37
+
38
+ # At end of class
39
+ sig {void}
40
+ end
41
+
42
+ class Subclass < Signatures
43
+ # with subclass
44
+ sig {void}
45
+ def method; end
46
+ end
47
+
48
+ class ClassWithCode
49
+ # bar
50
+ sig {void}
51
+ def bar; end
52
+
53
+ puts 'foobar'
54
+
55
+ # foo
56
+ sig {void}
57
+ def foo; end
58
+ end
59
+
60
+ class Outer
61
+ # outer method
62
+ sig {void}
63
+ def outer; end
64
+
65
+ class Inner
66
+ # inner method
67
+ sig {void}
68
+ def inner; end
69
+ end
70
+
71
+ # outer method 2
72
+ sig {void}
73
+ def outer2; end
74
+ end
75
+
76
+ module Module
77
+ # module function
78
+ sig {void}
79
+ def self.foo; end
80
+
81
+ # module instance method
82
+ sig {void}
83
+ def bar; end
84
+ end
85
+
86
+ class SigReturn
87
+ sig {returns(Integer)}
88
+ def one; 1; end
89
+
90
+ # @deprecated do not use
91
+ sig {returns(Integer)}
92
+ def two; 2; end
93
+
94
+ # @return [Numeric]
95
+ sig {returns(Integer)}
96
+ def three; 3; end
97
+
98
+ # @return the number four
99
+ sig {returns(Integer)}
100
+ def four; 4; end
101
+
102
+ sig {params(int: Integer).returns(Float)}
103
+ def plus_one(int); int + 1.0; end
104
+
105
+ sig {returns(T.any(Numeric, String))}
106
+ def plus(a, b); a + b; end
107
+
108
+ sig {void}
109
+ def void_method; end
110
+ end
111
+
112
+ class SigAbstract
113
+ sig {abstract}
114
+ def one; end
115
+
116
+ # @abstract subclass must implement
117
+ sig {abstract}
118
+ def two; end
119
+
120
+ sig {abstract.returns(Boolean)}
121
+ def with_return; true; end
122
+
123
+ sig {abstract.void}
124
+ def with_void; end
125
+ end
126
+
127
+ class SigParams
128
+ # @param bar the thing
129
+ # @param baz [Object] the other thing
130
+ sig {params(bar: T.any(String, Symbol), baz: T.nilable(String)).void}
131
+ def foo(bar, baz); end
132
+
133
+ sig do
134
+ params(
135
+ blk: T.proc.params(arg0: String).returns(T::Array[Hash])
136
+ )
137
+ .returns(NilClass)
138
+ end
139
+ def blk_method(&blk); nil; end
140
+
141
+ sig do
142
+ override
143
+ .params(block: T.proc.params(
144
+ model: EmailConversation,
145
+ mutator: T.untyped,
146
+ ).void)
147
+ .void
148
+ end
149
+ def impl_blk_method(&block); end
150
+ end
151
+
152
+ class CollectionSigs
153
+ sig {params(arr: T::Array[String]).void}
154
+ def collection(arr); end
155
+
156
+ sig {params(arr: T::Array[T::Array[String]]).void}
157
+ def nested_collection(arr); end
158
+
159
+ sig {params(arr: T::Array[T.any(String, Symbol)]).returns(TrueClass)}
160
+ def mixed_collection(arr); true; end
161
+
162
+ sig {returns(T::Hash[String, Symbol])}
163
+ def hash_method; end
164
+
165
+ sig {returns([String, Integer])}
166
+ def fixed_array; ['', 0]; end
167
+
168
+ # @!visibility protected
169
+ sig {returns({foo: T.nilable(String)})}
170
+ def fixed_hash; {foo: nil}; end
171
+
172
+ sig do
173
+ params(
174
+ tos_acceptance: T.nilable({
175
+ date: Integer,
176
+ ip: String,
177
+ user_agent: T.nilable(String),
178
+ signator: T.nilable(String),
179
+ iovation_blackbox: T.nilable(String),
180
+ })
181
+ )
182
+ .returns(NilClass)
183
+ end
184
+ def fixed_param_hash(tos_acceptance); nil; end
185
+ end
186
+
187
+ class AttrSigs
188
+ sig {returns(String)}
189
+ attr_accessor :my_accessor
190
+
191
+ sig {returns(Integer)}
192
+ attr_reader :my_reader
193
+
194
+ sig {params(my_writer: T.nilable(Symbol)).returns(T.nilable(Symbol))}
195
+ attr_writer :my_writer
196
+ end
@@ -0,0 +1,25 @@
1
+ # Comment on PersonStruct
2
+ class PersonStruct < T:Struct
3
+ # A name
4
+ const :name, String
5
+ # An age
6
+ const :age, Integer
7
+ # An optional
8
+ const :optional, T.nilable(String)
9
+ const :mystery, T.untyped
10
+ end
11
+
12
+ class SpecializedPersonStruct < T::Struct
13
+ const :special, String
14
+
15
+ # This is a special intializer
16
+ def initialize(special:)
17
+ raise ArgumentError("bad human") if special != "special"
18
+ super
19
+ end
20
+ end
21
+
22
+ class DefaultPersonStruct < T::Struct
23
+ # This has a default
24
+ const :defaulted, String, default: 'hello'
25
+ end
@@ -0,0 +1,111 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/yard-sorbet'
5
+
6
+ if ENV['CI'] == 'true'
7
+ require 'simplecov'
8
+ require 'codecov'
9
+ SimpleCov.start
10
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
11
+ end
12
+
13
+ # This file was generated by the `rspec --init` command. Conventionally, all
14
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
15
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
16
+ # this file to always be loaded, without a need to explicitly require it in any
17
+ # files.
18
+ #
19
+ # Given that it is always loaded, you are encouraged to keep this file as
20
+ # light-weight as possible. Requiring heavyweight dependencies from this file
21
+ # will add to the boot time of your test suite on EVERY test run, even for an
22
+ # individual file that may not need all of that loaded. Instead, consider making
23
+ # a separate helper file that requires the additional dependencies and performs
24
+ # the additional setup, and require it from the spec files that actually need
25
+ # it.
26
+ #
27
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
28
+ RSpec.configure do |config|
29
+ # rspec-expectations config goes here. You can use an alternate
30
+ # assertion/expectation library such as wrong or the stdlib/minitest
31
+ # assertions if you prefer.
32
+ config.expect_with :rspec do |expectations|
33
+ # This option will default to `true` in RSpec 4. It makes the `description`
34
+ # and `failure_message` of custom matchers include text for helper methods
35
+ # defined using `chain`, e.g.:
36
+ # be_bigger_than(2).and_smaller_than(4).description
37
+ # # => "be bigger than 2 and smaller than 4"
38
+ # ...rather than:
39
+ # # => "be bigger than 2"
40
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
41
+ end
42
+
43
+ # rspec-mocks config goes here. You can use an alternate test double
44
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
45
+ config.mock_with :rspec do |mocks|
46
+ # Prevents you from mocking or stubbing a method that does not exist on
47
+ # a real object. This is generally recommended, and will default to
48
+ # `true` in RSpec 4.
49
+ mocks.verify_partial_doubles = true
50
+ end
51
+
52
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
53
+ # have no way to turn it off -- the option exists only for backwards
54
+ # compatibility in RSpec 3). It causes shared context metadata to be
55
+ # inherited by the metadata hash of host groups and examples, rather than
56
+ # triggering implicit auto-inclusion in groups with matching metadata.
57
+ config.shared_context_metadata_behavior = :apply_to_host_groups
58
+
59
+ # The settings below are suggested to provide a good initial experience
60
+ # with RSpec, but feel free to customize to your heart's content.
61
+
62
+ # This allows you to limit a spec run to individual examples or groups
63
+ # you care about by tagging them with `:focus` metadata. When nothing
64
+ # is tagged with `:focus`, all examples get run. RSpec also provides
65
+ # aliases for `it`, `describe`, and `context` that include `:focus`
66
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
67
+ config.filter_run_when_matching :focus
68
+
69
+ # Allows RSpec to persist some state between runs in order to support
70
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
71
+ # you configure your source control system to ignore this file.
72
+ config.example_status_persistence_file_path = 'spec/examples.txt'
73
+
74
+ # Limits the available syntax to the non-monkey patched syntax that is
75
+ # recommended. For more details, see:
76
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
77
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
79
+ config.disable_monkey_patching!
80
+
81
+ # This setting enables warnings. It's recommended, but in some cases may
82
+ # be too noisy due to issues in dependencies.
83
+ config.warnings = true
84
+
85
+ # Many RSpec users commonly either run the entire suite or an individual
86
+ # file, and it's useful to allow more verbose output when running an
87
+ # individual spec file.
88
+ if config.files_to_run.one?
89
+ # Use the documentation formatter for detailed output,
90
+ # unless a formatter has already been configured
91
+ # (e.g. via a command-line flag).
92
+ config.default_formatter = 'doc'
93
+ end
94
+
95
+ # Print the 10 slowest examples and example groups at the
96
+ # end of the spec run, to help surface which specs are running
97
+ # particularly slow.
98
+ config.profile_examples = 10
99
+
100
+ # Run specs in random order to surface order dependencies. If you find an
101
+ # order dependency and want to debug it, you can fix the order by providing
102
+ # the seed, which is printed after each run.
103
+ # --seed 1234
104
+ config.order = :random
105
+
106
+ # Seed global randomization in this process using the `--seed` CLI option.
107
+ # Setting this allows you to use `--seed` to deterministically reproduce
108
+ # test failures related to randomization by passing the same `--seed` value
109
+ # as the one that triggered the failure.
110
+ Kernel.srand config.seed
111
+ end
@@ -0,0 +1,233 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require 'yard'
5
+
6
+ RSpec.describe YARDSorbet::SigHandler do
7
+ before do
8
+ YARD::Registry.clear
9
+ path = File.join(
10
+ File.expand_path('../data', __dir__),
11
+ 'sig_handler.rb.txt'
12
+ )
13
+ YARD::Parser::SourceParser.parse(path)
14
+ end
15
+
16
+ describe 'attaching to method' do
17
+ it 'handles signatures without arguments' do
18
+ node = YARD::Registry.at('Signatures#sig_void')
19
+ expect(node.docstring).to eq('comment sig_void')
20
+ end
21
+
22
+ it 'handles chaining' do
23
+ node = YARD::Registry.at('Signatures#sig_override_void')
24
+ expect(node.docstring).to eq('comment sig_override_void')
25
+ end
26
+
27
+ it 'handles arguments' do
28
+ node = YARD::Registry.at('Signatures#sig_arguments')
29
+ expect(node.docstring).to eq('comment sig_arguments')
30
+ end
31
+
32
+ it 'handles multiline arguments' do
33
+ node = YARD::Registry.at('Signatures#sig_multiline_arguments')
34
+ expect(node.docstring).to eq('comment sig_multiline_arguments')
35
+ end
36
+
37
+ it 'handles multiline comments' do
38
+ node = YARD::Registry.at('Signatures#sig_multiline_comments')
39
+ expect(node.docstring).to eq("comment sig_multiline_comments\ncomment sig_multiline_comments")
40
+ end
41
+
42
+ it 'handles class methods' do
43
+ node = YARD::Registry.at('Signatures.sig_class_method')
44
+ expect(node.docstring).to eq('comment sig_class_method')
45
+ end
46
+
47
+ it 'handles subclasses' do
48
+ node = YARD::Registry.at('Subclass#method')
49
+ expect(node.docstring).to eq('with subclass')
50
+ end
51
+
52
+ it 'handles classes executing code' do
53
+ node = YARD::Registry.at('ClassWithCode#foo')
54
+ expect(node.docstring).to eq('foo')
55
+ end
56
+
57
+ it 'handles nested classes' do
58
+ node = YARD::Registry.at('Outer#outer')
59
+ expect(node.docstring).to eq('outer method')
60
+
61
+ node = YARD::Registry.at('Outer#outer2')
62
+ expect(node.docstring).to eq('outer method 2')
63
+
64
+ node = YARD::Registry.at('Outer::Inner#inner')
65
+ expect(node.docstring).to eq('inner method')
66
+ end
67
+
68
+ it 'handles modules' do
69
+ node = YARD::Registry.at('Module.foo')
70
+ expect(node.docstring).to eq('module function')
71
+
72
+ node = YARD::Registry.at('Module#bar')
73
+ expect(node.docstring).to eq('module instance method')
74
+ end
75
+
76
+ it 'handles singleton class syntax' do
77
+ skip('TODO')
78
+ node = YARD::Registry.at('Signatures.reopening')
79
+ expect(node.docstring).to eq('comment reopening')
80
+ end
81
+ end
82
+
83
+ describe 'sig parsing' do
84
+ it 'parses return types' do
85
+ node = YARD::Registry.at('SigReturn#one')
86
+ expect(node.tag(:return).types).to eq(['Integer'])
87
+ end
88
+
89
+ it 'merges tags' do
90
+ node = YARD::Registry.at('SigReturn#two')
91
+ expect(node.tag(:return).types).to eq(['Integer'])
92
+ expect(node.tag(:deprecated).text).to eq('do not use')
93
+ end
94
+
95
+ it 'overrides explicit tag' do
96
+ node = YARD::Registry.at('SigReturn#three')
97
+ expect(node.tag(:return).types).to eq(['Integer'])
98
+ end
99
+
100
+ it 'merges comment' do
101
+ node = YARD::Registry.at('SigReturn#four')
102
+ expect(node.tag(:return).types).to eq(['Integer'])
103
+ expect(node.tag(:return).text).to eq('the number four')
104
+ end
105
+
106
+ it 'with params' do
107
+ node = YARD::Registry.at('SigReturn#plus_one')
108
+ expect(node.tag(:return).types).to eq(['Float'])
109
+ end
110
+
111
+ it 'with T syntax' do
112
+ node = YARD::Registry.at('SigReturn#plus')
113
+ expect(node.tag(:return).types).to eq(%w[Numeric String])
114
+ end
115
+
116
+ it 'with void sig' do
117
+ node = YARD::Registry.at('SigReturn#void_method')
118
+ expect(node.tag(:return).types).to eq(['void'])
119
+ end
120
+
121
+ it 'with abstract sig' do
122
+ node = YARD::Registry.at('SigAbstract#one')
123
+ expect(node.tag(:abstract).text).to eq('')
124
+ end
125
+
126
+ it 'merges abstract tag' do
127
+ node = YARD::Registry.at('SigAbstract#two')
128
+ expect(node.tag(:abstract).text).to eq('subclass must implement')
129
+ end
130
+
131
+ it 'with returns' do
132
+ node = YARD::Registry.at('SigAbstract#with_return')
133
+ expect(node.tag(:abstract).text).to eq('')
134
+ expect(node.tag(:return).types).to eq(['Boolean'])
135
+ end
136
+
137
+ it 'with void' do
138
+ node = YARD::Registry.at('SigAbstract#with_void')
139
+ expect(node.tag(:abstract).text).to eq('')
140
+ expect(node.tag(:return).types).to eq(['void'])
141
+ end
142
+
143
+ it 'params' do
144
+ node = YARD::Registry.at('SigParams#foo')
145
+ bar_tag = node.tags.find { |t| t.name == 'bar' }
146
+ expect(bar_tag.text).to eq('the thing')
147
+ expect(bar_tag.types).to eq(%w[String Symbol])
148
+ baz_tag = node.tags.find { |t| t.name == 'baz' }
149
+ expect(baz_tag.text).to eq('the other thing')
150
+ expect(baz_tag.types).to eq(%w[String nil])
151
+ end
152
+
153
+ it 'block param' do
154
+ node = YARD::Registry.at('SigParams#blk_method')
155
+ blk_tag = node.tags.find { |t| t.name == 'blk' }
156
+ expect(blk_tag.types).to eq(
157
+ ['T.proc.params(arg0: String).returns(T::Array[Hash])']
158
+ )
159
+ expect(node.tag(:return).types).to eq(['nil'])
160
+ end
161
+
162
+ it 'block param with newlines' do
163
+ node = YARD::Registry.at('SigParams#impl_blk_method')
164
+ blk_tag = node.tags.find { |t| t.name == 'block' }
165
+ expect(blk_tag.types).to eq(
166
+ ['T.proc.params( model: EmailConversation, mutator: T.untyped, ).void']
167
+ )
168
+ expect(node.tag(:return).types).to eq(['void'])
169
+ end
170
+
171
+ it 'T::Array' do
172
+ node = YARD::Registry.at('CollectionSigs#collection')
173
+ param_tag = node.tags.find { |t| t.name == 'arr' }
174
+ expect(param_tag.types).to eq(['Array<String>'])
175
+ end
176
+
177
+ it 'nested T::Array' do
178
+ node = YARD::Registry.at('CollectionSigs#nested_collection')
179
+ param_tag = node.tags.find { |t| t.name == 'arr' }
180
+ expect(param_tag.types).to eq(['Array<Array<String>>'])
181
+ end
182
+
183
+ it 'mixed T::Array' do
184
+ node = YARD::Registry.at('CollectionSigs#mixed_collection')
185
+ param_tag = node.tags.find { |t| t.name == 'arr' }
186
+ expect(param_tag.types).to eq(['Array<String, Symbol>'])
187
+ end
188
+
189
+ it 'T::Hash' do
190
+ node = YARD::Registry.at('CollectionSigs#hash_method')
191
+ expect(node.tag(:return).types).to eq(['Hash{String => Symbol}'])
192
+ end
193
+
194
+ it 'fixed Array' do
195
+ node = YARD::Registry.at('CollectionSigs#fixed_array')
196
+ expect(node.tag(:return).types).to eq(['Array(String, Integer)'])
197
+ end
198
+
199
+ it 'fixed Hash' do
200
+ node = YARD::Registry.at('CollectionSigs#fixed_hash')
201
+ expect(node.tag(:return).types).to eq(['Hash'])
202
+ expect(node.visibility).to eq(:protected)
203
+ end
204
+
205
+ it 'fixed param Hash' do
206
+ node = YARD::Registry.at('CollectionSigs#fixed_param_hash')
207
+ param_tag = node.tags.find { |t| t.name == 'tos_acceptance' }
208
+ expect(param_tag.types).to eq(%w[Hash nil])
209
+ end
210
+ end
211
+
212
+ describe 'attributes' do
213
+ it 'handles attr_accessor getter' do
214
+ node = YARD::Registry.at('AttrSigs#my_accessor')
215
+ expect(node.tag(:return).types).to eq(['String'])
216
+ end
217
+
218
+ it 'handles attr_accessor setter' do
219
+ node = YARD::Registry.at('AttrSigs#my_accessor=')
220
+ expect(node.tag(:return).types).to eq(['String'])
221
+ end
222
+
223
+ it 'handles attr_reader' do
224
+ node = YARD::Registry.at('AttrSigs#my_reader')
225
+ expect(node.tag(:return).types).to eq(['Integer'])
226
+ end
227
+
228
+ it 'handles attr_writer' do
229
+ node = YARD::Registry.at('AttrSigs#my_writer=')
230
+ expect(node.tag(:return).types).to eq(%w[Symbol nil])
231
+ end
232
+ end
233
+ end