zui 0.0.6 → 0.0.8

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.
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "json"
5
+
6
+ module Zui
7
+ class LiteRuntime < Client
8
+ FORMAT = 1
9
+ MRUBY_VERSION = "4.0.0"
10
+ MRUBY_REVISION = "831da26b9021de0369d17b71b5667e2941a1a32d"
11
+ MRUBY_JSON_REVISION = "f99d9428025469f2400f93c53b185f65f963e507"
12
+
13
+ def root
14
+ override = @environment["ZUI_LITE_RUNTIME_ROOT"]
15
+ return File.expand_path(override) if override && !override.empty?
16
+
17
+ File.join(cache_root, "zui", "runtimes", version, platform.id, "lite")
18
+ end
19
+
20
+ def archive_name = "zui-runtime-lite-#{platform.id}.tar.gz"
21
+
22
+ def configure!
23
+ return root if configured?
24
+ if client_root_override?
25
+ raise ArgumentError, "ZUI_LITE_RUNTIME_ROOT is not a valid configured lite runtime: #{root}"
26
+ end
27
+
28
+ super
29
+ end
30
+
31
+ def archive_url
32
+ override = @environment["ZUI_LITE_RUNTIME_ARCHIVE"]
33
+ return File.expand_path(override) if override && !override.empty?
34
+
35
+ URI.join("#{release_base_url}/", archive_name)
36
+ end
37
+
38
+ def checksum_url
39
+ override = @environment["ZUI_LITE_RUNTIME_CHECKSUM"]
40
+ return File.expand_path(override) if override && !override.empty?
41
+
42
+ source = archive_url
43
+ source.is_a?(URI) ? URI("#{source}.sha256") : "#{source}.sha256"
44
+ end
45
+
46
+ def install(project:, destination:)
47
+ unless configured?
48
+ raise ArgumentError,
49
+ "Zui lite runtime is not configured for #{platform.id}; run `zui doctor --fix` before bundling"
50
+ end
51
+
52
+ copy_to(destination)
53
+ File.write(File.join(destination, "app.rb"), LiteSource.new(project:).call)
54
+ ApplicationRuntime.new(
55
+ engine: "mruby", version: manifest.fetch("engine_version"),
56
+ executable: manifest.fetch("executable"), program: "app.rb", load_path: ""
57
+ ).write(destination)
58
+ end
59
+
60
+ private
61
+
62
+ def validate!(directory)
63
+ manifest_path = File.join(directory, "lite-runtime.json")
64
+ raise ArgumentError, "Zui lite runtime manifest not found: #{manifest_path}" unless File.file?(manifest_path)
65
+ raise ArgumentError, "Zui lite runtime manifest is too large" if File.size(manifest_path) > 65_536
66
+
67
+ manifest = JSON.parse(File.read(manifest_path))
68
+ raise ArgumentError, "invalid Zui lite runtime manifest root" unless manifest.is_a?(Hash)
69
+ expected = {
70
+ "format" => FORMAT,
71
+ "framework" => "zui",
72
+ "zui_version" => version,
73
+ "platform" => platform.id,
74
+ "engine" => "mruby",
75
+ "engine_version" => MRUBY_VERSION,
76
+ "engine_revision" => MRUBY_REVISION,
77
+ "json_revision" => MRUBY_JSON_REVISION,
78
+ "payload" => ["mruby"]
79
+ }
80
+ expected.each do |key, value|
81
+ actual = manifest[key]
82
+ unless actual == value
83
+ raise ArgumentError,
84
+ "invalid Zui lite runtime #{key}: expected #{value.inspect}, got #{actual.inspect}"
85
+ end
86
+ end
87
+
88
+ required_paths = manifest["required_paths"]
89
+ unless required_paths.is_a?(Array) && !required_paths.empty? &&
90
+ required_paths.all? { |path| path.is_a?(String) }
91
+ raise ArgumentError, "invalid Zui lite runtime required paths"
92
+ end
93
+ required_paths.each do |path|
94
+ relative = safe_manifest_path!(path, "lite runtime required path")
95
+ resolved = File.join(directory, relative)
96
+ raise ArgumentError, "Zui lite runtime required path is missing: #{resolved}" unless File.exist?(resolved)
97
+ end
98
+
99
+ relative = safe_manifest_path!(manifest["executable"], "lite runtime executable")
100
+ executable = File.join(directory, relative)
101
+ unless File.file?(executable) && executable_for_target?(executable)
102
+ raise ArgumentError, "Zui lite runtime executable is missing or not executable: #{executable}"
103
+ end
104
+ manifest
105
+ rescue JSON::ParserError => error
106
+ raise ArgumentError, "invalid Zui lite runtime manifest: #{error.message}"
107
+ end
108
+
109
+ def release_base_url
110
+ @release_base_url || @environment["ZUI_LITE_RUNTIME_BASE_URL"] ||
111
+ "https://github.com/AdamMusa/zui/releases/download/v#{version}"
112
+ end
113
+
114
+ def client_root_override?
115
+ value = @environment["ZUI_LITE_RUNTIME_ROOT"]
116
+ value && !value.empty?
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zui
4
+ class LiteSource
5
+ RUNTIME_FILES = %w[
6
+ lite_support.rb protocol.rb value.rb state_store.rb node.rb animation.rb scheduler.rb
7
+ component_registry.rb components.rb builder.rb application.rb lite_entry.rb
8
+ ].freeze
9
+ REQUIRE = /^\s*require\s*(?:\(\s*)?["']([^"']+)["']/
10
+
11
+ def initialize(project:, framework_root: FRAMEWORK_ROOT)
12
+ @project = File.expand_path(project)
13
+ @framework_root = File.expand_path(framework_root)
14
+ end
15
+
16
+ def call
17
+ application = SourceBundle.new(
18
+ File.join(@project, "main.rb"), root: @project, embedded_frameworks: ["zui"]
19
+ ).call
20
+ external = application.scan(REQUIRE).flatten.uniq
21
+ unless external.empty?
22
+ raise ArgumentError,
23
+ "--lite does not support CRuby gem requires (#{external.join(', ')}); use --full"
24
+ end
25
+
26
+ runtime = RUNTIME_FILES.map do |name|
27
+ path = File.join(@framework_root, "lib", "zui", name)
28
+ raise ArgumentError, "lite runtime source is missing: #{path}" unless File.file?(path)
29
+
30
+ source = File.readlines(path).reject { |line| REQUIRE.match?(line) }.join
31
+ "# runtime: #{name}\n#{source}"
32
+ end
33
+ runtime << "module Zui\n VERSION = #{VERSION.dump}\nend"
34
+ runtime << application
35
+ "#{runtime.join("\n\n")}\n"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless Object.const_defined?(:Mutex)
4
+ class Mutex
5
+ def synchronize
6
+ yield
7
+ end
8
+ end
9
+ end
10
+
11
+ unless Object.const_defined?(:ConditionVariable)
12
+ class ConditionVariable
13
+ def wait(_mutex, _seconds = nil)
14
+ self
15
+ end
16
+
17
+ def broadcast
18
+ self
19
+ end
20
+ end
21
+ end
data/lib/zui/node.rb CHANGED
@@ -25,6 +25,27 @@ module Zui
25
25
  end
26
26
  end
27
27
 
28
- Binding = Struct.new(:node, :property, :reader, :last_value, :animation, keyword_init: true)
29
- StructuralBinding = Struct.new(:node, :renderer, :last_children, keyword_init: true)
28
+ class Binding
29
+ attr_accessor :last_value
30
+ attr_reader :node, :property, :reader, :animation
31
+
32
+ def initialize(node:, property:, reader:, last_value:, animation:)
33
+ @node = node
34
+ @property = property
35
+ @reader = reader
36
+ @last_value = last_value
37
+ @animation = animation
38
+ end
39
+ end
40
+
41
+ class StructuralBinding
42
+ attr_accessor :last_children
43
+ attr_reader :node, :renderer
44
+
45
+ def initialize(node:, renderer:, last_children:)
46
+ @node = node
47
+ @renderer = renderer
48
+ @last_children = last_children
49
+ end
50
+ end
30
51
  end