orthoses-rails 0.8.0 → 1.0.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 +4 -4
- data/README.md +13 -65
- data/lib/generators/orthoses/rails/install_generator.rb +18 -0
- data/lib/orthoses/active_record/belongs_to.rb +15 -4
- data/lib/orthoses/active_record/enum.rb +5 -0
- data/lib/orthoses/active_record/generated_attribute_methods.rb +47 -55
- data/lib/orthoses/active_record/has_many.rb +15 -4
- data/lib/orthoses/active_record/has_one.rb +12 -2
- data/lib/orthoses/active_record/relation.rb +56 -0
- data/lib/orthoses/active_record.rb +36 -0
- data/lib/orthoses/active_support/delegation.rb +20 -9
- data/lib/orthoses/active_support/time_with_zone.rb +35 -28
- data/lib/orthoses/rails/application.rb +33 -0
- data/lib/orthoses/rails/version.rb +1 -1
- data/lib/orthoses/rails.rb +3 -2
- metadata +10 -47
- data/examples/rails/Gemfile +0 -16
- data/examples/rails/Gemfile.lock +0 -179
- data/examples/rails/Rakefile +0 -328
- data/examples/rails/config/database.yml +0 -8
- data/examples/rails/config/storage.yml +0 -3
- data/examples/rails/known_sig/actionpack/7.0/action_controller/metal.rbs +0 -4
- data/examples/rails/known_sig/activemodel/7.0/active_model/serialization.rbs +0 -4
- data/examples/rails/known_sig/activemodel/7.0/active_model/validations.rbs +0 -4
- data/examples/rails/known_sig/activerecord/6.0/_active_record_relation.rbs +0 -49
- data/examples/rails/known_sig/activerecord/6.0/_active_record_relation_class_methods.rbs +0 -45
- data/examples/rails/known_sig/activerecord/6.0/active_record/result.rbs +0 -5
- data/examples/rails/known_sig/activerecord/6.1/_active_record_relation.rbs +0 -49
- data/examples/rails/known_sig/activerecord/6.1/_active_record_relation_class_methods.rbs +0 -45
- data/examples/rails/known_sig/activerecord/6.1/active_record/result.rbs +0 -5
- data/examples/rails/known_sig/activerecord/7.0/_active_record_relation.rbs +0 -49
- data/examples/rails/known_sig/activerecord/7.0/_active_record_relation_class_methods.rbs +0 -45
- data/examples/rails/known_sig/activerecord/7.0/active_record/encryption/context.rbs +0 -9
- data/examples/rails/known_sig/activerecord/7.0/active_record/result.rbs +0 -5
- data/examples/rails/known_sig/activesupport/7.0/active_support/callbacks/callback_chain.rbs +0 -9
- data/examples/rails/known_sig/activesupport/7.0/active_support/duration.rbs +0 -4
- data/examples/rails/known_sig/activesupport/7.0/active_support/hash_with_indifferent_access.rbs +0 -6
- data/examples/rails/known_sig/activesupport/7.0/active_support/multibyte/chars.rbs +0 -7
- data/examples/rails/known_sig/activesupport/7.0/active_support/time_with_zone.rbs +0 -5
- data/examples/rails/known_sig/activesupport/7.0/active_support/time_zone.rbs +0 -3
- data/examples/rails/known_sig/activesupport/7.0/date.rbs +0 -6
- data/examples/rails/known_sig/activesupport/7.0/date_and_time/zones.rbs +0 -4
- data/examples/rails/known_sig/activesupport/7.0/hash_with_indifferent_access.rbs +0 -2
- data/examples/rails/known_sig/activesupport/7.0/integer.rbs +0 -9
- data/examples/rails/known_sig/activesupport/7.0/numeric.rbs +0 -15
- data/examples/rails/known_sig/activesupport/7.0/string.rbs +0 -4
- data/examples/rails/known_sig/activesupport/7.0/time.rbs +0 -46
- data/examples/rails/tasks/action_pack.rake +0 -141
- data/examples/rails/tasks/action_view.rake +0 -77
- data/examples/rails/tasks/active_job.rake +0 -99
- data/examples/rails/tasks/active_model.rake +0 -46
- data/examples/rails/tasks/active_record.rake +0 -88
- data/examples/rails/tasks/active_storage.rake +0 -94
- data/examples/rails/tasks/active_support.rake +0 -99
- data/examples/rails/tasks/railties.rake +0 -34
- data/orthoses-rails.gemspec +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 620d49df1787f2c79e641435da0cf872d0d8604930729bc746a72ec787677b78
|
4
|
+
data.tar.gz: fc06f6c06c7941f5ca36bbc1aabf6730e641e7cac2ea2a4f7ee1242284ebb4de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63e8a69d07faab3bda23d71df987b87352e245b46d14cf824576c2a66502ad95e2523bc8f11eb8030e3325707b7b9b8e2e28103c560dba01bb0234ecf23fb54c
|
7
|
+
data.tar.gz: 13fd887d6564a51e19a0cdea17b80b5d3cfedd5a56f4096c1ec44a27dca3ba3e6a57c34dd22aa069a808fea34ec2eab1f265f0fa7d42f1394f8c00937642eb03
|
data/README.md
CHANGED
@@ -3,38 +3,19 @@
|
|
3
3
|
[Orthoses](https://github.com/ksss/orthoses) extension for Ruby on Rails.
|
4
4
|
Orthoses::Rails automatically generates RBS for methods added by Rails.
|
5
5
|
|
6
|
-
##
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
- `Enum`
|
20
|
-
- Add signatures that generated from `enum`
|
21
|
-
- `HasMany`
|
22
|
-
- Add signatures that generated form `has_many`.
|
23
|
-
- `HasOne`
|
24
|
-
- Add signatures that generated form `has_one`.
|
25
|
-
- `Scope`
|
26
|
-
- Add signatures that generated form `scope`.
|
27
|
-
|
28
|
-
### Orthoses::ActiveSupport
|
29
|
-
|
30
|
-
- `ClassAttribute`
|
31
|
-
- Add signatures that generated form `class_attribute`.
|
32
|
-
- `Configurable`
|
33
|
-
- Add signatures that generated from `config_accessor`
|
34
|
-
- `Delegation`
|
35
|
-
- Add signatures that generated from `delegate`. The type definition of the method or instance variable specified by `to` is required.
|
36
|
-
- `MattrAccessor`
|
37
|
-
- Add signatures that generated form `mattr_accessor`, `cattr_accessor`, `mattr_reader`, `cattr_reader`, `mattr_writer` and `cattr_writer`.
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
Build your Rake task for RBS generation.
|
9
|
+
|
10
|
+
```rb
|
11
|
+
$ bin/rails generate orthoses:rails:install
|
12
|
+
```
|
13
|
+
|
14
|
+
Then run the rake task.
|
15
|
+
|
16
|
+
```
|
17
|
+
$ bin/rails orthoses:rails
|
18
|
+
```
|
38
19
|
|
39
20
|
## Installation
|
40
21
|
|
@@ -46,39 +27,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
46
27
|
|
47
28
|
$ gem install orthoses-rails
|
48
29
|
|
49
|
-
## Usage
|
50
|
-
|
51
|
-
Build your Rake task for RBS generation.
|
52
|
-
|
53
|
-
```rb
|
54
|
-
task :rbs_generate => :environment do
|
55
|
-
Orthoses::Builder.new do
|
56
|
-
use Orthoses::CreateFileByName
|
57
|
-
base_dir: Rails.root.join("sig/out"),
|
58
|
-
header: "# !!! GENERATED CODE !!!"
|
59
|
-
use Orthoses::Filter do |name, _content|
|
60
|
-
path, _lineno = Object.const_source_location(name)
|
61
|
-
return false unless path
|
62
|
-
%r{app/models}.match?(path)
|
63
|
-
end
|
64
|
-
use YourCustom::Middleware
|
65
|
-
use Orthoses::ActiveModel::HasSecurePassword
|
66
|
-
use Orthoses::ActiveRecord::BelongsTo
|
67
|
-
use Orthoses::ActiveRecord::HasMany
|
68
|
-
use Orthoses::ActiveRecord::HasOne
|
69
|
-
use Orthoses::ActiveSupport::ClassAttribute
|
70
|
-
use Orthoses::ActiveSupport::MattrAccessor
|
71
|
-
use Orthoses::Mixin
|
72
|
-
use Orthoses::Constant, strict: false
|
73
|
-
use Orthoses::ObjectSpaceAll
|
74
|
-
use Orthoses::Autoload
|
75
|
-
run -> {
|
76
|
-
Rails.application.eager_load!
|
77
|
-
}
|
78
|
-
end.call
|
79
|
-
end
|
80
|
-
```
|
81
|
-
|
82
30
|
## Development
|
83
31
|
|
84
32
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/base'
|
4
|
+
require 'orthoses/rails'
|
5
|
+
|
6
|
+
module Orthoses
|
7
|
+
module Rails
|
8
|
+
module Generators
|
9
|
+
class InstallGenerator < ::Rails::Generators::Base
|
10
|
+
source_root File.expand_path('templates', __dir__)
|
11
|
+
|
12
|
+
def copy_rake_task_file
|
13
|
+
copy_file "rails.rake", "lib/tasks/orthoses/rails.rake"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -15,7 +15,19 @@ module Orthoses
|
|
15
15
|
|
16
16
|
lines = base.reflect_on_all_associations(:belongs_to).flat_map do |ref|
|
17
17
|
# FIXME: Can I get list of class for polymorphic?
|
18
|
-
type = ref.polymorphic?
|
18
|
+
type = if ref.polymorphic?
|
19
|
+
'untyped'
|
20
|
+
else
|
21
|
+
begin
|
22
|
+
Utils.module_name(ref.klass) or next
|
23
|
+
rescue NameError => e
|
24
|
+
while e
|
25
|
+
Orthoses.logger.warn(e.message)
|
26
|
+
e = e.cause
|
27
|
+
end
|
28
|
+
next
|
29
|
+
end
|
30
|
+
end
|
19
31
|
opt = "#{type}?"
|
20
32
|
|
21
33
|
[
|
@@ -38,9 +50,8 @@ module Orthoses
|
|
38
50
|
content.concat(lines)
|
39
51
|
end
|
40
52
|
|
41
|
-
|
42
|
-
|
43
|
-
end
|
53
|
+
sig = "include #{generated_association_methods}"
|
54
|
+
store[base_name] << sig if !store[base_name].body.include?(sig)
|
44
55
|
end
|
45
56
|
end
|
46
57
|
end
|
@@ -20,6 +20,11 @@ module Orthoses
|
|
20
20
|
enum.captures.each do |capture|
|
21
21
|
base_name = Utils.module_name(capture.method.receiver) or next
|
22
22
|
|
23
|
+
sig = "include #{base_name}::ActiveRecord_Enum_EnumMethods"
|
24
|
+
if !store[base_name].body.include?(sig)
|
25
|
+
store[base_name] << sig
|
26
|
+
end
|
27
|
+
|
23
28
|
if capture.argument[:definitions]
|
24
29
|
# on rails 6
|
25
30
|
definitions = capture.argument[:definitions].slice!(:_prefix, :_suffix, :_scopes, :_default)
|
@@ -3,6 +3,30 @@
|
|
3
3
|
module Orthoses
|
4
4
|
module ActiveRecord
|
5
5
|
class GeneratedAttributeMethods
|
6
|
+
TARGET_TYPE_MAP = {
|
7
|
+
"attribute" => "() -> %<type>s",
|
8
|
+
"attribute=" => "(%<type>s) -> %<type>s",
|
9
|
+
"attribute?" => "() -> bool",
|
10
|
+
"attribute_before_last_save" => "() -> %<opt>s",
|
11
|
+
"attribute_before_type_cast" => "() -> %<type>s",
|
12
|
+
"attribute_came_from_user?" => "() -> bool",
|
13
|
+
"attribute_change" => "() -> [%<opt>s, %<opt>s]",
|
14
|
+
"attribute_change_to_be_saved" => "() -> Array[%<opt>s]?",
|
15
|
+
"attribute_changed?" => "() -> bool",
|
16
|
+
"attribute_for_database" => "() -> %<type>s",
|
17
|
+
"attribute_in_database" => "() -> %<opt>s",
|
18
|
+
"attribute_previous_change" => "() -> Array[%<opt>s]?",
|
19
|
+
"attribute_previously_changed?" => "() -> bool",
|
20
|
+
"attribute_previously_was" => "() -> %<opt>s",
|
21
|
+
"attribute_was" => "() -> %<opt>s",
|
22
|
+
"attribute_will_change!" => "() -> void",
|
23
|
+
"clear_attribute_change" => "() -> void",
|
24
|
+
"restore_attribute!" => "() -> void",
|
25
|
+
"saved_change_to_attribute" => "() -> Array[%<opt>s]?",
|
26
|
+
"saved_change_to_attribute?" => "() -> bool",
|
27
|
+
"will_save_change_to_attribute?" => "() -> bool",
|
28
|
+
}
|
29
|
+
|
6
30
|
def initialize(loader)
|
7
31
|
@loader = loader
|
8
32
|
end
|
@@ -12,71 +36,39 @@ module Orthoses
|
|
12
36
|
::ActiveRecord::Base.descendants.each do |klass|
|
13
37
|
next if klass.abstract_class?
|
14
38
|
|
15
|
-
|
16
|
-
|
17
|
-
|
39
|
+
base_klass_name = Utils.module_name(klass) || next
|
40
|
+
begin
|
41
|
+
klass.columns
|
42
|
+
rescue ::ActiveRecord::StatementInvalid => e
|
43
|
+
Orthoses.logger.warn(e.to_s)
|
44
|
+
next
|
45
|
+
end
|
46
|
+
|
47
|
+
lines = []
|
48
|
+
klass.columns_hash.each do |name, col|
|
49
|
+
req = ActiveRecord.sql_type_to_rbs(col.type)
|
18
50
|
opt = "#{req}?"
|
19
51
|
type = col.null ? opt : req
|
20
52
|
|
21
|
-
|
22
|
-
|
23
|
-
"def #{
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
"
|
29
|
-
|
30
|
-
"def #{col.name}_previous_change: () -> Array[#{opt}]?",
|
31
|
-
"def #{col.name}_previously_was: () -> #{opt}",
|
32
|
-
"def #{col.name}_before_last_save: () -> #{opt}",
|
33
|
-
"def #{col.name}_change_to_be_saved: () -> Array[#{opt}]?",
|
34
|
-
"def #{col.name}_in_database: () -> #{opt}",
|
35
|
-
"def saved_change_to_#{col.name}: () -> Array[#{opt}]?",
|
36
|
-
"def saved_change_to_#{col.name}?: () -> bool",
|
37
|
-
"def will_save_change_to_#{col.name}?: () -> bool",
|
38
|
-
"def restore_#{col.name}!: () -> void",
|
39
|
-
"def clear_#{col.name}_change: () -> void",
|
40
|
-
]
|
53
|
+
::ActiveRecord::Base.attribute_method_matchers.each do |matcher|
|
54
|
+
tmpl = TARGET_TYPE_MAP[matcher.target]
|
55
|
+
lines << "def #{matcher.method_name(name)}: #{tmpl % {type: type, opt: opt}}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
klass.attribute_aliases.each do |alias_name, column_name|
|
59
|
+
::ActiveRecord::Base.attribute_method_matchers.each do |matcher|
|
60
|
+
lines << "alias #{matcher.method_name(alias_name)} #{matcher.method_name(column_name)}"
|
61
|
+
end
|
41
62
|
end
|
42
|
-
generated_attribute_methods = "#{name}::AttributeMethods::GeneratedAttributeMethods"
|
43
|
-
store[name] << "include #{generated_attribute_methods}"
|
44
63
|
|
45
|
-
|
64
|
+
generated_attribute_methods = "#{base_klass_name}::GeneratedAttributeMethods"
|
65
|
+
store[base_klass_name] << "include #{generated_attribute_methods}"
|
66
|
+
|
46
67
|
store[generated_attribute_methods].header = "module #{generated_attribute_methods}"
|
47
68
|
store[generated_attribute_methods].concat(lines)
|
48
69
|
end
|
49
70
|
end
|
50
71
|
end
|
51
|
-
|
52
|
-
# Thanks https://github.com/pocke/rbs_rails/blob/8a128a8d29f0861aa2c25aa4110ff7c2ea674865/lib/rbs_rails/active_record.rb#L525-L551
|
53
|
-
def sql_type_to_rbs(t)
|
54
|
-
case t
|
55
|
-
when :integer
|
56
|
-
'Integer'
|
57
|
-
when :float
|
58
|
-
'Float'
|
59
|
-
when :decimal
|
60
|
-
'BigDecimal'
|
61
|
-
when :string, :text, :citext, :uuid, :binary
|
62
|
-
'String'
|
63
|
-
when :datetime
|
64
|
-
'ActiveSupport::TimeWithZone'
|
65
|
-
when :boolean
|
66
|
-
"bool"
|
67
|
-
when :jsonb, :json
|
68
|
-
"untyped"
|
69
|
-
when :date
|
70
|
-
'Date'
|
71
|
-
when :time
|
72
|
-
'Time'
|
73
|
-
when :inet
|
74
|
-
"IPAddr"
|
75
|
-
else
|
76
|
-
# Unknown column type, give up
|
77
|
-
'untyped'
|
78
|
-
end
|
79
|
-
end
|
80
72
|
end
|
81
73
|
end
|
82
74
|
end
|
@@ -13,14 +13,23 @@ module Orthoses
|
|
13
13
|
next if base.abstract_class?
|
14
14
|
base_name = Utils.module_name(base) || next
|
15
15
|
|
16
|
-
collection_proxy = "#{base_name}::ActiveRecord_Associations_CollectionProxy"
|
17
|
-
|
18
16
|
lines = base.reflect_on_all_associations(:has_many).flat_map do |ref|
|
19
17
|
singular_name = ref.name.to_s.singularize
|
18
|
+
type =
|
19
|
+
begin
|
20
|
+
Utils.module_name(ref.klass)
|
21
|
+
rescue NameError => e
|
22
|
+
while e
|
23
|
+
Orthoses.logger.warn(e.message)
|
24
|
+
e = e.cause
|
25
|
+
end
|
26
|
+
next
|
27
|
+
end
|
20
28
|
|
29
|
+
collection_proxy = "::#{type}::ActiveRecord_Associations_CollectionProxy"
|
21
30
|
[
|
22
31
|
"def #{ref.name}: () -> #{collection_proxy}",
|
23
|
-
"def #{ref.name}=: (#{collection_proxy} | Array[#{
|
32
|
+
"def #{ref.name}=: (#{collection_proxy} | Array[#{type}]) -> (#{collection_proxy} | Array[#{type}])",
|
24
33
|
"def #{singular_name}_ids: () -> Array[Integer]",
|
25
34
|
"def #{singular_name}_ids=: (Array[Integer]) -> Array[Integer]",
|
26
35
|
]
|
@@ -29,7 +38,9 @@ module Orthoses
|
|
29
38
|
generated_association_methods = "#{base_name}::GeneratedAssociationMethods"
|
30
39
|
store[generated_association_methods].header = "module #{generated_association_methods}"
|
31
40
|
store[generated_association_methods].concat(lines)
|
32
|
-
|
41
|
+
|
42
|
+
sig = "include #{generated_association_methods}"
|
43
|
+
store[base_name] << sig if !store[base_name].body.include?(sig)
|
33
44
|
end
|
34
45
|
end
|
35
46
|
end
|
@@ -14,7 +14,16 @@ module Orthoses
|
|
14
14
|
base_name = Utils.module_name(base) || next
|
15
15
|
|
16
16
|
lines = base.reflect_on_all_associations(:has_one).flat_map do |ref|
|
17
|
-
type =
|
17
|
+
type =
|
18
|
+
begin
|
19
|
+
Utils.module_name(ref.klass) or next
|
20
|
+
rescue NameError => e
|
21
|
+
while e
|
22
|
+
Orthoses.logger.warn(e.message)
|
23
|
+
e = e.cause
|
24
|
+
end
|
25
|
+
next
|
26
|
+
end
|
18
27
|
opt = "#{type}?"
|
19
28
|
|
20
29
|
[
|
@@ -31,7 +40,8 @@ module Orthoses
|
|
31
40
|
store[generated_association_methods].header = "module #{generated_association_methods}"
|
32
41
|
store[generated_association_methods].concat(lines)
|
33
42
|
|
34
|
-
|
43
|
+
sig = "include #{generated_association_methods}"
|
44
|
+
store[base_name] << sig if !store[base_name].body.include?(sig)
|
35
45
|
end
|
36
46
|
end
|
37
47
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveRecord
|
5
|
+
class Relation
|
6
|
+
def initialize(loader)
|
7
|
+
@loader = loader
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
@loader.call.tap do |store|
|
12
|
+
::ActiveRecord::Base.descendants.each do |klass|
|
13
|
+
next if klass.abstract_class?
|
14
|
+
|
15
|
+
primary_key = fetch_primary_key(klass)
|
16
|
+
|
17
|
+
model_name = Utils.module_name(klass) or next
|
18
|
+
class_specific_relation = "#{model_name}::ActiveRecord_Relation"
|
19
|
+
class_specific_proxy = "#{model_name}::ActiveRecord_Associations_CollectionProxy"
|
20
|
+
class_specific_generated_relation_methods = "#{model_name}::GeneratedRelationMethods"
|
21
|
+
|
22
|
+
store[class_specific_generated_relation_methods].tap do |c|
|
23
|
+
end
|
24
|
+
|
25
|
+
store[class_specific_relation].tap do |c|
|
26
|
+
c.header = "class #{class_specific_relation} < ::ActiveRecord::Relation"
|
27
|
+
c << "include #{class_specific_generated_relation_methods}"
|
28
|
+
c << "include _ActiveRecord_Relation[#{model_name}, #{primary_key}]"
|
29
|
+
c << "include Enumerable[#{model_name}]"
|
30
|
+
end
|
31
|
+
|
32
|
+
store[class_specific_proxy].tap do |c|
|
33
|
+
c.header = "class #{class_specific_proxy} < ::ActiveRecord::Associations::CollectionProxy"
|
34
|
+
c << "include _ActiveRecord_Relation[#{model_name}, #{primary_key}]"
|
35
|
+
end
|
36
|
+
|
37
|
+
store[model_name].tap do |c|
|
38
|
+
c << "extend _ActiveRecord_Relation_ClassMethods[#{model_name}, #{class_specific_relation}, #{primary_key}]"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def fetch_primary_key(klass)
|
47
|
+
type = klass.type_for_attribute(klass.primary_key).type
|
48
|
+
ActiveRecord.sql_type_to_rbs(type)
|
49
|
+
rescue ::ActiveRecord::StatementInvalid => e
|
50
|
+
Orthoses.logger.warn(e.to_s)
|
51
|
+
"untyped"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -7,4 +7,40 @@ require_relative 'active_record/generated_attribute_methods'
|
|
7
7
|
require_relative 'active_record/has_many'
|
8
8
|
require_relative 'active_record/has_one'
|
9
9
|
require_relative 'active_record/query_methods'
|
10
|
+
require_relative 'active_record/relation'
|
10
11
|
require_relative 'active_record/scope'
|
12
|
+
|
13
|
+
module Orthoses
|
14
|
+
module ActiveRecord
|
15
|
+
# Thanks https://github.com/pocke/rbs_rails/blob/8a128a8d29f0861aa2c25aa4110ff7c2ea674865/lib/rbs_rails/active_record.rb#L525-L551
|
16
|
+
def self.sql_type_to_rbs(t)
|
17
|
+
case t
|
18
|
+
when :integer, :big_integer
|
19
|
+
'::Integer'
|
20
|
+
when :float
|
21
|
+
'::Float'
|
22
|
+
when :decimal
|
23
|
+
'::BigDecimal'
|
24
|
+
when :string, :text, :citext, :uuid, :binary, :immutable_string
|
25
|
+
'::String'
|
26
|
+
when :datetime
|
27
|
+
'::ActiveSupport::TimeWithZone'
|
28
|
+
when :boolean
|
29
|
+
"bool"
|
30
|
+
when :date
|
31
|
+
'::Date'
|
32
|
+
when :time
|
33
|
+
'::Time'
|
34
|
+
when :cidr, :inet
|
35
|
+
"::IPAddr"
|
36
|
+
when :bit, :bit_varying, :enum, :hstore,
|
37
|
+
:interval, :jsonb, :json, :legacy_point, :money, :point, :vector, :xml
|
38
|
+
# FIXME
|
39
|
+
'untyped'
|
40
|
+
else
|
41
|
+
# Unknown column type, give up
|
42
|
+
'untyped'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -20,14 +20,16 @@ module Orthoses
|
|
20
20
|
delegate.captures.each do |capture|
|
21
21
|
receiver_name = Utils.module_name(capture.method.receiver) or next
|
22
22
|
receiver_content = store[receiver_name]
|
23
|
+
prefix = capture.argument[:private] ? "private " : ""
|
23
24
|
|
24
25
|
case capture.argument[:to]
|
26
|
+
# delegate :foo, to: Foo
|
25
27
|
when Module
|
26
28
|
to_module_name = Utils.module_name(capture.argument[:to]) or next
|
27
29
|
capture.argument[:methods].each do |arg|
|
28
30
|
if sig = resource.build_signature(to_module_name, arg, :singleton, false)
|
29
31
|
receiver_content << "# defined by `delegate` to: #{to_module_name}"
|
30
|
-
receiver_content << sig
|
32
|
+
receiver_content << "#{prefix}#{sig}"
|
31
33
|
else
|
32
34
|
Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_module_name}.#{arg.inspect} in #{capture.argument.inspect}")
|
33
35
|
end
|
@@ -35,20 +37,28 @@ module Orthoses
|
|
35
37
|
else
|
36
38
|
to_name = capture.argument[:to].to_s.to_sym
|
37
39
|
tag, to_return_type = resource.find(receiver_name, to_name, :instance, false)
|
38
|
-
|
40
|
+
if tag == :multi
|
41
|
+
to_return_type = if to_return_type.length == 1
|
42
|
+
to_return_type.first.type.return_type
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
39
47
|
|
40
48
|
case to_return_type
|
41
49
|
when nil, RBS::Types::Bases::Any
|
50
|
+
# no type found
|
42
51
|
capture.argument[:methods].each do |method|
|
43
52
|
receiver_content << "# defined by `delegate` to: #{to_return_type}##{to_name}"
|
44
|
-
receiver_content << "def #{method}: (*untyped, **untyped) -> untyped"
|
53
|
+
receiver_content << "#{prefix}def #{method}: (*untyped, **untyped) -> untyped"
|
45
54
|
end
|
46
55
|
else
|
56
|
+
# found return type in store or env
|
47
57
|
to_typename = to_return_type.name.relative!.to_s
|
48
58
|
capture.argument[:methods].each do |method|
|
49
59
|
if sig = resource.build_signature(to_typename, method, :instance, true)
|
50
60
|
receiver_content << "# defined by `delegate` to #{to_return_type}##{to_name}"
|
51
|
-
receiver_content << sig
|
61
|
+
receiver_content << "#{prefix}#{sig}"
|
52
62
|
else
|
53
63
|
Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_typename}##{method.inspect} in #{capture.argument.inspect}")
|
54
64
|
end
|
@@ -73,6 +83,7 @@ module Orthoses
|
|
73
83
|
typename = TypeName(mod_name).absolute!
|
74
84
|
|
75
85
|
if definition_method = build_definition(typename, kind)&.methods&.[](name)
|
86
|
+
# found in env
|
76
87
|
return [:multi, definition_method.defs.map(&:type)]
|
77
88
|
end
|
78
89
|
resolve_type_by_name(@store[mod_name].to_decl.members, name, kind, argument)
|
@@ -85,7 +96,7 @@ module Orthoses
|
|
85
96
|
when :singleton
|
86
97
|
@definition_builder.build_singleton(typename)
|
87
98
|
else
|
88
|
-
raise "
|
99
|
+
raise "bug"
|
89
100
|
end
|
90
101
|
rescue RuntimeError => e
|
91
102
|
if e.message.match?(/\AUnknown name for/)
|
@@ -115,13 +126,13 @@ module Orthoses
|
|
115
126
|
when RBS::AST::Members::MethodDefinition
|
116
127
|
next unless member.name == name && member.kind == kind
|
117
128
|
if argument
|
118
|
-
return [:multi, member.
|
129
|
+
return [:multi, member.overloads.map { |o| o.method_type }]
|
119
130
|
else
|
120
|
-
|
131
|
+
method_type = member.overloads.map(&:method_type).find do |method_type|
|
121
132
|
method_type.type.required_positionals.empty? && method_type.type.required_keywords.empty?
|
122
133
|
end
|
123
|
-
next unless
|
124
|
-
return [:single,
|
134
|
+
next unless method_type
|
135
|
+
return [:single, method_type.type.return_type]
|
125
136
|
end
|
126
137
|
when RBS::AST::Members::Var
|
127
138
|
next unless member.name == name
|
@@ -13,6 +13,7 @@ module Orthoses
|
|
13
13
|
store = @loader.call
|
14
14
|
|
15
15
|
time_with_zone_store = store["ActiveSupport::TimeWithZone"]
|
16
|
+
time_with_zone_store.body.replace(filter_decl(time_with_zone_store))
|
16
17
|
each_line_from_core_time_definition(store) do |line|
|
17
18
|
time_with_zone_store << line
|
18
19
|
end
|
@@ -22,63 +23,69 @@ module Orthoses
|
|
22
23
|
|
23
24
|
private
|
24
25
|
|
25
|
-
NOT_DELEGATE_METHODS = Set.new(%i[
|
26
|
-
utc
|
27
|
-
getgm
|
28
|
-
getutc
|
29
|
-
gmtime
|
30
|
-
localtime
|
31
|
-
])
|
32
|
-
|
33
26
|
TYPE_MERGE_METHODS = Set.new(%i[
|
34
27
|
+
|
35
28
|
-
|
36
29
|
])
|
37
30
|
|
31
|
+
def filter_decl(time_with_zone_store)
|
32
|
+
writer = RBS::Writer.new(out: StringIO.new)
|
33
|
+
time_with_zone_store.to_decl.members.each do |member|
|
34
|
+
# ActiveSupport::TimeWithZone.name has been deprecated
|
35
|
+
next if member.instance_of?(RBS::AST::Members::MethodDefinition) && member.kind == :singleton && member.name == :name
|
36
|
+
writer.write_member(member)
|
37
|
+
end
|
38
|
+
writer.out.string.each_line.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_signature(env, content)
|
42
|
+
buffer, directives, decls = RBS::Parser.parse_signature(content.to_rbs)
|
43
|
+
env.add_signature(buffer: buffer, directives: directives, decls: decls)
|
44
|
+
end
|
45
|
+
|
38
46
|
def each_line_from_core_time_definition(store)
|
39
47
|
type_name_time = TypeName("::Time")
|
40
48
|
type_name_time_with_zone = TypeName("::ActiveSupport::TimeWithZone")
|
41
49
|
env = Utils.rbs_environment(collection: true, cache: false)
|
42
|
-
|
43
|
-
env
|
44
|
-
env
|
45
|
-
env
|
46
|
-
env
|
47
|
-
env
|
48
|
-
env
|
49
|
-
env
|
50
|
-
env
|
50
|
+
|
51
|
+
add_signature(env, store["Time"])
|
52
|
+
add_signature(env, store["DateAndTime"])
|
53
|
+
add_signature(env, store["DateAndTime::Zones"])
|
54
|
+
add_signature(env, store["DateAndTime::Calculations"])
|
55
|
+
add_signature(env, store["DateAndTime::Compatibility"])
|
56
|
+
add_signature(env, store["ActiveSupport"])
|
57
|
+
add_signature(env, store["ActiveSupport::TimeZone"])
|
58
|
+
add_signature(env, store["ActiveSupport::Duration"])
|
59
|
+
add_signature(env, store["ActiveSupport::TimeWithZone"])
|
51
60
|
|
52
61
|
builder = RBS::DefinitionBuilder.new(env: env.resolve_type_names)
|
53
|
-
one_ancestors = builder.ancestor_builder.one_instance_ancestors(type_name_time)
|
54
|
-
one_ancestors.included_modules.each do |included_module|
|
55
|
-
yield "include #{included_module.source.name}"
|
56
|
-
end
|
57
62
|
twz_methods = builder.build_instance(type_name_time_with_zone).methods
|
58
63
|
builder.build_instance(type_name_time).methods.each do |sym, definition_method|
|
64
|
+
next if twz_methods.has_key?(sym) && !TYPE_MERGE_METHODS.include?(sym)
|
59
65
|
next if !definition_method.public?
|
66
|
+
|
60
67
|
definition_method.defs.reject! do |type_def|
|
61
68
|
type_def.implemented_in != type_name_time
|
62
69
|
end
|
63
70
|
next if definition_method.defs.empty?
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
rt.instance_variable_set(:@name, RBS::Types::Bases::Self.new(location: nil))
|
70
|
-
end
|
72
|
+
definition_method.method_types.each do |method_type|
|
73
|
+
rt = method_type.type.return_type
|
74
|
+
if rt.instance_of?(RBS::Types::ClassInstance) && rt.name.to_s == "::Time"
|
75
|
+
rt.instance_variable_set(:@name, RBS::Types::Bases::Self.new(location: nil))
|
71
76
|
end
|
72
77
|
end
|
73
78
|
|
74
79
|
if definition_method.alias_of.nil?
|
75
80
|
method_types = definition_method.method_types
|
76
81
|
|
82
|
+
# merge method types (e.g. :+, :-
|
83
|
+
# TimeWithZone -delegate-> Time(core_ext) -delegate-> Time(core)
|
77
84
|
if TYPE_MERGE_METHODS.include?(sym)
|
78
85
|
if twz_definition_method = twz_methods[sym]
|
79
86
|
twz_definition_method.defs.each do |type_def|
|
80
87
|
if type_def.implemented_in == type_name_time_with_zone
|
81
|
-
method_types
|
88
|
+
method_types.unshift(type_def.type)
|
82
89
|
end
|
83
90
|
end
|
84
91
|
end
|