packwerk 1.3.1 → 2.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/Gemfile.lock +12 -9
  4. data/README.md +9 -3
  5. data/TROUBLESHOOT.md +3 -3
  6. data/UPGRADING.md +54 -0
  7. data/USAGE.md +32 -51
  8. data/exe/packwerk +7 -1
  9. data/lib/packwerk/application_load_paths.rb +1 -0
  10. data/lib/packwerk/application_validator.rb +17 -59
  11. data/lib/packwerk/association_inspector.rb +1 -1
  12. data/lib/packwerk/cache.rb +168 -0
  13. data/lib/packwerk/cli.rb +37 -20
  14. data/lib/packwerk/configuration.rb +40 -5
  15. data/lib/packwerk/const_node_inspector.rb +3 -2
  16. data/lib/packwerk/constant_discovery.rb +4 -4
  17. data/lib/packwerk/constant_name_inspector.rb +1 -1
  18. data/lib/packwerk/deprecated_references.rb +18 -6
  19. data/lib/packwerk/file_processor.rb +53 -14
  20. data/lib/packwerk/files_for_processing.rb +15 -4
  21. data/lib/packwerk/formatters/offenses_formatter.rb +1 -1
  22. data/lib/packwerk/formatters/progress_formatter.rb +1 -1
  23. data/lib/packwerk/generators/configuration_file.rb +4 -19
  24. data/lib/packwerk/generators/templates/package.yml +1 -1
  25. data/lib/packwerk/generators/templates/packwerk.yml.erb +5 -5
  26. data/lib/packwerk/graph.rb +2 -0
  27. data/lib/packwerk/node.rb +2 -0
  28. data/lib/packwerk/node_processor.rb +10 -22
  29. data/lib/packwerk/node_processor_factory.rb +0 -3
  30. data/lib/packwerk/node_visitor.rb +7 -2
  31. data/lib/packwerk/package.rb +25 -4
  32. data/lib/packwerk/package_set.rb +44 -8
  33. data/lib/packwerk/parsed_constant_definitions.rb +5 -4
  34. data/lib/packwerk/reference.rb +2 -1
  35. data/lib/packwerk/reference_checking/checkers/checker.rb +21 -0
  36. data/lib/packwerk/reference_checking/checkers/dependency_checker.rb +31 -0
  37. data/lib/packwerk/reference_checking/checkers/privacy_checker.rb +58 -0
  38. data/lib/packwerk/reference_checking/reference_checker.rb +33 -0
  39. data/lib/packwerk/reference_extractor.rb +66 -19
  40. data/lib/packwerk/reference_offense.rb +1 -0
  41. data/lib/packwerk/run_context.rb +32 -11
  42. data/lib/packwerk/sanity_checker.rb +1 -1
  43. data/lib/packwerk/spring_command.rb +28 -0
  44. data/lib/packwerk/unresolved_reference.rb +10 -0
  45. data/lib/packwerk/version.rb +1 -1
  46. data/lib/packwerk/violation_type.rb +1 -1
  47. data/lib/packwerk.rb +19 -12
  48. data/packwerk.gemspec +4 -1
  49. data/service.yml +0 -2
  50. data/sorbet/rbi/gems/psych@3.3.2.rbi +24 -0
  51. metadata +41 -11
  52. data/lib/packwerk/checker.rb +0 -17
  53. data/lib/packwerk/dependency_checker.rb +0 -26
  54. data/lib/packwerk/generators/inflections_file.rb +0 -43
  55. data/lib/packwerk/generators/templates/inflections.yml +0 -6
  56. data/lib/packwerk/inflections/custom.rb +0 -33
  57. data/lib/packwerk/inflections/default.rb +0 -73
  58. data/lib/packwerk/inflector.rb +0 -48
  59. data/lib/packwerk/privacy_checker.rb +0 -53
@@ -4,6 +4,7 @@
4
4
  require "constant_resolver"
5
5
 
6
6
  module Packwerk
7
+ # Holds the context of a Packwerk run across multiple files.
7
8
  class RunContext
8
9
  extend T::Sig
9
10
 
@@ -17,19 +18,23 @@ module Packwerk
17
18
  )
18
19
 
19
20
  DEFAULT_CHECKERS = [
20
- ::Packwerk::DependencyChecker,
21
- ::Packwerk::PrivacyChecker,
21
+ ::Packwerk::ReferenceChecking::Checkers::DependencyChecker,
22
+ ::Packwerk::ReferenceChecking::Checkers::PrivacyChecker,
22
23
  ]
23
24
 
24
25
  class << self
25
26
  def from_configuration(configuration)
26
- inflector = ::Packwerk::Inflector.from_file(configuration.inflections_file)
27
+ inflector = ActiveSupport::Inflector
28
+
27
29
  new(
28
30
  root_path: configuration.root_path,
29
31
  load_paths: configuration.load_paths,
30
32
  package_paths: configuration.package_paths,
31
33
  inflector: inflector,
32
- custom_associations: configuration.custom_associations
34
+ custom_associations: configuration.custom_associations,
35
+ cache_enabled: configuration.cache_enabled?,
36
+ cache_directory: configuration.cache_directory,
37
+ config_path: configuration.config_path,
33
38
  )
34
39
  end
35
40
  end
@@ -40,7 +45,10 @@ module Packwerk
40
45
  package_paths: nil,
41
46
  inflector: nil,
42
47
  custom_associations: [],
43
- checker_classes: DEFAULT_CHECKERS
48
+ checker_classes: DEFAULT_CHECKERS,
49
+ cache_enabled: false,
50
+ cache_directory: nil,
51
+ config_path: nil
44
52
  )
45
53
  @root_path = root_path
46
54
  @load_paths = load_paths
@@ -48,25 +56,33 @@ module Packwerk
48
56
  @inflector = inflector
49
57
  @custom_associations = custom_associations
50
58
  @checker_classes = checker_classes
59
+ @cache_enabled = cache_enabled
60
+ @cache_directory = cache_directory
61
+ @config_path = config_path
51
62
  end
52
63
 
53
- sig { params(file: String).returns(T::Array[T.nilable(::Packwerk::Offense)]) }
64
+ sig { params(file: String).returns(T::Array[Packwerk::Offense]) }
54
65
  def process_file(file:)
55
- file_processor.call(file)
66
+ unresolved_references_and_offenses = file_processor.call(file)
67
+ references_and_offenses = ReferenceExtractor.get_fully_qualified_references_and_offenses_from(
68
+ unresolved_references_and_offenses,
69
+ context_provider
70
+ )
71
+ reference_checker = ReferenceChecking::ReferenceChecker.new(checkers)
72
+ references_and_offenses.flat_map { |reference| reference_checker.call(reference) }
56
73
  end
57
74
 
58
75
  private
59
76
 
60
77
  sig { returns(FileProcessor) }
61
78
  def file_processor
62
- @file_processor ||= FileProcessor.new(node_processor_factory: node_processor_factory)
79
+ @file_processor ||= FileProcessor.new(node_processor_factory: node_processor_factory, cache: cache)
63
80
  end
64
81
 
65
82
  sig { returns(NodeProcessorFactory) }
66
83
  def node_processor_factory
67
84
  NodeProcessorFactory.new(
68
85
  context_provider: context_provider,
69
- checkers: checkers,
70
86
  root_path: root_path,
71
87
  constant_name_inspectors: constant_name_inspectors
72
88
  )
@@ -74,7 +90,7 @@ module Packwerk
74
90
 
75
91
  sig { returns(ConstantDiscovery) }
76
92
  def context_provider
77
- ::Packwerk::ConstantDiscovery.new(
93
+ @context_provider ||= ::Packwerk::ConstantDiscovery.new(
78
94
  constant_resolver: resolver,
79
95
  packages: package_set
80
96
  )
@@ -89,12 +105,17 @@ module Packwerk
89
105
  )
90
106
  end
91
107
 
108
+ sig { returns(Cache) }
109
+ def cache
110
+ @cache ||= Cache.new(enable_cache: @cache_enabled, cache_directory: @cache_directory, config_path: @config_path)
111
+ end
112
+
92
113
  sig { returns(PackageSet) }
93
114
  def package_set
94
115
  ::Packwerk::PackageSet.load_all_from(root_path, package_pathspec: package_paths)
95
116
  end
96
117
 
97
- sig { returns(T::Array[Checker]) }
118
+ sig { returns(T::Array[ReferenceChecking::Checkers::Checker]) }
98
119
  def checkers
99
120
  checker_classes.map(&:new)
100
121
  end
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ require "spring/commands"
5
+
6
+ module Packwerk
7
+ class SpringCommand
8
+ def env(*)
9
+ # Packwerk needs to run in a test environment, which has a set of autoload paths that are
10
+ # often a superset of the dev/prod paths (for example, test/support/helpers)
11
+ "test"
12
+ end
13
+
14
+ def exec_name
15
+ "packwerk"
16
+ end
17
+
18
+ def gem_name
19
+ "packwerk"
20
+ end
21
+
22
+ def call
23
+ load(Gem.bin_path(gem_name, exec_name))
24
+ end
25
+ end
26
+
27
+ Spring.register_command("packwerk", SpringCommand.new)
28
+ end
@@ -0,0 +1,10 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Packwerk
5
+ # An unresolved reference from a file in one package to a constant that may be defined in a different package.
6
+ # Unresolved means that we know how it's referred to in the file,
7
+ # and we have enough context on that reference to figure out the fully qualified reference such that we
8
+ # can produce a Reference in a separate pass. However, we have not yet resolved it to its fully qualified version.
9
+ UnresolvedReference = Struct.new(:constant_name, :namespace_path, :relative_path, :source_location)
10
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
5
- VERSION = "1.3.1"
5
+ VERSION = "2.1.0"
6
6
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Packwerk
data/lib/packwerk.rb CHANGED
@@ -5,6 +5,9 @@ require "sorbet-runtime"
5
5
  require "active_support"
6
6
  require "fileutils"
7
7
 
8
+ # Provides String#pluralize
9
+ require "active_support/core_ext/string"
10
+
8
11
  module Packwerk
9
12
  extend ActiveSupport::Autoload
10
13
 
@@ -12,18 +15,16 @@ module Packwerk
12
15
  autoload :ApplicationValidator
13
16
  autoload :AssociationInspector
14
17
  autoload :OffenseCollection
15
- autoload :Checker
18
+ autoload :Cache
16
19
  autoload :Cli
17
20
  autoload :Configuration
18
21
  autoload :ConstantDiscovery
19
22
  autoload :ConstantNameInspector
20
23
  autoload :ConstNodeInspector
21
- autoload :DependencyChecker
22
24
  autoload :DeprecatedReferences
23
25
  autoload :FileProcessor
24
26
  autoload :FilesForProcessing
25
27
  autoload :Graph
26
- autoload :Inflector
27
28
  autoload :Node
28
29
  autoload :NodeProcessor
29
30
  autoload :NodeProcessorFactory
@@ -36,7 +37,7 @@ module Packwerk
36
37
  autoload :ParsedConstantDefinitions
37
38
  autoload :Parsers
38
39
  autoload :ParseRun
39
- autoload :PrivacyChecker
40
+ autoload :UnresolvedReference
40
41
  autoload :Reference
41
42
  autoload :ReferenceExtractor
42
43
  autoload :ReferenceOffense
@@ -45,13 +46,6 @@ module Packwerk
45
46
  autoload :Version
46
47
  autoload :ViolationType
47
48
 
48
- module Inflections
49
- extend ActiveSupport::Autoload
50
-
51
- autoload :Custom
52
- autoload :Default
53
- end
54
-
55
49
  module OutputStyles
56
50
  extend ActiveSupport::Autoload
57
51
 
@@ -74,7 +68,20 @@ module Packwerk
74
68
  extend ActiveSupport::Autoload
75
69
 
76
70
  autoload :ConfigurationFile
77
- autoload :InflectionsFile
78
71
  autoload :RootPackage
79
72
  end
73
+
74
+ module ReferenceChecking
75
+ extend ActiveSupport::Autoload
76
+
77
+ autoload :ReferenceChecker
78
+
79
+ module Checkers
80
+ extend ActiveSupport::Autoload
81
+
82
+ autoload :Checker
83
+ autoload :DependencyChecker
84
+ autoload :PrivacyChecker
85
+ end
86
+ end
80
87
  end
data/packwerk.gemspec CHANGED
@@ -44,11 +44,14 @@ Gem::Specification.new do |spec|
44
44
  spec.add_dependency("constant_resolver")
45
45
  spec.add_dependency("parallel")
46
46
  spec.add_dependency("sorbet-runtime")
47
+ spec.add_dependency("bundler")
48
+ spec.add_dependency("digest")
47
49
 
48
- spec.add_development_dependency("bundler")
49
50
  spec.add_development_dependency("rake")
50
51
  spec.add_development_dependency("sorbet")
51
52
  spec.add_development_dependency("m")
53
+ # https://github.com/ruby/psych/pull/487
54
+ spec.add_development_dependency("psych", "~> 3")
52
55
 
53
56
  # For Ruby parsing
54
57
  spec.add_dependency("ast")
data/service.yml CHANGED
@@ -1,3 +1 @@
1
1
  classification: library
2
- slack_channels:
3
- - core-stewardship
@@ -0,0 +1,24 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for types exported from the `psych` gem.
5
+ # Please instead update this file by running `bin/tapioca gem psych`.
6
+
7
+ ::RUBY19 = T.let(T.unsafe(nil), TrueClass)
8
+
9
+ class Object < ::BasicObject
10
+ include ::ActiveSupport::ToJsonWithActiveSupportEncoder
11
+ include ::Kernel
12
+ include ::JSON::Ext::Generator::GeneratorMethods::Object
13
+ include ::ActiveSupport::Tryable
14
+ include ::Minitest::Expectations
15
+ include ::Mocha::ParameterMatchers::InstanceMethods
16
+ include ::Mocha::Inspect::ObjectMethods
17
+ include ::Mocha::ObjectMethods
18
+
19
+ def to_yaml(options = T.unsafe(nil)); end
20
+
21
+ class << self
22
+ def yaml_tag(url); end
23
+ end
24
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packwerk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-15 00:00:00.000000000 Z
11
+ date: 2022-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -73,7 +73,21 @@ dependencies:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- type: :development
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: digest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
@@ -122,6 +136,20 @@ dependencies:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: psych
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3'
125
153
  - !ruby/object:Gem::Dependency
126
154
  name: ast
127
155
  requirement: !ruby/object:Gem::Requirement
@@ -181,6 +209,7 @@ files:
181
209
  - ".gitignore"
182
210
  - ".rubocop.yml"
183
211
  - ".ruby-version"
212
+ - CHANGELOG.md
184
213
  - CODEOWNERS
185
214
  - CODE_OF_CONDUCT.md
186
215
  - CONTRIBUTING.md
@@ -190,6 +219,7 @@ files:
190
219
  - README.md
191
220
  - Rakefile
192
221
  - TROUBLESHOOT.md
222
+ - UPGRADING.md
193
223
  - USAGE.md
194
224
  - bin/console
195
225
  - bin/m
@@ -206,28 +236,22 @@ files:
206
236
  - lib/packwerk/application_load_paths.rb
207
237
  - lib/packwerk/application_validator.rb
208
238
  - lib/packwerk/association_inspector.rb
209
- - lib/packwerk/checker.rb
239
+ - lib/packwerk/cache.rb
210
240
  - lib/packwerk/cli.rb
211
241
  - lib/packwerk/configuration.rb
212
242
  - lib/packwerk/const_node_inspector.rb
213
243
  - lib/packwerk/constant_discovery.rb
214
244
  - lib/packwerk/constant_name_inspector.rb
215
- - lib/packwerk/dependency_checker.rb
216
245
  - lib/packwerk/deprecated_references.rb
217
246
  - lib/packwerk/file_processor.rb
218
247
  - lib/packwerk/files_for_processing.rb
219
248
  - lib/packwerk/formatters/offenses_formatter.rb
220
249
  - lib/packwerk/formatters/progress_formatter.rb
221
250
  - lib/packwerk/generators/configuration_file.rb
222
- - lib/packwerk/generators/inflections_file.rb
223
251
  - lib/packwerk/generators/root_package.rb
224
- - lib/packwerk/generators/templates/inflections.yml
225
252
  - lib/packwerk/generators/templates/package.yml
226
253
  - lib/packwerk/generators/templates/packwerk.yml.erb
227
254
  - lib/packwerk/graph.rb
228
- - lib/packwerk/inflections/custom.rb
229
- - lib/packwerk/inflections/default.rb
230
- - lib/packwerk/inflector.rb
231
255
  - lib/packwerk/node.rb
232
256
  - lib/packwerk/node_processor.rb
233
257
  - lib/packwerk/node_processor_factory.rb
@@ -246,13 +270,18 @@ files:
246
270
  - lib/packwerk/parsers/erb.rb
247
271
  - lib/packwerk/parsers/factory.rb
248
272
  - lib/packwerk/parsers/ruby.rb
249
- - lib/packwerk/privacy_checker.rb
250
273
  - lib/packwerk/reference.rb
274
+ - lib/packwerk/reference_checking/checkers/checker.rb
275
+ - lib/packwerk/reference_checking/checkers/dependency_checker.rb
276
+ - lib/packwerk/reference_checking/checkers/privacy_checker.rb
277
+ - lib/packwerk/reference_checking/reference_checker.rb
251
278
  - lib/packwerk/reference_extractor.rb
252
279
  - lib/packwerk/reference_offense.rb
253
280
  - lib/packwerk/result.rb
254
281
  - lib/packwerk/run_context.rb
255
282
  - lib/packwerk/sanity_checker.rb
283
+ - lib/packwerk/spring_command.rb
284
+ - lib/packwerk/unresolved_reference.rb
256
285
  - lib/packwerk/version.rb
257
286
  - lib/packwerk/violation_type.rb
258
287
  - library.yml
@@ -301,6 +330,7 @@ files:
301
330
  - sorbet/rbi/gems/parlour@6.0.0.rbi
302
331
  - sorbet/rbi/gems/parser@3.0.0.0.rbi
303
332
  - sorbet/rbi/gems/pry@0.14.0.rbi
333
+ - sorbet/rbi/gems/psych@3.3.2.rbi
304
334
  - sorbet/rbi/gems/racc@1.5.2.rbi
305
335
  - sorbet/rbi/gems/rack-test@1.1.0.rbi
306
336
  - sorbet/rbi/gems/rack@2.2.3.rbi
@@ -1,17 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module Checker
6
- extend T::Sig
7
- extend T::Helpers
8
-
9
- interface!
10
-
11
- sig { returns(ViolationType).abstract }
12
- def violation_type; end
13
-
14
- sig { params(reference: Reference).returns(T::Boolean).abstract }
15
- def invalid_reference?(reference); end
16
- end
17
- end
@@ -1,26 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- class DependencyChecker
6
- extend T::Sig
7
- include Checker
8
-
9
- sig { override.returns(ViolationType) }
10
- def violation_type
11
- ViolationType::Dependency
12
- end
13
-
14
- sig do
15
- override
16
- .params(reference: Packwerk::Reference)
17
- .returns(T::Boolean)
18
- end
19
- def invalid_reference?(reference)
20
- return false unless reference.source_package
21
- return false unless reference.source_package.enforce_dependencies?
22
- return false if reference.source_package.dependency?(reference.constant.package)
23
- true
24
- end
25
- end
26
- end
@@ -1,43 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module Generators
6
- class InflectionsFile
7
- extend T::Sig
8
-
9
- class << self
10
- def generate(root:, out:)
11
- new(root, out: out).generate
12
- end
13
- end
14
-
15
- def initialize(root, out: $stdout)
16
- @root = root
17
- @out = out
18
- end
19
-
20
- sig { returns(T::Boolean) }
21
- def generate
22
- ruby_inflection_file_exist = Dir.glob("#{@root}/**/inflections.rb").any?
23
- yaml_inflection_file_exist = Dir.glob("#{@root}/**/inflections.yml").any?
24
-
25
- if !ruby_inflection_file_exist || yaml_inflection_file_exist
26
- return true
27
- end
28
-
29
- @out.puts("📦 Generating `inflections.yml` file...")
30
-
31
- destination_file_path = File.join(@root, "config")
32
- FileUtils.mkdir_p(destination_file_path)
33
-
34
- source_file_path = File.join(__dir__, "/templates/inflections.yml")
35
- FileUtils.cp(source_file_path, destination_file_path)
36
-
37
- @out.puts("✅ `inflections.yml` generated in #{destination_file_path}")
38
-
39
- true
40
- end
41
- end
42
- end
43
- end
@@ -1,6 +0,0 @@
1
- # List your inflections in this file instead of `inflections.rb`
2
- # See steps to set up custom inflections:
3
- # https://github.com/Shopify/packwerk/blob/main/USAGE.md#Inflections
4
-
5
- # acronym:
6
- # - "GraphQL"
@@ -1,33 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require "yaml"
5
-
6
- module Packwerk
7
- module Inflections
8
- class Custom
9
- SUPPORTED_INFLECTION_METHODS = %w(acronym human irregular plural singular uncountable)
10
-
11
- attr_accessor :inflections
12
-
13
- def initialize(custom_inflection_file = nil)
14
- if custom_inflection_file && File.exist?(custom_inflection_file)
15
- @inflections = YAML.load_file(custom_inflection_file) || {}
16
-
17
- invalid_inflections = @inflections.keys - SUPPORTED_INFLECTION_METHODS
18
- raise ArgumentError, "Unsupported inflection types: #{invalid_inflections}" if invalid_inflections.any?
19
- else
20
- @inflections = []
21
- end
22
- end
23
-
24
- def apply_to(inflections_object)
25
- @inflections.each do |inflection_type, inflections|
26
- inflections.each do |inflection|
27
- inflections_object.public_send(inflection_type, *Array(inflection))
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,73 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module Packwerk
5
- module Inflections
6
- module Default
7
- class << self
8
- def apply_to(inflections_object)
9
- # copied from active_support/inflections
10
- # https://github.com/rails/rails/blob/d2ae2c3103e93783971d5356d0b3fd1b4070d6cf/activesupport/lib/active_support/inflections.rb#L12
11
- inflections_object.plural(/$/, "s")
12
- inflections_object.plural(/s$/i, "s")
13
- inflections_object.plural(/^(ax|test)is$/i, '\1es')
14
- inflections_object.plural(/(octop|vir)us$/i, '\1i')
15
- inflections_object.plural(/(octop|vir)i$/i, '\1i')
16
- inflections_object.plural(/(alias|status)$/i, '\1es')
17
- inflections_object.plural(/(bu)s$/i, '\1ses')
18
- inflections_object.plural(/(buffal|tomat)o$/i, '\1oes')
19
- inflections_object.plural(/([ti])um$/i, '\1a')
20
- inflections_object.plural(/([ti])a$/i, '\1a')
21
- inflections_object.plural(/sis$/i, "ses")
22
- inflections_object.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
23
- inflections_object.plural(/(hive)$/i, '\1s')
24
- inflections_object.plural(/([^aeiouy]|qu)y$/i, '\1ies')
25
- inflections_object.plural(/(x|ch|ss|sh)$/i, '\1es')
26
- inflections_object.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
27
- inflections_object.plural(/^(m|l)ouse$/i, '\1ice')
28
- inflections_object.plural(/^(m|l)ice$/i, '\1ice')
29
- inflections_object.plural(/^(ox)$/i, '\1en')
30
- inflections_object.plural(/^(oxen)$/i, '\1')
31
- inflections_object.plural(/(quiz)$/i, '\1zes')
32
-
33
- inflections_object.singular(/s$/i, "")
34
- inflections_object.singular(/(ss)$/i, '\1')
35
- inflections_object.singular(/(n)ews$/i, '\1ews')
36
- inflections_object.singular(/([ti])a$/i, '\1um')
37
- inflections_object.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
38
- inflections_object.singular(/(^analy)(sis|ses)$/i, '\1sis')
39
- inflections_object.singular(/([^f])ves$/i, '\1fe')
40
- inflections_object.singular(/(hive)s$/i, '\1')
41
- inflections_object.singular(/(tive)s$/i, '\1')
42
- inflections_object.singular(/([lr])ves$/i, '\1f')
43
- inflections_object.singular(/([^aeiouy]|qu)ies$/i, '\1y')
44
- inflections_object.singular(/(s)eries$/i, '\1eries')
45
- inflections_object.singular(/(m)ovies$/i, '\1ovie')
46
- inflections_object.singular(/(x|ch|ss|sh)es$/i, '\1')
47
- inflections_object.singular(/^(m|l)ice$/i, '\1ouse')
48
- inflections_object.singular(/(bus)(es)?$/i, '\1')
49
- inflections_object.singular(/(o)es$/i, '\1')
50
- inflections_object.singular(/(shoe)s$/i, '\1')
51
- inflections_object.singular(/(cris|test)(is|es)$/i, '\1is')
52
- inflections_object.singular(/^(a)x[ie]s$/i, '\1xis')
53
- inflections_object.singular(/(octop|vir)(us|i)$/i, '\1us')
54
- inflections_object.singular(/(alias|status)(es)?$/i, '\1')
55
- inflections_object.singular(/^(ox)en/i, '\1')
56
- inflections_object.singular(/(vert|ind)ices$/i, '\1ex')
57
- inflections_object.singular(/(matr)ices$/i, '\1ix')
58
- inflections_object.singular(/(quiz)zes$/i, '\1')
59
- inflections_object.singular(/(database)s$/i, '\1')
60
-
61
- inflections_object.irregular("person", "people")
62
- inflections_object.irregular("man", "men")
63
- inflections_object.irregular("child", "children")
64
- inflections_object.irregular("sex", "sexes")
65
- inflections_object.irregular("move", "moves")
66
- inflections_object.irregular("zombie", "zombies")
67
-
68
- inflections_object.uncountable(%w(equipment information rice money species series fish sheep jeans police))
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,48 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require "active_support/inflector"
5
-
6
- module Packwerk
7
- class Inflector
8
- class << self
9
- extend T::Sig
10
-
11
- def default
12
- @default ||= new(custom_inflector: Inflections::Custom.new)
13
- end
14
-
15
- sig { params(inflections_file: String).returns(::Packwerk::Inflector) }
16
- def from_file(inflections_file)
17
- new(custom_inflector: Inflections::Custom.new(inflections_file))
18
- end
19
- end
20
-
21
- extend T::Sig
22
- include ::ActiveSupport::Inflector # For #camelize, #classify, #pluralize, #singularize
23
-
24
- sig do
25
- params(
26
- custom_inflector: Inflections::Custom
27
- ).void
28
- end
29
- def initialize(custom_inflector:)
30
- @inflections = ::ActiveSupport::Inflector::Inflections.new
31
-
32
- Inflections::Default.apply_to(@inflections)
33
- custom_inflector.apply_to(@inflections)
34
- end
35
-
36
- def pluralize(word, count = nil)
37
- if count == 1
38
- singularize(word)
39
- else
40
- super(word)
41
- end
42
- end
43
-
44
- def inflections(_ = nil)
45
- @inflections
46
- end
47
- end
48
- end