tina4ruby 3.13.128 → 3.13.129

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tina4/cli.rb +73 -22
  3. data/lib/tina4/version.rb +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63a254da7848fb136bf9c014d3ac291c31b9046ee2ad7bd40222189f5d8e031b
4
- data.tar.gz: e9a23c45ec6b6c3ff46125454259447e743ffe6097a7866f486c6b5a8cc5aaad
3
+ metadata.gz: e0792f247e0fc7d10a52db84896d8cd475d509e258a1b121b06564e45cfa3913
4
+ data.tar.gz: 91ecd21265adabfd4874596c68b63f10c36bab1cb39fd49c4be4b0db1d8ec289
5
5
  SHA512:
6
- metadata.gz: dd3e42f53f1515ddfb137cd6713a11650309d4da359030cecde6be6368cad5309175b04943b25fa8bc5349e6b8505c2231a128b7de3c905c7a5605bf4d71c454
7
- data.tar.gz: 81c929c2b3b06ce99682c440e1ce6385cb2bda7d836638e158fd0c0d2bcc41526eb7b7e055159c9aeab38468a16843d05b77b57f76beec525dab16ccc8cf9dec
6
+ metadata.gz: a464c761ff621eeb3a10068a1ad436fe1b71d1403792885a07442b1f8dc475d80c1f64736e3a456c2a71edd72c0fee6fabd215e8fb61e6eb543e2d2b02531831
7
+ data.tar.gz: 86c6e9cb683134790b85159c797225c3bb8d126fe8fbc1d0bfc8d0f3aeaf1dfcf781b5a21ae4d8cf414c04875726a32db98cc5cfd12b87b10603e815d805e17a
data/lib/tina4/cli.rb CHANGED
@@ -30,7 +30,7 @@ module Tina4
30
30
  # handlers take (name, flags); COMMANDS handlers take (argv).
31
31
 
32
32
  GENERATORS = {
33
- "model" => { handler: :generate_model, usage: '<Name> [--fields "name:string,price:float"]', summary: "ORM model + matching migration" },
33
+ "model" => { handler: :generate_model, usage: '<Name> [--fields "name:string,price:float"] [--table-name <name>]', summary: "ORM model + matching migration" },
34
34
  "route" => { handler: :generate_route, usage: "<name> [--model Name] [--public]", summary: "CRUD route file, secure by default (--public opens writes)" },
35
35
  "crud" => { handler: :generate_crud, usage: '<Name> [--fields "..."] [--public]', summary: "Model + migration + routes + form + view + test" },
36
36
  "migration" => { handler: :generate_migration, usage: "<description>", summary: "Timestamped migration file (UP/DOWN)" },
@@ -284,6 +284,52 @@ module Tina4
284
284
  pluralize_table(to_snake_case(name))
285
285
  end
286
286
 
287
+ # The table name a generator uses, honouring `--table-name` and speaking up
288
+ # instead of renaming silently (issue #123). Mirrors `_resolve_table` in
289
+ # tina4-python/tina4_python/cli/__init__.py:98.
290
+ #
291
+ # `announce` prints the note/warning; it is TRUE only for `generate_model`
292
+ # (where the table is born). Composite generators (crud) let the model
293
+ # sub-call announce, and generators that target an EXISTING table
294
+ # (seeder/form/view) still honour `--table-name` but stay quiet so the note
295
+ # is not repeated. `build_model_resolution` calls it with announce:false too,
296
+ # so the envelope's table_name/migration_path equal what lands on disk.
297
+ #
298
+ # * `--table-name <name>` wins verbatim. If that name is ITSELF a reserved
299
+ # word, warn loudly: Tina4 interpolates table names UNQUOTED, so the ORM's
300
+ # generated SQL will fail on it and quoting it in raw SQL + migrations is
301
+ # now the developer's job (we do NOT silently quote — identifier quoting is
302
+ # a global storage invariant, not a local fix).
303
+ # * Otherwise fall back to `to_table_name`. When that auto-pluralises a
304
+ # reserved-word class name (Order -> orders), print a one-line note naming
305
+ # the rename and the `--table-name` escape hatch, so the developer is
306
+ # informed rather than surprised.
307
+ def resolve_table(name, flags = {}, announce: false)
308
+ flags ||= {}
309
+ override = flags["table-name"]
310
+ # A real value only — a bare `--table-name` parses to `true` and an empty
311
+ # `--table-name ""` to "", both of which fall through to the pluralise path
312
+ # (parity with Python's `if override and not isinstance(override, bool)`).
313
+ if override.is_a?(String) && !override.empty?
314
+ if announce && SQL_RESERVED_TABLE_NAMES.include?(to_snake_case(override))
315
+ puts " ! table_name '#{override}' is a SQL reserved word. Tina4 interpolates " \
316
+ "table names UNQUOTED, so the ORM's generated SQL will fail on it -- " \
317
+ "quote it yourself in raw SQL and migrations."
318
+ end
319
+ return override
320
+ end
321
+ bare = to_snake_case(name)
322
+ if SQL_RESERVED_TABLE_NAMES.include?(bare)
323
+ table = pluralize_table(bare)
324
+ if announce
325
+ puts " · '#{bare}' is a SQL reserved word; using table_name '#{table}' " \
326
+ "(Tina4 interpolates table names unquoted). Override with --table-name <name>."
327
+ end
328
+ return table
329
+ end
330
+ bare
331
+ end
332
+
287
333
  # Called without --fields, the generators fall back to a single `name`
288
334
  # string column. That default MUST be materialised here, in one place, and
289
335
  # then flow into the model, the migration, the form, the view and the spec
@@ -1616,21 +1662,19 @@ module Tina4
1616
1662
 
1617
1663
  def build_model_resolution(name, flags)
1618
1664
  raw = to_snake_case(name)
1665
+ # Honour --table-name (silent here; generate_model announces). The envelope
1666
+ # thus reports the SAME table_name/migration_path the generator writes.
1667
+ table = resolve_table(name, flags)
1619
1668
  transformations = []
1620
- table =
1621
- if SQL_RESERVED_TABLE_NAMES.include?(raw)
1622
- plural = pluralize_table(raw)
1623
- transformations << {
1624
- "kind" => "reserved_word_pluralize",
1625
- "from" => raw,
1626
- "to" => plural,
1627
- "reason" => "SQL reserved word '#{raw}' would break CREATE TABLE",
1628
- "override" => "--table #{raw} --quote (requires quoted-identifier mode, not yet implemented)"
1629
- }
1630
- plural
1631
- else
1632
- raw
1633
- end
1669
+ if SQL_RESERVED_TABLE_NAMES.include?(raw) && raw != table
1670
+ transformations << {
1671
+ "kind" => "reserved_word_pluralize",
1672
+ "from" => raw,
1673
+ "to" => table,
1674
+ "reason" => "SQL reserved word '#{raw}' would break CREATE TABLE",
1675
+ "override" => "--table-name <name> (table names interpolate unquoted; forcing a reserved name is yours to quote in raw SQL)"
1676
+ }
1677
+ end
1634
1678
  # The migration filename embeds a timestamp; predict it deterministically
1635
1679
  # so a `--dry-run` and the real run agree on the same second. Two
1636
1680
  # generations within the same second collide anyway (existing behaviour).
@@ -1797,8 +1841,9 @@ module Tina4
1797
1841
  pluralized = resolution["transformations"].find { |t| t["kind"] == "reserved_word_pluralize" }
1798
1842
  if pluralized
1799
1843
  lines << ""
1800
- lines << " To keep the raw name '#{pluralized['from']}' as the table:"
1801
- lines << " tina4ruby generate #{target} #{name} --table #{pluralized['from']} --quote (opt-in, ADR-0062 forthcoming)"
1844
+ lines << " To set the table name yourself:"
1845
+ lines << " tina4ruby generate #{target} #{name} --table-name <name>"
1846
+ lines << " Tina4 interpolates table names unquoted; if you force the reserved '#{pluralized['from']}', you own the quoting in raw SQL."
1802
1847
  end
1803
1848
  # ADR-0063 v1.1: surface `edit_hints[]` under "Edit these lines:" and
1804
1849
  # `next[]` under "Next:" — both additive; missing / empty arrays elide
@@ -1847,7 +1892,9 @@ module Tina4
1847
1892
 
1848
1893
  def generate_model(name, flags, emit_test: true)
1849
1894
  fields = fields_or_default(flags["fields"])
1850
- table = to_table_name(name)
1895
+ # announce: this is where the table is born, so a reserved-word pluralise
1896
+ # (Order -> orders) or a forced reserved --table-name speaks up (#123).
1897
+ table = resolve_table(name, flags, announce: true)
1851
1898
  snake = to_snake_case(name)
1852
1899
 
1853
1900
  # Build field lines
@@ -2093,7 +2140,8 @@ module Tina4
2093
2140
  # ── Generator: crud ──────────────────────────────────────────────────
2094
2141
 
2095
2142
  def generate_crud(name, flags)
2096
- table = to_table_name(name)
2143
+ # Quiet here — the generate_model sub-call below announces once (#123).
2144
+ table = resolve_table(name, flags)
2097
2145
  # Always derive the plural route from the CLASS NAME, not by appending
2098
2146
  # "s" to the table — otherwise a reserved-word table (already plural,
2099
2147
  # Order -> orders) becomes orderss, and a `y`-ending class (Category)
@@ -2422,7 +2470,8 @@ module Tina4
2422
2470
 
2423
2471
  def generate_form(name, flags = {})
2424
2472
  fields = fields_or_default(flags["fields"])
2425
- table = to_table_name(name)
2473
+ # Targets an existing table honour --table-name but stay quiet (#123).
2474
+ table = resolve_table(name, flags)
2426
2475
  route_name = to_route_name(name)
2427
2476
 
2428
2477
  # Input type mapping
@@ -2505,7 +2554,8 @@ module Tina4
2505
2554
 
2506
2555
  def generate_view(name, flags = {})
2507
2556
  fields = fields_or_default(flags["fields"])
2508
- table = to_table_name(name)
2557
+ # Targets an existing table honour --table-name but stay quiet (#123).
2558
+ table = resolve_table(name, flags)
2509
2559
  route_name = to_route_name(name)
2510
2560
 
2511
2561
  cols = fields.map { |f, _| f }
@@ -2938,7 +2988,8 @@ module Tina4
2938
2988
  #
2939
2989
  # tina4ruby generate seeder Product
2940
2990
  def generate_seeder(name, flags = {})
2941
- table = to_table_name(name)
2991
+ # Targets an existing table honour --table-name but stay quiet (#123).
2992
+ table = resolve_table(name, flags)
2942
2993
  model_snake = to_snake_case(name)
2943
2994
  dir = "seeds"
2944
2995
  FileUtils.mkdir_p(dir)
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.13.128"
4
+ VERSION = "3.13.129"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.128
4
+ version: 3.13.129
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-31 00:00:00.000000000 Z
11
+ date: 2026-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack