-
-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MasgnNode
class for masgn
nodes
#203
base: master
Are you sure you want to change the base?
Conversation
Sorry I missed this in my previous PR @marcandre 😅 🙌 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
masgn
is complicated, isn't it? 😅
PR looks like a good start, but you seem to have overlooked 2 important cases: foo.bar, foo[:baz], ... = ...
.
Please describe results of your proposed methods and add tests.
Also:
-
each_descendant
should only be used on the first child. Please add a test forx, y = 1, z+=2
for example. Even then, some corner cases could be problematic:foo[x+=1], bar = ...
-
I doubt
each_assignment
is necessary. Performance of enumerators is typically quite poor, especially for short lists
I knew there were things I wasn't thinking of, thanks @marcandre I'll fix up for those cases! |
@marcandre updated now. I have now introduced a
I also added For symmetry, Please let me know your thoughts! |
0476aa2
to
8b5f9b3
Compare
The "modern" spec was failing on |
96e0836
to
ff20438
Compare
context 'with nested assignment on LHS' do | ||
let(:source) { 'a, b[c+=1] = z' } | ||
|
||
it { is_expected.to eq([:a, 'b[c+=1]']) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a use for 'b[c+=1]'
? It seems like a bad result for a name, and string vs symbol is a bit ugly. What about :"b[]"
instead?
context 'with a method chain on LHS' do | ||
let(:source) { 'a, b.c = z' } | ||
|
||
it { is_expected.to eq([:a, 'b.c']) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same with 'b.c'
. How about :c=
or :"#c"
?
it { is_expected.to eq(%i[a b c]) } | ||
end | ||
|
||
context 'with nested assignment on LHS' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong description
context 'with variables' do | ||
it { is_expected.to eq(s(:send, nil, :z)) } | ||
end | ||
|
||
context 'with a LHS splat' do | ||
let(:source) { 'x, *y = z' } | ||
|
||
it { is_expected.to eq(s(:send, nil, :z)) } | ||
end | ||
|
||
context 'with multiple RHS values' do | ||
let(:source) { 'x, y = 1, 2' } | ||
|
||
it { is_expected.to eq(s(:array, s(:int, 1), s(:int, 2))) } | ||
end | ||
|
||
context 'with an RHS splat' do | ||
let(:source) { 'x, y = *z' } | ||
|
||
it { is_expected.to eq(s(:array, s(:splat, s(:send, nil, :z)))) } | ||
end | ||
|
||
context 'with assignment on RHS' do | ||
let(:source) { 'x, y = 1, z+=2' } | ||
|
||
it { is_expected.to eq(s(:array, s(:int, 1), s(:op_asgn, s(:lvasgn, :z), :+, s(:int, 2)))) } | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is overkill for such a simple method. How about a single test here?
# @return [Array<Node>] values being assigned on the RHS of the multiple assignment | ||
def values | ||
array? ? expression.children : [expression] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you justify when / how this is useful? I find it a bad idea that x, y = z
and x, y = [z]
produce the same values
even though they are very different
context 'when the RHS has a single value' do | ||
let(:source) { 'x, y = z' } | ||
|
||
it { is_expected.to eq([s(:send, nil, :z)]) } | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this method is to remain, then needs a test for 'x, y = [z]'
end | ||
|
||
# @return [Boolean] whether the expression has multiple values | ||
def array? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a need for this public method? I find the definition dubious, as x, y = z
and x, y = *z
are basically the same yet have a different array?
result.
Follows #201. I actually ended up needing
masgn
to have its own class withexpression
defined in order to do the refactoring I wanted to, so this adds it.Because
masgn
nodes are more involved than the other assignment types, this class has a different interface than the other assignments, except forexpression
which works the same. Rather thanname
that the other assignment classes have,MasgnNode
hasnames
(since there will inherently be more than one). It also is able to handle nestedmlhs
es.