rubocop-sketchup 0.5.0 → 0.6.0
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/Gemfile +19 -19
- data/assets/output.html.erb +301 -301
- data/config/default.yml +355 -355
- data/lib/rubocop/sketchup/config.rb +63 -63
- data/lib/rubocop/sketchup/cop/deprecations/add_separator_to_menu.rb +25 -25
- data/lib/rubocop/sketchup/cop/deprecations/operation_next_transparent.rb +30 -30
- data/lib/rubocop/sketchup/cop/deprecations/require_all.rb +27 -27
- data/lib/rubocop/sketchup/cop/deprecations/set_texture_projection.rb +26 -26
- data/lib/rubocop/sketchup/cop/deprecations/show_ruby_panel.rb +25 -25
- data/lib/rubocop/sketchup/cop/deprecations/sketchup_set.rb +30 -30
- data/lib/rubocop/sketchup/cop/performance/openssl.rb +41 -41
- data/lib/rubocop/sketchup/cop/performance/operation_disable_ui.rb +33 -33
- data/lib/rubocop/sketchup/cop/performance/selection_bulk.rb +79 -79
- data/lib/rubocop/sketchup/cop/performance/type_check.rb +63 -63
- data/lib/rubocop/sketchup/cop/performance/typename.rb +24 -24
- data/lib/rubocop/sketchup/cop/requirements/api_namespace.rb +30 -30
- data/lib/rubocop/sketchup/cop/requirements/exit.rb +32 -32
- data/lib/rubocop/sketchup/cop/requirements/extension_namespace.rb +108 -108
- data/lib/rubocop/sketchup/cop/requirements/file_structure.rb +97 -97
- data/lib/rubocop/sketchup/cop/requirements/gem_install.rb +45 -45
- data/lib/rubocop/sketchup/cop/requirements/get_extension_license.rb +95 -95
- data/lib/rubocop/sketchup/cop/requirements/global_constants.rb +38 -38
- data/lib/rubocop/sketchup/cop/requirements/global_include.rb +42 -42
- data/lib/rubocop/sketchup/cop/requirements/global_methods.rb +65 -65
- data/lib/rubocop/sketchup/cop/requirements/global_variables.rb +95 -95
- data/lib/rubocop/sketchup/cop/requirements/language_handler_globals.rb +46 -46
- data/lib/rubocop/sketchup/cop/requirements/load_path.rb +83 -83
- data/lib/rubocop/sketchup/cop/requirements/minimal_registration.rb +73 -73
- data/lib/rubocop/sketchup/cop/requirements/observers_start_operation.rb +161 -161
- data/lib/rubocop/sketchup/cop/requirements/register_extension.rb +45 -45
- data/lib/rubocop/sketchup/cop/requirements/ruby_core_namespace.rb +291 -291
- data/lib/rubocop/sketchup/cop/requirements/ruby_stdlib_namespace.rb +634 -634
- data/lib/rubocop/sketchup/cop/requirements/shipped_extensions_namespace.rb +61 -61
- data/lib/rubocop/sketchup/cop/requirements/sketchup_extension.rb +119 -119
- data/lib/rubocop/sketchup/cop/requirements/sketchup_require.rb +163 -163
- data/lib/rubocop/sketchup/cop/suggestions/add_group.rb +49 -49
- data/lib/rubocop/sketchup/cop/suggestions/compatibility.rb +117 -117
- data/lib/rubocop/sketchup/cop/suggestions/dc_internals.rb +34 -34
- data/lib/rubocop/sketchup/cop/suggestions/file_encoding.rb +78 -78
- data/lib/rubocop/sketchup/cop/suggestions/model_entities.rb +58 -58
- data/lib/rubocop/sketchup/cop/suggestions/monkey_patched_api.rb +45 -45
- data/lib/rubocop/sketchup/cop/suggestions/operation_name.rb +103 -103
- data/lib/rubocop/sketchup/cop/suggestions/sketchup_find_support_file.rb +39 -39
- data/lib/rubocop/sketchup/cop/suggestions/tool_drawing_bounds.rb +44 -44
- data/lib/rubocop/sketchup/cop/suggestions/tool_invalidate.rb +66 -66
- data/lib/rubocop/sketchup/cop/suggestions/tool_user_input.rb +41 -41
- data/lib/rubocop/sketchup/cop/suggestions/toolbar_timer.rb +65 -65
- data/lib/rubocop/sketchup/cop.rb +111 -111
- data/lib/rubocop/sketchup/dc_globals.rb +24 -24
- data/lib/rubocop/sketchup/dc_methods.rb +130 -130
- data/lib/rubocop/sketchup/extension_project.rb +65 -65
- data/lib/rubocop/sketchup/features.rb +738 -738
- data/lib/rubocop/sketchup/formatter/extension_review.rb +259 -259
- data/lib/rubocop/sketchup/inject.rb +19 -19
- data/lib/rubocop/sketchup/namespace.rb +47 -47
- data/lib/rubocop/sketchup/namespace_checker.rb +46 -46
- data/lib/rubocop/sketchup/no_comment_disable.rb +17 -17
- data/lib/rubocop/sketchup/range_help.rb +52 -52
- data/lib/rubocop/sketchup/sketchup_version.rb +87 -87
- data/lib/rubocop/sketchup/tool_checker.rb +43 -43
- data/lib/rubocop/sketchup/version.rb +5 -5
- data/lib/rubocop/sketchup.rb +12 -12
- data/lib/rubocop-sketchup.rb +48 -48
- data/rubocop-sketchup.gemspec +27 -27
- metadata +4 -4
@@ -1,34 +1,34 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module SketchupSuggestions
|
6
|
-
# Tapping into the internals of Dynamic Components is risky. It could
|
7
|
-
# change at any time. If you create an extension that depend on the
|
8
|
-
# internal logic of another extension you are at the mercy of change and
|
9
|
-
# luck!
|
10
|
-
class DynamicComponentInternals < SketchUp::Cop
|
11
|
-
|
12
|
-
include SketchUp::DynamicComponentGlobals
|
13
|
-
|
14
|
-
MSG = 'Avoid relying on internal logic of Dynamic Components.'.freeze
|
15
|
-
|
16
|
-
def on_gvar(node)
|
17
|
-
check_global(node)
|
18
|
-
end
|
19
|
-
|
20
|
-
def on_gvasgn(node)
|
21
|
-
check_global(node)
|
22
|
-
end
|
23
|
-
|
24
|
-
def check_global(node)
|
25
|
-
global_var, = *node
|
26
|
-
return unless dc_global_var?(global_var)
|
27
|
-
|
28
|
-
add_offense(node, location: :name, severity: :warning)
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Tapping into the internals of Dynamic Components is risky. It could
|
7
|
+
# change at any time. If you create an extension that depend on the
|
8
|
+
# internal logic of another extension you are at the mercy of change and
|
9
|
+
# luck!
|
10
|
+
class DynamicComponentInternals < SketchUp::Cop
|
11
|
+
|
12
|
+
include SketchUp::DynamicComponentGlobals
|
13
|
+
|
14
|
+
MSG = 'Avoid relying on internal logic of Dynamic Components.'.freeze
|
15
|
+
|
16
|
+
def on_gvar(node)
|
17
|
+
check_global(node)
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_gvasgn(node)
|
21
|
+
check_global(node)
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_global(node)
|
25
|
+
global_var, = *node
|
26
|
+
return unless dc_global_var?(global_var)
|
27
|
+
|
28
|
+
add_offense(node, location: :name, severity: :warning)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,78 +1,78 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module SketchupSuggestions
|
6
|
-
# When using __FILE__ and __dir__, beware that Ruby doesn't apply the
|
7
|
-
# correct encoding to the strings under Windows. When they contain
|
8
|
-
# non-english characters it will lead to exceptions being raised when the
|
9
|
-
# strings are used. Force encoding to work around this.
|
10
|
-
#
|
11
|
-
# @example Might fail
|
12
|
-
# basename = File.basename(__FILE__, '.*')
|
13
|
-
#
|
14
|
-
# @example Workaround
|
15
|
-
# file = __FILE__.dup
|
16
|
-
# file.force_encoding('UTF-8') if file.respond_to?(:force_encoding)
|
17
|
-
# basename = File.basename(file, '.*')
|
18
|
-
class FileEncoding < SketchUp::Cop
|
19
|
-
|
20
|
-
MSG = 'Beware encoding bug with `__FILE__` and `__dir__`.'.freeze
|
21
|
-
|
22
|
-
def_node_matcher :file_loaded?, <<-PATTERN
|
23
|
-
(send nil? {:file_loaded? :file_loaded} ...)
|
24
|
-
PATTERN
|
25
|
-
|
26
|
-
def_node_matcher :magic_dir?, <<-PATTERN
|
27
|
-
(send nil? :__dir__)
|
28
|
-
PATTERN
|
29
|
-
|
30
|
-
def magic_file?(node)
|
31
|
-
node.respond_to?(:str_type?) &&
|
32
|
-
node.str_type? &&
|
33
|
-
node.source_range.is?('__FILE__')
|
34
|
-
end
|
35
|
-
|
36
|
-
def magic_file_or_dir?(node)
|
37
|
-
magic_file?(node) || magic_dir?(node)
|
38
|
-
end
|
39
|
-
|
40
|
-
def on_send(node)
|
41
|
-
return if file_loaded?(node)
|
42
|
-
return if node.arguments.none?(&method(:magic_file_or_dir?))
|
43
|
-
|
44
|
-
add_offense(node, location: :expression)
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
def_node_search :force_encoding, <<-PATTERN
|
49
|
-
(send ({lvar ivar cvar} $_) :force_encoding ...)
|
50
|
-
PATTERN
|
51
|
-
|
52
|
-
def on_assign(node)
|
53
|
-
lhs, value = *node
|
54
|
-
return unless magic_file_or_dir?(value)
|
55
|
-
# After assigning __FILE__ or __dir_ to a variable, check the parent
|
56
|
-
# scope to whether .force_encoding is called on the variable.
|
57
|
-
return if node.parent.nil?
|
58
|
-
|
59
|
-
encoded = force_encoding(node.parent).to_a
|
60
|
-
return if encoded.include?(lhs)
|
61
|
-
|
62
|
-
add_offense(node)
|
63
|
-
end
|
64
|
-
|
65
|
-
alias on_lvasgn on_assign
|
66
|
-
alias on_masgn on_assign
|
67
|
-
alias on_casgn on_assign
|
68
|
-
alias on_ivasgn on_assign
|
69
|
-
alias on_cvasgn on_assign
|
70
|
-
alias on_gvasgn on_assign
|
71
|
-
alias on_or_asgn on_assign
|
72
|
-
alias on_and_asgn on_assign
|
73
|
-
alias on_op_asgn on_assign
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# When using __FILE__ and __dir__, beware that Ruby doesn't apply the
|
7
|
+
# correct encoding to the strings under Windows. When they contain
|
8
|
+
# non-english characters it will lead to exceptions being raised when the
|
9
|
+
# strings are used. Force encoding to work around this.
|
10
|
+
#
|
11
|
+
# @example Might fail
|
12
|
+
# basename = File.basename(__FILE__, '.*')
|
13
|
+
#
|
14
|
+
# @example Workaround
|
15
|
+
# file = __FILE__.dup
|
16
|
+
# file.force_encoding('UTF-8') if file.respond_to?(:force_encoding)
|
17
|
+
# basename = File.basename(file, '.*')
|
18
|
+
class FileEncoding < SketchUp::Cop
|
19
|
+
|
20
|
+
MSG = 'Beware encoding bug with `__FILE__` and `__dir__`.'.freeze
|
21
|
+
|
22
|
+
def_node_matcher :file_loaded?, <<-PATTERN
|
23
|
+
(send nil? {:file_loaded? :file_loaded} ...)
|
24
|
+
PATTERN
|
25
|
+
|
26
|
+
def_node_matcher :magic_dir?, <<-PATTERN
|
27
|
+
(send nil? :__dir__)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def magic_file?(node)
|
31
|
+
node.respond_to?(:str_type?) &&
|
32
|
+
node.str_type? &&
|
33
|
+
node.source_range.is?('__FILE__')
|
34
|
+
end
|
35
|
+
|
36
|
+
def magic_file_or_dir?(node)
|
37
|
+
magic_file?(node) || magic_dir?(node)
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
return if file_loaded?(node)
|
42
|
+
return if node.arguments.none?(&method(:magic_file_or_dir?))
|
43
|
+
|
44
|
+
add_offense(node, location: :expression)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def_node_search :force_encoding, <<-PATTERN
|
49
|
+
(send ({lvar ivar cvar} $_) :force_encoding ...)
|
50
|
+
PATTERN
|
51
|
+
|
52
|
+
def on_assign(node)
|
53
|
+
lhs, value = *node
|
54
|
+
return unless magic_file_or_dir?(value)
|
55
|
+
# After assigning __FILE__ or __dir_ to a variable, check the parent
|
56
|
+
# scope to whether .force_encoding is called on the variable.
|
57
|
+
return if node.parent.nil?
|
58
|
+
|
59
|
+
encoded = force_encoding(node.parent).to_a
|
60
|
+
return if encoded.include?(lhs)
|
61
|
+
|
62
|
+
add_offense(node)
|
63
|
+
end
|
64
|
+
|
65
|
+
alias on_lvasgn on_assign
|
66
|
+
alias on_masgn on_assign
|
67
|
+
alias on_casgn on_assign
|
68
|
+
alias on_ivasgn on_assign
|
69
|
+
alias on_cvasgn on_assign
|
70
|
+
alias on_gvasgn on_assign
|
71
|
+
alias on_or_asgn on_assign
|
72
|
+
alias on_and_asgn on_assign
|
73
|
+
alias on_op_asgn on_assign
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,58 +1,58 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module SketchupSuggestions
|
6
|
-
# Prefer `model.active_entities` over `model.entities`.
|
7
|
-
#
|
8
|
-
# Most tools/actions act upon the active entities context. This could be
|
9
|
-
# an opened group or component instance. Because of this, prefer
|
10
|
-
# `model.active_entities` by default over `model.entities` unless you
|
11
|
-
# have an explicit reason to work in the root model context.
|
12
|
-
class ModelEntities < SketchUp::Cop
|
13
|
-
|
14
|
-
MSG = 'Prefer `model.active_entities` over `model.entities`.'.freeze
|
15
|
-
|
16
|
-
# Reference: http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
17
|
-
def_node_matcher :active_model_entities?, <<-PATTERN
|
18
|
-
(send
|
19
|
-
(send (const nil? :Sketchup) :active_model) :entities)
|
20
|
-
PATTERN
|
21
|
-
|
22
|
-
def_node_matcher :entities_receiver, <<-PATTERN
|
23
|
-
(send
|
24
|
-
({lvar ivar cvar} $_) :entities)
|
25
|
-
PATTERN
|
26
|
-
|
27
|
-
MODEL_VARIABLE_NAMES = %w[model mod].freeze
|
28
|
-
|
29
|
-
def model_entities?(node)
|
30
|
-
return true if active_model_entities?(node)
|
31
|
-
|
32
|
-
name = entities_receiver(node)
|
33
|
-
name && model_variable?(name)
|
34
|
-
end
|
35
|
-
|
36
|
-
def on_send(node)
|
37
|
-
add_offense(node, location: :expression) if model_entities?(node)
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def model_variable?(name)
|
43
|
-
basename = variable_basename(name)
|
44
|
-
MODEL_VARIABLE_NAMES.include?(basename)
|
45
|
-
end
|
46
|
-
|
47
|
-
def variable_basename(name)
|
48
|
-
# Extract the basename from variables:
|
49
|
-
# model => model
|
50
|
-
# @model => model
|
51
|
-
# @@model => model
|
52
|
-
name.to_s.tr('@', '')
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Prefer `model.active_entities` over `model.entities`.
|
7
|
+
#
|
8
|
+
# Most tools/actions act upon the active entities context. This could be
|
9
|
+
# an opened group or component instance. Because of this, prefer
|
10
|
+
# `model.active_entities` by default over `model.entities` unless you
|
11
|
+
# have an explicit reason to work in the root model context.
|
12
|
+
class ModelEntities < SketchUp::Cop
|
13
|
+
|
14
|
+
MSG = 'Prefer `model.active_entities` over `model.entities`.'.freeze
|
15
|
+
|
16
|
+
# Reference: http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
17
|
+
def_node_matcher :active_model_entities?, <<-PATTERN
|
18
|
+
(send
|
19
|
+
(send (const nil? :Sketchup) :active_model) :entities)
|
20
|
+
PATTERN
|
21
|
+
|
22
|
+
def_node_matcher :entities_receiver, <<-PATTERN
|
23
|
+
(send
|
24
|
+
({lvar ivar cvar} $_) :entities)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
MODEL_VARIABLE_NAMES = %w[model mod].freeze
|
28
|
+
|
29
|
+
def model_entities?(node)
|
30
|
+
return true if active_model_entities?(node)
|
31
|
+
|
32
|
+
name = entities_receiver(node)
|
33
|
+
name && model_variable?(name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_send(node)
|
37
|
+
add_offense(node, location: :expression) if model_entities?(node)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def model_variable?(name)
|
43
|
+
basename = variable_basename(name)
|
44
|
+
MODEL_VARIABLE_NAMES.include?(basename)
|
45
|
+
end
|
46
|
+
|
47
|
+
def variable_basename(name)
|
48
|
+
# Extract the basename from variables:
|
49
|
+
# model => model
|
50
|
+
# @model => model
|
51
|
+
# @@model => model
|
52
|
+
name.to_s.tr('@', '')
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,45 +1,45 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module SketchupSuggestions
|
6
|
-
# Some of the shipped extensions in SketchUp monkey-patch the API
|
7
|
-
# namespace. This is an unfortunate no-no that was done a long time ago
|
8
|
-
# before the extension best-practices were established. These functions
|
9
|
-
# might change or be removed at any time. They will also not work when
|
10
|
-
# the extensions are disabled. Avoid using these methods.
|
11
|
-
class MonkeyPatchedApi < SketchUp::Cop
|
12
|
-
|
13
|
-
include SketchUp::DynamicComponentMethods
|
14
|
-
|
15
|
-
def on_send(node)
|
16
|
-
# Only check instance methods.
|
17
|
-
return if node.receiver && node.receiver.const_type?
|
18
|
-
|
19
|
-
name = node.method_name
|
20
|
-
|
21
|
-
dc_method = DC_METHODS.find { |m| m[:name] == name }
|
22
|
-
return unless dc_method
|
23
|
-
|
24
|
-
if dc_method.key?(:variables)
|
25
|
-
return unless node.receiver && node.receiver.variable?
|
26
|
-
|
27
|
-
receiver_name = node.receiver.children.first
|
28
|
-
# Account for instance and class variables.
|
29
|
-
receiver_name = receiver_name.to_s.tr('@', '').to_sym
|
30
|
-
return unless dc_method[:variables].include?(receiver_name)
|
31
|
-
end
|
32
|
-
|
33
|
-
path = dc_method[:path]
|
34
|
-
message = "#{path}##{name} is not part of the official API. "\
|
35
|
-
"It's a monkey-patched addition by Dynamic Components."
|
36
|
-
add_offense(node,
|
37
|
-
location: :selector,
|
38
|
-
severity: :warning,
|
39
|
-
message: message)
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Some of the shipped extensions in SketchUp monkey-patch the API
|
7
|
+
# namespace. This is an unfortunate no-no that was done a long time ago
|
8
|
+
# before the extension best-practices were established. These functions
|
9
|
+
# might change or be removed at any time. They will also not work when
|
10
|
+
# the extensions are disabled. Avoid using these methods.
|
11
|
+
class MonkeyPatchedApi < SketchUp::Cop
|
12
|
+
|
13
|
+
include SketchUp::DynamicComponentMethods
|
14
|
+
|
15
|
+
def on_send(node)
|
16
|
+
# Only check instance methods.
|
17
|
+
return if node.receiver && node.receiver.const_type?
|
18
|
+
|
19
|
+
name = node.method_name
|
20
|
+
|
21
|
+
dc_method = DC_METHODS.find { |m| m[:name] == name }
|
22
|
+
return unless dc_method
|
23
|
+
|
24
|
+
if dc_method.key?(:variables)
|
25
|
+
return unless node.receiver && node.receiver.variable?
|
26
|
+
|
27
|
+
receiver_name = node.receiver.children.first
|
28
|
+
# Account for instance and class variables.
|
29
|
+
receiver_name = receiver_name.to_s.tr('@', '').to_sym
|
30
|
+
return unless dc_method[:variables].include?(receiver_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
path = dc_method[:path]
|
34
|
+
message = "#{path}##{name} is not part of the official API. "\
|
35
|
+
"It's a monkey-patched addition by Dynamic Components."
|
36
|
+
add_offense(node,
|
37
|
+
location: :selector,
|
38
|
+
severity: :warning,
|
39
|
+
message: message)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,103 +1,103 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module SketchupSuggestions
|
6
|
-
# Operation name should be a short capitalized description. It will be
|
7
|
-
# visible to the user in the Edit > Undo menu. Make sure to give it a
|
8
|
-
# short human readable name, similar to SketchUp's own operation names.
|
9
|
-
#
|
10
|
-
# This cop make some very naive assumptions and will have more false
|
11
|
-
# positives than most of the other cops. It's purpose is mainly to enable
|
12
|
-
# awareness.
|
13
|
-
class OperationName < SketchUp::Cop
|
14
|
-
|
15
|
-
include RangeHelp
|
16
|
-
|
17
|
-
MSG = 'Operation name should be a short capitalized description.'.freeze
|
18
|
-
MSG_MAX = 'Operation names should not be short and concise. [%d/%d]'.freeze
|
19
|
-
|
20
|
-
def on_send(node)
|
21
|
-
_, method_name, *args = *node
|
22
|
-
return unless method_name == :start_operation
|
23
|
-
return if args.empty? || !args.first.str_type?
|
24
|
-
|
25
|
-
# Ignore transparent operations.
|
26
|
-
return if args.size == 4 && args.last.true_type?
|
27
|
-
|
28
|
-
operation_name = args.first.str_content
|
29
|
-
# We can only inspect string literals.
|
30
|
-
return unless operation_name.is_a?(String)
|
31
|
-
|
32
|
-
# Check the format of the operation name.
|
33
|
-
unless acceptable_operation_name?(operation_name)
|
34
|
-
msg = %(#{MSG} Expected: `"#{titleize(operation_name)}"`)
|
35
|
-
add_offense(args.first, location: :expression, message: msg)
|
36
|
-
end
|
37
|
-
# Check the length of the operation name.
|
38
|
-
unless operation_name.size <= max_operation_name_length
|
39
|
-
message = format(MSG_MAX, operation_name.size, max_operation_name_length)
|
40
|
-
add_offense(args.first,
|
41
|
-
location: excess_range(args.first, operation_name),
|
42
|
-
message: message)
|
43
|
-
end
|
44
|
-
# Ensure operation name is not empty.
|
45
|
-
if operation_name.empty?
|
46
|
-
msg = 'Operation names should not be empty.'
|
47
|
-
add_offense(args.first, location: :expression, message: msg)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def excess_range(node, operation_name)
|
54
|
-
string_start = node.source.index(operation_name)
|
55
|
-
range = node.loc.expression
|
56
|
-
if string_start
|
57
|
-
excess_start = range.begin_pos + string_start + max_operation_name_length
|
58
|
-
excess_end = range.begin_pos + string_start + operation_name.size
|
59
|
-
range_between(excess_start, excess_end)
|
60
|
-
else
|
61
|
-
range_between(range.begin_pos, range.end_pos)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def acceptable_operation_name?(name)
|
66
|
-
# Capitalization, no programmer name, no punctuation.
|
67
|
-
return false if name.end_with?('.')
|
68
|
-
return false if titleize(name) != name
|
69
|
-
|
70
|
-
true
|
71
|
-
end
|
72
|
-
|
73
|
-
def max_operation_name_length
|
74
|
-
length = cop_config['Max'] || 25
|
75
|
-
return length if length.is_a?(Integer) && length > 0
|
76
|
-
|
77
|
-
raise 'Max needs to be a positive integer!'
|
78
|
-
end
|
79
|
-
|
80
|
-
TITLEIZE_EXCLUDE = %w[
|
81
|
-
by for from in of to
|
82
|
-
and or if
|
83
|
-
].freeze
|
84
|
-
|
85
|
-
def titleize(string)
|
86
|
-
string = string.gsub(/[_.]/, ' ')
|
87
|
-
words = string.split.map { |word|
|
88
|
-
unless TITLEIZE_EXCLUDE.include?(word)
|
89
|
-
# word.capitalize won't work here, as we want to allow words like:
|
90
|
-
# "HTML", "SketchUp". So instead only the first character in each
|
91
|
-
# word is modified.
|
92
|
-
char = word[0].upcase
|
93
|
-
word[0, 1] = char
|
94
|
-
end
|
95
|
-
word
|
96
|
-
}
|
97
|
-
words.join(' ')
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Operation name should be a short capitalized description. It will be
|
7
|
+
# visible to the user in the Edit > Undo menu. Make sure to give it a
|
8
|
+
# short human readable name, similar to SketchUp's own operation names.
|
9
|
+
#
|
10
|
+
# This cop make some very naive assumptions and will have more false
|
11
|
+
# positives than most of the other cops. It's purpose is mainly to enable
|
12
|
+
# awareness.
|
13
|
+
class OperationName < SketchUp::Cop
|
14
|
+
|
15
|
+
include RangeHelp
|
16
|
+
|
17
|
+
MSG = 'Operation name should be a short capitalized description.'.freeze
|
18
|
+
MSG_MAX = 'Operation names should not be short and concise. [%d/%d]'.freeze
|
19
|
+
|
20
|
+
def on_send(node)
|
21
|
+
_, method_name, *args = *node
|
22
|
+
return unless method_name == :start_operation
|
23
|
+
return if args.empty? || !args.first.str_type?
|
24
|
+
|
25
|
+
# Ignore transparent operations.
|
26
|
+
return if args.size == 4 && args.last.true_type?
|
27
|
+
|
28
|
+
operation_name = args.first.str_content
|
29
|
+
# We can only inspect string literals.
|
30
|
+
return unless operation_name.is_a?(String)
|
31
|
+
|
32
|
+
# Check the format of the operation name.
|
33
|
+
unless acceptable_operation_name?(operation_name)
|
34
|
+
msg = %(#{MSG} Expected: `"#{titleize(operation_name)}"`)
|
35
|
+
add_offense(args.first, location: :expression, message: msg)
|
36
|
+
end
|
37
|
+
# Check the length of the operation name.
|
38
|
+
unless operation_name.size <= max_operation_name_length
|
39
|
+
message = format(MSG_MAX, operation_name.size, max_operation_name_length)
|
40
|
+
add_offense(args.first,
|
41
|
+
location: excess_range(args.first, operation_name),
|
42
|
+
message: message)
|
43
|
+
end
|
44
|
+
# Ensure operation name is not empty.
|
45
|
+
if operation_name.empty?
|
46
|
+
msg = 'Operation names should not be empty.'
|
47
|
+
add_offense(args.first, location: :expression, message: msg)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def excess_range(node, operation_name)
|
54
|
+
string_start = node.source.index(operation_name)
|
55
|
+
range = node.loc.expression
|
56
|
+
if string_start
|
57
|
+
excess_start = range.begin_pos + string_start + max_operation_name_length
|
58
|
+
excess_end = range.begin_pos + string_start + operation_name.size
|
59
|
+
range_between(excess_start, excess_end)
|
60
|
+
else
|
61
|
+
range_between(range.begin_pos, range.end_pos)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def acceptable_operation_name?(name)
|
66
|
+
# Capitalization, no programmer name, no punctuation.
|
67
|
+
return false if name.end_with?('.')
|
68
|
+
return false if titleize(name) != name
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def max_operation_name_length
|
74
|
+
length = cop_config['Max'] || 25
|
75
|
+
return length if length.is_a?(Integer) && length > 0
|
76
|
+
|
77
|
+
raise 'Max needs to be a positive integer!'
|
78
|
+
end
|
79
|
+
|
80
|
+
TITLEIZE_EXCLUDE = %w[
|
81
|
+
by for from in of to
|
82
|
+
and or if
|
83
|
+
].freeze
|
84
|
+
|
85
|
+
def titleize(string)
|
86
|
+
string = string.gsub(/[_.]/, ' ')
|
87
|
+
words = string.split.map { |word|
|
88
|
+
unless TITLEIZE_EXCLUDE.include?(word)
|
89
|
+
# word.capitalize won't work here, as we want to allow words like:
|
90
|
+
# "HTML", "SketchUp". So instead only the first character in each
|
91
|
+
# word is modified.
|
92
|
+
char = word[0].upcase
|
93
|
+
word[0, 1] = char
|
94
|
+
end
|
95
|
+
word
|
96
|
+
}
|
97
|
+
words.join(' ')
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|