rbs-siggen 0.1.0 → 0.2.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: 1e403c0c57cc49ef98ae97fc5f63ee2f0c7bfdb3d4311fd45239fc8c7c3c18a7
4
- data.tar.gz: 98fcb8dd20631d140fd925ce71f0f8864f47c0b1e3ad22cc8db536b9f3a42d25
3
+ metadata.gz: c368db792e08e8417cfc36a43cac9aa49e33eeeaf60c39cc7700db494832553b
4
+ data.tar.gz: 11ac12278d9d200e6258fb7230623213e3342006d138127b17f5fd24a454919d
5
5
  SHA512:
6
- metadata.gz: fa1febf6e6fe41d8bf020f1854cf0f41e956eec2b017d5c468196cfd78cb5cd802e7f6367c027cb9d1bfaf408252181c4d018ca66ca4e63e32a47d727de995e7
7
- data.tar.gz: 8bb8326380805b4a6732328e3715cf9e1315c9e3ad8d926b41857a4dff7a42185a6f9081d29dcb4a4e785c7761d2ea1f5cc67262c43e3f0141d85d0927786757
6
+ metadata.gz: d0ece64d8a739c938ad31197082f29fb7db72141a3932512117ea8e42073c56002b6db12fc4fdd130e25bc1d4c78178b1a39345299726344bebdab59a8059ed0
7
+ data.tar.gz: aec7870eb75d4fb9d568a546218d4807e1190ac9521b7e50392e0aac4089f79abc5bf6303c621cfddb6f54f44883ba6b0f0e4683a4855308b46147091173eb5c
data/Rakefile CHANGED
@@ -16,3 +16,12 @@ Steep::RakeTask.new do |t|
16
16
  end
17
17
 
18
18
  task default: %i[test rubocop steep]
19
+
20
+ desc "Generate siggen/*.rbs"
21
+ task :run_erb do
22
+ infile = "siggen/activerecord_model.rbs.erb"
23
+ outfile = "siggen/activerecord_model.rbs"
24
+ sh %|ruby -rerb -e 'ERB.new(File.read("#{infile}"), trim_mode: ?-).run' > #{outfile}|
25
+ end
26
+
27
+ task install: :run_erb
data/Steepfile CHANGED
@@ -12,5 +12,6 @@ target :test do
12
12
  unreferenced!
13
13
  signature "sig/test"
14
14
  check "test"
15
+ ignore "test/lib"
15
16
  configure_code_diagnostics(D::Ruby.lenient)
16
17
  end
data/exe/rbs-siggen CHANGED
@@ -6,12 +6,16 @@ require "rbs/siggen"
6
6
  require "pathname"
7
7
  require "optparse"
8
8
 
9
- options = { sig_dir: "sig" }
9
+ options = { sig_dirs: [], rails: false }
10
10
  parser = OptionParser.new do |opts|
11
11
  opts.banner = "Usage: rbs-siggen [options] <lib-path>"
12
12
 
13
- opts.on("--sig-dir DIR", "Path to RBS signature directory (default: sig)") do |dir|
14
- options[:sig_dir] = dir
13
+ opts.on("--sig-dir DIR", "Path to RBS signature directory (can be specified multiple times)") do |dir|
14
+ options[:sig_dirs] << dir
15
+ end
16
+
17
+ opts.on("--rails", "Preset to generate signatures for Rails applications") do
18
+ options[:rails] = true
15
19
  end
16
20
 
17
21
  opts.on("-v", "--version", "Show version") do
@@ -27,14 +31,47 @@ end
27
31
 
28
32
  parser.parse!
29
33
 
30
- if ARGV.empty?
34
+ if ARGV.empty? && !options[:rails]
31
35
  puts parser
32
36
  exit 1
33
37
  end
34
38
 
39
+ options[:sig_dirs] = ["sig"] if options[:sig_dirs].empty?
40
+
35
41
  lib_path = ARGV[0]
36
42
 
37
- siggen = RBS::Siggen.new(path: options[:sig_dir])
38
- siggen.analyze(path: Pathname(lib_path)) do |siggen, _|
39
- puts siggen.generate
43
+ siggen = RBS::Siggen.new do |env_loader|
44
+ options[:sig_dirs].each do |dir|
45
+ env_loader.add path: Pathname(dir)
46
+ end
47
+
48
+ Dir.glob("#{Dir.pwd}/**/rbs_collection.yaml").each do |path|
49
+ content = YAML.load_file(path)
50
+ env_loader.add path: Pathname(content["path"]) if Dir.exist?(content["path"])
51
+ end
52
+
53
+ if options[:rails]
54
+ spec = Gem::Specification.find_by_name("rbs-siggen")
55
+ env_loader.add path: Pathname(spec.gem_dir) / "siggen"
56
+ end
57
+ end
58
+
59
+ def find_rails_root(start_dir = Dir.pwd)
60
+ Pathname.new(start_dir).ascend do |path|
61
+ return path if File.exist? "#{path}/config/application.rb"
62
+ end
63
+ nil
64
+ end
65
+
66
+ if options[:rails] && lib_path.nil?
67
+ rails_root = find_rails_root
68
+ if rails_root
69
+ siggen.analyze(path: "#{rails_root}/db/schema.rb") do |siggen, _|
70
+ puts siggen.generate
71
+ end
72
+ end
73
+ else
74
+ siggen.analyze(path: Pathname(lib_path)) do |siggen, _|
75
+ puts siggen.generate
76
+ end
40
77
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RBS
4
4
  class Siggen
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
data/lib/rbs/siggen.rb CHANGED
@@ -13,11 +13,11 @@ module RBS
13
13
  # @rbs @typing: untyped
14
14
  # @rbs @node: Parser::AST::Node
15
15
 
16
- #: (path: String) -> void
17
- def initialize(path: "sig")
16
+ #: () ?{ (RBS::EnvironmentLoader) -> void } -> void
17
+ def initialize
18
18
  core_root = RBS::EnvironmentLoader::DEFAULT_CORE_ROOT
19
19
  env_loader = RBS::EnvironmentLoader.new(core_root: core_root)
20
- env_loader.add path: Pathname(path)
20
+ yield env_loader if block_given?
21
21
 
22
22
  env = RBS::Environment.new
23
23
  env_loader.load(env: env)
@@ -33,7 +33,7 @@ module RBS
33
33
 
34
34
  #: (path: String) { (Siggen, String) -> void } -> void
35
35
  def analyze(path:)
36
- ruby_files = Dir.glob("#{path}/**/*.rb")
36
+ ruby_files = Dir.glob(path) + Dir.glob("#{path}/**/*.rb")
37
37
  ruby_files.each do |file|
38
38
  analyze_ruby(File.read(file), name: file)
39
39
  yield self, file
@@ -102,7 +102,7 @@ module RBS
102
102
  annotations: annotations,
103
103
  context: context,
104
104
  typing: typing)
105
- construction.synthesize(source.node)
105
+ construction.synthesize(source.node) unless source.node.nil?
106
106
 
107
107
  @typing = typing
108
108
  @node = source.node
@@ -111,64 +111,233 @@ module RBS
111
111
 
112
112
  #: () -> String
113
113
  def generate
114
- result = {} #: Hash[String, Array[String]]
114
+ io = ::StringIO.new
115
+ traverse(@node) do |class_name, anno, arg_hash|
116
+ generated = ERB.new(anno).result_with_hash(arg_hash)
117
+ surround_class_def = false
118
+ begin
119
+ ::RBS::Parser.parse_signature(generated)
120
+ rescue ::RBS::ParsingError => e
121
+ if e.message =~ /Syntax error: cannot start a declaration/
122
+ surround_class_def = true
123
+ else
124
+ # TODO: Should output human readable error messages
125
+ puts generated # for debug
126
+ raise e
127
+ end
128
+ end
115
129
 
116
- traverse(@node) do |node, call_of|
117
- next unless node.type == :send
130
+ io.puts "class #{class_name}" if surround_class_def
131
+ io.puts generated
132
+ io.puts "end" if surround_class_def
133
+ end
134
+ io.rewind
135
+ _, _, decls = ::RBS::Parser.parse_signature(io.read || "")
136
+ return "" if decls.empty?
118
137
 
119
- _, _, *args = node.children
120
- args = args.map { |a| a.children[0] }
138
+ io = ::StringIO.new
139
+ ::RBS::Writer.new(out: io).write(merge_class_declarations(decls))
140
+ io.rewind
141
+ io.readlines.reject { |line| line.strip.empty? }.join
142
+ end
121
143
 
122
- call_of.method_decls.each do |method_decl|
123
- receiver_type = method_decl.method_name.type_name
124
- class_name = "#{receiver_type.namespace}#{receiver_type.name}"
144
+ #: (Parser::AST::Node node, ?Array[untyped] stack) ?{ (String, untyped, Hash[untyped, untyped]) -> void } -> void
145
+ def traverse(node, stack = [], &block)
146
+ return unless node.is_a?(::Parser::AST::Node)
125
147
 
126
- rp = method_decl.method_def.type.type.required_positionals.map(&:name)
127
- arg_hash = rp.zip(args).to_h
148
+ call_of = begin
149
+ @typing.call_of(node:)
150
+ rescue StandardError
151
+ nil
152
+ end
153
+
154
+ if call_of.nil? ||
155
+ call_of.is_a?(Steep::TypeInference::MethodCall::NoMethodError) || # steep:ignore
156
+ call_of.is_a?(Steep::TypeInference::MethodCall::Untyped) # steep:ignore
157
+ node.children.each do |child|
158
+ traverse(child, stack, &block)
159
+ end
160
+ elsif %i[send block].include?(node.type) # steep:ignore
161
+ call_of.method_decls.each do |method_decl|
128
162
  annos = method_decl.method_def
129
163
  .member_annotations
130
164
  .filter { |a| a.string.include?("siggen:") }
131
165
  .map { |a| a.string.split("siggen:")[1].strip }
132
166
  next if annos.empty?
133
167
 
134
- result[class_name] ||= []
135
- annos.each do |anno|
136
- result[class_name] << ERB.new(anno).result_with_hash(arg_hash)
168
+ arg_hash = {} #: Hash[untyped, untyped]
169
+ stack.each do |n, c|
170
+ arg_hash.merge!({ c.method_name.to_sym => hash_to_data(create_arg_hash(n, c.method_decls.first)) })
137
171
  end
172
+ arg_hash.merge!(create_arg_hash(node, method_decl))
173
+
174
+ annos.each { |anno| yield(create_class_name(method_decl), anno, arg_hash) }
138
175
  end
139
- end
140
176
 
141
- io = ::StringIO.new
142
- result.each do |key, values|
143
- io.puts "class #{key}"
144
- values.each do |v|
145
- io.puts " #{v}"
177
+ if node.type == :block
178
+ stack << [node, call_of]
179
+ node.children.each do |child|
180
+ traverse(child, stack, &block)
181
+ end
182
+ stack.pop
183
+ end
184
+ else # rubocop:disable Lint/DuplicateBranch
185
+ node.children.each do |child|
186
+ traverse(child, stack, &block)
146
187
  end
147
- io.puts "end"
148
188
  end
149
- io.rewind
150
- io.read || ""
151
189
  end
152
190
 
153
- #: (untyped node) ?{ (Parser::AST::Node node, untyped call_of) -> void } -> void
154
- def traverse(node, &block)
155
- return unless node.is_a?(::Parser::AST::Node)
191
+ #: (untyped) -> String
192
+ def create_class_name(method_decl)
193
+ receiver_type = method_decl.method_name.type_name.relative!
194
+ "#{receiver_type.namespace}#{receiver_type.name}"
195
+ end
156
196
 
157
- call_of = begin
158
- @typing.call_of(node:)
159
- rescue StandardError
160
- nil
197
+ #: (Parser::AST::Node, untyped) -> Hash[Symbol, untyped]
198
+ def create_arg_hash(node, method_decl)
199
+ send_node = node.type == :block ? node.children.first : node
200
+ _, _, *args = send_node.children
201
+ args = args.map { |arg_node| arg_node.type == :kwargs ? arg_node.children : arg_node.children[0] }.flatten
202
+ positional_args = args.reject { |arg_node| arg_node.respond_to?(:type) && arg_node.type == :pair }
203
+ keyword_args = args.filter do |arg_node|
204
+ arg_node.respond_to?(:type) && arg_node.type == :pair
205
+ end.to_h do |pair_node| # rubocop:disable Style/MultilineBlockChain
206
+ key = pair_node.children[0].children[0]
207
+ val_node = pair_node.children[1]
208
+ val = val_node.children[0] || val_node
209
+ val = val.type == :true if val.respond_to?(:type) # rubocop:disable Lint/BooleanSymbol
210
+ [key, val]
211
+ end
212
+
213
+ type = method_decl.method_def.type.type
214
+ hash = {} #: Hash[Symbol, untyped]
215
+ hash[:___node] = send_node
216
+ hash[:___source] = commentify(node.location.expression.source, node.location.expression.column)
217
+ hash[:___comment_of] = self
218
+
219
+ type.required_positionals.map(&:name).each do |name|
220
+ hash[name] = positional_args.shift
221
+ end
222
+ type.optional_positionals.map(&:name).each do |name|
223
+ hash[name] = positional_args.shift
161
224
  end
225
+ hash[type.rest_positionals.name] = positional_args.dup unless type.rest_positionals.nil?
162
226
 
163
- unless call_of.nil? ||
164
- call_of.is_a?(Steep::TypeInference::MethodCall::NoMethodError) || # steep:ignore
165
- call_of.is_a?(Steep::TypeInference::MethodCall::Untyped) # steep:ignore
166
- yield(node, call_of)
227
+ type.required_keywords.each_key do |name|
228
+ hash[name] = keyword_args[name]
229
+ keyword_args.delete(name)
167
230
  end
231
+ type.optional_keywords.each_key do |name|
232
+ hash[name] = keyword_args[name]
233
+ keyword_args.delete(name)
234
+ end
235
+ hash[type.rest_keywords.name] = keyword_args.dup unless type.rest_keywords.nil?
236
+ hash
237
+ end
238
+
239
+ #: (Hash[Symbol, untyped]) -> untyped
240
+ def hash_to_data(hash)
241
+ Data.define(*hash.keys).new(*hash.values)
242
+ end
168
243
 
169
- node.children.each do |child|
170
- traverse(child, &block)
244
+ #: (Array[untyped]) -> Array[untyped]
245
+ def merge_class_declarations(decls)
246
+ # 同じ名前のClass宣言をグループ化
247
+ grouped = decls.group_by do |decl|
248
+ case decl
249
+ when RBS::AST::Declarations::Class
250
+ [:class,
251
+ decl.name]
252
+ when RBS::AST::Declarations::Module
253
+ [:module,
254
+ decl.name]
255
+ else
256
+ [:other, decl.object_id] # その他はマージしない
257
+ end
171
258
  end
259
+
260
+ grouped.map do |(kind, _name), group|
261
+ if kind == :class && group.size > 1
262
+ # 複数のClass宣言をマージ
263
+ primary = group.find(&:super_class) || group.first
264
+ merged_members = merge_class_declarations(group.flat_map(&:members))
265
+ merged_annotations = group.flat_map(&:annotations).uniq
266
+ merged_comment = group.map(&:comment).compact.first
267
+
268
+ RBS::AST::Declarations::Class.new(
269
+ name: primary.name,
270
+ type_params: primary.type_params,
271
+ super_class: primary.super_class,
272
+ members: merged_members,
273
+ annotations: merged_annotations,
274
+ location: primary.location,
275
+ comment: merged_comment
276
+ )
277
+ elsif kind == :module && group.size > 1
278
+ # 複数のModule宣言をマージ
279
+ primary = group.first
280
+ merged_members = merge_class_declarations(group.flat_map(&:members))
281
+ merged_annotations = group.flat_map(&:annotations).uniq
282
+ merged_comment = group.map(&:comment).compact.first
283
+ merged_self_types = group.flat_map(&:self_types).uniq
284
+
285
+ RBS::AST::Declarations::Module.new(
286
+ name: primary.name,
287
+ type_params: primary.type_params,
288
+ self_types: merged_self_types,
289
+ members: merged_members,
290
+ annotations: merged_annotations,
291
+ location: primary.location,
292
+ comment: merged_comment
293
+ )
294
+ else
295
+ group
296
+ end
297
+ end.flatten
298
+ end
299
+
300
+ #: (String) -> Array[untyped]
301
+ def method_definitions(type_with_name)
302
+ definition_builder = RBS::DefinitionBuilder.new(env: @env)
303
+
304
+ definition = if type_with_name.include?("#")
305
+ type, name = type_with_name.split("#")
306
+ return [] if type.nil? || name.nil?
307
+
308
+ type_name = TypeName.parse(type).absolute!
309
+ return [] unless @env.module_name?(type_name)
310
+
311
+ definition_builder.build_instance(type_name)
312
+ else
313
+ type, name = type_with_name.split(".")
314
+ return [] if type.nil? || name.nil?
315
+
316
+ type_name = TypeName.parse(type).absolute!
317
+ return [] unless @env.module_name?(type_name)
318
+
319
+ definition_builder.build_singleton(TypeName.parse(type).absolute!)
320
+ end
321
+
322
+ method = definition.methods[name.to_sym]
323
+ return [] unless method
324
+
325
+ method.defs.map(&:member)
326
+ end
327
+
328
+ #: (String) -> String
329
+ def comment_of(type_with_name)
330
+ method_definitions(type_with_name).map(&:comment).map(&:string).join("\n")
331
+ end
332
+
333
+ #: (String, ?Integer) -> String
334
+ def commentify(string, start_column = 0)
335
+ string.each_line.map { |line| "# #{line.sub(/\A {0,#{start_column}}/, "")}" }.join.chomp.gsub(/\A# /, "")
336
+ end
337
+
338
+ #: (String) -> String
339
+ def [](type_with_name)
340
+ commentify(comment_of(type_with_name))
172
341
  end
173
342
  end
174
343
  end
@@ -0,0 +1,7 @@
1
+ # Generated from lib/rbs/siggen/version.rb with RBS::Inline
2
+
3
+ module RBS
4
+ class Siggen
5
+ VERSION: ::String
6
+ end
7
+ end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module RBS
4
4
  class Siggen
5
- @env: RBS::Environment
5
+ @node: Parser::AST::Node
6
6
 
7
7
  @typing: untyped
8
8
 
9
- @node: Parser::AST::Node
9
+ @env: RBS::Environment
10
10
 
11
- # : (path: String) -> void
12
- def initialize: (path: String) -> void
11
+ # : () ?{ (RBS::EnvironmentLoader) -> void } -> void
12
+ def initialize: () ?{ (RBS::EnvironmentLoader) -> void } -> void
13
13
 
14
14
  # : (String sig_string, ?name: String) -> void
15
15
  def add_signature: (String sig_string, ?name: String) -> void
@@ -23,7 +23,31 @@ module RBS
23
23
  # : () -> String
24
24
  def generate: () -> String
25
25
 
26
- # : (untyped node) ?{ (Parser::AST::Node node, untyped call_of) -> void } -> void
27
- def traverse: (untyped node) ?{ (Parser::AST::Node node, untyped call_of) -> void } -> void
26
+ # : (Parser::AST::Node node, ?Array[untyped] stack) ?{ (String, untyped, Hash[untyped, untyped]) -> void } -> void
27
+ def traverse: (Parser::AST::Node node, ?Array[untyped] stack) ?{ (String, untyped, Hash[untyped, untyped]) -> void } -> void
28
+
29
+ # : (untyped) -> String
30
+ def create_class_name: (untyped) -> String
31
+
32
+ # : (Parser::AST::Node, untyped) -> Hash[Symbol, untyped]
33
+ def create_arg_hash: (Parser::AST::Node, untyped) -> Hash[Symbol, untyped]
34
+
35
+ # : (Hash[Symbol, untyped]) -> untyped
36
+ def hash_to_data: (Hash[Symbol, untyped]) -> untyped
37
+
38
+ # : (Array[untyped]) -> Array[untyped]
39
+ def merge_class_declarations: (Array[untyped]) -> Array[untyped]
40
+
41
+ # : (String) -> Array[untyped]
42
+ def method_definitions: (String) -> Array[untyped]
43
+
44
+ # : (String) -> String
45
+ def comment_of: (String) -> String
46
+
47
+ # : (String, ?Integer) -> String
48
+ def commentify: (String, ?Integer) -> String
49
+
50
+ # : (String) -> String
51
+ def []: (String) -> String
28
52
  end
29
53
  end
@@ -0,0 +1,116 @@
1
+ module ActiveRecord
2
+ class Schema
3
+ def self.[]: (untyped version) -> ActiveRecord::Migration::Current
4
+ end
5
+ class Migration
6
+ class Current
7
+ def define: (version: untyped) { () [self: instance] -> void } -> void
8
+ %a{siggen:
9
+ # In schema.rb, this model is declared as:
10
+ #
11
+ # ```ruby
12
+ # <%= ___source %>
13
+ # ```
14
+ class <%= table_name.classify %>
15
+ include GeneratedAttributeMethods
16
+ end
17
+ }
18
+ def create_table: (untyped table_name, **untyped options) { (ActiveRecord::ConnectionAdapters::ColumnMethods t) -> void } -> void
19
+ end
20
+ end
21
+ module ConnectionAdapters
22
+ module ColumnMethods
23
+ %a{siggen:
24
+ class <%= create_table.table_name.classify %>
25
+ module GeneratedAttributeMethods
26
+ <% names.each do |name| %>
27
+ # In schema.rb, this column is declared as:
28
+ #
29
+ # ```ruby
30
+ # <%= ___source %>
31
+ # ```
32
+ #
33
+ # This method delegates to `ActiveRecord::AttributeMethods::Read` `#_read_attribute`,
34
+ # passing `"<%= name %>"` as the `attr_name` argument.
35
+ #
36
+ # See the documentation comment for the delegated method below:
37
+ #
38
+ # <%= ___comment_of["ActiveRecord::AttributeMethods::Read#read_attribute"] %>
39
+ def <%= name %>: () -> ::String<%= "?" unless options[:null] == false %>
40
+ <% end %>
41
+ end
42
+ end
43
+ }
44
+ def text: (*Array[untyped] names, **untyped options) -> void
45
+ %a{siggen:
46
+ class <%= create_table.table_name.classify %>
47
+ module GeneratedAttributeMethods
48
+ <% names.each do |name| %>
49
+ # In schema.rb, this column is declared as:
50
+ #
51
+ # ```ruby
52
+ # <%= ___source %>
53
+ # ```
54
+ #
55
+ # This method delegates to `ActiveRecord::AttributeMethods::Read` `#_read_attribute`,
56
+ # passing `"<%= name %>"` as the `attr_name` argument.
57
+ #
58
+ # See the documentation comment for the delegated method below:
59
+ #
60
+ # <%= ___comment_of["ActiveRecord::AttributeMethods::Read#read_attribute"] %>
61
+ def <%= name %>: () -> ::String<%= "?" unless options[:null] == false %>
62
+ <% end %>
63
+ end
64
+ end
65
+ }
66
+ def string: (*Array[untyped] names, **untyped options) -> void
67
+ %a{siggen:
68
+ class <%= create_table.table_name.classify %>
69
+ module GeneratedAttributeMethods
70
+ <% names.each do |name| %>
71
+ # In schema.rb, this column is declared as:
72
+ #
73
+ # ```ruby
74
+ # <%= ___source %>
75
+ # ```
76
+ #
77
+ # This method delegates to `ActiveRecord::AttributeMethods::Read` `#_read_attribute`,
78
+ # passing `"<%= name %>"` as the `attr_name` argument.
79
+ #
80
+ # See the documentation comment for the delegated method below:
81
+ #
82
+ # <%= ___comment_of["ActiveRecord::AttributeMethods::Read#read_attribute"] %>
83
+ def <%= name %>: () -> ::ActiveSupport::TimeWithZone<%= "?" unless options[:null] == false %>
84
+ <% end %>
85
+ end
86
+ end
87
+ }
88
+ def datetime: (*Array[untyped] names, **untyped options) -> void
89
+ %a{siggen:
90
+ class <%= create_table.table_name.classify %>
91
+ module GeneratedAttributeMethods
92
+ <% names.each do |name| %>
93
+ # In schema.rb, this column is declared as:
94
+ #
95
+ # ```ruby
96
+ # <%= ___source %>
97
+ # ```
98
+ #
99
+ # This method delegates to `ActiveRecord::AttributeMethods::Read` `#_read_attribute`,
100
+ # passing `"<%= name %>"` as the `attr_name` argument.
101
+ #
102
+ # See the documentation comment for the delegated method below:
103
+ #
104
+ # <%= ___comment_of["ActiveRecord::AttributeMethods::Read#read_attribute"] %>
105
+ def <%= name %>: () -> ::Integer<%= "?" unless options[:null] == false %>
106
+ <% end %>
107
+ end
108
+ end
109
+ }
110
+ def integer: (*Array[untyped] names, **untyped options) -> void
111
+ end
112
+ class TableDefinition
113
+ include ColumnMethods
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,53 @@
1
+ <%# ruby -rerb -e 'ERB.new(File.read("siggen/activerecord_model.rbs.erb"), trim_mode: ?-).run' > siggen/activerecord_model.rbs -%>
2
+ module ActiveRecord
3
+ class Schema
4
+ def self.[]: (untyped version) -> ActiveRecord::Migration::Current
5
+ end
6
+ class Migration
7
+ class Current
8
+ def define: (version: untyped) { () [self: instance] -> void } -> void
9
+ %a{siggen:
10
+ # In schema.rb, this model is declared as:
11
+ #
12
+ # ```ruby
13
+ # <%%= ___source %>
14
+ # ```
15
+ class <%%= table_name.classify %>
16
+ include GeneratedAttributeMethods
17
+ end
18
+ }
19
+ def create_table: (untyped table_name, **untyped options) { (ActiveRecord::ConnectionAdapters::ColumnMethods t) -> void } -> void
20
+ end
21
+ end
22
+ module ConnectionAdapters
23
+ module ColumnMethods
24
+ <%- { text: "::String", string: "::String", datetime: "::ActiveSupport::TimeWithZone", integer: "::Integer" }.each do |key, type| -%>
25
+ %a{siggen:
26
+ class <%%= create_table.table_name.classify %>
27
+ module GeneratedAttributeMethods
28
+ <%% names.each do |name| %>
29
+ # In schema.rb, this column is declared as:
30
+ #
31
+ # ```ruby
32
+ # <%%= ___source %>
33
+ # ```
34
+ #
35
+ # This method delegates to `ActiveRecord::AttributeMethods::Read` `#_read_attribute`,
36
+ # passing `"<%%= name %>"` as the `attr_name` argument.
37
+ #
38
+ # See the documentation comment for the delegated method below:
39
+ #
40
+ # <%%= ___comment_of["ActiveRecord::AttributeMethods::Read#read_attribute"] %>
41
+ def <%%= name %>: () -> <%= type %><%%= "?" unless options[:null] == false %>
42
+ <%% end %>
43
+ end
44
+ end
45
+ }
46
+ def <%= key %>: (*Array[untyped] names, **untyped options) -> void
47
+ <%- end -%>
48
+ end
49
+ class TableDefinition
50
+ include ColumnMethods
51
+ end
52
+ end
53
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbs-siggen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koji NAKAMURA
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: rbs
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -55,7 +69,9 @@ files:
55
69
  - rbs_collection.lock.yaml
56
70
  - rbs_collection.yaml
57
71
  - sig/generated/rbs/siggen.rbs
58
- - sig/rbs/siggen.rbs
72
+ - sig/generated/rbs/siggen/version.rbs
73
+ - siggen/activerecord_model.rbs
74
+ - siggen/activerecord_model.rbs.erb
59
75
  homepage: https://github.com/kozy4324/rbs-siggen
60
76
  licenses:
61
77
  - MIT
data/sig/rbs/siggen.rbs DELETED
@@ -1,5 +0,0 @@
1
- module RBS
2
- class Siggen
3
- VERSION: String
4
- end
5
- end