momocop 0.1.3 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d823774129843455f368f3dc22991236d0526448998c352736a92db7b4ffe91
4
- data.tar.gz: c9c43808e8ff31c78c4efdc42bf3ef1a6553467568df304be5cfc800561a985b
3
+ metadata.gz: 2f8ebe27766e45fdc287845e8dc4d8015b13b279a34ba58a0b85f3daa0406dd6
4
+ data.tar.gz: c991e08f8256f641657868520293b117b694d7177142d8d9e82c226e18f85305
5
5
  SHA512:
6
- metadata.gz: dcb5eb8dd8d815f98dcc3acdd726f3256e17689f52a039da8f51e4e77c3a5ebfdc65ee72127a808a9bec11278ce6c7ddaad5fb1ef0df98ce31a60ddf95645a5a
7
- data.tar.gz: 7d43fd5166f63ccabeb485d89d0dffe635563001d4353f6b5ee820e3690ff7a0d70ab1d906d380cb78c17b00a43d4fb3a513bfde34ebee3b57ae761f22560b4b
6
+ metadata.gz: d44b953c25c50ca2da56043dceb78b41db565f5226d84bf091ca1cc32bb886d08b93791751c511bc37eda7d1f509b27645f1ce4202e7c5e7b47656f53e963995
7
+ data.tar.gz: '0348eb2e208e147158a837934efadeb796bbc0d4169a2c9dfb050eba282488ea6c28e96ed57d2deae4dd6202a996487162ecaad06a94faa537693b7b49edf49d'
data/.rubocop.yml CHANGED
@@ -41,6 +41,10 @@ Security:
41
41
  Style:
42
42
  Enabled: true
43
43
 
44
+ Style/BlockDelimiters:
45
+ EnforcedStyle: semantic
46
+ AllowBracesOnProceduralOneLiners: false
47
+
44
48
  Style/Documentation:
45
49
  Enabled: false
46
50
 
@@ -49,6 +53,9 @@ Style/FrozenStringLiteralComment:
49
53
  EnforcedStyle: always_true
50
54
  SafeAutoCorrect: true
51
55
 
56
+ Style/IfUnlessModifier:
57
+ Enabled: false
58
+
52
59
  Style/RequireOrder:
53
60
  Enabled: true
54
61
  SafeAutoCorrect: true
data/CODEOWNERS ADDED
@@ -0,0 +1 @@
1
+ * @supermomonga
@@ -22,9 +22,23 @@ module Momocop
22
22
  end
23
23
 
24
24
  private def extract_associations(node, associations = [])
25
- if node.type == :send && ASSOCIATION_METHODS.include?(node.children[1])
26
- association_name = node.children[2].type == :sym ? node.children[2].children[0] : node.children[2]
27
- associations << { type: node.children[1], name: association_name }
25
+ association_type = node.children[1]
26
+ options = {}
27
+ if node.type == :send && ASSOCIATION_METHODS.include?(association_type)
28
+ association_name = node.children[2].children[0].to_sym
29
+
30
+ # Extract some options
31
+ if association_type == :belongs_to
32
+ option_hash = node.children[3]
33
+ option_hash&.children&.each do |option|
34
+ key_node, value_node = option.children
35
+ if value_node.type == :sym || value_node.type == :str
36
+ options[key_node.children[0]] = value_node.children[0]
37
+ end
38
+ end
39
+ end
40
+
41
+ associations << { type: association_type, name: association_name, options: }
28
42
  elsif node.children.is_a? Array
29
43
  node.children.each do |child|
30
44
  extract_associations(child, associations) if child.is_a? Parser::AST::Node
@@ -21,8 +21,15 @@ module Momocop
21
21
 
22
22
  private def extract_enums(node, enums = [])
23
23
  if node.type == :send && node.children[1] == :enum
24
- enum_name = node.children[2].type == :sym ? node.children[2].children[0] : node.children[2]
25
- enums << enum_name.to_sym
24
+ arg = node.children[2]
25
+
26
+ if arg.type == :sym
27
+ # enum :role, { admin: 0, user: 1 }
28
+ enums << arg.children[0]
29
+ elsif arg.type == :hash
30
+ # enum role: { admin: 0, user: 1 }
31
+ enums << arg.children[0].children[0].children[0].to_sym
32
+ end
26
33
  elsif node.children.is_a? Array
27
34
  node.children.each do |child|
28
35
  extract_enums(child, enums) if child.is_a? Parser::AST::Node
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Momocop
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.5'
5
5
  end
@@ -49,11 +49,24 @@ module RuboCop
49
49
  block_node = node.block_node
50
50
 
51
51
  # Check missing associations
52
+
53
+ # Exclude defined sequences
52
54
  defined_sequences = get_defined_sequence_names(block_node)
55
+ # Exclude defined properties
53
56
  defined_properties = get_defined_property_names(block_node)
57
+ # Exclude foreign keys
58
+ model_foreign_keys = get_model_foreign_key_column_names(class_name)
59
+ # All available properties
54
60
  model_properties = get_model_property_names(class_name)
61
+ # Calc missing properties
62
+ missing_properties = (
63
+ model_properties -
64
+ (defined_sequences + defined_properties) -
65
+ model_foreign_keys
66
+ ).sort
67
+
68
+ # for definition block generation
55
69
  model_enum_properties = get_model_enum_property_names(class_name)
56
- missing_properties = (model_properties - (defined_sequences + defined_properties)).sort
57
70
 
58
71
  # Add offense for missing properties
59
72
  return unless missing_properties.any?
@@ -101,8 +114,28 @@ module RuboCop
101
114
  return [] unless source
102
115
 
103
116
  extractor = ::Momocop::EnumExtractor.new
117
+ enums = extractor.extract(source)
118
+ return enums.map(&:to_sym)
119
+ end
120
+
121
+ private def get_model_foreign_key_column_names(class_name)
122
+ source = model_file_source(class_name)
123
+ return [] unless source
124
+
125
+ extractor = ::Momocop::AssociationExtractor.new
104
126
  associations = extractor.extract(source)
105
- return associations.map(&:to_sym)
127
+ foreign_key_names =
128
+ associations
129
+ .map { |association|
130
+ options = association[:options]
131
+ if options[:foreign_key]
132
+ options[:foreign_key]
133
+ elsif options[:class_name]
134
+ foreign_key_name(options[:class_name])
135
+ end
136
+ }
137
+ .compact
138
+ return foreign_key_names.map(&:to_sym)
106
139
  end
107
140
 
108
141
  RESTRICTED_COLUMNS = %w[created_at updated_at].freeze
@@ -123,6 +156,14 @@ module RuboCop
123
156
  class_name.tableize.gsub('/', '_')
124
157
  end
125
158
 
159
+ # e.g.)
160
+ # 'User' -> ['users']
161
+ # 'Admin::User' -> ['admin_users', 'users']
162
+ private def foreign_key_name(class_name)
163
+ # TODO: parse model class file and try to get table_name_prefix and table_name_suffix
164
+ "#{class_name.underscore.gsub('/', '_')}_id"
165
+ end
166
+
126
167
  private def get_defined_sequence_names(block_node)
127
168
  body_node = block_node&.children&.last
128
169
  return [] unless body_node
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: momocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - supermomonga
@@ -63,6 +63,7 @@ files:
63
63
  - ".rubocop.yml"
64
64
  - ".rubocop_todo.yml"
65
65
  - CHANGELOG.md
66
+ - CODEOWNERS
66
67
  - CODE_OF_CONDUCT.md
67
68
  - LICENSE.txt
68
69
  - README.md