orthoses-rails 0.9.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -65
  3. data/lib/generators/orthoses/rails/install_generator.rb +18 -0
  4. data/lib/generators/orthoses/rails/templates/rails.rake +31 -0
  5. data/lib/orthoses/active_record/belongs_to.rb +15 -4
  6. data/lib/orthoses/active_record/enum.rb +5 -0
  7. data/lib/orthoses/active_record/generated_attribute_methods.rb +47 -55
  8. data/lib/orthoses/active_record/has_many.rb +15 -4
  9. data/lib/orthoses/active_record/has_one.rb +12 -2
  10. data/lib/orthoses/active_record/relation.rb +56 -0
  11. data/lib/orthoses/active_record/secure_token.rb +28 -0
  12. data/lib/orthoses/active_record.rb +37 -0
  13. data/lib/orthoses/active_storage/attached/model.rb +47 -0
  14. data/lib/orthoses/active_storage.rb +3 -0
  15. data/lib/orthoses/active_support/aliasing.rb +34 -0
  16. data/lib/orthoses/active_support/delegation.rb +17 -6
  17. data/lib/orthoses/active_support/time_with_zone.rb +30 -21
  18. data/lib/orthoses/active_support.rb +1 -0
  19. data/lib/orthoses/rails/application.rb +47 -0
  20. data/lib/orthoses/rails/version.rb +1 -1
  21. data/lib/orthoses/rails.rb +4 -2
  22. metadata +13 -45
  23. data/examples/rails/Gemfile +0 -16
  24. data/examples/rails/Gemfile.lock +0 -179
  25. data/examples/rails/Rakefile +0 -328
  26. data/examples/rails/config/database.yml +0 -8
  27. data/examples/rails/config/storage.yml +0 -3
  28. data/examples/rails/known_sig/actionpack/7.0/action_controller/metal.rbs +0 -4
  29. data/examples/rails/known_sig/activemodel/7.0/active_model/serialization.rbs +0 -4
  30. data/examples/rails/known_sig/activemodel/7.0/active_model/validations.rbs +0 -4
  31. data/examples/rails/known_sig/activerecord/6.0/_active_record_relation.rbs +0 -49
  32. data/examples/rails/known_sig/activerecord/6.0/_active_record_relation_class_methods.rbs +0 -45
  33. data/examples/rails/known_sig/activerecord/6.0/active_record/result.rbs +0 -5
  34. data/examples/rails/known_sig/activerecord/6.1/_active_record_relation.rbs +0 -49
  35. data/examples/rails/known_sig/activerecord/6.1/_active_record_relation_class_methods.rbs +0 -45
  36. data/examples/rails/known_sig/activerecord/6.1/active_record/result.rbs +0 -5
  37. data/examples/rails/known_sig/activerecord/7.0/_active_record_relation.rbs +0 -49
  38. data/examples/rails/known_sig/activerecord/7.0/_active_record_relation_class_methods.rbs +0 -45
  39. data/examples/rails/known_sig/activerecord/7.0/active_record/encryption/context.rbs +0 -9
  40. data/examples/rails/known_sig/activerecord/7.0/active_record/result.rbs +0 -5
  41. data/examples/rails/known_sig/activesupport/7.0/active_support/callbacks/callback_chain.rbs +0 -9
  42. data/examples/rails/known_sig/activesupport/7.0/active_support/duration.rbs +0 -4
  43. data/examples/rails/known_sig/activesupport/7.0/active_support/hash_with_indifferent_access.rbs +0 -6
  44. data/examples/rails/known_sig/activesupport/7.0/active_support/multibyte/chars.rbs +0 -7
  45. data/examples/rails/known_sig/activesupport/7.0/active_support/time_with_zone.rbs +0 -5
  46. data/examples/rails/known_sig/activesupport/7.0/active_support/time_zone.rbs +0 -3
  47. data/examples/rails/known_sig/activesupport/7.0/date.rbs +0 -6
  48. data/examples/rails/known_sig/activesupport/7.0/date_and_time/zones.rbs +0 -4
  49. data/examples/rails/known_sig/activesupport/7.0/hash_with_indifferent_access.rbs +0 -2
  50. data/examples/rails/known_sig/activesupport/7.0/integer.rbs +0 -9
  51. data/examples/rails/known_sig/activesupport/7.0/numeric.rbs +0 -15
  52. data/examples/rails/known_sig/activesupport/7.0/string.rbs +0 -4
  53. data/examples/rails/known_sig/activesupport/7.0/time.rbs +0 -46
  54. data/examples/rails/tasks/action_pack.rake +0 -141
  55. data/examples/rails/tasks/action_view.rake +0 -77
  56. data/examples/rails/tasks/active_job.rake +0 -99
  57. data/examples/rails/tasks/active_model.rake +0 -46
  58. data/examples/rails/tasks/active_record.rake +0 -88
  59. data/examples/rails/tasks/active_storage.rake +0 -94
  60. data/examples/rails/tasks/active_support.rake +0 -99
  61. data/examples/rails/tasks/railties.rake +0 -34
  62. data/orthoses-rails.gemspec +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a43ce53af9e7aec6ef02751c5649146d817e76770a9b15bb2fb5a24fa1b0447b
4
- data.tar.gz: 83c78756ff7794059a1001902f887509d8be7b42f116a2ce30b1cdb27d75ff6a
3
+ metadata.gz: ec337b1da4ecda39f953797824239ede59c536c74da48cc1dbd01e46eed1d2b0
4
+ data.tar.gz: b146481d3fda9b3568a1593fd05608f09c811e1181356f2e36d2b010c30dd130
5
5
  SHA512:
6
- metadata.gz: bce1abdf1faf93222005ba51aa4c74675fc98edef98a546faecd52280bf03ce11dc896379ab7269c3c7bda3be43eddae81cf01ab6fc701e8a2e96d4f841dd7b8
7
- data.tar.gz: be065396c52d757e110c2668e5eb90ada5f58275376bc93f0e9e4d25be4968735bccae5ace6d2ad7e08c8642b75b1ff5f5bd63b93c4019faba66101f1de34757
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
- ## Features
7
-
8
- ### Orthoses::ActiveModel
9
-
10
- - `HasSecurePassword`
11
- - Add signatures that generated form `has_secure_password`.
12
-
13
- ### Orthoses::ActiveRecord
14
-
15
- - `BelongsTo`
16
- - Add signatures that generated form `belongs_to`.
17
- - `DelegatedType`
18
- - Add signatures that generated from `delegated_type`
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
+ 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? ? 'untyped' : ref.klass.to_s
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
- store[base_name].tap do |content|
42
- store[base_name] << "include #{generated_association_methods}"
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
- name = Utils.module_name(klass) || next
16
- lines = klass.columns.flat_map do |col|
17
- req = sql_type_to_rbs(col.type)
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
- "def #{col.name}: () -> #{type}",
23
- "def #{col.name}=: (#{type}) -> #{type}",
24
- "def #{col.name}?: () -> bool",
25
- "def #{col.name}_changed?: () -> bool",
26
- "def #{col.name}_change: () -> [#{opt}, #{opt}]",
27
- "def #{col.name}_will_change!: () -> void",
28
- "def #{col.name}_was: () -> #{opt}",
29
- "def #{col.name}_previously_changed?: () -> bool",
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
- store["#{name}::AttributeMethods"].header = "module #{name}::AttributeMethods"
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[#{ref.klass}]) -> (#{collection_proxy} | Array[#{ref.klass}])",
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
- store[base_name] << "include #{generated_association_methods}"
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 = ref.klass.to_s
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
- store[base_name] << "include #{generated_association_methods}"
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,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'active_storage/attached/model'
@@ -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