rubocop-yast 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c16c03c56b76dc2b1b8896fda2f2d5765d686c41
4
- data.tar.gz: 695426ba9cb0fd0ff1d273d337c3947f8a785b80
3
+ metadata.gz: 8f14f2792588ff28f55867a356603deeeafe6deb
4
+ data.tar.gz: 03433493409f9d50a333391b4e05c8782a525064
5
5
  SHA512:
6
- metadata.gz: 5d69f1ac5711c04993f135091ea1ea1d6ac4159c579a45afe7d3c783f6650416af0aef1b4819ec0a0033dfc140fd1ad54f4e994332ef389905096fad1de8ca94
7
- data.tar.gz: 5bd8f3cd68cdbd225c148eec3082914ff9c4345926bf14b0819f9d61b39a857277e0be03deebffb2192ee6a3a520d051935a65ea7695c28f13dbd0adc6478d2b
6
+ metadata.gz: 3fed38028da0bd94e103e5a5091e1723857c3c5b1995216fa175f8dc6fadaefc81f77f6182abf80a6cbe7c5e7b41fda716f44150ce6a4dc3aa2a599b7cec01f6
7
+ data.tar.gz: 32e08248270ec322da28aabf4ff9fa27fc8be17729b3b64d92336106e92cf946a65d3462c4634cca7467ace025eba6ffe41b593aff467af02d09f38c16bd3d8c
data/Gemfile CHANGED
@@ -6,4 +6,5 @@ gemspec
6
6
 
7
7
  group :test do
8
8
  gem "coveralls", require: false if ENV["TRAVIS"]
9
+ gem "byebug", require: false if ENV["DEBUGGER"]
9
10
  end
data/README.md CHANGED
@@ -9,3 +9,125 @@ rubocop-yast
9
9
  [![Inline docs](http://inch-ci.org/github/lslezak/rubocop-yast.svg?branch=master)](http://inch-ci.org/github/lslezak/rubocop-yast)
10
10
 
11
11
 
12
+ This is a plugin for [RuboCop](https://github.com/bbatsov/rubocop)
13
+ a Ruby static code analyzer. It was inspired by [Rubocop-Rspec](https://github.com/nevir/rubocop-rspec)
14
+ and [YCP Zombie Killer](https://github.com/yast/zombie-killer).
15
+
16
+ The goal is to create a Rubocop plugin which can check for
17
+ [YaST](http://yast.github.io/) specific issues. Optionally it should allow to
18
+ covert some ugly code parts introduced by the automatic code conversion done by
19
+ [YCP Killer](https://github.com/yast/ycp-killer) (conversion from YCP to Ruby).
20
+
21
+ Check [the test descriptions](spec/builtins_spec.md) to see the examples of offense
22
+ detection and code conversion.
23
+
24
+ *The plugin is currently in early development, always manually check the chages
25
+ done by the plugin! It can eat your code... ;-)*
26
+
27
+
28
+ Installation
29
+ ------------
30
+
31
+ The plugin is published at [rubygems.org](https://rubygems.org/gems/rubocop-yast),
32
+ you can install it using the `gem` command:
33
+
34
+ ```shell
35
+ sudo gem install rubocop-yast
36
+ ```
37
+
38
+ Usage
39
+ -----
40
+
41
+ You need to manually load the Yast plugin into RuboCop to run the extra checks.
42
+ There are two options:
43
+
44
+ - Use `--require rubocop-yast` command line option when invoking `rubocop`
45
+ - Enable the plugin in `.rubocop.yml` file:
46
+ ```yaml
47
+ require:
48
+ - rubocop-yast
49
+ ```
50
+
51
+ See the [RuboCop documentation](https://github.com/bbatsov/rubocop#loading-extensions).
52
+
53
+ Configuration
54
+ -------------
55
+
56
+ You can configure Rubocop-Yast the same way as the standard RuboCop checks
57
+ (see the [RuboCop configuration](https://github.com/bbatsov/rubocop#configuration)):
58
+
59
+ ```yaml
60
+ # Check for obsolete Builtins.* calls
61
+ Yast/Builtins:
62
+ Enabled: true
63
+
64
+ # Check for obsolete Ops.* calls
65
+ Yast/Ops:
66
+ Enabled: true
67
+ # in the safe mode only safe places are reported and fixed
68
+ SafeMode: true
69
+ ```
70
+
71
+ Development
72
+ -----------
73
+
74
+ ### Prerequisites
75
+
76
+ For development you need some extra development gems. The best way is to install them with [Bundler](http://bundler.io/). To avoid a possible collision with system gems it is recommended
77
+ to install the gems into a local subdirectory using
78
+
79
+ ```shell
80
+ bundle install --path vendor/bundle
81
+ ```
82
+
83
+ ### Source Directories
84
+
85
+ * [`config/default.yml`](config/default.yml) contains the default Cop configurations
86
+ * [`lib/rubocop/cop/yast`](lib/rubocop/yast) contains Yast Cops (the checks which are called
87
+ from the main rubocop script)
88
+ * [`lib/rubocop/yast`](lib/rubocop/yast) contains libraries used by the Cops
89
+ * [`spec`](spec) contains tests, some tests are automatically generated from a MarkDown
90
+ documentation
91
+
92
+ ### Running Tests
93
+
94
+ ```
95
+ bundle exec rake
96
+ ```
97
+
98
+ By default the tests check the code coverage, if it is below 95% the test fails although
99
+ there was no test failure.
100
+
101
+ ### Autocorrecting Rubocop Issues
102
+
103
+ ```
104
+ bundle exec rake rubocop:auto_correct
105
+ ```
106
+
107
+ You can also load the plugin itself to verify that plugin loading works correctly.
108
+ (Plugin loading is not covered by tests as it needs the base Rubocop framework.)
109
+
110
+ ```
111
+ bundle exec rubocop -r rubocop-yast
112
+ ```
113
+
114
+ ### Building a Gem
115
+
116
+ ```
117
+ bundle exec rake build
118
+ ```
119
+
120
+ This builds `pkg/rubocop-yast-<version>.gem` gem file, it can be installed locally using
121
+ ```
122
+ sudo gem install --local pkg/rubocop-yast-<version>.gem
123
+ ```
124
+
125
+ ### Publishing the Gem to Rubygems.org
126
+
127
+ Increase the version in [`lib/rubocop/yast/version.rb`](lib/rubocop/yast/version.rb) file
128
+ and then run:
129
+
130
+ ```
131
+ bundle exec rake release
132
+ ```
133
+
data/Rakefile CHANGED
@@ -10,8 +10,32 @@ rescue Bundler::BundlerError => e
10
10
  exit e.status_code
11
11
  end
12
12
 
13
+ require "redcarpet"
14
+ require_relative "spec/rspec_renderer"
15
+
16
+ def render_markdown(renderer_class, task)
17
+ puts "Rendering file: #{task.name}"
18
+ markdown = Redcarpet::Markdown.new(renderer_class, fenced_code_blocks: true)
19
+
20
+ string = markdown.render(File.read(task.prerequisites[0]))
21
+ File.write(task.name, string)
22
+ end
23
+
24
+ renderer = "spec/rspec_renderer.rb"
25
+
26
+ file "spec/builtins_spec.rb" => ["spec/builtins_spec.md", renderer] do |t|
27
+ render_markdown(RSpecRenderer, t)
28
+ end
29
+
30
+ file "spec/builtins_spec.html" => ["spec/builtins_spec.md", renderer] do |t|
31
+ render_markdown(Redcarpet::Render::HTML, t)
32
+ end
33
+ desc "Render the specification to HTML locally"
34
+ task html: ["spec/builtins_spec.html"]
35
+
13
36
  require "rspec/core/rake_task"
14
37
  RSpec::Core::RakeTask.new(:spec)
38
+ task spec: ["spec/builtins_spec.rb"]
15
39
 
16
40
  require "rubocop/rake_task"
17
41
  RuboCop::RakeTask.new(:rubocop)
@@ -1,5 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require "rubocop/yast/builtins/builtin"
4
+ require "rubocop/yast/builtins/getenv"
5
+ require "rubocop/yast/builtins/time"
6
+ require "rubocop/yast/builtins/y2log"
7
+
3
8
  module RuboCop
4
9
  module Cop
5
10
  module Yast
@@ -7,23 +12,9 @@ module RuboCop
7
12
  class Builtins < Cop
8
13
  include AST::Sexp
9
14
 
10
- MSG = "Builtin call `%s` is obsolete, use native Ruby function instead."
15
+ attr_reader :handlers, :default_handler
11
16
 
12
- # white list of allowed Builtins calls
13
- ALLOWED_FUNCTIONS = [
14
- # locale dependent sorting in not available in Ruby stdlib
15
- :lsort,
16
- # gettext helpers
17
- :dgettext,
18
- :dngettext,
19
- :dpgettext,
20
- # crypt* helpers
21
- :crypt,
22
- :cryptmd5,
23
- :cryptblowfish,
24
- :cryptsha256,
25
- :cryptsha512
26
- ]
17
+ MSG = "Builtin call `%s` is obsolete, use native Ruby function instead."
27
18
 
28
19
  BUILTINS_NODES = [
29
20
  # Builtins.*
@@ -34,34 +25,52 @@ module RuboCop
34
25
  s(:const, s(:const, s(:cbase), :Yast), :Builtins)
35
26
  ]
36
27
 
28
+ def initialize(config = nil, options = nil)
29
+ super(config, options)
30
+
31
+ @handlers = builtin_mapping
32
+ @default_handler = RuboCop::Yast::Builtins::Builtin.new
33
+ end
34
+
37
35
  def on_send(node)
38
36
  receiver, method_name, *_args = *node
39
37
 
38
+ # not an Yast builtin call or not an offense
40
39
  return if !BUILTINS_NODES.include?(receiver) ||
41
- ALLOWED_FUNCTIONS.include?(method_name)
40
+ !builtin_handler(method_name).offense?(node)
42
41
 
43
42
  add_offense(node, :selector, format(MSG, method_name))
44
43
  end
45
44
 
46
45
  def autocorrect(node)
47
- @corrections << lambda do |corrector|
48
- _builtins, message, args = *node
49
-
50
- new_code = builtins_replacement(message, args)
46
+ _builtins, method_name, *_args = *node
51
47
 
52
- corrector.replace(node.loc.expression, new_code) if new_code
53
- end
48
+ @corrections << builtin_handler(method_name).correction(node)
54
49
  end
55
50
 
56
51
  private
57
52
 
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
53
+ # rubocop:disable Metrics/MethodLength
54
+ def builtin_mapping
55
+ # use the same instance for all logging functions
56
+ logging = RuboCop::Yast::Builtins::Y2log.new
57
+
58
+ {
59
+ y2debug: logging,
60
+ y2milestone: logging,
61
+ y2warning: logging,
62
+ y2error: logging,
63
+ y2security: logging,
64
+ y2internal: logging,
65
+
66
+ getenv: RuboCop::Yast::Builtins::Getenv.new,
67
+ time: RuboCop::Yast::Builtins::Time.new
68
+ }
69
+ end
70
+ # rubocop:enable Metrics/MethodLength
71
+
72
+ def builtin_handler(method)
73
+ handlers[method] || default_handler
65
74
  end
66
75
  end
67
76
  end
@@ -1,7 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "rubocop/yast/niceness"
4
- require "rubocop/yast/variable_scope"
3
+ require "rubocop/yast/track_variable_scope"
5
4
 
6
5
  # We have encountered code that does satisfy our simplifying assumptions,
7
6
  # translating it would not be correct.
@@ -14,7 +13,7 @@ module RuboCop
14
13
  # This cop checks for Ops.* calls, it can autocorrect safe places or
15
14
  # all places in unsafe mode
16
15
  class Ops < Cop
17
- include Niceness
16
+ include RuboCop::Yast::TrackVariableScope
18
17
 
19
18
  # Ops replacement mapping
20
19
  REPLACEMENT = {
@@ -26,96 +25,10 @@ module RuboCop
26
25
  def initialize(config = nil, options = nil)
27
26
  super(config, options)
28
27
 
29
- @scopes = VariableScopeStack.new
30
28
  @safe_mode = cop_config["SafeMode"]
31
29
  @replaced_nodes = []
32
30
  end
33
31
 
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
32
  def on_send(node)
120
33
  return unless call?(node, :Ops, :add)
121
34
 
@@ -125,75 +38,8 @@ module RuboCop
125
38
  add_offense(node, :selector, format(MSG, method))
126
39
  end
127
40
 
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
41
  private
190
42
 
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
43
  def call?(node, namespace, message)
198
44
  n_receiver, n_message = *node
199
45
  n_receiver && n_receiver.type == :const &&
@@ -219,7 +65,7 @@ module RuboCop
219
65
  "#{arg2.loc.expression.source}"
220
66
  end
221
67
 
222
- attr_reader :scopes, :safe_mode
68
+ attr_reader :safe_mode
223
69
  end
224
70
  end
225
71
  end