rubocop-yast 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/config/default.yml +8 -0
- data/lib/rubocop-yast.rb +4 -0
- data/lib/rubocop/cop/yast/builtins.rb +28 -1
- data/lib/rubocop/cop/yast/ops.rb +226 -0
- data/lib/rubocop/yast/config.rb +19 -0
- data/lib/rubocop/yast/niceness.rb +60 -0
- data/lib/rubocop/yast/variable_scope.rb +62 -0
- data/lib/rubocop/yast/version.rb +1 -1
- data/rubocop-yast.gemspec +3 -2
- data/spec/builtins_spec.rb +15 -1
- data/spec/ops_spec.rb +116 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c16c03c56b76dc2b1b8896fda2f2d5765d686c41
|
4
|
+
data.tar.gz: 695426ba9cb0fd0ff1d273d337c3947f8a785b80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d69f1ac5711c04993f135091ea1ea1d6ac4159c579a45afe7d3c783f6650416af0aef1b4819ec0a0033dfc140fd1ad54f4e994332ef389905096fad1de8ca94
|
7
|
+
data.tar.gz: 5bd8f3cd68cdbd225c148eec3082914ff9c4345926bf14b0819f9d61b39a857277e0be03deebffb2192ee6a3a520d051935a65ea7695c28f13dbd0adc6478d2b
|
data/config/default.yml
ADDED
data/lib/rubocop-yast.rb
CHANGED
@@ -16,7 +16,13 @@ module RuboCop
|
|
16
16
|
# gettext helpers
|
17
17
|
:dgettext,
|
18
18
|
:dngettext,
|
19
|
-
:dpgettext
|
19
|
+
:dpgettext,
|
20
|
+
# crypt* helpers
|
21
|
+
:crypt,
|
22
|
+
:cryptmd5,
|
23
|
+
:cryptblowfish,
|
24
|
+
:cryptsha256,
|
25
|
+
:cryptsha512
|
20
26
|
]
|
21
27
|
|
22
28
|
BUILTINS_NODES = [
|
@@ -36,6 +42,27 @@ module RuboCop
|
|
36
42
|
|
37
43
|
add_offense(node, :selector, format(MSG, method_name))
|
38
44
|
end
|
45
|
+
|
46
|
+
def autocorrect(node)
|
47
|
+
@corrections << lambda do |corrector|
|
48
|
+
_builtins, message, args = *node
|
49
|
+
|
50
|
+
new_code = builtins_replacement(message, args)
|
51
|
+
|
52
|
+
corrector.replace(node.loc.expression, new_code) if new_code
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def builtins_replacement(message, args)
|
59
|
+
case message
|
60
|
+
when :getenv
|
61
|
+
"ENV[#{args.loc.expression.source}]"
|
62
|
+
when :time
|
63
|
+
"::Time.now.to_i"
|
64
|
+
end
|
65
|
+
end
|
39
66
|
end
|
40
67
|
end
|
41
68
|
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rubocop/yast/niceness"
|
4
|
+
require "rubocop/yast/variable_scope"
|
5
|
+
|
6
|
+
# We have encountered code that does satisfy our simplifying assumptions,
|
7
|
+
# translating it would not be correct.
|
8
|
+
class TooComplexToTranslateError < Exception
|
9
|
+
end
|
10
|
+
|
11
|
+
module RuboCop
|
12
|
+
module Cop
|
13
|
+
module Yast
|
14
|
+
# This cop checks for Ops.* calls, it can autocorrect safe places or
|
15
|
+
# all places in unsafe mode
|
16
|
+
class Ops < Cop
|
17
|
+
include Niceness
|
18
|
+
|
19
|
+
# Ops replacement mapping
|
20
|
+
REPLACEMENT = {
|
21
|
+
add: "+"
|
22
|
+
}
|
23
|
+
|
24
|
+
MSG = "Obsolete Ops.%s call found"
|
25
|
+
|
26
|
+
def initialize(config = nil, options = nil)
|
27
|
+
super(config, options)
|
28
|
+
|
29
|
+
@scopes = VariableScopeStack.new
|
30
|
+
@safe_mode = cop_config["SafeMode"]
|
31
|
+
@replaced_nodes = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# FIXME
|
35
|
+
def process(node)
|
36
|
+
return if node.nil?
|
37
|
+
# if ! @unsafe
|
38
|
+
# oops(node, RuntimeError.new("Unknown node type #{node.type}")) \
|
39
|
+
# unless HANDLED_NODE_TYPES.include? node.type
|
40
|
+
# end
|
41
|
+
end
|
42
|
+
|
43
|
+
# currently visible scope
|
44
|
+
def scope
|
45
|
+
scopes.innermost
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_new_scope_rescuing_oops(node, &block)
|
49
|
+
scopes.with_new do
|
50
|
+
block.call if block_given?
|
51
|
+
end
|
52
|
+
rescue => e
|
53
|
+
oops(node, e)
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_def(node)
|
57
|
+
with_new_scope_rescuing_oops(node)
|
58
|
+
end
|
59
|
+
|
60
|
+
def on_defs(node)
|
61
|
+
with_new_scope_rescuing_oops(node)
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_module(node)
|
65
|
+
with_new_scope_rescuing_oops(node)
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_class(node)
|
69
|
+
with_new_scope_rescuing_oops(node)
|
70
|
+
end
|
71
|
+
|
72
|
+
def on_sclass(node)
|
73
|
+
with_new_scope_rescuing_oops(node)
|
74
|
+
end
|
75
|
+
|
76
|
+
# def on_unless
|
77
|
+
# Does not exist.
|
78
|
+
# `unless` is parsed as an `if` with then_body and else_body swapped.
|
79
|
+
# Compare with `while` and `until` which cannot do that and thus need
|
80
|
+
# distinct node types.
|
81
|
+
# end
|
82
|
+
|
83
|
+
def on_case(node)
|
84
|
+
expr, *cases = *node
|
85
|
+
process(expr)
|
86
|
+
|
87
|
+
cases.each do |case_|
|
88
|
+
scopes.with_copy do
|
89
|
+
process(case_)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# clean slate
|
94
|
+
scope.clear
|
95
|
+
end
|
96
|
+
|
97
|
+
def on_lvasgn(node)
|
98
|
+
name, value = * node
|
99
|
+
return if value.nil? # and-asgn, or-asgn, resbody do this
|
100
|
+
scope[name].nice = nice(value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def on_and_asgn(node)
|
104
|
+
var, value = * node
|
105
|
+
return if var.type != :lvasgn
|
106
|
+
name = var.children[0]
|
107
|
+
|
108
|
+
scope[name].nice &&= nice(value)
|
109
|
+
end
|
110
|
+
|
111
|
+
def on_or_asgn(node)
|
112
|
+
var, value = * node
|
113
|
+
return if var.type != :lvasgn
|
114
|
+
name = var.children[0]
|
115
|
+
|
116
|
+
scope[name].nice ||= nice(value)
|
117
|
+
end
|
118
|
+
|
119
|
+
def on_send(node)
|
120
|
+
return unless call?(node, :Ops, :add)
|
121
|
+
|
122
|
+
_ops, method, a, b = *node
|
123
|
+
return if !(nice(a) && nice(b)) && safe_mode
|
124
|
+
|
125
|
+
add_offense(node, :selector, format(MSG, method))
|
126
|
+
end
|
127
|
+
|
128
|
+
def on_block(_node)
|
129
|
+
# ignore body, clean slate
|
130
|
+
scope.clear
|
131
|
+
end
|
132
|
+
alias_method :on_for, :on_block
|
133
|
+
|
134
|
+
def on_while(_node)
|
135
|
+
# ignore both condition and body,
|
136
|
+
# with a simplistic scope we cannot handle them
|
137
|
+
|
138
|
+
# clean slate
|
139
|
+
scope.clear
|
140
|
+
end
|
141
|
+
alias_method :on_until, :on_while
|
142
|
+
|
143
|
+
# Exceptions:
|
144
|
+
# `raise` is an ordinary :send for the parser
|
145
|
+
|
146
|
+
def on_rescue(node)
|
147
|
+
# (:rescue, begin-block, resbody..., else-block-or-nil)
|
148
|
+
_begin_body, *_rescue_bodies, _else_body = *node
|
149
|
+
|
150
|
+
# FIXME
|
151
|
+
# @source_rewriter.transaction do
|
152
|
+
# process(begin_body)
|
153
|
+
# process(else_body)
|
154
|
+
# rescue_bodies.each do |r|
|
155
|
+
# process(r)
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
# rescue TooComplexToTranslateError
|
159
|
+
# warning "begin-rescue is too complex to translate due to a retry"
|
160
|
+
# end
|
161
|
+
end
|
162
|
+
|
163
|
+
def on_resbody(_node)
|
164
|
+
# How it is parsed:
|
165
|
+
# (:resbody, exception-types-or-nil, exception-variable-or-nil, body)
|
166
|
+
# exception-types is an :array
|
167
|
+
# exception-variable is a (:lvasgn, name), without a value
|
168
|
+
|
169
|
+
# A rescue means that *some* previous code was skipped.
|
170
|
+
# We know nothing. We could process the resbodies individually,
|
171
|
+
# and join begin-block with else-block, but it is little worth
|
172
|
+
# because they will contain few zombies.
|
173
|
+
scope.clear
|
174
|
+
end
|
175
|
+
|
176
|
+
def on_ensure(_node)
|
177
|
+
# (:ensure, guarded-code, ensuring-code)
|
178
|
+
# guarded-code may be a :rescue or not
|
179
|
+
|
180
|
+
scope.clear
|
181
|
+
end
|
182
|
+
|
183
|
+
def on_retry(_node)
|
184
|
+
# that makes the :rescue a loop, top-down data-flow fails
|
185
|
+
# FIXME
|
186
|
+
# raise TooComplexToTranslateError
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def oops(node, exception)
|
192
|
+
puts "Node exception @ #{node.loc.expression}"
|
193
|
+
puts "Offending node: #{node.inspect}"
|
194
|
+
raise exception unless exception.is_a?(TooComplexToTranslateError)
|
195
|
+
end
|
196
|
+
|
197
|
+
def call?(node, namespace, message)
|
198
|
+
n_receiver, n_message = *node
|
199
|
+
n_receiver && n_receiver.type == :const &&
|
200
|
+
n_receiver.children[0].nil? &&
|
201
|
+
n_receiver.children[1] == namespace &&
|
202
|
+
n_message == message
|
203
|
+
end
|
204
|
+
|
205
|
+
def autocorrect(node)
|
206
|
+
@corrections << lambda do |corrector|
|
207
|
+
_ops, message, arg1, arg2 = *node
|
208
|
+
|
209
|
+
new_ops = REPLACEMENT[message]
|
210
|
+
return unless new_ops
|
211
|
+
|
212
|
+
corrector.replace(node.loc.expression,
|
213
|
+
ops_replacement(new_ops, arg1, arg2))
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def ops_replacement(new_ops, arg1, arg2)
|
218
|
+
"#{arg1.loc.expression.source} #{new_ops} " \
|
219
|
+
"#{arg2.loc.expression.source}"
|
220
|
+
end
|
221
|
+
|
222
|
+
attr_reader :scopes, :safe_mode
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Yast
|
7
|
+
# patch the Rubocop config - include the plugin defaults
|
8
|
+
module Config
|
9
|
+
DEFAULT = File.expand_path("../../../../config/default.yml", __FILE__)
|
10
|
+
|
11
|
+
def self.load_defaults
|
12
|
+
plugin_config = YAML.load_file(DEFAULT)
|
13
|
+
config = ConfigLoader.merge_with_default(plugin_config, DEFAULT)
|
14
|
+
|
15
|
+
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
# Niceness of a node means that it cannot be nil.
|
4
|
+
#
|
5
|
+
# Note that the module depends on the includer
|
6
|
+
# to provide #scope (for #nice_variable)
|
7
|
+
module Niceness
|
8
|
+
# Literals are nice, except the nil literal.
|
9
|
+
NICE_LITERAL_NODE_TYPES = [
|
10
|
+
:self,
|
11
|
+
:false, :true,
|
12
|
+
:int, :float,
|
13
|
+
:str, :sym, :regexp,
|
14
|
+
:array, :hash, :pair, :irange, # may contain nils but they are not nil
|
15
|
+
:dstr, # "String #{interpolation}" mixes :str, :begin
|
16
|
+
:dsym # :"#{foo}"
|
17
|
+
].to_set
|
18
|
+
|
19
|
+
def nice(node)
|
20
|
+
nice_literal(node) || nice_variable(node) || nice_send(node) ||
|
21
|
+
nice_begin(node)
|
22
|
+
end
|
23
|
+
|
24
|
+
def nice_literal(node)
|
25
|
+
NICE_LITERAL_NODE_TYPES.include? node.type
|
26
|
+
end
|
27
|
+
|
28
|
+
def nice_variable(node)
|
29
|
+
node.type == :lvar && scope[node.children.first].nice
|
30
|
+
end
|
31
|
+
|
32
|
+
# Methods that preserve niceness if all their arguments are nice
|
33
|
+
# These are global, called with a nil receiver
|
34
|
+
NICE_GLOBAL_METHODS = {
|
35
|
+
# message, number of arguments
|
36
|
+
_: 1
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
NICE_OPERATORS = {
|
40
|
+
# message, number of arguments (other than receiver)
|
41
|
+
:+ => 1
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
def nice_send(node)
|
45
|
+
return false unless node.type == :send
|
46
|
+
receiver, message, *args = *node
|
47
|
+
|
48
|
+
if receiver.nil?
|
49
|
+
arity = NICE_GLOBAL_METHODS.fetch(message, -1)
|
50
|
+
else
|
51
|
+
return false unless nice(receiver)
|
52
|
+
arity = NICE_OPERATORS.fetch(message, -1)
|
53
|
+
end
|
54
|
+
args.size == arity && args.all? { |a| nice(a) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def nice_begin(node)
|
58
|
+
node.type == :begin && nice(node.children.last)
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Tracks state for a variable
|
2
|
+
class VariableState
|
3
|
+
attr_accessor :nice
|
4
|
+
end
|
5
|
+
|
6
|
+
# Tracks state for local variables visible at certain point.
|
7
|
+
# Keys are symbols, values are VariableState
|
8
|
+
class VariableScope < Hash
|
9
|
+
def initialize
|
10
|
+
super do |hash, key|
|
11
|
+
hash[key] = VariableState.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Deep copy the VariableState values
|
16
|
+
def dup
|
17
|
+
copy = self.class.new
|
18
|
+
each do |k, v|
|
19
|
+
copy[k] = v.dup
|
20
|
+
end
|
21
|
+
copy
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [VariableState] state
|
25
|
+
def [](varname)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set state for a variable
|
30
|
+
def []=(varname, state)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# A stack of VariableScope
|
36
|
+
class VariableScopeStack
|
37
|
+
def initialize
|
38
|
+
outer_scope = VariableScope.new
|
39
|
+
@stack = [outer_scope]
|
40
|
+
end
|
41
|
+
|
42
|
+
# The innermost, or current VariableScope
|
43
|
+
def innermost
|
44
|
+
@stack.last
|
45
|
+
end
|
46
|
+
|
47
|
+
# Run *block* using a new clean scope
|
48
|
+
# @return the scope as the block left it, popped from the stack
|
49
|
+
def with_new(&block)
|
50
|
+
@stack.push VariableScope.new
|
51
|
+
block.call
|
52
|
+
@stack.pop
|
53
|
+
end
|
54
|
+
|
55
|
+
# Run *block* using a copy of the innermost scope
|
56
|
+
# @return the scope as the block left it, popped from the stack
|
57
|
+
def with_copy(&block)
|
58
|
+
@stack.push innermost.dup
|
59
|
+
block.call
|
60
|
+
@stack.pop
|
61
|
+
end
|
62
|
+
end
|
data/lib/rubocop/yast/version.rb
CHANGED
data/rubocop-yast.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
spec.files = Dir[
|
22
|
-
"{lib,spec}/**/*",
|
22
|
+
"{config,lib,spec}/**/*",
|
23
23
|
"*.md",
|
24
24
|
"*.gemspec",
|
25
25
|
"Gemfile",
|
@@ -28,7 +28,8 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.test_files = spec.files.grep(/^spec\//)
|
29
29
|
spec.extra_rdoc_files = ["LICENSE", "README.md"]
|
30
30
|
|
31
|
-
spec.
|
31
|
+
spec.add_runtime_dependency("rubocop", "~> 0.27")
|
32
|
+
|
32
33
|
spec.add_development_dependency("rake")
|
33
34
|
spec.add_development_dependency("rspec", "~> 3.1.0")
|
34
35
|
spec.add_development_dependency("simplecov")
|
data/spec/builtins_spec.rb
CHANGED
@@ -6,7 +6,7 @@ def expect_y2milestone_offense(cop)
|
|
6
6
|
expect(cop.offenses.size).to eq(1)
|
7
7
|
expect(cop.offenses.first.line).to eq(1)
|
8
8
|
expect(cop.messages).to eq(["Builtin call `y2milestone` is obsolete, " \
|
9
|
-
|
9
|
+
"use native Ruby function instead."])
|
10
10
|
end
|
11
11
|
|
12
12
|
describe RuboCop::Cop::Yast::Builtins do
|
@@ -48,4 +48,18 @@ describe RuboCop::Cop::Yast::Builtins do
|
|
48
48
|
expect(cop.offenses).to be_empty
|
49
49
|
end
|
50
50
|
|
51
|
+
it "auto-corrects Builtins.time with ::Time.now.to_i" do
|
52
|
+
new_source = autocorrect_source(cop, "Builtins.time")
|
53
|
+
expect(new_source).to eq("::Time.now.to_i")
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'auto-corrects Builtins.getenv("foo") with ENV["foo"]' do
|
57
|
+
new_source = autocorrect_source(cop, 'Builtins.getenv("foo")')
|
58
|
+
expect(new_source).to eq('ENV["foo"]')
|
59
|
+
end
|
60
|
+
|
61
|
+
it "auto-corrects Builtins.getenv(foo) with ENV[foo]" do
|
62
|
+
new_source = autocorrect_source(cop, "Builtins.getenv(foo)")
|
63
|
+
expect(new_source).to eq("ENV[foo]")
|
64
|
+
end
|
51
65
|
end
|
data/spec/ops_spec.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
def config(safe_mode: true)
|
6
|
+
conf = { "Yast/Ops" => { "SafeMode" => safe_mode } }
|
7
|
+
RuboCop::Config.new(conf)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe RuboCop::Cop::Yast::Ops do
|
11
|
+
context("In safe mode") do
|
12
|
+
subject(:cop) { described_class.new(config(safe_mode: true)) }
|
13
|
+
|
14
|
+
it "finds trivial Ops.add call" do
|
15
|
+
inspect_source(cop, ["Ops.add(2, 4)"])
|
16
|
+
|
17
|
+
expect(cop.offenses.size).to eq(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "finds Ops.add call with variable" do
|
21
|
+
inspect_source(cop, ["foo = 2\n Ops.add(foo, 4)"])
|
22
|
+
|
23
|
+
expect(cop.offenses.size).to eq(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "finds Ops.add call with variable inside condition" do
|
27
|
+
inspect_source(cop, ["foo = 1\nif true\nOps.add(foo, 4)\nend"])
|
28
|
+
|
29
|
+
expect(cop.offenses.size).to eq(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "ignores unsafe calls" do
|
33
|
+
inspect_source(cop, ["if true\nOps.add(foo, 4)\nend"])
|
34
|
+
|
35
|
+
expect(cop.offenses).to be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
# check that all node types are handled properly
|
39
|
+
it "parses complex code" do
|
40
|
+
src = <<-EOF
|
41
|
+
module Foo
|
42
|
+
class Bar
|
43
|
+
def baz(arg)
|
44
|
+
case arg
|
45
|
+
when :foo
|
46
|
+
a &&= true
|
47
|
+
b ||= true
|
48
|
+
end
|
49
|
+
rescue e
|
50
|
+
while false
|
51
|
+
find.foo do
|
52
|
+
end
|
53
|
+
retry
|
54
|
+
end
|
55
|
+
ensure
|
56
|
+
sure
|
57
|
+
end
|
58
|
+
class << foo
|
59
|
+
end
|
60
|
+
def self.foo
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
EOF
|
65
|
+
|
66
|
+
inspect_source(cop, src)
|
67
|
+
|
68
|
+
expect(cop.offenses).to be_empty
|
69
|
+
end
|
70
|
+
|
71
|
+
it "auto-corrects Ops.add(2, 4) with 2 + 4" do
|
72
|
+
new_source = autocorrect_source(cop, "Ops.add(2, 4)")
|
73
|
+
expect(new_source).to eq("2 + 4")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "auto-corrects Ops.add(a, b) with a + b" do
|
77
|
+
new_source = autocorrect_source(cop, "a = 1; b = 2; Ops.add(a, b)")
|
78
|
+
expect(new_source).to eq("a = 1; b = 2; a + b")
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'auto-corrects Ops.add("foo", "bar") with "foo" + "bar"' do
|
82
|
+
new_source = autocorrect_source(cop, 'Ops.add("foo", "bar")')
|
83
|
+
expect(new_source).to eq('"foo" + "bar"')
|
84
|
+
end
|
85
|
+
|
86
|
+
# FIXME: auto-correct does not work work recursively
|
87
|
+
xit "auto-corrects nested Ops.add calls" do
|
88
|
+
new_source = autocorrect_source(cop,
|
89
|
+
'Ops.add("foo", Ops.add("bar", "baz"))')
|
90
|
+
expect(new_source).to eq('"foo" + "bar + baz"')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "keeps unsafe call Ops.add(foo, bar)" do
|
94
|
+
source = "foo = 1; Ops.add(foo, bar)"
|
95
|
+
new_source = autocorrect_source(cop, source)
|
96
|
+
expect(new_source).to eq(source)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context("In unsafe mode") do
|
102
|
+
subject(:cop) { described_class.new(config(safe_mode: false)) }
|
103
|
+
|
104
|
+
it "finds unsafe Ops.add calls" do
|
105
|
+
inspect_source(cop, ["if true\nOps.add(foo, 4)\nend"])
|
106
|
+
|
107
|
+
expect(cop.offenses.size).to eq(1)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "auto-corrects unsafe call Ops.add(foo, bar) with foo + bar" do
|
111
|
+
new_source = autocorrect_source(cop, "Ops.add(foo, bar)")
|
112
|
+
expect(new_source).to eq("foo + bar")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-yast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ladislav Slezák
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -17,7 +17,7 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.27'
|
20
|
-
type: :
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
@@ -81,11 +81,17 @@ files:
|
|
81
81
|
- LICENSE
|
82
82
|
- README.md
|
83
83
|
- Rakefile
|
84
|
+
- config/default.yml
|
84
85
|
- lib/rubocop-yast.rb
|
85
86
|
- lib/rubocop/cop/yast/builtins.rb
|
87
|
+
- lib/rubocop/cop/yast/ops.rb
|
88
|
+
- lib/rubocop/yast/config.rb
|
89
|
+
- lib/rubocop/yast/niceness.rb
|
90
|
+
- lib/rubocop/yast/variable_scope.rb
|
86
91
|
- lib/rubocop/yast/version.rb
|
87
92
|
- rubocop-yast.gemspec
|
88
93
|
- spec/builtins_spec.rb
|
94
|
+
- spec/ops_spec.rb
|
89
95
|
- spec/spec_helper.rb
|
90
96
|
homepage: http://github.com/yast/rubocop-yast
|
91
97
|
licenses:
|
@@ -113,4 +119,5 @@ specification_version: 4
|
|
113
119
|
summary: Specific YaST Rubocop checks
|
114
120
|
test_files:
|
115
121
|
- spec/builtins_spec.rb
|
122
|
+
- spec/ops_spec.rb
|
116
123
|
- spec/spec_helper.rb
|