rubocop-sketchup 0.0.2 → 0.1.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/config/default.yml +95 -0
- data/lib/rubocop-sketchup.rb +5 -0
- data/lib/rubocop/sketchup.rb +12 -0
- data/lib/rubocop/sketchup/deprecations/operation_next_transparent.rb +2 -2
- data/lib/rubocop/sketchup/extension_project.rb +48 -0
- data/lib/rubocop/sketchup/inject.rb +17 -0
- data/lib/rubocop/sketchup/namespace_checker.rb +3 -4
- data/lib/rubocop/sketchup/performance/openssl.rb +39 -0
- data/lib/rubocop/sketchup/performance/operation_disable_ui.rb +3 -3
- data/lib/rubocop/sketchup/performance/selection_bulk.rb +72 -0
- data/lib/rubocop/sketchup/performance/typename.rb +1 -1
- data/lib/rubocop/sketchup/requirements/exit.rb +24 -0
- data/lib/rubocop/sketchup/requirements/extension_namespace.rb +1 -1
- data/lib/rubocop/sketchup/requirements/file_structure.rb +75 -0
- data/lib/rubocop/sketchup/requirements/global_constants.rb +8 -1
- data/lib/rubocop/sketchup/requirements/global_methods.rb +7 -7
- data/lib/rubocop/sketchup/requirements/global_variables.rb +9 -2
- data/lib/rubocop/sketchup/requirements/language_handler_globals.rb +42 -0
- data/lib/rubocop/sketchup/requirements/load_path.rb +2 -2
- data/lib/rubocop/sketchup/requirements/minimal_registration.rb +48 -0
- data/lib/rubocop/sketchup/requirements/register_extension.rb +35 -0
- data/lib/rubocop/sketchup/requirements/shipped_extensions_namespace.rb +61 -0
- data/lib/rubocop/sketchup/requirements/sketchup_extension.rb +80 -0
- data/lib/rubocop/sketchup/suggestions/dc_internals.rb +42 -0
- data/lib/rubocop/sketchup/suggestions/file_encoding.rb +78 -0
- data/lib/rubocop/sketchup/suggestions/model_entities.rb +2 -2
- data/lib/rubocop/sketchup/suggestions/operation_name.rb +59 -7
- data/lib/rubocop/sketchup/suggestions/sketchup_find_support_file.rb +28 -0
- data/lib/rubocop/sketchup/suggestions/sketchup_require.rb +42 -0
- data/lib/rubocop/sketchup/version.rb +1 -1
- data/rubocop-sketchup.gemspec +2 -1
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aaaa92ae5a979fc2fbfb37d4e809e3f747337029
|
4
|
+
data.tar.gz: 66216c4e9a5004d7e5a70cda380a257df65b68cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0db51625b9ca4b001e899e5cda805ef99817badf8b710d8310204b83b86fd81b1b58519e7ebdcdf46222574c2559b93b0b9727343907b367efebaacebd084fe2
|
7
|
+
data.tar.gz: 6dc1219506f59c2abb7e0246715b35304acf14aa62d165be5aa2f7b5c2a696737537f8485186ac694682ef5e09797b96fee0b47e74a7cd5e24db06c500a861a8
|
data/config/default.yml
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
---
|
2
|
+
SketchupPerformance/SelectionBulkChanges:
|
3
|
+
Description: >-
|
4
|
+
Avoid modifying the selection set within loops. It's much
|
5
|
+
faster to change the selection in bulk.
|
6
|
+
Enabled: true
|
7
|
+
|
8
|
+
SketchupPerformance/OpenSSL:
|
9
|
+
Description: >-
|
10
|
+
Avoid using Ruby's OpenSSL within SketchUp. A flaw in how it
|
11
|
+
obtain random bits under Windows can severely affect
|
12
|
+
performance, freezing SketchUp for many minutes.
|
13
|
+
This also affects SecureRandom and anything else
|
14
|
+
that depend on OpenSSL. Net::HTTP is affected if connecting via
|
15
|
+
HTTPS. Connecting via plain HTTP is unaffected.
|
16
|
+
Enabled: true
|
17
|
+
|
18
|
+
SketchupRequirements/Exit:
|
19
|
+
Description: Exit attempts to kill the Ruby interpreter.
|
20
|
+
Enabled: true
|
21
|
+
|
22
|
+
SketchupRequirements/FileStructure:
|
23
|
+
Description: >-
|
24
|
+
Check that the extension conform to expected file structure
|
25
|
+
with a single root .rb file and a support folder with matching
|
26
|
+
name.
|
27
|
+
Enabled: true
|
28
|
+
|
29
|
+
SketchupRequirements/LanguageHandlerGlobals:
|
30
|
+
Description: >-
|
31
|
+
Avoid using globals in general, but especially these which are
|
32
|
+
known to be in use by other extensions made by SketchUp.
|
33
|
+
They are still in use due to compatibility reasons.
|
34
|
+
Enabled: true
|
35
|
+
|
36
|
+
SketchupRequirements/MinimalRegistration:
|
37
|
+
Description: >-
|
38
|
+
Don't load extension files in the root file registering the
|
39
|
+
extension. Extensions should not load additional files when
|
40
|
+
it's disabled.
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
SketchupRequirements/RegisterExtension:
|
44
|
+
Description: >-
|
45
|
+
Always register extensions to load by default. Otherwise it
|
46
|
+
might confuse users to think the extension isn't working.
|
47
|
+
Enabled: true
|
48
|
+
|
49
|
+
SketchupRequirements/ShippedExtensionsNamespace:
|
50
|
+
Description: ShippedExtensionsNamespace
|
51
|
+
Enabled: true
|
52
|
+
|
53
|
+
SketchupRequirements/SketchupExtension:
|
54
|
+
Description: >-
|
55
|
+
Register a single instance of SketchupExtension per extension.
|
56
|
+
This should be done by the root .rb file in the extension
|
57
|
+
package.
|
58
|
+
Enabled: true
|
59
|
+
|
60
|
+
SketchupSuggestions/FileEncoding:
|
61
|
+
Description: >-
|
62
|
+
When using __FILE__ and __dir__, beware that Ruby doesn't apply
|
63
|
+
the correct encoding to the strings under Windows. When they
|
64
|
+
contain non-english characters it will lead to exceptions being
|
65
|
+
raised when the strings are used. Force encoding to work around
|
66
|
+
this.
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
SketchupSuggestions/SketchupExtension:
|
70
|
+
Description: Check that extension registers a SketchupExtension object.
|
71
|
+
Enabled: true
|
72
|
+
SourcePath: src
|
73
|
+
|
74
|
+
SketchupSuggestions/DynamicComponentInternals:
|
75
|
+
Description: >-
|
76
|
+
Avoid relying on internal logic of Dynamic Components. It's
|
77
|
+
behavior might change between versions.
|
78
|
+
Enabled: true
|
79
|
+
|
80
|
+
SketchupSuggestions/OperationName:
|
81
|
+
Description: Check that operation names are human friendly and consistent with SketchUp.
|
82
|
+
Enabled: true
|
83
|
+
Max: 25
|
84
|
+
|
85
|
+
SketchupSuggestions/SketchupFindSupportFile:
|
86
|
+
Description: >-
|
87
|
+
Avoid Sketchup.find_support_file to find your extension's files.
|
88
|
+
Extensions might be installed outside the SketchUp Plugins folder.
|
89
|
+
Use __FILE__ and __dir__ to locate your files relative to the
|
90
|
+
executing file.
|
91
|
+
Enabled: true
|
92
|
+
|
93
|
+
SketchupSuggestions/SketchupRequire:
|
94
|
+
Description: Omit file extensions when using Sketchup.require to allow encrypted files to be loaded.
|
95
|
+
Enabled: true
|
data/lib/rubocop-sketchup.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
require 'rubocop'
|
2
|
+
require 'rubocop/sketchup'
|
2
3
|
require 'rubocop/sketchup/version'
|
4
|
+
require 'rubocop/sketchup/inject'
|
3
5
|
|
6
|
+
require 'rubocop/sketchup/extension_project'
|
4
7
|
require 'rubocop/sketchup/namespace'
|
5
8
|
require 'rubocop/sketchup/namespace_checker'
|
6
9
|
require 'rubocop/sketchup/no_comment_disable'
|
7
10
|
|
11
|
+
RuboCop::SketchUp::Inject.defaults!
|
12
|
+
|
8
13
|
# Load all custom cops.
|
9
14
|
pattern = File.join(__dir__, 'rubocop', 'sketchup', '**/*rb')
|
10
15
|
Dir.glob(pattern) { |file|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# RuboCop SketchUp project namespace
|
5
|
+
module SketchUp
|
6
|
+
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
7
|
+
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
8
|
+
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
9
|
+
|
10
|
+
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
11
|
+
end
|
12
|
+
end
|
@@ -6,14 +6,14 @@ module RuboCop
|
|
6
6
|
# Weak warning. (Question?)
|
7
7
|
class OperationNextTransparent < Cop
|
8
8
|
MSG = 'Third argument is deprecated.'.freeze
|
9
|
-
|
9
|
+
|
10
10
|
def on_send(node)
|
11
11
|
_, method_name, *args = *node
|
12
12
|
return unless method_name == :start_operation
|
13
13
|
return if args.size < 3
|
14
14
|
argument = args[2]
|
15
15
|
next_transparent = argument.type == :true
|
16
|
-
add_offense(argument, :expression) if next_transparent
|
16
|
+
add_offense(argument, location: :expression) if next_transparent
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sketchup
|
8
|
+
module ExtensionProject
|
9
|
+
|
10
|
+
# @return [Pathname]
|
11
|
+
def config_path
|
12
|
+
path = config.instance_variable_get(:@loaded_path)
|
13
|
+
if path
|
14
|
+
Pathname.new(path).expand_path.dirname
|
15
|
+
else
|
16
|
+
Pathname.new(Dir.pwd).expand_path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Pathname]
|
21
|
+
def relative_source_path
|
22
|
+
Pathname.new(cop_config['SourcePath'] || 'src')
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Pathname]
|
26
|
+
def source_path
|
27
|
+
config_path.join(relative_source_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [RuboCop::ProcessedSource] processed_source
|
31
|
+
def path_relative_to_source(processed_source)
|
32
|
+
source_filename = processed_source.buffer.name
|
33
|
+
rel_path = config.path_relative_to_config(source_filename)
|
34
|
+
path = Pathname.new(rel_path).expand_path
|
35
|
+
path.relative_path_from(source_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [RuboCop::ProcessedSource] processed_source
|
39
|
+
def root_file?(processed_source)
|
40
|
+
filename = path_relative_to_source(processed_source)
|
41
|
+
filename.extname.downcase == '.rb' &&
|
42
|
+
filename.parent.to_s == '.'
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RuboCop
|
2
|
+
# Ripped directly from rubocop-rspec.
|
3
|
+
module SketchUp
|
4
|
+
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
5
|
+
# bit of our configuration.
|
6
|
+
module Inject
|
7
|
+
def self.defaults!
|
8
|
+
path = CONFIG_DEFAULT.to_s
|
9
|
+
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
10
|
+
config = Config.new(hash, path)
|
11
|
+
puts "configuration from #{path}" if ConfigLoader.debug?
|
12
|
+
config = ConfigLoader.merge_with_default(config, path)
|
13
|
+
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -5,8 +5,6 @@ module RuboCop
|
|
5
5
|
module Sketchup
|
6
6
|
module NamespaceChecker
|
7
7
|
|
8
|
-
include OnMethodDef
|
9
|
-
|
10
8
|
def on_class(node)
|
11
9
|
check_namespace(node)
|
12
10
|
end
|
@@ -15,9 +13,10 @@ module RuboCop
|
|
15
13
|
check_namespace(node)
|
16
14
|
end
|
17
15
|
|
18
|
-
def
|
16
|
+
def on_def(node)
|
19
17
|
check_namespace(node)
|
20
18
|
end
|
19
|
+
alias on_defs on_def
|
21
20
|
|
22
21
|
# Constant assignment.
|
23
22
|
def on_casgn(node)
|
@@ -25,7 +24,7 @@ module RuboCop
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def check_namespace(node)
|
28
|
-
add_offense(node, :name,
|
27
|
+
add_offense(node, location: :name, severity: :error) if in_namespace?(node)
|
29
28
|
end
|
30
29
|
|
31
30
|
def in_namespace?(node)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupPerformance
|
6
|
+
# There are performance issue with the OpenSSL library that Ruby ship. In
|
7
|
+
# a clean SU session, default model there is a small delay observed in the
|
8
|
+
# Windows version of SU.
|
9
|
+
#
|
10
|
+
# But with a larger model loaded, or session that have had larger files
|
11
|
+
# loaded the lag will be minutes.
|
12
|
+
#
|
13
|
+
# `SecureRandom` is also affected by this, as it uses OpenSSL to seed.
|
14
|
+
#
|
15
|
+
# It also affects Net::HTTP if making HTTPS connections.
|
16
|
+
class OpenSSL < Cop
|
17
|
+
|
18
|
+
MSG = 'Avoid use of OpenSSL within SketchUp due to severe performance issues.'.freeze
|
19
|
+
|
20
|
+
# http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
21
|
+
# https://rubocop.readthedocs.io/en/latest/node_pattern/
|
22
|
+
def_node_matcher :require, <<-PATTERN
|
23
|
+
(send nil? :require
|
24
|
+
(str $_)
|
25
|
+
)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
OPEN_SSL_USAGE = %w[openssl securerandom net/https net/http]
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
filename = require(node)
|
32
|
+
return if filename.nil?
|
33
|
+
return unless OPEN_SSL_USAGE.include?(filename.downcase)
|
34
|
+
add_offense(node, location: :expression)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -11,13 +11,13 @@ module RuboCop
|
|
11
11
|
_, method_name, *args = *node
|
12
12
|
return unless method_name == :start_operation
|
13
13
|
if args.size < 2
|
14
|
-
add_offense(node, :expression)
|
14
|
+
add_offense(node, location: :expression)
|
15
15
|
return
|
16
16
|
end
|
17
17
|
argument = args[1]
|
18
|
-
disable_ui = argument.
|
18
|
+
disable_ui = argument.truthy_literal?
|
19
19
|
return if disable_ui
|
20
|
-
add_offense(argument, :expression)
|
20
|
+
add_offense(argument, location: :expression)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupPerformance
|
6
|
+
# Avoid modifying the selection set within loops. It's much faster to
|
7
|
+
# change the selection in bulk.
|
8
|
+
#
|
9
|
+
# @example Poor performance
|
10
|
+
# model = Sketchup.active_model
|
11
|
+
# model.active_entities.each { |entity|
|
12
|
+
# model.selection.add(entity) if entity.is_a?(Sketchup::Face)
|
13
|
+
# }
|
14
|
+
#
|
15
|
+
# @example Better performance
|
16
|
+
# model = Sketchup.active_model
|
17
|
+
# faces = model.active_entities.map { |entity|
|
18
|
+
# entity.is_a?(Sketchup::Face)
|
19
|
+
# }
|
20
|
+
# model.selection.add(faces)
|
21
|
+
#
|
22
|
+
# @example Better performance and simpler
|
23
|
+
# model = Sketchup.active_model
|
24
|
+
# faces = model.active_entities.grep(Sketchup::Face)
|
25
|
+
# model.selection.add(faces)
|
26
|
+
class SelectionBulkChanges < Cop
|
27
|
+
MSG = 'Avoid modifying selecting within loops.'.freeze
|
28
|
+
|
29
|
+
# http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
30
|
+
# https://rubocop.readthedocs.io/en/latest/node_pattern/
|
31
|
+
def_node_matcher :selection?, <<-PATTERN
|
32
|
+
(send
|
33
|
+
(send _ {:selection :sel}) {:add :remove :toggle}
|
34
|
+
...)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
def_node_matcher :block_loop?, <<-PATTERN
|
38
|
+
(block
|
39
|
+
(send
|
40
|
+
(send _ _) {
|
41
|
+
:each :each_with_index :each_with_object
|
42
|
+
:each_entry :each_index :each_slice
|
43
|
+
:each_key :each_pair :each_value
|
44
|
+
:grep
|
45
|
+
} ...)
|
46
|
+
...)
|
47
|
+
PATTERN
|
48
|
+
|
49
|
+
def_node_matcher :numeric_loop?, <<-PATTERN
|
50
|
+
(block
|
51
|
+
(send
|
52
|
+
({int float} _) {:times :upto :downto} ...)
|
53
|
+
...)
|
54
|
+
PATTERN
|
55
|
+
|
56
|
+
def iterator?(node)
|
57
|
+
node.is_a?(RuboCop::AST::ForNode) ||
|
58
|
+
node.is_a?(RuboCop::AST::UntilNode) ||
|
59
|
+
node.is_a?(RuboCop::AST::WhileNode) ||
|
60
|
+
block_loop?(node) ||
|
61
|
+
numeric_loop?(node)
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_send(node)
|
65
|
+
return unless selection?(node)
|
66
|
+
return unless node.ancestors.any?(&method(:iterator?))
|
67
|
+
add_offense(node, location: :expression)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
return unless method_name == :typename
|
12
12
|
# TODO(thomthom): Should we try to detect use of #typename
|
13
13
|
# in context of comparing against a string?
|
14
|
-
add_offense(node, :expression)
|
14
|
+
add_offense(node, location: :expression)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Don't attempt to kill the Ruby interpreter by calling exit or exit!.
|
7
|
+
class Exit < Cop
|
8
|
+
|
9
|
+
include NoCommentDisable
|
10
|
+
|
11
|
+
MSG = 'Exit attempts to kill the Ruby interpreter.'.freeze
|
12
|
+
|
13
|
+
# Reference: http://rubocop.readthedocs.io/en/latest/development/
|
14
|
+
def_node_matcher :exit?, <<-PATTERN
|
15
|
+
(send nil? {:exit :exit!})
|
16
|
+
PATTERN
|
17
|
+
|
18
|
+
def on_send(node)
|
19
|
+
add_offense(node, location: :expression) if exit?(node)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Check that the extension conform to expected file structure with a
|
7
|
+
# single root .rb file and a support folder with matching name.
|
8
|
+
class FileStructure < Cop
|
9
|
+
|
10
|
+
include Sketchup::ExtensionProject
|
11
|
+
include NoCommentDisable
|
12
|
+
|
13
|
+
IGNORED_DIRECTORIES = %w[
|
14
|
+
__MACOSX
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
def investigate(processed_source)
|
18
|
+
return if already_run?
|
19
|
+
|
20
|
+
# Using range similar to RuboCop::Cop::Naming::Filename (file_name.rb)
|
21
|
+
range = source_range(processed_source.buffer, 1, 0)
|
22
|
+
|
23
|
+
# Find all root Ruby files in the source directory.
|
24
|
+
pattern = "#{source_path}/*.rb"
|
25
|
+
root_ruby_files = Dir.glob(pattern)
|
26
|
+
|
27
|
+
# Ensure there is only one root Ruby file.
|
28
|
+
if root_ruby_files.size != 1
|
29
|
+
msg = "Extensions must have exactly one root Ruby (.rb) file. Found: %d"
|
30
|
+
add_offense(nil, location: range, message: format(msg, root_ruby_files.size))
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
# Find the root file and collect the sub-directories.
|
35
|
+
root_file = root_ruby_files.first
|
36
|
+
extension_basename = File.basename(root_file, '.*')
|
37
|
+
sub_folders = source_path.children.select { |c| c.directory? }
|
38
|
+
sub_folders.reject! { |folder|
|
39
|
+
IGNORED_DIRECTORIES.include?(folder.basename.to_s)
|
40
|
+
}
|
41
|
+
|
42
|
+
# Ensure there is only one sub-directory.
|
43
|
+
if sub_folders.size != 1
|
44
|
+
msg = "Extensions must have exactly one support directory. Found %d"
|
45
|
+
add_offense(nil, location: range, message: format(msg, sub_folders.size))
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
# Ensure support directory's name match the root Ruby file.
|
50
|
+
support_directory = sub_folders.first
|
51
|
+
unless support_directory.basename.to_s == extension_basename
|
52
|
+
msg = 'Extensions must have a support directory matching the name of the root Ruby file. Expected %s, found %s'
|
53
|
+
msg = format(msg, extension_basename, support_directory.basename)
|
54
|
+
add_offense(nil, location: range, message: msg)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
@@already_run = false
|
61
|
+
|
62
|
+
def already_run?
|
63
|
+
return true if @@already_run
|
64
|
+
@@already_run = true
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.reset
|
69
|
+
@@already_run = false
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -10,10 +10,17 @@ module RuboCop
|
|
10
10
|
|
11
11
|
MSG = 'Do not introduce global constants.'.freeze
|
12
12
|
|
13
|
+
def_node_matcher :namespaced_constant?, <<-PATTERN
|
14
|
+
(casgn
|
15
|
+
(const _ _) ...
|
16
|
+
)
|
17
|
+
PATTERN
|
18
|
+
|
13
19
|
# Constant assignment.
|
14
20
|
def on_casgn(node)
|
21
|
+
return if namespaced_constant?(node)
|
15
22
|
namespace = Namespace.new(node.parent_module_name)
|
16
|
-
add_offense(node, :name,
|
23
|
+
add_offense(node, location: :name, severity: :error) if namespace.top_level?
|
17
24
|
end
|
18
25
|
|
19
26
|
end
|
@@ -6,7 +6,6 @@ module RuboCop
|
|
6
6
|
class GlobalMethods < Cop
|
7
7
|
|
8
8
|
include NoCommentDisable
|
9
|
-
include OnMethodDef
|
10
9
|
include SketchUp
|
11
10
|
|
12
11
|
MSG = 'Do not introduce global methods.'.freeze
|
@@ -30,16 +29,16 @@ module RuboCop
|
|
30
29
|
def_node_matcher :class_method, <<-PATTERN
|
31
30
|
(defs
|
32
31
|
{
|
33
|
-
(const nil $_)
|
34
|
-
(const (const nil $_) ...)
|
32
|
+
(const nil? $_)
|
33
|
+
(const (const nil? $_) ...)
|
35
34
|
}
|
36
35
|
...
|
37
36
|
)
|
38
37
|
PATTERN
|
39
38
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
39
|
+
def on_def(node)
|
40
|
+
if class_method?(node)
|
41
|
+
class_method_parent = class_method(node)
|
43
42
|
namespace = Namespace.new(class_method_parent.to_s)
|
44
43
|
else
|
45
44
|
# If a method is defined inside a block then parent_module_name
|
@@ -47,8 +46,9 @@ module RuboCop
|
|
47
46
|
return if node.parent_module_name.nil?
|
48
47
|
namespace = Namespace.new(node.parent_module_name)
|
49
48
|
end
|
50
|
-
add_offense(node, :name,
|
49
|
+
add_offense(node, location: :name, severity: :error) if namespace.top_level?
|
51
50
|
end
|
51
|
+
alias on_defs on_def
|
52
52
|
|
53
53
|
end
|
54
54
|
end
|
@@ -44,8 +44,15 @@ module RuboCop
|
|
44
44
|
$CLASSPATH $JRUBY_VERSION $JRUBY_REVISION $ENV_JAVA
|
45
45
|
).map(&:to_sym)
|
46
46
|
|
47
|
+
# TODO: This should probably be read only.
|
48
|
+
SKETCHUP_VARS = %w(
|
49
|
+
$loaded_files
|
50
|
+
).map(&:to_sym)
|
51
|
+
|
52
|
+
ALLOWED_VARS = BUILT_IN_VARS | SKETCHUP_VARS
|
53
|
+
|
47
54
|
def allowed_var?(global_var)
|
48
|
-
|
55
|
+
ALLOWED_VARS.include?(global_var)
|
49
56
|
end
|
50
57
|
|
51
58
|
def on_gvar(node)
|
@@ -59,7 +66,7 @@ module RuboCop
|
|
59
66
|
def check(node)
|
60
67
|
global_var, = *node
|
61
68
|
|
62
|
-
add_offense(node, :name,
|
69
|
+
add_offense(node, location: :name, severity: :error) unless allowed_var?(global_var)
|
63
70
|
end
|
64
71
|
end
|
65
72
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Avoid using globals in general, but especially these which are known to
|
7
|
+
# be in use by other extensions made by SketchUp.
|
8
|
+
# They are still in use due to compatibility reasons.
|
9
|
+
class LanguageHandlerGlobals < Cop
|
10
|
+
|
11
|
+
MSG = "Avoid globals in general, but especially these which are known to be in use.".freeze
|
12
|
+
|
13
|
+
LH_GLOBALS = %i[
|
14
|
+
$dc_strings
|
15
|
+
$devl_strings
|
16
|
+
$exStrings
|
17
|
+
$fs_strings
|
18
|
+
$make_pano_string
|
19
|
+
$oceanStrings
|
20
|
+
$sn_strings
|
21
|
+
$ssf_strings
|
22
|
+
$suStrings
|
23
|
+
$tStrings
|
24
|
+
$unitsStrings
|
25
|
+
$uStrings
|
26
|
+
$wt_strings
|
27
|
+
]
|
28
|
+
|
29
|
+
def hl_global_var?(global_var)
|
30
|
+
LH_GLOBALS.include?(global_var)
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_gvasgn(node)
|
34
|
+
global_var, = *node
|
35
|
+
return unless hl_global_var?(global_var)
|
36
|
+
add_offense(node, location: :name, severity: :error)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -64,14 +64,14 @@ module RuboCop
|
|
64
64
|
def on_gvasgn(node)
|
65
65
|
global_var, = *node
|
66
66
|
|
67
|
-
add_offense(node, :name,
|
67
|
+
add_offense(node, location: :name, severity: :error) if load_path?(global_var)
|
68
68
|
end
|
69
69
|
|
70
70
|
def on_send(node)
|
71
71
|
method_name = load_path_mutator?(node)
|
72
72
|
return unless method_name
|
73
73
|
|
74
|
-
add_offense(node, :expression,
|
74
|
+
add_offense(node, location: :expression, severity: :error)
|
75
75
|
end
|
76
76
|
|
77
77
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module SketchupRequirements
|
8
|
+
# Don't load extension files in the root file registering the extension.
|
9
|
+
# Extensions should not load additional files when it's disabled.
|
10
|
+
class MinimalRegistration < Cop
|
11
|
+
|
12
|
+
include Sketchup::ExtensionProject
|
13
|
+
include NoCommentDisable
|
14
|
+
|
15
|
+
MSG = "Don't load extension files in the root file registering the extension.".freeze
|
16
|
+
|
17
|
+
# Reference: http://rubocop.readthedocs.io/en/latest/node_pattern/
|
18
|
+
def_node_matcher :require_filename, <<-PATTERN
|
19
|
+
(:send
|
20
|
+
{(const nil? :Sketchup) nil?} :require
|
21
|
+
(str $_))
|
22
|
+
PATTERN
|
23
|
+
|
24
|
+
def investigate(processed_source)
|
25
|
+
if root_file?(processed_source)
|
26
|
+
filename = processed_source.buffer.name
|
27
|
+
@extension_basename = File.basename(filename, '.*')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def extension_file?(filename)
|
32
|
+
return false unless filename.include?('/')
|
33
|
+
first_directory = filename.split('/').first
|
34
|
+
@extension_basename.casecmp(first_directory) == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_send(node)
|
38
|
+
return unless @extension_basename
|
39
|
+
filename = require_filename(node)
|
40
|
+
return if filename.nil?
|
41
|
+
return unless extension_file?(filename)
|
42
|
+
add_offense(node)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Always register extensions to load by default. Otherwise it might
|
7
|
+
# confuse users to think the extension isn't working.
|
8
|
+
class RegisterExtension < Cop
|
9
|
+
|
10
|
+
include NoCommentDisable
|
11
|
+
|
12
|
+
MSG = 'Always register extensions to load by default.'.freeze
|
13
|
+
|
14
|
+
def_node_search :sketchup_register_extension, <<-PATTERN
|
15
|
+
(:send
|
16
|
+
(const nil? :Sketchup) :register_extension
|
17
|
+
$...)
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
def on_send(node)
|
21
|
+
sketchup_register_extension(node).each { |args|
|
22
|
+
if args.size < 2
|
23
|
+
add_offense(node)
|
24
|
+
next
|
25
|
+
end
|
26
|
+
load_arg = args[1]
|
27
|
+
next if load_arg.true_type?
|
28
|
+
add_offense(load_arg)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Don't modify SketchUp's shipped extensions.
|
7
|
+
class ShippedExtensionsNamespace < Cop
|
8
|
+
|
9
|
+
include NoCommentDisable
|
10
|
+
include Sketchup::NamespaceChecker
|
11
|
+
|
12
|
+
MSG = 'Do not modify shipped extensions.'.freeze
|
13
|
+
|
14
|
+
# We check only against the top level namespaces. The core define more
|
15
|
+
# objects, but they are under one of the top level namespaces listed.
|
16
|
+
|
17
|
+
NAMESPACES_ADVANCED_CAMERA_TOOLS = %w(
|
18
|
+
ACTUtil
|
19
|
+
CameraAppObserver
|
20
|
+
CameraEntityObserver
|
21
|
+
CameraFrameChangeObserver
|
22
|
+
CameraRep
|
23
|
+
CameraToolModelObserver
|
24
|
+
CameraToolPagesObserver
|
25
|
+
CameraToolViewObserver
|
26
|
+
FilmCameraTool
|
27
|
+
FSCameraData
|
28
|
+
FSGeomUtils
|
29
|
+
FSValidate
|
30
|
+
PageNameChangeObserver
|
31
|
+
).freeze
|
32
|
+
|
33
|
+
NAMESPACES_DYNAMIC_COMPONENTS = %w(
|
34
|
+
DCConverter
|
35
|
+
DCDownloader
|
36
|
+
DCFunctionsV1
|
37
|
+
DCInteractTool
|
38
|
+
DCObservers
|
39
|
+
DCProgressBar
|
40
|
+
DynamicComponents
|
41
|
+
DynamicComponentsV1
|
42
|
+
).freeze
|
43
|
+
|
44
|
+
NAMESPACES_TRIMBLE_CONNECT = %w(
|
45
|
+
Trimble
|
46
|
+
).freeze
|
47
|
+
|
48
|
+
NAMESPACES = (
|
49
|
+
NAMESPACES_ADVANCED_CAMERA_TOOLS |
|
50
|
+
NAMESPACES_DYNAMIC_COMPONENTS |
|
51
|
+
NAMESPACES_TRIMBLE_CONNECT
|
52
|
+
).freeze
|
53
|
+
|
54
|
+
def namespaces
|
55
|
+
NAMESPACES
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupRequirements
|
6
|
+
# Register a single instance of SketchupExtension per extension.
|
7
|
+
# This should be done by the root .rb file in the extension package.
|
8
|
+
class SketchupExtension < Cop
|
9
|
+
|
10
|
+
include Sketchup::ExtensionProject
|
11
|
+
include NoCommentDisable
|
12
|
+
|
13
|
+
MSG = 'Create and register one SketchupExtension instance per extension.'.freeze
|
14
|
+
MSG_CREATE_ONE = 'Create only SketchupExtension instance per extension.'.freeze
|
15
|
+
MSG_CREATE_MISSING = 'SketchupExtension.new not found.'.freeze
|
16
|
+
MSG_REGISTER_ONE = 'Only register one SketchupExtension instance per extension.'.freeze
|
17
|
+
MSG_REGISTER_MISSING = 'Registration of SketchupExtension not found. Expected %s'.freeze
|
18
|
+
|
19
|
+
# Reference: http://rubocop.readthedocs.io/en/latest/node_pattern/
|
20
|
+
def_node_search :sketchup_extension_new, <<-PATTERN
|
21
|
+
({:lvasgn :ivasgn :cvasgn :gvasgn :casgn} ...
|
22
|
+
(:send
|
23
|
+
(:const nil? :SketchupExtension) :new
|
24
|
+
_
|
25
|
+
_))
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def_node_search :sketchup_register_extension, <<-PATTERN
|
29
|
+
(:send
|
30
|
+
(const nil? :Sketchup) :register_extension
|
31
|
+
{({:lvar :ivar :cvar :gvar} $_)(const nil? $_)}
|
32
|
+
_)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def investigate(processed_source)
|
36
|
+
return unless root_file?(processed_source)
|
37
|
+
|
38
|
+
source_node = processed_source.ast
|
39
|
+
# Using range similar to RuboCop::Cop::Naming::Filename (file_name.rb)
|
40
|
+
range = source_range(processed_source.buffer, 1, 0)
|
41
|
+
|
42
|
+
# Look for SketchupExtension.new.
|
43
|
+
extension_nodes = sketchup_extension_new(source_node).to_a
|
44
|
+
if extension_nodes.size > 1
|
45
|
+
add_offense(nil, location: range, message: MSG_CREATE_ONE)
|
46
|
+
return
|
47
|
+
end
|
48
|
+
extension_node = extension_nodes.first
|
49
|
+
if extension_node.nil?
|
50
|
+
add_offense(nil, location: range, message: MSG_CREATE_MISSING)
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
# Find the name of the value SketchupExtension.new was assigned to.
|
55
|
+
if extension_node.casgn_type?
|
56
|
+
extension_var = extension_node.to_a[1]
|
57
|
+
else
|
58
|
+
extension_var = extension_node.to_a[0]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Look for Sketchup.register and make sure it register the extension
|
62
|
+
# object detected earlier.
|
63
|
+
registered_vars = sketchup_register_extension(source_node).to_a
|
64
|
+
# TODO: The offences here should probably highlight the line where
|
65
|
+
# Sketchup.register_extension is.
|
66
|
+
if registered_vars.size > 1
|
67
|
+
add_offense(nil, location: range, message: MSG_REGISTER_ONE)
|
68
|
+
return
|
69
|
+
end
|
70
|
+
registered_var = sketchup_register_extension(source_node).first
|
71
|
+
unless registered_var == extension_var
|
72
|
+
msg = MSG_REGISTER_MISSING % extension_var.to_s
|
73
|
+
add_offense(nil, location: range, message: msg)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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.
|
8
|
+
class DynamicComponentInternals < Cop
|
9
|
+
|
10
|
+
MSG = "Avoid relying on internal logic of Dynamic Components.".freeze
|
11
|
+
|
12
|
+
DC_GLOBALS = %i[
|
13
|
+
$dc_strings
|
14
|
+
$dc_extension
|
15
|
+
$dc_CONFIGURATOR_NAME
|
16
|
+
$dc_REPORTER_NAME
|
17
|
+
$dc_MANAGER_NAME
|
18
|
+
$dc_observers
|
19
|
+
]
|
20
|
+
|
21
|
+
def dc_global_var?(global_var)
|
22
|
+
DC_GLOBALS.include?(global_var)
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_gvar(node)
|
26
|
+
check(node)
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_gvasgn(node)
|
30
|
+
check(node)
|
31
|
+
end
|
32
|
+
|
33
|
+
def check(node)
|
34
|
+
global_var, = *node
|
35
|
+
return unless dc_global_var?(global_var)
|
36
|
+
add_offense(node, location: :name, severity: :error)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +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 < 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
|
+
add_offense(node, location: :expression)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def_node_search :force_encoding, <<-PATTERN
|
48
|
+
(send
|
49
|
+
(_ $_)
|
50
|
+
:force_encoding ...)
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
def on_assign(node)
|
54
|
+
lhs, value = *node
|
55
|
+
return unless magic_file_or_dir?(value)
|
56
|
+
# After assigning __FILE__ or __dir_ to a variable, check the parent
|
57
|
+
# scope to whether .force_encoding is called on the variable.
|
58
|
+
return if node.parent.nil?
|
59
|
+
encoded = force_encoding(node.parent).to_a
|
60
|
+
return if encoded.include?(lhs)
|
61
|
+
add_offense(node)
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: Review this list of aliases.
|
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
|
@@ -18,14 +18,14 @@ module RuboCop
|
|
18
18
|
def_node_matcher :model_entities?, <<-PATTERN
|
19
19
|
(send
|
20
20
|
{
|
21
|
-
(send (const nil :Sketchup) :active_model)
|
21
|
+
(send (const nil? :Sketchup) :active_model)
|
22
22
|
(lvar {:model :mod})
|
23
23
|
}
|
24
24
|
:entities)
|
25
25
|
PATTERN
|
26
26
|
|
27
27
|
def on_send(node)
|
28
|
-
add_offense(node, :expression) if model_entities?(node)
|
28
|
+
add_offense(node, location: :expression) if model_entities?(node)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -4,28 +4,80 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module SketchupSuggestions
|
6
6
|
class OperationName < Cop
|
7
|
+
|
7
8
|
MSG = 'Operation name should be a short capitalized description.'.freeze
|
9
|
+
MSG_MAX = "Operation names should not be short and concise. [%d/%d]".freeze
|
8
10
|
|
9
11
|
def on_send(node)
|
10
12
|
_, method_name, *args = *node
|
11
13
|
return unless method_name == :start_operation
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
return unless args.first.str_type?
|
15
|
+
operation_name = args.first.str_content
|
16
|
+
# We can only inspect string literals.
|
17
|
+
return unless operation_name.is_a?(String)
|
18
|
+
# Check the format of the operation name.
|
19
|
+
unless acceptable_operation_name?(operation_name)
|
20
|
+
msg = %[#{MSG} Expected: "#{titleize(operation_name)}"]
|
21
|
+
add_offense(args.first, location: :expression, message: msg)
|
22
|
+
end
|
23
|
+
# Check the length of the operation name.
|
24
|
+
unless operation_name.size <= max_operation_name_length
|
25
|
+
message = format(MSG_MAX, operation_name.size, max_operation_name_length)
|
26
|
+
add_offense(args.first,
|
27
|
+
location: excess_range(args.first, operation_name),
|
28
|
+
message: message)
|
29
|
+
end
|
30
|
+
# Ensure operation name is not empty.
|
31
|
+
if operation_name.empty?
|
32
|
+
msg = 'Operation names should not be empty.'
|
33
|
+
add_offense(args.first, location: :expression, message: msg)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def excess_range(node, operation_name)
|
40
|
+
string_start = node.source.index(operation_name)
|
41
|
+
range = node.loc.expression
|
42
|
+
if string_start
|
43
|
+
excess_start = range.begin_pos + string_start + max_operation_name_length
|
44
|
+
excess_end = range.begin_pos + string_start + operation_name.size
|
45
|
+
range_between(excess_start, excess_end)
|
46
|
+
else
|
47
|
+
range_between(range.begin_pos, range.end_pos)
|
48
|
+
end
|
15
49
|
end
|
16
50
|
|
17
51
|
def acceptable_operation_name?(name)
|
18
|
-
# Capitalization, no programmer name, no punctuation
|
19
|
-
return false if name.size > 25 # TODO: Separate Cop?
|
52
|
+
# Capitalization, no programmer name, no punctuation.
|
20
53
|
return false if name.end_with?('.')
|
21
54
|
return false if titleize(name) != name
|
22
55
|
true
|
23
56
|
end
|
24
57
|
|
25
|
-
|
58
|
+
def max_operation_name_length
|
59
|
+
length = cop_config['Max'] || 25
|
60
|
+
return length if length.is_a?(Integer) && length > 0
|
61
|
+
|
62
|
+
raise 'Max needs to be a positive integer!'
|
63
|
+
end
|
64
|
+
|
65
|
+
TITLEIZE_EXCLUDE = %w[
|
66
|
+
by for from in of to
|
67
|
+
and or if
|
68
|
+
]
|
69
|
+
|
26
70
|
def titleize(string)
|
27
|
-
string.split.map
|
71
|
+
words = string.split.map { |word|
|
72
|
+
if TITLEIZE_EXCLUDE.include?(word)
|
73
|
+
word
|
74
|
+
else
|
75
|
+
word.capitalize
|
76
|
+
end
|
77
|
+
}
|
78
|
+
words.join(' ')
|
28
79
|
end
|
80
|
+
|
29
81
|
end
|
30
82
|
end
|
31
83
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Avoid Sketchup.find_support_file to find your extension's files.
|
7
|
+
class SketchupFindSupportFile < Cop
|
8
|
+
|
9
|
+
MSG = "Don't hard code file extensions with Sketchup.require".freeze
|
10
|
+
|
11
|
+
# http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
12
|
+
# https://rubocop.readthedocs.io/en/latest/node_pattern/
|
13
|
+
def_node_matcher :sketchup_find_support_file?, <<-PATTERN
|
14
|
+
(send
|
15
|
+
(const nil? :Sketchup) :find_support_file
|
16
|
+
...
|
17
|
+
)
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
def on_send(node)
|
21
|
+
return unless sketchup_find_support_file?(node)
|
22
|
+
add_offense(node, location: :expression)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module SketchupSuggestions
|
6
|
+
# Omit file extensions when using Sketchup.require to allow encrypted
|
7
|
+
# files to be loaded.
|
8
|
+
class SketchupRequire < Cop
|
9
|
+
|
10
|
+
MSG = "Don't hard code file extensions with Sketchup.require".freeze
|
11
|
+
|
12
|
+
# http://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern
|
13
|
+
# https://rubocop.readthedocs.io/en/latest/node_pattern/
|
14
|
+
def_node_matcher :sketchup_require, <<-PATTERN
|
15
|
+
(send
|
16
|
+
(const nil? :Sketchup) :require
|
17
|
+
(str $_)
|
18
|
+
)
|
19
|
+
PATTERN
|
20
|
+
|
21
|
+
def_node_matcher :sketchup_require?, <<-PATTERN
|
22
|
+
(send
|
23
|
+
(const nil? :Sketchup) :require
|
24
|
+
(str _)
|
25
|
+
)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def on_send(node)
|
29
|
+
return unless sketchup_require?(node)
|
30
|
+
filename = sketchup_require(node)
|
31
|
+
add_offense(node, location: :expression) unless valid_filename?(filename)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def valid_filename?(filename)
|
37
|
+
File.extname(filename).empty?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/rubocop-sketchup.gemspec
CHANGED
@@ -17,11 +17,12 @@ Gem::Specification.new do |spec|
|
|
17
17
|
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
spec.files = Dir[
|
20
|
+
'config/**/*',
|
20
21
|
'lib/**/*',
|
21
22
|
'*.gemspec',
|
22
23
|
'Gemfile'
|
23
24
|
]
|
24
25
|
|
25
|
-
spec.add_dependency 'rubocop', '~> 0.
|
26
|
+
spec.add_dependency 'rubocop', '~> 0.51.0'
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.13'
|
27
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-sketchup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Trimble Inc, SketchUp Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.51.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.51.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,23 +45,40 @@ extensions: []
|
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
47
|
- Gemfile
|
48
|
+
- config/default.yml
|
48
49
|
- lib/rubocop-sketchup.rb
|
50
|
+
- lib/rubocop/sketchup.rb
|
49
51
|
- lib/rubocop/sketchup/deprecations/operation_next_transparent.rb
|
52
|
+
- lib/rubocop/sketchup/extension_project.rb
|
53
|
+
- lib/rubocop/sketchup/inject.rb
|
50
54
|
- lib/rubocop/sketchup/namespace.rb
|
51
55
|
- lib/rubocop/sketchup/namespace_checker.rb
|
52
56
|
- lib/rubocop/sketchup/no_comment_disable.rb
|
57
|
+
- lib/rubocop/sketchup/performance/openssl.rb
|
53
58
|
- lib/rubocop/sketchup/performance/operation_disable_ui.rb
|
59
|
+
- lib/rubocop/sketchup/performance/selection_bulk.rb
|
54
60
|
- lib/rubocop/sketchup/performance/typename.rb
|
55
61
|
- lib/rubocop/sketchup/requirements/api_namespace.rb
|
62
|
+
- lib/rubocop/sketchup/requirements/exit.rb
|
56
63
|
- lib/rubocop/sketchup/requirements/extension_namespace.rb
|
64
|
+
- lib/rubocop/sketchup/requirements/file_structure.rb
|
57
65
|
- lib/rubocop/sketchup/requirements/global_constants.rb
|
58
66
|
- lib/rubocop/sketchup/requirements/global_methods.rb
|
59
67
|
- lib/rubocop/sketchup/requirements/global_variables.rb
|
68
|
+
- lib/rubocop/sketchup/requirements/language_handler_globals.rb
|
60
69
|
- lib/rubocop/sketchup/requirements/load_path.rb
|
70
|
+
- lib/rubocop/sketchup/requirements/minimal_registration.rb
|
71
|
+
- lib/rubocop/sketchup/requirements/register_extension.rb
|
61
72
|
- lib/rubocop/sketchup/requirements/ruby_core_namespace.rb
|
62
73
|
- lib/rubocop/sketchup/requirements/ruby_stdlib_namespace.rb
|
74
|
+
- lib/rubocop/sketchup/requirements/shipped_extensions_namespace.rb
|
75
|
+
- lib/rubocop/sketchup/requirements/sketchup_extension.rb
|
76
|
+
- lib/rubocop/sketchup/suggestions/dc_internals.rb
|
77
|
+
- lib/rubocop/sketchup/suggestions/file_encoding.rb
|
63
78
|
- lib/rubocop/sketchup/suggestions/model_entities.rb
|
64
79
|
- lib/rubocop/sketchup/suggestions/operation_name.rb
|
80
|
+
- lib/rubocop/sketchup/suggestions/sketchup_find_support_file.rb
|
81
|
+
- lib/rubocop/sketchup/suggestions/sketchup_require.rb
|
65
82
|
- lib/rubocop/sketchup/version.rb
|
66
83
|
- rubocop-sketchup.gemspec
|
67
84
|
homepage: http://github.com/sketchup/rubocop-sketchup
|