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.
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