orthoses-rails 0.2.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/rails/Rakefile +315 -0
- data/examples/rails/config/database.yml +8 -0
- data/examples/rails/config/storage.yml +3 -0
- data/examples/rails/gemfiles/Gemfile_6_0 +16 -0
- data/examples/rails/gemfiles/Gemfile_6_0.lock +172 -0
- data/examples/rails/gemfiles/Gemfile_6_1 +15 -0
- data/examples/rails/gemfiles/Gemfile_6_1.lock +173 -0
- data/examples/rails/gemfiles/Gemfile_7_0 +15 -0
- data/examples/rails/gemfiles/Gemfile_7_0.lock +172 -0
- data/examples/rails/tasks/active_job.rake +95 -0
- data/examples/rails/tasks/active_model.rake +46 -0
- data/examples/rails/tasks/active_record.rake +83 -0
- data/examples/rails/tasks/active_storage.rake +94 -0
- data/examples/rails/tasks/active_support.rake +92 -0
- data/lib/orthoses/active_model/has_secure_password.rb +12 -5
- data/lib/orthoses/active_model.rb +3 -0
- data/lib/orthoses/active_record/query_methods.rb +32 -0
- data/lib/orthoses/active_record.rb +7 -0
- data/lib/orthoses/active_support/class_attribute.rb +25 -14
- data/lib/orthoses/active_support/configurable.rb +36 -0
- data/lib/orthoses/active_support/delegation.rb +158 -0
- data/lib/orthoses/active_support/mattr_accessor.rb +18 -10
- data/lib/orthoses/active_support/time_with_zone.rb +34 -18
- data/lib/orthoses/active_support.rb +22 -0
- data/lib/orthoses/rails/version.rb +1 -1
- data/lib/orthoses/rails.rb +3 -11
- data/orthoses-rails.gemspec +1 -1
- metadata +25 -8
- data/lib/orthoses/active_support/concern.rb +0 -24
- data/lib/orthoses/active_support/known_sig/active_support/time_with_zone.rbs +0 -4
- data/lib/orthoses/active_support/known_sig/time.rbs +0 -64
@@ -0,0 +1,92 @@
|
|
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
|
+
Pathname(export).join("EXTERNAL_TODO.rbs").write(<<~RBS)
|
32
|
+
# !!! GENERATED CODE !!!
|
33
|
+
# Please see generators/rails-generator
|
34
|
+
|
35
|
+
module DRb
|
36
|
+
module DRbUndumped
|
37
|
+
end
|
38
|
+
end
|
39
|
+
module Concurrent
|
40
|
+
class Map
|
41
|
+
end
|
42
|
+
end
|
43
|
+
RBS
|
44
|
+
|
45
|
+
case version
|
46
|
+
when "6.0", "6.1"
|
47
|
+
sh "rm -fr #{export}/uri"
|
48
|
+
when "7.0"
|
49
|
+
# deprecated
|
50
|
+
sh "rm -fr #{export}/uri{,.rbs}"
|
51
|
+
end
|
52
|
+
|
53
|
+
generate_test_script(
|
54
|
+
gem: :activesupport,
|
55
|
+
version: version,
|
56
|
+
export: export,
|
57
|
+
stdlib_dependencies: stdlib_dependencies,
|
58
|
+
gem_dependencies: gem_dependencies,
|
59
|
+
rails_dependencies: rails_dependencies,
|
60
|
+
)
|
61
|
+
|
62
|
+
Pathname(export).join('_test').join('test.rb').write(<<~'RUBY')
|
63
|
+
# !!! GENERATED CODE !!!
|
64
|
+
# Please see generators/rails-generator
|
65
|
+
|
66
|
+
require 'active_support/all'
|
67
|
+
|
68
|
+
# Test ActiveSupport::NumericWithFormat
|
69
|
+
42.to_s
|
70
|
+
42.to_s(:phone)
|
71
|
+
|
72
|
+
3.days.ago + 1.minute
|
73
|
+
RUBY
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "validate version=#{version} gem=active_support"
|
77
|
+
task :validate do
|
78
|
+
stdlib_opt = stdlib_dependencies.map{"-r #{_1}"}.join(" ")
|
79
|
+
gem_opt = gem_dependencies.map{"-I ../../.gem_rbs_collection/#{_1}"}.join(" ")
|
80
|
+
rails_opt = rails_dependencies.map{"-I export/#{_1}/#{version}"}.join(" ")
|
81
|
+
sh "rbs #{stdlib_opt} #{gem_opt} #{rails_opt} -I #{export} validate --silent"
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "install to ../../../gems/activesupport/#{version}"
|
85
|
+
task :install do
|
86
|
+
install_to = File.expand_path("../../../gems/activesupport/#{version}", __dir__)
|
87
|
+
sh "rm -fr #{install_to}"
|
88
|
+
sh "cp -a #{export} #{install_to}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -13,19 +13,26 @@ module Orthoses
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def call
|
16
|
-
target_method =
|
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
|
17
24
|
call_tracer = Orthoses::CallTracer.new
|
18
25
|
|
19
26
|
store = call_tracer.trace(target_method) do
|
20
27
|
@loader.call
|
21
28
|
end
|
22
29
|
|
23
|
-
call_tracer.
|
24
|
-
next unless method.receiver.kind_of?(Class)
|
25
|
-
base_name = Utils.module_name(method.receiver)
|
30
|
+
call_tracer.captures.each do |capture|
|
31
|
+
next unless capture.method.receiver.kind_of?(Class)
|
32
|
+
base_name = Utils.module_name(capture.method.receiver)
|
26
33
|
next unless base_name
|
27
34
|
|
28
|
-
attribute = argument[:attribute] || :password
|
35
|
+
attribute = capture.argument[:attribute] || :password
|
29
36
|
full_name = if ::ActiveModel::VERSION::MAJOR < 6
|
30
37
|
"ActiveModel::SecurePassword::InstanceMethodsOnActivation"
|
31
38
|
else
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveRecord
|
5
|
+
class QueryMethods
|
6
|
+
def initialize(loader)
|
7
|
+
@loader = loader
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
@loader.call.tap do |store|
|
12
|
+
content = store["ActiveRecord::QueryMethods"]
|
13
|
+
|
14
|
+
::ActiveRecord::Relation::VALUE_METHODS.each do |name|
|
15
|
+
method_name, type =
|
16
|
+
case name
|
17
|
+
when *::ActiveRecord::Relation::MULTI_VALUE_METHODS
|
18
|
+
["#{name}_values", "::Array[untyped]"]
|
19
|
+
when *::ActiveRecord::Relation::SINGLE_VALUE_METHODS
|
20
|
+
["#{name}_value", name == :create_with ? "::Hash[untyped, untyped]?" : "untyped"]
|
21
|
+
when *::ActiveRecord::Relation::CLAUSE_METHODS
|
22
|
+
["#{name}_clause", name == :from ? "::ActiveRecord::Relation::FromClause" : "::ActiveRecord::Relation::WhereClause"]
|
23
|
+
end
|
24
|
+
|
25
|
+
content << "def #{method_name}: () -> #{type}"
|
26
|
+
content << "def #{method_name}=: (#{type} value) -> #{type}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'active_record/belongs_to'
|
4
|
+
require_relative 'active_record/generated_attribute_methods'
|
5
|
+
require_relative 'active_record/has_many'
|
6
|
+
require_relative 'active_record/has_one'
|
7
|
+
require_relative 'active_record/query_methods'
|
@@ -15,26 +15,35 @@ module Orthoses
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def call
|
18
|
-
target_method =
|
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
|
19
25
|
call_tracer = Orthoses::CallTracer.new
|
20
26
|
|
21
27
|
store = call_tracer.trace(target_method) do
|
22
28
|
@loader.call
|
23
29
|
end
|
24
30
|
|
25
|
-
call_tracer.
|
26
|
-
receiver_name = Orthoses::Utils.module_name(method.receiver)
|
31
|
+
call_tracer.captures.each do |capture|
|
32
|
+
receiver_name = Orthoses::Utils.module_name(capture.method.receiver)
|
27
33
|
next unless receiver_name
|
28
34
|
|
29
35
|
methods = []
|
30
36
|
if ::ActiveSupport::VERSION::MAJOR < 6
|
31
|
-
options = argument[:attrs].extract_options!
|
32
|
-
argument[:instance_reader] = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
|
33
|
-
argument[:instance_writer] = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
|
34
|
-
argument[:instance_predicate] = options.fetch(:instance_predicate, true)
|
35
|
-
argument[:default_value] = options.fetch(:default, nil)
|
37
|
+
options = capture.argument[:attrs].extract_options!
|
38
|
+
capture.argument[:instance_reader] = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
|
39
|
+
capture.argument[:instance_writer] = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
|
40
|
+
capture.argument[:instance_predicate] = options.fetch(:instance_predicate, true)
|
41
|
+
capture.argument[:default_value] = options.fetch(:default, nil)
|
36
42
|
end
|
37
|
-
|
43
|
+
|
44
|
+
content = store[receiver_name]
|
45
|
+
|
46
|
+
capture.argument[:attrs].each do |name|
|
38
47
|
next unless @if.nil? || @if.call(method, name)
|
39
48
|
|
40
49
|
# skip internal attribute
|
@@ -43,15 +52,17 @@ module Orthoses
|
|
43
52
|
next if name == :attributes_to_define_after_schema_loads
|
44
53
|
|
45
54
|
methods << "def self.#{name}: () -> untyped"
|
46
|
-
methods << "def self.#{name}?: () -> bool" if argument[:instance_predicate]
|
55
|
+
methods << "def self.#{name}?: () -> bool" if capture.argument[:instance_predicate]
|
47
56
|
methods << "def self.#{name}=: (untyped value) -> untyped"
|
48
|
-
methods << "def #{name}: () -> untyped" if argument[:instance_reader]
|
49
|
-
methods << "def #{name}?: () -> bool" if argument[:instance_predicate] && argument[:instance_reader]
|
50
|
-
methods << "
|
57
|
+
methods << "def #{name}: () -> untyped" if capture.argument[:instance_reader]
|
58
|
+
methods << "def #{name}?: () -> bool" if capture.argument[:instance_predicate] && capture.argument[:instance_reader]
|
59
|
+
methods << "def #{name}=: (untyped value) -> untyped" if capture.argument[:instance_writer]
|
60
|
+
# In RBS, `foo=` and attr_writer :foo cannot live together.
|
61
|
+
content.body.delete_if { |line| line.start_with?("attr_writer #{name}:") }
|
51
62
|
end
|
52
63
|
next if methods.empty?
|
53
64
|
|
54
|
-
|
65
|
+
content.concat(methods)
|
55
66
|
end
|
56
67
|
|
57
68
|
store
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveSupport
|
5
|
+
# <= 6.1
|
6
|
+
# def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true)
|
7
|
+
# >= 7
|
8
|
+
# def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
|
9
|
+
class Configurable
|
10
|
+
def initialize(loader)
|
11
|
+
@loader = loader
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
config_accessor = CallTracer.new
|
16
|
+
store = config_accessor.trace(::ActiveSupport::Configurable::ClassMethods.instance_method(:config_accessor)) do
|
17
|
+
@loader.call
|
18
|
+
end
|
19
|
+
config_accessor.captures.each do |capture|
|
20
|
+
mod_name = Utils.module_name(capture.method.receiver) or next
|
21
|
+
content = store[mod_name]
|
22
|
+
capture.argument[:names].each do |name|
|
23
|
+
content << "def self.#{name}: () -> untyped"
|
24
|
+
content << "def self.#{name}=: (untyped value) -> untyped"
|
25
|
+
if capture.argument[:instance_accessor]
|
26
|
+
content << "def #{name}: () -> untyped" if capture.argument[:instance_reader]
|
27
|
+
content << "def #{name}=: (untyped value) -> untyped" if capture.argument[:instance_writer]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
store
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module ActiveSupport
|
5
|
+
class Delegation
|
6
|
+
def initialize(loader)
|
7
|
+
@loader = loader
|
8
|
+
end
|
9
|
+
|
10
|
+
# def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
|
11
|
+
# def delegate_missing_to(target, allow_nil: nil)
|
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
|
22
|
+
@loader.call
|
23
|
+
end
|
24
|
+
|
25
|
+
resource = Resource.new(store)
|
26
|
+
|
27
|
+
delegate.captures.each do |capture|
|
28
|
+
receiver_name = Utils.module_name(capture.method.receiver) or next
|
29
|
+
receiver_content = store[receiver_name]
|
30
|
+
case capture.argument[:to]
|
31
|
+
when Module
|
32
|
+
to_module_name = Utils.module_name(capture.argument[:to]) or next
|
33
|
+
capture.argument[:methods].each do |arg|
|
34
|
+
if sig = resource.build_signature(to_module_name, arg, :singleton, false)
|
35
|
+
receiver_content << "# defined by `delegate` to: #{to_module_name}"
|
36
|
+
receiver_content << sig
|
37
|
+
else
|
38
|
+
Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_module_name}.#{arg.inspect} in #{capture.argument.inspect}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else
|
42
|
+
to_name = capture.argument[:to].to_s.to_sym
|
43
|
+
tag, to_return_type = resource.find(receiver_name, to_name, :instance, false)
|
44
|
+
raise "bug" if tag == :multi
|
45
|
+
if to_return_type.nil?
|
46
|
+
Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{receiver_name}##{to_name.inspect} in #{capture.argument.inspect}")
|
47
|
+
next
|
48
|
+
end
|
49
|
+
if to_return_type.instance_of?(RBS::Types::Bases::Any)
|
50
|
+
capture.argument[:methods].each do |method|
|
51
|
+
receiver_content << "# defined by `delegate` to: #{to_return_type}##{to_name}"
|
52
|
+
receiver_content << "def #{method}: (*untyped, **untyped) -> untyped"
|
53
|
+
end
|
54
|
+
else
|
55
|
+
to_typename = to_return_type.name.relative!.to_s
|
56
|
+
capture.argument[:methods].each do |method|
|
57
|
+
if sig = resource.build_signature(to_typename, method, :instance, true)
|
58
|
+
receiver_content << "# defined by `delegate` to #{to_return_type}##{to_name}"
|
59
|
+
receiver_content << sig
|
60
|
+
else
|
61
|
+
Orthoses.logger.warn("[ActiveSupport::Delegation] Ignore since missing type for #{to_typename}##{method.inspect} in #{capture.argument.inspect}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
store
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
class Resource
|
74
|
+
def initialize(store)
|
75
|
+
@store = store
|
76
|
+
env = Orthoses::Utils.rbs_environment(collection: true)
|
77
|
+
@definition_builder = RBS::DefinitionBuilder.new(env: env)
|
78
|
+
end
|
79
|
+
|
80
|
+
def find(mod_name, name, kind, argument)
|
81
|
+
typename = TypeName(mod_name).absolute!
|
82
|
+
|
83
|
+
if definition_method = build_definition(typename, kind)&.methods&.[](name)
|
84
|
+
return [:multi, definition_method.defs.map(&:type)]
|
85
|
+
end
|
86
|
+
resolve_type_by_name(@store[mod_name].to_decl.members, name, kind, argument)
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_definition(typename, kind)
|
90
|
+
case kind
|
91
|
+
when :instance
|
92
|
+
@definition_builder.build_instance(typename)
|
93
|
+
when :singleton
|
94
|
+
@definition_builder.build_singleton(typename)
|
95
|
+
else
|
96
|
+
raise "big"
|
97
|
+
end
|
98
|
+
rescue RuntimeError => e
|
99
|
+
if e.message.match?(/\AUnknown name for/)
|
100
|
+
nil
|
101
|
+
else
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_signature(mod_name, name, kind, argument)
|
107
|
+
tag, type = find(mod_name, name, kind, argument)
|
108
|
+
case tag
|
109
|
+
when :single
|
110
|
+
"def #{name}: () -> #{type}"
|
111
|
+
when :multi
|
112
|
+
"def #{name}: #{type.join(' | ')}"
|
113
|
+
else
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def resolve_type_by_name(members, name, kind, argument)
|
121
|
+
members.each do |member|
|
122
|
+
case member
|
123
|
+
when RBS::AST::Members::MethodDefinition
|
124
|
+
next unless member.name == name && member.kind == kind
|
125
|
+
if argument
|
126
|
+
return [:multi, member.types]
|
127
|
+
else
|
128
|
+
type = member.types.find do |method_type|
|
129
|
+
method_type.type.required_positionals.empty? && method_type.type.required_keywords.empty?
|
130
|
+
end
|
131
|
+
next unless type
|
132
|
+
return [:single, type.type.return_type]
|
133
|
+
end
|
134
|
+
when RBS::AST::Members::Var
|
135
|
+
next unless member.name == name
|
136
|
+
return [:single, member.type]
|
137
|
+
when RBS::AST::Declarations::Constant
|
138
|
+
next unless member.name.to_s.to_sym == name
|
139
|
+
return [:single, member.type]
|
140
|
+
when RBS::AST::Members::Attribute
|
141
|
+
next unless member.name == name && member.kind == kind
|
142
|
+
return [:single, member.type]
|
143
|
+
when RBS::AST::Members::Alias
|
144
|
+
next unless member.new_name == name && member.kind == kind
|
145
|
+
return resolve_type_by_name(members, member.old_name, kind, argument)
|
146
|
+
when RBS::AST::Members::Mixin, RBS::AST::Members::LocationOnly
|
147
|
+
next
|
148
|
+
else
|
149
|
+
raise "bug: #{member.class} is not supported yet"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -16,20 +16,20 @@ module Orthoses
|
|
16
16
|
mattr_reader = Orthoses::CallTracer.new
|
17
17
|
mattr_writer = Orthoses::CallTracer.new
|
18
18
|
|
19
|
-
store = mattr_reader.trace(
|
20
|
-
mattr_writer.trace(
|
19
|
+
store = mattr_reader.trace(target_method(:mattr_reader)) do
|
20
|
+
mattr_writer.trace(target_method(:mattr_writer)) do
|
21
21
|
@loader.call
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
mattr_reader.
|
26
|
-
base = Orthoses::Utils.module_name(method.receiver) || next
|
25
|
+
mattr_reader.captures.each do |capture|
|
26
|
+
base = Orthoses::Utils.module_name(capture.method.receiver) || next
|
27
27
|
methods = []
|
28
|
-
argument[:syms].each do |sym|
|
28
|
+
capture.argument[:syms].each do |sym|
|
29
29
|
next unless @if.nil? || @if.call(method, sym)
|
30
30
|
|
31
31
|
methods << "def self.#{sym}: () -> untyped"
|
32
|
-
if argument[:instance_reader] && argument[:instance_accessor]
|
32
|
+
if capture.argument[:instance_reader] && capture.argument[:instance_accessor]
|
33
33
|
methods << "def #{sym}: () -> untyped"
|
34
34
|
end
|
35
35
|
end
|
@@ -38,14 +38,14 @@ module Orthoses
|
|
38
38
|
store[base].concat(methods)
|
39
39
|
end
|
40
40
|
|
41
|
-
mattr_writer.
|
42
|
-
base = Orthoses::Utils.module_name(method.receiver) || next
|
41
|
+
mattr_writer.captures.each do |capture|
|
42
|
+
base = Orthoses::Utils.module_name(capture.method.receiver) || next
|
43
43
|
methods = []
|
44
|
-
argument[:syms].each do |sym|
|
44
|
+
capture.argument[:syms].each do |sym|
|
45
45
|
next unless @if.nil? || @if.call(method, sym)
|
46
46
|
|
47
47
|
methods << "def self.#{sym}=: (untyped val) -> untyped"
|
48
|
-
if argument[:instance_writer] && argument[:instance_accessor]
|
48
|
+
if capture.argument[:instance_writer] && capture.argument[:instance_accessor]
|
49
49
|
methods << "def #{sym}=: (untyped val) -> untyped"
|
50
50
|
end
|
51
51
|
end
|
@@ -56,6 +56,14 @@ 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
|
59
67
|
end
|
60
68
|
end
|
61
69
|
end
|
@@ -7,18 +7,13 @@ module Orthoses
|
|
7
7
|
@loader = loader
|
8
8
|
end
|
9
9
|
|
10
|
-
LOAD_PATHS = [
|
11
|
-
File.expand_path("known_sig/time.rbs", __dir__),
|
12
|
-
File.expand_path("known_sig/active_support/time_with_zone.rbs", __dir__),
|
13
|
-
]
|
14
|
-
|
15
10
|
# Time <= (known Time)
|
16
11
|
# TimeWithZone <= (known TimeWithZone, known Time, core Time)
|
17
12
|
def call
|
18
|
-
store =
|
13
|
+
store = @loader.call
|
19
14
|
|
20
15
|
time_with_zone_store = store["ActiveSupport::TimeWithZone"]
|
21
|
-
each_line_from_core_time_definition do |line|
|
16
|
+
each_line_from_core_time_definition(store) do |line|
|
22
17
|
time_with_zone_store << line
|
23
18
|
end
|
24
19
|
|
@@ -27,29 +22,39 @@ module Orthoses
|
|
27
22
|
|
28
23
|
private
|
29
24
|
|
30
|
-
NOT_DELEGATE_METHODS = %i[
|
25
|
+
NOT_DELEGATE_METHODS = Set.new(%i[
|
31
26
|
utc
|
32
27
|
getgm
|
33
28
|
getutc
|
34
29
|
gmtime
|
35
30
|
localtime
|
36
|
-
]
|
31
|
+
])
|
32
|
+
|
33
|
+
TYPE_MERGE_METHODS = Set.new(%i[
|
34
|
+
+
|
35
|
+
-
|
36
|
+
])
|
37
37
|
|
38
|
-
def each_line_from_core_time_definition
|
38
|
+
def each_line_from_core_time_definition(store)
|
39
39
|
type_name_time = TypeName("::Time")
|
40
|
-
|
41
|
-
env =
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
type_name_time_with_zone = TypeName("::ActiveSupport::TimeWithZone")
|
41
|
+
env = Utils.rbs_environment(collection: true, cache: false)
|
42
|
+
env << store["Time"].to_decl
|
43
|
+
env << store["DateAndTime"].to_decl
|
44
|
+
env << store["DateAndTime::Zones"].to_decl
|
45
|
+
env << store["DateAndTime::Calculations"].to_decl
|
46
|
+
env << store["DateAndTime::Compatibility"].to_decl
|
47
|
+
env << store["ActiveSupport"].to_decl
|
48
|
+
env << store["ActiveSupport::TimeZone"].to_decl
|
49
|
+
env << store["ActiveSupport::Duration"].to_decl
|
50
|
+
env << store["ActiveSupport::TimeWithZone"].to_decl
|
47
51
|
|
48
52
|
builder = RBS::DefinitionBuilder.new(env: env.resolve_type_names)
|
49
53
|
one_ancestors = builder.ancestor_builder.one_instance_ancestors(type_name_time)
|
50
54
|
one_ancestors.included_modules.each do |included_module|
|
51
55
|
yield "include #{included_module.source.name}"
|
52
56
|
end
|
57
|
+
twz_methods = builder.build_instance(type_name_time_with_zone).methods
|
53
58
|
builder.build_instance(type_name_time).methods.each do |sym, definition_method|
|
54
59
|
next if !definition_method.public?
|
55
60
|
definition_method.defs.reject! do |type_def|
|
@@ -67,7 +72,18 @@ module Orthoses
|
|
67
72
|
end
|
68
73
|
|
69
74
|
if definition_method.alias_of.nil?
|
70
|
-
|
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(" | ")}"
|
71
87
|
else
|
72
88
|
yield "alias #{sym} #{definition_method.alias_of.defs.first.member.name}"
|
73
89
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'active_support/class_attribute'
|
4
|
+
require_relative 'active_support/configurable'
|
5
|
+
require_relative 'active_support/delegation'
|
6
|
+
require_relative 'active_support/mattr_accessor'
|
7
|
+
require_relative 'active_support/time_with_zone'
|
8
|
+
|
9
|
+
module Orthoses
|
10
|
+
module ActiveSupport
|
11
|
+
# Interface for adding middleware in bulk.
|
12
|
+
# Orthoses::ActiveSupport.each do |middleware, **args|
|
13
|
+
# use middleware, **args
|
14
|
+
# end
|
15
|
+
def self.each
|
16
|
+
yield ClassAttribute
|
17
|
+
yield Delegation
|
18
|
+
yield MattrAccessor
|
19
|
+
yield TimeWithZone
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/orthoses/rails.rb
CHANGED
@@ -4,14 +4,6 @@ require 'orthoses'
|
|
4
4
|
|
5
5
|
require_relative "rails/version"
|
6
6
|
|
7
|
-
require_relative 'active_model
|
8
|
-
|
9
|
-
require_relative '
|
10
|
-
require_relative 'active_record/has_many'
|
11
|
-
require_relative 'active_record/has_one'
|
12
|
-
require_relative 'active_record/belongs_to'
|
13
|
-
|
14
|
-
require_relative 'active_support/class_attribute'
|
15
|
-
require_relative 'active_support/concern'
|
16
|
-
require_relative 'active_support/mattr_accessor'
|
17
|
-
require_relative 'active_support/time_with_zone'
|
7
|
+
require_relative 'active_model'
|
8
|
+
require_relative 'active_record'
|
9
|
+
require_relative 'active_support'
|
data/orthoses-rails.gemspec
CHANGED