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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/examples/rails/Rakefile +315 -0
  3. data/examples/rails/config/database.yml +8 -0
  4. data/examples/rails/config/storage.yml +3 -0
  5. data/examples/rails/gemfiles/Gemfile_6_0 +16 -0
  6. data/examples/rails/gemfiles/Gemfile_6_0.lock +172 -0
  7. data/examples/rails/gemfiles/Gemfile_6_1 +15 -0
  8. data/examples/rails/gemfiles/Gemfile_6_1.lock +173 -0
  9. data/examples/rails/gemfiles/Gemfile_7_0 +15 -0
  10. data/examples/rails/gemfiles/Gemfile_7_0.lock +172 -0
  11. data/examples/rails/tasks/active_job.rake +95 -0
  12. data/examples/rails/tasks/active_model.rake +46 -0
  13. data/examples/rails/tasks/active_record.rake +83 -0
  14. data/examples/rails/tasks/active_storage.rake +94 -0
  15. data/examples/rails/tasks/active_support.rake +92 -0
  16. data/lib/orthoses/active_model/has_secure_password.rb +12 -5
  17. data/lib/orthoses/active_model.rb +3 -0
  18. data/lib/orthoses/active_record/query_methods.rb +32 -0
  19. data/lib/orthoses/active_record.rb +7 -0
  20. data/lib/orthoses/active_support/class_attribute.rb +25 -14
  21. data/lib/orthoses/active_support/configurable.rb +36 -0
  22. data/lib/orthoses/active_support/delegation.rb +158 -0
  23. data/lib/orthoses/active_support/mattr_accessor.rb +18 -10
  24. data/lib/orthoses/active_support/time_with_zone.rb +34 -18
  25. data/lib/orthoses/active_support.rb +22 -0
  26. data/lib/orthoses/rails/version.rb +1 -1
  27. data/lib/orthoses/rails.rb +3 -11
  28. data/orthoses-rails.gemspec +1 -1
  29. metadata +25 -8
  30. data/lib/orthoses/active_support/concern.rb +0 -24
  31. data/lib/orthoses/active_support/known_sig/active_support/time_with_zone.rbs +0 -4
  32. 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 = ::ActiveModel::SecurePassword::ClassMethods.instance_method(:has_secure_password)
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.result.each do |method, argument|
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,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'active_model/has_secure_password'
@@ -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 = ::Class.instance_method(:class_attribute)
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.result.each do |method, argument|
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
- argument[:attrs].each do |name|
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 << "attr_writer #{name}: untyped" if argument[:instance_writer]
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
- store[receiver_name].concat(methods)
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(::Module.instance_method(:mattr_reader)) do
20
- mattr_writer.trace(::Module.instance_method(:mattr_writer)) do
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.result.each do |method, argument|
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.result.each do |method, argument|
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 = Orthoses::LoadRBS.new(@loader, paths: LOAD_PATHS).call
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
- loader = RBS::EnvironmentLoader.new
41
- env = RBS::Environment.from_loader(loader)
42
- LOAD_PATHS.each do |path|
43
- RBS::Parser.parse_signature(File.read(path)).each do |decl|
44
- env << decl
45
- end
46
- end
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
- 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(" | ")}"
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Orthoses
4
4
  module Rails
5
- VERSION = "0.2.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
@@ -4,14 +4,6 @@ require 'orthoses'
4
4
 
5
5
  require_relative "rails/version"
6
6
 
7
- require_relative 'active_model/has_secure_password'
8
-
9
- require_relative 'active_record/generated_attribute_methods'
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'
@@ -32,5 +32,5 @@ Gem::Specification.new do |spec|
32
32
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
33
  spec.require_paths = ["lib"]
34
34
 
35
- spec.add_dependency "orthoses"
35
+ spec.add_dependency "orthoses", ">= 0.10"
36
36
  end