rbs_rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)