orthoses-rails 0.2.0 → 0.5.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/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