alba_migration 0.0.1 → 0.0.3
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/CHANGELOG.md +9 -0
- data/README.md +1 -0
- data/lib/alba_migration/cli.rb +4 -2
- data/lib/alba_migration/snippet.rb +221 -10
- data/lib/alba_migration/version.rb +1 -1
- data/sig/generated/alba_migration/snippet.rbs +12 -2
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f67906a1b1a0b5a723ed8c008a01ddc3175605b951545e5f9c63a6abea87720
|
4
|
+
data.tar.gz: bb47d0f21eb17c2ce923d3073426936fcfe30836c55010dd0eef6f99de664a61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bcfd3e77babad553ad41e7e6889448bc47c5da2fd7fa199238a04b547dfa7f3ed7c18c18fcc8eae37f01622aca87ccd4e4381346ab6c6509e6ce3faec63c428
|
7
|
+
data.tar.gz: a8e02d2763f1d6745ca9d5d7db8f079bc9988df7fda1229e7e9b6df7069560a7116a5db46e4574a4aa07535509ef49fbedefdbd117a6bf0d745757bf90a56a54
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# GHANGELOG
|
2
2
|
|
3
|
+
## 0.0.3 (2024-06-07)
|
4
|
+
|
5
|
+
- Add gem dependency for easier installation
|
6
|
+
|
7
|
+
## 0.0.2 (2024-05-19)
|
8
|
+
|
9
|
+
- Add attribute method rewriter for better AMS to Alba conversion
|
10
|
+
- Add tests for nested class conversion
|
11
|
+
|
3
12
|
## 0.0.1 (2025-05-19)
|
4
13
|
|
5
14
|
- Initial release
|
data/README.md
CHANGED
@@ -64,6 +64,7 @@ end
|
|
64
64
|
Currently, AlbaMigration supports the following AMS syntax:
|
65
65
|
- `class ... < ActiveModel::Serializer` with `attributes ...` inside the class body
|
66
66
|
- Only the conversion of the class definition and `attributes` is supported at this time
|
67
|
+
- Attribute methods (e.g. `attribute :foo do ... end`) are now automatically converted
|
67
68
|
- Other AMS features (e.g., associations, custom methods) are **not** yet supported
|
68
69
|
|
69
70
|
## Contributing
|
data/lib/alba_migration/cli.rb
CHANGED
@@ -28,8 +28,10 @@ module AlbaMigration
|
|
28
28
|
exit(1)
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
rewriter
|
31
|
+
snippets = AlbaMigration::Snippet.snippets(migrate_file_path: matched_files)
|
32
|
+
snippets.each do |rewriter|
|
33
|
+
rewriter.process
|
34
|
+
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -3,13 +3,31 @@
|
|
3
3
|
# rbs_inline: enabled
|
4
4
|
|
5
5
|
require "synvert/core"
|
6
|
+
require "standard"
|
6
7
|
|
7
8
|
module AlbaMigration
|
8
9
|
class Snippet
|
9
|
-
# @rbs
|
10
|
+
# @rbs migrate_file_path: String
|
11
|
+
# @rbs return: Array[Synvert::Core::Rewriter]
|
12
|
+
def self.snippets(migrate_file_path:)
|
13
|
+
snippet_creator = new(migrate_file_path:)
|
14
|
+
[
|
15
|
+
snippet_creator.superclass_rewriter,
|
16
|
+
snippet_creator.attribute_method_rewriter
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
# @rbs migrate_file_path: String
|
21
|
+
# @rbs return: void
|
22
|
+
def initialize(migrate_file_path:)
|
23
|
+
@migrate_file_path = migrate_file_path
|
24
|
+
end
|
25
|
+
|
10
26
|
# @rbs return: Synvert::Core::Rewriter
|
11
|
-
def
|
12
|
-
|
27
|
+
def superclass_rewriter
|
28
|
+
migrate_file_path = @migrate_file_path
|
29
|
+
|
30
|
+
Synvert::Core::Rewriter.new "alba_migration", "rewrite_superclass" do
|
13
31
|
description <<~EOS
|
14
32
|
It migrates ActiveModelSerializers syntax to Alba syntax.
|
15
33
|
|
@@ -36,16 +54,209 @@ module AlbaMigration
|
|
36
54
|
|
37
55
|
within_files migrate_file_path do
|
38
56
|
with_node node_type: "class_node", superclass: "ActiveModel::Serializer" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
57
|
+
body_src = node.body ? node.body.to_source : ""
|
58
|
+
replace_with "class #{node.constant_path.to_source}\ninclude Alba::Resource\n\n#{body_src}\nend"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Standard::Cli.new(["--fix", Array(migrate_file_path).join(" ")]).run
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @rbs return: Synvert::Core::Rewriter
|
67
|
+
def attribute_method_rewriter
|
68
|
+
migrate_file_path = @migrate_file_path
|
69
|
+
|
70
|
+
Synvert::Core::Rewriter.new "alba_migration", "rewrite_attribute_method" do
|
71
|
+
description <<~EOS
|
72
|
+
It migrates ActiveModelSerializers attribute syntax to Alba attribute syntax.
|
73
|
+
|
74
|
+
Example:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
class AttributeResource
|
78
|
+
attribute(:object)
|
79
|
+
attribute(:user_id)
|
80
|
+
attribute :user_name
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
=>
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class AttributeResource
|
88
|
+
attributes :object, :user_id, :user_name
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class AttributeResource
|
94
|
+
attribute(:object) { 'access_token' }
|
95
|
+
attribute(:user_id) { object.user_id }
|
96
|
+
attribute :user_name
|
97
|
+
def user_name
|
98
|
+
object.user.name
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
=>
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class AttributeResource
|
107
|
+
attribute :object do
|
108
|
+
'access_token'
|
109
|
+
end
|
110
|
+
attribute :user_id do |object|
|
111
|
+
object.user_id
|
112
|
+
end
|
113
|
+
attribute :user_name do |object|
|
114
|
+
object.user.name
|
45
115
|
end
|
46
|
-
|
116
|
+
end
|
117
|
+
```
|
118
|
+
EOS
|
119
|
+
|
120
|
+
configure(parser: "parser")
|
121
|
+
|
122
|
+
within_files migrate_file_path do
|
123
|
+
# Rewrite the entire class at once
|
124
|
+
with_node type: "class" do
|
125
|
+
class_name = node.children[0].loc.expression.source
|
126
|
+
class_body = node.children[2]
|
127
|
+
next unless class_body
|
128
|
+
|
129
|
+
# 1. Collect attribute blocks
|
130
|
+
attribute_blocks = []
|
131
|
+
other_lines = []
|
132
|
+
|
133
|
+
# Collect other lines in the class
|
134
|
+
class_body.children.each do |child|
|
135
|
+
if child && child.type == :send
|
136
|
+
if child.children[1] == :include || child.children[1] == :attributes
|
137
|
+
other_lines << " " + child.loc.expression.source
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# 1-1. Collect attribute(:xxx) { ... } style
|
143
|
+
class_body.children.each do |child|
|
144
|
+
if child && child.type == :block &&
|
145
|
+
child.children[0] && child.children[0].type == :send &&
|
146
|
+
child.children[0].children[1] == :attribute
|
147
|
+
|
148
|
+
# Process arguments
|
149
|
+
arg_node = child.children[0].children[2]
|
150
|
+
arg = (arg_node.type == :sym) ? ":#{arg_node.children[0]}" : arg_node.loc.expression.source
|
151
|
+
|
152
|
+
# Process block parameters
|
153
|
+
block_params = child.children[1] ? child.children[1].children.map { |c| c.children[0].to_s }.join(", ") : ""
|
154
|
+
|
155
|
+
# Process block body
|
156
|
+
block_body = child.children[2] ? child.children[2].loc.expression.source : ""
|
157
|
+
|
158
|
+
# Add 'object' to parameters if used in block body
|
159
|
+
if block_params.strip.empty? && block_body.include?("object")
|
160
|
+
block_params = "object"
|
161
|
+
end
|
162
|
+
|
163
|
+
# Generate new code(インデント付与はしない)
|
164
|
+
attribute_blocks << if block_params.strip.empty?
|
165
|
+
"attribute #{arg} do\n#{block_body}\nend"
|
166
|
+
else
|
167
|
+
"attribute #{arg} do |#{block_params.strip}|\n#{block_body}\nend"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# 1-2. Collect attribute :name + def name ... end style
|
173
|
+
attr_names = {}
|
174
|
+
other_methods = []
|
175
|
+
|
176
|
+
# First, collect attribute :name
|
177
|
+
class_body.children.each do |child|
|
178
|
+
if child && child.type == :send &&
|
179
|
+
child.children[1] == :attribute &&
|
180
|
+
child.children.length == 3 &&
|
181
|
+
child.children[2].type == :sym
|
182
|
+
|
183
|
+
attr_name = child.children[2].children[0].to_s
|
184
|
+
attr_names[attr_name] = nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Extract attribute names to be grouped as attributes
|
189
|
+
attributes_group = []
|
190
|
+
class_body.children.each do |child|
|
191
|
+
if child && child.type == :send &&
|
192
|
+
child.children[1] == :attribute &&
|
193
|
+
child.children.length == 3 &&
|
194
|
+
child.children[2].type == :sym
|
195
|
+
method_name = child.children[2].children[0].to_s
|
196
|
+
# Only group as attributes if there is no corresponding def method
|
197
|
+
unless class_body.children.any? { |c| c && c.type == :def && c.children[0].to_s == method_name }
|
198
|
+
attributes_group << ":#{method_name}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# 2. Generate new code for the entire class
|
204
|
+
new_lines = ["class #{class_name}"]
|
205
|
+
|
206
|
+
# Add attributes group at the top
|
207
|
+
unless attributes_group.empty?
|
208
|
+
new_lines << " attributes #{attributes_group.join(", ")}"
|
209
|
+
end
|
210
|
+
|
211
|
+
# Add include and attributes lines
|
212
|
+
if !other_lines.empty?
|
213
|
+
include_line = other_lines.find { |line| line.include?("include") }
|
214
|
+
attribute_lines = other_lines.select { |line| !line.include?("include") }
|
215
|
+
|
216
|
+
# Add include first
|
217
|
+
new_lines << include_line if include_line
|
218
|
+
|
219
|
+
# Add a blank line
|
220
|
+
new_lines << ""
|
221
|
+
|
222
|
+
# Add attributes lines
|
223
|
+
new_lines.concat(attribute_lines) unless attribute_lines.empty?
|
224
|
+
end
|
225
|
+
|
226
|
+
# 2-1. Add attribute blocks (no extra blank lines)
|
227
|
+
new_lines.concat(attribute_blocks)
|
228
|
+
|
229
|
+
# Convert attribute :name + def name ... end pairs
|
230
|
+
class_body.children.each do |child|
|
231
|
+
if child && child.type == :def
|
232
|
+
method_name = child.children[0].to_s
|
233
|
+
if attr_names.key?(method_name)
|
234
|
+
# Method corresponding to attribute (to be converted)
|
235
|
+
method_body = child.children[2]
|
236
|
+
method_src = method_body ? method_body.loc.expression.source : ""
|
237
|
+
# No indent
|
238
|
+
attr_names[method_name] = "attribute :#{method_name} do |object|\n#{method_src}\nend"
|
239
|
+
elsif child.respond_to?(:loc) && child.loc.respond_to?(:expression)
|
240
|
+
# Methods not corresponding to attribute (preserved)
|
241
|
+
method_src = child.loc.expression.source
|
242
|
+
other_methods << method_src
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# 2-2. Add conversion results of attribute :name + def name ... end (no extra blank lines)
|
248
|
+
attr_blocks = attr_names.values.compact
|
249
|
+
new_lines.concat(attr_blocks)
|
250
|
+
# 2-3. Add other methods (def not corresponding to attribute) (no extra blank lines)
|
251
|
+
new_lines.concat(other_methods)
|
252
|
+
|
253
|
+
new_lines << "end"
|
254
|
+
|
255
|
+
replace_with new_lines.join("\n")
|
47
256
|
end
|
48
257
|
end
|
258
|
+
|
259
|
+
Standard::Cli.new(["--fix", Array(migrate_file_path).join(" ")]).run
|
49
260
|
end
|
50
261
|
end
|
51
262
|
end
|
@@ -2,8 +2,18 @@
|
|
2
2
|
|
3
3
|
module AlbaMigration
|
4
4
|
class Snippet
|
5
|
-
# @rbs
|
5
|
+
# @rbs migrate_file_path: String
|
6
|
+
# @rbs return: Array[Synvert::Core::Rewriter]
|
7
|
+
def self.snippets: (migrate_file_path: String) -> Array[Synvert::Core::Rewriter]
|
8
|
+
|
9
|
+
# @rbs migrate_file_path: String
|
10
|
+
# @rbs return: void
|
11
|
+
def initialize: (migrate_file_path: String) -> void
|
12
|
+
|
13
|
+
# @rbs return: Synvert::Core::Rewriter
|
14
|
+
def superclass_rewriter: () -> Synvert::Core::Rewriter
|
15
|
+
|
6
16
|
# @rbs return: Synvert::Core::Rewriter
|
7
|
-
def
|
17
|
+
def attribute_method_rewriter: () -> Synvert::Core::Rewriter
|
8
18
|
end
|
9
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alba_migration
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ShoheiMitani
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: synvert-core
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: standard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: AlbaMigration is a CLI tool and library to help you convert your Ruby
|
28
42
|
code from ActiveModelSerializers (AMS) to Alba syntax. It rewrites AMS serializer
|
29
43
|
classes to Alba resource classes, supporting the migration of class definitions
|