tapioca 0.4.8 → 0.4.13
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/Gemfile +3 -1
- data/README.md +8 -6
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +38 -39
- data/lib/tapioca/compilers/dsl/action_mailer.rb +4 -4
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +49 -48
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +60 -65
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +27 -23
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +18 -17
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +8 -7
- data/lib/tapioca/compilers/dsl/active_resource.rb +5 -4
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +6 -7
- data/lib/tapioca/compilers/dsl/base.rb +1 -1
- data/lib/tapioca/compilers/dsl/frozen_record.rb +25 -25
- data/lib/tapioca/compilers/dsl/{active_record_identity_cache.rb → identity_cache.rb} +11 -10
- data/lib/tapioca/compilers/dsl/protobuf.rb +1 -1
- data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +83 -0
- data/lib/tapioca/compilers/dsl/smart_properties.rb +1 -1
- data/lib/tapioca/compilers/dsl/state_machines.rb +75 -73
- data/lib/tapioca/compilers/dsl/url_helpers.rb +9 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +62 -30
- data/lib/tapioca/version.rb +1 -1
- metadata +4 -3
@@ -15,7 +15,7 @@ module Tapioca
|
|
15
15
|
module Compilers
|
16
16
|
module Dsl
|
17
17
|
# `Tapioca::Compilers::Dsl::SmartProperties` generates RBI files for classes that include
|
18
|
-
# `SmartProperties`
|
18
|
+
# [`SmartProperties`](https://github.com/t6d/smart_properties).
|
19
19
|
#
|
20
20
|
# For example, with the following class that includes `SmartProperties`:
|
21
21
|
#
|
@@ -15,10 +15,12 @@ end
|
|
15
15
|
module Tapioca
|
16
16
|
module Compilers
|
17
17
|
module Dsl
|
18
|
-
# `
|
19
|
-
# (
|
20
|
-
# methods generated by
|
21
|
-
#
|
18
|
+
# `Tapioca::Compilers::Dsl::StateMachines` generates RBI files for classes that setup a
|
19
|
+
# [`state_machine`](https://github.com/state-machines/state_machines). The generator also
|
20
|
+
# processes the extra methods generated by
|
21
|
+
# [StateMachines Active Record](https://github.com/state-machines/state_machines-activerecord)
|
22
|
+
# and [StateMachines Active Model](https://github.com/state-machines/state_machines-activemodel)
|
23
|
+
# integrations.
|
22
24
|
#
|
23
25
|
# For example, with the following `Vehicle` class:
|
24
26
|
#
|
@@ -45,75 +47,75 @@ module Tapioca
|
|
45
47
|
# # vehicle.rbi
|
46
48
|
# # typed: true
|
47
49
|
# class Vehicle
|
48
|
-
# include
|
49
|
-
# extend
|
50
|
-
# end
|
50
|
+
# include StateMachineInstanceHelperModule
|
51
|
+
# extend StateMachineClassHelperModule
|
51
52
|
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
53
|
+
# module StateMachineClassHelperModule
|
54
|
+
# sig { params(event: T.any(String, Symbol)).returns(String) }
|
55
|
+
# def human_alarm_state_event_name(event); end
|
55
56
|
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
57
|
+
# sig { params(state: T.any(String, Symbol)).returns(String) }
|
58
|
+
# def human_alarm_state_name(state); end
|
59
|
+
# end
|
59
60
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
61
|
+
# module StateMachineInstanceHelperModule
|
62
|
+
# sig { returns(T::Boolean) }
|
63
|
+
# def alarm_active?; end
|
63
64
|
#
|
64
|
-
#
|
65
|
-
#
|
65
|
+
# sig { returns(T::Boolean) }
|
66
|
+
# def alarm_off?; end
|
66
67
|
#
|
67
|
-
#
|
68
|
-
#
|
68
|
+
# sig { returns(Integer) }
|
69
|
+
# def alarm_state; end
|
69
70
|
#
|
70
|
-
#
|
71
|
-
#
|
71
|
+
# sig { params(value: Integer).returns(Integer) }
|
72
|
+
# def alarm_state=(value); end
|
72
73
|
#
|
73
|
-
#
|
74
|
-
#
|
74
|
+
# sig { params(state: T.any(String, Symbol)).returns(T::Boolean) }
|
75
|
+
# def alarm_state?(state); end
|
75
76
|
#
|
76
|
-
#
|
77
|
-
#
|
77
|
+
# sig { params(args: T.untyped).returns(T::Array[T.any(String, Symbol)]) }
|
78
|
+
# def alarm_state_events(*args); end
|
78
79
|
#
|
79
|
-
#
|
80
|
-
#
|
80
|
+
# sig { returns(T.any(String, Symbol)) }
|
81
|
+
# def alarm_state_name; end
|
81
82
|
#
|
82
|
-
#
|
83
|
-
#
|
83
|
+
# sig { params(args: T.untyped).returns(T::Array[::StateMachines::Transition]) }
|
84
|
+
# def alarm_state_paths(*args); end
|
84
85
|
#
|
85
|
-
#
|
86
|
-
#
|
86
|
+
# sig { params(args: T.untyped).returns(T::Array[::StateMachines::Transition]) }
|
87
|
+
# def alarm_state_transitions(*args); end
|
87
88
|
#
|
88
|
-
#
|
89
|
-
#
|
89
|
+
# sig { returns(T::Boolean) }
|
90
|
+
# def can_disable_alarm?; end
|
90
91
|
#
|
91
|
-
#
|
92
|
-
#
|
92
|
+
# sig { returns(T::Boolean) }
|
93
|
+
# def can_enable_alarm?; end
|
93
94
|
#
|
94
|
-
#
|
95
|
-
#
|
95
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
96
|
+
# def disable_alarm(*args); end
|
96
97
|
#
|
97
|
-
#
|
98
|
-
#
|
98
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
99
|
+
# def disable_alarm!(*args); end
|
99
100
|
#
|
100
|
-
#
|
101
|
-
#
|
101
|
+
# sig { params(args: T.untyped).returns(T.nilable(::StateMachines::Transition)) }
|
102
|
+
# def disable_alarm_transition(*args); end
|
102
103
|
#
|
103
|
-
#
|
104
|
-
#
|
104
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
105
|
+
# def enable_alarm(*args); end
|
105
106
|
#
|
106
|
-
#
|
107
|
-
#
|
107
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
108
|
+
# def enable_alarm!(*args); end
|
108
109
|
#
|
109
|
-
#
|
110
|
-
#
|
110
|
+
# sig { params(args: T.untyped).returns(T.nilable(::StateMachines::Transition)) }
|
111
|
+
# def enable_alarm_transition(*args); end
|
111
112
|
#
|
112
|
-
#
|
113
|
-
#
|
113
|
+
# sig { params(event: T.any(String, Symbol), args: T.untyped).returns(T::Boolean) }
|
114
|
+
# def fire_alarm_state_event(event, *args); end
|
114
115
|
#
|
115
|
-
#
|
116
|
-
#
|
116
|
+
# sig { returns(String) }
|
117
|
+
# def human_alarm_state_name; end
|
118
|
+
# end
|
117
119
|
# end
|
118
120
|
# ~~~
|
119
121
|
class StateMachines < Base
|
@@ -123,34 +125,34 @@ module Tapioca
|
|
123
125
|
def decorate(root, constant)
|
124
126
|
return if constant.state_machines.empty?
|
125
127
|
|
126
|
-
|
127
|
-
|
128
|
+
root.path(constant) do |klass|
|
129
|
+
instance_module_name = "StateMachineInstanceHelperModule"
|
130
|
+
class_module_name = "StateMachineClassHelperModule"
|
128
131
|
|
129
|
-
|
130
|
-
|
132
|
+
instance_module = klass.create_module(instance_module_name)
|
133
|
+
class_module = klass.create_module(class_module_name)
|
131
134
|
|
132
|
-
|
133
|
-
|
135
|
+
constant.state_machines.each_value do |machine|
|
136
|
+
state_type = state_type_for(machine)
|
134
137
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
define_state_accessor(instance_module, machine, state_type)
|
139
|
+
define_state_predicate(instance_module, machine)
|
140
|
+
define_event_helpers(instance_module, machine)
|
141
|
+
define_path_helpers(instance_module, machine)
|
142
|
+
define_name_helpers(instance_module, class_module, machine)
|
143
|
+
define_scopes(class_module, machine)
|
141
144
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
+
define_state_methods(instance_module, machine)
|
146
|
+
define_event_methods(instance_module, machine)
|
147
|
+
end
|
145
148
|
|
146
|
-
|
149
|
+
matching_integration_name = ::StateMachines::Integrations.match(constant)&.integration_name
|
147
150
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
151
|
+
case matching_integration_name
|
152
|
+
when :active_record
|
153
|
+
define_activerecord_methods(instance_module)
|
154
|
+
end
|
152
155
|
|
153
|
-
root.path(constant) do |klass|
|
154
156
|
klass.create_include(instance_module_name)
|
155
157
|
klass.create_extend(class_module_name)
|
156
158
|
end
|
@@ -15,8 +15,7 @@ module Tapioca
|
|
15
15
|
module Compilers
|
16
16
|
module Dsl
|
17
17
|
# `Tapioca::Compilers::Dsl::UrlHelpers` generates RBI files for classes that include or extend
|
18
|
-
# `Rails.application.routes.url_helpers`
|
19
|
-
# (see https://api.rubyonrails.org/v5.1.7/classes/ActionDispatch/Routing/UrlFor.html#module-ActionDispatch::Routing::UrlFor-label-URL+generation+for+named+routes).
|
18
|
+
# [`Rails.application.routes.url_helpers`](https://api.rubyonrails.org/v5.1.7/classes/ActionDispatch/Routing/UrlFor.html#module-ActionDispatch::Routing::UrlFor-label-URL+generation+for+named+routes).
|
20
19
|
#
|
21
20
|
# For example, with the following setup:
|
22
21
|
#
|
@@ -32,7 +31,12 @@ module Tapioca
|
|
32
31
|
# ~~~rb
|
33
32
|
# app/models/post.rb
|
34
33
|
# class Post
|
35
|
-
#
|
34
|
+
# # Use `T.unsafe` so that Sorbet does not complain about a dynamic
|
35
|
+
# # module being included. This allows the `include` to happen properly
|
36
|
+
# # at runtime but Sorbet won't see the include. However, since this
|
37
|
+
# # generator will generate the proper RBI files for the include,
|
38
|
+
# # static type checking will work as expected.
|
39
|
+
# T.unsafe(self).include Rails.application.routes.url_helpers
|
36
40
|
# end
|
37
41
|
# ~~~
|
38
42
|
#
|
@@ -126,8 +130,8 @@ module Tapioca
|
|
126
130
|
sig { params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(Module)).void }
|
127
131
|
def generate_module_for(root, constant)
|
128
132
|
root.create_module(T.must(constant.name)) do |mod|
|
129
|
-
mod.create_include("ActionDispatch::Routing::UrlFor")
|
130
|
-
mod.create_include("ActionDispatch::Routing::PolymorphicRoutes")
|
133
|
+
mod.create_include("::ActionDispatch::Routing::UrlFor")
|
134
|
+
mod.create_include("::ActionDispatch::Routing::PolymorphicRoutes")
|
131
135
|
|
132
136
|
constant.instance_methods(false).each do |method|
|
133
137
|
mod.create_method(
|
@@ -74,9 +74,9 @@ module Tapioca
|
|
74
74
|
compile(symbol, constant)
|
75
75
|
end
|
76
76
|
|
77
|
-
sig { params(symbol: String).returns(BasicObject).checked(:never) }
|
78
|
-
def resolve_constant(symbol)
|
79
|
-
Object.const_get(symbol,
|
77
|
+
sig { params(symbol: String, inherit: T::Boolean).returns(BasicObject).checked(:never) }
|
78
|
+
def resolve_constant(symbol, inherit: false)
|
79
|
+
Object.const_get(symbol, inherit)
|
80
80
|
rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
|
81
81
|
nil
|
82
82
|
end
|
@@ -122,12 +122,15 @@ module Tapioca
|
|
122
122
|
def compile_alias(name, constant)
|
123
123
|
return if symbol_ignored?(name)
|
124
124
|
|
125
|
-
|
125
|
+
target = name_of(constant)
|
126
|
+
# If target has no name, let's make it an anonymous class or module with `Class.new` or `Module.new`
|
127
|
+
target = "#{constant.class}.new" unless target
|
128
|
+
|
126
129
|
add_to_alias_namespace(name)
|
127
130
|
|
128
131
|
return if IGNORED_SYMBOLS.include?(name)
|
129
132
|
|
130
|
-
indented("#{name} = #{
|
133
|
+
indented("#{name} = #{target}")
|
131
134
|
end
|
132
135
|
|
133
136
|
sig do
|
@@ -292,33 +295,16 @@ module Tapioca
|
|
292
295
|
|
293
296
|
sig { params(constant: Module).returns(String) }
|
294
297
|
def compile_mixins(constant)
|
295
|
-
|
296
|
-
if constant.is_a?(Class)
|
297
|
-
ancestors = constant.superclass&.ancestors || Object.ancestors
|
298
|
-
Set.new(ancestors)
|
299
|
-
else
|
300
|
-
Module.ancestors
|
301
|
-
end
|
302
|
-
|
303
|
-
inherited_singleton_class_ancestors =
|
304
|
-
if constant.is_a?(Class)
|
305
|
-
Set.new(singleton_class_of(constant.superclass).ancestors)
|
306
|
-
else
|
307
|
-
Module.ancestors
|
308
|
-
end
|
298
|
+
singleton_class = singleton_class_of(constant)
|
309
299
|
|
310
|
-
interesting_ancestors =
|
311
|
-
|
300
|
+
interesting_ancestors = interesting_ancestors_of(constant)
|
301
|
+
interesting_singleton_class_ancestors = interesting_ancestors_of(singleton_class)
|
312
302
|
|
313
303
|
prepend = interesting_ancestors.take_while { |c| !are_equal?(constant, c) }
|
314
304
|
include = interesting_ancestors.drop(prepend.size + 1)
|
315
|
-
extend =
|
316
|
-
|
317
|
-
|
318
|
-
inherited_singleton_class_ancestors.include?(mod) ||
|
319
|
-
!public_module?(mod) ||
|
320
|
-
Module != class_of(mod)
|
321
|
-
end
|
305
|
+
extend = interesting_singleton_class_ancestors.reject do |mod|
|
306
|
+
!public_module?(mod) || Module != class_of(mod) || are_equal?(mod, singleton_class)
|
307
|
+
end
|
322
308
|
|
323
309
|
prepends = prepend
|
324
310
|
.reverse
|
@@ -757,18 +743,59 @@ module Tapioca
|
|
757
743
|
Module.instance_method(:name).bind(constant).call
|
758
744
|
end
|
759
745
|
|
760
|
-
sig { params(constant:
|
746
|
+
sig { params(constant: Module).returns(Class) }
|
761
747
|
def singleton_class_of(constant)
|
762
748
|
Object.instance_method(:singleton_class).bind(constant).call
|
763
749
|
end
|
764
750
|
|
751
|
+
sig { params(constant: Module).returns(T::Array[Module]) }
|
752
|
+
def ancestors_of(constant)
|
753
|
+
Module.instance_method(:ancestors).bind(constant).call
|
754
|
+
end
|
755
|
+
|
756
|
+
sig { params(constant: Module).returns(T::Array[Module]) }
|
757
|
+
def inherited_ancestors_of(constant)
|
758
|
+
if Class === constant
|
759
|
+
ancestors_of(superclass_of(constant) || Object)
|
760
|
+
else
|
761
|
+
Module.ancestors
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
sig { params(constant: Module).returns(T::Array[Module]) }
|
766
|
+
def interesting_ancestors_of(constant)
|
767
|
+
inherited_ancestors_ids = Set.new(
|
768
|
+
inherited_ancestors_of(constant).map { |mod| object_id_of(mod) }
|
769
|
+
)
|
770
|
+
# TODO: There is actually a bug here where this will drop modules that
|
771
|
+
# may be included twice. For example:
|
772
|
+
#
|
773
|
+
# ```ruby
|
774
|
+
# class Foo
|
775
|
+
# prepend Kernel
|
776
|
+
# end
|
777
|
+
# ````
|
778
|
+
# would give:
|
779
|
+
# ```ruby
|
780
|
+
# Foo.ancestors #=> [Kernel, Foo, Object, Kernel, BasicObject]
|
781
|
+
# ````
|
782
|
+
# but since we drop `Kernel` whenever we match it, we would miss
|
783
|
+
# the `prepend Kernel` in the output.
|
784
|
+
#
|
785
|
+
# Instead, we should only drop the tail matches of the ancestors and
|
786
|
+
# inherited ancestors, past the location of the constant itself.
|
787
|
+
constant.ancestors.reject do |mod|
|
788
|
+
inherited_ancestors_ids.include?(object_id_of(mod))
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
765
792
|
sig { params(constant: Module).returns(T.nilable(String)) }
|
766
793
|
def name_of(constant)
|
767
794
|
name = name_of_proxy_target(constant)
|
768
795
|
return name if name
|
769
796
|
name = raw_name_of(constant)
|
770
797
|
return if name.nil?
|
771
|
-
return unless are_equal?(constant, resolve_constant(name))
|
798
|
+
return unless are_equal?(constant, resolve_constant(name, inherit: true))
|
772
799
|
name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
|
773
800
|
name
|
774
801
|
end
|
@@ -817,6 +844,11 @@ module Tapioca
|
|
817
844
|
constant.to_s.gsub(/\bAttachedClass\b/, "T.attached_class")
|
818
845
|
end
|
819
846
|
|
847
|
+
sig { params(object: Object).returns(T::Boolean).checked(:never) }
|
848
|
+
def object_id_of(object)
|
849
|
+
Object.instance_method(:object_id).bind(object).call
|
850
|
+
end
|
851
|
+
|
820
852
|
sig { params(constant: Module, other: BasicObject).returns(T::Boolean).checked(:never) }
|
821
853
|
def are_equal?(constant, other)
|
822
854
|
BasicObject.instance_method(:equal?).bind(constant).call(other)
|
data/lib/tapioca/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapioca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2021-01-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pry
|
@@ -116,14 +116,15 @@ files:
|
|
116
116
|
- lib/tapioca/compilers/dsl/active_record_associations.rb
|
117
117
|
- lib/tapioca/compilers/dsl/active_record_columns.rb
|
118
118
|
- lib/tapioca/compilers/dsl/active_record_enum.rb
|
119
|
-
- lib/tapioca/compilers/dsl/active_record_identity_cache.rb
|
120
119
|
- lib/tapioca/compilers/dsl/active_record_scope.rb
|
121
120
|
- lib/tapioca/compilers/dsl/active_record_typed_store.rb
|
122
121
|
- lib/tapioca/compilers/dsl/active_resource.rb
|
123
122
|
- lib/tapioca/compilers/dsl/active_support_current_attributes.rb
|
124
123
|
- lib/tapioca/compilers/dsl/base.rb
|
125
124
|
- lib/tapioca/compilers/dsl/frozen_record.rb
|
125
|
+
- lib/tapioca/compilers/dsl/identity_cache.rb
|
126
126
|
- lib/tapioca/compilers/dsl/protobuf.rb
|
127
|
+
- lib/tapioca/compilers/dsl/sidekiq_worker.rb
|
127
128
|
- lib/tapioca/compilers/dsl/smart_properties.rb
|
128
129
|
- lib/tapioca/compilers/dsl/state_machines.rb
|
129
130
|
- lib/tapioca/compilers/dsl/url_helpers.rb
|