tapioca 0.10.5 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9df4814fb4f17b9f1d53aab7a9b9b23498cfea0330fb48b47d909af119ac6ea0
4
- data.tar.gz: 7f2d233a47a7ceb2b4a1f4894c794d65c2cca9c9e1547022630d7b395de0cd47
3
+ metadata.gz: f32d4fd559ee85f540926b3faa454aaf2ddd919b502438bf2deda24a4b04f855
4
+ data.tar.gz: 9368c2329923554e639310003630d36f9bf7a2f895df619cfe844dacd9a2c176
5
5
  SHA512:
6
- metadata.gz: f65d462c261005c62b31f0864df29b550d5a07551433203f485f8f66c57a8e100fccdb1deb1b7f29e185a1f6e8bf5b4e9f59387a1ba24ea8b4cff168b1b4ca12
7
- data.tar.gz: 721c40a48f379eda0e6302ff59b2a3228f0262c5d2b2bac1111016d92ec02597e9d35c28a38a6fcc903a8ac13b0b8c4dddcc7e1d747907390762f47601d19e68
6
+ metadata.gz: c997e7598a5cef84e52935b0f9681ca636fef5fb866d30f1e6d19e2912ae38b5ec7499e69cde6cd147b4a723214d80abb109dbd523e48f143eae0b1edbefd46e
7
+ data.tar.gz: 33882ab5de1b8b43d775bdb20b0fab39d97ebe2ce7b346bb9828b64e27dd99bb7d46814ac441dd1b6b7aadb3b4aa02f93a652d4e6fa42c34ac83241eb9eb78d7
data/lib/tapioca/cli.rb CHANGED
@@ -130,11 +130,15 @@ module Tapioca
130
130
  type: :string,
131
131
  desc: "The path to the Rails application",
132
132
  default: "."
133
- def dsl(*constants)
133
+ def dsl(*constant_or_paths)
134
134
  set_environment(options)
135
135
 
136
+ # Assume anything starting with a capital letter or colon is a class, otherwise a path
137
+ constants, paths = constant_or_paths.partition { |c| c =~ /\A[A-Z:]/ }
138
+
136
139
  command = Commands::Dsl.new(
137
140
  requested_constants: constants,
141
+ requested_paths: paths.map { |p| Pathname.new(p) },
138
142
  outpath: Pathname.new(options[:outdir]),
139
143
  only: options[:only],
140
144
  exclude: options[:exclude],
@@ -189,6 +189,8 @@ module Tapioca
189
189
 
190
190
  sig { params(name: String, content: String).returns(String) }
191
191
  def add_header(name, content)
192
+ # WARNING: Changing this header could impact how GitHub determines if the file should be hidden:
193
+ # https://github.com/github/linguist/pull/6143
192
194
  header = <<~COMMENT
193
195
  # DO NOT EDIT MANUALLY
194
196
  # This file was pulled from a central RBI files repository.
@@ -41,6 +41,7 @@ module Tapioca
41
41
  create_file(@sorbet_config, <<~CONTENT, skip: true, force: false)
42
42
  --dir
43
43
  .
44
+ --ignore=tmp/
44
45
  --ignore=vendor/
45
46
  CONTENT
46
47
  end
@@ -10,6 +10,7 @@ module Tapioca
10
10
  sig do
11
11
  params(
12
12
  requested_constants: T::Array[String],
13
+ requested_paths: T::Array[Pathname],
13
14
  outpath: Pathname,
14
15
  only: T::Array[String],
15
16
  exclude: T::Array[String],
@@ -27,6 +28,7 @@ module Tapioca
27
28
  end
28
29
  def initialize(
29
30
  requested_constants:,
31
+ requested_paths:,
30
32
  outpath:,
31
33
  only:,
32
34
  exclude:,
@@ -42,6 +44,7 @@ module Tapioca
42
44
  app_root: "."
43
45
  )
44
46
  @requested_constants = requested_constants
47
+ @requested_paths = requested_paths
45
48
  @outpath = outpath
46
49
  @only = only
47
50
  @exclude = exclude
@@ -63,7 +66,7 @@ module Tapioca
63
66
  def list_compilers
64
67
  Loaders::Dsl.load_application(
65
68
  tapioca_path: @tapioca_path,
66
- eager_load: @requested_constants.empty?,
69
+ eager_load: @requested_constants.empty? && @requested_paths.empty?,
67
70
  app_root: @app_root,
68
71
  )
69
72
 
@@ -101,6 +104,15 @@ module Tapioca
101
104
  end
102
105
  say("")
103
106
 
107
+ unless @requested_paths.empty?
108
+ constants_from_paths = Static::SymbolLoader.symbols_from_paths(@requested_paths).to_a
109
+ if constants_from_paths.empty?
110
+ say_error("\nWarning: No constants found in: #{@requested_paths.map(&:to_s).join(", ")}", :yellow)
111
+ end
112
+
113
+ @requested_constants += constants_from_paths
114
+ end
115
+
104
116
  outpath = @should_verify ? Pathname.new(Dir.mktmpdir) : @outpath
105
117
  rbi_files_to_purge = existing_rbi_filenames(@requested_constants)
106
118
 
@@ -153,6 +165,7 @@ module Tapioca
153
165
  def create_pipeline
154
166
  Tapioca::Dsl::Pipeline.new(
155
167
  requested_constants: constantize(@requested_constants),
168
+ requested_paths: @requested_paths,
156
169
  requested_compilers: constantize_compilers(@only),
157
170
  excluded_compilers: constantize_compilers(@exclude),
158
171
  error_handler: ->(error) {
@@ -167,8 +180,9 @@ module Tapioca
167
180
  filenames = if requested_constants.empty?
168
181
  Pathname.glob(path / "**/*.rbi")
169
182
  else
170
- requested_constants.map do |constant_name|
171
- dsl_rbi_filename(constant_name)
183
+ requested_constants.filter_map do |constant_name|
184
+ filename = dsl_rbi_filename(constant_name)
185
+ filename if File.exist?(filename)
172
186
  end
173
187
  end
174
188
 
@@ -58,27 +58,67 @@ module Tapioca
58
58
  T::Array[String],
59
59
  )
60
60
 
61
+ # Taken directly from the AASM::Base class, here:
62
+ # https://github.com/aasm/aasm/blob/0e03746a2b86558ee1bf7bd7db873938cbb3b29b/lib/aasm/base.rb#L145-L171
63
+ GLOBAL_CALLBACKS =
64
+ T.let(
65
+ [
66
+ "after_all_transitions",
67
+ "after_all_transactions",
68
+ "before_all_transactions",
69
+ "before_all_events",
70
+ "after_all_events",
71
+ "error_on_all_events",
72
+ "ensure_on_all_events",
73
+ ].freeze,
74
+ T::Array[String],
75
+ )
76
+
61
77
  ConstantType = type_member { { fixed: T.all(::AASM::ClassMethods, Class) } }
62
78
 
63
79
  sig { override.void }
64
80
  def decorate
65
- aasm = constant.aasm
66
- return if !aasm || aasm.states.empty?
81
+ state_machine_store = ::AASM::StateMachineStore.fetch(constant)
82
+ return unless state_machine_store
83
+
84
+ state_machines = state_machine_store.machine_names.map { |n| constant.aasm(n) }
85
+ return if state_machines.all? { |m| m.states.empty? }
67
86
 
68
87
  root.create_path(constant) do |model|
69
- # Create all of the constants and methods for each state
70
- aasm.states.each do |state|
71
- model.create_constant("STATE_#{state.name.upcase}", value: "T.let(T.unsafe(nil), Symbol)")
72
- model.create_method("#{state.name}?", return_type: "T::Boolean")
73
- end
88
+ state_machines.each do |state_machine|
89
+ namespace = state_machine.__send__(:namespace)
74
90
 
75
- # Create all of the methods for each event
76
- parameters = [create_rest_param("opts", type: "T.untyped")]
77
- aasm.events.each do |event|
78
- model.create_method(event.name.to_s, parameters: parameters)
79
- model.create_method("#{event.name}!", parameters: parameters)
80
- model.create_method("#{event.name}_without_validation!", parameters: parameters)
81
- model.create_method("may_#{event.name}?", return_type: "T::Boolean")
91
+ # Create all of the constants and methods for each state
92
+ state_machine.states.each do |state|
93
+ name = state.name
94
+ name = "#{namespace}_#{name}" if namespace
95
+
96
+ model.create_constant("STATE_#{name.upcase}", value: "T.let(T.unsafe(nil), Symbol)")
97
+ model.create_method("#{name}?", return_type: "T::Boolean")
98
+ end
99
+
100
+ # Create all of the methods for each event
101
+ parameters = [create_rest_param("opts", type: "T.untyped")]
102
+ state_machine.events.each do |event|
103
+ model.create_method(event.name.to_s, parameters: parameters)
104
+ model.create_method("#{event.name}!", parameters: parameters)
105
+ model.create_method("#{event.name}_without_validation!", parameters: parameters)
106
+ model.create_method("may_#{event.name}?", return_type: "T::Boolean")
107
+
108
+ # For events, if there's a namespace the default methods are created in addition to
109
+ # namespaced ones.
110
+ next unless namespace
111
+
112
+ name = "#{event.name}_#{namespace}"
113
+
114
+ model.create_method(name.to_s, parameters: parameters)
115
+ model.create_method("#{name}!", parameters: parameters)
116
+ model.create_method("may_#{name}?", return_type: "T::Boolean")
117
+
118
+ # There's no namespaced method created for `_without_validation`, so skip
119
+ # defining a method for:
120
+ # "#{name}_without_validation!"
121
+ end
82
122
  end
83
123
 
84
124
  # Create the overall state machine method, which will return an
@@ -106,6 +146,18 @@ module Tapioca
106
146
  ],
107
147
  )
108
148
 
149
+ constant_name = name_of(constant)
150
+
151
+ GLOBAL_CALLBACKS.each do |method|
152
+ machine.create_method(
153
+ method,
154
+ parameters: [
155
+ create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
156
+ create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
157
+ ],
158
+ )
159
+ end
160
+
109
161
  # Create a private event class that we can pass around for the
110
162
  # purpose of binding all of the callbacks without having to
111
163
  # explicitly bind self in each one.
@@ -115,7 +167,7 @@ module Tapioca
115
167
  method,
116
168
  parameters: [
117
169
  create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
118
- create_block_param("block", type: "T.nilable(T.proc.bind(#{name_of(constant)}).void)"),
170
+ create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
119
171
  ],
120
172
  )
121
173
  end
@@ -156,7 +156,7 @@ module Tapioca
156
156
  sig { params(mod: Module).returns(T::Array[String]) }
157
157
  def gather_includes(mod)
158
158
  mod.ancestors
159
- .reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.name.nil? }
159
+ .reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || name_of(ancestor).nil? }
160
160
  .map { |ancestor| T.must(qualified_name_of(ancestor)) }
161
161
  .reverse
162
162
  end
@@ -16,7 +16,8 @@ module Tapioca
16
16
  # `Tapioca::Dsl::Compilers::ActiveRecordColumns` refines RBI files for subclasses of
17
17
  # [`ActiveRecord::Base`](https://api.rubyonrails.org/classes/ActiveRecord/Base.html).
18
18
  # This compiler is only responsible for defining the attribute methods that would be
19
- # created for the columns that are defined in the Active Record model.
19
+ # created for columns and virtual attributes that are defined in the Active Record
20
+ # model.
20
21
  #
21
22
  # For example, with the following model class:
22
23
  # ~~~rb
@@ -109,8 +110,7 @@ module Tapioca
109
110
 
110
111
  root.create_path(constant) do |model|
111
112
  model.create_module(AttributeMethodsModuleName) do |mod|
112
- constant.columns_hash.each_key do |column_name|
113
- column_name = column_name.to_s
113
+ constant.attribute_names.each do |column_name|
114
114
  add_methods_for_attribute(mod, column_name)
115
115
  end
116
116