orthoses-rails 0.9.0 → 1.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.
- checksums.yaml +4 -4
- data/README.md +20 -65
- data/lib/generators/orthoses/rails/install_generator.rb +18 -0
- data/lib/generators/orthoses/rails/templates/rails.rake +31 -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/secure_token.rb +28 -0
- data/lib/orthoses/active_record.rb +37 -0
- data/lib/orthoses/active_storage/attached/model.rb +47 -0
- data/lib/orthoses/active_storage.rb +3 -0
- data/lib/orthoses/active_support/aliasing.rb +34 -0
- data/lib/orthoses/active_support/delegation.rb +17 -6
- data/lib/orthoses/active_support/time_with_zone.rb +30 -21
- data/lib/orthoses/active_support.rb +1 -0
- data/lib/orthoses/rails/application.rb +47 -0
- data/lib/orthoses/rails/version.rb +1 -1
- data/lib/orthoses/rails.rb +4 -2
- metadata +13 -45
- 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: ec337b1da4ecda39f953797824239ede59c536c74da48cc1dbd01e46eed1d2b0
|
4
|
+
data.tar.gz: b146481d3fda9b3568a1593fd05608f09c811e1181356f2e36d2b010c30dd130
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bec23dc332048a010d10a2dc01754b969f76d2dd19bfa4b50393c1a764b3de496a35d018560aca04fe43630de497e900bb580774698bda3073ea33dcbf44bb5
|
7
|
+
data.tar.gz: e2dac22ee12a3bf049a73e5609d4a3ca1693c2dbc851c3bb06256e4566e9adad6c991fa9a60b0aaa7b22d6ea19e0c7cbc65c403cd136669d4c98b58deb7d90e7
|
data/README.md
CHANGED
@@ -3,38 +3,26 @@
|
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
+
If you have never performed rbs collection initialization, you need to do it.
|
9
|
+
|
10
|
+
```
|
11
|
+
$ bundle exec rbs collection init
|
12
|
+
$ bundle exec rbs collection install
|
13
|
+
```
|
14
|
+
|
15
|
+
Build your Rake task for RBS generation.
|
16
|
+
|
17
|
+
```
|
18
|
+
$ bin/rails generate orthoses:rails:install
|
19
|
+
```
|
20
|
+
|
21
|
+
Then run the rake task.
|
22
|
+
|
23
|
+
```
|
24
|
+
$ bin/rails orthoses:rails
|
25
|
+
```
|
38
26
|
|
39
27
|
## Installation
|
40
28
|
|
@@ -46,39 +34,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
46
34
|
|
47
35
|
$ gem install orthoses-rails
|
48
36
|
|
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
37
|
## Development
|
83
38
|
|
84
39
|
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
|
@@ -0,0 +1,31 @@
|
|
1
|
+
namespace :orthoses do
|
2
|
+
task :rails do
|
3
|
+
# Phase to load libraries
|
4
|
+
require Rails.root / "config/application"
|
5
|
+
require 'orthoses/rails'
|
6
|
+
|
7
|
+
# You can choose logger level
|
8
|
+
Orthoses.logger.level = :warn
|
9
|
+
|
10
|
+
# DSL for Orthoses.
|
11
|
+
Orthoses::Builder.new do
|
12
|
+
use Orthoses::CreateFileByName,
|
13
|
+
to: 'sig/orthoses', # Write to this dir. (require)
|
14
|
+
depth: 1, # Group files by module name path depth. (default: nil)
|
15
|
+
rmtree: true # Remove all `to` dir before generation. (default: false)
|
16
|
+
|
17
|
+
# Complement missing const name.
|
18
|
+
use Orthoses::MissingName
|
19
|
+
|
20
|
+
# You can load hand written RBS.
|
21
|
+
# use Orthoses::LoadRBS,
|
22
|
+
# paths: Dir.glob(Rails.root / "sig/hand-written/**/*.rbs")
|
23
|
+
|
24
|
+
# Middleware package for rails application.
|
25
|
+
use Orthoses::Rails::Application
|
26
|
+
|
27
|
+
# Application code loaded here is the target of the analysis.
|
28
|
+
run Orthoses::Rails::Application::Loader.new
|
29
|
+
end.call
|
30
|
+
end
|
31
|
+
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
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveRecord
|
5
|
+
# def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH)
|
6
|
+
class SecureToken
|
7
|
+
def initialize(loader)
|
8
|
+
@loader = loader
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
has_secure_token = CallTracer::Lazy.new
|
13
|
+
store = has_secure_token.trace('ActiveRecord::SecureToken::ClassMethods#has_secure_token') do
|
14
|
+
@loader.call
|
15
|
+
end
|
16
|
+
|
17
|
+
has_secure_token.captures.each do |capture|
|
18
|
+
base_name = Utils.module_name(capture.method.receiver) or next
|
19
|
+
attribute = capture.argument[:attribute]
|
20
|
+
|
21
|
+
store[base_name] << "def regenerate_#{attribute}: () -> bool"
|
22
|
+
end
|
23
|
+
|
24
|
+
store
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -7,4 +7,41 @@ 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
|
+
require_relative 'active_record/secure_token'
|
13
|
+
|
14
|
+
module Orthoses
|
15
|
+
module ActiveRecord
|
16
|
+
# Thanks https://github.com/pocke/rbs_rails/blob/8a128a8d29f0861aa2c25aa4110ff7c2ea674865/lib/rbs_rails/active_record.rb#L525-L551
|
17
|
+
def self.sql_type_to_rbs(t)
|
18
|
+
case t
|
19
|
+
when :integer, :big_integer
|
20
|
+
'::Integer'
|
21
|
+
when :float
|
22
|
+
'::Float'
|
23
|
+
when :decimal
|
24
|
+
'::BigDecimal'
|
25
|
+
when :string, :text, :citext, :uuid, :binary, :immutable_string
|
26
|
+
'::String'
|
27
|
+
when :datetime
|
28
|
+
'::ActiveSupport::TimeWithZone'
|
29
|
+
when :boolean
|
30
|
+
"bool"
|
31
|
+
when :date
|
32
|
+
'::Date'
|
33
|
+
when :time
|
34
|
+
'::Time'
|
35
|
+
when :cidr, :inet
|
36
|
+
"::IPAddr"
|
37
|
+
when :bit, :bit_varying, :enum, :hstore,
|
38
|
+
:interval, :jsonb, :json, :legacy_point, :money, :point, :vector, :xml
|
39
|
+
# FIXME
|
40
|
+
'untyped'
|
41
|
+
else
|
42
|
+
# Unknown column type, give up
|
43
|
+
'untyped'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveStorage
|
5
|
+
module Attached
|
6
|
+
# <= 6.0
|
7
|
+
# def has_one_attached(name, dependent: :purge_later)
|
8
|
+
# >= 6.1
|
9
|
+
# def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
|
10
|
+
class Model
|
11
|
+
def initialize(loader)
|
12
|
+
@loader = loader
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
store = @loader.call
|
17
|
+
|
18
|
+
::ActiveRecord::Base.descendants.each do |base|
|
19
|
+
next if base.abstract_class?
|
20
|
+
next if base.reflect_on_all_attachments.empty?
|
21
|
+
|
22
|
+
base_name = Utils.module_name(base) or next
|
23
|
+
base.reflect_on_all_attachments.each do |reflection|
|
24
|
+
type =
|
25
|
+
case reflection
|
26
|
+
when ::ActiveStorage::Reflection::HasOneAttachedReflection
|
27
|
+
"ActiveStorage::Attached::One"
|
28
|
+
when ::ActiveStorage::Reflection::HasManyAttachedReflection
|
29
|
+
"ActiveStorage::Attached::Many"
|
30
|
+
else
|
31
|
+
"untyped"
|
32
|
+
end
|
33
|
+
name = reflection.name
|
34
|
+
|
35
|
+
store[base_name].tap do |content|
|
36
|
+
content << "def #{name}: () -> #{type}"
|
37
|
+
content << "def #{name}=: (untyped attachable) -> untyped"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
store
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveSupport
|
5
|
+
# def alias_attribute(new_name, old_name)
|
6
|
+
class Aliasing
|
7
|
+
def initialize(loader)
|
8
|
+
@loader = loader
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
alias_attribute = CallTracer::Lazy.new
|
13
|
+
|
14
|
+
store =
|
15
|
+
alias_attribute.trace('Module#alias_attribute') do
|
16
|
+
@loader.call
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_attribute.captures.each do |capture|
|
20
|
+
base_mod_name = Utils.module_name(capture.method.receiver) or next
|
21
|
+
new_name = capture.argument[:new_name]
|
22
|
+
|
23
|
+
content = store[base_mod_name]
|
24
|
+
# TODO: Shold use alias? But, it has risc of undefined method
|
25
|
+
content << "def #{new_name}: () -> untyped"
|
26
|
+
content << "def #{new_name}?: () -> bool"
|
27
|
+
content << "def #{new_name}=: (untyped) -> untyped"
|
28
|
+
end
|
29
|
+
|
30
|
+
store
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|