plutonium 0.41.0 → 0.41.1
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/skills/plutonium-create-resource/SKILL.md +13 -0
- data/CHANGELOG.md +5 -0
- data/docs/reference/generators/index.md +14 -1
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +84 -15
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: db950a1455c885d7bdc26d86b267e95c8a7bd7cc61d5d3b2153d4225e7a40dcc
|
|
4
|
+
data.tar.gz: 6387d54982f72c298861147b167b59d768b32fa5f8ecccaa113c75b2d825df1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9a9dcb55e48ce7d86d8b8ee697149a96025cbacee380869188fa6d6af98981456e388ae16c141f5fc7934f44f8c1044aa0696aa9afe83e5749c8733a56bb7a5
|
|
7
|
+
data.tar.gz: 7e1c4765aa8d761ef049e9824574442b534bd1272506d2298993555bbfe25be929c58518876839f7e2be422e3cbd670c4504439f9ad05a3bf6bf14d052468f8e
|
|
@@ -113,6 +113,19 @@ Use `{default:value}` syntax for default values:
|
|
|
113
113
|
'status:string?{default:pending}' # Nullable with default
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
### JSON/JSONB Default Values
|
|
117
|
+
|
|
118
|
+
Supports nested braces for structured defaults:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
'metadata:jsonb{default:{}}' # Empty hash
|
|
122
|
+
'tags:jsonb{default:[]}' # Empty array
|
|
123
|
+
'settings:jsonb{default:{"theme":"dark"}}' # Object with values
|
|
124
|
+
'config:jsonb?{default:{}}' # Nullable with empty hash default
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Default values are parsed as JSON first. If JSON parsing fails, the value is treated as a string (or coerced based on column type for integers, floats, and booleans).
|
|
128
|
+
|
|
116
129
|
### Decimal with Precision and Default
|
|
117
130
|
|
|
118
131
|
```bash
|
data/CHANGELOG.md
CHANGED
|
@@ -96,7 +96,7 @@ Use `{default:value}` syntax to set default values:
|
|
|
96
96
|
# String with default
|
|
97
97
|
rails generate pu:res:scaffold Post 'status:string{default:draft}'
|
|
98
98
|
|
|
99
|
-
# Boolean with default
|
|
99
|
+
# Boolean with default (supports true/false/yes/1)
|
|
100
100
|
rails generate pu:res:scaffold Post 'active:boolean{default:true}'
|
|
101
101
|
|
|
102
102
|
# Integer with default
|
|
@@ -107,12 +107,25 @@ rails generate pu:res:scaffold Product 'price:decimal{10,2,default:0}'
|
|
|
107
107
|
|
|
108
108
|
# Nullable with default
|
|
109
109
|
rails generate pu:res:scaffold Post 'category:string?{default:general}'
|
|
110
|
+
|
|
111
|
+
# JSONB with empty hash default
|
|
112
|
+
rails generate pu:res:scaffold Post 'metadata:jsonb{default:{}}'
|
|
113
|
+
|
|
114
|
+
# JSONB with empty array default
|
|
115
|
+
rails generate pu:res:scaffold Post 'tags:jsonb{default:[]}'
|
|
116
|
+
|
|
117
|
+
# JSONB with object default
|
|
118
|
+
rails generate pu:res:scaffold Post 'settings:jsonb{default:{"theme":"dark"}}'
|
|
110
119
|
```
|
|
111
120
|
|
|
112
121
|
::: tip Shell Quoting
|
|
113
122
|
Always quote fields containing `?` or `{}` to prevent shell expansion.
|
|
114
123
|
:::
|
|
115
124
|
|
|
125
|
+
::: tip JSON Default Values
|
|
126
|
+
Default values are parsed as JSON first. This allows structured defaults like `{}` and `[]` for JSONB fields. If JSON parsing fails, the value is treated as a string (or coerced based on the column type for integers, floats, and booleans).
|
|
127
|
+
:::
|
|
128
|
+
|
|
116
129
|
#### Associations
|
|
117
130
|
|
|
118
131
|
```bash
|
|
@@ -73,11 +73,14 @@ module PlutoniumGenerators
|
|
|
73
73
|
def parse(model_name, column_definition)
|
|
74
74
|
# Protect content inside {} from being split on colons
|
|
75
75
|
# e.g., "status:string{default:draft}" -> split correctly
|
|
76
|
+
# Handles nested braces like "data:jsonb{default:{}}"
|
|
76
77
|
options_content = nil
|
|
77
78
|
if column_definition.include?("{")
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"{
|
|
79
|
+
options_content = extract_braced_content(column_definition)
|
|
80
|
+
if options_content
|
|
81
|
+
start_idx = column_definition.index("{")
|
|
82
|
+
end_idx = start_idx + options_content.length + 2 # +2 for { and }
|
|
83
|
+
column_definition = column_definition[0...start_idx] + "{OPTIONS}" + column_definition[end_idx..]
|
|
81
84
|
end
|
|
82
85
|
end
|
|
83
86
|
|
|
@@ -141,15 +144,17 @@ module PlutoniumGenerators
|
|
|
141
144
|
class_name_value = nil
|
|
142
145
|
|
|
143
146
|
if type&.include?("{")
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
options_content = extract_braced_content(type)
|
|
148
|
+
|
|
149
|
+
# Extract default:value (supports nested braces like {})
|
|
150
|
+
if options_content&.include?("default:")
|
|
151
|
+
default_value = extract_option_value(options_content, "default")
|
|
147
152
|
type = remove_option_from_type(type, "default", default_value)
|
|
148
153
|
end
|
|
149
154
|
|
|
150
155
|
# Extract class_name:Value
|
|
151
|
-
if (
|
|
152
|
-
class_name_value =
|
|
156
|
+
if options_content&.include?("class_name:")
|
|
157
|
+
class_name_value = extract_option_value(options_content, "class_name")
|
|
153
158
|
type = remove_option_from_type(type, "class_name", class_name_value)
|
|
154
159
|
end
|
|
155
160
|
end
|
|
@@ -166,18 +171,82 @@ module PlutoniumGenerators
|
|
|
166
171
|
[parsed_type, parsed_options]
|
|
167
172
|
end
|
|
168
173
|
|
|
174
|
+
# Extracts content inside outermost braces, respecting nested braces
|
|
175
|
+
# e.g., "jsonb{default:{}}" -> "default:{}"
|
|
176
|
+
def extract_braced_content(str)
|
|
177
|
+
start_idx = str.index("{")
|
|
178
|
+
return nil unless start_idx
|
|
179
|
+
|
|
180
|
+
depth = 0
|
|
181
|
+
(start_idx...str.length).each do |i|
|
|
182
|
+
case str[i]
|
|
183
|
+
when "{"
|
|
184
|
+
depth += 1
|
|
185
|
+
when "}"
|
|
186
|
+
depth -= 1
|
|
187
|
+
return str[(start_idx + 1)...i] if depth == 0
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Extracts option value, handling nested braces
|
|
194
|
+
# e.g., from "default:{},other:val" extracts "{}" for "default"
|
|
195
|
+
def extract_option_value(content, option_name)
|
|
196
|
+
prefix = "#{option_name}:"
|
|
197
|
+
start_idx = content.index(prefix)
|
|
198
|
+
return nil unless start_idx
|
|
199
|
+
|
|
200
|
+
value_start = start_idx + prefix.length
|
|
201
|
+
return nil if value_start >= content.length
|
|
202
|
+
|
|
203
|
+
# Check if value starts with a brace (nested structure)
|
|
204
|
+
if content[value_start] == "{"
|
|
205
|
+
depth = 0
|
|
206
|
+
(value_start...content.length).each do |i|
|
|
207
|
+
case content[i]
|
|
208
|
+
when "{"
|
|
209
|
+
depth += 1
|
|
210
|
+
when "}"
|
|
211
|
+
depth -= 1
|
|
212
|
+
return content[value_start..i] if depth == 0
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
content[value_start..]
|
|
216
|
+
else
|
|
217
|
+
# Simple value - read until comma or end
|
|
218
|
+
end_idx = content.index(",", value_start) || content.length
|
|
219
|
+
content[value_start...end_idx]
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
169
223
|
def remove_option_from_type(type, option_name, option_value)
|
|
170
224
|
escaped_value = Regexp.escape(option_value)
|
|
171
|
-
type
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
225
|
+
options_content = extract_braced_content(type)
|
|
226
|
+
return type unless options_content
|
|
227
|
+
|
|
228
|
+
cleaned = options_content
|
|
229
|
+
.gsub(/,?\s*#{option_name}:#{escaped_value}/, "")
|
|
230
|
+
.gsub(/#{option_name}:#{escaped_value},?\s*/, "")
|
|
231
|
+
|
|
232
|
+
prefix = type[0...type.index("{")]
|
|
233
|
+
cleaned.empty? ? prefix : "#{prefix}{#{cleaned}}"
|
|
178
234
|
end
|
|
179
235
|
|
|
236
|
+
# Coerces default value using JSON parsing for structured types,
|
|
237
|
+
# with type-based fallback for primitives
|
|
180
238
|
def coerce_default_value(value, type)
|
|
239
|
+
# Try JSON for structured types (hashes, arrays)
|
|
240
|
+
parsed = JSON.parse(value)
|
|
241
|
+
return parsed if parsed.is_a?(Hash) || parsed.is_a?(Array)
|
|
242
|
+
|
|
243
|
+
# For primitives, use type-based coercion
|
|
244
|
+
coerce_primitive_value(value, type)
|
|
245
|
+
rescue JSON::ParserError
|
|
246
|
+
coerce_primitive_value(value, type)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def coerce_primitive_value(value, type)
|
|
181
250
|
case type&.to_s
|
|
182
251
|
when "integer"
|
|
183
252
|
value.to_i
|
data/lib/plutonium/version.rb
CHANGED
data/package.json
CHANGED