rbs-inline 0.2.0 → 0.4.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.
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