rubyx-py 0.2.0-aarch64-linux → 0.2.1-aarch64-linux
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 +61 -6
- data/lib/rubyx/3.1/rubyx.so +0 -0
- data/lib/rubyx/3.2/rubyx.so +0 -0
- data/lib/rubyx/3.3/rubyx.so +0 -0
- data/lib/rubyx/3.4/rubyx.so +0 -0
- data/lib/rubyx/railtie.rb +2 -1
- data/lib/rubyx/tasks/rubyx.rake +127 -0
- data/lib/rubyx/version.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25cb549b764a4c233144af01c9fe0fc86709ba1c9c6bbc8ac01a4f60f030ffe6
|
|
4
|
+
data.tar.gz: 812f62a87103e7c52e2503054942645aaa6e9e5f5c0ddf63d20a484c6f9da1b2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea4882957a0522567d2dbdfe7c9a64b0d7bfa23522928d7bb39d22c763b5d936d348b1dfa762e4197bd67174aa3d2e4a26928f0586c93bc267d7d56ca02a7563
|
|
7
|
+
data.tar.gz: 34b00a5cdcf9347ec8a812ac30ad7e6142ff435768e66d582c0e6125632a637ae136b813f1ffba4af3b3c19779674968e088f5014bfa9383a8c76a9c9be437bc
|
data/README.md
CHANGED
|
@@ -6,14 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
**Call Python from Ruby. No microservices, no REST APIs, no serialization overhead.**
|
|
8
8
|
|
|
9
|
-
Powered by Rust for safety and performance. Built for Rails.
|
|
9
|
+
Powered by Rust for safety and performance. Built for Rails. Inspired by [Pythonx](https://github.com/livebook-dev/pythonx)
|
|
10
10
|
|
|
11
11
|
[](https://badge.fury.io/rb/rubyx-py)
|
|
12
12
|
[](https://github.com/yinho999/rubyx/actions/workflows/ci.yml)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
14
|
[](https://www.ruby-lang.org)
|
|
15
15
|
[](https://www.rust-lang.org)
|
|
16
|
-
|
|
16
|
+
> *"Rubyx showed that the proxy-object pattern works beautifully for cross-language bridges in Rust, and its magnus + rb-sys architecture is exactly what [Boax](https://intertwingly.net/blog/2026/03/25/Calling-JavaScript-from-Ruby.html) uses."*
|
|
17
|
+
>
|
|
18
|
+
> — [Sam Ruby](https://en.wikipedia.org/wiki/Sam_Ruby), author of *Agile Web Development with Rails*
|
|
17
19
|
</div>
|
|
18
20
|
|
|
19
21
|
---
|
|
@@ -93,7 +95,7 @@ dependencies = []
|
|
|
93
95
|
|
|
94
96
|
```python
|
|
95
97
|
# app/python/example.py
|
|
96
|
-
def hello(name
|
|
98
|
+
def hello(name):
|
|
97
99
|
return f"Hello, {name}! From Python."
|
|
98
100
|
```
|
|
99
101
|
|
|
@@ -102,7 +104,7 @@ def hello(name="World"):
|
|
|
102
104
|
class GreetingsController < ApplicationController
|
|
103
105
|
def index
|
|
104
106
|
example = Rubyx.import('example')
|
|
105
|
-
render json: { message: example.hello(params[:name]).to_ruby }
|
|
107
|
+
render json: { message: example.hello(params[:name] || 'World').to_ruby }
|
|
106
108
|
end
|
|
107
109
|
end
|
|
108
110
|
```
|
|
@@ -159,7 +161,7 @@ class TasksController < ApplicationController
|
|
|
159
161
|
tasks = Rubyx.import('tasks')
|
|
160
162
|
|
|
161
163
|
# Non-blocking — returns a Future immediately
|
|
162
|
-
future = Rubyx.async_await(tasks.delayed_greet(params[:name], seconds: 2))
|
|
164
|
+
future = Rubyx.async_await(tasks.delayed_greet(params[:name] || 'World', seconds: 2))
|
|
163
165
|
do_other_work()
|
|
164
166
|
render json: { message: future.await.to_ruby }
|
|
165
167
|
end
|
|
@@ -331,7 +333,29 @@ Rubyx.eval("f'Hello, {name}!'", name: "World").to_ruby # => "Hello, World!"
|
|
|
331
333
|
Rubyx.eval("max(items)", items: [3, 1, 4, 1, 5]).to_ruby # => 5
|
|
332
334
|
```
|
|
333
335
|
|
|
334
|
-
Supports: Integer, Float, String, Symbol, Bool, nil, Array, Hash, and RubyxObject.
|
|
336
|
+
Supports: Integer, Float, String, Symbol, Bool, nil, Array, Hash, binary String (ASCII-8BIT), and RubyxObject.
|
|
337
|
+
|
|
338
|
+
## Bytes / Binary Data
|
|
339
|
+
|
|
340
|
+
Python `bytes` and `bytearray` convert to Ruby `String` with `ASCII-8BIT` encoding. Ruby binary strings (`.b`) convert to Python `bytes`:
|
|
341
|
+
|
|
342
|
+
```ruby
|
|
343
|
+
# Python bytes → Ruby
|
|
344
|
+
Rubyx.eval("b'hello'").to_ruby # => "hello" (ASCII-8BIT)
|
|
345
|
+
Rubyx.eval("bytearray(b'hello')").to_ruby # => "hello" (ASCII-8BIT)
|
|
346
|
+
|
|
347
|
+
# Ruby → Python
|
|
348
|
+
ctx = Rubyx.context
|
|
349
|
+
ctx.eval("type(data).__name__", data: "hello".b) # => "bytes"
|
|
350
|
+
ctx.eval("type(data).__name__", data: "hello") # => "str"
|
|
351
|
+
|
|
352
|
+
# Roundtrip binary data
|
|
353
|
+
ctx.eval("data", data: "\xff\x00\xfe".b).to_ruby # => "\xFF\x00\xFE" (ASCII-8BIT)
|
|
354
|
+
|
|
355
|
+
# Works with Python stdlib
|
|
356
|
+
ctx.eval("import base64")
|
|
357
|
+
ctx.eval("base64.b64encode(raw)", raw: "Hello".b).to_ruby # => "SGVsbG8=" (ASCII-8BIT)
|
|
358
|
+
```
|
|
335
359
|
|
|
336
360
|
## Python Objects
|
|
337
361
|
|
|
@@ -470,6 +494,37 @@ svc.Analyzer([1, 2, 3]).summary.to_ruby # => {"count" => 3, "sum" => 6}
|
|
|
470
494
|
| `.callable?` | Check if callable |
|
|
471
495
|
| `.py_type` | Python type name |
|
|
472
496
|
|
|
497
|
+
## Type Conversion
|
|
498
|
+
|
|
499
|
+
| Python | Ruby | Notes |
|
|
500
|
+
|-----------------------|------------------------------|------------------------|
|
|
501
|
+
| `int` | `Integer` | |
|
|
502
|
+
| `float` | `Float` | |
|
|
503
|
+
| `str` | `String` (UTF-8) | |
|
|
504
|
+
| `bytes` | `String` (ASCII-8BIT) | binary data |
|
|
505
|
+
| `bytearray` | `String` (ASCII-8BIT) | binary data |
|
|
506
|
+
| `bool` | `true` / `false` | |
|
|
507
|
+
| `None` | `nil` | |
|
|
508
|
+
| `list` / `tuple` | `Array` | |
|
|
509
|
+
| `dict` | `Hash` | |
|
|
510
|
+
| `set` / `frozenset` | `Array` | |
|
|
511
|
+
| everything else | `RubyxObject` | proxy to Python object |
|
|
512
|
+
|
|
513
|
+
**Ruby → Python** (via globals/kwargs):
|
|
514
|
+
|
|
515
|
+
| Ruby | Python |
|
|
516
|
+
|--------------------------------|-------------|
|
|
517
|
+
| `Integer` | `int` |
|
|
518
|
+
| `Float` | `float` |
|
|
519
|
+
| `String` (UTF-8) | `str` |
|
|
520
|
+
| `String` (ASCII-8BIT / `.b`) | `bytes` |
|
|
521
|
+
| `true` / `false` | `bool` |
|
|
522
|
+
| `nil` | `None` |
|
|
523
|
+
| `Array` | `list` |
|
|
524
|
+
| `Hash` | `dict` |
|
|
525
|
+
| `Symbol` | `str` |
|
|
526
|
+
| `RubyxObject` | original |
|
|
527
|
+
|
|
473
528
|
## Requirements
|
|
474
529
|
|
|
475
530
|
- Ruby >= 3.0
|
data/lib/rubyx/3.1/rubyx.so
CHANGED
|
Binary file
|
data/lib/rubyx/3.2/rubyx.so
CHANGED
|
Binary file
|
data/lib/rubyx/3.3/rubyx.so
CHANGED
|
Binary file
|
data/lib/rubyx/3.4/rubyx.so
CHANGED
|
Binary file
|
data/lib/rubyx/railtie.rb
CHANGED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
namespace :rubyx do
|
|
2
|
+
desc 'Initialize Python environment (downloads uv and Python if needed)'
|
|
3
|
+
task init: :environment do
|
|
4
|
+
Rubyx::Rails.init!
|
|
5
|
+
puts '[Rubyx] Python environment initialized successfully.'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
desc 'Check Python environment health'
|
|
9
|
+
task check: :environment do
|
|
10
|
+
puts 'Checking Python environment...'
|
|
11
|
+
puts
|
|
12
|
+
|
|
13
|
+
# Check uv
|
|
14
|
+
system_uv = `which uv 2>/dev/null`.strip
|
|
15
|
+
uv_available = !system_uv.empty? && File.exist?(system_uv)
|
|
16
|
+
puts "uv available: #{uv_available ? "Yes (#{system_uv})" : 'No (will auto-download)'}"
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
Rubyx::Rails.ensure_initialized!
|
|
20
|
+
puts 'Python initialized: Yes'
|
|
21
|
+
rescue => e
|
|
22
|
+
puts "Python initialized: No (#{e.message})"
|
|
23
|
+
puts
|
|
24
|
+
puts 'Run `rake rubyx:init` to initialize.'
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
Rubyx.eval('1 + 1')
|
|
30
|
+
puts 'Basic eval: OK'
|
|
31
|
+
rescue => e
|
|
32
|
+
puts "Basic eval: FAILED (#{e.message})"
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
gen = Rubyx.eval("import sys\niter([sys.version.split()[0]])")
|
|
38
|
+
version = Rubyx.stream(gen).first
|
|
39
|
+
puts "Import sys: OK (Python #{version})"
|
|
40
|
+
rescue => e
|
|
41
|
+
puts "Import sys: FAILED (#{e.message})"
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
puts
|
|
46
|
+
puts 'All checks passed!'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
desc 'Show Rubyx configuration and status'
|
|
50
|
+
task status: :environment do
|
|
51
|
+
config = Rubyx::Rails.configuration
|
|
52
|
+
|
|
53
|
+
puts 'Rubyx Status'
|
|
54
|
+
puts '=' * 40
|
|
55
|
+
|
|
56
|
+
puts "Initialized: #{Rubyx::Rails.initialized?}"
|
|
57
|
+
puts
|
|
58
|
+
|
|
59
|
+
puts 'Configuration:'
|
|
60
|
+
puts " pyproject_path: #{config.pyproject_path || '(not set)'}"
|
|
61
|
+
puts " pyproject_content: #{config.pyproject_content ? '(inline, %d bytes)' % config.pyproject_content.length : '(not set)'}"
|
|
62
|
+
puts " auto_init: #{config.auto_init}"
|
|
63
|
+
puts " force_reinit: #{config.force_reinit}"
|
|
64
|
+
puts " uv_version: #{config.uv_version}"
|
|
65
|
+
puts " debug: #{config.debug}"
|
|
66
|
+
puts " python_paths: #{config.python_paths.inspect}"
|
|
67
|
+
puts " uv_path: #{config.uv_path || '(auto-download)'}"
|
|
68
|
+
puts " uv_args: #{config.uv_args.inspect}"
|
|
69
|
+
puts
|
|
70
|
+
|
|
71
|
+
if config.pyproject_path
|
|
72
|
+
exists = File.exist?(config.pyproject_path.to_s)
|
|
73
|
+
puts "pyproject.toml exists: #{exists}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if config.pyproject_path
|
|
77
|
+
venv_dir = File.join(File.dirname(config.pyproject_path.to_s), '.venv')
|
|
78
|
+
puts ".venv exists: #{Dir.exist?(venv_dir)}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
system_uv = `which uv 2>/dev/null`.strip
|
|
82
|
+
puts "System uv: #{!system_uv.empty? ? system_uv : '(not found)'}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc 'List installed Python packages'
|
|
86
|
+
task packages: :environment do
|
|
87
|
+
Rubyx::Rails.ensure_initialized!
|
|
88
|
+
|
|
89
|
+
gen = Rubyx.eval(<<~PY)
|
|
90
|
+
import pkg_resources
|
|
91
|
+
packages = sorted([f"{d.project_name}=={d.version}" for d in pkg_resources.working_set])
|
|
92
|
+
iter(packages)
|
|
93
|
+
PY
|
|
94
|
+
|
|
95
|
+
puts 'Installed Python packages:'
|
|
96
|
+
Rubyx.stream(gen).each { |pkg| puts " #{pkg}" }
|
|
97
|
+
rescue => e
|
|
98
|
+
begin
|
|
99
|
+
gen = Rubyx.eval(<<~PY)
|
|
100
|
+
from importlib.metadata import distributions
|
|
101
|
+
packages = sorted([f"{d.metadata['Name']}=={d.metadata['Version']}" for d in distributions()])
|
|
102
|
+
iter(packages)
|
|
103
|
+
PY
|
|
104
|
+
|
|
105
|
+
puts 'Installed Python packages:'
|
|
106
|
+
Rubyx.stream(gen).each { |pkg| puts " #{pkg}" }
|
|
107
|
+
rescue => e2
|
|
108
|
+
puts "Could not list packages: #{e2.message}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
desc 'Clear the Rubyx cache (re-download uv + Python on next init)'
|
|
113
|
+
task clear_cache: :environment do
|
|
114
|
+
cache_dir = File.join(
|
|
115
|
+
ENV.fetch('XDG_CACHE_HOME', File.join(Dir.home, '.cache')),
|
|
116
|
+
'rubyx'
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if Dir.exist?(cache_dir)
|
|
120
|
+
require 'fileutils'
|
|
121
|
+
FileUtils.rm_rf(cache_dir)
|
|
122
|
+
puts "[Rubyx] Cache cleared: #{cache_dir}"
|
|
123
|
+
else
|
|
124
|
+
puts '[Rubyx] No cache directory found.'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
data/lib/rubyx/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyx-py
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Naiker
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake-compiler
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/rubyx/error.rb
|
|
64
64
|
- lib/rubyx/rails.rb
|
|
65
65
|
- lib/rubyx/railtie.rb
|
|
66
|
+
- lib/rubyx/tasks/rubyx.rake
|
|
66
67
|
- lib/rubyx/uv.rb
|
|
67
68
|
- lib/rubyx/version.rb
|
|
68
69
|
homepage: https://github.com/yinho999/rubyx
|