tapioca 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +6 -4
- data/Rakefile +1 -0
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +1 -0
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +11 -0
- data/lib/tapioca/compilers/dsl/active_record_identity_cache.rb +1 -2
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +1 -1
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +0 -2
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +1 -1
- data/lib/tapioca/compilers/dsl/protobuf.rb +8 -8
- data/lib/tapioca/compilers/dsl/url_helpers.rb +68 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +40 -19
- data/lib/tapioca/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6ca30be86eac3958354ca4204904993088bfeeef36c72d63b428ccc5ff3eff3
|
4
|
+
data.tar.gz: e218a8ed57c6eb6c46b00f423771fa1a4874a8f0a945d8f5683e849fe5ca9e91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39b2b67d35896d998f0f11dcdeda386e6e8312e124b12d8e5e252650417ba3c8a452aedfe014059064ca69e465d97089bfad55f1801d6667612902a4edc24903
|
7
|
+
data.tar.gz: 0fa4fe00a45d1f0e870f6d2cf985291ee1ed3f78d339c1f27be5653cff99490de31c6907abc462f1c1c7c197d7eb3eba63c2a90764c56a89fd607fd950c4a493
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -97,6 +97,12 @@ Command: `tapioca todo`
|
|
97
97
|
|
98
98
|
This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved constants as empty modules.
|
99
99
|
|
100
|
+
### Generate DSL RBI files
|
101
|
+
|
102
|
+
Command: `tapioca dsl [constant...]`
|
103
|
+
|
104
|
+
This will generate DSL RBIs for specified constants (or for all handled constants, if a constant name is not supplied). You can read about DSL RBI generators supplied by `tapioca` in [the manual](manual/generators.md).
|
105
|
+
|
100
106
|
### Flags
|
101
107
|
|
102
108
|
- `--prerequire [file]`: A file to be required before `Bundler.require` is called.
|
@@ -105,10 +111,6 @@ This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved consta
|
|
105
111
|
- `--generate-command [command]`: The command to run to regenerate RBI files (used in header comment of the RBI files), defaults to the current command.
|
106
112
|
- `--typed-overrides [gem:level]`: Overrides typed sigils for generated gem RBIs for gem `gem` to level `level` (`level` can be one of `ignore`, `false`, `true`, `strict`, or `strong`, see [the Sorbet docs](https://sorbet.org/docs/static#file-level-granularity-strictness-levels) for more details).
|
107
113
|
|
108
|
-
### Strong typing option for ActiveRecord column methods
|
109
|
-
|
110
|
-
`tapioca` gives you the option to generate stricter type signatures for your ActiveRecord column types. By default, methods generated for columns that are defined in the schema have signatures of T.untyped. However, if the object extends a module with name StrongTypeGeneration, tapioca will generate stricter signatures that follow closely with the types defined in the schema. Expectation is the StrongTypeGeneration module you define in your application won't allow objects to be initialized with "bad state". It will check all the attributes that are not nillable to ensure they are not nil.
|
111
|
-
|
112
114
|
## Contributing
|
113
115
|
|
114
116
|
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tapioca. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://github.com/Shopify/tapioca/blob/master/CODE_OF_CONDUCT.md) code of conduct.
|
data/Rakefile
CHANGED
@@ -17,6 +17,17 @@ module Tapioca
|
|
17
17
|
# responsible for defining the attribute methods that would be created for the columns that
|
18
18
|
# are defined in the Active Record model.
|
19
19
|
#
|
20
|
+
# **Note:** This generator, by default, generates weak signatures for column methods and treats each
|
21
|
+
# column to be `T.untyped`. This is done on purpose to ensure that the nilability of Active Record
|
22
|
+
# columns do not make it hard for existing code to adopt gradual typing. It is possible, however, to
|
23
|
+
# generate stricter type signatures for your ActiveRecord column types. If your ActiveRecord model extends
|
24
|
+
# a module with name `StrongTypeGeneration`, this generator will generate stricter signatures that follow
|
25
|
+
# closely with the types defined in the schema.
|
26
|
+
#
|
27
|
+
# The `StrongTypeGeneration` module you define in your application should add an `after_initialize` callback
|
28
|
+
# to the model and ensure that all the non-nilable attributes of the model are actually initialized with non-`nil`
|
29
|
+
# values.
|
30
|
+
#
|
20
31
|
# For example, with the following model class:
|
21
32
|
#
|
22
33
|
# ~~~rb
|
@@ -16,7 +16,7 @@ module Tapioca
|
|
16
16
|
module Compilers
|
17
17
|
module Dsl
|
18
18
|
# `Tapioca::Compilers::DSL::ActiveRecordIdentityCache` generates RBI files for ActiveRecord models
|
19
|
-
# that use `include IdentityCache
|
19
|
+
# that use `include IdentityCache`.
|
20
20
|
# `IdentityCache` is a blob level caching solution to plug into ActiveRecord. (see https://github.com/Shopify/identity_cache).
|
21
21
|
#
|
22
22
|
# For example, with the following ActiveRecord class:
|
@@ -61,7 +61,6 @@ module Tapioca
|
|
61
61
|
# def fetch_by_title_and_review_date(title, review_date, includes: nil); end
|
62
62
|
# end
|
63
63
|
# ~~~
|
64
|
-
|
65
64
|
class ActiveRecordIdentityCache < Base
|
66
65
|
extend T::Sig
|
67
66
|
|
@@ -37,7 +37,7 @@ module Tapioca
|
|
37
37
|
# module Post::GeneratedRelationMethods
|
38
38
|
# sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
|
39
39
|
# def private_kind(*args, &blk); end
|
40
|
-
|
40
|
+
#
|
41
41
|
# sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
|
42
42
|
# def public_kind(*args, &blk); end
|
43
43
|
# end
|
@@ -12,19 +12,19 @@ module Tapioca
|
|
12
12
|
module Compilers
|
13
13
|
module Dsl
|
14
14
|
# `Tapioca::Compilers::Dsl::Protobuf` decorates RBI files for subclasses of
|
15
|
-
# `Google::Protobuf::MessageExts
|
16
|
-
# (see https://github.com/coinbase/protoc-gen-rbi).
|
15
|
+
# `Google::Protobuf::MessageExts` (see https://github.com/protocolbuffers/protobuf/tree/master/ruby).
|
17
16
|
#
|
18
17
|
# For example, with the following "cart.rb" file:
|
19
18
|
#
|
20
19
|
# ~~~rb
|
21
20
|
# Google::Protobuf::DescriptorPool.generated_pool.build do
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
21
|
+
# add_file("cart.proto", :syntax => :proto3) do
|
22
|
+
# add_message "MyCart" do
|
23
|
+
# optional :shop_id, :int32, 1
|
24
|
+
# optional :customer_id, :int64, 2
|
25
|
+
# optional :number_value, :double, 3
|
26
|
+
# optional :string_value, :string, 4
|
27
|
+
# end
|
28
28
|
# end
|
29
29
|
# end
|
30
30
|
# ~~~
|
@@ -14,6 +14,74 @@ end
|
|
14
14
|
module Tapioca
|
15
15
|
module Compilers
|
16
16
|
module Dsl
|
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).
|
20
|
+
#
|
21
|
+
# For example, with the following setup:
|
22
|
+
#
|
23
|
+
# ~~~rb
|
24
|
+
# # config/application.rb
|
25
|
+
# class Application < Rails::Application
|
26
|
+
# routes.draw do
|
27
|
+
# resource :index
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# ~~~
|
31
|
+
#
|
32
|
+
# ~~~rb
|
33
|
+
# app/models/post.rb
|
34
|
+
# class Post
|
35
|
+
# include Rails.application.routes.url_helpers
|
36
|
+
# end
|
37
|
+
# ~~~
|
38
|
+
#
|
39
|
+
# this generator will produce the following RBI files:
|
40
|
+
#
|
41
|
+
# ~~~rbi
|
42
|
+
# # generated_path_helpers_module.rbi
|
43
|
+
# # typed: true
|
44
|
+
# module GeneratedPathHelpersModule
|
45
|
+
# include ActionDispatch::Routing::PolymorphicRoutes
|
46
|
+
# include ActionDispatch::Routing::UrlFor
|
47
|
+
#
|
48
|
+
# sig { params(args: T.untyped).returns(String) }
|
49
|
+
# def edit_index_path(*args); end
|
50
|
+
#
|
51
|
+
# sig { params(args: T.untyped).returns(String) }
|
52
|
+
# def index_path(*args); end
|
53
|
+
#
|
54
|
+
# sig { params(args: T.untyped).returns(String) }
|
55
|
+
# def new_index_path(*args); end
|
56
|
+
# end
|
57
|
+
# ~~~
|
58
|
+
#
|
59
|
+
# ~~~rbi
|
60
|
+
# # generated_url_helpers_module.rbi
|
61
|
+
# # typed: true
|
62
|
+
# module GeneratedUrlHelpersModule
|
63
|
+
# include ActionDispatch::Routing::PolymorphicRoutes
|
64
|
+
# include ActionDispatch::Routing::UrlFor
|
65
|
+
#
|
66
|
+
# sig { params(args: T.untyped).returns(String) }
|
67
|
+
# def edit_index_url(*args); end
|
68
|
+
#
|
69
|
+
# sig { params(args: T.untyped).returns(String) }
|
70
|
+
# def index_url(*args); end
|
71
|
+
#
|
72
|
+
# sig { params(args: T.untyped).returns(String) }
|
73
|
+
# def new_index_url(*args); end
|
74
|
+
# end
|
75
|
+
# ~~~
|
76
|
+
#
|
77
|
+
# ~~~rbi
|
78
|
+
# # post.rbi
|
79
|
+
# # typed: true
|
80
|
+
# class Post
|
81
|
+
# include GeneratedPathHelpersModule
|
82
|
+
# include GeneratedUrlHelpersModule
|
83
|
+
# end
|
84
|
+
# ~~~
|
17
85
|
class UrlHelpers < Base
|
18
86
|
extend T::Sig
|
19
87
|
|
@@ -383,8 +383,18 @@ module Tapioca
|
|
383
383
|
indented("include(#{qualified_name_of(mod)})")
|
384
384
|
end.join("\n")
|
385
385
|
|
386
|
-
|
387
|
-
|
386
|
+
ancestors = singleton_class_of(constant).ancestors
|
387
|
+
extends_as_concern = ancestors.any? do |mod|
|
388
|
+
qualified_name_of(mod) == "::ActiveSupport::Concern"
|
389
|
+
end
|
390
|
+
class_methods_module = resolve_constant("#{name_of(constant)}::ClassMethods")
|
391
|
+
|
392
|
+
mixed_in_module = if extends_as_concern && Module === class_methods_module
|
393
|
+
class_methods_module
|
394
|
+
else
|
395
|
+
dynamic_extends.find do |mod|
|
396
|
+
mod != constant && public_module?(mod)
|
397
|
+
end
|
388
398
|
end
|
389
399
|
|
390
400
|
return result if mixed_in_module.nil?
|
@@ -494,15 +504,16 @@ module Tapioca
|
|
494
504
|
return if symbol_ignored?(symbol_name) && !method_in_gem?(method)
|
495
505
|
|
496
506
|
signature = signature_of(method)
|
497
|
-
method = signature.method if signature
|
507
|
+
method = T.let(signature.method, UnboundMethod) if signature
|
498
508
|
|
499
509
|
method_name = method.name.to_s
|
500
510
|
return unless valid_method_name?(method_name)
|
501
511
|
return if struct_method?(constant, method_name)
|
502
512
|
return if method_name.start_with?("__t_props_generated_")
|
503
513
|
|
504
|
-
|
505
|
-
|
514
|
+
parameters = T.let(method.parameters, T::Array[[Symbol, T.nilable(Symbol)]])
|
515
|
+
|
516
|
+
sanitized_parameters = parameters.map do |type, name|
|
506
517
|
unless name
|
507
518
|
# For attr_writer methods, Sorbet signatures have the name
|
508
519
|
# of the method (without the trailing = sign) as the name of
|
@@ -512,14 +523,15 @@ module Tapioca
|
|
512
523
|
# method and the parameter is required and there is a single
|
513
524
|
# parameter and the signature also defines a single parameter and
|
514
525
|
# the name of the method ends with a = character.
|
515
|
-
writer_method_with_sig =
|
516
|
-
type == :req &&
|
517
|
-
|
526
|
+
writer_method_with_sig = (
|
527
|
+
signature && type == :req &&
|
528
|
+
parameters.size == 1 &&
|
518
529
|
signature.arg_types.size == 1 &&
|
519
530
|
method_name[-1] == "="
|
531
|
+
)
|
520
532
|
|
521
533
|
name = if writer_method_with_sig
|
522
|
-
method_name[0...-1].to_sym
|
534
|
+
T.must(method_name[0...-1]).to_sym
|
523
535
|
else
|
524
536
|
:_
|
525
537
|
end
|
@@ -528,6 +540,10 @@ module Tapioca
|
|
528
540
|
# Sanitize param names
|
529
541
|
name = name.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
|
530
542
|
|
543
|
+
[type, name]
|
544
|
+
end
|
545
|
+
|
546
|
+
parameter_list = sanitized_parameters.map do |type, name|
|
531
547
|
case type
|
532
548
|
when :req
|
533
549
|
name
|
@@ -546,25 +562,30 @@ module Tapioca
|
|
546
562
|
end
|
547
563
|
end.join(', ')
|
548
564
|
|
549
|
-
|
565
|
+
parameter_list = "(#{parameter_list})" if parameter_list != ""
|
566
|
+
signature_str = indented(compile_signature(signature, sanitized_parameters)) if signature
|
550
567
|
|
551
|
-
signature_str = indented(compile_signature(signature)) if signature
|
552
568
|
[
|
553
569
|
signature_str,
|
554
|
-
indented("def #{method_name}#{
|
570
|
+
indented("def #{method_name}#{parameter_list}; end"),
|
555
571
|
].compact.join("\n")
|
556
572
|
end
|
557
573
|
|
558
574
|
TYPE_PARAMETER_MATCHER = /T\.type_parameter\(:?([[:word:]]+)\)/
|
559
575
|
|
560
|
-
sig { params(signature: T.untyped).returns(String) }
|
561
|
-
def compile_signature(signature)
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
576
|
+
sig { params(signature: T.untyped, parameters: T::Array[[Symbol, String]]).returns(String) }
|
577
|
+
def compile_signature(signature, parameters)
|
578
|
+
parameter_types = T.let(signature.arg_types.to_h, T::Hash[Symbol, T::Types::Base])
|
579
|
+
parameter_types.merge!(signature.kwarg_types)
|
580
|
+
parameter_types[signature.rest_name] = signature.rest_type if signature.has_rest
|
581
|
+
parameter_types[signature.keyrest_name] = signature.keyrest_type if signature.has_keyrest
|
582
|
+
parameter_types[signature.block_name] = signature.block_type if signature.block_name
|
583
|
+
|
584
|
+
params = parameters.map do |_, name|
|
585
|
+
type = parameter_types[name.to_sym]
|
586
|
+
"#{name}: #{type}"
|
587
|
+
end.join(", ")
|
566
588
|
|
567
|
-
params = params.compact.map { |name, type| "#{name}: #{type}" }.join(", ")
|
568
589
|
returns = type_of(signature.return_type)
|
569
590
|
|
570
591
|
type_parameters = (params + returns).scan(TYPE_PARAMETER_MATCHER).flatten.uniq.map { |p| ":#{p}" }.join(", ")
|
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.5
|
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: 2020-
|
14
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pry
|
@@ -155,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
155
|
requirements:
|
156
156
|
- - ">="
|
157
157
|
- !ruby/object:Gem::Version
|
158
|
-
version: 2.
|
158
|
+
version: '2.4'
|
159
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
160
|
requirements:
|
161
161
|
- - ">="
|