rbs_activerecord 1.2.1 → 1.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 +4 -4
- data/.claude/hooks/claude-code-web-session-start.sh +14 -0
- data/.claude/hooks/pre-commit-check.sh +73 -0
- data/.claude/hooks/protect-sig-files.sh +45 -0
- data/.claude/hooks/rbs-inline.sh +95 -0
- data/.claude/hooks/self-review.sh +93 -0
- data/.claude/settings.json +58 -0
- data/.rubocop.yml +61 -1
- data/.vscode/settings.json +16 -1
- data/README.md +7 -0
- data/Rakefile +32 -3
- data/lib/generators/rbs_activerecord/install_generator.rb +5 -2
- data/lib/rbs_activerecord/generator/active_storage/instance_methods.rb +3 -2
- data/lib/rbs_activerecord/generator/active_storage/scopes.rb +1 -1
- data/lib/rbs_activerecord/generator/associations.rb +4 -4
- data/lib/rbs_activerecord/generator/attributes.rb +30 -5
- data/lib/rbs_activerecord/generator/delegated_type/instance_methods.rb +5 -5
- data/lib/rbs_activerecord/generator/delegated_type/scopes.rb +3 -3
- data/lib/rbs_activerecord/generator/enum/base.rb +2 -2
- data/lib/rbs_activerecord/generator/enum/instance_methods.rb +3 -3
- data/lib/rbs_activerecord/generator/enum/mappings.rb +2 -2
- data/lib/rbs_activerecord/generator/enum/scopes.rb +2 -2
- data/lib/rbs_activerecord/generator/scopes.rb +2 -2
- data/lib/rbs_activerecord/generator/secure_password.rb +1 -1
- data/lib/rbs_activerecord/generator.rb +6 -3
- data/lib/rbs_activerecord/model.rb +2 -1
- data/lib/rbs_activerecord/parser/evaluator.rb +3 -12
- data/lib/rbs_activerecord/parser/include_expander/module.rb +7 -5
- data/lib/rbs_activerecord/parser/include_expander.rb +4 -4
- data/lib/rbs_activerecord/parser/visitor.rb +1 -1
- data/lib/rbs_activerecord/parser.rb +2 -1
- data/lib/rbs_activerecord/rake_task.rb +6 -3
- data/lib/rbs_activerecord/utils.rb +8 -8
- data/lib/rbs_activerecord/version.rb +1 -1
- data/rbs_collection.lock.yaml +136 -64
- data/rbs_collection.yaml +1 -0
- data/sig/generators/rbs_activerecord/install_generator.rbs +1 -1
- data/sig/rbs_activerecord/generator/active_storage/instance_methods.rbs +1 -0
- data/sig/rbs_activerecord/generator/attributes.rbs +14 -1
- data/sig/rbs_activerecord/generator.rbs +4 -1
- data/sig/rbs_activerecord/parser.rbs +2 -1
- data/sig/rbs_activerecord/rake_task.rbs +4 -2
- data/sig/rbs_activerecord/utils.rbs +2 -2
- metadata +11 -7
|
@@ -6,16 +6,19 @@ module RbsActiverecord
|
|
|
6
6
|
include Utils
|
|
7
7
|
|
|
8
8
|
attr_reader :model #: RbsActiverecord::Model
|
|
9
|
+
attr_reader :pure_accessors #: bool
|
|
9
10
|
|
|
10
11
|
# @rbs model: RbsActiverecord::Model
|
|
11
|
-
|
|
12
|
+
# @rbs pure_accessors: bool
|
|
13
|
+
def initialize(model, pure_accessors:) #: void
|
|
12
14
|
@model = model
|
|
15
|
+
@pure_accessors = pure_accessors
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
def generate #: String
|
|
16
19
|
<<~RBS
|
|
17
20
|
module GeneratedAttributeMethods
|
|
18
|
-
#{model.columns.map {
|
|
21
|
+
#{model.columns.map { column(_1) }.join("\n")}
|
|
19
22
|
#{attributes.map { |name, type| attribute(name, type) }.join("\n")}
|
|
20
23
|
#{model.attribute_aliases.map { |from, to| alias_method(from, to) }.join("\n")}
|
|
21
24
|
end
|
|
@@ -24,14 +27,17 @@ module RbsActiverecord
|
|
|
24
27
|
|
|
25
28
|
private
|
|
26
29
|
|
|
30
|
+
# @rbs col: untyped
|
|
27
31
|
def column(col) #: String # rubocop:disable Metrics/AbcSize
|
|
28
32
|
type = sql_type_to_class(col.type)
|
|
29
33
|
optional = "#{type}?"
|
|
30
34
|
column_type = col.null ? optional : type
|
|
35
|
+
writer_type = writer_type_for(col.type, nullable: col.null)
|
|
31
36
|
|
|
32
37
|
<<~RBS
|
|
38
|
+
#{"%a{pure}" if pure_accessors}
|
|
33
39
|
def #{col.name}: () -> #{column_type}
|
|
34
|
-
def #{col.name}=: (#{
|
|
40
|
+
def #{col.name}=: (#{writer_type}) -> #{writer_type}
|
|
35
41
|
def #{col.name}?: () -> bool
|
|
36
42
|
def #{col.name}_changed?: () -> bool
|
|
37
43
|
def #{col.name}_change: () -> [#{optional}, #{optional}]
|
|
@@ -53,7 +59,7 @@ module RbsActiverecord
|
|
|
53
59
|
|
|
54
60
|
def attributes #: Hash[String, untyped]
|
|
55
61
|
model.attribute_types.filter_map do |name, type|
|
|
56
|
-
[name, type] if model.columns.none? {
|
|
62
|
+
[name, type] if model.columns.none? { _1.name == name }
|
|
57
63
|
end.to_h
|
|
58
64
|
end
|
|
59
65
|
|
|
@@ -61,13 +67,32 @@ module RbsActiverecord
|
|
|
61
67
|
# @rbs type: untyped
|
|
62
68
|
def attribute(name, type) #: String
|
|
63
69
|
column_type = sql_type_to_class(type.type)
|
|
70
|
+
writer_type = writer_type_for(type.type, nullable: false)
|
|
64
71
|
|
|
65
72
|
<<~RBS
|
|
66
73
|
def #{name}: () -> #{column_type}
|
|
67
|
-
def #{name}=: (#{
|
|
74
|
+
def #{name}=: (#{writer_type}) -> #{writer_type}
|
|
68
75
|
RBS
|
|
69
76
|
end
|
|
70
77
|
|
|
78
|
+
# The type accepted by the attribute writer.
|
|
79
|
+
# It is wider than the reader type for the types ActiveRecord casts on assignment.
|
|
80
|
+
#
|
|
81
|
+
# @rbs type: Symbol
|
|
82
|
+
# @rbs nullable: bool
|
|
83
|
+
def writer_type_for(type, nullable:) #: String
|
|
84
|
+
writer_type = case type
|
|
85
|
+
when :datetime
|
|
86
|
+
# A datetime attribute also accepts ::Time and converts it to ::ActiveSupport::TimeWithZone
|
|
87
|
+
"(::ActiveSupport::TimeWithZone | ::Time)"
|
|
88
|
+
else
|
|
89
|
+
sql_type_to_class(type)
|
|
90
|
+
end
|
|
91
|
+
nullable ? "#{writer_type}?" : writer_type
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @rbs from: untyped
|
|
95
|
+
# @rbs to: untyped
|
|
71
96
|
def alias_method(from, to) #: String
|
|
72
97
|
<<~RBS
|
|
73
98
|
alias #{from} #{to}
|
|
@@ -19,7 +19,7 @@ module RbsActiverecord
|
|
|
19
19
|
def generate #: String
|
|
20
20
|
<<~RBS.strip
|
|
21
21
|
module GeneratedDelegatedTypeInstanceMethods
|
|
22
|
-
#{delegated_types.map {
|
|
22
|
+
#{delegated_types.map { delegated_type(_1) }.join("\n")}
|
|
23
23
|
end
|
|
24
24
|
RBS
|
|
25
25
|
end
|
|
@@ -27,18 +27,18 @@ module RbsActiverecord
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def delegated_types #: Array[Prism::CallNode]
|
|
30
|
-
declarations.select {
|
|
30
|
+
declarations.select { _1.name == :delegated_type }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @rbs node: Prism::CallNode
|
|
34
|
-
def delegated_type(node) #: String
|
|
34
|
+
def delegated_type(node) #: String
|
|
35
35
|
arguments = node.arguments&.arguments || []
|
|
36
|
-
name, options = arguments.map {
|
|
36
|
+
name, options = arguments.map { Parser.eval_node(_1) } #: [String?, Hash[Symbol, untyped]]
|
|
37
37
|
return "" unless name
|
|
38
38
|
|
|
39
39
|
types = options[:types]
|
|
40
40
|
role_methods = <<~RBS
|
|
41
|
-
def #{name}_class: () -> (#{types.map {
|
|
41
|
+
def #{name}_class: () -> (#{types.map { "::#{_1}" }.join(" | ")})
|
|
42
42
|
def #{name}_name: () -> ::String
|
|
43
43
|
RBS
|
|
44
44
|
|
|
@@ -17,7 +17,7 @@ module RbsActiverecord
|
|
|
17
17
|
def generate #: String
|
|
18
18
|
<<~RBS.strip
|
|
19
19
|
module GeneratedDelegatedTypeScopeMethods[Relation]
|
|
20
|
-
#{delegated_types.map {
|
|
20
|
+
#{delegated_types.map { delegated_type(_1) }.join("\n")}
|
|
21
21
|
end
|
|
22
22
|
RBS
|
|
23
23
|
end
|
|
@@ -25,13 +25,13 @@ module RbsActiverecord
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
27
|
def delegated_types #: Array[Prism::CallNode]
|
|
28
|
-
declarations.select {
|
|
28
|
+
declarations.select { _1.name == :delegated_type }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
# @rbs node: Prism::CallNode
|
|
32
32
|
def delegated_type(node) #: String
|
|
33
33
|
arguments = node.arguments&.arguments || []
|
|
34
|
-
name, options = arguments.map {
|
|
34
|
+
name, options = arguments.map { Parser.eval_node(_1) } #: [String?, Hash[Symbol, untyped]]
|
|
35
35
|
return "" unless name
|
|
36
36
|
|
|
37
37
|
options[:types].map do |type|
|
|
@@ -7,9 +7,9 @@ module RbsActiverecord
|
|
|
7
7
|
private
|
|
8
8
|
|
|
9
9
|
# @rbs node: Prism::CallNode
|
|
10
|
-
def parse_arguments(node) #: [String?, Array[String | Symbol], Hash[Symbol, untyped]] # rubocop:disable Metrics/
|
|
10
|
+
def parse_arguments(node) #: [String?, Array[String | Symbol], Hash[Symbol, untyped]] # rubocop:disable Metrics/CyclomaticComplexity
|
|
11
11
|
arguments = node.arguments&.arguments || []
|
|
12
|
-
args = arguments.map {
|
|
12
|
+
args = arguments.map { Parser.eval_node(_1) }
|
|
13
13
|
return nil, [], {} if args.empty?
|
|
14
14
|
|
|
15
15
|
name = args[0] #: String?
|
|
@@ -21,7 +21,7 @@ module RbsActiverecord
|
|
|
21
21
|
def generate #: String
|
|
22
22
|
<<~RBS.strip
|
|
23
23
|
module GeneratedEnumInstanceMethods
|
|
24
|
-
#{enums.map {
|
|
24
|
+
#{enums.map { enum(_1) }.join("\n")}
|
|
25
25
|
end
|
|
26
26
|
RBS
|
|
27
27
|
end
|
|
@@ -29,7 +29,7 @@ module RbsActiverecord
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
31
|
def enums #: Array[Prism::CallNode]
|
|
32
|
-
declarations.select {
|
|
32
|
+
declarations.select { _1.name == :enum }
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
# @rbs node: Prism::CallNode
|
|
@@ -58,7 +58,7 @@ module RbsActiverecord
|
|
|
58
58
|
|
|
59
59
|
# @rbs name: String
|
|
60
60
|
def column_type(name) #: String
|
|
61
|
-
col = model.columns.find {
|
|
61
|
+
col = model.columns.find { _1.name == name.to_s }
|
|
62
62
|
if col
|
|
63
63
|
sql_type_to_class(col.type)
|
|
64
64
|
else
|
|
@@ -19,7 +19,7 @@ module RbsActiverecord
|
|
|
19
19
|
def generate #: String
|
|
20
20
|
<<~RBS.strip
|
|
21
21
|
module GeneratedEnumMappingMethods
|
|
22
|
-
#{enums.map {
|
|
22
|
+
#{enums.map { enum(_1) }.join("\n")}
|
|
23
23
|
end
|
|
24
24
|
RBS
|
|
25
25
|
end
|
|
@@ -27,7 +27,7 @@ module RbsActiverecord
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def enums #: Array[Prism::CallNode]
|
|
30
|
-
declarations.select {
|
|
30
|
+
declarations.select { _1.name == :enum }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @rbs node: Prism::CallNode
|
|
@@ -19,7 +19,7 @@ module RbsActiverecord
|
|
|
19
19
|
def generate #: String
|
|
20
20
|
<<~RBS.strip
|
|
21
21
|
module GeneratedEnumScopeMethods[Relation]
|
|
22
|
-
#{enums.map {
|
|
22
|
+
#{enums.map { enum(_1) }.join("\n")}
|
|
23
23
|
end
|
|
24
24
|
RBS
|
|
25
25
|
end
|
|
@@ -27,7 +27,7 @@ module RbsActiverecord
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def enums #: Array[Prism::CallNode]
|
|
30
|
-
declarations.select {
|
|
30
|
+
declarations.select { _1.name == :enum }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @rbs node: Prism::CallNode
|
|
@@ -16,7 +16,7 @@ module RbsActiverecord
|
|
|
16
16
|
def generate #: String
|
|
17
17
|
<<~RBS.strip
|
|
18
18
|
module GeneratedScopeMethods[Relation]
|
|
19
|
-
#{scopes.map {
|
|
19
|
+
#{scopes.map { scope(_1) }.join("\n")}
|
|
20
20
|
end
|
|
21
21
|
RBS
|
|
22
22
|
end
|
|
@@ -24,7 +24,7 @@ module RbsActiverecord
|
|
|
24
24
|
private
|
|
25
25
|
|
|
26
26
|
def scopes #: Array[Prism::CallNode]
|
|
27
|
-
declarations.select {
|
|
27
|
+
declarations.select { _1.name == :scope }
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
# @rbs node: Prism::CallNode
|
|
@@ -40,7 +40,7 @@ module RbsActiverecord
|
|
|
40
40
|
return [] unless secure_password?
|
|
41
41
|
|
|
42
42
|
model.klass.instance_methods.grep(/authenticate_/).filter_map do |method|
|
|
43
|
-
next if model.klass.
|
|
43
|
+
next if model.klass.method_defined?(:"#{method}_confirmation")
|
|
44
44
|
|
|
45
45
|
method.to_s.split("_", 2).last
|
|
46
46
|
end
|
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
require "rails"
|
|
4
4
|
|
|
5
5
|
module RbsActiverecord
|
|
6
|
-
class Generator
|
|
6
|
+
class Generator
|
|
7
7
|
include Utils
|
|
8
8
|
|
|
9
9
|
attr_reader :klass #: singleton(ActiveRecord::Base)
|
|
10
10
|
attr_reader :klass_name #: String
|
|
11
11
|
attr_reader :model #: RbsActiverecord::Model
|
|
12
|
+
attr_reader :pure_accessors #: bool
|
|
12
13
|
|
|
13
14
|
# @rbs klass: singleton(ActiveRecord::Base)
|
|
14
|
-
|
|
15
|
+
# @rbs pure_accessors: bool
|
|
16
|
+
def initialize(klass, pure_accessors: false) #: void
|
|
15
17
|
@klass = klass
|
|
16
18
|
@klass_name = klass.name || ""
|
|
17
19
|
@model = Model.new(klass)
|
|
20
|
+
@pure_accessors = pure_accessors
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
def generate #: String # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
@@ -22,7 +25,7 @@ module RbsActiverecord
|
|
|
22
25
|
# resolve-type-names: false
|
|
23
26
|
|
|
24
27
|
#{header}
|
|
25
|
-
#{Attributes.new(model).generate}
|
|
28
|
+
#{Attributes.new(model, pure_accessors:).generate}
|
|
26
29
|
#{Associations.new(model).generate}
|
|
27
30
|
|
|
28
31
|
#{ActiveStorage::InstanceMethods.new(model).generate}
|
|
@@ -14,6 +14,7 @@ module RbsActiverecord
|
|
|
14
14
|
# def columns: () -> Array[untyped]
|
|
15
15
|
# def defined_enums: () -> Hash[String, untyped]
|
|
16
16
|
# def reflect_on_all_associations: (Symbol) -> Array[untyped]
|
|
17
|
+
|
|
17
18
|
def_delegators :klass, :attribute_aliases, :attribute_types, :columns, :defined_enums, :reflect_on_all_associations
|
|
18
19
|
|
|
19
20
|
# @rbs klass: singleton(ActiveRecord::Base)
|
|
@@ -27,7 +28,7 @@ module RbsActiverecord
|
|
|
27
28
|
|
|
28
29
|
def parents #: Array[singleton(ActiveRecord::Base)]
|
|
29
30
|
ancestors = klass.ancestors #: Array[singleton(ActiveRecord::Base)]
|
|
30
|
-
ancestors.select {
|
|
31
|
+
ancestors.select { _1 < ActiveRecord::Base && _1 != klass && !_1.abstract_class? }
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
end
|
|
@@ -4,7 +4,7 @@ module RbsActiverecord
|
|
|
4
4
|
module Parser
|
|
5
5
|
module Evaluator
|
|
6
6
|
# @rbs node: Prism::Node
|
|
7
|
-
def eval_node(node) #: untyped # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
7
|
+
def eval_node(node) #: untyped # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
8
8
|
case node
|
|
9
9
|
when Prism::NilNode
|
|
10
10
|
nil
|
|
@@ -19,8 +19,8 @@ module RbsActiverecord
|
|
|
19
19
|
when Prism::StringNode
|
|
20
20
|
node.unescaped
|
|
21
21
|
when Prism::ArrayNode
|
|
22
|
-
node.elements.map {
|
|
23
|
-
when Prism::HashNode
|
|
22
|
+
node.elements.map { eval_node(_1) }
|
|
23
|
+
when Prism::HashNode, Prism::KeywordHashNode
|
|
24
24
|
node.elements.filter_map do |assoc|
|
|
25
25
|
case assoc
|
|
26
26
|
when Prism::AssocNode
|
|
@@ -34,15 +34,6 @@ module RbsActiverecord
|
|
|
34
34
|
when Prism::ConstantPathNode
|
|
35
35
|
parent = node.parent ? eval_node(node.parent) : nil
|
|
36
36
|
"#{parent}::#{node.name}"
|
|
37
|
-
when Prism::KeywordHashNode
|
|
38
|
-
node.elements.filter_map do |assoc|
|
|
39
|
-
case assoc
|
|
40
|
-
when Prism::AssocNode
|
|
41
|
-
key = eval_node(assoc.key)
|
|
42
|
-
value = eval_node(assoc.value)
|
|
43
|
-
[key, value]
|
|
44
|
-
end
|
|
45
|
-
end.to_h
|
|
46
37
|
end
|
|
47
38
|
end
|
|
48
39
|
module_function :eval_node
|
|
@@ -21,7 +21,7 @@ module RbsActiverecord
|
|
|
21
21
|
def included_blocks #: Array[Prism::CallNode]
|
|
22
22
|
return [] unless concern?
|
|
23
23
|
|
|
24
|
-
declarations.select {
|
|
24
|
+
declarations.select { _1.name == :included }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
private
|
|
@@ -31,10 +31,12 @@ module RbsActiverecord
|
|
|
31
31
|
def declarations #: Array[Prism::CallNode]
|
|
32
32
|
@declarations ||= begin
|
|
33
33
|
path = source_location
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
if path && File.exist?(path)
|
|
35
|
+
declarations = Parser.parse_file(path)
|
|
36
|
+
declarations.fetch(name, [])
|
|
37
|
+
else
|
|
38
|
+
[]
|
|
39
|
+
end
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
|
|
@@ -22,7 +22,7 @@ module RbsActiverecord
|
|
|
22
22
|
def expand #: void
|
|
23
23
|
declarations.each_value do |decls|
|
|
24
24
|
loop do
|
|
25
|
-
index = decls.index {
|
|
25
|
+
index = decls.index { _1.name == :include }
|
|
26
26
|
break unless index
|
|
27
27
|
|
|
28
28
|
included_module = decls.delete_at(index) || raise
|
|
@@ -39,8 +39,8 @@ module RbsActiverecord
|
|
|
39
39
|
# @rbs node: Prism::CallNode
|
|
40
40
|
def included_blocks_for(node) #: Array[Prism::CallNode]
|
|
41
41
|
modules = node.arguments&.arguments.to_a
|
|
42
|
-
.map {
|
|
43
|
-
.
|
|
42
|
+
.map { Parser.eval_node(_1) }
|
|
43
|
+
.grep(String)
|
|
44
44
|
modules.flat_map do |modname|
|
|
45
45
|
mod = const_get(modname)
|
|
46
46
|
next [] unless mod
|
|
@@ -69,7 +69,7 @@ module RbsActiverecord
|
|
|
69
69
|
case node.block.body
|
|
70
70
|
when Prism::StatementsNode
|
|
71
71
|
body = node.block.body.body #: Array[Prism::CallNode]
|
|
72
|
-
body.
|
|
72
|
+
body.grep(Prism::CallNode)
|
|
73
73
|
else
|
|
74
74
|
[]
|
|
75
75
|
end
|
|
@@ -14,8 +14,9 @@ module RbsActiverecord
|
|
|
14
14
|
end
|
|
15
15
|
module_function :parse
|
|
16
16
|
|
|
17
|
+
# @rbs filename: String
|
|
17
18
|
def parse_file(filename) #: Hash[String, Array[Prism::CallNode]]
|
|
18
|
-
File.open(filename) {
|
|
19
|
+
File.open(filename) { parse(_1.read) }
|
|
19
20
|
end
|
|
20
21
|
module_function :parse_file
|
|
21
22
|
|
|
@@ -4,14 +4,17 @@ require "rake/tasklib"
|
|
|
4
4
|
|
|
5
5
|
module RbsActiverecord
|
|
6
6
|
class RakeTask < Rake::TaskLib
|
|
7
|
-
attr_accessor :name
|
|
7
|
+
attr_accessor :name #: Symbol
|
|
8
|
+
attr_accessor :pure_accessors #: bool
|
|
9
|
+
attr_accessor :signature_root_dir #: Pathname
|
|
8
10
|
|
|
9
11
|
# @rbs name: Symbol
|
|
10
12
|
# @rbs &block: (RakeTask) -> void
|
|
11
|
-
def initialize(name = :
|
|
13
|
+
def initialize(name = :"rbs:activerecord", &block) #: void
|
|
12
14
|
super()
|
|
13
15
|
|
|
14
16
|
@name = name
|
|
17
|
+
@pure_accessors = false
|
|
15
18
|
@signature_root_dir = Rails.root / "sig/activerecord"
|
|
16
19
|
|
|
17
20
|
block&.call(self)
|
|
@@ -48,7 +51,7 @@ module RbsActiverecord
|
|
|
48
51
|
next if klass.abstract_class?
|
|
49
52
|
next unless klass.connection.table_exists?(klass.table_name)
|
|
50
53
|
|
|
51
|
-
rbs = Generator.new(klass).generate
|
|
54
|
+
rbs = Generator.new(klass, pure_accessors:).generate
|
|
52
55
|
|
|
53
56
|
path = signature_root_dir / "app/models/#{klass.name.underscore}.rbs"
|
|
54
57
|
path.dirname.mkpath
|
|
@@ -8,11 +8,11 @@ module RbsActiverecord
|
|
|
8
8
|
def format(str) #: String
|
|
9
9
|
parsed = RBS::Parser.parse_signature(str)
|
|
10
10
|
StringIO.new.tap do |out|
|
|
11
|
-
RBS::Writer.new(out:
|
|
11
|
+
RBS::Writer.new(out:).write(parsed[1] + parsed[2])
|
|
12
12
|
end.string
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
# @rbs
|
|
15
|
+
# @rbs klass: singleton(Object)
|
|
16
16
|
def klass_to_names(klass) #: Array[RBS::TypeName]
|
|
17
17
|
type_name = RBS::TypeName.parse("::#{klass.name}")
|
|
18
18
|
|
|
@@ -26,22 +26,22 @@ module RbsActiverecord
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# @rbs klass: singleton(ActiveRecord::Base)
|
|
29
|
-
def primary_key_type_for(klass) #: String
|
|
29
|
+
def primary_key_type_for(klass) #: String
|
|
30
30
|
case klass.primary_key
|
|
31
31
|
when Array
|
|
32
32
|
primary_keys = klass.primary_key.map(&:to_s)
|
|
33
33
|
types = klass.columns
|
|
34
|
-
.select {
|
|
35
|
-
.map {
|
|
34
|
+
.select { primary_keys.include?(_1.name) }
|
|
35
|
+
.map { sql_type_to_class(_1.type) }
|
|
36
36
|
"[#{types.join(" | ")}]"
|
|
37
37
|
else
|
|
38
|
-
primary_key = klass.columns.find {
|
|
38
|
+
primary_key = klass.columns.find { _1.name == klass.primary_key }
|
|
39
39
|
sql_type_to_class(primary_key.type)
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# @rbs type: Symbol
|
|
44
|
-
def sql_type_to_class(type) #: String # rubocop:disable
|
|
44
|
+
def sql_type_to_class(type) #: String # rubocop:disable Metrics/CyclomaticComplexity
|
|
45
45
|
case type
|
|
46
46
|
when :integer
|
|
47
47
|
"::Integer"
|
|
@@ -63,7 +63,7 @@ module RbsActiverecord
|
|
|
63
63
|
"untyped"
|
|
64
64
|
when :inet
|
|
65
65
|
"::IPAddr"
|
|
66
|
-
else
|
|
66
|
+
else # rubocop:disable Lint/DuplicateBranch
|
|
67
67
|
"untyped"
|
|
68
68
|
end
|
|
69
69
|
end
|