rubocop-sketchup 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|