orthoses-rails 0.4.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -39
  3. data/examples/rails/Gemfile +16 -0
  4. data/examples/rails/Gemfile.lock +178 -0
  5. data/examples/rails/Rakefile +149 -193
  6. data/examples/rails/config/database.yml +8 -0
  7. data/examples/rails/config/storage.yml +3 -0
  8. data/examples/rails/known_sig/actionpack/7.0/action_controller/metal.rbs +4 -0
  9. data/{lib/orthoses/active_model/known_sig/7.0 → examples/rails/known_sig/activemodel/7.0/active_model}/serialization.rbs +0 -0
  10. data/{lib/orthoses/active_model/known_sig/7.0 → examples/rails/known_sig/activemodel/7.0/active_model}/validations.rbs +0 -0
  11. data/examples/rails/known_sig/activerecord/6.0/_active_record_relation.rbs +49 -0
  12. data/examples/rails/known_sig/activerecord/6.0/_active_record_relation_class_methods.rbs +45 -0
  13. data/{lib/orthoses/active_record/known_sig/6.0 → examples/rails/known_sig/activerecord/6.0/active_record}/result.rbs +0 -0
  14. data/examples/rails/known_sig/activerecord/6.1/_active_record_relation.rbs +49 -0
  15. data/examples/rails/known_sig/activerecord/6.1/_active_record_relation_class_methods.rbs +45 -0
  16. data/{lib/orthoses/active_record/known_sig/6.1 → examples/rails/known_sig/activerecord/6.1/active_record}/result.rbs +0 -0
  17. data/examples/rails/known_sig/activerecord/7.0/_active_record_relation.rbs +49 -0
  18. data/examples/rails/known_sig/activerecord/7.0/_active_record_relation_class_methods.rbs +45 -0
  19. data/{lib/orthoses/active_record/known_sig/7.0 → examples/rails/known_sig/activerecord/7.0/active_record}/encryption/context.rbs +0 -0
  20. data/{lib/orthoses/active_record/known_sig/7.0 → examples/rails/known_sig/activerecord/7.0/active_record}/result.rbs +0 -0
  21. data/{lib/orthoses/active_support/known_sig → examples/rails/known_sig/activesupport}/7.0/active_support/callbacks/callback_chain.rbs +0 -0
  22. data/examples/rails/known_sig/activesupport/7.0/active_support/duration.rbs +4 -0
  23. data/{lib/orthoses/active_support/known_sig → examples/rails/known_sig/activesupport}/7.0/active_support/hash_with_indifferent_access.rbs +0 -0
  24. data/{lib/orthoses/active_support/known_sig → examples/rails/known_sig/activesupport}/7.0/active_support/multibyte/chars.rbs +0 -0
  25. data/examples/rails/known_sig/activesupport/7.0/active_support/time_with_zone.rbs +5 -0
  26. data/examples/rails/known_sig/activesupport/7.0/active_support/time_zone.rbs +3 -0
  27. data/examples/rails/known_sig/activesupport/7.0/date.rbs +6 -0
  28. data/examples/rails/known_sig/activesupport/7.0/date_and_time/zones.rbs +4 -0
  29. data/{lib/orthoses/active_support/known_sig → examples/rails/known_sig/activesupport}/7.0/hash_with_indifferent_access.rbs +0 -0
  30. data/examples/rails/known_sig/activesupport/7.0/integer.rbs +9 -0
  31. data/examples/rails/known_sig/activesupport/7.0/numeric.rbs +15 -0
  32. data/examples/rails/known_sig/activesupport/7.0/string.rbs +4 -0
  33. data/{lib/orthoses/active_support/known_sig → examples/rails/known_sig/activesupport}/7.0/time.rbs +8 -0
  34. data/examples/rails/tasks/action_pack.rake +141 -0
  35. data/examples/rails/tasks/action_view.rake +77 -0
  36. data/examples/rails/tasks/active_job.rake +99 -0
  37. data/examples/rails/tasks/active_model.rake +46 -0
  38. data/examples/rails/tasks/active_record.rake +88 -0
  39. data/examples/rails/tasks/active_storage.rake +94 -0
  40. data/examples/rails/tasks/active_support.rake +99 -0
  41. data/examples/rails/tasks/railties.rake +37 -0
  42. data/lib/orthoses/active_model/has_secure_password.rb +2 -10
  43. data/lib/orthoses/active_model.rb +0 -1
  44. data/lib/orthoses/active_record/delegated_type.rb +44 -0
  45. data/lib/orthoses/active_record/enum.rb +77 -0
  46. data/lib/orthoses/active_record/generated_attribute_methods.rb +1 -0
  47. data/lib/orthoses/active_record/scope.rb +63 -0
  48. data/lib/orthoses/active_record.rb +3 -1
  49. data/lib/orthoses/active_support/class_attribute.rb +3 -10
  50. data/lib/orthoses/active_support/configurable.rb +3 -2
  51. data/lib/orthoses/active_support/delegation.rb +11 -19
  52. data/lib/orthoses/active_support/mattr_accessor.rb +4 -12
  53. data/lib/orthoses/active_support/time_with_zone.rb +21 -3
  54. data/lib/orthoses/active_support.rb +0 -17
  55. data/lib/orthoses/rails/version.rb +1 -1
  56. data/lib/orthoses/rails.rb +1 -1
  57. data/lib/orthoses/railties/mixin.rb +107 -0
  58. data/lib/orthoses/railties.rb +3 -0
  59. data/orthoses-rails.gemspec +1 -1
  60. metadata +48 -89
  61. data/examples/rails/known_sig/action_cable/connection/test_cookie_jar.rbs +0 -2
  62. data/examples/rails/known_sig/action_controller/metal.rbs +0 -4
  63. data/examples/rails/known_sig/action_dispatch/cookies/cookie_jar.rbs +0 -3
  64. data/examples/rails/known_sig/action_dispatch/response.rbs +0 -4
  65. data/examples/rails/patch/drb/drb_undumped.rbs +0 -2
  66. data/examples/rails/patch/drb.rbs +0 -2
  67. data/examples/rails/patch/erubi/engine.rbs +0 -4
  68. data/examples/rails/patch/erubi.rbs +0 -2
  69. data/examples/rails/patch/minitest/kernel.rbs +0 -44
  70. data/examples/rails/patch/minitest/minitest/abstract_reporter.rbs +0 -49
  71. data/examples/rails/patch/minitest/minitest/assertion.rbs +0 -16
  72. data/examples/rails/patch/minitest/minitest/assertions.rbs +0 -545
  73. data/examples/rails/patch/minitest/minitest/backtrace_filter.rbs +0 -16
  74. data/examples/rails/patch/minitest/minitest/bench_spec.rbs +0 -101
  75. data/examples/rails/patch/minitest/minitest/benchmark.rbs +0 -258
  76. data/examples/rails/patch/minitest/minitest/composite_reporter.rbs +0 -25
  77. data/examples/rails/patch/minitest/minitest/expectations.rbs +0 -21
  78. data/examples/rails/patch/minitest/minitest/guard.rbs +0 -64
  79. data/examples/rails/patch/minitest/minitest/mock.rbs +0 -60
  80. data/examples/rails/patch/minitest/minitest/parallel/executor.rbs +0 -42
  81. data/examples/rails/patch/minitest/minitest/parallel/test/class_methods.rbs +0 -6
  82. data/examples/rails/patch/minitest/minitest/parallel/test.rbs +0 -3
  83. data/examples/rails/patch/minitest/minitest/parallel.rbs +0 -2
  84. data/examples/rails/patch/minitest/minitest/pride_io.rbs +0 -54
  85. data/examples/rails/patch/minitest/minitest/pride_lol.rbs +0 -17
  86. data/examples/rails/patch/minitest/minitest/progress_reporter.rbs +0 -11
  87. data/examples/rails/patch/minitest/minitest/reportable.rbs +0 -51
  88. data/examples/rails/patch/minitest/minitest/reporter.rbs +0 -5
  89. data/examples/rails/patch/minitest/minitest/result.rbs +0 -28
  90. data/examples/rails/patch/minitest/minitest/runnable.rbs +0 -131
  91. data/examples/rails/patch/minitest/minitest/skip.rbs +0 -6
  92. data/examples/rails/patch/minitest/minitest/spec/dsl/instance_methods.rbs +0 -48
  93. data/examples/rails/patch/minitest/minitest/spec/dsl.rbs +0 -125
  94. data/examples/rails/patch/minitest/minitest/spec.rbs +0 -10
  95. data/examples/rails/patch/minitest/minitest/statistics_reporter.rbs +0 -76
  96. data/examples/rails/patch/minitest/minitest/summary_reporter.rbs +0 -26
  97. data/examples/rails/patch/minitest/minitest/test/lifecycle_hooks.rbs +0 -92
  98. data/examples/rails/patch/minitest/minitest/test.rbs +0 -76
  99. data/examples/rails/patch/minitest/minitest/unexpected_error.rbs +0 -10
  100. data/examples/rails/patch/minitest/minitest/unit/test_case.rbs +0 -3
  101. data/examples/rails/patch/minitest/minitest/unit.rbs +0 -5
  102. data/examples/rails/patch/minitest/minitest.rbs +0 -966
  103. data/examples/rails/patch/pg/simple_decoder.rbs +0 -4
  104. data/examples/rails/patch/pg.rbs +0 -2
  105. data/examples/rails/patch/qc/queue.rbs +0 -2
  106. data/examples/rails/patch/qc.rbs +0 -2
  107. data/examples/rails/patch/que/job.rbs +0 -2
  108. data/examples/rails/patch/que.rbs +0 -2
  109. data/examples/rails/patch/rack/cache/entity_store.rbs +0 -2
  110. data/examples/rails/patch/rack/cache/meta_store.rbs +0 -2
  111. data/examples/rails/patch/rack/cache.rbs +0 -2
  112. data/examples/rails/patch/rack/session/dalli.rbs +0 -2
  113. data/examples/rails/patch/rack/session.rbs +0 -2
  114. data/examples/rails/patch/rboc.rbs +0 -2
  115. data/examples/rails/patch/rdoc/generator/sdoc.rbs +0 -3
  116. data/examples/rails/patch/rdoc/generator.rbs +0 -2
  117. data/examples/rails/patch/rdoc/task.rbs +0 -2
  118. data/examples/rails/patch/ripper.rbs +0 -2
  119. data/examples/rails/patch/sidekiq/worker.rbs +0 -2
  120. data/examples/rails/patch/sidekiq.rbs +0 -2
  121. data/examples/rails/patch/sneakers/worker.rbs +0 -2
  122. data/examples/rails/patch/sneakers.rbs +0 -2
  123. data/examples/rails/patch/sucker_punch/job.rbs +0 -2
  124. data/examples/rails/patch/sucker_punch.rbs +0 -2
  125. data/examples/rails/patch/thor/actions/create_file.rbs +0 -2
  126. data/examples/rails/patch/thor/actions.rbs +0 -2
  127. data/examples/rails/patch/thor/error.rbs +0 -2
  128. data/examples/rails/patch/thor/group.rbs +0 -2
  129. data/examples/rails/patch/thor.rbs +0 -2
  130. data/lib/orthoses/active_model/known_sig.rb +0 -21
  131. data/lib/orthoses/active_record/known_sig.rb +0 -21
  132. data/lib/orthoses/active_support/known_sig.rb +0 -21
  133. data/lib/orthoses/rails/known_sig_helper.rb +0 -22
@@ -0,0 +1,94 @@
1
+ require 'rbs'
2
+
3
+ stdlib_dependencies = %w[time monitor singleton logger mutex_m json date benchmark digest forwardable did_you_mean openssl socket minitest]
4
+ gem_dependencies = %w[nokogiri]
5
+ rails_dependencies = %w[activesupport activemodel activejob activerecord]
6
+
7
+ VERSIONS.each do |version|
8
+ namespace version do
9
+ namespace :active_storage do
10
+ export = "export/activestorage/#{version}"
11
+
12
+ desc "export to #{export}"
13
+ task :export do
14
+ sh "rm -fr #{export}"
15
+ sh "mkdir -p #{export}"
16
+
17
+ # base
18
+ sh "cp -a out/#{version}/active_storage.rbs #{export}"
19
+ sh "cp -a out/#{version}/active_storage #{export}"
20
+ sh "rm #{export}/active_storage/engine.rbs"
21
+ decls = RBS::Parser.parse_signature(RBS::Buffer.new(
22
+ content: File.read("out/#{version}/active_record/base.rbs"),
23
+ name: "out/#{version}/active_record/base.rbs"
24
+ )).map do |decl|
25
+ decl.members.select! do |member|
26
+ case member
27
+ when RBS::AST::Members::Mixin
28
+ # Remove ActiveStorage
29
+ member.name.to_s.include?("ActiveStorage")
30
+ end
31
+ end
32
+ decl
33
+ end
34
+ File.open("#{export}/active_record_base.rbs", "w+") do |f|
35
+ RBS::Writer.new(out: f).write(decls)
36
+ end
37
+
38
+ # TODO: remove after support action_controller
39
+ sh "rm -fr #{export}/active_storage/blobs"
40
+ sh "rm -fr #{export}/active_storage/representations"
41
+ Dir.glob("#{export}/active_storage/*_controller.rbs").each do |controller|
42
+ sh "rm -f #{controller}"
43
+ end
44
+ sh "rm -f #{export}/active_storage/streaming.rbs"
45
+
46
+ generate_test_script(
47
+ gem: :activestorage,
48
+ version: version,
49
+ export: export,
50
+ stdlib_dependencies: stdlib_dependencies,
51
+ gem_dependencies: gem_dependencies,
52
+ rails_dependencies: rails_dependencies,
53
+ )
54
+
55
+ Pathname(export).join('_test').join('test.rb').write(<<~RUBY)
56
+ # !!! GENERATED CODE !!!
57
+ # Please see generators/rails-generator
58
+
59
+ class User < ActiveRecord::Base
60
+ has_one_attached :one_image
61
+ has_many_attached :many_image
62
+ end
63
+
64
+ user = User.new
65
+ one = ActiveStorage::Attached::One.new("one_image", user)
66
+ one.url
67
+ RUBY
68
+
69
+ Pathname(export).join('_test').join('test.rbs').write(<<~RBS)
70
+ # !!! GENERATED CODE !!!
71
+ # Please see generators/rails-generator
72
+
73
+ class User < ActiveRecord::Base
74
+ end
75
+ RBS
76
+ end
77
+
78
+ desc "validate version=#{version} gem=active_storage"
79
+ task :validate do
80
+ stdlib_opt = stdlib_dependencies.map{"-r #{_1}"}.join(" ")
81
+ gem_opt = gem_dependencies.map{"-I ../../.gem_rbs_collection/#{_1}"}.join(" ")
82
+ rails_opt = rails_dependencies.map{"-I export/#{_1}/#{version}"}.join(" ")
83
+ sh "rbs #{stdlib_opt} #{gem_opt} #{rails_opt} -I #{export} validate --silent"
84
+ end
85
+
86
+ desc "install to ../../../gems/activestorage/#{version}"
87
+ task :install do
88
+ install_to = File.expand_path("../../../gems/activestorage/#{version}", __dir__)
89
+ sh "rm -fr #{install_to}"
90
+ sh "cp -a #{export} #{install_to}"
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,99 @@
1
+ stdlib_dependencies = %w[benchmark date digest json logger monitor mutex_m pathname singleton time minitest]
2
+ gem_dependencies = %w[nokogiri]
3
+ rails_dependencies = %w[]
4
+
5
+ VERSIONS.each do |version|
6
+ namespace version do
7
+ namespace :active_support do
8
+ export = "export/activesupport/#{version}"
9
+
10
+ desc "export to #{export}"
11
+ task :export do
12
+ sh "rm -fr #{export}"
13
+ sh "mkdir -p #{export}"
14
+
15
+ # minimum
16
+ sh "cp -a out/#{version}/active_support.rbs #{export}"
17
+ sh "cp -a out/#{version}/active_support #{export}"
18
+ sh "rm #{export}/active_support/railtie.rbs"
19
+
20
+ # core_ext
21
+ %w[
22
+ array benchmark big_decimal class date date_and_time date_time digest
23
+ enumerable file hash integer kernel load_error marshal module name_error numeric
24
+ object pathname range regexp securerandom string symbol time uri
25
+ ].each do |lib|
26
+ out = "out/#{version}/#{lib}"
27
+ sh "cp -a #{out} #{export}" if File.exist?(out)
28
+ sh "cp -a #{out}.rbs #{export}" if File.exist?("#{out}.rbs")
29
+ end
30
+
31
+ # 5.2
32
+ sh "cp -a out/#{version}/logger_silence.rbs #{export}" if File.exist?("out/#{version}/logger_silence.rbs")
33
+
34
+ Pathname(export).join("EXTERNAL_TODO.rbs").write(<<~RBS)
35
+ # !!! GENERATED CODE !!!
36
+ # Please see generators/rails-generator
37
+
38
+ module DRb
39
+ module DRbUndumped
40
+ end
41
+ end
42
+ module Concurrent
43
+ class Map
44
+ end
45
+ end
46
+ RBS
47
+
48
+ case version
49
+ when "6.0", "6.1"
50
+ sh "rm -fr #{export}/uri"
51
+ when "7.0"
52
+ # deprecated
53
+ sh "rm -fr #{export}/uri{,.rbs}"
54
+ end
55
+
56
+ generate_manifest(
57
+ export: export,
58
+ stdlib_dependencies: stdlib_dependencies
59
+ )
60
+ generate_test_script(
61
+ gem: :activesupport,
62
+ version: version,
63
+ export: export,
64
+ stdlib_dependencies: stdlib_dependencies,
65
+ gem_dependencies: gem_dependencies,
66
+ rails_dependencies: rails_dependencies,
67
+ )
68
+
69
+ Pathname(export).join('_test').join('test.rb').write(<<~'RUBY')
70
+ # !!! GENERATED CODE !!!
71
+ # Please see generators/rails-generator
72
+
73
+ require 'active_support/all'
74
+
75
+ # Test ActiveSupport::NumericWithFormat
76
+ 42.to_s
77
+ 42.to_s(:phone)
78
+
79
+ 3.days.ago + 1.minute
80
+ RUBY
81
+ end
82
+
83
+ desc "validate version=#{version} gem=active_support"
84
+ task :validate do
85
+ stdlib_opt = stdlib_dependencies.map{"-r #{_1}"}.join(" ")
86
+ gem_opt = gem_dependencies.map{"-I ../../.gem_rbs_collection/#{_1}"}.join(" ")
87
+ rails_opt = rails_dependencies.map{"-I export/#{_1}/#{version}"}.join(" ")
88
+ sh "rbs #{stdlib_opt} #{gem_opt} #{rails_opt} -I #{export} validate --silent"
89
+ end
90
+
91
+ desc "install to ../../../gems/activesupport/#{version}"
92
+ task :install do
93
+ install_to = File.expand_path("../../../gems/activesupport/#{version}", __dir__)
94
+ sh "rm -fr #{install_to}"
95
+ sh "cp -a #{export} #{install_to}"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,37 @@
1
+ stdlib_dependencies = %w[benchmark date digest json logger monitor mutex_m pathname singleton time minitest securerandom ipaddr did_you_mean forwardable openssl socket]
2
+ gem_dependencies = %w[nokogiri i18n rack rails-dom-testing]
3
+ rails_dependencies = %w[actionpack actionview activejob activemodel activerecord activestorage activesupport]
4
+
5
+ VERSIONS.each do |version|
6
+ namespace version do
7
+ namespace :railties do
8
+ export = "export/railties/#{version}"
9
+
10
+ desc "export to #{export}"
11
+ task :export do
12
+ sh "rm -fr #{export}"
13
+ sh "mkdir -p #{export}"
14
+
15
+ if File.exist?("out/#{version}/active_record/destroy_association_async_job.rbs")
16
+ sh "mkdir -p #{export}/active_record"
17
+ sh "cp out/#{version}/active_record/destroy_association_async_job.rbs #{export}/active_record/destroy_association_async_job.rbs"
18
+ end
19
+ end
20
+
21
+ desc "validate version=#{version} gem=railties"
22
+ task :validate do
23
+ stdlib_opt = stdlib_dependencies.map{"-r #{_1}"}.join(" ")
24
+ gem_opt = gem_dependencies.map{"-I ../../.gem_rbs_collection/#{_1}"}.join(" ")
25
+ rails_opt = rails_dependencies.map{"-I export/#{_1}/#{version}"}.join(" ")
26
+ sh "rbs #{stdlib_opt} #{gem_opt} #{rails_opt} -I #{export} validate --silent"
27
+ end
28
+
29
+ desc "install to ../../../gems/railties/#{version}"
30
+ task :install do
31
+ install_to = File.expand_path("../../../gems/railties/#{version}", __dir__)
32
+ sh "rm -fr #{install_to}"
33
+ sh "cp -a #{export} #{install_to}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -13,17 +13,9 @@ module Orthoses
13
13
  end
14
14
 
15
15
  def call
16
- target_method = begin
17
- ::ActiveModel::SecurePassword::ClassMethods.instance_method(:has_secure_password)
18
- rescue NameError => err
19
- Orthoses.logger.warn("Run `require 'active_support/concern'; require 'active_model/secure_password'` and retry because #{err}")
20
- require 'active_support/concern'
21
- require 'active_model/secure_password'
22
- retry
23
- end
24
- call_tracer = Orthoses::CallTracer.new
16
+ call_tracer = CallTracer::Lazy.new
25
17
 
26
- store = call_tracer.trace(target_method) do
18
+ store = call_tracer.trace('ActiveModel::SecurePassword::ClassMethods#has_secure_password') do
27
19
  @loader.call
28
20
  end
29
21
 
@@ -1,4 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'active_model/has_secure_password'
4
- require_relative 'active_model/known_sig'
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ module ActiveRecord
5
+ # <= 6.0
6
+ # not implemented
7
+ # >= 6.1
8
+ # def delegated_type(role, types:, **options)
9
+ class DelegatedType
10
+ def initialize(loader)
11
+ @loader = loader
12
+ end
13
+
14
+ def call
15
+ delegated_type = CallTracer::Lazy.new
16
+ store = delegated_type.trace('ActiveRecord::DelegatedType#delegated_type') do
17
+ @loader.call
18
+ end
19
+
20
+ delegated_type.captures.each do |capture|
21
+ base_name = Utils.module_name(capture.method.receiver) or next
22
+ role = capture.argument[:role]
23
+ types = capture.argument[:types]
24
+ options = capture.argument[:options]
25
+ primary_key = options[:primary_key] || "id"
26
+
27
+ content = store[base_name]
28
+ content << "def #{role}_class: () -> (#{types.join(' | ')})"
29
+ content << "def #{role}_name: () -> String"
30
+ content << "def build_#{role}: () -> (#{types.join(' | ')})"
31
+ types.each do |type|
32
+ scope_name = type.tableize.gsub("/", "_")
33
+ singular = scope_name.singularize
34
+ content << "def #{singular}?: () -> bool"
35
+ content << "def #{singular}: () -> #{type}?"
36
+ content << "def #{singular}_#{primary_key}: () -> Integer?"
37
+ end
38
+ end
39
+
40
+ store
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ module ActiveRecord
5
+ # <= 6.1
6
+ # def enum(definitions)
7
+ # >= 7.0
8
+ # def enum(name = nil, values = nil, **options)
9
+ class Enum
10
+ def initialize(loader)
11
+ @loader = loader
12
+ end
13
+
14
+ def call
15
+ enum = CallTracer::Lazy.new
16
+ store = enum.trace('ActiveRecord::Enum#enum') do
17
+ @loader.call
18
+ end
19
+
20
+ enum.captures.each do |capture|
21
+ base_name = Utils.module_name(capture.method.receiver) or next
22
+
23
+ if capture.argument[:definitions]
24
+ # on rails 6
25
+ definitions = capture.argument[:definitions].slice!(:_prefix, :_suffix, :_scopes, :_default)
26
+ options = capture.argument[:definitions].transform_keys { |key| :"#{key[1..-1]}" }
27
+ definitions.each { |name, values| _enum(store, base_name, name, values, **options) }
28
+ else
29
+ # on rails 7
30
+ name = capture.argument[:name]
31
+ values = capture.argument[:values]
32
+ options = capture.argument[:options]
33
+ if name
34
+ # rails 7 style
35
+ values, options = options, {} unless values
36
+ _enum(store, base_name, name, values, **options)
37
+ else
38
+ # rails 6 style
39
+ definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default)
40
+ options.transform_keys! { |key| :"#{key[1..-1]}" }
41
+
42
+ definitions.each { |name, values| _enum(store, base_name, name, values, **options) }
43
+ end
44
+ end
45
+ end
46
+
47
+ store
48
+ end
49
+
50
+ private
51
+
52
+ def _enum(store, base_name, name, values, prefix: nil, suffix: nil, **_options)
53
+ name = name.to_s
54
+
55
+ prefix = if prefix
56
+ prefix == true ? "#{name}_" : "#{prefix}_"
57
+ end
58
+
59
+ suffix = if suffix
60
+ suffix == true ? "_#{name}" : "_#{suffix}"
61
+ end
62
+
63
+ return_type_param = Hash === values ? "[String, String]" : "[String, Integer]"
64
+ store[base_name] << "def self.#{name.pluralize}: () -> ActiveSupport::HashWithIndifferentAccess#{return_type_param}"
65
+
66
+ pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
67
+ pairs.each do |label, value|
68
+ value_method_name = "#{prefix}#{label}#{suffix}"
69
+ enum_methods_content = store["#{base_name}::ActiveRecord_Enum_EnumMethods"]
70
+ enum_methods_content.header = "module #{base_name}::ActiveRecord_Enum_EnumMethods"
71
+ enum_methods_content << "def #{value_method_name}?: () -> bool"
72
+ enum_methods_content << "def #{value_method_name}!: () -> bool"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -42,6 +42,7 @@ module Orthoses
42
42
  generated_attribute_methods = "#{name}::AttributeMethods::GeneratedAttributeMethods"
43
43
  store[name] << "include #{generated_attribute_methods}"
44
44
 
45
+ store["#{name}::AttributeMethods"].header = "module #{name}::AttributeMethods"
45
46
  store[generated_attribute_methods].header = "module #{generated_attribute_methods}"
46
47
  store[generated_attribute_methods].concat(lines)
47
48
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ module ActiveRecord
5
+ # def scope(name, body, &block)
6
+ class Scope
7
+ def initialize(loader)
8
+ @loader = loader
9
+ end
10
+
11
+ def call
12
+ scope = CallTracer::Lazy.new
13
+ store = scope.trace('ActiveRecord::Scoping::Named::ClassMethods#scope') do
14
+ @loader.call
15
+ end
16
+
17
+ scope.captures.each do |capture|
18
+ base_name = Utils.module_name(capture.method.receiver) or next
19
+
20
+ name = capture.argument[:name]
21
+ body = capture.argument[:body]
22
+
23
+ definition = "#{name}: #{parameters_to_type(body.parameters)} -> #{base_name}::ActiveRecord_Relation"
24
+ store[base_name] << "def self.#{definition}"
25
+ store["#{base_name}::GeneratedRelationMethods"].header = "module #{base_name}::GeneratedRelationMethods"
26
+ store["#{base_name}::GeneratedRelationMethods"] << "def #{definition}"
27
+ end
28
+
29
+ store
30
+ end
31
+
32
+ private
33
+
34
+ def parameters_to_type(parameters)
35
+ # @type var res: Array[String]
36
+ res = []
37
+ # @type var block: String?
38
+ block = nil
39
+ parameters.each do |(type, name)|
40
+ case type
41
+ when :req
42
+ res << "untyped #{name}"
43
+ when :opt
44
+ res << "?untyped #{name}"
45
+ when :keyreq
46
+ res << "#{name}: untyped"
47
+ when :key
48
+ res << "?#{name}: untyped"
49
+ when :rest
50
+ res << "*untyped #{name}"
51
+ when :keyrest
52
+ res << "**untyped #{name}"
53
+ when :block
54
+ block = " { (*untyped) -> untyped }"
55
+ else
56
+ raise "unexpected: #{type}"
57
+ end
58
+ end
59
+ "(#{res.join(", ")})#{block}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'active_record/belongs_to'
4
+ require_relative 'active_record/delegated_type'
5
+ require_relative 'active_record/enum'
4
6
  require_relative 'active_record/generated_attribute_methods'
5
7
  require_relative 'active_record/has_many'
6
8
  require_relative 'active_record/has_one'
7
- require_relative 'active_record/known_sig'
8
9
  require_relative 'active_record/query_methods'
10
+ require_relative 'active_record/scope'
@@ -15,20 +15,13 @@ module Orthoses
15
15
  end
16
16
 
17
17
  def call
18
- target_method = begin
19
- ::Class.instance_method(:class_attribute)
20
- rescue NameError => err
21
- Orthoses.logger.warn("Run `require 'active_support/core_ext/class/attribute'` and retry because #{err}")
22
- require 'active_support/core_ext/class/attribute'
23
- retry
24
- end
25
- call_tracer = Orthoses::CallTracer.new
18
+ lazy_tracer = Orthoses::CallTracer::Lazy.new
26
19
 
27
- store = call_tracer.trace(target_method) do
20
+ store = lazy_tracer.trace('Class#class_attribute') do
28
21
  @loader.call
29
22
  end
30
23
 
31
- call_tracer.captures.each do |capture|
24
+ lazy_tracer.captures.each do |capture|
32
25
  receiver_name = Orthoses::Utils.module_name(capture.method.receiver)
33
26
  next unless receiver_name
34
27
 
@@ -12,8 +12,9 @@ module Orthoses
12
12
  end
13
13
 
14
14
  def call
15
- config_accessor = CallTracer.new
16
- store = config_accessor.trace(::ActiveSupport::Configurable::ClassMethods.instance_method(:config_accessor)) do
15
+ config_accessor = CallTracer::Lazy.new
16
+
17
+ store = config_accessor.trace('ActiveSupport::Configurable::ClassMethods#config_accessor') do
17
18
  @loader.call
18
19
  end
19
20
  config_accessor.captures.each do |capture|
@@ -10,15 +10,8 @@ module Orthoses
10
10
  # def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
11
11
  # def delegate_missing_to(target, allow_nil: nil)
12
12
  def call
13
- target_method = begin
14
- ::Module.method(:delegate)
15
- rescue NameError => err
16
- Orthoses.logger.warn("Run `require 'active_support/core_ext/module/delegation'` and retry because #{err}")
17
- require 'active_support/core_ext/module/delegation'
18
- retry
19
- end
20
- delegate = CallTracer.new
21
- store = delegate.trace(target_method) do
13
+ delegate = CallTracer::Lazy.new
14
+ store = delegate.trace('Module#delegate') do
22
15
  @loader.call
23
16
  end
24
17
 
@@ -27,6 +20,7 @@ module Orthoses
27
20
  delegate.captures.each do |capture|
28
21
  receiver_name = Utils.module_name(capture.method.receiver) or next
29
22
  receiver_content = store[receiver_name]
23
+
30
24
  case capture.argument[:to]
31
25
  when Module
32
26
  to_module_name = Utils.module_name(capture.argument[:to]) or next
@@ -35,30 +29,28 @@ module Orthoses
35
29
  receiver_content << "# defined by `delegate` to: #{to_module_name}"
36
30
  receiver_content << sig
37
31
  else
38
- Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore #{arg.inspect}")
32
+ Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_module_name}.#{arg.inspect} in #{capture.argument.inspect}")
39
33
  end
40
34
  end
41
35
  else
42
36
  to_name = capture.argument[:to].to_s.to_sym
43
37
  tag, to_return_type = resource.find(receiver_name, to_name, :instance, false)
44
38
  raise "bug" if tag == :multi
45
- if to_return_type.nil?
46
- Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore #{capture.argument.inspect}")
47
- next
48
- end
49
- if to_return_type.instance_of?(RBS::Types::Bases::Any)
39
+
40
+ case to_return_type
41
+ when nil, RBS::Types::Bases::Any
50
42
  capture.argument[:methods].each do |method|
51
- receiver_content << "# defined by `delegate` to: :#{to_name}(#{to_return_type})"
43
+ receiver_content << "# defined by `delegate` to: #{to_return_type}##{to_name}"
52
44
  receiver_content << "def #{method}: (*untyped, **untyped) -> untyped"
53
45
  end
54
46
  else
55
47
  to_typename = to_return_type.name.relative!.to_s
56
48
  capture.argument[:methods].each do |method|
57
49
  if sig = resource.build_signature(to_typename, method, :instance, true)
58
- receiver_content << "# defined by `delegate` to: :#{to_name}(#{to_return_type})"
50
+ receiver_content << "# defined by `delegate` to #{to_return_type}##{to_name}"
59
51
  receiver_content << sig
60
52
  else
61
- Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore #{method.inspect}")
53
+ Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_typename}##{method.inspect} in #{capture.argument.inspect}")
62
54
  end
63
55
  end
64
56
  end
@@ -146,7 +138,7 @@ module Orthoses
146
138
  when RBS::AST::Members::Mixin, RBS::AST::Members::LocationOnly
147
139
  next
148
140
  else
149
- binding.irb
141
+ raise "bug: #{member.class} is not supported yet"
150
142
  end
151
143
  end
152
144
 
@@ -13,11 +13,11 @@ module Orthoses
13
13
  end
14
14
 
15
15
  def call
16
- mattr_reader = Orthoses::CallTracer.new
17
- mattr_writer = Orthoses::CallTracer.new
16
+ mattr_reader = CallTracer::Lazy.new
17
+ mattr_writer = CallTracer::Lazy.new
18
18
 
19
- store = mattr_reader.trace(target_method(:mattr_reader)) do
20
- mattr_writer.trace(target_method(:mattr_writer)) do
19
+ store = mattr_reader.trace('Module#mattr_reader') do
20
+ mattr_writer.trace('Module#mattr_writer') do
21
21
  @loader.call
22
22
  end
23
23
  end
@@ -56,14 +56,6 @@ module Orthoses
56
56
 
57
57
  store
58
58
  end
59
-
60
- def target_method(name)
61
- ::Module.instance_method(name)
62
- rescue NameError => err
63
- Orthoses.logger.warn("Run `require 'active_support/core_ext/module/attribute_accessors'` and retry because #{err}")
64
- require 'active_support/core_ext/module/attribute_accessors'
65
- retry
66
- end
67
59
  end
68
60
  end
69
61
  end
@@ -22,16 +22,22 @@ module Orthoses
22
22
 
23
23
  private
24
24
 
25
- NOT_DELEGATE_METHODS = %i[
25
+ NOT_DELEGATE_METHODS = Set.new(%i[
26
26
  utc
27
27
  getgm
28
28
  getutc
29
29
  gmtime
30
30
  localtime
31
- ]
31
+ ])
32
+
33
+ TYPE_MERGE_METHODS = Set.new(%i[
34
+ +
35
+ -
36
+ ])
32
37
 
33
38
  def each_line_from_core_time_definition(store)
34
39
  type_name_time = TypeName("::Time")
40
+ type_name_time_with_zone = TypeName("::ActiveSupport::TimeWithZone")
35
41
  env = Utils.rbs_environment(collection: true, cache: false)
36
42
  env << store["Time"].to_decl
37
43
  env << store["DateAndTime"].to_decl
@@ -48,6 +54,7 @@ module Orthoses
48
54
  one_ancestors.included_modules.each do |included_module|
49
55
  yield "include #{included_module.source.name}"
50
56
  end
57
+ twz_methods = builder.build_instance(type_name_time_with_zone).methods
51
58
  builder.build_instance(type_name_time).methods.each do |sym, definition_method|
52
59
  next if !definition_method.public?
53
60
  definition_method.defs.reject! do |type_def|
@@ -65,7 +72,18 @@ module Orthoses
65
72
  end
66
73
 
67
74
  if definition_method.alias_of.nil?
68
- yield "def #{sym}: #{definition_method.method_types.join(" | ")}"
75
+ method_types = definition_method.method_types
76
+
77
+ if TYPE_MERGE_METHODS.include?(sym)
78
+ if twz_definition_method = twz_methods[sym]
79
+ twz_definition_method.defs.each do |type_def|
80
+ if type_def.implemented_in == type_name_time_with_zone
81
+ method_types << type_def.type
82
+ end
83
+ end
84
+ end
85
+ end
86
+ yield "def #{sym}: #{method_types.join(" | ")}"
69
87
  else
70
88
  yield "alias #{sym} #{definition_method.alias_of.defs.first.member.name}"
71
89
  end