A Pseudo-IDE permite criar, empacotar e distribuir suas próprias bibliotecas de funções para os alunos usando um servidor em nuvem (API REST).
Uma biblioteca é um algoritmo normal que contém funções e um cabeçalho de metadados. O marcador
principal é o @BIBLIOTECA[nome_do_pacote].
imprima()) fora de
funções serão executados assim que o aluno importar o pacote. Coloque sua lógica de negócio
dentro de blocos funcao.funcao calcular()) ficará disponível para os alunos usarem.
funcao _ajuste()). Ela não será exportada para
o usuário.@NOME[Física Básica] @AUTOR[Prof. Gabriel] @VERSAO[1.0] @BIBLIOTECA[fisica_basica] minhaBiblioteca() { importar mat como m; // Função Privada (Oculta do aluno) funcao _validarTempo(t) { se (t < 0) { lançar erro "Tempo não pode ser negativo!"; } } // Função Pública funcao mru(pos_inicial, vel, tempo) { _validarTempo(tempo); retorno pos_inicial + (vel * tempo); } }
ajuda() — Documentando sua BibliotecaInclua uma função pública ajuda() em toda biblioteca que criar.
Quando o aluno a chamar, ela imprime a documentação diretamente no console — sem abrir nenhum guia externo:
@NOME[Estatística Aplicada] @AUTOR[Prof. Gabriel] @VERSAO[1.2] @BIBLIOTECA[estatistica] minhaBiblioteca() { importar mat como m; // O aluno chama estatistica.ajuda() para ver isto: funcao ajuda() { imprima("══ Estatística Aplicada v1.2 ═══════════════════"); imprima("Autor: Prof. Gabriel"); imprima(""); imprima("Funções disponíveis:"); imprima(" media(lista) → média aritmética"); imprima(" variancia(lista) → variância amostral"); imprima(" desvPadrao(lista) → desvio padrão"); imprima(" correlacao(lx, ly) → coeficiente de Pearson [-1, 1]"); imprima(""); imprima("Exemplo: importar estatistica como e;"); imprima(" e.media(m.lista(2, 4, 6, 8)) → 5"); } funcao media(lista) { retorno lista.reduzir('+') / lista.tamanho(); } funcao variancia(lista) { super med = media(lista); retorno lista.transformar(x => (x - med)**2).reduzir('+') / (lista.tamanho() - 1); } funcao desvPadrao(lista) { retorno m.raiz(variancia(lista)); } funcao correlacao(lx, ly) { super mx = media(lx), my = media(ly); super num = lx.transformar((x, i) => (x - mx) * (ly[i] - my)).reduzir('+'); super den = m.raiz(variancia(lx) * variancia(ly)) * (lx.tamanho() - 1); retorno num / den; } }
O Pseudo-IDE realiza apenas quatro tipos de requisição HTTP. Todas usam a mesma URL
configurada no botão ⚙ API. O campo tipo no corpo discrimina a
operação. Se quiser usar um back-end próprio (Node.js, Python, Deno, etc.) em vez do modelo
Google Apps Script, implemente os quatro contratos abaixo.
Content-Type: text/plain no POST? Servidores serverless
(Google Apps Script, Cloudflare Workers, etc.) exigem que o preflight CORS seja evitado.
Requisições com Content-Type: application/json disparam um preflight
OPTIONS que esses servidores rejeitam. Usando text/plain o navegador
envia a requisição diretamente (same-origin mode simples). O corpo continua sendo JSON válido —
o back-end só precisa fazer JSON.parse(body) antes de usar.
| Método | Quando ocorre | URL / Corpo |
|---|---|---|
| GET | Baixar biblioteca na execução de importar bib |
{API}?nome=bib[&versao=1.0.0] |
| GET | Carregar snippet ao abrir link compartilhado (?c=token) |
{API}?nome=snp_<token> |
| POST | Publicar biblioteca (Publicar na nuvem) | JSON com tipo:"biblioteca" (ver abaixo) |
| POST | Criar link de compartilhamento (Gerar link) | JSON com tipo:"snippet" (ver abaixo) |
Contrato de resposta do GET (biblioteca ou snippet):
// Resposta esperada para GET ?nome=minhaLib (ou ?nome=minhaLib&versao=2.0.0) { "codigoInjetor": "Bibliotecas['minhaLib'] = { ... };" // string de JS que, ao ser avaliada com eval(), registra a biblioteca } // Resposta esperada para GET ?nome=snp_abc123 (snippet compartilhado) { "codigoInjetor": "// código Pseudo original do usuário" }
Corpo do POST — publicar biblioteca:
// Content-Type: text/plain (corpo é JSON, mas cabeçalho deve ser text/plain) { "tipo": "biblioteca", "nome": "minhaLib", "autor": "Nome do Autor", "versao": "1.0.0", "codigoInjetor":"Bibliotecas['minhaLib'] = { funcaoA: ..., funcaoB: ... };" } // Resposta esperada (texto simples ou JSON, a IDE ignora o corpo): "OK" // qualquer resposta 2xx é considerada sucesso
Corpo do POST — criar link de compartilhamento:
// Content-Type: text/plain { "tipo": "snippet", "nome": "snp_abc123", // token gerado pela IDE (8 chars aleatórios) "codigoInjetor":"// código Pseudo do usuário (texto puro)" } // Resposta esperada: "OK"
Exemplo mínimo — Node.js / Express:
const express = require('express'); const app = express(); const db = {}; // substitua por banco real app.use((_req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); next(); }); app.get('/', (req, res) => { const { nome, versao } = req.query; const key = versao ? `${nome}@${versao}` : nome; const entry = db[key] || db[nome]; // fallback para última versão if (!entry) return res.status(404).json({ erro: 'não encontrado' }); res.json({ codigoInjetor: entry.codigoInjetor }); }); app.post('/', express.text(), (req, res) => { const payload = JSON.parse(req.body); const key = payload.versao ? `${payload.nome}@${payload.versao}` : payload.nome; db[key] = payload; res.send('OK'); }); app.listen(3000);
Exemplo mínimo — Python / Flask:
from flask import Flask, request, jsonify
import json
app = Flask(__name__)
db = {} # substitua por banco real
@app.after_request
def cors(r):
r.headers['Access-Control-Allow-Origin'] = '*'
r.headers['Access-Control-Allow-Headers'] = 'Content-Type'
return r
@app.route('/', methods=['GET'])
def get_item():
nome = request.args.get('nome')
versao = request.args.get('versao')
key = f"{nome}@{versao}" if versao else nome
entry = db.get(key) or db.get(nome)
if not entry:
return jsonify({'erro': 'não encontrado'}), 404
return jsonify({'codigoInjetor': entry['codigoInjetor']})
@app.route('/', methods=['POST', 'OPTIONS'])
def post_item():
if request.method == 'OPTIONS':
return '', 204
payload = json.loads(request.get_data(as_text=True))
nome = payload['nome']
versao = payload.get('versao')
key = f"{nome}@{versao}" if versao else nome
db[key] = payload
return 'OK'
app.run(port=3000)
Backend completo que substitui o exemplo simples acima. Suporta múltiplas versões da mesma biblioteca, busca por versão específica e listagem do catálogo completo.
text/plain no POST? Evita o preflight CORS que bloqueia
servidores serverless como o Apps Script.
// ══ Pseudo-IDE — Repositório de Bibliotecas com Versionamento ══════════════ // Crie uma Planilha Google, vá em Extensões → Apps Script, cole este código // e publique como "App da Web" com acesso público. const PLANILHA_LIBS = "Bibliotecas"; // aba criada automaticamente na primeira publicação function _aba() { const ss = SpreadsheetApp.getActiveSpreadsheet(); return ss.getSheetByName(PLANILHA_LIBS) || ss.insertSheet(PLANILHA_LIBS); } function _json(obj) { return ContentService.createTextOutput(JSON.stringify(obj)) .setMimeType(ContentService.MimeType.JSON); } // ── POST: publica (ou atualiza) uma biblioteca ───────────────────────────── // Body (text/plain, JSON): { nome, autor?, versao?, codigoInjetor, descricao? } function doPost(e) { try { const d = JSON.parse(e.postData.contents); if (!d.nome || !d.codigoInjetor) return _json({ ok: false, erro: "Campos 'nome' e 'codigoInjetor' são obrigatórios." }); _aba().appendRow([ d.nome, d.autor || "—", d.versao || "1.0", d.codigoInjetor, d.descricao || "", new Date().toISOString() ]); return _json({ ok: true, mensagem: `'${d.nome}' v${d.versao || "1.0"} publicada com sucesso.` }); } catch (err) { return _json({ ok: false, erro: err.message }); } } // ── GET: recupera biblioteca ou lista o catálogo ─────────────────────────── // ?nome=fisica_basica → versão mais recente // ?nome=fisica_basica&versao=1.1 → versão específica // ?listar=1 → catálogo de todas as bibliotecas disponíveis function doGet(e) { const p = e.parameter; if (p.listar) { const cat = {}; _aba().getDataRange().getValues().forEach(r => { if (!r[0]) return; if (!cat[r[0]]) cat[r[0]] = { nome: r[0], autor: r[1], descricao: r[4], versoes: [] }; cat[r[0]].versoes.push(r[2]); }); return _json({ ok: true, bibliotecas: Object.values(cat) }); } if (!p.nome) return _json({ ok: false, erro: "Parâmetro 'nome' é obrigatório." }); const dados = _aba().getDataRange().getValues(); for (let i = dados.length - 1; i >= 0; i--) { // de baixo para cima → mais recente primeiro if (dados[i][0] !== p.nome) continue; if (p.versao && dados[i][2] !== p.versao) continue; return _json({ tipo: "biblioteca", nome: dados[i][0], autor: dados[i][1], versao: dados[i][2], codigoInjetor: dados[i][3], descricao: dados[i][4] }); } const msg = p.versao ? `'${p.nome}' v${p.versao} não encontrada.` : `'${p.nome}' não encontrada.`; return _json({ ok: false, erro: msg }); }
Permite salvar e recuperar trechos de código via um ID curto de 8 caracteres. Ideal para o professor distribuir gabaritos, exercícios-modelo e exemplos prontos — sem precisar enviar arquivos por e-mail.
Fluxo: professor faz um POST com o código → recebe um ID de 8 letras →
compartilha o link ?id=XXXXXXXX com os alunos → aluno faz GET e recebe o
código de volta (pode ser colado diretamente no editor).
// ══ Pseudo-IDE — Compartilhamento de Códigos ══════════════════════════════ // Projeto Apps Script separado do repositório de bibliotecas. // Publique como "App da Web" com acesso público. const PLANILHA_CODIGOS = "Codigos"; function _aba() { const ss = SpreadsheetApp.getActiveSpreadsheet(); return ss.getSheetByName(PLANILHA_CODIGOS) || ss.insertSheet(PLANILHA_CODIGOS); } function _json(obj) { return ContentService.createTextOutput(JSON.stringify(obj)) .setMimeType(ContentService.MimeType.JSON); } // ── POST: salva o código e devolve um ID de 8 caracteres ────────────────── // Body (text/plain, JSON): { titulo?, autor?, codigo } // Resposta: { ok: true, id: "A3F7C2B1", url: "https://script.google.com/...?id=A3F7C2B1" } function doPost(e) { try { const d = JSON.parse(e.postData.contents); if (!d.codigo) return _json({ ok: false, erro: "Campo 'codigo' é obrigatório." }); const id = Utilities.getUuid().substring(0, 8).toUpperCase(); _aba().appendRow([ id, d.titulo || "Sem título", d.autor || "Anônimo", d.codigo, new Date().toISOString() ]); const url = ScriptApp.getService().getUrl() + "?id=" + id; return _json({ ok: true, id, url }); } catch (err) { return _json({ ok: false, erro: err.message }); } } // ── GET ?id=XXXXXXXX: recupera o código pelo ID ─────────────────────────── // Resposta: { ok: true, id, titulo, autor, codigo, criado } function doGet(e) { const id = (e.parameter.id || "").trim().toUpperCase(); if (!id) return _json({ ok: false, erro: "Parâmetro 'id' é obrigatório." }); const dados = _aba().getDataRange().getValues(); for (let i = 0; i < dados.length; i++) { if (dados[i][0] === id) return _json({ ok: true, id, titulo: dados[i][1], autor: dados[i][2], codigo: dados[i][3], criado: dados[i][4] }); } return _json({ ok: false, erro: `ID '${id}' não encontrado.` }); }
No cabeçalho da Pseudo-IDE, o aluno clica no botão ⚙️ API e cola a URL do repositório de bibliotecas. Depois, basta importar o pacote e, se desejar, pedir ajuda:
importar fisica_basica como fb; fb.ajuda(); // imprime a documentação da biblioteca imprima(fb.mru(0, 10, 5)); // usa normalmente → 50