1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
# frozen_string_literal: true
RSpec.describe YARD::Parser::Ruby::Legacy::StatementList do
def stmts(code) YARD::Parser::Ruby::Legacy::StatementList.new(code) end
def stmt(code) stmts(code).first end
it "parses dangling block expressions" do
s = stmt <<-eof
if
foo
puts 'hi'
end
eof
expect(s.tokens.to_s(true)).to eq "if\n foo\n ...\n end"
expect(s.tokens.to_s).to eq "if\n foo"
expect(s.block.to_s).to eq "puts 'hi'"
s = stmt <<-eof
if foo ||
bar
puts 'hi'
end
eof
expect(s.tokens.to_s(true)).to eq "if foo ||\n bar\n ...\n end"
expect(s.tokens.to_s).to eq "if foo ||\n bar"
expect(s.block.to_s).to eq "puts 'hi'"
end
it "allows semicolons within parentheses" do
s = stmt "(foo; bar)"
expect(s.tokens.to_s(true)).to eq "(foo; bar)"
expect(s.block).to be nil
end
it "allows for non-block statements" do
s = stmt "hello_world(1, 2, 3)"
expect(s.tokens.to_s).to eq "hello_world(1, 2, 3)"
expect(s.block).to be nil
end
it "allows block statements to be used as part of other block statements" do
s = stmt "while (foo; bar); foo = 12; end; while"
expect(s.tokens.to_s(true)).to eq "while (foo; bar); ... end"
expect(s.tokens.to_s).to eq "while (foo; bar)"
expect(s.block.to_s).to eq "foo = 12"
end
it "allows continued processing after a block" do
s = stmt "if foo; end.stuff"
expect(s.tokens.to_s(true)).to eq "if foo; end.stuff"
expect(s.block.to_s).to eq ""
s = stmt "if foo; end[stuff]"
expect(s.tokens.to_s(true)).to eq "if foo; end[stuff]"
expect(s.block.to_s).to eq ""
s = stmt "if foo; hi end.map do; 123; end"
expect(s.tokens.to_s(true)).to eq "if foo; ... end.map do; 123; end"
expect(s.block.to_s).to eq "hi"
end
it "parses default arguments" do
s = stmt "def foo(bar, baz = 1, bang = 2); bar; end"
expect(s.tokens.to_s(true)).to eq "def foo(bar, baz = 1, bang = 2) ... end"
expect(s.block.to_s).to eq "bar"
s = stmt "def foo bar, baz = 1, bang = 2; bar; end"
expect(s.tokens.to_s(true)).to eq "def foo bar, baz = 1, bang = 2; ... end"
expect(s.block.to_s).to eq "bar"
s = stmt "def foo bar , baz = 1 , bang = 2; bar; end"
expect(s.tokens.to_s(true)).to eq "def foo bar , baz = 1 , bang = 2; ... end"
expect(s.block.to_s).to eq "bar"
end
it "parses complex default arguments" do
s = stmt "def foo(bar, baz = File.new(1, 2), bang = 3); bar; end"
expect(s.tokens.to_s(true)).to eq "def foo(bar, baz = File.new(1, 2), bang = 3) ... end"
expect(s.block.to_s).to eq "bar"
s = stmt "def foo bar, baz = File.new(1, 2), bang = 3; bar; end"
expect(s.tokens.to_s(true)).to eq "def foo bar, baz = File.new(1, 2), bang = 3; ... end"
expect(s.block.to_s).to eq "bar"
s = stmt "def foo bar , baz = File.new(1, 2) , bang = 3; bar; end"
expect(s.tokens.to_s(true)).to eq "def foo bar , baz = File.new(1, 2) , bang = 3; ... end"
expect(s.block.to_s).to eq "bar"
end
it "parses blocks with do/end" do
s = stmt <<-eof
foo do
puts 'hi'
end
eof
expect(s.tokens.to_s(true)).to eq "foo do\n ...\n end"
expect(s.block.to_s).to eq "puts 'hi'"
end
it "parses blocks with {}" do
s = stmt "x { y }"
expect(s.tokens.to_s(true)).to eq "x { ... }"
expect(s.block.to_s).to eq "y"
s = stmt "x() { y }"
expect(s.tokens.to_s(true)).to eq "x() { ... }"
expect(s.block.to_s).to eq "y"
end
it "parses blocks with begin/end" do
s = stmt "begin xyz end"
expect(s.tokens.to_s(true)).to eq "begin ... end"
expect(s.block.to_s).to eq "xyz"
end
it "parses nested blocks" do
s = stmt "foo(:x) { baz(:y) { skippy } }"
expect(s.tokens.to_s(true)).to eq "foo(:x) { ... }"
expect(s.block.to_s).to eq "baz(:y) { skippy }"
end
it "does not parse hashes as blocks" do
s = stmt "x({})"
expect(s.tokens.to_s(true)).to eq "x({})"
expect(s.block.to_s).to eq ""
s = stmt "x = {}"
expect(s.tokens.to_s(true)).to eq "x = {}"
expect(s.block.to_s).to eq ""
s = stmt "x(y, {})"
expect(s.tokens.to_s(true)).to eq "x(y, {})"
expect(s.block.to_s).to eq ""
end
it "parses hashes in blocks with {}" do
s = stmt "x {x = {}}"
expect(s.tokens.to_s(true)).to eq "x {...}"
expect(s.block.to_s).to eq "x = {}"
end
it "parses blocks with {} in hashes" do
s = stmt "[:foo, x {}]"
expect(s.tokens.to_s(true)).to eq "[:foo, x {}]"
expect(s.block.to_s).to eq ""
end
it "handles multiple methods" do
s = stmt <<-eof
def %; end
def b; end
eof
expect(s.to_s).to eq "def %; end"
end
it "handles nested methods" do
s = stmt <<-eof
def *(o) def +@; end
def ~@
end end
eof
expect(s.tokens.to_s(true)).to eq "def *(o) ... end"
expect(s.block.to_s).to eq "def +@; end\n def ~@\n end"
s = stmts(<<-eof)
def /(other) 'hi' end
def method1
def dynamic; end
end
eof
expect(s[1].to_s).to eq "def method1\n def dynamic; end\n end"
end
it "gets comment line numbers" do
s = stmt <<-eof
# comment
# comment
# comment
def method; end
eof
expect(s.comments).to eq ["comment", "comment", "comment"]
expect(s.comments_range).to eq(1..3)
s = stmt <<-eof
# comment
# comment
def method; end
eof
expect(s.comments).to eq ["comment", "comment"]
expect(s.comments_range).to eq(2..3)
s = stmt <<-eof
# comment
# comment
def method; end
eof
expect(s.comments).to eq ["comment", "comment"]
expect(s.comments_range).to eq(1..2)
s = stmt <<-eof
# comment
def method; end
eof
expect(s.comments).to eq ["comment"]
expect(s.comments_range).to eq(1..1)
s = stmt <<-eof
def method; end # comment
eof
expect(s.comments).to eq ["comment"]
expect(s.comments_range).to eq(1..1)
end
it "only looks up to two lines back for comments" do
s = stmt <<-eof
# comments
# comments
def method; end
eof
expect(s.comments).to eq ["comments"]
s = stmt <<-eof
# comments
def method; end
eof
expect(s.comments).to eq nil
ss = stmts <<-eof
# comments
def method; end
# hello
def method2; end
eof
expect(ss[0].comments).to eq nil
expect(ss[1].comments).to eq ['hello']
end
it "handles CRLF (Windows) newlines" do
s = stmts("require 'foo'\r\n\r\n# Test Test\r\n# \r\n# Example:\r\n# example code\r\ndef test\r\nend\r\n")
expect(s[1].comments).to eq ['Test Test', '', 'Example:', ' example code']
end
it "handles elsif blocks" do
s = stmts(stmt("if 0\n foo\nelsif 2\n bar\nend\nbaz").block)
expect(s.size).to eq 2
expect(s[1].tokens.to_s).to eq "elsif 2"
expect(s[1].block.to_s).to eq "bar"
end
it "handles else blocks" do
s = stmts(stmt("if 0\n foo\nelse\n bar\nend\nbaz").block)
expect(s.size).to eq 2
expect(s[1].tokens.to_s).to eq "else"
expect(s[1].block.to_s).to eq "bar"
end
it "allows aliasing keywords" do
['do x', 'x do', 'end begin', 'begin end'].each do |a|
s = stmt("alias #{a}\ndef foo; end")
expect(s.tokens.to_s).to eq "alias #{a}"
expect(s.block).to be nil
end
s = stmt("alias do x if 2 ==\n 2")
expect(s.tokens.to_s).to eq "alias do x if 2 ==\n 2"
end
it "does not open a block on an aliased keyword block opener" do
s = stmts(<<-eof)
class A; alias x do end
class B; end
eof
expect(s[0].block.to_s).to eq 'alias x do'
expect(s.size).to be > 1
end
it "converts heredoc to string" do
src = "<<-XML\n foo\n\nXML"
s = stmt(src)
expect(s.source).to eq '" foo\n\n"'
end
it "converts squiggly heredoc to string" do
src = "<<~XML\n bar\n\nXML"
s = stmt(src)
expect(s.source).to eq '"bar\n\n"'
end
end
|