rbs_rails 0.2.0 → 0.3.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.
@@ -0,0 +1,4 @@
1
+ module I18n
2
+ class Config
3
+ end
4
+ end
@@ -1,2 +1,13 @@
1
- class Minitest::Test
1
+ module Minitest
2
+ class Test
3
+ end
4
+
5
+ class SummaryReporter
6
+ end
7
+
8
+ class StatisticsReporter
9
+ end
10
+
11
+ module Assertions
12
+ end
2
13
  end
@@ -0,0 +1,4 @@
1
+ module Racc
2
+ class Parser
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Rack
2
+ module Test
3
+ class UploadedFile
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,46 @@
1
+ module Rack
2
+ class Server
3
+ end
4
+
5
+ class Response
6
+ module Helpers
7
+ end
8
+ end
9
+
10
+ class Request
11
+ module Helpers
12
+ end
13
+
14
+ module Env
15
+ end
16
+ end
17
+
18
+ module Session
19
+ module Abstract
20
+ class SessionHash
21
+ end
22
+
23
+ class PersistedSecure
24
+ class SecureSessionHash
25
+ end
26
+ end
27
+
28
+ class Persisted
29
+ end
30
+ end
31
+
32
+ class SessionId
33
+ end
34
+
35
+ class Dalli
36
+ end
37
+ end
38
+
39
+ module Cache
40
+ class MetaStore
41
+ end
42
+
43
+ class EntityStore
44
+ end
45
+ end
46
+ end
@@ -1,11 +1,14 @@
1
1
  module Rails
2
- def self.root: () -> Pathname
3
- def self.application: () -> Rails::Application
2
+ overload def self.env: () -> ActiveSupport::StringInquirer
3
+
4
+ module Dom
5
+ module Testing
6
+ module Assertions
7
+ end
8
+ end
9
+ end
4
10
  end
5
11
 
6
12
  class Rails::Application
7
13
  def routes: () -> untyped
8
14
  end
9
-
10
- class Rails::Railtie
11
- end
@@ -0,0 +1,9 @@
1
+ module RDoc
2
+ module Generator
3
+ class SDoc
4
+ end
5
+ end
6
+
7
+ class Task
8
+ end
9
+ end
@@ -1,14 +1,24 @@
1
- class Logger
1
+ module DRb
2
2
  end
3
3
 
4
- class Logger::Formatter
4
+ module DRb::DRbUndumped
5
5
  end
6
6
 
7
- module Mutex_m
7
+ module TSort
8
8
  end
9
9
 
10
- module DRb
10
+ class SimpleDelegator
11
11
  end
12
12
 
13
- module DRb::DRbUndumped
13
+ module Gem
14
+ class Version
15
+ end
16
+ end
17
+
18
+ module OpenSSL
19
+ class Cipher
20
+ end
21
+ end
22
+
23
+ module FileUtils
14
24
  end
@@ -0,0 +1,12 @@
1
+ class Thor
2
+ class Group
3
+ end
4
+
5
+ module Actions
6
+ class CreateFile
7
+ end
8
+ end
9
+
10
+ class Error
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module TZInfo
2
+ class Timezone
3
+ end
4
+ end
@@ -1,15 +1,15 @@
1
+ #!ruby
2
+
1
3
  require 'rbs'
2
- rbs = ARGF.read
3
- decls = RBS::Parser.parse_signature(rbs)
4
4
 
5
5
  def args(n)
6
6
  (:T..).take(n)
7
7
  end
8
8
 
9
9
  def env
10
- @env ||= RBS::Environment.new.tap do |env|
10
+ @env ||= begin
11
11
  loader = RBS::EnvironmentLoader.new()
12
- loader.load(env: env)
12
+ RBS::Environment.from_loader(loader).resolve_type_names
13
13
  end
14
14
  end
15
15
 
@@ -17,7 +17,7 @@ def apply_to_superclass(decl)
17
17
  return unless decl.super_class
18
18
 
19
19
  name = decl.super_class.name
20
- type = env.find_class(name) || env.find_class(name.absolute!)
20
+ type = env.class_decls[name] || env.class_decls[name.absolute!]
21
21
  return unless type
22
22
  return if type.type_params.empty?
23
23
 
@@ -32,12 +32,21 @@ def apply_to_superclass(decl)
32
32
  decl.instance_variable_set(:@type_params, type_params)
33
33
  end
34
34
 
35
+ def apply_to_itself(decl)
36
+ name = decl.name
37
+ type = env.class_decls[name] || env.class_decls[name.absolute!]
38
+ return unless type
39
+ return if type.type_params.empty?
40
+
41
+ decl.instance_variable_set(:@type_params, type.type_params.dup)
42
+ end
43
+
35
44
  def apply_to_includes(decl)
36
45
  decl.members.each do |member|
37
46
  next unless member.is_a?(RBS::AST::Members::Mixin)
38
47
 
39
48
  name = member.name
40
- type = env.find_class(name) || env.find_class(name.absolute!)
49
+ type = env.class_decls[name] || env.class_decls[name.absolute!]
41
50
  next unless type
42
51
  next if type.type_params.empty?
43
52
 
@@ -46,14 +55,24 @@ def apply_to_includes(decl)
46
55
  end
47
56
  end
48
57
 
49
- decls.each do |decl|
50
- case decl
51
- when RBS::AST::Declarations::Class
52
- apply_to_superclass(decl)
53
- apply_to_includes(decl)
54
- when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface, RBS::AST::Declarations::Extension
55
- apply_to_includes(decl)
58
+ def analyze(decls)
59
+ decls.each do |decl|
60
+ case decl
61
+ when RBS::AST::Declarations::Class
62
+ apply_to_itself(decl)
63
+ apply_to_superclass(decl)
64
+ apply_to_includes(decl)
65
+ analyze(decl.members)
66
+ when RBS::AST::Declarations::Module, RBS::AST::Declarations::Interface
67
+ apply_to_itself(decl)
68
+ apply_to_includes(decl)
69
+ analyze(decl.members)
70
+ end
56
71
  end
57
72
  end
58
73
 
74
+ rbs = ARGF.read
75
+ decls = RBS::Parser.parse_signature(rbs)
76
+ analyze(decls)
77
+
59
78
  puts RBS::Writer.new(out: $stdout).write(decls)
@@ -0,0 +1,128 @@
1
+ #!ruby
2
+
3
+ # TODO: Expose me to user
4
+
5
+ require 'rbs'
6
+ require 'rbs/cli'
7
+ require 'optparse'
8
+
9
+ def env(options:)
10
+ loader = RBS::EnvironmentLoader.new()
11
+ options.setup(loader)
12
+ RBS::Environment.from_loader(loader).resolve_type_names
13
+ end
14
+
15
+ def parse_option(argv)
16
+ opt = OptionParser.new
17
+ options = RBS::CLI::LibraryOptions.new
18
+ cli = RBS::CLI.new(stdout: nil, stderr: nil)
19
+ cli.library_parse(opt, options: options)
20
+
21
+ return opt.parse(argv), options
22
+ end
23
+
24
+ class FileMatcher
25
+ def initialize(targets:)
26
+ base_dir = Dir.pwd
27
+ @targets = targets + targets.map { |t| File.expand_path(t, base_dir) }
28
+ end
29
+
30
+ def match?(fname)
31
+ @targets.any? { |t| fname.start_with?(t) }
32
+ end
33
+ end
34
+
35
+ def class_method_name(concern)
36
+ RBS::TypeName.new(namespace: concern.name.to_namespace, name: :ClassMethods)
37
+ end
38
+
39
+ def process(decl, env:, builder:, update_targets:)
40
+ concerns = decl.members.select do |m|
41
+ next false unless m.is_a?(RBS::AST::Members::Include)
42
+ next false unless m.name.kind == :class
43
+
44
+ mod_entry = env.class_decls[m.name]
45
+ unless mod_entry
46
+ warn "unknown type: #{m.name}"
47
+ next false
48
+ end
49
+
50
+ a = builder.singleton_ancestors(m.name)
51
+ a.ancestors.any? { |ancestor| ancestor.name.to_s == '::ActiveSupport::Concern' }
52
+ end
53
+
54
+ concerns.each do |concern|
55
+ class_methods_name = class_method_name(concern)
56
+ class_methods_type = env.class_decls[class_methods_name]
57
+ next unless class_methods_type
58
+
59
+ # Skip if the decl already extend ClassMethods
60
+ a = builder.singleton_ancestors(decl.name)
61
+ next if a.ancestors.any? { |ancestor| ancestor.name == class_methods_name }
62
+
63
+ # TODO: Insert `extend class_methods_name` to decl
64
+ update_targets << [decl, concern]
65
+ end
66
+ end
67
+
68
+ def each_decl_descendant(decl:, path: [], &block)
69
+ return unless decl.is_a?(RBS::AST::Declarations::Class) || decl.is_a?(RBS::AST::Declarations::Module)
70
+
71
+ block.call(decl: decl, path: path)
72
+ path = [*path, decl]
73
+ decl.each_decl do |child|
74
+ each_decl_descendant(decl: child, path: path, &block)
75
+ end
76
+ end
77
+
78
+ def may_eql_member?(a, b)
79
+ a.name.to_s.split('::').last == b.name.to_s.split('::').last
80
+ end
81
+
82
+ def update!(update_targets:)
83
+ update_targets.group_by { |decl, _concern| decl.location.name }.each do |fname, target_decls|
84
+ tree = RBS::Parser.parse_signature(File.read(fname))
85
+ target_decls.each do |target_decl, concern|
86
+ catch(:break) do
87
+ tree.each do |node|
88
+ each_decl_descendant(decl: node) do |decl:, path:|
89
+ next unless [relative = [*path, decl].map { |p| p.name.to_s }.join('::'), '::' + relative].include?(target_decl.name.to_s)
90
+
91
+ idx = decl.members.index { |m| may_eql_member?(m, concern) } || -1
92
+ extend = RBS::AST::Members::Extend.new(name: class_method_name(concern), args: [], annotations: [], location: nil, comment: nil)
93
+ decl.members.insert(idx + 1, extend)
94
+ throw :break
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ File.open(fname, 'w') do |f|
101
+ RBS::Writer.new(out: f).write(tree)
102
+ end
103
+ end
104
+ end
105
+
106
+ def run(argv)
107
+ targets, options = parse_option(argv)
108
+ env = env(options: options)
109
+ builder = RBS::DefinitionBuilder.new(env: env)
110
+ matcher = FileMatcher.new(targets: targets)
111
+
112
+ update_targets = []
113
+
114
+ env.class_decls.each do |_name, entry|
115
+ entry.decls.each do |d|
116
+ decl = d.decl
117
+ loc = decl.location
118
+ fname = loc.name
119
+ next unless matcher.match?(fname)
120
+
121
+ process(decl, env: env, builder: builder, update_targets: update_targets)
122
+ end
123
+ end
124
+
125
+ update!(update_targets: update_targets)
126
+ end
127
+
128
+ run(ARGV)
data/bin/rbs ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ rbs -rlogger -rpathname -rmutex_m -Isig -Iassets/sig $@
@@ -0,0 +1,142 @@
1
+ #!ruby
2
+
3
+ require 'rbs'
4
+ require 'rbs/cli'
5
+
6
+ using Module.new {
7
+ refine(Object) do
8
+ def const_name(node)
9
+ case node.type
10
+ when :CONST
11
+ node.children[0]
12
+ when :COLON2
13
+ base, name = node.children
14
+ base = const_name(base)
15
+ return unless base
16
+ "#{base}::#{name}"
17
+ end
18
+ end
19
+
20
+ def process_class_methods(node, decls:, comments:, singleton:)
21
+ return false unless node.type == :ITER
22
+
23
+ fcall = node.children[0]
24
+ return false unless fcall.children[0] == :class_methods
25
+
26
+ name = RBS::TypeName.new(name: :ClassMethods, namespace: RBS::Namespace.empty)
27
+ mod = RBS::AST::Declarations::Module.new(
28
+ name: name,
29
+ type_params: RBS::AST::Declarations::ModuleTypeParams.empty,
30
+ self_types: [],
31
+ members: [],
32
+ annotations: [],
33
+ location: nil,
34
+ comment: comments[node.first_lineno - 1]
35
+ )
36
+
37
+ decls.push mod
38
+
39
+ each_node [node.children[1]] do |child|
40
+ process child, decls: mod.members, comments: comments, singleton: false
41
+ end
42
+
43
+ true
44
+ end
45
+
46
+ def process_struct_new(node, decls:, comments:, singleton:)
47
+ return unless node.type == :CDECL
48
+
49
+ name, *_, rhs = node.children
50
+ fields, body = struct_new(rhs)
51
+ return unless fields
52
+
53
+ type_name = RBS::TypeName.new(name: name, namespace: RBS::Namespace.empty)
54
+ kls = RBS::AST::Declarations::Class.new(
55
+ name: type_name,
56
+ super_class: struct_as_superclass,
57
+ type_params: RBS::AST::Declarations::ModuleTypeParams.empty,
58
+ members: [],
59
+ annotations: [],
60
+ location: nil,
61
+ comment: comments[node.first_lineno - 1],
62
+ )
63
+ decls.push kls
64
+
65
+ fields.children.compact.each do |f|
66
+ case f.type
67
+ when :LIT, :STR
68
+ kls.members << RBS::AST::Members::AttrAccessor.new(
69
+ name: f.children.first,
70
+ type: untyped,
71
+ ivar_name: false,
72
+ annotations: [],
73
+ location: nil,
74
+ comment: nil,
75
+ )
76
+ end
77
+ end
78
+
79
+ if body
80
+ each_node [body] do |child|
81
+ process child, decls: kls.members, comments: comments, singleton: false
82
+ end
83
+ end
84
+
85
+ true
86
+ end
87
+
88
+ def class_new_method_to_type(node)
89
+ case node.type
90
+ when :CALL
91
+ recv, name, _args = node.children
92
+ return unless name == :new
93
+
94
+ klass = const_name(recv)
95
+ return unless klass
96
+
97
+ type_name = RBS::TypeName.new(name: klass, namespace: RBS::Namespace.empty)
98
+ RBS::Types::ClassInstance.new(name: type_name, args: [], location: nil)
99
+ end
100
+ end
101
+
102
+ def struct_new(node)
103
+ case node.type
104
+ when :CALL
105
+ # ok
106
+ when :ITER
107
+ call, block = node.children
108
+ return struct_new(call)&.tap do |r|
109
+ r << block
110
+ end
111
+ else
112
+ return
113
+ end
114
+
115
+ recv, method_name, args = node.children
116
+ return unless method_name == :new
117
+ return unless recv.type == :CONST || recv.type == :COLON3
118
+ return unless recv.children.first == :Struct
119
+
120
+ [args]
121
+ end
122
+
123
+ def struct_as_superclass
124
+ name = RBS::TypeName.new(name: 'Struct', namespace: RBS::Namespace.root)
125
+ RBS::AST::Declarations::Class::Super.new(name: name, args: ['untyped'])
126
+ end
127
+ end
128
+ }
129
+
130
+ module PrototypeExt
131
+ def process(...)
132
+ process_class_methods(...) || process_struct_new(...) || super
133
+ end
134
+
135
+ def literal_to_type(node)
136
+ class_new_method_to_type(node) || super
137
+ end
138
+ end
139
+
140
+ RBS::Prototype::RB.prepend PrototypeExt
141
+
142
+ RBS::CLI.new(stdout: STDOUT, stderr: STDERR).run(ARGV.dup)