rbs-inline 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '091f44026573a60f39acf39a0b8865a3cee4a4f72401cd0ab8ce37d9e397caad'
4
- data.tar.gz: 95236c91fac2461db268a7fbd81503210d0d818bad958a6b9ff03d708a28558b
3
+ metadata.gz: 713b2bd4c5ddd833fa1bd1a71505924081013101a8a41200a88fed55751146ba
4
+ data.tar.gz: 44ffe7a91c0c0afeb7e163a02de508c50f96a609ae7c64593a6b739109ac11b0
5
5
  SHA512:
6
- metadata.gz: e76c5c6311109ffbac3a157625370a42f7f8b0cd2e1be58f8de4352d5e1528027acff819ecf7db6d9a6bb16bbb478adadfcb09d474816f7cc942a5a42be63729
7
- data.tar.gz: 8d7d4aba2f04cac960975add67c7d7ad30366806a540cd899a11f1250a7045145a9578732c055cf75ad50d1a68949d6aea55c7f7e3077d958aafb042f7c52149
6
+ metadata.gz: 6507f727be79bcae3890c8b8c3c3865544022058e44d5bfd060efb5df0c91e50f2b5e43a11f284c7ea3de1066bdd0ed7e269a14c20b45cc05cafa7ad60ecffb7
7
+ data.tar.gz: aad87cafa19657b4d4b055527924146cb232cd96c56081bcbb24c1e1b0ff2fc24a449bdfe2132a43c2e5f5ac2affca8d615d0946b135676979556eaca4887aec
data/README.md CHANGED
@@ -80,12 +80,12 @@ The gem works as a transpiler from annotated Ruby code to RBS files. Run `rbs-in
80
80
  $ bundle exec rbs-inline lib
81
81
 
82
82
  # Save generated RBS files under sig/generated
83
- $ bundle exec rbs-inline --output=sig/generated lib
83
+ $ bundle exec rbs-inline --output lib
84
84
  ```
85
85
 
86
86
  You may want to use `fswatch` or likes to automatically generate RBS files when you edit the Ruby code.
87
87
 
88
- $ fswatch -0 lib | xargs -0 -n1 bundle exec rbs-inline --output=sig/generated
88
+ $ fswatch -0 lib | xargs -0 -n1 bundle exec rbs-inline --output
89
89
 
90
90
  ## More materials
91
91
 
@@ -4,6 +4,27 @@ module RBS
4
4
  module Inline
5
5
  module AST
6
6
  module Annotations
7
+ # @rbs!
8
+ # type t = VarType
9
+ # | ReturnType
10
+ # | Use
11
+ # | Inherits
12
+ # | Generic
13
+ # | ModuleSelf
14
+ # | Skip
15
+ # | Assertion
16
+ # | Application
17
+ # | RBSAnnotation
18
+ # | Override
19
+ # | IvarType
20
+ # | Yields
21
+ # | Embedded
22
+ # # | Def
23
+ # # | AttrReader | AttrWriter | AttrAccessor
24
+ # # | Include | Extend | Prepend
25
+ # # | Alias
26
+
27
+
7
28
  class Base
8
29
  attr_reader :source #:: CommentLines
9
30
  attr_reader :tree #:: Tree
@@ -1,9 +1,24 @@
1
+ # rbs_inline: enabled
2
+
1
3
  module RBS
2
4
  module Inline
3
5
  module AST
6
+ # CommentLines represents consecutive comments
7
+ #
8
+ # The comments construct one String.
9
+ #
10
+ # ```ruby
11
+ # # Hello <-- Comment1
12
+ # # World <-- Comment2
13
+ # ```
14
+ #
15
+ # We want to get a String of comment1 and comment2, `"Hello\nWorld".
16
+ # And want to translate a location in the string into the location in comment1 and comment2.
17
+ #
4
18
  class CommentLines
5
- attr_reader :comments
19
+ attr_reader :comments #:: Array[[Prism::Comment, Integer]]
6
20
 
21
+ # @rbs comments: Array[Prism::Comment]
7
22
  def initialize(comments)
8
23
  offsets = comments.map do |comment|
9
24
  comment.location.slice.index(/[^#\s]/) || 1
@@ -18,10 +33,12 @@ module RBS
18
33
  end
19
34
  end
20
35
 
21
- def string
36
+ def string #:: String
22
37
  comments.map {|comment, offset| comment.location.slice[offset..] }.join("\n")
23
38
  end
24
39
 
40
+ # @rbs index: Integer
41
+ # @rbs returns [Prism::Comment, Integer]?
25
42
  def comment_location(index)
26
43
  comments.each do |comment, offset|
27
44
  comment_length = comment.location.length
@@ -9,23 +9,13 @@ module RBS
9
9
  # @rbs returns TypeName?
10
10
  def type_name(node)
11
11
  case node
12
- when Prism::ConstantReadNode
13
- TypeName(node.name.to_s)
14
- when Prism::ConstantPathNode
15
- if node.parent
16
- if parent = type_name(node.parent)
17
- if child = type_name(node.child)
18
- return parent + child
19
- end
20
- end
21
- else
22
- type_name(node.child)&.absolute!
23
- end
12
+ when Prism::ConstantReadNode, Prism::ConstantPathNode
13
+ TypeName(node.full_name)
24
14
  end
25
15
  end
26
16
  end
27
17
 
28
- # @rbs! type t = ClassDecl | ModuleDecl | ConstantDecl
18
+ # @rbs! type t = ClassDecl | ModuleDecl | ConstantDecl | SingletonClassDecl
29
19
 
30
20
  # @rbs!
31
21
  # interface _WithComments
@@ -237,6 +227,9 @@ module RBS
237
227
  node.location.start_line
238
228
  end
239
229
  end
230
+
231
+ class SingletonClassDecl < ModuleOrClass #[Prism::SingletonClassNode]
232
+ end
240
233
  end
241
234
  end
242
235
  end
@@ -4,6 +4,11 @@ module RBS
4
4
  module Inline
5
5
  module AST
6
6
  module Members
7
+ # @rbs!
8
+ # type ruby = RubyDef | RubyAlias | RubyMixin | RubyAttr | RubyPublic | RubyPrivate
9
+ # type rbs = RBSIvar | RBSEmbedded
10
+ # type t = ruby | rbs
11
+
7
12
  class Base
8
13
  attr_reader :location #:: Prism::Location
9
14
 
@@ -64,27 +69,6 @@ module RBS
64
69
  end
65
70
  end
66
71
 
67
- # Returns the `kind` of the method definition
68
- #
69
- # [FIXME] It only supports `self` receiver.
70
- #
71
- # ```rb
72
- # def self.foo = () # :singleton
73
- # def object.foo = () # Not supported (returns :instance)
74
- # ```
75
- #
76
- def method_kind #:: RBS::AST::Members::MethodDefinition::kind
77
- # FIXME: really hacky implementation
78
- case node.receiver
79
- when Prism::SelfNode
80
- :singleton
81
- when nil
82
- :instance
83
- else
84
- :instance
85
- end
86
- end
87
-
88
72
  def return_type #:: Types::t?
89
73
  if assertion
90
74
  if assertion.type?
@@ -341,6 +325,8 @@ module RBS
341
325
  end
342
326
 
343
327
  class RubyMixin < RubyBase
328
+ include Declarations::ConstantUtil
329
+
344
330
  # CallNode that calls `include`, `prepend`, and `extend` method
345
331
  attr_reader :node #:: Prism::CallNode
346
332
 
@@ -371,11 +357,8 @@ module RBS
371
357
  return unless node.arguments.arguments.size == 1
372
358
 
373
359
  arg = node.arguments.arguments[0] || raise
374
- if arg.is_a?(Prism::ConstantReadNode)
375
- type_name = RBS::TypeName.new(name: arg.name, namespace: RBS::Namespace.empty)
376
- else
377
- raise
378
- end
360
+ type_name = type_name(arg)
361
+ return unless type_name
379
362
 
380
363
  args = [] #: Array[Types::t]
381
364
  if application
@@ -1,17 +1,28 @@
1
+ # rbs_inline: enabled
2
+
1
3
  module RBS
2
4
  module Inline
3
5
  module AST
4
6
  class Tree
5
- attr_reader :trees
6
- attr_reader :type
7
- attr_reader :non_trivia_trees
7
+ # @rbs!
8
+ # type token = [Symbol, String]
9
+ # type tree = token | Tree | Types::t | MethodType | nil
10
+
11
+ attr_reader :trees #:: Array[tree]
12
+ attr_reader :type #:: Symbol
13
+
14
+ # Children but without `tWHITESPACE` tokens
15
+ attr_reader :non_trivia_trees #:: Array[tree]
8
16
 
17
+ # @rbs type: Symbol
9
18
  def initialize(type)
10
19
  @type = type
11
20
  @trees = []
12
21
  @non_trivia_trees = []
13
22
  end
14
23
 
24
+ # @rbs tok: tree
25
+ # @rbs returns self
15
26
  def <<(tok)
16
27
  trees << tok
17
28
  unless tok.is_a?(Array) && tok[0] == :tWHITESPACE
@@ -20,7 +31,8 @@ module RBS
20
31
  self
21
32
  end
22
33
 
23
- def to_s
34
+ # Returns the source code associated to the tree
35
+ def to_s #:: String
24
36
  buf = +""
25
37
 
26
38
  trees.each do |tree|
@@ -39,6 +51,12 @@ module RBS
39
51
  buf
40
52
  end
41
53
 
54
+ # Returns n-th token from the children
55
+ #
56
+ # Raises if the value is not a token or nil.
57
+ #
58
+ # @rbs index: Integer
59
+ # @rbs returns token?
42
60
  def nth_token(index)
43
61
  tok = non_trivia_trees[index]
44
62
  case tok
@@ -49,6 +67,12 @@ module RBS
49
67
  end
50
68
  end
51
69
 
70
+ # Returns n-th token from the children
71
+ #
72
+ # Returns `nil` if the value is not a token.
73
+ #
74
+ # @rbs index: Integer
75
+ # @rbs returns token?
52
76
  def nth_token?(index)
53
77
  tok = non_trivia_trees[index]
54
78
  case tok
@@ -59,10 +83,22 @@ module RBS
59
83
  end
60
84
  end
61
85
 
86
+ # Returns n-th token from the children
87
+ #
88
+ # Raises if the value is not token.
89
+ #
90
+ # @rbs index: Integer
91
+ # @rbs returns token
62
92
  def nth_token!(index)
63
93
  nth_token(index) || raise
64
94
  end
65
95
 
96
+ # Returns n-th tree from the children
97
+ #
98
+ # Raises if the value is not a tree or nil.
99
+ #
100
+ # @rbs index: Integer
101
+ # @rbs returns Tree?
66
102
  def nth_tree(index)
67
103
  tok = non_trivia_trees[index]
68
104
  case tok
@@ -73,6 +109,12 @@ module RBS
73
109
  end
74
110
  end
75
111
 
112
+ # Returns n-th tree from the children
113
+ #
114
+ # Returns `nil` if the value is not a tree or nil.
115
+ #
116
+ # @rbs index: Integer
117
+ # @rbs returns Tree?
76
118
  def nth_tree?(index)
77
119
  tok = non_trivia_trees[index]
78
120
  case tok
@@ -83,11 +125,23 @@ module RBS
83
125
  end
84
126
  end
85
127
 
128
+ # Returns n-th tree from the children
129
+ #
130
+ # Raises if the value is not a tree.
131
+ #
132
+ # @rbs index: Integer
133
+ # @rbs returns Tree
86
134
  def nth_tree!(index)
87
135
  nth_tree(index) || raise
88
136
  end
89
137
 
90
138
 
139
+ # Returns n-th type from the children
140
+ #
141
+ # Raises if the value is not a type or nil.
142
+ #
143
+ # @rbs index: Integer
144
+ # @rbs returns Types::t?
91
145
  def nth_type(index)
92
146
  tok = non_trivia_trees[index]
93
147
  case tok
@@ -98,6 +152,12 @@ module RBS
98
152
  end
99
153
  end
100
154
 
155
+ # Returns n-th type from the children
156
+ #
157
+ # Returns `nil` if the value is not a type.
158
+ #
159
+ # @rbs index: Integer
160
+ # @rbs returns Types::t?
101
161
  def nth_type?(index)
102
162
  tok = non_trivia_trees[index]
103
163
  case tok
@@ -108,10 +168,22 @@ module RBS
108
168
  end
109
169
  end
110
170
 
171
+ # Returns n-th type from the children
172
+ #
173
+ # Raises if the value is not a type.
174
+ #
175
+ # @rbs index: Integer
176
+ # @rbs returns Types::t
111
177
  def nth_type!(index)
112
178
  nth_type(index) || raise
113
179
  end
114
180
 
181
+ # Returns n-th method type from the children
182
+ #
183
+ # Raises if the value is not a method type or `nil`.
184
+ #
185
+ # @rbs index: Integer
186
+ # @rbs returns MethodType?
115
187
  def nth_method_type(index)
116
188
  tok = non_trivia_trees[index]
117
189
  case tok
@@ -122,6 +194,12 @@ module RBS
122
194
  end
123
195
  end
124
196
 
197
+ # Returns n-th method type from the children
198
+ #
199
+ # Returns `nil` if the value is not a method type.
200
+ #
201
+ # @rbs index: Integer
202
+ # @rbs returns MethodType?
125
203
  def nth_method_type?(index)
126
204
  tok = non_trivia_trees[index]
127
205
  case tok
@@ -132,6 +210,12 @@ module RBS
132
210
  end
133
211
  end
134
212
 
213
+ # Returns n-th method tree from the children
214
+ #
215
+ # Raises if the value is not a method tree.
216
+ #
217
+ # @rbs index: Integer
218
+ # @rbs returns MethodType
135
219
  def nth_method_type!(index)
136
220
  nth_method_type(index) || raise
137
221
  end
@@ -72,15 +72,28 @@ module RBS
72
72
  def run(args)
73
73
  base_paths = [Pathname("lib"), Pathname("app")]
74
74
  output_path = nil #: Pathname?
75
+ opt_in = true
75
76
 
76
77
  OptionParser.new do |opts|
77
- opts.on("--base=[BASE]", "The path to calculate relative path of files (defaults to #{base_paths.join(File::PATH_SEPARATOR)})") do |str|
78
+ opts.on("--base=BASE", "The path to calculate relative path of files (defaults to #{base_paths.join(File::PATH_SEPARATOR)})") do |str|
78
79
  # @type var str: String
79
80
  base_paths = str.split(File::PATH_SEPARATOR).map {|path| Pathname(path) }
80
81
  end
81
82
 
82
- opts.on("--output=[BASE]", "The directory where the RBS files are saved at (defaults to STDOUT if not specified)") do
83
- output_path = Pathname(_1)
83
+ opts.on("--output[=DEST]", "Save the generated RBS files under `sig/generated` or DEST if specified (defaults to output to STDOUT)") do
84
+ if _1
85
+ output_path = Pathname(_1)
86
+ else
87
+ output_path = Pathname("sig/generated")
88
+ end
89
+ end
90
+
91
+ opts.on("--opt-out", "Generates RBS files by default. Opt-out with `# rbs_inline: disabled` comment") do
92
+ opt_in = false
93
+ end
94
+
95
+ opts.on("--opt-in", "Generates RBS files only for files with `# rbs_inline: enabled` comment (default)") do
96
+ opt_in = true
84
97
  end
85
98
 
86
99
  opts.on("--verbose") do
@@ -126,7 +139,7 @@ module RBS
126
139
 
127
140
  logger.debug { "Parsing ruby file #{target}..." }
128
141
 
129
- if (uses, decls = Parser.parse(Prism.parse_file(target.to_s)))
142
+ if (uses, decls = Parser.parse(Prism.parse_file(target.to_s), opt_in: opt_in))
130
143
  writer = Writer.new()
131
144
  writer.header("Generated from #{target.relative? ? target : target.relative_path_from(Pathname.pwd)} with RBS::Inline")
132
145
  writer.write(uses, decls)
@@ -1,6 +1,10 @@
1
+ # rbs_inline: enabled
2
+
1
3
  module RBS
2
4
  module Inline
3
5
  module NodeUtils
6
+ # @rbs node: Prism::Node
7
+ # @rbs returns TypeName?
4
8
  def type_name(node)
5
9
  case node
6
10
  when Prism::ConstantReadNode
@@ -1,3 +1,5 @@
1
+ # rbs_inline: enabled
2
+
1
3
  # @rbs use Prism::*
2
4
 
3
5
  module RBS
@@ -36,22 +38,26 @@ module RBS
36
38
  @comments = {}
37
39
  end
38
40
 
39
- # @rbs result: ParseResult[ProgramNode]
41
+ # @rbs result: ParseResult
42
+ # @rbs opt_in: bool -- `true` for *opt-out* mode, `false` for *opt-in* mode.
40
43
  # @rbs returns [Array[AST::Annotations::Use], Array[AST::Declarations::t]]?
41
- def self.parse(result)
44
+ def self.parse(result, opt_in:)
42
45
  instance = Parser.new()
43
46
 
44
- # pp result
45
-
46
47
  annots = AnnotationParser.parse(result.comments)
47
48
  annots.each do |result|
48
49
  instance.comments[result.line_range.end] = result
49
50
  end
50
51
 
51
- with_magic_comment = result.comments.any? {|comment| comment.location.slice =~ /\A# rbs_inline: enabled\Z/}
52
- with_annotation = annots.any? {|result| result.annotations.any? }
52
+ with_enable_magic_comment = result.comments.any? {|comment| comment.location.slice =~ /\A# rbs_inline: enabled\Z/}
53
+ with_disable_magic_comment = result.comments.any? {|comment| comment.location.slice =~ /\A# rbs_inline: disabled\Z/}
53
54
 
54
- return unless with_magic_comment || with_annotation
55
+ return if with_disable_magic_comment # Skips if `rbs_inline: disabled`
56
+
57
+ if opt_in
58
+ # opt-in means the `rbs_inline: enable` is required.
59
+ return unless with_enable_magic_comment
60
+ end
55
61
 
56
62
  uses = [] #: Array[AST::Annotations::Use]
57
63
  annots.each do |annot|
@@ -80,7 +86,7 @@ module RBS
80
86
  current_class_module_decl or raise
81
87
  end
82
88
 
83
- #:: (AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl) { () -> void } -> void
89
+ #:: (AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl | AST::Declarations::SingletonClassDecl) { () -> void } -> void
84
90
  #:: (AST::Declarations::ConstantDecl) -> void
85
91
  def push_class_module_decl(decl)
86
92
  if current = current_class_module_decl
@@ -146,6 +152,18 @@ module RBS
146
152
  load_inner_annotations(node.location.start_line, node.location.end_line, class_decl.members)
147
153
  end
148
154
 
155
+ # @rbs override
156
+ def visit_singleton_class_node(node)
157
+ return if ignored_node?(node)
158
+
159
+ associated_comment = comments.delete(node.location.start_line - 1)
160
+ singleton_decl = AST::Declarations::SingletonClassDecl.new(node, associated_comment)
161
+
162
+ push_class_module_decl(singleton_decl) do
163
+ visit node.body
164
+ end
165
+ end
166
+
149
167
  # @rbs override
150
168
  def visit_module_node(node)
151
169
  return if ignored_node?(node)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RBS
4
4
  module Inline
5
- VERSION = "0.2.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end