Skip to content

Commit

Permalink
feat: version selector + define_text_rewriter
Browse files Browse the repository at this point in the history
  • Loading branch information
palkan committed Jan 23, 2024
1 parent 59899dd commit f282abe
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 21 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"build": "npm-run-all --parallel build:*",
"watch:js": "node ./esbuild.serve.js",
"watch:css": "yarn build:css --watch",
"serve": "npm-run-all --parallel watch:*"
"dev": "npm-run-all --parallel watch:*"
},
"dependencies": {
"@bjorn3/browser_wasi_shim": "^0.2.18",
Expand Down
64 changes: 50 additions & 14 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ puts greet.call(hello: 'martian')

const DEFAULT_PREVIEW = `# Here you will see the transpiled source code.`;

const CONFIG = `# Here you can define custom source rewriters.`;
const CONFIG = `# Here you can define custom source rewriters.
# For example, you can add ":=" operator (if you miss C) as follows:
#
# RubyNext.define_text_rewriter "operator_assign" do
# def safe_rewrite(source)
# source.gsub(":=", "=")
# end
# end
`;

const OUTPUT = "// Here will be the output of your program";

Expand All @@ -32,6 +40,7 @@ export default class App {
this.monaco = monaco;

this.onSelectEditor = this.onSelectEditor.bind(this);
this.invalidatePreview = this.invalidatePreview.bind(this);
}

bootstrap() {
Expand Down Expand Up @@ -71,12 +80,7 @@ export default class App {

this.el
.querySelector('[target="transpile-btn"]')
.addEventListener("click", () => {
const result = this.transpile(this.codeEditor.getValue());

this.previewEditor.setValue(result);
this.showEditor("previewEditor");
});
.addEventListener("click", this.invalidatePreview);

this.el
.querySelector('[target="run-btn"]')
Expand All @@ -96,15 +100,39 @@ export default class App {

this.el.addEventListener("change", this.onSelectEditor);

this.setCurrentVersion();
this.versionSelect = document.getElementById("versionSelect");

if (theme === "dark") this.versionSelect.classList.add("sl-theme-dark");

this.versionSelect.addEventListener("sl-change", this.invalidatePreview);

this.setCurrentVMVersion();
}

transpile(code) {
const result = this.vm
.eval("RubyNext.transform(%q(" + code + "))")
.toString();
transpile(code, opts = {}) {
let rubyOptions = "{";

if (opts.version) {
rubyOptions += `version: "${opts.version}"`;
}

rubyOptions += "}";

return result;
try {
// eval configuration
// first, reset custom rewriters
this.vm.eval("RubyNext.custom_rewriters.clear");
this.vm.eval(this.configEditor.getValue());

const result = this.vm
.eval("RubyNext.transform(%q(" + code + "), **" + rubyOptions + ")")
.toString();

return result;
} catch (e) {
console.error(e);
return e.message;
}
}

execute(source) {
Expand All @@ -116,7 +144,7 @@ export default class App {
}
}

async setCurrentVersion() {
async setCurrentVMVersion() {
const versionContainer = document.getElementById("currentVersion");
if (!versionContainer) return;

Expand All @@ -137,6 +165,14 @@ export default class App {
});
}

invalidatePreview() {
const version = this.versionSelect.value;
const newSource = this.transpile(this.codeEditor.getValue(), { version });
this.previewEditor.setValue(newSource);

this.showEditor("previewEditor");
}

showEditor(editorName) {
const editor = this.el.querySelector(`#${editorName}`);
if (!editor) return;
Expand Down
31 changes: 26 additions & 5 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<title>Ruby Next Playground</title>
<link rel="stylesheet" type="text/css" href="/app.css">
<link rel="stylesheet" type="text/css" href="/index.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/themes/light.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/themes/dark.css" />
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/shoelace-autoloader.js"></script>
</head>
<body class="w-full min-h-full">
<main class="w-full h-full bg-slate-100 dark:bg-slate-900 text-slate-800 dark:text-slate-200">
Expand Down Expand Up @@ -43,16 +47,33 @@ <h2>Initializing Ruby Next playground...</h2>
</div>
<div id="app" class="hidden w-full h-screen flex flex-col">
<nav class="flex-shrink flex flex-row justify-between items-middle border-b-1 border-slate-300 shadow-md">
<div class="flex flex-row items-center justify-start">
<div class="flex flex-row items-center justify-start ml-2">
<img class="mx-2 p-1 h-12 w-auto" src="/assets/logo.png" alt="Ruby Next">
<h1 class="text-2xl">Playground</h1>
<span class="text-sm ml-4 h-4" id="currentVersion"></span>
</div>
<div class="flex flex-row space-x-2 self-center justify-center items-center px-2">
<button target="transpile-btn">Transpile</button>
<button target="run-btn">Run</button>
<div class="flex flex-row space-x-2 self-center justify-center items-center px-2 align-middle">
<button target="transpile-btn" class="bg-purple-500 hover:bg-purple-400 active:bg-purple-600 text-slate-50 dark:bg-purple-700 dark:hover:bg-purple-600 dark:active:bg-purple-800 dark:text-slate-100 py-2 px-4 font-semibold rounded inline-flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" data-slot="icon" class="w-6 h-6 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.894 20.567 16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z" />
</svg>
<span>Transpile</span>
</button>
<sl-select id="versionSelect" value="2.5.0" class="w-32">
<sl-option value="2.5.0">2.5.0</sl-option>
<sl-option value="2.7.0">2.7.0</sl-option>
<sl-option value="3.1.0">3.1.0</sl-option>
<sl-option value="3.2.0">3.2.0</sl-option>
<sl-option value="3.3.0">3.3.0</sl-option>
</sl-select>
<button target="run-btn" class="bg-green-500 hover:bg-green-400 active:bg-green-600 text-slate-50 dark:bg-green-700 dark:hover:bg-green-600 dark:active:bg-green-800 dark:text-slate-100 py-2 px-4 font-semibold rounded inline-flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z" />
</svg>
<span>Run</span>
</button>
</div>
<div class="flex flex-row space-x-2 justify-center items-center px-2">
<div class="flex flex-row space-x-2 justify-center items-center px-2 mr-4">
<a href="https://github.com/ruby-next/ruby-next" target="_blank" class="flex flex-row items-center space-x-1 hover:opacity-75 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20" stroke="none" class="w-6 h-6 inline" data-slot="icon">
<g buffered-rendering="static">
Expand Down
17 changes: 16 additions & 1 deletion src/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,25 @@ export default async function initVM() {
require "ruby-next/language/rewriters/edge"
require "ruby-next/language/rewriters/proposed"
module RubyNext
class << self
attr_accessor :custom_rewriters
end
self.custom_rewriters = []
def self.define_text_rewriter(name, &block)
Class.new(RubyNext::Language::Rewriters::Text, &block).tap do |rw|
rw.const_set(:NAME, name)
rw.const_set(:MIN_SUPPORTED_VERSION, Gem::Version.new(RubyNext::NEXT_VERSION))
custom_rewriters << rw
end
end
def self.transform(code, version: RUBY_VERSION, using: false)
options = {using:}
options[:rewriters] = Language.rewriters.select { |rw| rw.unsupported_version?(version) }
options[:rewriters] = Language.rewriters.select { |rw| rw.unsupported_version?(version) } + custom_rewriters
source = Language.transform(code, **options)
source += "\n # Transformed with RubyNext v#{RubyNext::VERSION} for Ruby #{version}"
Expand Down

0 comments on commit f282abe

Please sign in to comment.