zui 0.0.9 → 0.0.10
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/README.md +6 -1
- data/lib/zui/cli.rb +218 -35
- data/lib/zui.rb +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: 708ca03d2896630151177ee0b6fe2d38a5a6e8da0ec03899a89342a881f431da
|
|
4
|
+
data.tar.gz: c2342386d280806246ce4e2dc6ef296b3e65474ff352bbca8e5085313c534886
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8529e5aa1ea6f062b56dec92e568895781f14ad8c5e0f7e22032d763f9f4c3f086c272203843de62bb613b8aedc5b28ac4b32bd9ceffbe4f3ec98e611e462375
|
|
7
|
+
data.tar.gz: e8e6047c3ec7423a2b49a0cb70a83acdd5e8315d974ebe7203e3e92492a864f0d13717a504e2bed599a036dcb902bdc0fdeac490a445c098c4e4d7a8f9cf1bed
|
data/README.md
CHANGED
|
@@ -188,7 +188,7 @@ uses a system Qt installation, or downloads an asset for a different platform. S
|
|
|
188
188
|
|
|
189
189
|
## Component catalog
|
|
190
190
|
|
|
191
|
-
Zui 0.0.
|
|
191
|
+
Zui 0.0.10 registers **241 built-in components**. Every entry has a named Ruby builder method,
|
|
192
192
|
property and event schema, native QML renderer, reactive patch support, and contract tests.
|
|
193
193
|
|
|
194
194
|
| Category | Count | Representative components |
|
|
@@ -217,6 +217,8 @@ an explicit error.
|
|
|
217
217
|
|
|
218
218
|
| Command | Purpose |
|
|
219
219
|
| --- | --- |
|
|
220
|
+
| `zui --help` | List every command and global option |
|
|
221
|
+
| `zui help COMMAND` | Show detailed usage, options, and examples for one command |
|
|
220
222
|
| `zui new NAME` | Generate a pure-Ruby application, `Gemfile`, distribution config, and reusable UI module |
|
|
221
223
|
| `zui doctor` | Report Ruby, platform, native-client, run, and bundle readiness without changing anything |
|
|
222
224
|
| `zui doctor --fix` | Download, verify, and install the missing native client and lite mruby runtime |
|
|
@@ -229,6 +231,9 @@ an explicit error.
|
|
|
229
231
|
| `zui bundle --dist [DIRECTORY]` | Build release installers from the required project-root `config.rb` |
|
|
230
232
|
| `zui version` | Print the installed framework version |
|
|
231
233
|
|
|
234
|
+
Every command also supports `-h` and `--help` directly, such as `zui bundle --help`.
|
|
235
|
+
Usage errors point to the relevant command help without starting downloads, builds, or applications.
|
|
236
|
+
|
|
232
237
|
Zui has no separate validation command. Ruby, DSL, schema, resource, protocol, and renderer errors
|
|
233
238
|
are reported by the operation that encounters them.
|
|
234
239
|
|
data/lib/zui/cli.rb
CHANGED
|
@@ -1,11 +1,127 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "optparse"
|
|
4
5
|
require "rbconfig"
|
|
5
6
|
|
|
6
7
|
module Zui
|
|
7
8
|
class CLI
|
|
8
|
-
|
|
9
|
+
class UsageError < ArgumentError; end
|
|
10
|
+
|
|
11
|
+
COMMANDS = {
|
|
12
|
+
"new" => "Create a new Zui application",
|
|
13
|
+
"configure" => "Install the native client and lite runtime",
|
|
14
|
+
"doctor" => "Check or repair the local Zui installation",
|
|
15
|
+
"run" => "Run a Ruby application with the native client",
|
|
16
|
+
"bundle" => "Build a standalone app or release installer",
|
|
17
|
+
"version" => "Print the installed Zui version"
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
GENERAL_HELP = <<~HELP.freeze
|
|
21
|
+
Zui #{VERSION} — native desktop applications in Ruby
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
zui COMMAND [arguments] [options]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
new NAME #{COMMANDS.fetch("new")}
|
|
28
|
+
configure #{COMMANDS.fetch("configure")}
|
|
29
|
+
doctor #{COMMANDS.fetch("doctor")}
|
|
30
|
+
run FILE #{COMMANDS.fetch("run")}
|
|
31
|
+
bundle [DIR] #{COMMANDS.fetch("bundle")}
|
|
32
|
+
version #{COMMANDS.fetch("version")}
|
|
33
|
+
|
|
34
|
+
Global options:
|
|
35
|
+
-h, --help Show this help
|
|
36
|
+
-v, --version Print the installed Zui version
|
|
37
|
+
|
|
38
|
+
Run `zui help COMMAND` or `zui COMMAND --help` for command details.
|
|
39
|
+
HELP
|
|
40
|
+
|
|
41
|
+
COMMAND_HELP = {
|
|
42
|
+
"new" => <<~HELP,
|
|
43
|
+
Create a new Zui application.
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
zui new NAME
|
|
47
|
+
|
|
48
|
+
NAME becomes both the project directory and display name. Underscores,
|
|
49
|
+
hyphens, and spaces are normalized; `smart_home` becomes “Smart Home”.
|
|
50
|
+
The project includes Ruby sources, distribution config, and release icons.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
zui new smart_home
|
|
54
|
+
HELP
|
|
55
|
+
"configure" => <<~HELP,
|
|
56
|
+
Install the verified native client and lite mruby runtime.
|
|
57
|
+
|
|
58
|
+
Usage:
|
|
59
|
+
zui configure
|
|
60
|
+
|
|
61
|
+
Downloads the platform assets for this Zui version from GitHub Releases,
|
|
62
|
+
verifies their checksums and manifests, and installs them in the user cache.
|
|
63
|
+
|
|
64
|
+
Equivalent repair command:
|
|
65
|
+
zui doctor --fix
|
|
66
|
+
HELP
|
|
67
|
+
"doctor" => <<~HELP,
|
|
68
|
+
Check or repair the local Zui installation.
|
|
69
|
+
|
|
70
|
+
Usage:
|
|
71
|
+
zui doctor [options]
|
|
72
|
+
|
|
73
|
+
Options:
|
|
74
|
+
-f, --fix Download, verify, and install missing platform assets
|
|
75
|
+
|
|
76
|
+
Without --fix, doctor is read-only and exits nonzero when setup is incomplete.
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
zui doctor
|
|
80
|
+
zui doctor --fix
|
|
81
|
+
HELP
|
|
82
|
+
"run" => <<~HELP,
|
|
83
|
+
Run a Ruby application with the private native client.
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
zui run FILE
|
|
87
|
+
|
|
88
|
+
FILE is the Ruby entry point for the application.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
zui run main.rb
|
|
92
|
+
HELP
|
|
93
|
+
"bundle" => <<~HELP,
|
|
94
|
+
Build a standalone application or platform release installer.
|
|
95
|
+
|
|
96
|
+
Usage:
|
|
97
|
+
zui bundle [DIRECTORY] [options]
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
-n, --name NAME Override the app name for a non-distribution bundle
|
|
101
|
+
-o, --output PATH Set the bundle destination or distribution directory
|
|
102
|
+
--lite Embed the portable mruby runtime (default)
|
|
103
|
+
--full Embed private CRuby and the project's locked gems
|
|
104
|
+
--dist Build platform installers using config.rb
|
|
105
|
+
--no-tree-shake Keep the complete component and Qt feature catalog
|
|
106
|
+
|
|
107
|
+
DIRECTORY defaults to the current directory. --lite and --full are mutually
|
|
108
|
+
exclusive. --dist reads the app name and release metadata from config.rb.
|
|
109
|
+
|
|
110
|
+
Examples:
|
|
111
|
+
zui bundle
|
|
112
|
+
zui bundle --full .
|
|
113
|
+
zui bundle --name "Smart Home" --output dist/SmartHome.app
|
|
114
|
+
zui bundle --dist --full .
|
|
115
|
+
HELP
|
|
116
|
+
"version" => <<~HELP
|
|
117
|
+
Print the installed Zui version.
|
|
118
|
+
|
|
119
|
+
Usage:
|
|
120
|
+
zui version
|
|
121
|
+
zui --version
|
|
122
|
+
zui -v
|
|
123
|
+
HELP
|
|
124
|
+
}.freeze
|
|
9
125
|
|
|
10
126
|
def self.run(arguments, out: $stdout, err: $stderr)
|
|
11
127
|
new(out:, err:).run(arguments.dup)
|
|
@@ -18,19 +134,26 @@ module Zui
|
|
|
18
134
|
|
|
19
135
|
def run(arguments)
|
|
20
136
|
command = arguments.shift
|
|
137
|
+
@active_command = command
|
|
138
|
+
return show_general_help if command.nil? || %w[-h --help].include?(command)
|
|
139
|
+
return show_command_help(arguments) if command == "help"
|
|
140
|
+
return show_named_help(command) if COMMANDS.key?(command) && help_requested?(arguments)
|
|
141
|
+
|
|
21
142
|
case command
|
|
22
143
|
when "new" then new_project(arguments)
|
|
23
144
|
when "configure" then configure(arguments)
|
|
24
145
|
when "run" then run_file(arguments)
|
|
25
146
|
when "bundle" then bundle_project(arguments)
|
|
26
147
|
when "doctor" then doctor(arguments)
|
|
27
|
-
when "version", "--version", "-v" then
|
|
28
|
-
else
|
|
29
|
-
@err.puts(USAGE)
|
|
30
|
-
command.nil? ? 0 : 64
|
|
148
|
+
when "version", "--version", "-v" then print_version(arguments)
|
|
149
|
+
else unknown_command(command)
|
|
31
150
|
end
|
|
32
151
|
rescue Interrupt
|
|
33
152
|
130
|
|
153
|
+
rescue OptionParser::ParseError, UsageError => error
|
|
154
|
+
@err.puts("zui: #{error.message}")
|
|
155
|
+
@err.puts(help_hint)
|
|
156
|
+
1
|
|
34
157
|
rescue ArgumentError, SystemCallError, JSON::ParserError => error
|
|
35
158
|
@err.puts("zui: #{error.message}")
|
|
36
159
|
1
|
|
@@ -39,8 +162,10 @@ module Zui
|
|
|
39
162
|
private
|
|
40
163
|
|
|
41
164
|
def new_project(arguments)
|
|
42
|
-
|
|
43
|
-
raise
|
|
165
|
+
parse_no_options!(arguments)
|
|
166
|
+
name = arguments.shift || raise(UsageError, "new requires a project name")
|
|
167
|
+
raise UsageError, "new accepts only one project name" unless arguments.empty?
|
|
168
|
+
|
|
44
169
|
destination = File.expand_path(slug(name))
|
|
45
170
|
Generator.new(path: destination, name:).create
|
|
46
171
|
@out.puts("Created Zui application in #{destination}")
|
|
@@ -48,35 +173,46 @@ module Zui
|
|
|
48
173
|
end
|
|
49
174
|
|
|
50
175
|
def run_file(arguments)
|
|
51
|
-
|
|
52
|
-
raise
|
|
176
|
+
parse_no_options!(arguments)
|
|
177
|
+
file = File.expand_path(arguments.shift || raise(UsageError, "run requires a Ruby file"))
|
|
178
|
+
raise UsageError, "run accepts only one Ruby file" unless arguments.empty?
|
|
179
|
+
|
|
53
180
|
Runner.new.run(file)
|
|
54
181
|
end
|
|
55
182
|
|
|
56
183
|
def bundle_project(arguments)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
184
|
+
options = { tree_shake: true }
|
|
185
|
+
parser = OptionParser.new do |option|
|
|
186
|
+
option.on("-n NAME", "--name NAME") { |value| options[:name] = value }
|
|
187
|
+
option.on("-o PATH", "--output PATH") { |value| options[:destination] = value }
|
|
188
|
+
option.on("--lite") { options[:lite] = true }
|
|
189
|
+
option.on("--full") { options[:full] = true }
|
|
190
|
+
option.on("--dist") { options[:create_installers] = true }
|
|
191
|
+
option.on("--no-tree-shake") { options[:tree_shake] = false }
|
|
192
|
+
end
|
|
193
|
+
parser.parse!(arguments)
|
|
194
|
+
if options[:lite] && options[:full]
|
|
195
|
+
raise UsageError, "bundle accepts only one of --lite or --full"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
runtime_mode = options[:full] ? :full : :lite
|
|
65
199
|
source = File.expand_path(arguments.shift || Dir.pwd)
|
|
66
|
-
raise
|
|
200
|
+
raise UsageError, "bundle accepts only one directory" unless arguments.empty?
|
|
67
201
|
|
|
68
|
-
if create_installers
|
|
69
|
-
|
|
202
|
+
if options[:create_installers]
|
|
203
|
+
if options[:name]
|
|
204
|
+
raise UsageError, "--name cannot be used with --dist; set name in config.rb"
|
|
205
|
+
end
|
|
70
206
|
|
|
71
|
-
packager = DistPackager.new(tree_shake
|
|
72
|
-
paths = packager.package(source, output: destination)
|
|
207
|
+
packager = DistPackager.new(tree_shake: options[:tree_shake], runtime_mode:)
|
|
208
|
+
paths = packager.package(source, output: options[:destination])
|
|
73
209
|
paths.each { |path| @out.puts("Created distribution artifact #{path}") }
|
|
74
210
|
report_tree_shaking(packager.tree_shake_report)
|
|
75
211
|
return 0
|
|
76
212
|
end
|
|
77
213
|
|
|
78
|
-
distribution = Distribution.new(tree_shake
|
|
79
|
-
path = distribution.bundle(source, name
|
|
214
|
+
distribution = Distribution.new(tree_shake: options[:tree_shake], runtime_mode:)
|
|
215
|
+
path = distribution.bundle(source, name: options[:name], destination: options[:destination])
|
|
80
216
|
@out.puts("Bundled #{Platform.current.os} application in #{path}")
|
|
81
217
|
report_tree_shaking(distribution.tree_shake_report)
|
|
82
218
|
0
|
|
@@ -89,8 +225,10 @@ module Zui
|
|
|
89
225
|
end
|
|
90
226
|
|
|
91
227
|
def doctor(arguments)
|
|
92
|
-
fix =
|
|
93
|
-
|
|
228
|
+
fix = false
|
|
229
|
+
OptionParser.new { |option| option.on("-f", "--fix") { fix = true } }.parse!(arguments)
|
|
230
|
+
raise UsageError, "doctor accepts no positional arguments" unless arguments.empty?
|
|
231
|
+
|
|
94
232
|
platform = Platform.current
|
|
95
233
|
@out.puts("Zui #{VERSION}")
|
|
96
234
|
@out.puts("Platform: #{platform.id}#{platform.supported? ? '' : ' (unsupported)'}")
|
|
@@ -124,7 +262,9 @@ module Zui
|
|
|
124
262
|
end
|
|
125
263
|
|
|
126
264
|
def configure(arguments)
|
|
127
|
-
|
|
265
|
+
parse_no_options!(arguments)
|
|
266
|
+
raise UsageError, "configure accepts no arguments" unless arguments.empty?
|
|
267
|
+
|
|
128
268
|
platform = Platform.current.assert_supported!
|
|
129
269
|
client = Client.new(platform:)
|
|
130
270
|
lite_runtime = LiteRuntime.new(platform:)
|
|
@@ -143,17 +283,60 @@ module Zui
|
|
|
143
283
|
@out.puts("Bundle --full: ready (uses this Ruby and the project's locked gems)")
|
|
144
284
|
end
|
|
145
285
|
|
|
146
|
-
def
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
286
|
+
def show_general_help
|
|
287
|
+
@out.puts(GENERAL_HELP)
|
|
288
|
+
0
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def show_command_help(arguments)
|
|
292
|
+
return show_general_help if arguments.empty? || arguments == ["-h"] || arguments == ["--help"]
|
|
293
|
+
raise UsageError, "help accepts only one command" unless arguments.length == 1
|
|
294
|
+
|
|
295
|
+
show_named_help(arguments.first)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def show_named_help(command)
|
|
299
|
+
help = COMMAND_HELP[command]
|
|
300
|
+
return unknown_command(command) unless help
|
|
301
|
+
|
|
302
|
+
@out.puts(help)
|
|
303
|
+
0
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def help_requested?(arguments)
|
|
307
|
+
arguments.any? { |argument| %w[-h --help].include?(argument) }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def print_version(arguments)
|
|
311
|
+
parse_no_options!(arguments)
|
|
312
|
+
raise UsageError, "version accepts no arguments" unless arguments.empty?
|
|
313
|
+
|
|
314
|
+
@out.puts(VERSION)
|
|
315
|
+
0
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def unknown_command(command)
|
|
319
|
+
@err.puts("zui: unknown command #{command.inspect}")
|
|
320
|
+
@err.puts("Run `zui --help` to see available commands.")
|
|
321
|
+
64
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def help_hint
|
|
325
|
+
if COMMANDS.key?(@active_command)
|
|
326
|
+
"Run `zui help #{@active_command}` for usage."
|
|
327
|
+
else
|
|
328
|
+
"Run `zui --help` to see available commands."
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def parse_no_options!(arguments)
|
|
333
|
+
OptionParser.new.parse!(arguments)
|
|
152
334
|
end
|
|
153
335
|
|
|
154
336
|
def slug(value)
|
|
155
|
-
result = value.to_s.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A
|
|
156
|
-
raise
|
|
337
|
+
result = value.to_s.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-|\z/, "")
|
|
338
|
+
raise UsageError, "name must contain letters or numbers" if result.empty?
|
|
339
|
+
|
|
157
340
|
result
|
|
158
341
|
end
|
|
159
342
|
|
data/lib/zui.rb
CHANGED