From 61e9e69dd6839e6915c4ffa5170d6d160c0405f1 Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Mon, 15 Jun 2020 22:42:25 +0100 Subject: [PATCH 1/4] Add `delimiter?' predicate for `RegexpNode` As suggested by @bbatsov here: https://github.com/rubocop-hq/rubocop/pull/8138#discussion_r439268175 --- CHANGELOG.md | 1 + lib/rubocop/ast/node/regexp_node.rb | 5 +++ spec/rubocop/ast/regexp_node_spec.rb | 57 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66822baa3..1318b4736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][]) * [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][]) * [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][]) +* [#TODO](https://github.com/rubocop-hq/rubocop-ast/pull/TODO): Add `delimiter?' predicate for `RegexpNode`. ([@owst][]) ## 0.0.3 (2020-05-15) diff --git a/lib/rubocop/ast/node/regexp_node.rb b/lib/rubocop/ast/node/regexp_node.rb index 14c33b104..5a2ee8d3f 100644 --- a/lib/rubocop/ast/node/regexp_node.rb +++ b/lib/rubocop/ast/node/regexp_node.rb @@ -32,6 +32,11 @@ def content children.select(&:str_type?).map(&:str_content).join end + # @return [Bool] if char is one of the delimiters + def delimiter?(char) + [loc.begin.source[-1], loc.end.source[0]].include?(char) + end + # @return [Bool] if regexp contains interpolation def interpolation? children.any?(&:begin_type?) diff --git a/spec/rubocop/ast/regexp_node_spec.rb b/spec/rubocop/ast/regexp_node_spec.rb index 580a98287..b9b55f9bc 100644 --- a/spec/rubocop/ast/regexp_node_spec.rb +++ b/spec/rubocop/ast/regexp_node_spec.rb @@ -141,6 +141,63 @@ end end + describe '#delimiter?' do + context 'with /-delimiters' do + let(:source) { '/abc/' } + + it { expect(regexp_node.delimiter?('/')).to eq(true) } + + it { expect(regexp_node.delimiter?('{')).to eq(false) } + end + + context 'with %r/-delimiters' do + let(:source) { '%r/abc/' } + + it { expect(regexp_node.delimiter?('/')).to eq(true) } + + it { expect(regexp_node.delimiter?('{')).to eq(false) } + it { expect(regexp_node.delimiter?('}')).to eq(false) } + it { expect(regexp_node.delimiter?('%')).to eq(false) } + it { expect(regexp_node.delimiter?('r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r/')).to eq(false) } + end + + context 'with %r{-delimiters' do + let(:source) { '%r{abc}' } + + it { expect(regexp_node.delimiter?('{')).to eq(true) } + it { expect(regexp_node.delimiter?('}')).to eq(true) } + + it { expect(regexp_node.delimiter?('/')).to eq(false) } + it { expect(regexp_node.delimiter?('%')).to eq(false) } + it { expect(regexp_node.delimiter?('r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r/')).to eq(false) } + it { expect(regexp_node.delimiter?('%r{')).to eq(false) } + end + + context 'with multi-line %r{-delimiters' do + let(:source) do + <<~SRC + %r{ + abc + }x + SRC + end + + it { expect(regexp_node.delimiter?('{')).to eq(true) } + it { expect(regexp_node.delimiter?('}')).to eq(true) } + + it { expect(regexp_node.delimiter?('/')).to eq(false) } + it { expect(regexp_node.delimiter?('%')).to eq(false) } + it { expect(regexp_node.delimiter?('r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r/')).to eq(false) } + it { expect(regexp_node.delimiter?('%r{')).to eq(false) } + end + end + describe '#interpolation?' do context 'with direct variable interpoation' do let(:source) { '/\n\n#{foo}(abc)+/' } From 6c3393d1c3b4a7cc77a1447e91e2f0c79ec626fa Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Mon, 15 Jun 2020 22:54:31 +0100 Subject: [PATCH 2/4] fixup! Add `delimiter?' predicate for `RegexpNode` --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1318b4736..2d6bccf71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ * [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][]) * [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][]) * [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][]) -* [#TODO](https://github.com/rubocop-hq/rubocop-ast/pull/TODO): Add `delimiter?' predicate for `RegexpNode`. ([@owst][]) +* [#41](https://github.com/rubocop-hq/rubocop-ast/pull/41): Add `delimiter?' predicate for `RegexpNode`. ([@owst][]) ## 0.0.3 (2020-05-15) From 7fc0d09750d0e6ca7bd0f806d226d2431dc87825 Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Tue, 16 Jun 2020 09:08:09 +0100 Subject: [PATCH 3/4] fixup! fixup! Add `delimiter?' predicate for `RegexpNode` --- CHANGELOG.md | 2 +- lib/rubocop/ast/node/regexp_node.rb | 17 +++- spec/rubocop/ast/regexp_node_spec.rb | 131 +++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6bccf71..53f812a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ * [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][]) * [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][]) * [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][]) -* [#41](https://github.com/rubocop-hq/rubocop-ast/pull/41): Add `delimiter?' predicate for `RegexpNode`. ([@owst][]) +* [#41](https://github.com/rubocop-hq/rubocop-ast/pull/41): Add `delimiters' and related predicates for `RegexpNode`. ([@owst][]) ## 0.0.3 (2020-05-15) diff --git a/lib/rubocop/ast/node/regexp_node.rb b/lib/rubocop/ast/node/regexp_node.rb index 5a2ee8d3f..2b621ad90 100644 --- a/lib/rubocop/ast/node/regexp_node.rb +++ b/lib/rubocop/ast/node/regexp_node.rb @@ -32,9 +32,24 @@ def content children.select(&:str_type?).map(&:str_content).join end + # @return [Bool] if the regexp is a /.../ literal + def slash_literal? + loc.begin.source == '/' + end + + # @return [Bool] if the regexp is a %r{...} literal (using any delimiters) + def percent_r_literal? + !slash_literal? + end + + # @return [String] the regexp delimiters (without %r) + def delimiters + [loc.begin.source[-1], loc.end.source[0]] + end + # @return [Bool] if char is one of the delimiters def delimiter?(char) - [loc.begin.source[-1], loc.end.source[0]].include?(char) + delimiters.include?(char) end # @return [Bool] if regexp contains interpolation diff --git a/spec/rubocop/ast/regexp_node_spec.rb b/spec/rubocop/ast/regexp_node_spec.rb index b9b55f9bc..8a9a0bbb3 100644 --- a/spec/rubocop/ast/regexp_node_spec.rb +++ b/spec/rubocop/ast/regexp_node_spec.rb @@ -141,6 +141,120 @@ end end + describe '#slash_literal?' do + context 'with /-delimiters' do + let(:source) { '/abc/' } + + it { expect(regexp_node.slash_literal?).to eq(true) } + end + + context 'with %r/-delimiters' do + let(:source) { '%r/abc/' } + + it { expect(regexp_node.slash_literal?).to eq(false) } + end + + context 'with %r{-delimiters' do + let(:source) { '%r{abc}' } + + it { expect(regexp_node.slash_literal?).to eq(false) } + end + + context 'with multi-line %r{-delimiters' do + let(:source) do + <<~SRC + %r{ + abc + }x + SRC + end + + it { expect(regexp_node.slash_literal?).to eq(false) } + end + + context 'with %r<-delimiters' do + let(:source) { '%rx' } + + it { expect(regexp_node.slash_literal?).to eq(false) } + end + end + + describe '#percent_r_literal?' do + context 'with /-delimiters' do + let(:source) { '/abc/' } + + it { expect(regexp_node.percent_r_literal?).to eq(false) } + end + + context 'with %r/-delimiters' do + let(:source) { '%r/abc/' } + + it { expect(regexp_node.percent_r_literal?).to eq(true) } + end + + context 'with %r{-delimiters' do + let(:source) { '%r{abc}' } + + it { expect(regexp_node.percent_r_literal?).to eq(true) } + end + + context 'with multi-line %r{-delimiters' do + let(:source) do + <<~SRC + %r{ + abc + }x + SRC + end + + it { expect(regexp_node.percent_r_literal?).to eq(true) } + end + + context 'with %r<-delimiters' do + let(:source) { '%rx' } + + it { expect(regexp_node.percent_r_literal?).to eq(true) } + end + end + + describe '#delimiters' do + context 'with /-delimiters' do + let(:source) { '/abc/' } + + it { expect(regexp_node.delimiters).to eq(['/', '/']) } + end + + context 'with %r/-delimiters' do + let(:source) { '%r/abc/' } + + it { expect(regexp_node.delimiters).to eq(['/', '/']) } + end + + context 'with %r{-delimiters' do + let(:source) { '%r{abc}' } + + it { expect(regexp_node.delimiters).to eq(['{', '}']) } + end + + context 'with multi-line %r{-delimiters' do + let(:source) do + <<~SRC + %r{ + abc + }x + SRC + end + + it { expect(regexp_node.delimiters).to eq(['{', '}']) } + end + + context 'with %r<-delimiters' do + let(:source) { '%rx' } + + it { expect(regexp_node.delimiters).to eq(['<', '>']) } + end + end + describe '#delimiter?' do context 'with /-delimiters' do let(:source) { '/abc/' } @@ -196,6 +310,23 @@ it { expect(regexp_node.delimiter?('%r/')).to eq(false) } it { expect(regexp_node.delimiter?('%r{')).to eq(false) } end + + context 'with %r<-delimiters' do + let(:source) { '%rx' } + + it { expect(regexp_node.delimiter?('<')).to eq(true) } + it { expect(regexp_node.delimiter?('>')).to eq(true) } + + it { expect(regexp_node.delimiter?('{')).to eq(false) } + it { expect(regexp_node.delimiter?('}')).to eq(false) } + it { expect(regexp_node.delimiter?('/')).to eq(false) } + it { expect(regexp_node.delimiter?('%')).to eq(false) } + it { expect(regexp_node.delimiter?('r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r')).to eq(false) } + it { expect(regexp_node.delimiter?('%r/')).to eq(false) } + it { expect(regexp_node.delimiter?('%r{')).to eq(false) } + it { expect(regexp_node.delimiter?('%r<')).to eq(false) } + end end describe '#interpolation?' do From 772b2471f473cf622dd0c7daf50fd72e6bc51ace Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Tue, 16 Jun 2020 09:24:32 +0100 Subject: [PATCH 4/4] fixup! fixup! fixup! Add `delimiter?' predicate for `RegexpNode` --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53f812a3d..4baa5dba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ * [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][]) * [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][]) * [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][]) -* [#41](https://github.com/rubocop-hq/rubocop-ast/pull/41): Add `delimiters' and related predicates for `RegexpNode`. ([@owst][]) +* [#41](https://github.com/rubocop-hq/rubocop-ast/pull/41): Add `delimiters` and related predicates for `RegexpNode`. ([@owst][]) ## 0.0.3 (2020-05-15)