mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
Source: Restore broken commit
This commit is contained in:
223
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core.java
Normal file
223
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.core.envs.*;
|
||||
import gplx.xowa.langs.*;
|
||||
import gplx.xowa.xtns.scribunto.libs.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_core {
|
||||
private Hash_adp_bry mods = Hash_adp_bry.cs();
|
||||
private int expensive_function_count;
|
||||
public Scrib_core(Xoae_app app, Xop_ctx ctx) {// NOTE: ctx needed for language reg
|
||||
this.app = app; this.ctx = ctx;
|
||||
this.wiki = ctx.Wiki(); this.page = ctx.Page(); // NOTE: wiki / page needed for title reg; DATE:2014-02-05
|
||||
this.lang = wiki.Lang();
|
||||
this.Engine_(Scrib_engine_type.Type_lua, false); // TEST: default to lua
|
||||
fsys_mgr.Root_dir_(app.Fsys_mgr().Bin_xtns_dir().GenSubDir_nest("Scribunto"));
|
||||
lib_mw = new Scrib_lib_mw(this);
|
||||
lib_uri = new Scrib_lib_uri(this);
|
||||
lib_ustring = new Scrib_lib_ustring(this);
|
||||
lib_language = new Scrib_lib_language(this);
|
||||
lib_site = new Scrib_lib_site(this);
|
||||
lib_title = new Scrib_lib_title(this);
|
||||
lib_message = new Scrib_lib_message(this);
|
||||
lib_text = new Scrib_lib_text(this);
|
||||
lib_html = new Scrib_lib_html(this);
|
||||
lib_wikibase = new Scrib_lib_wikibase(this);
|
||||
lib_wikibase_entity = new Scrib_lib_wikibase_entity(this);
|
||||
}
|
||||
public Xoae_app App() {return app;} private Xoae_app app;
|
||||
public Xowe_wiki Wiki() {return wiki;} private Xowe_wiki wiki;
|
||||
public Xol_lang_itm Lang() {return lang;} private Xol_lang_itm lang;
|
||||
@gplx.Internal protected void Wiki_(Xowe_wiki v) {this.wiki = v;} // TEST:
|
||||
public Xoae_page Page() {return page;} private Xoae_page page;
|
||||
public boolean Enabled() {return enabled;} private boolean enabled = true;
|
||||
public void Engine_(Scrib_engine v) {this.engine = v;}
|
||||
private void Engine_(byte type, boolean luaj_debug_enabled) {
|
||||
if (type == Scrib_engine_type.Type_lua)
|
||||
engine = new gplx.xowa.xtns.scribunto.engines.process.Process_engine(app, wiki, this);
|
||||
else if (type == Scrib_engine_type.Type_luaj)
|
||||
engine = new gplx.xowa.xtns.scribunto.engines.luaj.Luaj_engine(app, this, luaj_debug_enabled);
|
||||
}
|
||||
public Scrib_fsys_mgr Fsys_mgr() {return fsys_mgr;} private Scrib_fsys_mgr fsys_mgr = new Scrib_fsys_mgr();
|
||||
public Scrib_proc_mgr Proc_mgr() {return proc_mgr;} private Scrib_proc_mgr proc_mgr = new Scrib_proc_mgr();
|
||||
public Scrib_engine Interpreter() {return engine;} private Scrib_engine engine;
|
||||
public Scrib_lib_mw Lib_mw() {return lib_mw;} private Scrib_lib_mw lib_mw;
|
||||
public Scrib_lib_uri Lib_uri() {return lib_uri;} private Scrib_lib_uri lib_uri;
|
||||
public Scrib_lib_ustring Lib_ustring() {return lib_ustring;} private Scrib_lib_ustring lib_ustring;
|
||||
public Scrib_lib_language Lib_language() {return lib_language;} private Scrib_lib_language lib_language;
|
||||
public Scrib_lib_site Lib_site() {return lib_site;} private Scrib_lib_site lib_site;
|
||||
public Scrib_lib_title Lib_title() {return lib_title;} private Scrib_lib_title lib_title;
|
||||
public Scrib_lib_message Lib_message() {return lib_message;} private Scrib_lib_message lib_message;
|
||||
public Scrib_lib_text Lib_text() {return lib_text;} private Scrib_lib_text lib_text;
|
||||
public Scrib_lib_html Lib_html() {return lib_html;} private Scrib_lib_html lib_html;
|
||||
public Scrib_lib_wikibase Lib_wikibase() {return lib_wikibase;} private Scrib_lib_wikibase lib_wikibase;
|
||||
public Scrib_lib_wikibase_entity Lib_wikibase_entity() {return lib_wikibase_entity;} private Scrib_lib_wikibase_entity lib_wikibase_entity;
|
||||
public Scrib_core Init() { // REF:LuaCommon.php!Load
|
||||
Scrib_xtn_mgr xtn_mgr = (Scrib_xtn_mgr)wiki.Xtn_mgr().Get_or_fail(Scrib_xtn_mgr.XTN_KEY);
|
||||
Engine_(xtn_mgr.Engine_type(), xtn_mgr.Luaj_debug_enabled());
|
||||
engine.Server().Server_timeout_(xtn_mgr.Lua_timeout()).Server_timeout_polling_(xtn_mgr.Lua_timeout_polling()).Server_timeout_busy_wait_(xtn_mgr.Lua_timeout_busy_wait());
|
||||
enabled = xtn_mgr.Enabled();
|
||||
Io_url root_dir = fsys_mgr.Root_dir(), script_dir = fsys_mgr.Script_dir();
|
||||
engine.Server().Init
|
||||
( app.Prog_mgr().App_lua().Exe_url().Raw()
|
||||
, root_dir.GenSubFil_nest("engines", "LuaStandalone", "mw_main.lua").Raw()
|
||||
, root_dir.Raw()
|
||||
);
|
||||
Init_register(script_dir, lib_mw, lib_uri, lib_ustring, lib_language, lib_site, lib_title, lib_text, lib_html, lib_message, lib_wikibase, lib_wikibase_entity);
|
||||
xtn_mgr.Lib_mgr().Init_for_core(this, script_dir);
|
||||
return this;
|
||||
}
|
||||
private void Init_register(Io_url script_dir, Scrib_lib... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
ary[i].Register(this, script_dir);
|
||||
}
|
||||
public void Term() {engine.Server().Term(); mods.Clear();}
|
||||
public void When_page_changed(Xoae_page page) {
|
||||
mods.Clear(); // clear any loaded modules
|
||||
Xow_wiki wiki = page.Wiki();
|
||||
this.page = page;
|
||||
byte[] new_wiki = wiki.Domain_bry();
|
||||
if (!Bry_.Eq(cur_wiki, new_wiki)) {
|
||||
cur_wiki = new_wiki;
|
||||
lib_site.Notify_wiki_changed();
|
||||
lib_text.Notify_wiki_changed();
|
||||
}
|
||||
byte[] new_lang = wiki.Lang().Key_bry();
|
||||
if (!Bry_.Eq(cur_lang, new_lang)) {
|
||||
cur_lang = new_lang;
|
||||
lib_message.Notify_lang_changed();
|
||||
lib_language.Notify_lang_changed();
|
||||
}
|
||||
lib_uri.Notify_page_changed();
|
||||
lib_title.Notify_page_changed();
|
||||
lib_wikibase.Notify_page_changed();
|
||||
expensive_function_count = 0;
|
||||
}
|
||||
public byte[] Cur_wiki() {return cur_wiki;} private byte[] cur_wiki = Bry_.Empty;
|
||||
public byte[] Cur_lang() {return cur_lang;} private byte[] cur_lang = Bry_.Empty;
|
||||
public void Increment_expensive_function_count() {
|
||||
++expensive_function_count;
|
||||
if (expensive_function_count > 255) {}
|
||||
}
|
||||
public Scrib_lua_mod RegisterInterface(Scrib_lib lib, Io_url url, Keyval... args) {
|
||||
this.RegisterLibrary(lib.Procs());
|
||||
Scrib_lua_mod rv = this.LoadLibraryFromFile(url.NameAndExt(), Io_mgr.Instance.LoadFilStr(url));
|
||||
Scrib_lua_proc setupInterface_func = rv.Fncs_get_by_key("setupInterface");
|
||||
if (setupInterface_func != null)
|
||||
engine.CallFunction(setupInterface_func.Id(), Scrib_kv_utl_.base1_obj_(args));
|
||||
return rv;
|
||||
}
|
||||
public void RegisterLibrary(Scrib_proc_mgr lib_proc_mgr) {
|
||||
int len = lib_proc_mgr.Len();
|
||||
Keyval[] functions_ary = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Scrib_proc lib_proc = lib_proc_mgr.Get_at(i);
|
||||
String lib_proc_key = lib_proc.Proc_key();
|
||||
this.proc_mgr.Set(lib_proc_key, lib_proc);
|
||||
functions_ary[i] = Keyval_.new_(lib_proc.Proc_name(), lib_proc_key);
|
||||
}
|
||||
engine.RegisterLibrary(functions_ary);
|
||||
}
|
||||
@gplx.Internal protected Scrib_lua_mod LoadLibraryFromFile(String name, String text) {
|
||||
int lib_id = engine.LoadString("@" + name, text).Id(); // NOTE: 'Prepending an "@" to the chunk name makes Lua think it is a filename'
|
||||
Keyval[] values = engine.CallFunction(lib_id, Keyval_.Ary_empty);
|
||||
Scrib_lua_mod rv = new Scrib_lua_mod(this, name);
|
||||
if (values.length > 0) { // NOTE: values.length == 0 for "package.lua" (no fnc_ids returned);
|
||||
Keyval[] fncs = Scrib_kv_utl_.Val_to_KeyVal_ary(values, 0);
|
||||
int len = fncs.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval itm = fncs[i];
|
||||
Scrib_lua_proc fnc = Scrib_lua_proc.cast_or_null_(itm.Val());
|
||||
if (fnc != null) rv.Fncs_add(fnc); // NOTE: some lua funcs will return INF; EX: stringLengthLimit
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public Ordered_hash Frame_created_list() {return frame_created_list;} private Ordered_hash frame_created_list = Ordered_hash_.New(); // created by NewChildFrame
|
||||
public Xot_invk Frame_current() {return frame_current;} private Xot_invk frame_current;
|
||||
public Xot_invk Frame_parent() {return frame_parent;} private Xot_invk frame_parent;
|
||||
@gplx.Internal protected void Frame_current_(Xot_invk v) {frame_current = v;} // TEST:
|
||||
@gplx.Internal protected void Frame_parent_(Xot_invk v) {frame_parent = v;} // TEST:
|
||||
public Xop_ctx Ctx() {return ctx;} private Xop_ctx ctx;
|
||||
public byte[] Cur_src() {return cur_src;} private byte[] cur_src; // only used for error reporting
|
||||
public void Invoke_init(Xowe_wiki wiki, Xop_ctx ctx, byte[] src, Xot_invk parent_frame, Xot_invk current_frame) { // TEST
|
||||
this.wiki = wiki; this.ctx = ctx; this.cur_src = src;
|
||||
lib_mw.Invoke_bgn(wiki, ctx, src);
|
||||
this.frame_parent = parent_frame; this.frame_current = current_frame;
|
||||
}
|
||||
public void Invoke(Xowe_wiki wiki, Xop_ctx ctx, byte[] src, Xot_invk parent_frame, Xot_invk current_frame, Bry_bfr bfr, byte[] mod_name, byte[] mod_text, byte[] fnc_name) {
|
||||
// save current values for restoring later
|
||||
Xot_invk old_frame_parent = this.frame_parent; Xot_invk old_frame_current = this.frame_current;
|
||||
byte[] old_src = cur_src;
|
||||
|
||||
// init
|
||||
this.wiki = wiki; this.ctx = ctx; this.cur_src = src;
|
||||
lib_mw.Invoke_bgn(wiki, ctx, src);
|
||||
this.frame_parent = parent_frame; this.frame_current = current_frame;
|
||||
parent_frame.Frame_tid_(Scrib_frame_.Tid_parent); current_frame.Frame_tid_(Scrib_frame_.Tid_current);
|
||||
|
||||
try {
|
||||
Scrib_lua_mod mod = Mods_get_or_new(mod_name, mod_text);
|
||||
Keyval[] func_args = Scrib_kv_utl_.base1_many_(mod.Init_chunk_func(), String_.new_u8(fnc_name));
|
||||
Keyval[] func_rslt = engine.CallFunction(lib_mw.Mod().Fncs_get_id("executeModule"), func_args); // call init_chunk to get proc dynamically; DATE:2014-07-12
|
||||
if (func_rslt == null || func_rslt.length < 2) throw Err_.new_wo_type("lua.error:function did not return a value", "fnc_name", String_.new_u8(fnc_name)); // must return at least 2 items for func_rslt[1] below; DATE:2014-09-22
|
||||
Scrib_lua_proc proc = (Scrib_lua_proc)func_rslt[1].Val(); // note that init_chunk should have: [0]:true/false result; [1]:proc
|
||||
func_args = Scrib_kv_utl_.base1_many_(proc);
|
||||
func_rslt = engine.CallFunction(lib_mw.Mod().Fncs_get_id("executeFunction"), func_args); // call function now
|
||||
String rslt = Scrib_kv_utl_.Val_to_str(func_rslt, 0); // rslt expects an array with 1 scalar value
|
||||
bfr.Add_str_u8(rslt);
|
||||
//byte[] rslt_bry = Bry_.new_u8(rslt); // CHART
|
||||
//gplx.xowa.parsers.xndes.Xop_xnde_tkn.Hack_ctx = ctx;
|
||||
//bfr.Add(rslt_bry);
|
||||
if (!Env_.Mode_testing())
|
||||
engine.CleanupChunks(Keyval_.Ary(Keyval_.int_(proc.Id(), ""))); // cleanup chunk immediately; needed for heavy pages like en.d:water; DATE:2014-08-07
|
||||
}
|
||||
finally {
|
||||
lib_mw.Invoke_end();
|
||||
parent_frame.Frame_tid_(Scrib_frame_.Tid_null); current_frame.Frame_tid_(Scrib_frame_.Tid_null);
|
||||
this.frame_parent = old_frame_parent; this.frame_current = old_frame_current; // NOTE: reset template frame; PAGE:en.w:Constantine_the_Great {{Christianity}}; DATE:2014-06-26
|
||||
this.cur_src = old_src;
|
||||
frame_created_list.Clear();
|
||||
}
|
||||
}
|
||||
public Scrib_lua_mod Mods_get(byte[] mod_name) {return (Scrib_lua_mod)mods.Get_by(mod_name);}
|
||||
private Scrib_lua_mod Mods_get_or_new(byte[] mod_name, byte[] mod_text) {
|
||||
Scrib_lua_mod rv = (Scrib_lua_mod)mods.Get_by(mod_name);
|
||||
if (rv == null) {
|
||||
rv = new Scrib_lua_mod(this, "Module:" + String_.new_u8(mod_name));
|
||||
rv.LoadString(String_.new_u8(mod_text));
|
||||
mods.Add(mod_name, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void Handle_error(String err) {
|
||||
String excerpt = "";
|
||||
try {
|
||||
Xot_invk src_frame = frame_current;
|
||||
if (src_frame != null)
|
||||
excerpt = String_.new_u8(cur_src, src_frame.Src_bgn(), src_frame.Src_end());
|
||||
} catch (Exception e) {Err_.Noop(e);}
|
||||
throw Err_.new_wo_type(err, "ttl", page.Ttl().Page_db_as_str(), "excerpt", excerpt);
|
||||
}
|
||||
public static final String Frame_key_module = "current", Frame_key_template = "parent";
|
||||
public static final int Base_1 = 1;
|
||||
public static final String Key_mw_interface = "mw_interface";
|
||||
}
|
||||
149
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_fxt.java
Normal file
149
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_fxt.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.xtns.scribunto.engines.process.*; import gplx.xowa.parsers.tmpls.*;
|
||||
public class Scrib_core_fxt {
|
||||
public Scrib_core_fxt() {}
|
||||
public Scrib_core_fxt(Xop_fxt fxt) {
|
||||
app = fxt.App();
|
||||
wiki = fxt.Wiki();
|
||||
core = wiki.Parser_mgr().Scrib().Core_init(wiki.Parser_mgr().Ctx());
|
||||
server = new Process_server_mock();
|
||||
core.Interpreter().Server_(server);
|
||||
}
|
||||
public Scrib_core_fxt Clear() {
|
||||
if (core == null) {
|
||||
app = Xoa_app_fxt.Make__app__edit();
|
||||
wiki = Xoa_app_fxt.Make__wiki__edit(app);
|
||||
core = wiki.Parser_mgr().Scrib().Core_init(wiki.Parser_mgr().Ctx());
|
||||
server = new Process_server_mock();
|
||||
core.Interpreter().Server_(server);
|
||||
}
|
||||
server.Clear();
|
||||
core.Proc_mgr().Clear();
|
||||
core.Frame_parent_(null);
|
||||
core.When_page_changed(wiki.Parser_mgr().Ctx().Page());
|
||||
expd_server_rcvd_list.Clear();
|
||||
return this;
|
||||
} private Xoae_app app; Xowe_wiki wiki; Bry_bfr tmp_bfr = Bry_bfr_.Reset(255);
|
||||
public Scrib_core Core() {return core;} private Scrib_core core;
|
||||
public Process_server_mock Server() {return server;} Process_server_mock server;
|
||||
public Keyval kv_(Object key, Object val) {return Keyval_.obj_(key, val);}
|
||||
public Keyval[] kv_ary_(Keyval... v) {return v;}
|
||||
public Keyval kv_func_(String key, int id) {return Keyval_.new_(key, new Scrib_lua_proc(key, id));}
|
||||
public Scrib_core_fxt Init_lib_fil(String name, String text) {
|
||||
Io_url url = core.Fsys_mgr().Script_dir().GenSubFil(name);
|
||||
Io_mgr.Instance.SaveFilStr(url, text);
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Init_server_prep_add(String v) {server.Prep_add(v); return this;}
|
||||
public Scrib_core_fxt Init_lib_mw() {
|
||||
if (core.Lib_mw().Mod() == null) {
|
||||
Scrib_lua_mod mod = new Scrib_lua_mod(core, "mw.lua");
|
||||
mod.Fncs_add(new Scrib_lua_proc("executeModule", 8));
|
||||
mod.Fncs_add(new Scrib_lua_proc("executeFunction", 9));
|
||||
core.Lib_mw().Mod_(mod);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Init_cbks_add(String func, int idx) {
|
||||
core.Proc_mgr().Set(core.Lib_mw(), func, idx);
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Expd_server_rcvd_add(String v) {expd_server_rcvd_list.Add(v); return this;} List_adp expd_server_rcvd_list = List_adp_.New();
|
||||
public Scrib_core_fxt Test_LoadString(String name, String text, int expd_id) {
|
||||
int actl_id = core.Interpreter().LoadString(name, text).Id();
|
||||
Test_server_logs();
|
||||
Tfds.Eq(expd_id, actl_id);
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_CallFunction(int prc_id, Object[] args, Keyval... expd) {
|
||||
Keyval[] actl = core.Interpreter().CallFunction(prc_id, Scrib_kv_utl_.base1_many_(args));
|
||||
Test_server_logs();
|
||||
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_RegisterLibrary(String[] proc_names, String[] expd_keys) {
|
||||
core.Lib_mw().Procs().Init_by_lib(core.Lib_mw(), proc_names);
|
||||
core.RegisterLibrary(core.Lib_mw().Procs());
|
||||
Test_server_logs();
|
||||
int len = core.Proc_mgr().Len();
|
||||
String[] actl_keys = new String[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
actl_keys[i] = core.Proc_mgr().Get_at(i).Proc_key();
|
||||
Tfds.Eq_ary_str(expd_keys, actl_keys);
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_LoadLibraryFromFile(String name, String text, Keyval... expd) {
|
||||
Scrib_lua_mod actl_lib = core.LoadLibraryFromFile(name, text);
|
||||
int actl_len = actl_lib.Fncs_len();
|
||||
Keyval[] actl = new Keyval[actl_len];
|
||||
for (int i = 0; i < actl_len; i++) {
|
||||
Scrib_lua_proc itm = actl_lib.Fncs_get_at(i);
|
||||
actl[i] = Keyval_.new_(itm.Key(), itm.Id());
|
||||
}
|
||||
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_Module_GetInitChunk(String name, String text, int expd_id) {
|
||||
Scrib_lua_mod mod = new Scrib_lua_mod(core, name);
|
||||
int actl_id = mod.LoadString(text).Id();
|
||||
Test_server_logs();
|
||||
Tfds.Eq(expd_id, actl_id);
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_ExecuteModule(int mod_id, Keyval... expd) {
|
||||
Keyval[] values = core.Interpreter().ExecuteModule(mod_id);
|
||||
Keyval[] actl = (Keyval[])values[0].Val();
|
||||
Test_server_logs();
|
||||
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_GetExpandedArgument(Keyval[] args, String arg, String expd) {// NOTE: test is rigidly defined; (a) always same 3 arguments in frame; (b) expd={"val_1", "val_2", "val_3", ""}
|
||||
this.Expd_server_rcvd_add("0000003D00000079{[\"op\"]=\"call\",[\"id\"]=8,[\"nargs\"]=1,[\"args\"]={[1]=chunks[9]}}")
|
||||
.Init_server_prep_add("a:4:{s:2:\"id\";s:32:\"mw_interface-getExpandedArgument\";s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:2;s:4:\"args\";a:2:{i:1;s:7:\"current\";i:2;s:" + String_.Len(arg) + ":\"" + arg + "\";}}");
|
||||
if (String_.Eq(expd, ""))
|
||||
this.Expd_server_rcvd_add("0000002D00000059{[\"op\"]=\"return\",[\"nvalues\"]=0,[\"values\"]={}}");
|
||||
else
|
||||
this.Expd_server_rcvd_add("000000380000006F{[\"op\"]=\"return\",[\"nvalues\"]=1,[\"values\"]={[1]=\"" + expd + "\"}}");
|
||||
this.Init_server_prep_add("a:2:{s:6:\"values\";a:1:{i:1;s:6:\"ignore\";}s:2:\"op\";s:6:\"return\";}");
|
||||
core.Frame_current_(Xot_invk_mock.new_(Frame_ttl_test, args));
|
||||
core.Interpreter().ExecuteModule(9);
|
||||
Test_server_logs();
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_GetAllExpandedArguments(Keyval... args) {
|
||||
core.Frame_current_(Xot_invk_mock.new_(Frame_ttl_test, args));
|
||||
core.Interpreter().ExecuteModule(9);
|
||||
Test_server_logs();
|
||||
return this;
|
||||
}
|
||||
public Scrib_core_fxt Test_Invoke(String mod_name, String mod_code, String prc_name, Keyval... args) {
|
||||
core.Invoke(wiki, core.Ctx(), Bry_.Empty, Xot_invk_mock.Null, Xot_invk_mock.new_(Frame_ttl_test, args), tmp_bfr, Bry_.new_u8(mod_name), Bry_.new_u8(mod_code), Bry_.new_u8(prc_name));
|
||||
Test_server_logs();
|
||||
return this;
|
||||
} private static final byte[] Frame_ttl_test = Bry_.new_a7("test");
|
||||
private void Test_server_logs() {
|
||||
if (expd_server_rcvd_list.Count() > 0) {
|
||||
Tfds.Eq_ary_str(expd_server_rcvd_list.To_str_ary(), server.Log_rcvd().To_str_ary());
|
||||
expd_server_rcvd_list.Clear();
|
||||
server.Log_rcvd().Clear();
|
||||
}
|
||||
}
|
||||
public String Encode(String v) {return String_.Replace(v, "\n", "\\n");}
|
||||
}
|
||||
55
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_mgr.java
Normal file
55
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_mgr.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.wikis.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
public class Scrib_core_mgr {
|
||||
public Scrib_core Core() {return core;} private Scrib_core core;
|
||||
public void Terminate_when_page_changes_y_() {terminate_when_page_changes = true;} private boolean terminate_when_page_changes;
|
||||
public Scrib_core Core_init(Xop_ctx ctx) {
|
||||
core = new Scrib_core(ctx.App(), ctx);
|
||||
terminate_when_page_changes = false;
|
||||
return core;
|
||||
}
|
||||
public void Core_term() {
|
||||
if (core != null) {
|
||||
core.Term();
|
||||
core = null;
|
||||
}
|
||||
}
|
||||
public void When_page_changed(Xoae_page page) {
|
||||
if (terminate_when_page_changes) { // true when error in {{#invoke}}; PAGE:th.d:all; DATE:2014-10-03
|
||||
Core_term(); // terminate core; note that next call to {{#invoke}} will check for null and rebuild if null;
|
||||
terminate_when_page_changes = false;
|
||||
}
|
||||
else { // no error on previous page; notify core that page changed; note that lua will cache chunks by Module name and two modules in two different wikis can have the same name, but different data: EX:Module:Citation/CS1/Configuration and enwiki / zhwiki; DATE:2014-03-21
|
||||
if (core != null) // null-check needed when engine first created
|
||||
core.When_page_changed(page); // NOTE: must call When_page_changed on core to update page; else, current ttl is not updated, and scrib_wikibase will return wrong document; DATE:2016-07-22
|
||||
}
|
||||
}
|
||||
|
||||
public static void Term_all(Xoae_app app) { // NOLOCK.app_level
|
||||
if (app == null) return;
|
||||
Xoae_wiki_mgr wiki_mgr = app.Wiki_mgr();
|
||||
int len = wiki_mgr.Count();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Xowe_wiki wiki = (Xowe_wiki)wiki_mgr.Get_at(i);
|
||||
wiki.Parser_mgr().Scrib().Core_term();
|
||||
}
|
||||
}
|
||||
}
|
||||
117
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_tst.java
Normal file
117
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_tst.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_core_tst {
|
||||
@Before public void init() {fxt.Clear();} Scrib_core_fxt fxt = new Scrib_core_fxt();
|
||||
@Test public void LoadString() {
|
||||
String mod_text = Mod_basic();
|
||||
fxt .Expd_server_rcvd_add("00000067000000CD{[\"op\"]=\"loadString\",[\"text\"]=\"" + fxt.Encode(mod_text) + "\",[\"chunkName\"]=\"lib_name\"}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:1;}}")
|
||||
.Test_LoadString("lib_name", mod_text, 1)
|
||||
;
|
||||
}
|
||||
@Test public void CallFunction() {
|
||||
fxt .Expd_server_rcvd_add("000000300000005F{[\"op\"]=\"call\",[\"id\"]=1,[\"nargs\"]=0,[\"args\"]={}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;a:1:{s:4:\"noop\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:2;}}}}")
|
||||
.Test_CallFunction(1, Object_.Ary_empty, fxt.kv_ary_(fxt.kv_(1, fxt.kv_func_("noop", 2))))
|
||||
;
|
||||
}
|
||||
@Test public void CallFunction_args() {
|
||||
fxt .Expd_server_rcvd_add("0000004100000081{[\"op\"]=\"call\",[\"id\"]=1,[\"nargs\"]=1,[\"args\"]={[1]={[\"key\"]=123}}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;a:1:{s:4:\"noop\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:2;}}}}")
|
||||
.Test_CallFunction(1, Object_.Ary(fxt.kv_("key", 123)), fxt.kv_ary_(fxt.kv_(1, fxt.kv_func_("noop", 2))))
|
||||
;
|
||||
}
|
||||
@Test public void RegisterLibrary() {
|
||||
fxt .Expd_server_rcvd_add("00000080000000FF{[\"op\"]=\"registerLibrary\",[\"name\"]=\"mw_interface\",[\"functions\"]={[\"prc_0\"]=\"mw_interface-prc_0\",[\"prc_1\"]=\"mw_interface-prc_1\"}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:0;s:6:\"values\";a:0:{}}")
|
||||
.Test_RegisterLibrary(String_.Ary("prc_0", "prc_1"), String_.Ary("mw_interface-prc_0", "mw_interface-prc_1"))
|
||||
;
|
||||
}
|
||||
@Test public void LoadLibraryFromFile() {
|
||||
fxt .Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:15;}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;a:2:{s:5:\"prc_2\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:2;}s:5:\"prc_3\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:3;}}}}")
|
||||
.Test_LoadLibraryFromFile("lib_name", "doesn't matter", fxt.kv_("prc_2", 2), fxt.kv_("prc_3", 3));
|
||||
;
|
||||
}
|
||||
@Test public void LoadLibraryFromFile__rv_has_no_values() { // PURPOSE: "package.lua" does not return any prc_ids
|
||||
fxt .Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:15;}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:0;s:6:\"values\";a:0:{}}")
|
||||
.Test_LoadLibraryFromFile("lib_name", "doesn't matter");
|
||||
;
|
||||
}
|
||||
@Test public void CallFunction_cbk() { // PURPOSE: 'simulates interpreter.CallFunction(mw_lib.Fncs_get_by_key("setup").Id(), "allowEnvFuncs", allow_env_funcs);'
|
||||
fxt .Expd_server_rcvd_add("0000008C00000117{[\"op\"]=\"registerLibrary\",[\"name\"]=\"mw_interface\",[\"functions\"]={[\"loadPackage\"]=\"mw_interface-loadPackage\",[\"prc_1\"]=\"mw_interface-prc_1\"}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:0;s:6:\"values\";a:0:{}}")
|
||||
.Test_RegisterLibrary(String_.Ary("loadPackage", "prc_1"), String_.Ary("mw_interface-loadPackage", "mw_interface-prc_1"))
|
||||
;
|
||||
fxt .Init_lib_fil("package.lua", "package_text")
|
||||
.Expd_server_rcvd_add("000000470000008D{[\"op\"]=\"call\",[\"id\"]=2,[\"nargs\"]=1,[\"args\"]={[1]={[\"key_0\"]=\"val_0\"}}}")
|
||||
.Init_server_prep_add("a:4:{s:2:\"id\";s:24:\"mw_interface-loadPackage\";s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:1;s:4:\"args\";a:1:{i:1;s:7:\"package\";}}")
|
||||
.Expd_server_rcvd_add("0000004A00000093{[\"op\"]=\"loadString\",[\"text\"]=\"package_text\",[\"chunkName\"]=\"@package.lua\"}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:14;}}")
|
||||
.Expd_server_rcvd_add("0000003B00000075{[\"op\"]=\"return\",[\"nvalues\"]=1,[\"values\"]={[1]=chunks[14]}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:0;s:6:\"values\";a:0:{}}")
|
||||
.Test_CallFunction(2, Object_.Ary(fxt.kv_("key_0", "val_0")));
|
||||
}
|
||||
@Test public void Module_GetInitChunk() { // PURPOSE: similar to LoadString except name is prepended with "="
|
||||
String mod_text = Mod_basic();
|
||||
fxt .Expd_server_rcvd_add("0000006F000000DD{[\"op\"]=\"loadString\",[\"text\"]=\"" + fxt.Encode(mod_text) + "\",[\"chunkName\"]=\"=Module:Mod_name\"}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:1;}}")
|
||||
.Test_Module_GetInitChunk("Module:Mod_name", mod_text, 1)
|
||||
;
|
||||
}
|
||||
@Test public void Module_GetInitChunk_tabs() { // PURPOSE: swap out xowa's 	 with literal tabs, else will break lua
|
||||
fxt .Expd_server_rcvd_add("0000004500000089{[\"op\"]=\"loadString\",[\"text\"]=\"" + "a\tb" + "\",[\"chunkName\"]=\"=Module:Mod_name\"}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:1;}}")
|
||||
.Test_Module_GetInitChunk("Module:Mod_name", "a	b", 1)
|
||||
;
|
||||
}
|
||||
@Test public void ExecuteModule() {
|
||||
fxt .Init_lib_mw();
|
||||
fxt .Expd_server_rcvd_add("0000003E0000007B{[\"op\"]=\"call\",[\"id\"]=8,[\"nargs\"]=1,[\"args\"]={[1]=chunks[14]}}")
|
||||
.Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;a:2:{s:5:\"prc_0\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:15;}s:5:\"prc_1\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:16;}}}}")
|
||||
.Test_ExecuteModule(14, fxt.kv_func_("prc_0", 15), fxt.kv_func_("prc_1", 16))
|
||||
;
|
||||
}
|
||||
// @Test public void Invoke() {
|
||||
// fxt .Init_lib_mw();
|
||||
// fxt .Init_cbks_add("getExpandedArgument", gplx.xowa.xtns.scribunto.libs.Scrib_lib_mw.Proc_getExpandedArgument);
|
||||
// fxt .Expd_server_rcvd_add("0000004900000091{[\"op\"]=\"loadString\",[\"text\"]=\"Mod_0_code\",[\"chunkName\"]=\"=Module:Mod_0\"}")
|
||||
// .Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:13;}}") // NOTE: 13=id of "Module:Mod_0"
|
||||
// .Expd_server_rcvd_add("0000003E0000007B{[\"op\"]=\"call\",[\"id\"]=8,[\"nargs\"]=1,[\"args\"]={[1]=chunks[13]}}") // NOTE: 8=executeModule; 13=id of "Module:Mod_0"
|
||||
// .Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;a:1:{s:5:\"Prc_0\";O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:14;}}}}") // NOTE: 14=id of "Prc_0"
|
||||
// .Expd_server_rcvd_add("0000003E0000007B{[\"op\"]=\"call\",[\"id\"]=9,[\"nargs\"]=1,[\"args\"]={[1]=chunks[14]}}") // NOTE: 9=executeFunction; 14=id of "Prc_0"
|
||||
// .Init_server_prep_add("a:4:{s:2:\"id\";s:32:\"mw_interface-getExpandedArgument\";s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:2;s:4:\"args\";a:2:{i:1;s:7:\"current\";i:2;s:1:\"1\";}}")
|
||||
// .Expd_server_rcvd_add("000000380000006F{[\"op\"]=\"return\",[\"nvalues\"]=1,[\"values\"]={[1]=\"arg_0\"}}")
|
||||
// .Init_server_prep_add("a:4:{s:2:\"id\";s:32:\"mw_interface-getExpandedArgument\";s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:2;s:4:\"args\";a:2:{i:1;s:7:\"current\";i:2;s:1:\"2\";}}")
|
||||
// .Expd_server_rcvd_add("000000380000006F{[\"op\"]=\"return\",[\"nvalues\"]=1,[\"values\"]={[1]=\"arg_1\"}}")
|
||||
// .Init_server_prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:11:\"arg_0,arg_1\";}}")
|
||||
// .Test_Invoke("Mod_0", "Mod_0_code", "Prc_0", Scrib_kv_utl_.base1_many_("arg_0", "arg_1"))
|
||||
// ;
|
||||
// }
|
||||
String Mod_basic() {
|
||||
return String_.Concat
|
||||
( "local p = {}"
|
||||
, "function p.noop(frame)"
|
||||
, "end"
|
||||
, "return p"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_err_filter_mgr implements Gfo_invk {
|
||||
private final Ordered_hash hash_by_mod = Ordered_hash_.New();
|
||||
public void Clear() {hash_by_mod.Clear();}
|
||||
public boolean Count_eq_0() {return hash_by_mod.Count() == 0;}
|
||||
public boolean Match(String mod, String fnc, String err) {
|
||||
List_adp itms = Get_itms_or_null(mod, fnc); if (itms == null) return false;
|
||||
int itms_len = itms.Count();
|
||||
boolean match = false;
|
||||
for (int i = 0; i < itms_len; ++i) {
|
||||
Scrib_err_filter_itm itm = (Scrib_err_filter_itm)itms.Get_at(i);
|
||||
if (String_.Has(err, itm.Err())) {
|
||||
match = true;
|
||||
itm.Count_actl_add_1();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
public void Add(int count_expd, String mod, String fnc, String err, String comment) {
|
||||
List_adp itms = Get_itms_or_null(mod, fnc);
|
||||
if (itms == null) itms = New_itms(mod, fnc);
|
||||
itms.Add(new Scrib_err_filter_itm(count_expd, mod, fnc, err, comment));
|
||||
}
|
||||
public String Print() {
|
||||
Bry_bfr bfr = Bry_bfr_.New_w_size(8);
|
||||
int i_len = hash_by_mod.Count();
|
||||
for (int i = 0; i < i_len; ++i) {
|
||||
Ordered_hash fncs = (Ordered_hash)hash_by_mod.Get_at(i);
|
||||
int j_len = fncs.Count();
|
||||
for (int j = 0; j < j_len; ++j) {
|
||||
List_adp errs = (List_adp)fncs.Get_at(j);
|
||||
int k_len = errs.Count();
|
||||
for (int k = 0; k < k_len; ++k) {
|
||||
Scrib_err_filter_itm err = (Scrib_err_filter_itm)errs.Get_at(k);
|
||||
bfr.Add_int_variable(err.Count_actl()).Add_byte_pipe().Add_int_variable(err.Count_expd())
|
||||
.Add_byte_pipe().Add_str_u8(err.Mod()).Add_byte_pipe().Add_str_u8(err.Fnc()).Add_byte_pipe().Add_str_u8(err.Err())
|
||||
.Add_byte_pipe().Add_str_u8(err.Comment())
|
||||
.Add_byte_nl();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
private List_adp Get_itms_or_null(String mod, String fnc) {
|
||||
Ordered_hash hash_by_fnc = (Ordered_hash)hash_by_mod.Get_by(mod); if (hash_by_fnc == null) return null;
|
||||
return (List_adp)hash_by_fnc.Get_by(fnc);
|
||||
}
|
||||
private List_adp New_itms(String mod, String fnc) {
|
||||
Ordered_hash hash_by_fnc = (Ordered_hash)hash_by_mod.Get_by(mod);
|
||||
if (hash_by_fnc == null) {
|
||||
hash_by_fnc = Ordered_hash_.New();
|
||||
hash_by_mod.Add(mod, hash_by_fnc);
|
||||
}
|
||||
List_adp list_of_err = (List_adp)hash_by_fnc.Get_by(fnc);
|
||||
if (list_of_err == null) {
|
||||
list_of_err = List_adp_.New();
|
||||
hash_by_fnc.Add(fnc, list_of_err);
|
||||
}
|
||||
return list_of_err;
|
||||
}
|
||||
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
||||
if (ctx.Match(k, Invk_add)) Add(m.ReadInt("count_expd"), m.ReadStr("mod"), m.ReadStr("fnc"), m.ReadStr("err"), m.ReadStr("comment"));
|
||||
else return Gfo_invk_.Rv_unhandled;
|
||||
return this;
|
||||
} private static final String Invk_add = "add";
|
||||
}
|
||||
class Scrib_err_filter_itm {
|
||||
public Scrib_err_filter_itm(int count_expd, String mod, String fnc, String err, String comment) {this.count_expd = count_expd; this.mod = mod; this.err = err; this.fnc = fnc; this.comment = comment;}
|
||||
public String Mod() {return mod;} private final String mod;
|
||||
public String Fnc() {return fnc;} private final String fnc;
|
||||
public String Err() {return err;} private final String err;
|
||||
public String Comment() {return comment;} private final String comment;
|
||||
public int Count_expd() {return count_expd;} private final int count_expd;
|
||||
public int Count_actl() {return count_actl;} private int count_actl;
|
||||
public void Count_actl_add_1() {++count_actl;}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_err_filter_mgr_tst {
|
||||
@Before public void init() {fxt.Clear();} private final Scrib_err_filter_mgr_fxt fxt = new Scrib_err_filter_mgr_fxt();
|
||||
@Test public void Basic() {
|
||||
fxt.Exec_add(11, "Mod_1", "Fnc_1", "Err_11", "Comm_11");
|
||||
fxt.Exec_add(12, "Mod_1", "Fnc_2", "Err_12", "Comm_12");
|
||||
fxt.Exec_add(21, "Mod_2", "Fnc_1", "Err_21", "Comm_21");
|
||||
fxt.Test_match_y("Mod_1", "Fnc_2", "Err_12a");
|
||||
fxt.Test_match_y("Mod_2", "Fnc_1", "Err_21a");
|
||||
fxt.Test_match_n("Mod_1", "Fnc_1", "x");
|
||||
fxt.Test_match_n("Mod_1", "Fnc_3", "x");
|
||||
fxt.Test_match_n("Mod_3", "Fnc_1", "x");
|
||||
fxt.Test_print(String_.Concat_lines_nl
|
||||
( "0|11|Mod_1|Fnc_1|Err_11|Comm_11"
|
||||
, "1|12|Mod_1|Fnc_2|Err_12|Comm_12"
|
||||
, "1|21|Mod_2|Fnc_1|Err_21|Comm_21"
|
||||
));
|
||||
}
|
||||
}
|
||||
class Scrib_err_filter_mgr_fxt {
|
||||
private final Scrib_err_filter_mgr err_mgr = new Scrib_err_filter_mgr();
|
||||
public void Clear() {err_mgr.Clear();}
|
||||
public void Exec_add(int expd, String mod, String fnc, String err, String comment) {err_mgr.Add(expd, mod, fnc, err, comment);}
|
||||
public void Test_match_y(String mod, String fnc, String err) {Test_match(Bool_.Y, mod, fnc, err);}
|
||||
public void Test_match_n(String mod, String fnc, String err) {Test_match(Bool_.N, mod, fnc, err);}
|
||||
private void Test_match(boolean expd, String mod, String fnc, String err) {
|
||||
Tfds.Eq(expd, err_mgr.Match(mod, fnc, err));
|
||||
}
|
||||
public void Test_print(String expd) {
|
||||
Tfds.Eq_str_lines(expd, err_mgr.Print());
|
||||
}
|
||||
}
|
||||
44
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_frame_.java
Normal file
44
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_frame_.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.parsers.tmpls.*;
|
||||
public class Scrib_frame_ {
|
||||
public static final byte Tid_null = 0, Tid_current = 1, Tid_parent = 2, Tid_dynamic = 3;
|
||||
public static final int Arg_adj_current = 1, Arg_adj_owner = 0;
|
||||
public static int Get_frame_tid(String frame_id) {
|
||||
if (String_.Eq(frame_id, "current")) return Tid_current;
|
||||
else if (String_.Eq(frame_id, "parent")) return Tid_parent;
|
||||
else return Tid_dynamic;
|
||||
}
|
||||
public static Xot_invk Get_frame(Scrib_core core, String frame_id) {
|
||||
if (String_.Eq(frame_id, "current")) return core.Frame_current();
|
||||
else if (String_.Eq(frame_id, "parent")) return core.Frame_parent();
|
||||
else if (String_.Eq(frame_id, "empty")) return Xot_invk_mock.new_(core.Frame_current().Defn_tid(), 0, null, Keyval_.Ary_empty); // not sure if it should return null title; DATE:2014-07-12
|
||||
else {
|
||||
return (Xot_invk)core.Frame_created_list().Get_by(frame_id); // NOTE: can return null; some calls expect nil; EX:mw.lua and "currentFrame = newFrame( 'empty' )"; DATE:2014-07-12
|
||||
}
|
||||
}
|
||||
public static int Get_arg_adj(byte frame_tid) {
|
||||
if (frame_tid == Tid_current) return 1; // arg_0 is at idx_1 b/c Module frames use 1 arg for name of proc; EX: {{#invoke:module|proc|arg_0}}
|
||||
else return 0; // arg_0 is at idx_0; EX: {{template|arg_0}}
|
||||
}
|
||||
public static Xot_invk Get_parent(Scrib_core core, byte frame_tid) {
|
||||
if (frame_tid == Tid_current) return core.Frame_parent(); // current frame has an owner frame
|
||||
else return Xot_invk_mock.Null; // all other frames do not
|
||||
}
|
||||
}
|
||||
62
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_fsys_mgr.java
Normal file
62
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_fsys_mgr.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_fsys_mgr {
|
||||
private Ordered_hash libs;
|
||||
private Io_url[] lib_dirs = new Io_url[lib_dirs_len]; static final int lib_dirs_len = 3;
|
||||
public Io_url Root_dir() {return root_dir;} private Io_url root_dir;
|
||||
public Io_url Script_dir() {return script_dir;} private Io_url script_dir;
|
||||
public void Root_dir_(Io_url v) {
|
||||
root_dir = v;
|
||||
script_dir = root_dir.GenSubDir_nest("engines", "LuaCommon", "lualib");
|
||||
lib_dirs[0] = script_dir;
|
||||
lib_dirs[1] = script_dir.GenSubDir("luabit");
|
||||
lib_dirs[2] = script_dir.GenSubDir("ustring");
|
||||
}
|
||||
public String Get_or_null(String name) {
|
||||
if (libs == null) libs = libs_init(script_dir);
|
||||
Object lib_fil_obj = libs.Get_by(name); if (lib_fil_obj == null) return null;
|
||||
gplx.core.ios.Io_fil lib_fil = (gplx.core.ios.Io_fil)lib_fil_obj;
|
||||
String lib_data = lib_fil.Data();
|
||||
if (lib_data == null) {
|
||||
lib_data = Io_mgr.Instance.LoadFilStr(lib_fil.Url());
|
||||
lib_fil.Data_(lib_data);
|
||||
}
|
||||
return lib_data;
|
||||
}
|
||||
private static Ordered_hash libs_init(Io_url script_dir) {
|
||||
Ordered_hash rv = Ordered_hash_.New();
|
||||
Io_url[] fils = Io_mgr.Instance.QueryDir_args(script_dir).Recur_().ExecAsUrlAry();
|
||||
int fils_len = fils.length;
|
||||
for (int i = 0; i < fils_len; i++) {
|
||||
Io_url fil = fils[i];
|
||||
if (!String_.Eq(fil.Ext(), ".lua")) continue; // ignore readme.txt, readme
|
||||
gplx.core.ios.Io_fil fil_itm = new gplx.core.ios.Io_fil(fil, null);
|
||||
rv.Add_if_dupe_use_1st(fil.NameOnly(), fil_itm);
|
||||
rv.Add_if_dupe_use_1st(String_.Replace(String_.DelEndIf(fil.GenRelUrl_orEmpty(script_dir), ".lua"), "\\", "/"), fil_itm);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void Shrink() {
|
||||
int len = libs.Count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
gplx.core.ios.Io_fil fil = (gplx.core.ios.Io_fil)libs.Get_at(i);
|
||||
fil.Url_(null).Data_(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_fsys_mgr_tst {
|
||||
@Before public void init() {fxt.Clear();} private Scrib_fsys_mgr_fxt fxt = new Scrib_fsys_mgr_fxt();
|
||||
@Test public void Basic() {
|
||||
fxt.Init("mem/xowa/"
|
||||
, "mw.lua"
|
||||
, "mw.ustring.lua"
|
||||
, "ustring/ustring.lua"
|
||||
, "ustring/normalization-data.lua"
|
||||
, "ustring/README"
|
||||
);
|
||||
fxt.Test_exists_y("mw", "mw.ustring", "ustring", "ustring/normalization-data");
|
||||
fxt.Test_exists_n("README");
|
||||
}
|
||||
}
|
||||
class Scrib_fsys_mgr_fxt {
|
||||
private Scrib_fsys_mgr fsys_mgr;
|
||||
public void Clear() {
|
||||
Io_mgr.Instance.InitEngine_mem();
|
||||
fsys_mgr = new Scrib_fsys_mgr();
|
||||
}
|
||||
public Scrib_fsys_mgr_fxt Init(String root_dir, String... rel_paths) {
|
||||
Io_url root_url = Io_url_.mem_dir_(root_dir);
|
||||
fsys_mgr.Root_dir_(root_url);
|
||||
Io_url script_dir = fsys_mgr.Script_dir();
|
||||
int rel_paths_len = rel_paths.length;
|
||||
for (int i = 0; i < rel_paths_len; i++) {
|
||||
String rel_path = rel_paths[i];
|
||||
Io_url fil_url = script_dir.GenSubFil(rel_path);
|
||||
Io_mgr.Instance.SaveFilStr(fil_url, fil_url.Raw());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Scrib_fsys_mgr_fxt Test_exists_y(String... keys) {Test_exists(Bool_.Y, keys); return this;}
|
||||
public Scrib_fsys_mgr_fxt Test_exists_n(String... keys) {Test_exists(Bool_.N, keys); return this;}
|
||||
private void Test_exists(boolean expd, String[] keys) {
|
||||
int keys_len = keys.length;
|
||||
for (int i = 0; i < keys_len; i++) {
|
||||
String key = keys[i];
|
||||
String code = fsys_mgr.Get_or_null(key);
|
||||
Tfds.Eq(expd, code != null, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func.java
Normal file
90
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.core.brys.fmtrs.*; import gplx.core.envs.*;
|
||||
import gplx.langs.htmls.*;
|
||||
import gplx.xowa.langs.kwds.*; import gplx.xowa.langs.msgs.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.htmls.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.logs.*; import gplx.xowa.parsers.tmpls.*;
|
||||
import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Scrib_invoke_func extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_invoke;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Scrib_invoke_func().Name_(name);}
|
||||
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) {// {{#invoke:mod_name|prc_name|prc_args...}}
|
||||
Xowe_wiki wiki = ctx.Wiki();
|
||||
byte[] mod_name = Eval_argx(ctx, src, caller, self);
|
||||
if (Bry_.Len_eq_0(mod_name)) {Error(bfr, wiki.Msg_mgr(), Err_mod_missing); return;} // EX: "{{#invoke:}}"
|
||||
int args_len = self.Args_len();
|
||||
byte[] fnc_name = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, null);
|
||||
Xop_log_invoke_wkr invoke_wkr = ctx.Xtn__scribunto__invoke_wkr();
|
||||
long log_time_bgn = 0;
|
||||
if (invoke_wkr != null) {
|
||||
log_time_bgn = System_.Ticks();
|
||||
if (!invoke_wkr.Eval_bgn(ctx.Page(), mod_name, fnc_name)) return;
|
||||
}
|
||||
Scrib_core core = wiki.Parser_mgr().Scrib().Core();
|
||||
if (core == null) {
|
||||
synchronized (this) {
|
||||
core = wiki.Parser_mgr().Scrib().Core_init(ctx);
|
||||
core.Init();
|
||||
core.When_page_changed(ctx.Page());
|
||||
}
|
||||
}
|
||||
byte[] mod_raw = null;
|
||||
Scrib_lua_mod mod = core.Mods_get(mod_name);
|
||||
if (mod == null) {
|
||||
Xow_ns module_ns = wiki.Ns_mgr().Ids_get_or_null(Xow_ns_.Tid__module);
|
||||
Xoa_ttl mod_ttl = Xoa_ttl.Parse(wiki, Bry_.Add(module_ns.Name_db_w_colon(), mod_name));
|
||||
mod_raw = wiki.Cache_mgr().Page_cache().Get_or_load_as_src(mod_ttl);
|
||||
if (mod_raw == null) {Error(bfr, wiki.Msg_mgr(), Err_mod_missing); return;} // EX: "{{#invoke:missing_mod}}"
|
||||
}
|
||||
else
|
||||
mod_raw = mod.Text_bry();
|
||||
if (!core.Enabled()) {bfr.Add_mid(src, self.Src_bgn(), self.Src_end()); return;}
|
||||
try {
|
||||
core.Invoke(wiki, ctx, src, caller, self, bfr, mod_name, mod_raw, fnc_name);
|
||||
if (invoke_wkr != null)
|
||||
invoke_wkr.Eval_end(ctx.Page(), mod_name, fnc_name, log_time_bgn);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Err err = Err_.Cast_or_make(e);
|
||||
Error(bfr, wiki.Msg_mgr(), err);
|
||||
Scrib_err_filter_mgr err_filter_mgr = invoke_wkr == null ? null : invoke_wkr.Err_filter_mgr();
|
||||
if ( err_filter_mgr == null // no err_filter_mgr defined;
|
||||
|| err_filter_mgr.Count_eq_0( ) // err_filter_mgr exists, but no definitions
|
||||
|| !err_filter_mgr.Match(String_.new_u8(mod_name), String_.new_u8(fnc_name), err.To_str__msg_only())) // NOTE: must be To_str__msg_only; err_filter_mgr has defintion and it doesn't match current; print warn; DATE:2015-07-24
|
||||
ctx.App().Usr_dlg().Warn_many("", "", "invoke failed: ~{0} ~{1} ~{2}", ctx.Page().Ttl().Raw(), Bry_.Replace_nl_w_tab(src, self.Src_bgn(), self.Src_end()), err.To_str__log());
|
||||
wiki.Parser_mgr().Scrib().Terminate_when_page_changes_y_(); // NOTE: terminate core when page changes; not terminating now, else page with many errors will be very slow due to multiple remakes of core; PAGE:th.d:all; DATE:2014-10-03
|
||||
}
|
||||
}
|
||||
public static void Error(Bry_bfr bfr, Xow_msg_mgr msg_mgr, Err err) {Error(bfr, msg_mgr, Err_.Cast_or_make(err).To_str__top_wo_args());}// NOTE: must use "short" error message to show in wikitext; DATE:2015-07-27
|
||||
public static void Error(Bry_bfr bfr, Xow_msg_mgr msg_mgr, String error) {
|
||||
// for Luaj, msg combines both err; split out traceback else error message will be very long; note that Warn_many will still log traceback; DATE:2016-09-09
|
||||
String error_visible = error;
|
||||
int traceback_pos = String_.FindFwd(error, "\nstack traceback:\n"); // NOTE: produced by LuaError.getMessage()
|
||||
if (traceback_pos != String_.Find_none)
|
||||
error_visible = String_.Mid(error_visible, 0, traceback_pos);
|
||||
|
||||
// write "Script error: some error"
|
||||
byte[] script_error_msg = msg_mgr.Val_by_id(Xol_msg_itm_.Id_scribunto_parser_error);
|
||||
error_fmtr.Bld_bfr_many(bfr, script_error_msg, error_visible);
|
||||
}
|
||||
private static final Bry_fmtr error_fmtr = Bry_fmtr.new_("<strong class=\"error\"><span class=\"scribunto-error\" id=\"mw-scribunto-error-0\">~{0}: ~{1}</span></strong>"); // NOTE: must be "error" not 'error'; iferror checks for quote not apos; DATE:2015-09-17
|
||||
public static final String Err_mod_missing = "No such module";
|
||||
}
|
||||
238
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func_fxt.java
Normal file
238
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func_fxt.java
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.xtns.scribunto.libs.*; import gplx.xowa.xtns.scribunto.engines.process.*; import gplx.xowa.xtns.scribunto.procs.*;
|
||||
import gplx.xowa.parsers.tmpls.*;
|
||||
public class Scrib_invoke_func_fxt {
|
||||
private Xop_fxt fxt; Bry_bfr tmp_bfr = Bry_bfr_.Reset(255); Scrib_core core; Process_server_mock server; Scrib_lua_rsp_bldr rsp_bldr = new Scrib_lua_rsp_bldr();
|
||||
public Xop_fxt Parser_fxt() {return fxt;}
|
||||
public Scrib_core_fxt Core_fxt() {return core_fxt;} Scrib_core_fxt core_fxt;
|
||||
public Scrib_core Core() {return core;}
|
||||
public void Clear_for_invoke() {
|
||||
fxt = new Xop_fxt(); // NOTE: don't try to cache fxt on func_fxt level; causes errors in Language_lib
|
||||
core_fxt = new Scrib_core_fxt(fxt);
|
||||
core_fxt.Clear();
|
||||
core_fxt.Init_lib_mw();
|
||||
core = core_fxt.Core();
|
||||
server = core_fxt.Server();
|
||||
core.Interpreter().Server_(server);
|
||||
Io_mgr.Instance.InitEngine_mem();
|
||||
fxt.Reset();
|
||||
core.When_page_changed(fxt.Page());
|
||||
init_tmpl = init_page = null;
|
||||
fxt.Init_page_create("Module:Mod_0");
|
||||
this.Init_lua_rcvd_loadModule();
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_cbk(String lib_name, Scrib_lib lib, String... proc_names) {
|
||||
int len = proc_names.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
String proc_name = proc_names[i];
|
||||
Scrib_proc proc = lib.Procs().Get_by_key(proc_name);
|
||||
core.Proc_mgr().Set(proc.Proc_key(), proc); // NOTE: allow tests to call Init_cbk multiple times
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_tmpl(String v) {init_tmpl = v; return this;} private String init_tmpl;
|
||||
public Scrib_invoke_func_fxt Init_page(String v) {init_page = v; return this;} private String init_page;
|
||||
public Scrib_invoke_func_fxt Init_server_print_key_y_() {server.Print_key_(true); return this;}
|
||||
public Scrib_invoke_func_fxt Init_server_print_key_n_() {server.Print_key_(false); return this;}
|
||||
public Scrib_invoke_func_fxt Init_lua_rcvd_raw(String raw) {server.Prep_add(raw); return this;}
|
||||
public Scrib_invoke_func_fxt Init_lua_rcvd(String cbk_name, Keyval... ary) {
|
||||
server.Prep_add(rsp_bldr.Bld_mw_cbk(cbk_name, ary));
|
||||
return this;
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_lua_module() {
|
||||
server.Prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:2:{i:1;b:1;i:2;O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:14;}}}");
|
||||
return this;
|
||||
}
|
||||
private Scrib_invoke_func_fxt Init_lua_rcvd_loadModule() {
|
||||
server.Prep_add("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;i:1;}}");
|
||||
return this;
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_lua_rcvd_preprocess(String frame, String cmd) {
|
||||
server.Prep_add(String_.Concat_any("a:4:{s:2:\"id\";s:23:\"mw_interface-preprocess\";s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:2;s:4:\"args\";a:2:{i:1;s:", String_.Len(frame), ":\"", frame, "\";i:2;s:", String_.Len(cmd), ":\"", cmd, "\";}}"));
|
||||
this.Init_lua_rcvd_rv();
|
||||
return this;
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_lua_rcvd_expandTemplate(String frame, String tmpl_ttl, Keyval... ary) {
|
||||
ary = new Keyval[] {Keyval_.int_(1, "current"), Keyval_.int_(2, tmpl_ttl), Keyval_.int_(3, ary)};
|
||||
server.Prep_add(rsp_bldr.Bld_mw_cbk("expandTemplate", ary));
|
||||
this.Init_lua_rcvd_rv();
|
||||
return this;
|
||||
}
|
||||
public Scrib_invoke_func_fxt Init_lua_rcvd_rv() {
|
||||
server.Prep_add_dynamic_val();
|
||||
return this;
|
||||
}
|
||||
public void Test_invoke(String expd) {
|
||||
if (init_tmpl != null) fxt.Init_defn_add("test", init_tmpl);
|
||||
fxt.Test_parse_tmpl_str(init_page, expd);
|
||||
}
|
||||
public void Test_parse_err(String raw, String expd_err_type) {
|
||||
Scrib_invoke_func.Error(tmp_bfr, fxt.Wiki().Msg_mgr(), expd_err_type);
|
||||
fxt.Test_parse_page_tmpl_str(raw, tmp_bfr.To_str_and_clear());
|
||||
}
|
||||
public void Test_error(Exception e, String expd) {
|
||||
Scrib_invoke_func.Error(tmp_bfr, fxt.Wiki().Msg_mgr(), Err_.Cast_or_make(e));
|
||||
Tfds.Eq_str(expd, tmp_bfr.To_str_and_clear(), "error");
|
||||
}
|
||||
public void Test_lib_proc(Scrib_lib lib, String func_name, Object[] args, String expd) {Test_lib_proc_kv(lib, func_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_lib_proc_kv(Scrib_lib lib, String func_name, Keyval[] args, String expd) {
|
||||
Test_lib_proc_internal(lib, func_name, args);
|
||||
this.Test_invoke(expd);
|
||||
}
|
||||
private void Test_lib_proc_internal(Scrib_lib lib, String func_name, Keyval[] args) {
|
||||
Init_lua_module();
|
||||
this.Init_cbk(Scrib_core.Key_mw_interface, lib, func_name);
|
||||
this.Init_lua_rcvd(func_name, args);
|
||||
this.Init_lua_rcvd_rv();
|
||||
}
|
||||
public void Test_log_rcvd(int i, String expd) {
|
||||
Tfds.Eq(expd, (String)server.Log_rcvd().Get_at(i));
|
||||
}
|
||||
public void Init_frame_parent(String ttl, Keyval... ary) {
|
||||
core.Frame_parent_(Xot_invk_mock.test_(Bry_.new_u8(ttl), ary));
|
||||
}
|
||||
public void Init_frame_current(Keyval... ary) {
|
||||
core.Frame_current_(Xot_invk_mock.test_(Bry_.new_a7("Module:Mod_0"), ary));
|
||||
}
|
||||
public void Clear_for_lib() {Clear_for_lib("en.wikipedia.org", "en");}
|
||||
public void Clear_for_lib(String domain, String lang) {
|
||||
Xoae_app app = Xoa_app_fxt.Make__app__edit();
|
||||
fxt = new Xop_fxt(app, Xoa_app_fxt.Make__wiki__edit(app, domain, app.Lang_mgr().Get_by_or_new(Bry_.new_u8(lang)))); // NOTE: don't try to cache fxt on func_fxt level; causes errors in Language_lib
|
||||
core_fxt = new Scrib_core_fxt(fxt);
|
||||
core = core_fxt.Core();
|
||||
Xot_invk parent_frame = new Xot_invk_temp(true); parent_frame.Frame_tid_(Scrib_frame_.Tid_null);
|
||||
Xot_invk current_frame = Xot_invk_mock.test_(Bry_.new_a7("Module:Mod_0"));
|
||||
core.Invoke_init(core.Wiki(), core.Ctx(), Bry_.Empty, parent_frame, current_frame);
|
||||
core.When_page_changed(fxt.Page());
|
||||
}
|
||||
public void Test_scrib_proc_str(Scrib_lib lib, String proc_name, Object[] args, String expd) {Test_scrib_proc_str(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_scrib_proc_str(Scrib_lib lib, String proc_name, Keyval[] args, String expd) {
|
||||
Keyval[] actl = Test__lib_proc__core(lib, proc_name, args);
|
||||
Tfds.Eq(Object_.Xto_str_strict_or_null_mark(expd), Object_.Xto_str_strict_or_null_mark(actl[0].Val()));
|
||||
}
|
||||
public void Test__proc__kvps__flat(Scrib_lib lib, String proc_name, Object[] args, String expd) {Test__proc__kvps__flat(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test__proc__kvps__flat(Scrib_lib lib, String proc_name, Keyval[] args, String expd) {
|
||||
Keyval[] actl_ary = Test__lib_proc__core(lib, proc_name, args);
|
||||
Tfds.Eq(expd, Kv_ary_to_kv_vals_str(actl_ary));
|
||||
}
|
||||
public void Test_scrib_proc_kv_objs(Scrib_lib lib, String proc_name, Keyval[] args, Object... expd_ary) {
|
||||
Keyval[] actl_kvs = Test__lib_proc__core(lib, proc_name, args);
|
||||
Object[] actl_ary = KeyVal_to_obj_ary(actl_kvs);
|
||||
Tfds.Eq_ary(expd_ary, actl_ary);
|
||||
}
|
||||
public void Test_scrib_proc_err(Scrib_lib lib, String proc_name, Object[] args, String expd) {
|
||||
Scrib_proc proc = lib.Procs().Get_by_key(proc_name);
|
||||
Scrib_proc_rslt rslt = new Scrib_proc_rslt();
|
||||
boolean exec_rslt = proc.Proc_exec(new Scrib_proc_args(Scrib_kv_utl_.base1_many_(args)), rslt);
|
||||
Tfds.Eq(Bool_.N, exec_rslt);
|
||||
Tfds.Eq(null, rslt.Ary());
|
||||
Tfds.Eq(expd, rslt.Fail_msg());
|
||||
}
|
||||
private static Object[] KeyVal_to_obj_ary(Keyval[] kv_ary) {
|
||||
int len = kv_ary.length;
|
||||
Object[] rv = new Object[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval kv = kv_ary[i];
|
||||
rv[i] = kv.Val();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private String Kv_ary_to_kv_vals_str(Keyval[] ary) {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Semic);
|
||||
Keyval kv = ary[i];
|
||||
bfr.Add_str_u8(Object_.Xto_str_strict_or_null_mark(kv.Val()));
|
||||
}
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
public void Test_scrib_proc_bool(Scrib_lib lib, String proc_name, Object[] args, boolean expd) {Test_scrib_proc_obj(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_scrib_proc_int(Scrib_lib lib, String proc_name, Object[] args, int expd) {Test_scrib_proc_obj(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_scrib_proc_obj(Scrib_lib lib, String proc_name, Object[] args, Object expd) {Test_scrib_proc_obj(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_scrib_proc_obj(Scrib_lib lib, String proc_name, Keyval[] args, Object expd) {
|
||||
Keyval[] actl = Test__lib_proc__core(lib, proc_name, args);
|
||||
Tfds.Eq(expd, actl[0].Val());
|
||||
}
|
||||
public void Test_scrib_proc_empty(Scrib_lib lib, String proc_name, Object[] args) {Test_scrib_proc_empty(lib, proc_name, Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test_scrib_proc_empty(Scrib_lib lib, String proc_name, Keyval[] args) {
|
||||
Keyval[] actl = Test__lib_proc__core(lib, proc_name, args);
|
||||
Tfds.Eq(0, actl.length);
|
||||
}
|
||||
public void Test_scrib_proc_str_ary(Scrib_lib lib, String proc_name, Object[] args, String expd) {Test_scrib_proc_str_ary(lib, proc_name, Scrib_kv_utl_.base1_many_(args), expd);}
|
||||
public void Test_scrib_proc_str_ary(Scrib_lib lib, String proc_name, Keyval[] args, String expd) {
|
||||
Keyval[] actl_ary = Test__lib_proc__core(lib, proc_name, args);
|
||||
String actl = Keyval_.Ary__to_str__nest(actl_ary);
|
||||
Tfds.Eq_str_lines(expd, actl);
|
||||
}
|
||||
public Keyval[] Test_scrib_proc_rv_as_kv_ary(Scrib_lib lib, String proc_name, Object[] args) {
|
||||
Keyval[] actl = Test__lib_proc__core(lib, proc_name, Scrib_kv_utl_.base1_many_(args));
|
||||
return (Keyval[])actl[0].Val();
|
||||
}
|
||||
public Object Test_scrib_proc_rv_as_obj(Scrib_lib lib, String proc_name, Object[] args) {
|
||||
Keyval[] actl = Test__lib_proc__core(lib, proc_name, Scrib_kv_utl_.base1_many_(args));
|
||||
return actl[0].Val();
|
||||
}
|
||||
private Keyval[] Test__lib_proc__core(Scrib_lib lib, String proc_name, Keyval[] args) {
|
||||
Scrib_proc proc = lib.Procs().Get_by_key(proc_name);
|
||||
Scrib_proc_rslt proc_rslt = new Scrib_proc_rslt();
|
||||
proc.Proc_exec(new Scrib_proc_args(args), proc_rslt);
|
||||
return proc_rslt.Ary();
|
||||
}
|
||||
public static final String Null_rslt = "<<NULL>>";
|
||||
public static final String Null_rslt_ary = "1=<<NULL>>";
|
||||
}
|
||||
class Scrib_lua_rsp_bldr {
|
||||
Bry_bfr bfr = Bry_bfr_.Reset(255);
|
||||
public String Bld_mw_cbk(String cbk_name, Keyval... ary) {
|
||||
cbk_name = "mw_interface-" + cbk_name;
|
||||
bfr.Add_str_a7("a:4:{s:2:\"id\";");
|
||||
Bld_str(bfr, cbk_name);
|
||||
bfr.Add_str_a7("s:2:\"op\";s:4:\"call\";s:5:\"nargs\";i:3;s:4:\"args\";");
|
||||
Bld_kv_ary(bfr, ary);
|
||||
bfr.Add_str_a7("}");
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
private void Bld_obj(Bry_bfr bfr, Object v) {
|
||||
Class<?> v_type = v.getClass();
|
||||
if (Object_.Eq(v_type, Int_.Cls_ref_type)) Bld_int(bfr, Int_.cast(v));
|
||||
else if (Object_.Eq(v_type, String_.Cls_ref_type)) Bld_str(bfr, String_.cast(v));
|
||||
else if (Object_.Eq(v_type, Bool_.Cls_ref_type)) Bld_bool(bfr, Bool_.Cast(v));
|
||||
else if (Object_.Eq(v_type, Double_.Cls_ref_type)) Bld_double(bfr, Double_.cast(v));
|
||||
else if (Object_.Eq(v_type, Keyval[].class)) Bld_kv_ary(bfr, (Keyval[])v);
|
||||
else if (Object_.Eq(v_type, Scrib_lua_proc.class)) Bld_fnc(bfr, (Scrib_lua_proc)v);
|
||||
else throw Err_.new_unhandled(Type_adp_.NameOf_obj(v));
|
||||
}
|
||||
private void Bld_bool(Bry_bfr bfr, boolean v) {bfr.Add_str_a7("b:").Add_int_fixed(v ? 1 : 0, 1).Add_byte(Byte_ascii.Semic);}
|
||||
private void Bld_int(Bry_bfr bfr, int v) {bfr.Add_str_a7("i:").Add_int_variable(v).Add_byte(Byte_ascii.Semic);}
|
||||
private void Bld_double(Bry_bfr bfr, double v) {bfr.Add_str_a7("d:").Add_double(v).Add_byte(Byte_ascii.Semic);}
|
||||
private void Bld_str(Bry_bfr bfr, String v) {bfr.Add_str_a7("s:").Add_int_variable(Bry_.new_u8(v).length).Add_str_a7(":\"").Add_str_a7(v).Add_str_a7("\";");} // NOTE: must use Bry_.new_u8(v).length to calculate full bry len
|
||||
private void Bld_fnc(Bry_bfr bfr, Scrib_lua_proc v) {bfr.Add_str_a7("O:42:\"Scribunto_LuaStandaloneInterpreterFunction\":1:{s:2:\"id\";i:").Add_int_variable(v.Id()).Add_byte(Byte_ascii.Semic).Add_byte(Byte_ascii.Curly_end);}
|
||||
private void Bld_kv_ary(Bry_bfr bfr, Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
bfr.Add_str_a7("a:").Add_int_variable(len).Add_str_a7(":{");
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval kv = ary[i];
|
||||
Bld_obj(bfr, kv.Key_as_obj());
|
||||
Bld_obj(bfr, kv.Val());
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Curly_end);
|
||||
}
|
||||
}
|
||||
72
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_kv_utl_.java
Normal file
72
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_kv_utl_.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_kv_utl_ {
|
||||
public static Keyval[] base1_obj_(Object v) {return new Keyval[] {Keyval_.int_(0 + Scrib_core.Base_1, v)};}
|
||||
public static Keyval[] base1_many_(Object... vals) {
|
||||
int len = vals.length;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
rv[i] = Keyval_.int_(i + Scrib_core.Base_1, vals[i]);
|
||||
return rv;
|
||||
}
|
||||
public static Keyval[] base1_many_ary_(Object... vals) {
|
||||
int len = vals.length;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
rv[i] = Keyval_.int_(i + Scrib_core.Base_1, vals[i]);
|
||||
return rv;
|
||||
}
|
||||
public static Keyval[] base1_list_(List_adp list) {
|
||||
int len = list.Count();
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
rv[i] = Keyval_.int_(i + Scrib_core.Base_1, list.Get_at(i));
|
||||
list.Clear();
|
||||
return rv;
|
||||
}
|
||||
public static Keyval[] flat_many_(Object... vals) {
|
||||
int len = vals.length;
|
||||
Keyval[] rv = new Keyval[len / 2];
|
||||
for (int i = 0; i < len; i += 2)
|
||||
rv[i / 2] = Keyval_.obj_(vals[i], vals[i + 1]);
|
||||
return rv;
|
||||
}
|
||||
public static String Val_to_str(Keyval[] ary, int idx) {
|
||||
if (ary == null) throw Err_.new_wo_type("ary is null");
|
||||
int ary_len = ary.length;
|
||||
if (ary_len == 0 && idx == 0) return ""; // NOTE: Modules can throw exceptions in which return value is nothing; do not fail; return ""; EX: -logy; DATE:2013-10-14
|
||||
if (idx >= ary_len) throw Err_.new_wo_type("idx is not in bounds", "idx", idx, "len", Keyval_.Ary_to_str(ary));
|
||||
Object o = ary[idx].Val();
|
||||
try {return (String)o;}
|
||||
catch (Exception e) {throw Err_.new_cast(e, String.class, o);}
|
||||
}
|
||||
public static Keyval[] Val_to_KeyVal_ary(Keyval[] ary, int idx) {
|
||||
if (ary == null) throw Err_.new_wo_type("ary is null"); if (idx >= ary.length) throw Err_.new_wo_type("idx is not in bounds", "idx", idx, "len", Keyval_.Ary_to_str(ary));
|
||||
try {return (Keyval[])ary[idx].Val();}
|
||||
catch (Exception e) {throw Err_.new_exc(e, "scrib", "cast as Keyval[] failed", "ary", Keyval_.Ary_to_str(ary));}
|
||||
}
|
||||
public static Object Get_sub_by_key_or_null(Keyval[] ary, String key) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval sub = ary[i];
|
||||
if (String_.Eq(key, sub.Key())) return sub.Val();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
26
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib.java
Normal file
26
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public interface Scrib_lib {
|
||||
Scrib_proc_mgr Procs();
|
||||
Scrib_lib Init();
|
||||
Scrib_lua_mod Register(Scrib_core core, Io_url script_dir);
|
||||
boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt);
|
||||
Scrib_lib Clone_lib(Scrib_core core);
|
||||
}
|
||||
31
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib_mgr.java
Normal file
31
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib_mgr.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_lib_mgr {
|
||||
private List_adp list = List_adp_.New();
|
||||
public int Len() {return list.Count();}
|
||||
public void Add(Scrib_lib v) {list.Add(v); v.Init();}
|
||||
public Scrib_lib Get_at(int i) {return (Scrib_lib)list.Get_at(i);}
|
||||
public void Init_for_core(Scrib_core core, Io_url script_dir) {
|
||||
int len = list.Count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Scrib_lib lib = Get_at(i).Clone_lib(core);
|
||||
lib.Register(core, script_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_mod.java
Normal file
62
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_mod.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_lua_mod {
|
||||
private Ordered_hash hash = Ordered_hash_.New();
|
||||
public Scrib_lua_mod(Scrib_core core, String name) {this.name = name; this.core = core;} private Scrib_core core;
|
||||
public int Lua_id() {return lua_id;} private int lua_id = -1;
|
||||
public String Name() {return name;} private String name;
|
||||
public Scrib_lua_proc Init_chunk_func() {return init_chunk_func;} private Scrib_lua_proc init_chunk_func;
|
||||
public byte[] Text_bry() {return text_bry;} private byte[] text_bry;
|
||||
public void Fncs_clear() {hash.Clear();}
|
||||
public int Fncs_len() {return hash.Count();}
|
||||
public Scrib_lua_proc Fncs_get_at(int i) {return (Scrib_lua_proc)hash.Get_at(i);}
|
||||
public Scrib_lua_proc Fncs_get_by_key(String key) {return (Scrib_lua_proc)hash.Get_by(key);}
|
||||
public void Fncs_add(Scrib_lua_proc prc) {hash.Add(prc.Key(), prc);}
|
||||
public int Fncs_get_id(String key) {
|
||||
Scrib_lua_proc fnc = Fncs_get_by_key(key); if (fnc == null) throw Err_.new_wo_type("Scrb_fnc does not exist", "module", name, "func", key);
|
||||
return fnc.Id();
|
||||
}
|
||||
public Scrib_lua_proc LoadString(String text) {
|
||||
if (lua_id != -1) return init_chunk_func;
|
||||
text = String_.Replace(text, "	", "\t"); // NOTE: this should only get called once per module
|
||||
text_bry = Bry_.new_u8(text);
|
||||
init_chunk_func = core.Interpreter().LoadString("=" + name, text); // MW: Scribunto: Prepending an "=" to the chunk name avoids truncation or a "[string" prefix;
|
||||
lua_id = init_chunk_func.Id();
|
||||
return init_chunk_func;
|
||||
}
|
||||
public void Execute() {
|
||||
hash.Clear(); // NOTE: questionable. should probably be removed, as it forces all modules to be "loadString"'d again; DATE:2013-10-16
|
||||
this.LoadString(name); // assert lua_id;
|
||||
Keyval[] rslt = core.Interpreter().ExecuteModule(lua_id);
|
||||
if (rslt.length == 0) throw Err_.new_wo_type("module missing", "name", name, "lua_id", lua_id);
|
||||
Keyval[] prcs_ary = (Keyval[])rslt[0].Val();
|
||||
int prcs_len = prcs_ary.length;
|
||||
for (int i = 0; i < prcs_len; i++) {
|
||||
Keyval prc_kv = prcs_ary[i];
|
||||
String prc_key = prc_kv.Key();
|
||||
Object prc_val = prc_kv.Val();
|
||||
Scrib_lua_proc fnc = null;
|
||||
if (Type_adp_.ClassOf_obj(prc_val) == Scrib_lua_proc.class)
|
||||
fnc = (Scrib_lua_proc)prc_val;
|
||||
else
|
||||
fnc = new Scrib_lua_proc(prc_key, -1);
|
||||
Fncs_add(fnc);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_proc.java
Normal file
27
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_proc.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Scrib_lua_proc {
|
||||
public Scrib_lua_proc(String key, int id) {this.key = key; this.id = id;}
|
||||
public String Key() {return key;} private String key;
|
||||
public int Id() {return id;} private int id;
|
||||
@Override public String toString() {return key + ":" + id;}
|
||||
public static Scrib_lua_proc cast_or_null_(Object o) { // NOTE: maxStringLength and maxPatternLength return d:INF; ignore these
|
||||
return Type_adp_.ClassOf_obj(o) == Scrib_lua_proc.class ? (Scrib_lua_proc)o : null;
|
||||
}
|
||||
}
|
||||
69
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_xtn_mgr.java
Normal file
69
400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_xtn_mgr.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.parsers.logs.*;
|
||||
import gplx.xowa.xtns.scribunto.engines.*;
|
||||
public class Scrib_xtn_mgr extends Xox_mgr_base {
|
||||
private Xowe_wiki wiki;
|
||||
@Override public byte[] Xtn_key() {return XTN_KEY;} public static final byte[] XTN_KEY = Bry_.new_a7("scribunto");
|
||||
@Override public void Xtn_ctor_by_app(Xoae_app app) {this.app = app;} private Xoae_app app;
|
||||
@Override public Xox_mgr Xtn_clone_new() {return new Scrib_xtn_mgr();}
|
||||
public Scrib_lib_mgr Lib_mgr() {return lib_mgr;} private Scrib_lib_mgr lib_mgr = new Scrib_lib_mgr();
|
||||
public byte Engine_type() {return engine_type;} private byte engine_type = Scrib_engine_type.Type_luaj;
|
||||
public int Lua_timeout() {return lua_timeout;} private int lua_timeout = 4000;
|
||||
public int Lua_timeout_polling() {return lua_timeout_polling;} private int lua_timeout_polling = 1;
|
||||
public int Lua_timeout_busy_wait() {return lua_timeout_busy_wait;} private int lua_timeout_busy_wait = 250;
|
||||
public int Lua_timeout_loop() {return lua_timeout_loop;} private int lua_timeout_loop = 10000000;
|
||||
public boolean Lua_log_enabled() {return lua_log_enabled;} private boolean lua_log_enabled = false;
|
||||
public boolean Luaj_debug_enabled() {return luaj_debug_enabled;} private boolean luaj_debug_enabled;
|
||||
public void Luaj_debug_enabled_(boolean v) {
|
||||
this.luaj_debug_enabled = v;
|
||||
gplx.xowa.xtns.scribunto.Scrib_core_mgr.Term_all(app);// restart server in case luaj caches any debug data
|
||||
}
|
||||
public Xop_log_invoke_wkr Invoke_wkr() {return invoke_wkr;} private Xop_log_invoke_wkr invoke_wkr;
|
||||
@Override public void Xtn_init_by_wiki(Xowe_wiki wiki) {
|
||||
this.wiki = wiki;
|
||||
wiki.App().Cfg().Bind_many_wiki(this, wiki, Cfg__enabled, Cfg__engine, Cfg__lua__timeout, Cfg__lua__timeout_busy_wait, Cfg__lua__timeout_polling);
|
||||
}
|
||||
|
||||
@Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
||||
if (ctx.Match(k, Invk_invoke_wkr)) return m.ReadYnOrY("v") ? Invoke_wkr_or_new() : Gfo_invk_.Noop;
|
||||
else if (ctx.Match(k, Cfg__enabled)) {Enabled_(m.ReadYn("v")); wiki.Parser_mgr().Scrib().Core_term();}
|
||||
else if (ctx.Match(k, Cfg__engine)) {engine_type = Scrib_engine_type.Xto_byte(m.ReadStr("v")); wiki.Parser_mgr().Scrib().Core_term();}
|
||||
else if (ctx.Match(k, Cfg__lua__timeout)) {lua_timeout = m.ReadInt("v"); wiki.Parser_mgr().Scrib().Core_term();}
|
||||
else if (ctx.Match(k, Cfg__lua__timeout_polling)) {lua_timeout_polling = m.ReadInt("v"); wiki.Parser_mgr().Scrib().Core_term();}
|
||||
else if (ctx.Match(k, Cfg__lua__timeout_busy_wait)) {lua_timeout_busy_wait = m.ReadInt("v"); wiki.Parser_mgr().Scrib().Core_term();}
|
||||
else return super.Invk(ctx, ikey, k, m);
|
||||
return this;
|
||||
}
|
||||
private static final String Invk_invoke_wkr = "invoke_wkr";
|
||||
public Xop_log_invoke_wkr Invoke_wkr_or_new() {
|
||||
if (invoke_wkr == null) invoke_wkr = app.Log_mgr().Make_wkr_invoke();
|
||||
return invoke_wkr;
|
||||
}
|
||||
public static Err err_(String fmt, Object... args) {return Err_.new_wo_type(fmt, args).Trace_ignore_add_1_();}
|
||||
public static Err err_(Exception e, String msg, Object... args) {return Err_.new_exc(e, "xo", msg, args).Trace_ignore_add_1_();}
|
||||
private static final String
|
||||
Cfg__enabled = "xowa.addon.scribunto.enabled"
|
||||
, Cfg__engine = "xowa.addon.scribunto.engine"
|
||||
, Cfg__lua__timeout = "xowa.addon.scribunto.lua.timeout"
|
||||
, Cfg__lua__timeout_polling = "xowa.addon.scribunto.lua.timeout_polling"
|
||||
, Cfg__lua__timeout_busy_wait = "xowa.addon.scribunto.lua.timeout_busy_wait"
|
||||
;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public interface Scrib_engine {
|
||||
boolean Dbg_print(); void Dbg_print_(boolean v);
|
||||
Scrib_server Server(); void Server_(Scrib_server v);
|
||||
Scrib_lua_proc LoadString(String name, String text);
|
||||
Keyval[] CallFunction(int id, Keyval[] args);
|
||||
void RegisterLibrary(Keyval[] functions_ary);
|
||||
Keyval[] ExecuteModule(int mod_id);
|
||||
void CleanupChunks(Keyval[] ids);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public class Scrib_engine_type {
|
||||
public static String Xto_str(byte v) {
|
||||
switch (v) {
|
||||
case Type_lua: return "lua";
|
||||
case Type_luaj: return "luaj";
|
||||
default: throw Err_.new_unimplemented();
|
||||
}
|
||||
}
|
||||
public static byte Xto_byte(String s) {
|
||||
if (String_.Eq(s, "lua")) return Type_lua;
|
||||
else if (String_.Eq(s, "luaj")) return Type_luaj;
|
||||
else throw Err_.new_unimplemented();
|
||||
}
|
||||
public static final byte Type_lua = 0, Type_luaj = 1;
|
||||
public static Keyval[] Options__list = Keyval_.Ary(Keyval_.new_("luaj"), Keyval_.new_("lua"));
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public interface Scrib_server {
|
||||
void Init(String... process_args);
|
||||
int Server_timeout(); Scrib_server Server_timeout_(int v);
|
||||
int Server_timeout_polling(); Scrib_server Server_timeout_polling_(int v);
|
||||
int Server_timeout_busy_wait(); Scrib_server Server_timeout_busy_wait_(int v);
|
||||
byte[] Server_comm(byte[] cmd, Object[] cmd_objs);
|
||||
void Server_send(byte[] cmd, Object[] cmd_objs);
|
||||
byte[] Server_recv();
|
||||
void Term();
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.luaj; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
import org.luaj.vm2.*; import org.luaj.vm2.lib.*; import org.luaj.vm2.lib.jse.*;
|
||||
import gplx.xowa.xtns.scribunto.engines.process.*;
|
||||
public class Luaj_engine implements Scrib_engine {
|
||||
private final Luaj_server_func_recv func_recv;
|
||||
private final Luaj_server_func_dbg func_dbg;
|
||||
private final Scrib_proc_mgr proc_mgr;
|
||||
private final Scrib_core core;
|
||||
private Luaj_server server;
|
||||
public Luaj_engine(Xoae_app app, Scrib_core core, boolean debug_enabled) {
|
||||
this.core = core;
|
||||
this.proc_mgr = core.Proc_mgr();
|
||||
this.func_recv = new Luaj_server_func_recv(this);
|
||||
this.func_dbg = new Luaj_server_func_dbg(core);
|
||||
this.server = new Luaj_server(func_recv, func_dbg);
|
||||
}
|
||||
public Scrib_server Server() {return server;} public void Server_(Scrib_server v) {server = (Luaj_server)v;}
|
||||
public boolean Dbg_print() {return dbg_print;} public void Dbg_print_(boolean v) {dbg_print = v;} private boolean dbg_print;
|
||||
public Scrib_lua_proc LoadString(String name, String text) {
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", Val_loadString);
|
||||
msg.set("text", LuaValue.valueOf(text));
|
||||
msg.set("chunkName", LuaValue.valueOf(name));
|
||||
LuaTable rsp = server.Dispatch(msg);
|
||||
LuaTable values_tbl = Luaj_value_.Get_val_as_lua_table(rsp, "values");
|
||||
LuaInteger proc_id = (LuaInteger)values_tbl.rawget(1);
|
||||
return new Scrib_lua_proc(name, proc_id.v);
|
||||
}
|
||||
public void RegisterLibrary(Keyval[] functions) {
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", Val_registerLibrary);
|
||||
msg.set("name", "mw_interface");
|
||||
msg.set("functions", Luaj_value_.Obj_to_lua_val(server, functions));
|
||||
server.Dispatch(msg);
|
||||
}
|
||||
public Keyval[] CallFunction(int id, Keyval[] args) {
|
||||
int args_len = args.length;
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", Val_callFunction);
|
||||
msg.set("id", LuaValue.valueOf(id));
|
||||
msg.set("nargs", LuaValue.valueOf(args_len));
|
||||
msg.set("args", Luaj_value_.Obj_to_lua_val(server, args));
|
||||
return this.Dispatch_as_kv_ary(msg);
|
||||
}
|
||||
public Keyval[] ExecuteModule(int mod_id) {
|
||||
return this.CallFunction(core.Lib_mw().Mod().Fncs_get_id("executeModule"), Scrib_kv_utl_.base1_obj_(new Scrib_lua_proc("", mod_id)));
|
||||
}
|
||||
public void CleanupChunks(Keyval[] ids) {
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", "cleanupChunks");
|
||||
msg.set("ids", Luaj_value_.Obj_to_lua_val(server, ids));
|
||||
this.Dispatch_as_kv_ary(msg);
|
||||
}
|
||||
public Keyval[] Dispatch_as_kv_ary(LuaTable msg) {
|
||||
while (true) {
|
||||
LuaTable rsp = server.Dispatch(msg);
|
||||
String op = Luaj_value_.Get_val_as_str(rsp, "op");
|
||||
if (String_.Eq(op, "return"))
|
||||
return Luaj_value_.Get_val_as_kv_ary(server, rsp, "values");
|
||||
else if (String_.Eq(op, "call"))
|
||||
msg = Server_recv_call(rsp);
|
||||
else if (String_.Eq(op, "error")) {
|
||||
String err = Luaj_value_.Get_val_as_str(rsp, "value");
|
||||
core.Handle_error(err);
|
||||
return Keyval_.Ary_empty;
|
||||
}
|
||||
else
|
||||
return Keyval_.Ary_empty;
|
||||
}
|
||||
}
|
||||
public LuaTable Server_recv_call(LuaTable rsp) {
|
||||
String proc_id = Luaj_value_.Get_val_as_str(rsp, "id");
|
||||
Keyval[] args = Luaj_value_.Get_val_as_kv_ary(server, rsp, "args");
|
||||
Scrib_proc proc = proc_mgr.Get_by_key(proc_id); if (proc == null) throw Scrib_xtn_mgr.err_("could not find proc with id of {0}", proc_id);
|
||||
Scrib_proc_args proc_args = new Scrib_proc_args(args);
|
||||
Scrib_proc_rslt proc_rslt = new Scrib_proc_rslt();
|
||||
proc.Proc_exec(proc_args, proc_rslt);
|
||||
String fail_msg = proc_rslt.Fail_msg();
|
||||
if (fail_msg == null) {
|
||||
Keyval[] cbk_rslts = proc_rslt.Ary();
|
||||
return ReturnMessage(cbk_rslts);
|
||||
}
|
||||
else {
|
||||
return ReturnFail(fail_msg);
|
||||
}
|
||||
}
|
||||
private LuaTable ReturnMessage(Keyval[] values) {
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", Val_returnMessage);
|
||||
msg.set("nvalues", LuaValue.valueOf(values.length));
|
||||
msg.set("values", Luaj_value_.Obj_to_lua_val(server, values));
|
||||
return msg;
|
||||
}
|
||||
private LuaTable ReturnFail(String fail_msg) {
|
||||
LuaTable msg = LuaValue.tableOf();
|
||||
msg.set("op", Val_error);
|
||||
msg.set("value", LuaValue.valueOf(fail_msg));
|
||||
return msg;
|
||||
}
|
||||
private static final LuaValue
|
||||
Val_loadString = LuaValue.valueOf("loadString")
|
||||
, Val_registerLibrary = LuaValue.valueOf("registerLibrary")
|
||||
, Val_callFunction = LuaValue.valueOf("call")
|
||||
, Val_returnMessage = LuaValue.valueOf("return")
|
||||
, Val_error = LuaValue.valueOf("error")
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.luaj; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.envs.*;
|
||||
import org.luaj.vm2.*; import org.luaj.vm2.lib.*; import org.luaj.vm2.lib.jse.*;
|
||||
import gplx.xowa.xtns.scribunto.engines.process.*;
|
||||
public class Luaj_server implements Scrib_server {
|
||||
private final Luaj_server_func_recv func_recv;
|
||||
private final Luaj_server_func_dbg func_dbg;
|
||||
private LuaTable server;
|
||||
public Luaj_server(Luaj_server_func_recv func_recv, Luaj_server_func_dbg func_dbg) {
|
||||
this.func_recv = func_recv;
|
||||
this.func_dbg = func_dbg;
|
||||
}
|
||||
public Globals Luaj_globals() {return luaj_globals;} private Globals luaj_globals;
|
||||
public DebugLib Luaj_dbg() {return luaj_dbg;} private DebugLib luaj_dbg;
|
||||
public void Init(String... init_args) {
|
||||
luaj_dbg = new DebugLib(); // NOTE: needed for getfenv
|
||||
luaj_globals = JsePlatform.standardGlobals();
|
||||
luaj_globals.load(luaj_dbg);
|
||||
luaj_globals.load(new MWClient(luaj_globals, func_recv));
|
||||
luaj_globals.set("dbg", func_dbg);
|
||||
String root_str = init_args[2];
|
||||
if (Op_sys.Cur().Tid_is_wnt())
|
||||
root_str = String_.Replace(root_str, Op_sys.Wnt.Fsys_dir_spr_str(), Op_sys.Lnx.Fsys_dir_spr_str());
|
||||
LuaValue main_fil_val = LuaValue.valueOf(root_str + "engines/Luaj/mw_main.lua");
|
||||
LuaValue package_val = luaj_globals.get("package");
|
||||
package_val.rawset("path", LuaValue.valueOf(root_str + "engines/Luaj/?.lua;" + root_str + "engines/LuaCommon/lualib/?.lua"));
|
||||
server = (LuaTable)luaj_globals.get("dofile").call(main_fil_val);
|
||||
}
|
||||
public LuaTable Dispatch(LuaTable msg) {
|
||||
return (LuaTable)server.method(Val_server_recv, msg);
|
||||
}
|
||||
public int Get_id_by_closure(LuaValue closure) {
|
||||
LuaValue xchunks = server.get(Val_xchunks);
|
||||
LuaValue closure_id = xchunks.get(closure);
|
||||
int rv = -1;
|
||||
if (closure_id == LuaValue.NIL) // new closure; add it to chunks table via addChunk (which will return new id)
|
||||
rv = ((LuaInteger)server.method("addChunk", closure)).v;
|
||||
else
|
||||
rv = ((LuaInteger)closure_id).v;
|
||||
return rv;
|
||||
}
|
||||
public LuaValue Get_closure_by_id(int id) {
|
||||
LuaValue chunks = server.get(Val_chunks);
|
||||
return chunks.get(LuaValue.valueOf(id));
|
||||
}
|
||||
public int Server_timeout() {return server_timeout;} public Scrib_server Server_timeout_(int v) {server_timeout = v; return this;} private int server_timeout;
|
||||
public int Server_timeout_polling() {return server_timeout_polling;} public Scrib_server Server_timeout_polling_(int v) {server_timeout_polling = v; return this;} private int server_timeout_polling;
|
||||
public int Server_timeout_busy_wait() {return server_timeout_busy_wait;} public Scrib_server Server_timeout_busy_wait_(int v) {server_timeout_busy_wait = v; return this;} private int server_timeout_busy_wait;
|
||||
public byte[] Server_comm(byte[] cmd, Object[] cmd_objs) {return Bry_.Empty;}
|
||||
public void Server_send(byte[] cmd, Object[] cmd_objs) {}
|
||||
public byte[] Server_recv() {return Bry_.Empty;}
|
||||
public void Term() {}
|
||||
private static final LuaValue
|
||||
Val_server_recv = LuaValue.valueOf("server_recv")
|
||||
, Val_xchunks = LuaValue.valueOf("xchunks")
|
||||
, Val_chunks = LuaValue.valueOf("chunks")
|
||||
;
|
||||
class MWClient extends OneArgFunction {
|
||||
/** The implementation of the ZeroArgFunction interface.
|
||||
* This will be called once when the library is loaded via require().
|
||||
* @param arg LuaString containing the name used in the call to require().
|
||||
* @return Value that will be returned in the require() call. In this case,
|
||||
* it is the library itself.
|
||||
*/
|
||||
private final Globals luaj_globals;
|
||||
private final Luaj_server_func_recv func_recv;
|
||||
public MWClient(Globals luaj_globals, Luaj_server_func_recv func_recv) {
|
||||
this.luaj_globals = luaj_globals;
|
||||
this.func_recv = func_recv;
|
||||
}
|
||||
public LuaValue call(LuaValue libname) {
|
||||
LuaValue library = tableOf();
|
||||
library.set("client_recv", func_recv);
|
||||
LuaValue env = luaj_globals;
|
||||
env.set( "MWClient", library );
|
||||
return library;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.luaj; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
public class Luaj_server_func_dbg extends VarArgFunction {
|
||||
private final Scrib_core core;
|
||||
public Luaj_server_func_dbg(Scrib_core v) {this.core = v;}
|
||||
public Varargs invoke(Varargs args) {
|
||||
int len = args.narg();
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
bfr.Add_str_a7("<span class='xowa_dbg' style='color:red'>");
|
||||
for (int i = 1; i <= len; ++i) {
|
||||
String s = args.arg(i).toString();
|
||||
bfr.Add_str_u8(gplx.langs.htmls.Gfh_utl.Escape_html_as_str(s) + " ");
|
||||
}
|
||||
bfr.Add_str_a7("</span><br/>");
|
||||
core.Page().Html_data().Xtn_scribunto_dbg_(bfr.To_bry_and_clear());
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.luaj; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
public class Luaj_server_func_recv extends OneArgFunction {
|
||||
private final Luaj_engine engine;
|
||||
public Luaj_server_func_recv(Luaj_engine v) {this.engine = v;}
|
||||
public LuaValue call(LuaValue tbl_val) {
|
||||
LuaTable tbl = (LuaTable)tbl_val;
|
||||
String op = Luaj_value_.Get_val_as_str(tbl, "op");
|
||||
if (!String_.Eq(op, "call")) throw Err_.new_wo_type("luaj_recvr only processes op calls");
|
||||
return engine.Server_recv_call(tbl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.luaj; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import java.util.*;
|
||||
import org.luaj.vm2.*;
|
||||
class Luaj_value_ {
|
||||
public static String Get_val_as_str(LuaTable owner, String key) {
|
||||
return ((LuaString)owner.get(key)).tojstring();
|
||||
}
|
||||
public static LuaTable Get_val_as_lua_table(LuaTable owner, String key) {
|
||||
return (LuaTable)owner.get(key);
|
||||
}
|
||||
public static Keyval[] Get_val_as_kv_ary(Luaj_server server, LuaTable owner, String key) {
|
||||
LuaTable table = (LuaTable)owner.get(key);
|
||||
return Luaj_value_.Lua_tbl_to_kv_ary(server, table);
|
||||
}
|
||||
public static Keyval[] Lua_tbl_to_kv_ary(Luaj_server server, LuaTable tbl) {
|
||||
// init
|
||||
int tbl_len = tbl.length(); // gets length of tbl.array; note no way of getting length of tbl.hash; note that tbl.length is same as len; getn; rawlen; maxn;
|
||||
Keyval[] rv_ary = tbl_len == 0 ? Keyval_.Ary_empty : new Keyval[tbl_len]; // guess rv_ary dimensions
|
||||
List_adp rv_list = null;
|
||||
int rv_idx = 0;
|
||||
LuaValue cur = LuaValue.NIL; // needed for luaj iterator; tbl.next(cur);
|
||||
|
||||
// loop over pairs in tbl; no direct way to get kvs
|
||||
while (true) {
|
||||
// get next itm
|
||||
Varargs itm = tbl.next(cur);
|
||||
if (itm == LuaValue.NIL) break; // no more pairs; stop
|
||||
|
||||
// extract luaj key / val from itm; note itm.arg(1) is key and itm.arg(2) is val
|
||||
LuaValue itm_key = itm.arg(1);
|
||||
LuaValue itm_val = itm.arg(2);
|
||||
Object itm_val_obj = Lua_val_to_obj(server, itm_val);
|
||||
|
||||
// transform to xowa kv
|
||||
Keyval kv = null;
|
||||
// val is function
|
||||
if (itm_val.type() == LuaValue.TFUNCTION) {
|
||||
String func_key = itm_key.tojstring();
|
||||
int func_id = Int_.cast(itm_val_obj);
|
||||
Scrib_lua_proc lua_func = new Scrib_lua_proc(func_key, func_id);
|
||||
if (itm_key.type() == LuaValue.TSTRING) // most functions are named
|
||||
kv = Keyval_.new_(func_key, lua_func);
|
||||
else // some are not; particularly "anonymous" functions in Module for gsub_function; these will have a kv of int,int; note that key must be int; if string, lua will not be able to match it back to int later
|
||||
kv = Keyval_.int_(((LuaInteger)itm_key).v, lua_func);
|
||||
}
|
||||
// val is number or string
|
||||
else {
|
||||
switch (itm_key.type()) {
|
||||
case LuaValue.TNUMBER:
|
||||
int key_int = ((LuaNumber)itm_key).toint();
|
||||
kv = Keyval_.int_(key_int, itm_val_obj);
|
||||
break;
|
||||
case LuaValue.TSTRING:
|
||||
kv = Keyval_.new_(((LuaString)itm_key).tojstring(), itm_val_obj);
|
||||
break;
|
||||
default:
|
||||
throw Err_.new_unhandled(itm_key.type());
|
||||
}
|
||||
}
|
||||
|
||||
// store kv in rv
|
||||
// still enough space in array
|
||||
if (rv_idx < tbl_len) {
|
||||
rv_ary[rv_idx] = kv;
|
||||
}
|
||||
// exceeded rv_ary; store in list
|
||||
else {
|
||||
if (rv_idx == tbl_len) {
|
||||
rv_list = List_adp_.New();
|
||||
if (tbl_len > 0) { // don't bother entering for loop if rv_ary was 0
|
||||
for (int i = 0; i < tbl_len; i++) {
|
||||
rv_list.Add(rv_ary[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
rv_list.Add(kv);
|
||||
}
|
||||
|
||||
// increment list and rv_idx
|
||||
cur = itm_key;
|
||||
++rv_idx;
|
||||
}
|
||||
return rv_list == null ? rv_ary : (Keyval[])rv_list.To_ary_and_clear(Keyval.class);
|
||||
}
|
||||
private static Object Lua_val_to_obj(Luaj_server server, LuaValue v) {
|
||||
switch (v.type()) {
|
||||
case LuaValue.TNIL: return null;
|
||||
case LuaValue.TBOOLEAN: return ((LuaBoolean)v).toboolean();
|
||||
case LuaValue.TSTRING: return ((LuaString)v).tojstring();
|
||||
case LuaValue.TNUMBER:
|
||||
LuaNumber v_num = (LuaNumber)v;
|
||||
if (v_num.isint())
|
||||
return v_num.toint();
|
||||
else
|
||||
return v_num.todouble();
|
||||
case LuaValue.TTABLE: return Lua_tbl_to_kv_ary(server, (LuaTable)v);
|
||||
case LuaValue.TFUNCTION: return server.Get_id_by_closure(v);
|
||||
default: throw Err_.new_unhandled(v.type());
|
||||
}
|
||||
}
|
||||
public static LuaValue Obj_to_lua_val(Luaj_server server, Object o) {
|
||||
if (o == null) return LuaValue.NIL;
|
||||
Class<?> c = Type_adp_.ClassOf_obj(o);
|
||||
if (Object_.Eq(c, Bool_.Cls_ref_type)) return LuaValue.valueOf((Boolean)o);
|
||||
else if (Object_.Eq(c, Byte_.Cls_ref_type)) return LuaValue.valueOf((Byte)o);
|
||||
else if (Object_.Eq(c, Int_.Cls_ref_type)) return LuaValue.valueOf((Integer)o);
|
||||
else if (Object_.Eq(c, String_.Cls_ref_type)) return LuaValue.valueOf((String)o);
|
||||
else if (Object_.Eq(c, Double_.Cls_ref_type)) return LuaValue.valueOf((Double)o);
|
||||
else if (Object_.Eq(c, byte[].class)) return LuaValue.valueOf(String_.new_u8((byte[])o));
|
||||
else if (Object_.Eq(c, Keyval.class)) return Kv_ary_to_lua_tbl(server, (Keyval)o);
|
||||
else if (Object_.Eq(c, Keyval[].class)) return Kv_ary_to_lua_tbl(server, (Keyval[])o);
|
||||
else if (Object_.Eq(c, Long_.Cls_ref_type)) return LuaValue.valueOf((Long)o);
|
||||
else if (Object_.Eq(c, Scrib_lua_proc.class)) return server.Get_closure_by_id(((Scrib_lua_proc)o).Id());
|
||||
else if (Object_.Eq(c, Float_.Cls_ref_type)) return LuaValue.valueOf((Float)o);
|
||||
else if (Object_.Eq(c, Char_.Cls_ref_type)) return LuaValue.valueOf((Character)o);
|
||||
else if (Object_.Eq(c, Short_.Cls_ref_type)) return LuaValue.valueOf((Short)o);
|
||||
else if (Object_.Eq(c, Decimal_adp.class)) return LuaValue.valueOf(((Decimal_adp)o).To_double()); // DATE:2016-08-01
|
||||
else return LuaValue.NIL;
|
||||
}
|
||||
private static LuaTable Kv_ary_to_lua_tbl(Luaj_server server, Keyval... ary) {
|
||||
LuaTable rv = LuaValue.tableOf();
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval itm = ary[i];
|
||||
LuaValue itm_val = Obj_to_lua_val(server, itm.Val());
|
||||
switch (itm.Key_tid()) {
|
||||
case Type_adp_.Tid__int:
|
||||
rv.set(Int_.cast(itm.Key_as_obj()), itm_val);
|
||||
break;
|
||||
case Type_adp_.Tid__str:
|
||||
case Type_adp_.Tid__obj:
|
||||
rv.set(itm.Key(), itm_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.mocks; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.primitives.*;
|
||||
public abstract class Mock_proc_fxt {
|
||||
public Mock_proc_fxt(int id, String key) {this.id = id; this.key = key;}
|
||||
public int Id() {return id;} private final int id;
|
||||
public String Key() {return key;} private final String key;
|
||||
public Scrib_lua_proc To_scrib_lua_proc() {return new Scrib_lua_proc(key, id);}
|
||||
public abstract Keyval[] Exec_by_scrib(Keyval[] args);
|
||||
}
|
||||
class Mock_engine implements Scrib_engine {
|
||||
private final Hash_adp hash = Hash_adp_.New();
|
||||
private final Int_obj_ref tmp_hash_id = Int_obj_ref.New_neg1();
|
||||
public boolean Dbg_print() {return false;} public void Dbg_print_(boolean v) {}
|
||||
public Scrib_server Server() {return server;} public void Server_(Scrib_server v) {} private final Mock_server server = new Mock_server();
|
||||
public Scrib_lua_proc LoadString(String name, String text) {return null;}
|
||||
public Keyval[] CallFunction(int id, Keyval[] args) {
|
||||
Mock_proc_fxt proc = (Mock_proc_fxt)hash.Get_by_or_fail(tmp_hash_id.Val_(id));
|
||||
return proc.Exec_by_scrib(args);
|
||||
}
|
||||
public void RegisterLibrary(Keyval[] functions_ary) {}
|
||||
public Keyval[] ExecuteModule(int mod_id) {return null;}
|
||||
public void CleanupChunks(Keyval[] ids) {}
|
||||
public void Clear() {hash.Clear();}
|
||||
public void RegisterLibraryForTest(Mock_proc_fxt proc) {
|
||||
hash.Add(Int_obj_ref.New(proc.Id()), proc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.mocks; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.xowa.parsers.tmpls.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Mock_scrib_fxt {
|
||||
private final Mock_engine engine = new Mock_engine();
|
||||
private final Mock_server server = new Mock_server();
|
||||
public Scrib_core Core() {return core;} private Scrib_core core;
|
||||
public Xop_fxt Parser_fxt() {return parser_fxt;} private Xop_fxt parser_fxt;
|
||||
public void Clear() {Clear("en.wikipedia.org", "en");}
|
||||
public void Clear(String domain, String lang) {
|
||||
Xoae_app app = Xoa_app_fxt.Make__app__edit();
|
||||
Xowe_wiki wiki = Xoa_app_fxt.Make__wiki__edit(app, domain, app.Lang_mgr().Get_by_or_new(Bry_.new_u8(lang)));
|
||||
parser_fxt = new Xop_fxt(app, wiki); // NOTE: always new(); don't try to cache; causes errors in Language_lib
|
||||
core = wiki.Parser_mgr().Scrib().Core_init(wiki.Parser_mgr().Ctx());
|
||||
core.Engine_(engine); engine.Clear();
|
||||
core.Interpreter().Server_(server);
|
||||
Xot_invk parent_frame = new Xot_invk_temp(true); parent_frame.Frame_tid_(Scrib_frame_.Tid_null);
|
||||
Xot_invk current_frame = Xot_invk_mock.test_(Bry_.new_a7("Module:Mod_0"));
|
||||
core.Invoke_init(core.Wiki(), core.Ctx(), Bry_.Empty, parent_frame, current_frame);
|
||||
core.When_page_changed(parser_fxt.Page());
|
||||
}
|
||||
public void Init__cbk(Mock_proc_fxt... ary) {
|
||||
engine.Clear();
|
||||
for (Mock_proc_fxt proc : ary)
|
||||
engine.RegisterLibraryForTest(proc);
|
||||
}
|
||||
public void Init__page(String ttl, String txt) {parser_fxt.Init_page_create(ttl, txt);}
|
||||
public void Test__proc__ints (Scrib_lib lib, String proc_name, Object[] args, int expd) {Test__proc__kvps(lib, proc_name, Bool_.Y, Int_.To_str(expd), Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test__proc__objs__flat(Scrib_lib lib, String proc_name, Object[] args, String expd) {Test__proc__kvps(lib, proc_name, Bool_.Y, expd, Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test__proc__objs__nest(Scrib_lib lib, String proc_name, Object[] args, Keyval[] expd) {Test__proc__kvps(lib, proc_name, Bool_.N, Keyval_.Ary__to_str__nest(new Keyval[] {Keyval_.int_(Scrib_core.Base_1, expd)}), Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test__proc__objs__nest(Scrib_lib lib, String proc_name, Object[] args, String expd) {Test__proc__kvps(lib, proc_name, Bool_.N, expd, Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test__proc__kvps__flat(Scrib_lib lib, String proc_name, Keyval[] args, String expd) {Test__proc__kvps(lib, proc_name, Bool_.Y, expd, args);}
|
||||
public void Test__proc__kvps__nest(Scrib_lib lib, String proc_name, Keyval[] args, String expd) {Test__proc__kvps(lib, proc_name, Bool_.N, expd, args);}
|
||||
private static void Test__proc__kvps(Scrib_lib lib, String proc_name, boolean flat, String expd, Keyval[] args) {
|
||||
Keyval[] actl_ary = Mock_scrib_fxt_.Test__lib_proc__core(lib, proc_name, args);
|
||||
if (flat)
|
||||
Tfds.Eq(expd, Mock_scrib_fxt_.Kvp_vals_to_str(actl_ary));
|
||||
else
|
||||
Tfds.Eq_str_lines(expd, Keyval_.Ary__to_str__nest(actl_ary));
|
||||
}
|
||||
public void Test__proc__objs__empty(Scrib_lib lib, String proc_name, Object[] args) {Test__proc__kvps__empty(lib, proc_name, Scrib_kv_utl_.base1_many_(args));}
|
||||
public void Test__proc__kvps__empty(Scrib_lib lib, String proc_name, Keyval[] args) {
|
||||
Tfds.Eq(0, Mock_scrib_fxt_.Test__lib_proc__core(lib, proc_name, args).length);
|
||||
}
|
||||
public void Test__proc__kvps__vals(Scrib_lib lib, String proc_name, Keyval[] args, Object... expd_ary) {
|
||||
Keyval[] actl_kvs = Mock_scrib_fxt_.Test__lib_proc__core(lib, proc_name, args);
|
||||
Object[] actl_ary = Mock_scrib_fxt_.Kvp_vals_to_objs(actl_kvs);
|
||||
Tfds.Eq_ary(expd_ary, actl_ary);
|
||||
}
|
||||
}
|
||||
class Mock_scrib_fxt_ {
|
||||
public static Keyval[] Test__lib_proc__core(Scrib_lib lib, String proc_name, Keyval[] args) {
|
||||
Scrib_proc proc = lib.Procs().Get_by_key(proc_name);
|
||||
Scrib_proc_rslt proc_rslt = new Scrib_proc_rslt();
|
||||
proc.Proc_exec(new Scrib_proc_args(args), proc_rslt);
|
||||
return proc_rslt.Ary();
|
||||
}
|
||||
public static Object[] Kvp_vals_to_objs(Keyval[] kvps) {
|
||||
int len = kvps.length;
|
||||
Object[] rv = new Object[len];
|
||||
for (int i = 0; i < len; ++i)
|
||||
rv[i] = kvps[i].Val();
|
||||
return rv;
|
||||
}
|
||||
public static String Kvp_vals_to_str(Keyval[] ary) {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Semic);
|
||||
Keyval kv = ary[i];
|
||||
bfr.Add_str_u8(Object_.Xto_str_strict_or_null_mark(kv.Val()));
|
||||
}
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
}
|
||||
class Mock_server implements Scrib_server {
|
||||
public void Init(String... process_args) {}
|
||||
public int Server_timeout() {return server_timeout;} public Scrib_server Server_timeout_(int v) {server_timeout = v; return this;} private int server_timeout = 60;
|
||||
public int Server_timeout_polling() {return server_timeout_polling;} public Scrib_server Server_timeout_polling_(int v) {server_timeout_polling = v; return this;} private int server_timeout_polling = 1;
|
||||
public int Server_timeout_busy_wait() {return server_timeout_busy_wait;} public Scrib_server Server_timeout_busy_wait_(int v) {server_timeout_busy_wait = v; return this;} private int server_timeout_busy_wait = 1;
|
||||
public byte[] Server_comm(byte[] cmd, Object[] cmd_objs) {return Bry_.Empty;}
|
||||
public void Server_send(byte[] cmd, Object[] cmd_objs) {}
|
||||
public byte[] Server_recv() {return Bry_.Empty;}
|
||||
public void Term() {}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.encoders.*;
|
||||
import gplx.xowa.xtns.scribunto.libs.*; import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Process_engine implements Scrib_engine {
|
||||
private Scrib_core core; private Xoae_app app; private Scrib_xtn_mgr scrib_opts;
|
||||
private Process_recv_msg rsp = new Process_recv_msg(); private Process_send_wtr msg_encoder;
|
||||
private Scrib_proc_mgr proc_mgr;
|
||||
public Process_engine(Xoae_app app, Xowe_wiki wiki, Scrib_core core) {
|
||||
this.app = app; this.core = core; this.proc_mgr = core.Proc_mgr();
|
||||
msg_encoder = new Process_send_wtr(app.Usr_dlg());
|
||||
server = new Process_server();
|
||||
scrib_opts = (Scrib_xtn_mgr)wiki.Xtn_mgr().Get_or_fail(Scrib_xtn_mgr.XTN_KEY);
|
||||
}
|
||||
public boolean Dbg_print() {return dbg_print;} public void Dbg_print_(boolean v) {dbg_print = v;} private boolean dbg_print;
|
||||
public Scrib_server Server() {return server;} public void Server_(Scrib_server v) {server = v;} Scrib_server server;
|
||||
public Scrib_lua_proc LoadString(String name, String text) {
|
||||
Keyval[] rslt = this.Dispatch("op", "loadString", "text", text, "chunkName", name);
|
||||
return new Scrib_lua_proc(name, Int_.cast(rslt[0].Val()));
|
||||
}
|
||||
public Keyval[] CallFunction(int id, Keyval[] args) {
|
||||
return this.Dispatch("op", "call", "id", id, "nargs", args.length, "args", args);
|
||||
}
|
||||
public void RegisterLibrary(Keyval[] functions_ary) {
|
||||
this.Dispatch("op", "registerLibrary", "name", Scrib_core.Key_mw_interface, "functions", functions_ary);
|
||||
}
|
||||
public void CleanupChunks(Keyval[] ids) {
|
||||
this.Dispatch("op", "cleanupChunks", "ids", ids);
|
||||
}
|
||||
public Keyval[] ExecuteModule(int mod_id) {
|
||||
return this.CallFunction(core.Lib_mw().Mod().Fncs_get_id("executeModule"), Scrib_kv_utl_.base1_obj_(new Scrib_lua_proc("", mod_id)));
|
||||
}
|
||||
private Keyval[] Dispatch(Object... ary) {
|
||||
Bry_bfr bfr = app.Utl__bfr_mkr().Get_k004().Clear();
|
||||
while (true) {
|
||||
Dispatch_bld_send(bfr, ary);
|
||||
boolean log_enabled = scrib_opts.Lua_log_enabled();
|
||||
if (log_enabled) app.Usr_dlg().Log_direct("sent:" + bfr.To_str() + "\n");
|
||||
byte[] rsp_bry = server.Server_comm(bfr.To_bry_and_clear(), ary);
|
||||
if (log_enabled) app.Usr_dlg().Log_direct("rcvd:" + String_.new_u8(rsp_bry) + "\n\n");
|
||||
String op = rsp.Extract(rsp_bry);
|
||||
if (String_.Eq(op, "return")) {
|
||||
bfr.Mkr_rls();
|
||||
return rsp.Values();
|
||||
}
|
||||
else if (String_.Eq(op, "error")) {
|
||||
core.Handle_error(rsp.Rslt_ary()[0].Val_to_str_or_empty());
|
||||
return Keyval_.Ary_empty;
|
||||
}
|
||||
else if (String_.Eq(op, "call")) {
|
||||
String id = rsp.Call_id();
|
||||
Keyval[] args = rsp.Call_args();
|
||||
Scrib_proc proc = proc_mgr.Get_by_key(id); if (proc == null) throw Scrib_xtn_mgr.err_("could not find proc with id of {0}", id);
|
||||
Scrib_proc_args proc_args = new Scrib_proc_args(args);
|
||||
Scrib_proc_rslt proc_rslt = new Scrib_proc_rslt();
|
||||
proc.Proc_exec(proc_args, proc_rslt);
|
||||
String fail_msg = proc_rslt.Fail_msg();
|
||||
if (fail_msg == null) {
|
||||
Keyval[] cbk_rslts = proc_rslt.Ary();
|
||||
ary = Object_.Ary("op", "return", "nvalues", cbk_rslts.length, "values", cbk_rslts);
|
||||
}
|
||||
else {
|
||||
ary = Object_.Ary("op", "error", "value", fail_msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bfr.Mkr_rls();
|
||||
// app.Usr_dlg().Warn_many("", "", "invalid dispatch: op=~{0} page=~{1}", op, String_.new_u8(core.Ctx().Page().Page_ttl().Page_db()));
|
||||
return Keyval_.Ary_empty;
|
||||
}
|
||||
}
|
||||
} private static final byte[] Dispatch_hdr = Bry_.new_a7("0000000000000000"); // itm_len + itm_chk in 8-len HexDec
|
||||
private void Dispatch_bld_send(Bry_bfr bfr, Object[] ary) {
|
||||
int len = ary.length; if (len % 2 != 0) throw Err_.new_wo_type("arguments must be factor of 2", "len", len);
|
||||
bfr.Add(Dispatch_hdr);
|
||||
bfr.Add_byte(Byte_ascii.Curly_bgn);
|
||||
for (int i = 0; i < len; i++) {
|
||||
Object itm = ary[i];
|
||||
if (i % 2 == 0) {
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Comma);
|
||||
msg_encoder.Encode_key(bfr, itm);
|
||||
}
|
||||
else
|
||||
msg_encoder.Encode_obj(bfr, itm);
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Curly_end);
|
||||
int msg_len = bfr.Len() - 16; // 16 for Dispatch_hdr_len
|
||||
int chk_len = (msg_len * 2) -1; // defined by Scribunto
|
||||
Hex_utl_.Write(bfr.Bfr(), 0, 8, msg_len);
|
||||
Hex_utl_.Write(bfr.Bfr(), 9, 16, chk_len);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.primitives.*; import gplx.langs.phps.*;
|
||||
public class Process_recv_msg {
|
||||
private Php_srl_parser parser = new Php_srl_parser();
|
||||
public Process_recv_msg() {
|
||||
arg_keys.Add("op" , Byte_obj_val.new_(Arg_op));
|
||||
arg_keys.Add("values" , Byte_obj_val.new_(Arg_values));
|
||||
arg_keys.Add("id" , Byte_obj_val.new_(Arg_id));
|
||||
arg_keys.Add("args" , Byte_obj_val.new_(Arg_args));
|
||||
} private Hash_adp arg_keys = Hash_adp_.New(); private static final byte Arg_op = 0, Arg_values = 1, Arg_id = 2, Arg_args = 3;
|
||||
public String Op() {return op;} private String op;
|
||||
public String Call_id() {return call_id;} private String call_id;
|
||||
public Keyval[] Rslt_ary() {return rslt_ary;} private Keyval[] rslt_ary;
|
||||
public Keyval[] Values() {return values;} private Keyval[] values;
|
||||
public Keyval[] Call_args() {return call_args;} private Keyval[] call_args;
|
||||
public String Extract(byte[] rsp) {
|
||||
try {
|
||||
op = call_id = null;
|
||||
rslt_ary = values = call_args = null;
|
||||
Keyval[] root_ary = parser.Parse_as_kvs(rsp);
|
||||
rslt_ary = (Keyval[])root_ary[0].Val();
|
||||
int len = rslt_ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval kv = rslt_ary[i];
|
||||
String kv_key = kv.Key();
|
||||
Byte_obj_val bv = (Byte_obj_val)arg_keys.Get_by(kv_key);
|
||||
if (bv != null) {
|
||||
switch (bv.Val()) {
|
||||
case Arg_op: op = kv.Val_to_str_or_empty(); break;
|
||||
case Arg_values: values = (Keyval[])kv.Val(); break;
|
||||
case Arg_id: call_id = kv.Val_to_str_or_empty(); break;
|
||||
case Arg_args: call_args = (Keyval[])kv.Val(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return op;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Scrib_xtn_mgr.err_(e, "failed to extract data", "rsp", rsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
public class Process_send_wtr {
|
||||
public Process_send_wtr(Gfo_usr_dlg usr_dlg) {this.usr_dlg = usr_dlg;} private Gfo_usr_dlg usr_dlg;
|
||||
public String Encode(Object o) {
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.Reset(Io_mgr.Len_kb);
|
||||
Encode_obj(tmp_bfr, o);
|
||||
return tmp_bfr.To_str_and_clear();
|
||||
}
|
||||
public void Encode_bool(Bry_bfr bfr, boolean v) {bfr.Add(v ? CONST_bool_true : CONST_bool_false);}
|
||||
public void Encode_int(Bry_bfr bfr, int v) {bfr.Add_int_variable(v);}
|
||||
public boolean Encode_double(Bry_bfr bfr, double v) {
|
||||
if (Double_.IsNaN(v)) {usr_dlg.Warn_many(GRP_KEY, "fail_encode_double", "cannot convert non-finite number"); return false;}
|
||||
bfr.Add_double(v);
|
||||
return true;
|
||||
}
|
||||
public boolean Encode_str(Bry_bfr bfr, String v) {return Encode_str(bfr, Bry_.new_u8(v));}
|
||||
public boolean Encode_str(Bry_bfr bfr, byte[] bry) {
|
||||
int len = bry.length;
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = bry[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Quote: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(b); break;
|
||||
case Byte_ascii.Nl: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(Byte_ascii.Ltr_n); break;
|
||||
case Byte_ascii.Cr: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(Byte_ascii.Ltr_r); break;
|
||||
case Byte_ascii.Null: bfr.Add(CONST_escape_000); break;
|
||||
case Byte_ascii.Backslash: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(Byte_ascii.Backslash); break;
|
||||
default: bfr.Add_byte(b); break;
|
||||
}
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Quote);
|
||||
return true;
|
||||
}
|
||||
public boolean Encode_prc(Bry_bfr bfr, Scrib_lua_proc prc) {
|
||||
bfr.Add(Prc_bgn);
|
||||
bfr.Add_int_variable(prc.Id());
|
||||
bfr.Add_byte(Byte_ascii.Brack_end);
|
||||
return true;
|
||||
} private static final byte[] Prc_bgn = Bry_.new_a7("chunks[");
|
||||
private boolean Encode_ary(Bry_bfr bfr, Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
bfr.Add_byte(Byte_ascii.Curly_bgn);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Comma);
|
||||
Keyval itm = ary[i];
|
||||
Encode_key(bfr, itm.Key_as_obj());
|
||||
Encode_obj(bfr, itm.Val());
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Curly_end);
|
||||
return true;
|
||||
}
|
||||
private boolean Encode_kv(Bry_bfr bfr, Keyval kv) {
|
||||
bfr.Add_byte(Byte_ascii.Curly_bgn);
|
||||
Encode_key(bfr, kv.Key_as_obj());
|
||||
Encode_obj(bfr, kv.Val());
|
||||
bfr.Add_byte(Byte_ascii.Curly_end);
|
||||
return true;
|
||||
}
|
||||
public void Encode_key(Bry_bfr bfr, Object key) {
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn);
|
||||
Encode_obj(bfr, key);
|
||||
bfr.Add_byte(Byte_ascii.Brack_end);
|
||||
bfr.Add_byte(Byte_ascii.Eq);
|
||||
}
|
||||
public boolean Encode_obj(Bry_bfr bfr, Object o) {
|
||||
if (o == null) {bfr.Add(CONST_nil); return true;}
|
||||
Class<?> c = Type_adp_.ClassOf_obj(o);
|
||||
if (Object_.Eq(c, Bool_.Cls_ref_type)) Encode_bool(bfr, Bool_.Cast(o));
|
||||
else if (Object_.Eq(c, Int_.Cls_ref_type)) Encode_int(bfr, Int_.cast(o));
|
||||
else if (Object_.Eq(c, Long_.Cls_ref_type)) bfr.Add_long_variable(Long_.cast(o));
|
||||
else if (Object_.Eq(c, Double_.Cls_ref_type)) {if (!Encode_double(bfr, Double_.cast(o))) return false;}
|
||||
else if (Object_.Eq(c, String.class)) {if (!Encode_str(bfr, (String)o)) return false;}
|
||||
else if (Object_.Eq(c, byte[].class)) {if (!Encode_str(bfr, (byte[])o)) return false;} // NOTE: not in Scribunto; added here for PERF of not re-creating a String Object
|
||||
else if (Object_.Eq(c, Scrib_lua_proc.class)) {if (!Encode_prc(bfr, (Scrib_lua_proc)o)) return false;}
|
||||
else if (Object_.Eq(c, Keyval.class)) {if (!Encode_kv(bfr, (Keyval)o)) return false;}
|
||||
else if (Object_.Eq(c, Keyval[].class)) {if (!Encode_ary(bfr, (Keyval[])o)) return false;}
|
||||
else {throw Scrib_xtn_mgr.err_("Object cannot be serialized: ~{0}", Type_adp_.NameOf_obj(o));}
|
||||
return true;
|
||||
}
|
||||
private static final byte[] CONST_nil = Bry_.new_a7("nil"), CONST_bool_true = Bry_.new_a7("true"), CONST_bool_false = Bry_.new_a7("false"), CONST_escape_000 = Bry_.new_a7("\\000");
|
||||
private static final String GRP_KEY = "xowa-scribunto-lua-srl";
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import org.junit.*;
|
||||
public class Process_send_wtr_tst {
|
||||
@Before public void init() {fxt.Clear();} Scrib_lua_srl_fxt fxt = new Scrib_lua_srl_fxt();
|
||||
@Test public void Encode_str_basic() {fxt.Test_encode("ab" , "\"ab\"");}
|
||||
@Test public void Encode_str_quote() {fxt.Test_encode("a\"b" , "\"a\\\"b\"");}
|
||||
@Test public void Encode_str_nl() {fxt.Test_encode("a\nb" , "\"a\\nb\"");}
|
||||
@Test public void Encode_str_cr() {fxt.Test_encode("a\rb" , "\"a\\rb\"");}
|
||||
@Test public void Encode_str_nil() {fxt.Test_encode("a\0b" , "\"a\\000b\"");}
|
||||
@Test public void Encode_ary_empty() {fxt.Test_encode(fxt.ary_() , "{}");}
|
||||
@Test public void Encode_ary_one() {fxt.Test_encode(fxt.ary_(fxt.itm_("key", 123)), "{[\"key\"]=123}");}
|
||||
@Test public void Encode_ary_many() {fxt.Test_encode(fxt.ary_(fxt.itm_("k1", 123), fxt.itm_("k2", 234)), "{[\"k1\"]=123,[\"k2\"]=234}");}
|
||||
@Test public void Encode_ary_nest() {fxt.Test_encode(fxt.ary_(fxt.itm_("k1", fxt.ary_(fxt.itm_("k2", 234)))), "{[\"k1\"]={[\"k2\"]=234}}");}
|
||||
}
|
||||
class Scrib_lua_srl_fxt {
|
||||
public void Clear() {
|
||||
if (srl == null) {
|
||||
usr_dlg = Gfo_usr_dlg_.Test();
|
||||
srl = new Process_send_wtr(usr_dlg);
|
||||
}
|
||||
} Process_send_wtr srl; Gfo_usr_dlg usr_dlg;
|
||||
public Keyval[] ary_(Keyval... ary) {return ary;}
|
||||
public Keyval itm_(String key, Object val) {return Keyval_.new_(key, val);}
|
||||
public void Test_encode(Object o, String expd) {Tfds.Eq(expd, srl.Encode(o));}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.threads.*;
|
||||
import gplx.core.encoders.*;
|
||||
import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.threads.Thread_adp_;
|
||||
import java.io.*;
|
||||
public class Process_server implements Scrib_server {
|
||||
private Process process;
|
||||
private OutputStream stream_write; private Process_server_gobbler_recv stream_read; private byte[] bry_header = new byte[16], bry_body = new byte[Io_mgr.Len_kb * 4], bry_error = new byte[Io_mgr.Len_kb * 4];
|
||||
private Process_stream_rdr process_rdr;
|
||||
private Process_server_gobbler_error error_reader;
|
||||
public int Server_timeout() {return server_timeout;} public Scrib_server Server_timeout_(int v) {server_timeout = v; return this;} int server_timeout = 8000;
|
||||
public int Server_timeout_polling() {return server_timeout_polling;} public Scrib_server Server_timeout_polling_(int v) {server_timeout_polling = v; return this;} int server_timeout_polling = 1;
|
||||
public int Server_timeout_busy_wait() {return server_timeout_busy_wait;} public Scrib_server Server_timeout_busy_wait_(int v) {server_timeout_busy_wait = v; return this;} int server_timeout_busy_wait = 250;
|
||||
public void Init(String... process_args) {
|
||||
process_rdr = new Process_stream_rdr(bry_header, bry_body);
|
||||
ProcessBuilder pb = new ProcessBuilder(process_args);
|
||||
pb.redirectErrorStream(false);
|
||||
try {process = pb.start();}
|
||||
catch (Exception e) {throw Err_.new_exc(e, "core", "process init failed", "args", String_.AryXtoStr(process_args));}
|
||||
stream_write = process.getOutputStream();
|
||||
error_reader = new Process_server_gobbler_error(process.getErrorStream(), bry_error);
|
||||
error_reader.Start();
|
||||
}
|
||||
public byte[] Server_comm(byte[] cmd, Object[] cmd_objs) {
|
||||
Server_send(cmd, cmd_objs);
|
||||
return Server_recv();
|
||||
}
|
||||
public void Server_send(byte[] cmd, Object[] cmd_objs) {
|
||||
if (process == null) throw Err_.new_wo_type("process not started");
|
||||
cmd_last = cmd;
|
||||
// stream_read.Data_reset();
|
||||
stream_read = new Process_server_gobbler_recv(process.getInputStream(), process_rdr).Start();
|
||||
try {
|
||||
stream_write.write(cmd);
|
||||
stream_write.flush();
|
||||
}
|
||||
catch (Exception e) {throw Err_.new_exc(e, "core", "failed to write to output");}
|
||||
} private byte[] cmd_last;
|
||||
public byte[] Server_recv() {
|
||||
long time_bgn = System.currentTimeMillis();
|
||||
long time_woke = time_bgn;
|
||||
while (true) {
|
||||
byte[] rv = stream_read.Data();
|
||||
if (rv != null) return rv;
|
||||
long time_now = System.currentTimeMillis();
|
||||
if (time_now > time_woke + server_timeout_busy_wait) {
|
||||
if (time_now > time_bgn + server_timeout) throw Scrib_xtn_mgr.err_("lua_timeout: timeout={0} cmd={1}", server_timeout, String_.new_u8(cmd_last));
|
||||
Thread_adp_.Sleep(server_timeout_polling);
|
||||
time_woke = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Term() {
|
||||
if (error_reader != null) error_reader.Term(); // NOTE: need to interrupt close, else process stays open
|
||||
if (stream_read != null) stream_read.Term();
|
||||
if (process != null) process.destroy();
|
||||
}
|
||||
}
|
||||
class Process_server_gobbler_error extends Thread {
|
||||
private byte[] bfr;
|
||||
private InputStream stream;
|
||||
public Process_server_gobbler_error(InputStream stream, byte[] bfr) {
|
||||
super("process.lua.error");
|
||||
this.stream = stream;
|
||||
this.bfr = bfr;
|
||||
}
|
||||
public Process_server_gobbler_error Start() {this.start(); return this;}
|
||||
public void run() {
|
||||
try {
|
||||
while (true) { // loop b/c one gobbler is reused for multiple calls
|
||||
stream.read(bfr);
|
||||
if (terminating) break;
|
||||
// ThreadAdp_.Sleep(100); commented out; DATE:2014-03-20
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (terminating)
|
||||
return;
|
||||
else
|
||||
throw Err_.new_exc(e, "core", "failed to write to output");
|
||||
}
|
||||
}
|
||||
public void Term() {
|
||||
terminating = true;
|
||||
this.interrupt();
|
||||
} boolean terminating = false;
|
||||
}
|
||||
class Process_server_gobbler_recv extends Thread {
|
||||
private Process_stream_rdr process_rdr;
|
||||
private InputStream stream;
|
||||
public Process_server_gobbler_recv(InputStream stream, Process_stream_rdr process_rdr) {
|
||||
super("process.lua.read");
|
||||
this.stream = stream; this.process_rdr = process_rdr;
|
||||
}
|
||||
public void Data_reset() {data = null;}
|
||||
public byte[] Data() {return data;} private byte[] data;
|
||||
public Process_server_gobbler_recv Start() {
|
||||
process_rdr.Rdr().UnderRdr_(stream);
|
||||
this.start();
|
||||
return this;
|
||||
}
|
||||
public void run() {
|
||||
data = process_rdr.Read();
|
||||
}
|
||||
public void Term() {
|
||||
this.interrupt();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
public class Process_server_mock implements Scrib_server {
|
||||
private List_adp rsps = List_adp_.New(); private int rsps_idx = 0;
|
||||
public void Init(String... process_args) {}
|
||||
public int Server_timeout() {return server_timeout;} public Scrib_server Server_timeout_(int v) {server_timeout = v; return this;} private int server_timeout = 8000;
|
||||
public int Server_timeout_polling() {return server_timeout_polling;} public Scrib_server Server_timeout_polling_(int v) {server_timeout_polling = v; return this;} private int server_timeout_polling = 1;
|
||||
public int Server_timeout_busy_wait() {return server_timeout_busy_wait;} public Scrib_server Server_timeout_busy_wait_(int v) {server_timeout_busy_wait = v; return this;} private int server_timeout_busy_wait = 250;
|
||||
public byte[] Server_comm(byte[] cmd, Object[] cmd_objs) {
|
||||
Server_send(cmd, cmd_objs);
|
||||
return Server_recv();
|
||||
}
|
||||
public void Server_send(byte[] cmd, Object[] cmd_objs) {
|
||||
this.cmd_objs = cmd_objs;
|
||||
log_rcvd.Add(String_.new_u8(cmd));
|
||||
} Object[] cmd_objs;
|
||||
public byte[] Server_recv() {
|
||||
Process_server_mock_rcvd rcvd = (Process_server_mock_rcvd)rsps.Get_at(rsps_idx++);
|
||||
String rv = rcvd.Bld(cmd_objs);
|
||||
log_sent.Add(rv);
|
||||
return Bry_.new_u8(rv);
|
||||
}
|
||||
public void Term() {}
|
||||
public void Clear() {rsps.Clear(); rsps_idx = 0; log_rcvd.Clear(); log_sent.Clear();}
|
||||
public boolean Print_key() {return print_key;} public Process_server_mock Print_key_(boolean v) {print_key = v; return this;} private boolean print_key;
|
||||
public void Prep_add(String v) {rsps.Add(new Process_server_mock_rcvd_str(v));}
|
||||
public void Prep_add_dynamic_val() {rsps.Add(new Process_server_mock_rcvd_val(print_key));}
|
||||
public List_adp Log_rcvd() {return log_rcvd;} private List_adp log_rcvd = List_adp_.New();
|
||||
public List_adp Log_sent() {return log_sent;} private List_adp log_sent = List_adp_.New();
|
||||
}
|
||||
interface Process_server_mock_rcvd {
|
||||
String Bld(Object[] cmd_obs);
|
||||
}
|
||||
class Process_server_mock_rcvd_str implements Process_server_mock_rcvd {
|
||||
public Process_server_mock_rcvd_str(String rcvd) {this.rcvd = rcvd;} private String rcvd;
|
||||
public String Bld(Object[] cmd_obs) {return rcvd;}
|
||||
}
|
||||
class Process_server_mock_rcvd_val implements Process_server_mock_rcvd {
|
||||
public Process_server_mock_rcvd_val(boolean print_key) {this.print_key = print_key;} private boolean print_key;
|
||||
public String Bld(Object[] cmd_objs) {
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.New();
|
||||
Bld_recursive(tmp_bfr, 0, (Keyval[])cmd_objs[5]);
|
||||
byte[] values_str = tmp_bfr.To_bry_and_clear();
|
||||
tmp_bfr.Add(Bry_rv_bgn).Add_int_variable(values_str.length).Add(Bry_rv_mid).Add(values_str).Add(Bry_rv_end);
|
||||
return tmp_bfr.To_str_and_clear();
|
||||
}
|
||||
private void Bld_recursive(Bry_bfr bfr, int depth, Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Semic);
|
||||
Keyval kv = ary[i];
|
||||
Object kv_val = kv.Val();
|
||||
if (kv_val == null) {
|
||||
bfr.Add(gplx.langs.jsons.Json_itm_.Bry__null);
|
||||
continue;
|
||||
}
|
||||
Class<?> kv_val_type = kv_val.getClass();
|
||||
boolean kv_val_is_array = Type_adp_.Eq(kv_val_type, Keyval[].class);
|
||||
if (print_key && !kv_val_is_array)
|
||||
bfr.Add_str_u8(kv.Key()).Add_byte(Byte_ascii.Colon);
|
||||
if (Type_adp_.Eq(kv_val_type, Bool_.Cls_ref_type))
|
||||
bfr.Add(Bool_.Cast(kv_val) ? gplx.langs.jsons.Json_itm_.Bry__true : gplx.langs.jsons.Json_itm_.Bry__false);
|
||||
else if (kv_val_is_array) {
|
||||
Keyval[] sub = (Keyval[])kv_val;
|
||||
if (sub.length == 0) {bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Curly_end);}
|
||||
else {
|
||||
bfr.Add_byte_nl();
|
||||
bfr.Add_byte_repeat(Byte_ascii.Space, (depth + 1) * 2);
|
||||
Bld_recursive(bfr, depth + 1, (Keyval[])kv_val);
|
||||
}
|
||||
}
|
||||
else
|
||||
bfr.Add_str_u8(kv.Val_to_str_or_empty());
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] Bry_rv_bgn = Bry_.new_a7("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:"), Bry_rv_mid = Bry_.new_a7(":\""), Bry_rv_end = Bry_.new_a7("\";}}");
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import gplx.core.ios.*; import gplx.core.ios.streams.*; import gplx.core.encoders.*;
|
||||
public class Process_stream_rdr {
|
||||
public Process_stream_rdr(byte[] bry_header, byte[] bry_body) {this.bry_header = bry_header; this.bry_body = bry_body;} private byte[] bry_header, bry_body;
|
||||
public IoStream_stream_rdr Rdr() {return rdr;} IoStream_stream_rdr rdr = new IoStream_stream_rdr();
|
||||
public byte[] Read() {
|
||||
int bytes_read = rdr.Read(bry_header, 0, 16);
|
||||
if (bytes_read < 16) {
|
||||
if (bytes_read == -1) return null; // stream closed; should only occur when shutting down
|
||||
else throw Err_.new_wo_type("failed to read header");
|
||||
}
|
||||
int body_len = Hex_utl_.Parse_or(bry_header, 0,8, -1); if (body_len == -1) throw Err_.new_wo_type("failed to read body_len");
|
||||
int chk_len= Hex_utl_.Parse_or(bry_header, 9, 16, -1); if (chk_len == -1 || chk_len != (body_len * 2) - 1) throw Err_.new_wo_type("failed to read chk_len");
|
||||
byte[] trg_bry = (body_len > bry_body.length) ? new byte[body_len] : bry_body;
|
||||
return Read_body(trg_bry, body_len, rdr);
|
||||
}
|
||||
public byte[] Read_body(byte[] trg_bry, int src_len, IoStream rdr) {
|
||||
int src_len_orig = src_len;
|
||||
int src_pos = 0, trg_bgn = 0;
|
||||
boolean escaped = false, escaped_once = false;
|
||||
int adj = 0;
|
||||
while (src_pos < src_len_orig) {
|
||||
int read_len = rdr.Read(trg_bry, trg_bgn, src_len_orig - src_pos); // NOTE: 1st requests 16k, but only get back 2k; 2nd request 14k and only gets back 2k; etc.
|
||||
for (int i = 0; i < read_len; i++) {
|
||||
int trg_idx = trg_bgn + i;
|
||||
byte b = trg_bry[trg_idx];
|
||||
if (escaped) { // escaped mode; convert cur byte to appropriate byte
|
||||
switch (b) {
|
||||
case Byte_ascii.Ltr_n: b = Byte_ascii.Nl; break;
|
||||
case Byte_ascii.Ltr_r: b = Byte_ascii.Cr; break;
|
||||
case Byte_ascii.Backslash: b = Byte_ascii.Backslash; break;
|
||||
default: throw Err_.new_unhandled(b);
|
||||
}
|
||||
}
|
||||
else { // regular mode
|
||||
if (b == Byte_ascii.Backslash) {
|
||||
escaped = true; // flip flag
|
||||
escaped_once = true;
|
||||
--src_len; // add 1 to src_len; EX: "a\\nb" has 4 chars in stream, but src_len is reported as 3
|
||||
++adj; // add 1 to adj
|
||||
continue; // skip section below; cur byte is backslash, and is discarded (next byte is important)
|
||||
}
|
||||
}
|
||||
if (adj > 0 // check if there is adj; if no adj, don't bother overwriting; if adj, then shift all characters backwards; SEE:NOTE_1
|
||||
|| escaped_once) // NOTE: when trg_idx = 0, adj is always 0 but escaped can be true; occurs when straddling reads; EX: "a\nb\" -> 97
|
||||
trg_bry[trg_idx - adj] = b;
|
||||
escaped = false;
|
||||
}
|
||||
src_pos += read_len;
|
||||
trg_bgn += read_len;
|
||||
}
|
||||
return Bry_.Mid(trg_bry, 0, src_len);
|
||||
}
|
||||
}
|
||||
/*
|
||||
NOTE_1:
|
||||
EX: "a\nb\nc"
|
||||
. has src_len of 5: MWServer.lua counts chars exactly
|
||||
. has src_str of "a\\nb\\nc" (len of 7 characters: a, backslash, n, b, backslash, n, c); MWServer.lua converts \n -> \\n (or in ASCII, 10 -> 92 110)
|
||||
. so, process is as follows
|
||||
.. start :097 092 110 098 092 110 099 a \\ n b \\ n c)
|
||||
.. pass_0: 097 a
|
||||
.. pass_1: 097 092 \ escape mode entered; adj = 1
|
||||
.. pass_2a: 097 092 110 n n reached
|
||||
.. pass_2b: 097 092 010 n converted to \n
|
||||
.. pass_2c: 097 010 010 \n shifted down 1 to overwrite backslash
|
||||
.. pass_3: 097 010 098 b b shifted down 1 to overwrite \n
|
||||
.. pass_4: 097 010 098 092 \ escape mode entered; adj = 2
|
||||
.. pass_5: 097 010 098 010 n same as pass 2a-2c, except shift is 2
|
||||
.. pass_6: 097 010 098 010 099 c
|
||||
*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.engines.process; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.engines.*;
|
||||
import org.junit.*;
|
||||
import gplx.core.ios.*; import gplx.core.ios.streams.*;
|
||||
public class Process_stream_rdr_tst {
|
||||
@Before public void init() {fxt.Clear();} Scrib_lua_srl_fxt fxt = new Scrib_lua_srl_fxt();
|
||||
@Test public void Body_basic() {
|
||||
Process_stream_rdr_fxt fxt2 = new Process_stream_rdr_fxt().Init();
|
||||
fxt2.Init_src_str_("abcd").Test_read_body(); // read_1
|
||||
fxt2.Init_src_str_("abcde").Test_read_body(); // read_2
|
||||
fxt2.Init_src_str_("abcdefghijklm").Test_read_body(); // read_3
|
||||
fxt2.Init_src_str_w_nl_("a\\nb").Test_read_body(); // nl; read_1
|
||||
fxt2.Init_src_str_w_nl_("\\n\\\\ab").Test_read_body(); // nl; read_2
|
||||
fxt2.Init_src_str_w_nl_("\\n\\\\a").Test_read_body(); // nl; backslash
|
||||
fxt2.Init_src_str_w_nl_("a\\nb\\nc").Test_read_body(); // nl; straddling reads
|
||||
}
|
||||
}
|
||||
class Process_stream_rdr_fxt {
|
||||
public Process_stream_rdr_fxt Init() {
|
||||
if (process == null) {
|
||||
bry_header = new byte[16];
|
||||
bry_body = Bry_.Empty;
|
||||
rdr = new IoStream_mock().Read_limit_(5);
|
||||
process = new Process_stream_rdr(new byte[16], new byte[16]);
|
||||
}
|
||||
return this;
|
||||
} byte[] bry_header, bry_body; Process_stream_rdr process; IoStream_mock rdr;
|
||||
public Process_stream_rdr_fxt Init_src_str_(String v) {this.src_bry = Bry_.new_a7(v); src_len = src_bry.length; expd_str = v; return this;} private byte[] src_bry;
|
||||
public Process_stream_rdr_fxt Init_src_len_(int v) {this.src_len = v; return this;} private int src_len;
|
||||
public Process_stream_rdr_fxt Expd_str_(String v) {this.expd_str = v; return this;} private String expd_str;
|
||||
public Process_stream_rdr_fxt Init_src_str_w_nl_(String v) {
|
||||
this.Init_src_str_(v);
|
||||
int len = src_bry.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = src_bry[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Backslash:
|
||||
++i;
|
||||
b = src_bry[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Backslash: bfr.Add_byte(Byte_ascii.Backslash); break;
|
||||
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.Nl); break;
|
||||
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.Cr); break;
|
||||
default: throw Err_.new_unhandled(b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bfr.Add_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expd_str = bfr.To_str_and_clear();
|
||||
return this;
|
||||
} Bry_bfr bfr = Bry_bfr_.Reset(128);
|
||||
public void Test_read_body() {
|
||||
rdr.Data_bry_(src_bry);
|
||||
byte[] bry_body = new byte[src_len];
|
||||
rdr.Reset();
|
||||
byte[] rv = process.Read_body(bry_body, src_len, rdr);
|
||||
Tfds.Eq(expd_str, String_.new_a7(rv));
|
||||
Tfds.Eq(src_bry.length, rdr.Data_bry_pos());
|
||||
}
|
||||
}
|
||||
130
400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_comp_op_1.java
Normal file
130
400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_comp_op_1.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.errs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public interface Gfo_comp_op_1 {
|
||||
boolean Comp_bool(boolean val, boolean comp);
|
||||
boolean Comp_byte(byte val, byte comp);
|
||||
boolean Comp_int(int val, int comp);
|
||||
boolean Comp_long(long val, long comp);
|
||||
boolean Comp_float(float val, float comp);
|
||||
boolean Comp_double(double val, double comp);
|
||||
boolean Comp_decimal(Decimal_adp val, Decimal_adp comp);
|
||||
boolean Comp_char(char val, char comp);
|
||||
boolean Comp_str(String val, String comp);
|
||||
boolean Comp_bry(byte[] val, byte[] comp);
|
||||
boolean Comp_date(DateAdp val, DateAdp comp);
|
||||
boolean Comp_url(Io_url val, Io_url comp);
|
||||
boolean Comp_val(Gfo_val val, Gfo_val comp);
|
||||
boolean Comp_obj(Object val, Object comp);
|
||||
}
|
||||
class Gfo_comp_op_eq implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return val == comp;}
|
||||
public boolean Comp_byte(byte val, byte comp) {return val == comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val == comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val == comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val == comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val == comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return val.Eq(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val == comp;}
|
||||
public boolean Comp_str(String val, String comp) {return String_.Eq(val, comp);}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return Bry_.Eq(val, comp);}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return val.Eq(comp);}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return val.Eq(comp);}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return val.Eq(comp);}
|
||||
public boolean Comp_obj(Object val, Object comp) {return Object_.Eq(val, comp);}
|
||||
}
|
||||
class Gfo_comp_op_eqn implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return val != comp;}
|
||||
public boolean Comp_byte(byte val, byte comp) {return val != comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val != comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val != comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val != comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val != comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return !val.Eq(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val != comp;}
|
||||
public boolean Comp_str(String val, String comp) {return !String_.Eq(val, comp);}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return !Bry_.Eq(val, comp);}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return !val.Eq(comp);}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return !val.Eq(comp);}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return !val.Eq(comp);}
|
||||
public boolean Comp_obj(Object val, Object comp) {return Object_.Eq(val, comp);}
|
||||
}
|
||||
class Gfo_comp_op_lt implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return !val && comp;} // false < true
|
||||
public boolean Comp_byte(byte val, byte comp) {return val < comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val < comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val < comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val < comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val < comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return val.Comp_lt(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val < comp;}
|
||||
public boolean Comp_str(String val, String comp) {return String_.Compare(val, comp) == CompareAble_.Same;}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return Bry_.Compare(val, comp) < CompareAble_.Same;}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return val.compareTo(comp) < CompareAble_.Same;}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return val.compareTo(comp) < CompareAble_.Same;}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return val.compareTo(comp) < CompareAble_.Same;}
|
||||
public boolean Comp_obj(Object val, Object comp) {return CompareAble_.Compare_obj(val, comp) < CompareAble_.Same;}
|
||||
}
|
||||
class Gfo_comp_op_lte implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return !(val && !comp);} // !(true && false)
|
||||
public boolean Comp_byte(byte val, byte comp) {return val <= comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val <= comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val <= comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val <= comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val <= comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return val.Comp_lte(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val <= comp;}
|
||||
public boolean Comp_str(String val, String comp) {return String_.Compare(val, comp) != CompareAble_.More;}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return Bry_.Compare(val, comp) <= CompareAble_.Same;}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return val.compareTo(comp) <= CompareAble_.Same;}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return val.compareTo(comp) <= CompareAble_.Same;}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return val.compareTo(comp) <= CompareAble_.Same;}
|
||||
public boolean Comp_obj(Object val, Object comp) {return CompareAble_.Compare_obj(val, comp) <= CompareAble_.Same;}
|
||||
}
|
||||
class Gfo_comp_op_mt implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return val && !comp;} // true > false
|
||||
public boolean Comp_byte(byte val, byte comp) {return val > comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val > comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val > comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val > comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val > comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return val.Comp_lt(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val > comp;}
|
||||
public boolean Comp_str(String val, String comp) {return String_.Compare(val, comp) == CompareAble_.More;}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return Bry_.Compare(val, comp) > CompareAble_.Same;}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return val.compareTo(comp) > CompareAble_.Same;}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return val.compareTo(comp) > CompareAble_.Same;}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return val.compareTo(comp) > CompareAble_.Same;}
|
||||
public boolean Comp_obj(Object val, Object comp) {return CompareAble_.Compare_obj(val, comp) > CompareAble_.Same;}
|
||||
}
|
||||
class Gfo_comp_op_mte implements Gfo_comp_op_1 {
|
||||
public boolean Comp_bool(boolean val, boolean comp) {return !(!val && comp);} // !(false && true)
|
||||
public boolean Comp_byte(byte val, byte comp) {return val >= comp;}
|
||||
public boolean Comp_int(int val, int comp) {return val >= comp;}
|
||||
public boolean Comp_long(long val, long comp) {return val >= comp;}
|
||||
public boolean Comp_float(float val, float comp) {return val >= comp;}
|
||||
public boolean Comp_double(double val, double comp) {return val >= comp;}
|
||||
public boolean Comp_decimal(Decimal_adp val, Decimal_adp comp) {return val.Comp_lte(comp);}
|
||||
public boolean Comp_char(char val, char comp) {return val >= comp;}
|
||||
public boolean Comp_str(String val, String comp) {return String_.Compare(val, comp) != CompareAble_.Less;}
|
||||
public boolean Comp_bry(byte[] val, byte[] comp) {return Bry_.Compare(val, comp) >= CompareAble_.Same;}
|
||||
public boolean Comp_date(DateAdp val, DateAdp comp) {return val.compareTo(comp) >= CompareAble_.Same;}
|
||||
public boolean Comp_url(Io_url val, Io_url comp) {return val.compareTo(comp) >= CompareAble_.Same;}
|
||||
public boolean Comp_val(Gfo_val val, Gfo_val comp) {return val.compareTo(comp) >= CompareAble_.Same;}
|
||||
public boolean Comp_obj(Object val, Object comp) {return CompareAble_.Compare_obj(val, comp) >= CompareAble_.Same;}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.errs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.criterias.*;
|
||||
public interface Gfo_fld_owner {
|
||||
int Fld_val_as_int(int fld_idx);
|
||||
String Fld_val_as_str(int fld_idx);
|
||||
Object Fld_val_as_obj(int fld_idx);
|
||||
}
|
||||
interface Gfo_match {
|
||||
boolean Match(Gfo_fld_owner owner);
|
||||
}
|
||||
class Gfo_match_ {
|
||||
public boolean Match(Gfo_match root, Gfo_fld_owner owner) {
|
||||
return root.Match(owner);
|
||||
}
|
||||
}
|
||||
class Gfo_match_int_1 implements Gfo_match {
|
||||
public Gfo_match_int_1(int idx, Gfo_comp_op_1 comp, int rhs) {this.idx = idx; this.comp = comp; this.rhs = rhs;}
|
||||
private int idx; private int rhs;
|
||||
private Gfo_comp_op_1 comp;
|
||||
public boolean Match(Gfo_fld_owner owner) {
|
||||
int lhs = owner.Fld_val_as_int(idx);
|
||||
return comp.Comp_int(lhs, rhs);
|
||||
}
|
||||
}
|
||||
class Gfo_match_obj implements Gfo_match {
|
||||
public Gfo_match_obj(int idx, Gfo_comp_op_1 comp, Gfo_val rhs) {this.idx = idx; this.comp = comp; this.rhs = rhs;}
|
||||
private int idx; Gfo_val rhs;
|
||||
private Gfo_comp_op_1 comp;
|
||||
public boolean Match(Gfo_fld_owner owner) {
|
||||
Gfo_val lhs = (Gfo_val)owner.Fld_val_as_obj(idx);
|
||||
return lhs.Match_1(comp, rhs);
|
||||
}
|
||||
}
|
||||
class Gfo_fld_crt implements Criteria {
|
||||
public byte Tid() {return Criteria_.Tid_wrapper;}
|
||||
public byte Fld_idx() {return fld_idx;} private byte fld_idx;
|
||||
public Criteria Crt() {return crt;} private Criteria crt;
|
||||
public boolean Matches(Object o) {
|
||||
Gfo_fld_owner owner = (Gfo_fld_owner)o;
|
||||
Object comp = owner.Fld_val_as_obj(fld_idx);
|
||||
return crt.Matches(comp);
|
||||
}
|
||||
public void Val_from_args(Hash_adp args) {throw Err_.new_unimplemented();}
|
||||
public void Val_as_obj_(Object v) {throw Err_.new_unimplemented();}
|
||||
public String To_str() {return String_.Concat(Byte_.To_str(fld_idx), " ", crt.To_str());}
|
||||
public static Gfo_fld_crt new_(byte fld_idx, Criteria crt) {
|
||||
Gfo_fld_crt rv = new Gfo_fld_crt();
|
||||
rv.fld_idx = fld_idx; rv.crt = crt;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
31
400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_val.java
Normal file
31
400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_val.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.errs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public interface Gfo_val extends CompareAble {
|
||||
boolean Eq(Gfo_val rhs);
|
||||
boolean Match_1(Gfo_comp_op_1 op, Gfo_val comp);
|
||||
}
|
||||
class Gfo_val_mok implements Gfo_val {
|
||||
public String s = "";
|
||||
public boolean Eq(Gfo_val rhs) {return true;}
|
||||
public int compareTo(Object obj) {return 0;}
|
||||
public boolean Match_1(Gfo_comp_op_1 op, Gfo_val comp_obj) {
|
||||
Gfo_val_mok comp = (Gfo_val_mok)comp_obj;
|
||||
return op.Comp_str(s, comp.s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.errs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
class Scrib_err_mgr implements Gfo_invk {
|
||||
private Ordered_hash hash = Ordered_hash_.New_bry();
|
||||
private int key_id = 0;
|
||||
private static final byte[] Key_prefix = Bry_.new_a7("scrib_err_");
|
||||
private Scrib_err_cmd Set(byte[] key) {
|
||||
if (key == null) Bry_.Add(Key_prefix, Bry_.new_by_int(key_id++));
|
||||
Scrib_err_cmd rv = new Scrib_err_cmd(key);
|
||||
hash.Add_if_dupe_use_1st(key, rv);
|
||||
return rv;
|
||||
}
|
||||
public void Clear() {
|
||||
hash.Clear();
|
||||
key_id = 0;
|
||||
}
|
||||
public void Process(Scrib_err_data err) {
|
||||
int len = hash.Count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Scrib_err_cmd itm = (Scrib_err_cmd)hash.Get_at(i);
|
||||
if (itm.Warn_disabled(err)) {
|
||||
// log
|
||||
}
|
||||
else {
|
||||
// warn
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
||||
if (ctx.Match(k, Invk_set)) return Set(m.ReadBryOr("v", null));
|
||||
else if (ctx.Match(k, Invk_clear)) Clear();
|
||||
else return Gfo_invk_.Rv_unhandled;
|
||||
return this;
|
||||
} private static final String Invk_set = "set", Invk_clear = "clear";
|
||||
}
|
||||
class Scrib_err_data {
|
||||
public Scrib_err_data(byte[] mod, byte[] fnc, byte[] err, byte[] src) {this.mod = mod; this.fnc = fnc; this.err = err; this.src = src;}
|
||||
public byte[] Mod() {return mod;} private byte[] mod;
|
||||
public byte[] Fnc() {return fnc;} private byte[] fnc;
|
||||
public byte[] Err() {return err;} private byte[] err;
|
||||
public byte[] Src() {return src;} private byte[] src;
|
||||
}
|
||||
class Scrib_err_cmd implements Gfo_invk {
|
||||
public Scrib_err_cmd(byte[] key) {this.key = key;}
|
||||
public byte[] Key() {return key;} private byte[] key;
|
||||
public int Fail_after() {return fail_after;} private int fail_after = Int_.Max_value;
|
||||
public int Warn_every() {return warn_every;} private int warn_every = 10000; // worse case of 400 warnings for 4 million pages
|
||||
public int Summary_ttls_len() {return summary_ttls_len;} private int summary_ttls_len = 8;
|
||||
public String Warn_disabled_if() {return warn_disabled_if;} private String warn_disabled_if;
|
||||
private void Warn_disabled_if_(String v) {
|
||||
this.warn_disabled_if = v;
|
||||
// compile
|
||||
}
|
||||
public boolean Warn_disabled(Scrib_err_data err) {
|
||||
// gplx.core.criterias.Criteria c;
|
||||
// c.Matches(err);
|
||||
return false;
|
||||
}
|
||||
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
||||
if (ctx.Match(k, Invk_warn_disabled_if_)) Warn_disabled_if_(m.ReadStr("v"));
|
||||
else if (ctx.Match(k, Invk_fail_after_)) fail_after = m.ReadInt("v");
|
||||
else if (ctx.Match(k, Invk_warn_every_)) fail_after = m.ReadInt("v");
|
||||
else if (ctx.Match(k, Invk_summary_ttls_len_)) summary_ttls_len = m.ReadInt("v");
|
||||
else return Gfo_invk_.Rv_unhandled;
|
||||
return this;
|
||||
}
|
||||
private static final String
|
||||
Invk_warn_disabled_if_ = "warn_disabled_if_"
|
||||
, Invk_warn_every_ = "warn_every_", Invk_fail_after_ = "fail_after_"
|
||||
, Invk_summary_ttls_len_ = "summmary_ttls_len_"
|
||||
;
|
||||
}
|
||||
49
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Keyval_find_.java
Normal file
49
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Keyval_find_.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public class Keyval_find_ {
|
||||
public static Keyval Find(boolean fail, Keyval[] root, String... keys) {
|
||||
Keyval found = null;
|
||||
|
||||
Keyval[] kvs = root;
|
||||
int keys_len = keys.length;
|
||||
for (int i = 0; i < keys_len; ++i) {
|
||||
String key = keys[i];
|
||||
int kvs_len = kvs.length;
|
||||
found = null;
|
||||
for (int j = 0; j < kvs_len; ++j) {
|
||||
Keyval kv = kvs[j];
|
||||
if (String_.Eq(kv.Key(), key)) {
|
||||
found = kv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == null) {
|
||||
if (fail)
|
||||
throw Err_.new_wo_type("could not find key", "key", key);
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (i == keys_len - 1)
|
||||
return found;
|
||||
else
|
||||
kvs = (Keyval[])found.Val();
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
83
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Kv_ary_utl.java
Normal file
83
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Kv_ary_utl.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.langs.jsons.*;
|
||||
class Kv_ary_utl {
|
||||
public static Keyval[] new_(boolean base_1, Object... vals) {
|
||||
int len = vals.length;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; ++i)
|
||||
rv[i] = Keyval_.int_(i + (base_1 ? 1 : 0), vals[i]);
|
||||
return rv;
|
||||
}
|
||||
public static Keyval[] new_kvs(Keyval... vals) {return vals;}
|
||||
public static String Ary_to_str(Json_wtr wtr, Keyval[] ary) {
|
||||
wtr.Doc_nde_bgn();
|
||||
Ary_to_str(wtr, 0, ary);
|
||||
return wtr.Doc_nde_end().To_str_and_clear();
|
||||
}
|
||||
private static void Ary_to_str(Json_wtr wtr, int indent, Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Ary_to_str__itm(wtr, indent, ary[i]);
|
||||
}
|
||||
}
|
||||
private static void Ary_to_str__itm(Json_wtr wtr, int indent, Keyval itm) {
|
||||
Object val = itm.Val();
|
||||
Class<?> val_type = val.getClass();
|
||||
int type_tid = Type_adp_.To_tid_type(val_type);
|
||||
if (type_tid == Type_adp_.Tid__obj) {
|
||||
if (Type_adp_.Eq(val_type, Keyval[].class))
|
||||
Ary_to_str__nde(wtr, indent, itm.Key(), (Keyval[])itm.Val());
|
||||
else if (Type_adp_.Is_array(val_type))
|
||||
Ary_to_str__ary(wtr, indent, itm.Key(), Array_.cast(val));
|
||||
else
|
||||
throw Err_.new_unhandled(type_tid);
|
||||
}
|
||||
else
|
||||
wtr.Kv_obj(Bry_.new_u8(itm.Key()), itm.Val(), type_tid);
|
||||
}
|
||||
private static void Ary_to_str__ary(Json_wtr wtr, int indent, String key, Object array) {
|
||||
wtr.Ary_bgn(key);
|
||||
Ary_to_str__ary_itms(wtr, indent + 1, array);
|
||||
wtr.Ary_end();
|
||||
}
|
||||
private static void Ary_to_str__nde(Json_wtr wtr, int indent, String key, Keyval[] kv) {
|
||||
wtr.Nde_bgn(key);
|
||||
Ary_to_str(wtr, indent + 1, kv);
|
||||
wtr.Nde_end();
|
||||
}
|
||||
private static void Ary_to_str__ary_itms(Json_wtr wtr, int indent, Object array) {
|
||||
int len = Array_.Len(array);
|
||||
for (int j = 0; j < len; ++j) {
|
||||
Object itm = Array_.Get_at(array, j);
|
||||
Class<?> itm_type = itm.getClass();
|
||||
int itm_type_tid = Type_adp_.To_tid_type(itm_type);
|
||||
if (itm_type_tid == Type_adp_.Tid__obj) {
|
||||
if (Type_adp_.Eq(itm_type, Keyval.class))
|
||||
Ary_to_str__itm(wtr, indent + 1, (Keyval)itm);
|
||||
else if (Type_adp_.Is_array(itm_type))
|
||||
Ary_to_str__ary_itms(wtr, indent + 1, Array_.cast(itm));
|
||||
else
|
||||
throw Err_.new_unhandled(itm_type);
|
||||
}
|
||||
else
|
||||
wtr.Ary_itm_by_type_tid(itm_type_tid, itm);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_err.java
Normal file
24
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_err.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
class Scrib_err {
|
||||
public static Err Make__err__arg(String proc, int arg_idx, String actl, String expd) {
|
||||
String rv = String_.Format("bad argument #{0} to {1} ({2} expected, got {3})", arg_idx, proc, expd, actl); // "bad argument #$argIdx to '$name' ($expectType expected, got $type)"
|
||||
return Err_.new_("scribunto", rv);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_html implements Scrib_lib {
|
||||
public Scrib_lib_html(Scrib_core core) {}
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, String_.Ary_empty); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_html(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.html.lua"));
|
||||
return mod;
|
||||
}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.langs.*;
|
||||
import gplx.xowa.xtns.pfuncs.times.*; import gplx.xowa.langs.numbers.*; import gplx.xowa.xtns.pfuncs.numbers.*; import gplx.xowa.langs.durations.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_language implements Scrib_lib {
|
||||
public Scrib_lib_language(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_language(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.language.lua"));
|
||||
notify_lang_changed_fnc = mod.Fncs_get_by_key("notify_lang_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_lang_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_getContLangCode: return GetContLangCode(args, rslt);
|
||||
case Proc_isSupportedLanguage: return IsSupportedLanguage(args, rslt);
|
||||
case Proc_isKnownLanguageTag: return IsKnownLanguageTag(args, rslt);
|
||||
case Proc_isValidCode: return IsValidCode(args, rslt);
|
||||
case Proc_isValidBuiltInCode: return IsValidBuiltInCode(args, rslt);
|
||||
case Proc_fetchLanguageName: return FetchLanguageName(args, rslt);
|
||||
case Proc_fetchLanguageNames: return FetchLanguageNames(args, rslt);
|
||||
case Proc_getFallbacksFor: return GetFallbacksFor(args, rslt);
|
||||
case Proc_lcfirst: return Lcfirst(args, rslt);
|
||||
case Proc_ucfirst: return Ucfirst(args, rslt);
|
||||
case Proc_lc: return Lc(args, rslt);
|
||||
case Proc_uc: return Uc(args, rslt);
|
||||
case Proc_caseFold: return CaseFold(args, rslt);
|
||||
case Proc_formatNum: return FormatNum(args, rslt);
|
||||
case Proc_formatDate: return FormatDate(args, rslt);
|
||||
case Proc_formatDuration: return FormatDuration(args, rslt);
|
||||
case Proc_getDurationIntervals: return GetDurationIntervals(args, rslt);
|
||||
case Proc_parseFormattedNumber: return ParseFormattedNumber(args, rslt);
|
||||
case Proc_convertPlural: return ConvertPlural(args, rslt);
|
||||
case Proc_convertGrammar: return ConvertGrammar(args, rslt);
|
||||
case Proc_gender: return gender(args, rslt);
|
||||
case Proc_isRTL: return IsRTL(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int
|
||||
Proc_getContLangCode = 0, Proc_isSupportedLanguage = 1, Proc_isKnownLanguageTag = 2
|
||||
, Proc_isValidCode = 3, Proc_isValidBuiltInCode = 4, Proc_fetchLanguageName = 5, Proc_fetchLanguageNames = 6, Proc_getFallbacksFor = 7
|
||||
, Proc_lcfirst = 8, Proc_ucfirst = 9, Proc_lc = 10, Proc_uc = 11, Proc_caseFold = 12
|
||||
, Proc_formatNum = 13, Proc_formatDate = 14, Proc_formatDuration = 15, Proc_getDurationIntervals = 16, Proc_parseFormattedNumber = 17
|
||||
, Proc_convertPlural = 18, Proc_convertGrammar = 19, Proc_gender = 20, Proc_isRTL = 21
|
||||
;
|
||||
public static final String
|
||||
Invk_getContLangCode = "getContLangCode", Invk_isSupportedLanguage = "isSupportedLanguage", Invk_isKnownLanguageTag = "isKnownLanguageTag"
|
||||
, Invk_isValidCode = "isValidCode", Invk_isValidBuiltInCode = "isValidBuiltInCode"
|
||||
, Invk_fetchLanguageName = "fetchLanguageName", Invk_fetchLanguageNames = "fetchLanguageNames", Invk_getFallbacksFor = "getFallbacksFor"
|
||||
, Invk_lcfirst = "lcfirst", Invk_ucfirst = "ucfirst", Invk_lc = "lc", Invk_uc = "uc", Invk_caseFold = "caseFold"
|
||||
, Invk_formatNum = "formatNum", Invk_formatDate = "formatDate", Invk_formatDuration = "formatDuration", Invk_getDurationIntervals = "getDurationIntervals", Invk_parseFormattedNumber = "parseFormattedNumber"
|
||||
, Invk_convertPlural = "convertPlural", Invk_convertGrammar = "convertGrammar", Invk_gender = "gender", Invk_isRTL = "isRTL"
|
||||
;
|
||||
private static final String[] Proc_names = String_.Ary
|
||||
( Invk_getContLangCode, Invk_isSupportedLanguage, Invk_isKnownLanguageTag
|
||||
, Invk_isValidCode, Invk_isValidBuiltInCode, Invk_fetchLanguageName, Invk_fetchLanguageNames, Invk_getFallbacksFor
|
||||
, Invk_lcfirst, Invk_ucfirst, Invk_lc, Invk_uc, Invk_caseFold
|
||||
, Invk_formatNum, Invk_formatDate, Invk_formatDuration, Invk_getDurationIntervals, Invk_parseFormattedNumber
|
||||
, Invk_convertPlural, Invk_convertGrammar, Invk_gender, Invk_isRTL
|
||||
);
|
||||
public void Notify_lang_changed() {if (notify_lang_changed_fnc != null) core.Interpreter().CallFunction(notify_lang_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean GetContLangCode(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(core.Ctx().Lang().Key_str());}
|
||||
public boolean IsSupportedLanguage(Scrib_proc_args args, Scrib_proc_rslt rslt) {return IsKnownLanguageTag(args, rslt);}// NOTE: checks if "MessagesXX.php" exists; note that xowa has all "MessagesXX.php"; for now, assume same functionality as IsKnownLanguageTag (worst case is that a small wiki depends on a lang not being there; will need to put in a "wiki.Langs()" then)
|
||||
public boolean IsKnownLanguageTag(Scrib_proc_args args, Scrib_proc_rslt rslt) { // NOTE: checks if in languages/Names.php
|
||||
String lang_code = args.Cast_str_or_null(0);
|
||||
boolean exists = false;
|
||||
if ( lang_code != null // null check; protecting against Module passing in nil from lua
|
||||
&& String_.Eq(lang_code, String_.Lower(lang_code)) // must be lower-case; REF.MW: $code === strtolower( $code )
|
||||
&& Xol_lang_stub_.Exists(Bry_.new_a7(lang_code))
|
||||
)
|
||||
exists = true;
|
||||
return rslt.Init_obj(exists);
|
||||
}
|
||||
public boolean IsValidCode(Scrib_proc_args args, Scrib_proc_rslt rslt) { // REF.MW: Language.php!isValidCode
|
||||
byte[] lang_code = args.Pull_bry(0);
|
||||
boolean valid = Xoa_ttl.Parse(core.Wiki(), lang_code) != null; // NOTE: MW calls Title::getTitleInvalidRegex()
|
||||
if (valid) {
|
||||
int len = lang_code.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = lang_code[i];
|
||||
switch (b) { // NOTE: snippet from MW follows; also \000 assumed to be Nil --> :/\\\000&<>'\"
|
||||
case Byte_ascii.Colon: case Byte_ascii.Slash: case Byte_ascii.Backslash: case Byte_ascii.Null: case Byte_ascii.Amp: case Byte_ascii.Lt: case Byte_ascii.Gt: case Byte_ascii.Apos: case Byte_ascii.Quote:
|
||||
valid = false;
|
||||
i = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rslt.Init_obj(valid);
|
||||
}
|
||||
public boolean IsValidBuiltInCode(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] lang_code = args.Pull_bry(0);
|
||||
int len = lang_code.length;
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < len; i++) { // REF.MW: '/^[a-z0-9-]+$/i'
|
||||
byte b = lang_code[i];
|
||||
if (b == Byte_ascii.Dash) {}
|
||||
else {
|
||||
byte tid = Xol_lang_itm_.Char_tid(b);
|
||||
switch (tid) {
|
||||
case Xol_lang_itm_.Char_tid_ltr_l: case Xol_lang_itm_.Char_tid_ltr_u: case Xol_lang_itm_.Char_tid_num:
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
i = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rslt.Init_obj(valid);
|
||||
}
|
||||
public boolean FetchLanguageName(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] lang_code = args.Pull_bry(0);
|
||||
// byte[] trans_code = args.Get_bry_or_null(1); // TODO_OLD: FetchLanguageName("en", "fr") -> Anglais; WHEN: needs global database of languages; cldr
|
||||
Xol_lang_stub lang_itm = Xol_lang_stub_.Get_by_key_or_null(lang_code);
|
||||
return rslt.Init_obj(lang_itm == null ? String_.Empty : String_.new_u8(lang_itm.Canonical_name()));
|
||||
}
|
||||
public boolean FetchLanguageNames(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
// byte[] lang_code = args.Cast_bry_or_null(0);
|
||||
// byte[] include = args.Form_bry_or(1, FetchLanguageNames_mw);
|
||||
return rslt.Init_obj(core.Wiki().Cache_mgr().Scrib_lang_names()); // NOTE: return current language only; MW iterates over langs in wiki; XO is more complicated as technically all langs are available; need to map subset of langs per wiki, which is not trivial
|
||||
}
|
||||
public boolean GetFallbacksFor(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] lang_code = args.Pull_bry(0);
|
||||
Xol_lang_itm lang = core.App().Lang_mgr().Get_by(lang_code); if (lang == null) return rslt.Init_many_empty(); // lang is not valid; return empty array per MW;
|
||||
return rslt.Init_bry_ary(lang.Fallback_bry_ary());
|
||||
}
|
||||
public boolean Lcfirst(Scrib_proc_args args, Scrib_proc_rslt rslt) {return Case_1st(args, rslt, Bool_.N);}
|
||||
public boolean Ucfirst(Scrib_proc_args args, Scrib_proc_rslt rslt) {return Case_1st(args, rslt, Bool_.Y);}
|
||||
private boolean Case_1st(Scrib_proc_args args, Scrib_proc_rslt rslt, boolean upper) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] word = args.Pull_bry(1);
|
||||
Bry_bfr bfr = core.Wiki().Utl__bfr_mkr().Get_b128();
|
||||
try {
|
||||
return rslt.Init_obj(lang.Case_mgr().Case_build_1st(bfr, upper, word, 0, word.length));
|
||||
} finally {bfr.Mkr_rls();}
|
||||
}
|
||||
public boolean Lc(Scrib_proc_args args, Scrib_proc_rslt rslt) {return Case_all(args, rslt, Bool_.N);}
|
||||
public boolean Uc(Scrib_proc_args args, Scrib_proc_rslt rslt) {return Case_all(args, rslt, Bool_.Y);}
|
||||
private boolean Case_all(Scrib_proc_args args, Scrib_proc_rslt rslt, boolean upper) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] word = args.Pull_bry(1);
|
||||
return rslt.Init_obj(lang.Case_mgr().Case_build(upper, word, 0, word.length));
|
||||
}
|
||||
public boolean CaseFold(Scrib_proc_args args, Scrib_proc_rslt rslt) {return Uc(args, rslt);} // REF.MW:Language.php!caseFold; http://www.w3.org/International/wiki/Case_folding
|
||||
public boolean FormatNum(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] num = args.Xstr_bry_or_null(1);
|
||||
boolean skip_commafy = false;
|
||||
if (num != null) { // MW: if num present, check options table for noCommafy arg;
|
||||
Keyval[] kv_ary = args.Cast_kv_ary_or_null(2);
|
||||
if (kv_ary != null) {
|
||||
Object skip_commafy_obj = Keyval_.Ary_get_by_key_or_null(kv_ary, "noCommafy");
|
||||
if (skip_commafy_obj != null)
|
||||
skip_commafy = Bool_.Cast(skip_commafy_obj);
|
||||
}
|
||||
}
|
||||
byte[] rv = lang.Num_mgr().Format_num(num, skip_commafy);
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean FormatDate(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] fmt_bry = args.Pull_bry(1);
|
||||
byte[] date_bry = args.Cast_bry_or_empty(2); // NOTE: optional empty is required b/c date is sometimes null; use Bry_.Empty b/c this is what Pft_func_time.ParseDate takes; DATE:2013-04-05
|
||||
boolean utc = args.Cast_bool_or_n(3);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
Pft_fmt_itm[] fmt_ary = Pft_fmt_itm_.Parse(core.Ctx(), fmt_bry);
|
||||
DateAdp date = null;
|
||||
if (Bry_.Len_eq_0(date_bry))
|
||||
date = Datetime_now.Get();
|
||||
else {
|
||||
if (date_bry[0] == Byte_ascii.Plus) { // detect wikidata-style dates; EX: +00000002010-05-01T00:00:00Z; PAGE:en.w:Mountain_Province; DATE:2015-07-29
|
||||
int date_bry_len = date_bry.length;
|
||||
if ( date_bry[date_bry_len - 1] == Byte_ascii.Ltr_Z
|
||||
&& date_bry[date_bry_len - 10] == Byte_ascii.Ltr_T) {
|
||||
int year_bgn = Bry_find_.Find_fwd_while(date_bry, 1, date_bry_len, Byte_ascii.Num_0);
|
||||
date_bry = Bry_.Mid(date_bry, year_bgn); // lop off beginning "+000000..."
|
||||
}
|
||||
}
|
||||
date = Pft_func_time.ParseDate(date_bry, utc, tmp_bfr); // NOTE: not using java's datetime parse b/c it is more strict; not reconstructing PHP's datetime parse b/c it is very complicated (state machine); re-using MW's parser b/c it is inbetween; DATE:2015-07-29
|
||||
}
|
||||
if (date == null || tmp_bfr.Len() > 0) {tmp_bfr.Mkr_rls(); return rslt.Init_fail("bad argument #2 to 'formatDate' (not a valid timestamp)");}
|
||||
|
||||
wiki.Parser_mgr().Date_fmt_bldr().Format(tmp_bfr, wiki, lang, date, fmt_ary);
|
||||
byte[] rv = tmp_bfr.To_bry_and_rls();
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean ParseFormattedNumber(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] num = args.Xstr_bry_or_null(1);
|
||||
if (num == null) return rslt.Init_null(); // ParseFormattedNumber can sometimes take 1 arg ({'en'}), or null arg ({'en', null}); return null (not ""); DATE:2014-01-07
|
||||
byte[] rv = lang.Num_mgr().Raw(num);
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean FormatDuration(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
long seconds = args.Pull_long(1);
|
||||
Keyval[] intervals_kv_ary = args.Cast_kv_ary_or_null(2);
|
||||
Xol_duration_itm[] intervals = Xol_duration_itm_.Xto_itm_ary(intervals_kv_ary);
|
||||
byte[] rv = lang.Duration_mgr().Format_durations(core.Ctx(), seconds, intervals);
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean GetDurationIntervals(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
long seconds = args.Pull_long(1);
|
||||
Keyval[] intervals_kv_ary = args.Cast_kv_ary_or_null(2);
|
||||
Xol_duration_itm[] intervals = Xol_duration_itm_.Xto_itm_ary(intervals_kv_ary);
|
||||
Xol_interval_itm[] rv = lang.Duration_mgr().Get_duration_intervals(seconds, intervals);
|
||||
return rslt.Init_obj(Xol_interval_itm.Xto_kv_ary(rv));
|
||||
}
|
||||
public boolean ConvertPlural(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
int count = args.Pull_int(1);
|
||||
byte[][] words = args.Cast_params_as_bry_ary_or_rest_of_ary(2);
|
||||
byte[] rv = lang.Plural().Plural_eval(lang, count, words);
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean ConvertGrammar(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
byte[] word = args.Pull_bry(1);
|
||||
byte[] type = args.Pull_bry(2);
|
||||
Bry_bfr bfr = core.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
lang.Grammar().Grammar_eval(bfr, lang, word, type);
|
||||
return rslt.Init_obj(bfr.To_str_and_rls());
|
||||
}
|
||||
public boolean gender(Scrib_proc_args args, Scrib_proc_rslt rslt) {throw Err_.new_unimplemented();}
|
||||
public boolean IsRTL(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xol_lang_itm lang = lang_(args);
|
||||
return rslt.Init_obj(!lang.Dir_ltr());
|
||||
}
|
||||
private Xol_lang_itm lang_(Scrib_proc_args args) {
|
||||
byte[] lang_code = args.Cast_bry_or_null(0);
|
||||
Xol_lang_itm lang = lang_code == null ? null : core.App().Lang_mgr().Get_by_or_load(lang_code);
|
||||
if (lang == null) throw Err_.new_wo_type("lang_code is not valid", "lang_code", String_.new_u8(lang_code));
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.langs.numbers.*;
|
||||
public class Scrib_lib_language_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_language().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Test public void GetContLangCode() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_getContLangCode, Object_.Ary_empty, "en");
|
||||
}
|
||||
@Test public void IsSupportedLanguage() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isSupportedLanguage, Object_.Ary("fr"), true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isSupportedLanguage, Object_.Ary("qq"), false);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isSupportedLanguage, Object_.Ary("EN"), false);
|
||||
}
|
||||
@Test public void IsKnownLanguageTag() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isKnownLanguageTag, Object_.Ary("fr"), true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isKnownLanguageTag, Object_.Ary("qq"), false);
|
||||
}
|
||||
@Test public void IsValidCode() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isValidCode, Object_.Ary("a,b"), true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isValidCode, Object_.Ary("a'b"), false);
|
||||
}
|
||||
@Test public void IsValidBuiltInCode() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isValidBuiltInCode, Object_.Ary("e-N"), true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isValidBuiltInCode, Object_.Ary("e n"), false);
|
||||
}
|
||||
@Test public void FetchLanguageName() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_fetchLanguageName, Object_.Ary("en"), "English");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_fetchLanguageName, Object_.Ary("fr"), "Français");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_fetchLanguageName, Object_.Ary("enx"), "");
|
||||
}
|
||||
@Test public void GetFallbacksFor() {
|
||||
Xol_lang_itm other_lang = fxt.Core().App().Lang_mgr().Get_by_or_new(Bry_.new_a7("zh"));
|
||||
other_lang.Fallback_bry_(Bry_.new_a7("gan-hant, zh-hant, zh-hans"));
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_language.Invk_getFallbacksFor, Object_.Ary("zh"), String_.Concat_lines_nl
|
||||
( "1="
|
||||
, " 1=gan-hant"
|
||||
, " 2=zh-hant"
|
||||
, " 3=zh-hans"
|
||||
, " 4=en" // auto-add en
|
||||
));
|
||||
}
|
||||
@Test public void GetFallbacksFor_unknown() {
|
||||
fxt.Test_scrib_proc_empty(lib, Scrib_lib_language.Invk_getFallbacksFor, Object_.Ary("unknown"));
|
||||
}
|
||||
@Test public void FormatNum() {
|
||||
Xol_lang_itm other_lang = fxt.Core().App().Lang_mgr().Get_by_or_new(Bry_.new_a7("de")).Init_by_load_assert(); // NOTE: must call Init_by_load_assert, else load will be called by scrib and sprs below will get overwritten during load;
|
||||
fxt.Parser_fxt().Init_lang_numbers_separators(other_lang, ".", ",");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("de", 1234), "1.234"); // german spr
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", 1234), "1,234"); // english spr
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234"), "1,234"); // String passed (not int)
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234", Keyval_.Ary(Keyval_.new_("noCommafy", true))) , "1234"); // noCommafy.y
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatNum, Object_.Ary("en", "1234", Keyval_.Ary(Keyval_.new_("noCommafy", false))) , "1,234"); // noCommafy.n
|
||||
}
|
||||
@Test public void FormatDate() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d", "2013-03-17", false), "2013-03-17");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d"), Datetime_now.Get().XtoStr_fmt_yyyy_MM_dd()); // empty date should default to today;
|
||||
}
|
||||
@Test public void FormatDate__ymd_12() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d", "201603160102", false), "2016-03-16"); // handle long numeric date (12 digits); PAGE:en.w:Boron; DATE:2015-07-29
|
||||
}
|
||||
@Test public void FormatDate__utc() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d", "+00000002010-05-01T00:00:00Z", false), "2010-05-01"); // handle Wikidata style dates; PAGE:en.w:Mountain_Province; DATE:2015-07-29
|
||||
}
|
||||
@Test public void FormatDate_date_omitted() { // PURPOSE: some calls skip the date; retrieve arg_4 by int; EX: pl.w:L._Frank_Baum
|
||||
Datetime_now.Manual_y_();
|
||||
Datetime_now.Manual_(DateAdp_.new_(2013, 12, 19, 1, 2, 3, 4));
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Keyval_.Ary(Keyval_.int_(1, "en"), Keyval_.int_(2, "Y-m-d"), Keyval_.int_(4, false)), "2013-12-19");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDate, Object_.Ary("en", "Y-m-d", ""), "2013-12-19");// PURPOSE: '' should return today, not fail; EX: th.w:สถานีรถไฟตรัง
|
||||
Datetime_now.Manual_n_();
|
||||
}
|
||||
@Test public void Lc() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_lc, Object_.Ary("en", "ABC"), "abc");
|
||||
}
|
||||
@Test public void Uc() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_uc, Object_.Ary("en", "abc"), "ABC");
|
||||
}
|
||||
@Test public void LcFirst() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_lcfirst, Object_.Ary("en", "ABC"), "aBC");
|
||||
}
|
||||
@Test public void UcFirst() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_uc, Object_.Ary("en", "abc"), "ABC");
|
||||
}
|
||||
@Test public void ParseFormattedNumber() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_parseFormattedNumber, Object_.Ary("en", "1,234.56") , "1234.56"); // formatted String
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_parseFormattedNumber, Object_.Ary("en", "1234") , "1234"); // String
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_parseFormattedNumber, Object_.Ary("en", 1234) , "1234"); // int
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_parseFormattedNumber, Object_.Ary("en", 1234.56) , "1234.56"); // double
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_parseFormattedNumber, Object_.Ary("en"), Scrib_invoke_func_fxt.Null_rslt); // PURPOSE: missing arg should not fail; EX: ru.w:Туйон DATE:2014-01-06
|
||||
}
|
||||
@Test public void ConvertGrammar() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_convertGrammar, Object_.Ary("fi", "talo", "elative"), "talosta");
|
||||
}
|
||||
@Test public void ConvertPlural() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_convertPlural, Object_.Ary("ru", 5, Kv_ary_("a", "b", "c")), "c"); // forms in kv_ary
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_convertPlural, Object_.Ary("ru", 5, "a", "b", "c"), "c"); // forms as rest of ary; PAGE:ru.w:Ленин,_Владимир_Ильич DATE:2014-07-01
|
||||
}
|
||||
@Test public void IsRTL() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isRTL, Object_.Ary("en"), false);
|
||||
Xol_lang_itm other_lang = fxt.Core().App().Lang_mgr().Get_by_or_new(Bry_.new_a7("ar"));
|
||||
Gfo_invk_.Invk_by_val(other_lang, Xol_lang_itm.Invk_dir_rtl_, true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_language.Invk_isRTL, Object_.Ary("ar"), true);
|
||||
}
|
||||
@Test public void Format_duration() {
|
||||
Init_lang_durations(fxt.Core().Wiki());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDuration, Object_.Ary("en", 3723d, Kv_ary_("hours", "minutes", "seconds")), "1 hour, 2 minutes and 3 seconds"); // basic
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDuration, Object_.Ary("en", 123d, Kv_ary_("hours", "minutes", "seconds")), "2 minutes and 3 seconds"); // omit hour since < 1
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_language.Invk_formatDuration, Object_.Ary("en", 123d, Kv_ary_("hours")) , "0 hours"); // handle fractional duration
|
||||
}
|
||||
@Test public void Get_duration_intervals() {
|
||||
Init_lang_durations(fxt.Core().Wiki());
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_language.Invk_getDurationIntervals, Object_.Ary("en", 3723d, Kv_ary_("hours", "minutes", "seconds")), String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " hours=1"
|
||||
, " minutes=2"
|
||||
, " seconds=3"
|
||||
));
|
||||
}
|
||||
public static Keyval[] Kv_ary_(String... ary) {
|
||||
int ary_len = ary.length;
|
||||
Keyval[] rv = new Keyval[ary_len];
|
||||
for (int i = 0; i < ary_len; i++) {
|
||||
rv[i] = Keyval_.int_(i, ary[i]);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public static void Init_lang_durations(Xowe_wiki wiki) {
|
||||
Xol_msg_mgr msg_mgr = wiki.Lang().Msg_mgr();
|
||||
msg_mgr.Clear();
|
||||
msg_mgr.Itm_by_key_or_new("duration-millenia" , "~{0} {{PLURAL:~{0}\u007Cmillennium\u007Cmillennia}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-centuries" , "~{0} {{PLURAL:~{0}\u007Ccentury\u007Ccenturies}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-decades" , "~{0} {{PLURAL:~{0}\u007Cdecade\u007Cdecades}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-years" , "~{0} {{PLURAL:~{0}\u007Cyear\u007Cyears}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-weeks" , "~{0} {{PLURAL:~{0}\u007Cweek\u007Cweeks}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-days" , "~{0} {{PLURAL:~{0}\u007Cday\u007Cdays}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-hours" , "~{0} {{PLURAL:~{0}\u007Chour\u007Chours}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-minutes" , "~{0} {{PLURAL:~{0}\u007Cminute\u007Cminutes}}");
|
||||
msg_mgr.Itm_by_key_or_new("duration-seconds" , "~{0} {{PLURAL:~{0}\u007Csecond\u007Cseconds}}");
|
||||
msg_mgr.Itm_by_key_or_new("and" , " and");
|
||||
msg_mgr.Itm_by_key_or_new("word-separator" , " ");
|
||||
msg_mgr.Itm_by_key_or_new("comma-separator" , ", ");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.primitives.*; import gplx.langs.htmls.*;
|
||||
import gplx.xowa.apps.gfs.*;
|
||||
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_message implements Scrib_lib {
|
||||
public Scrib_lib_message(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_message(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.message.lua"));// NOTE: "lang" not passed in
|
||||
notify_lang_changed_fnc = mod.Fncs_get_by_key("notify_lang_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_lang_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_plain: return Plain(args, rslt);
|
||||
case Proc_check: return Check(args, rslt);
|
||||
case Proc_init_message_for_lang: return Init_message_for_lang(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_plain = 0, Proc_check = 1, Proc_init_message_for_lang = 2;
|
||||
public static final String Invk_plain = "plain", Invk_check = "check", Invk_init_message_for_lang = "init_message_for_lang";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_plain, Invk_check, Invk_init_message_for_lang);
|
||||
public void Notify_lang_changed() {if (notify_lang_changed_fnc != null) core.Interpreter().CallFunction(notify_lang_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean Plain(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte fmt_tid = Scrib_lib_message_data.Fmt_tid_plain;
|
||||
Keyval[] data_kvary = args.Pull_kv_ary_safe(0);
|
||||
Scrib_lib_message_data msg_data = new Scrib_lib_message_data().Parse(data_kvary);
|
||||
return rslt.Init_obj(String_.new_u8(msg_data.Make_msg(core.Cur_lang(), core.Wiki(), core.Ctx(), true, fmt_tid)));
|
||||
}
|
||||
public boolean Check(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte chk_tid = Scrib_lib_message_data.parse_chk_(args.Pull_bry(0));
|
||||
Keyval[] data_kvary = args.Pull_kv_ary_safe(1);
|
||||
Scrib_lib_message_data msg_data = new Scrib_lib_message_data().Parse(data_kvary);
|
||||
return rslt.Init_obj(msg_data.Chk_msg(core.Cur_lang(), core.Wiki(), core.Ctx(), false, chk_tid));
|
||||
}
|
||||
public boolean Init_message_for_lang(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(Keyval_.new_("lang", core.Wiki().Lang().Key_str()));}
|
||||
}
|
||||
class Scrib_lib_message_data {
|
||||
public boolean Use_db() {return use_db;} private boolean use_db;
|
||||
public byte[] Lang_key() {return lang_key;} private byte[] lang_key = Bry_.Empty;
|
||||
public byte[] Title_bry() {return title_bry;} private byte[] title_bry;
|
||||
public byte[] Msg_key() {return msg_key;} private byte[] msg_key;
|
||||
public byte[] Raw_msg_key() {return raw_msg_key;} private byte[] raw_msg_key;
|
||||
public Object[] Args() {return args;} Object[] args;
|
||||
public Xoa_ttl Ttl() {return ttl;} public Scrib_lib_message_data Ttl_(Xoa_ttl v) {ttl = v; return this;} Xoa_ttl ttl;
|
||||
public Scrib_lib_message_data Parse(Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval kv = ary[i];
|
||||
byte[] kv_key = Bry_.new_a7(kv.Key());
|
||||
Object key_obj = key_hash.Get_by(kv_key); if (key_obj == null) throw Err_.new_wo_type("msg_key is invalid", "key", kv_key);
|
||||
byte key_tid = ((Byte_obj_val)key_obj).Val();
|
||||
switch (key_tid) {
|
||||
case Key_tid_keys:
|
||||
Keyval[] keys_ary = (Keyval[])kv.Val();
|
||||
msg_key = keys_ary[0].Val_to_bry();
|
||||
break;
|
||||
case Key_tid_rawMessage: raw_msg_key = kv.Val_to_bry(); break;
|
||||
case Key_tid_lang: lang_key = kv.Val_to_bry(); break;
|
||||
case Key_tid_useDB: use_db = Bool_.Cast(kv.Val()); break;
|
||||
case Key_tid_title: title_bry = kv.Val_to_bry(); break;
|
||||
case Key_tid_params:
|
||||
Keyval[] args_ary = (Keyval[])kv.Val();
|
||||
int args_ary_len = args_ary.length;
|
||||
args = new String[args_ary_len];
|
||||
for (int j = 0; j < args_ary_len; j++)
|
||||
args[j] = args_ary[j].Val_to_str_or_empty();
|
||||
break;
|
||||
default: throw Err_.new_unhandled(key_tid);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public byte[] Fetch_msg(byte[] cur_lang, Xowe_wiki wiki, Xop_ctx ctx, boolean exec_params) {
|
||||
if (exec_params) {
|
||||
byte[] data_ttl = title_bry;
|
||||
if (data_ttl == null)
|
||||
ttl = ctx.Page().Ttl();
|
||||
else
|
||||
ttl = Xoa_ttl.Parse(wiki, data_ttl);
|
||||
}
|
||||
if (raw_msg_key != null) {
|
||||
Xol_msg_itm raw_msg_itm = new Xol_msg_itm(-1, Bry_.Empty);
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.New(); // wiki.Utl__bfr_mkr().Get_b512();
|
||||
byte[] raw_msg_val = Gfs_php_converter.To_gfs(tmp_bfr, raw_msg_key);
|
||||
Xol_msg_itm_.update_val_(raw_msg_itm, raw_msg_val);
|
||||
byte[] raw_msg_rv = wiki.Msg_mgr().Val_by_itm(tmp_bfr, raw_msg_itm, args);
|
||||
tmp_bfr.Mkr_rls();
|
||||
return raw_msg_rv;
|
||||
}
|
||||
if (msg_key == null) return Bry_.Empty;
|
||||
|
||||
if (Bry_.Eq(lang_key, cur_lang) || Bry_.Len_eq_0(lang_key)) // if lang_key == core_lang then use wiki.msg_mgr; also same if lang_key == blank (arg not given)
|
||||
return wiki.Msg_mgr().Val_by_key_args(msg_key, args);
|
||||
else {
|
||||
Xol_lang_itm lang = wiki.Appe().Lang_mgr().Get_by_or_new(lang_key); lang.Init_by_load_assert();
|
||||
Xol_msg_itm msg_itm = lang.Msg_mgr().Itm_by_key_or_null(msg_key); if (msg_itm == null) return Bry_.Empty;
|
||||
return msg_itm.Val();
|
||||
}
|
||||
}
|
||||
public boolean Chk_msg(byte[] cur_lang, Xowe_wiki wiki, Xop_ctx ctx, boolean exec_params, byte chk_tid) {
|
||||
byte[] msg_val = Fetch_msg(cur_lang, wiki, ctx, false);
|
||||
switch (chk_tid) {
|
||||
case Check_tid_exists : return Bry_.Len_gt_0(msg_val);
|
||||
case Check_tid_isBlank : return Bry_.Len_eq_0(msg_val); // REF.MW: $message === false || $message === ''
|
||||
case Check_tid_isDisabled : return Bry_.Len_eq_0(msg_val) || msg_val.length == 1 && msg_val[0] == Byte_ascii.Dash; // REF.MW: $message === false || $message === '' || $message === '-'
|
||||
default : throw Err_.new_unhandled(chk_tid);
|
||||
}
|
||||
}
|
||||
public byte[] Make_msg(byte[] cur_lang, Xowe_wiki wiki, Xop_ctx ctx, boolean exec_params, byte fmt_tid) {
|
||||
byte[] msg_val = Fetch_msg(cur_lang, wiki, ctx, exec_params);
|
||||
if ( Bry_.Len_eq_0(msg_val) // msg_key returned empty/null msg_val; assume not found
|
||||
&& raw_msg_key == null // ignore if raw_msg; note that raw_msg can generate empty String; EX:raw_msg={{empty}} -> ""; PAGE:it.w:L'Internazionale DATE:2015-02-25
|
||||
) {
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
bfr.Add(gplx.langs.htmls.entitys.Gfh_entity_.Lt_bry).Add(msg_key).Add(gplx.langs.htmls.entitys.Gfh_entity_.Gt_bry); // NOTE: Message.php has logic that says: if plain, "< >", else "< >"; for now, always use escaped
|
||||
return bfr.To_bry_and_rls();
|
||||
}
|
||||
switch (fmt_tid) {
|
||||
case Fmt_tid_parse:
|
||||
case Fmt_tid_text: // NOTE: not sure what this does; seems to be a "lighter" parser
|
||||
break;
|
||||
case Fmt_tid_parseAsBlock: // NOTE: MW passes msg_val through parser and strips <p> if tid==parse; XOWA does the opposite, so add <p> if parseAsBlock requested
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
msg_val = bfr.Add(Gfh_tag_.P_lhs).Add(msg_val).Add(Gfh_tag_.P_rhs).To_bry_and_rls();
|
||||
break;
|
||||
case Fmt_tid_escaped:
|
||||
msg_val = gplx.langs.htmls.Gfh_utl.Escape_html_as_bry(msg_val);
|
||||
break;
|
||||
}
|
||||
return msg_val;
|
||||
}
|
||||
static final byte Key_tid_keys = 1, Key_tid_rawMessage = 2, Key_tid_lang = 3, Key_tid_useDB = 4, Key_tid_title = 5, Key_tid_params = 6;
|
||||
private static final Hash_adp_bry key_hash = Hash_adp_bry.ci_a7()
|
||||
.Add_str_byte("keys", Key_tid_keys)
|
||||
.Add_str_byte("rawMessage", Key_tid_rawMessage)
|
||||
.Add_str_byte("lang", Key_tid_lang)
|
||||
.Add_str_byte("useDB", Key_tid_useDB)
|
||||
.Add_str_byte("title", Key_tid_title)
|
||||
.Add_str_byte("params", Key_tid_params);
|
||||
public static byte parse_fmt_(byte[] key) {return parse_or_fail(fmt_hash, key, "invalid message format: {0}");}
|
||||
public static byte parse_chk_(byte[] key) {return parse_or_fail(check_hash, key, "invalid check arg: {0}");}
|
||||
public static byte parse_or_fail(Hash_adp_bry hash, byte[] key, String fmt) {
|
||||
Object o = hash.Get_by_bry(key);
|
||||
if (o == null) throw Err_.new_wo_type(fmt, "key", String_.new_u8(key)).Trace_ignore_add_1_();
|
||||
return ((Byte_obj_val)o).Val();
|
||||
}
|
||||
public static final byte Fmt_tid_parse = 1, Fmt_tid_text = 2, Fmt_tid_plain = 3, Fmt_tid_escaped = 4, Fmt_tid_parseAsBlock = 5;
|
||||
private static final Hash_adp_bry fmt_hash = Hash_adp_bry.ci_a7()
|
||||
.Add_str_byte("parse", Fmt_tid_parse)
|
||||
.Add_str_byte("text", Fmt_tid_text)
|
||||
.Add_str_byte("plain", Fmt_tid_plain)
|
||||
.Add_str_byte("escaped", Fmt_tid_escaped)
|
||||
.Add_str_byte("parseAsBlock", Fmt_tid_parseAsBlock);
|
||||
public static final byte Check_tid_exists = 1, Check_tid_isBlank = 2, Check_tid_isDisabled = 3;
|
||||
private static final Hash_adp_bry check_hash = Hash_adp_bry.ci_a7()
|
||||
.Add_str_byte("exists", Check_tid_exists)
|
||||
.Add_str_byte("isBlank", Check_tid_isBlank)
|
||||
.Add_str_byte("isDisabled", Check_tid_isDisabled);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.langs.*;
|
||||
public class Scrib_lib_message_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_message().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Test public void Plain() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)keys_ary("sun")) , "Sun");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)keys_ary("sunx")) , "<sunx>");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)keys_ary_arg("redirectedfrom", "A")) , "(Redirected from A)");
|
||||
}
|
||||
@Test public void Plain_lang() {
|
||||
Xol_lang_itm lang = fxt.Parser_fxt().Wiki().Appe().Lang_mgr().Get_by_or_new(Bry_.new_a7("fr"));
|
||||
Init_msg(lang, "sun", "dim");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)keys_ary_lang("sun", "fr")) , "dim");
|
||||
}
|
||||
@Test public void Plain_rawMessage() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)Scrib_kv_utl_.flat_many_("rawMessage", "$1", "params", Keyval_.Ary(Keyval_.int_(1, "abc")))), "abc");
|
||||
}
|
||||
@Test public void Plain_rawMessage_empty() {// PURPOSE:rawMessage would throw null ref if rawMessage called template that returns empty value; PAGE:it.w:L'Internazionale DATE:2015-02-25
|
||||
fxt.Parser_fxt().Init_page_create("Template:Msg", "");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_plain, Object_.Ary((Object)Scrib_kv_utl_.flat_many_("rawMessage", "{{Msg}}", "params", Keyval_.Ary(Keyval_.int_(1, "abc")))), "");
|
||||
}
|
||||
@Test public void Check() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("exists" , keys_ary("sun")) , true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("exists" , keys_ary("sunx")) , false);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isBlank" , keys_ary("sun")) , false);
|
||||
Init_msg("blank", "");
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isBlank" , keys_ary("blank")) , true);
|
||||
Init_msg("disabled", "-");
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isDisabled" , keys_ary("sun")) , false);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isDisabled" , keys_ary("blank")) , true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isDisabled" , keys_ary("disabled")) , true);
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_message.Invk_check, Object_.Ary("isBlank" , keys_ary("disabled")) , false);
|
||||
}
|
||||
@Test public void Init_message_for_lang() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_message.Invk_init_message_for_lang, Object_.Ary_empty , "lang=en");
|
||||
}
|
||||
private void Init_msg(String key, String val) {Init_msg(fxt.Core().Wiki().Lang(), key, val);}
|
||||
private void Init_msg(Xol_lang_itm lang, String key, String val) {
|
||||
lang.Msg_mgr().Itm_by_key_or_new(Bry_.new_a7(key)).Atrs_set(Bry_.new_a7(val), false, false);
|
||||
}
|
||||
Keyval[] keys_ary(String msg_key) {return keys_ary(msg_key, null, null);}
|
||||
Keyval[] keys_ary_arg(String msg_key, String arg) {return keys_ary(msg_key, null, arg);}
|
||||
Keyval[] keys_ary_lang(String msg_key, String lang) {return keys_ary(msg_key, lang, null);}
|
||||
Keyval[] keys_ary(String msg_key, String lang, String arg) {
|
||||
boolean arg_exists = arg != null;
|
||||
boolean lang_exists = lang != null;
|
||||
int idx = 0;
|
||||
Keyval[] rv = new Keyval[1 + (arg_exists ? 1 : 0) + (lang_exists ? 1 : 0)];
|
||||
rv[0] = Keyval_.new_("keys", Keyval_.Ary(Keyval_.int_(1, msg_key)));
|
||||
if (arg_exists)
|
||||
rv[++idx] = Keyval_.new_("params", Keyval_.Ary(Keyval_.int_(1, arg)));
|
||||
if (lang_exists)
|
||||
rv[++idx] = Keyval_.new_("lang", lang);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
402
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_mw.java
Normal file
402
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_mw.java
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.primitives.*; import gplx.core.envs.*; import gplx.core.errs.*;
|
||||
import gplx.xowa.langs.*; import gplx.xowa.langs.funcs.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_mw implements Scrib_lib {
|
||||
private Scrib_core core; private Scrib_fsys_mgr fsys_mgr;
|
||||
public Scrib_lib_mw(Scrib_core core) {this.core = core; this.fsys_mgr = core.Fsys_mgr();}
|
||||
public Scrib_lua_mod Mod() {return mod;} public void Mod_(Scrib_lua_mod v) {this.mod = v;} private Scrib_lua_mod mod;
|
||||
public boolean Allow_env_funcs() {return allow_env_funcs;} private boolean allow_env_funcs = true;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_mw(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
core.RegisterInterface(this, script_dir.GenSubFil("mwInit.lua")); // DATE:2014-07-12
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.lua")
|
||||
, Keyval_.new_("allowEnvFuncs", allow_env_funcs));
|
||||
return mod;
|
||||
}
|
||||
public void Invoke_bgn(Xowe_wiki wiki, Xop_ctx ctx, byte[] new_src) {
|
||||
if (src != null) // src exists; indicates that Invoke being called recursively; push existing src onto stack
|
||||
src_stack.Add(src);
|
||||
this.cur_wiki = wiki; this.ctx = ctx; this.src = new_src;
|
||||
} private Xowe_wiki cur_wiki; private byte[] src; private Xop_ctx ctx; private List_adp src_stack = List_adp_.New();
|
||||
public void Invoke_end() {
|
||||
if (src_stack.Count() > 0) // src_stack item exists; pop
|
||||
src = (byte[])List_adp_.Pop(src_stack);
|
||||
else // entry point; set to null
|
||||
src = null;
|
||||
}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_loadPackage: return LoadPackage(args, rslt);
|
||||
case Proc_loadPHPLibrary: return LoadPHPLibrary(args, rslt);
|
||||
case Proc_frameExists: return FrameExists(args, rslt);
|
||||
case Proc_newChildFrame: return NewChildFrame(args, rslt);
|
||||
case Proc_getExpandedArgument: return GetExpandedArgument(args, rslt);
|
||||
case Proc_getAllExpandedArguments: return GetAllExpandedArguments(args, rslt);
|
||||
case Proc_expandTemplate: return ExpandTemplate(args, rslt);
|
||||
case Proc_callParserFunction: return CallParserFunction(args, rslt);
|
||||
case Proc_preprocess: return Preprocess(args, rslt);
|
||||
case Proc_incrementExpensiveFunctionCount: return IncrementExpensiveFunctionCount(args, rslt);
|
||||
case Proc_isSubsting: return IsSubsting(args, rslt);
|
||||
case Proc_getFrameTitle: return GetFrameTitle(args, rslt);
|
||||
case Proc_setTTL: return SetTTL(args, rslt);
|
||||
case Proc_parentFrameExists: return ParentFrameExists(args, rslt); // DEPRECATED:not in Scribunto anymore
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
public static final int
|
||||
Proc_loadPackage = 0, Proc_loadPHPLibrary = 1
|
||||
, Proc_frameExists = 2, Proc_newChildFrame = 3
|
||||
, Proc_getExpandedArgument = 4, Proc_getAllExpandedArguments = 5
|
||||
, Proc_expandTemplate = 6, Proc_callParserFunction = 7, Proc_preprocess = 8
|
||||
, Proc_incrementExpensiveFunctionCount = 9, Proc_isSubsting = 10
|
||||
, Proc_getFrameTitle = 11, Proc_setTTL = 12
|
||||
, Proc_parentFrameExists = 13
|
||||
;
|
||||
public static final String
|
||||
Invk_loadPackage = "loadPackage", Invk_loadPHPLibrary = "loadPHPLibrary"
|
||||
, Invk_frameExists = "frameExists", Invk_newChildFrame = "newChildFrame"
|
||||
, Invk_getExpandedArgument = "getExpandedArgument", Invk_getAllExpandedArguments = "getAllExpandedArguments"
|
||||
, Invk_expandTemplate = "expandTemplate", Invk_callParserFunction = "callParserFunction", Invk_preprocess = "preprocess"
|
||||
, Invk_incrementExpensiveFunctionCount = "incrementExpensiveFunctionCount", Invk_isSubsting = "isSubsting"
|
||||
, Invk_getFrameTitle = "getFrameTitle", Invk_setTTL = "setTTL"
|
||||
, Invk_parentFrameExists = "parentFrameExists"
|
||||
;
|
||||
private static final String[] Proc_names = String_.Ary
|
||||
( Invk_loadPackage, Invk_loadPHPLibrary
|
||||
, Invk_frameExists, Invk_newChildFrame
|
||||
, Invk_getExpandedArgument, Invk_getAllExpandedArguments
|
||||
, Invk_expandTemplate, Invk_callParserFunction, Invk_preprocess
|
||||
, Invk_incrementExpensiveFunctionCount, Invk_isSubsting
|
||||
, Invk_getFrameTitle, Invk_setTTL
|
||||
, Invk_parentFrameExists
|
||||
);
|
||||
public boolean LoadPackage(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String mod_name = args.Pull_str(0);
|
||||
String mod_code = fsys_mgr.Get_or_null(mod_name); // check if mod_name a file in /lualib/ directoryScribunto .lua file (in /lualib/)
|
||||
if (mod_code != null)
|
||||
return rslt.Init_obj(core.Interpreter().LoadString("@" + mod_name + ".lua", mod_code));
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(cur_wiki, Bry_.new_u8(mod_name));// NOTE: should have Module: prefix
|
||||
if (ttl == null) return rslt.Init_ary_empty();
|
||||
byte[] page_db = cur_wiki.Cache_mgr().Page_cache().Get_or_load_as_src(ttl);
|
||||
if (page_db == null) return rslt.Init_ary_empty();
|
||||
Scrib_lua_mod mod = new Scrib_lua_mod(core, mod_name);
|
||||
return rslt.Init_obj(mod.LoadString(String_.new_u8(page_db)));
|
||||
}
|
||||
public boolean LoadPHPLibrary(Scrib_proc_args args, Scrib_proc_rslt rslt) { // NOTE: noop; Scribunto uses this to load the Scribunto_*Library classses (EX: Scribunto_TitleLibrary); DATE:2015-01-21
|
||||
return rslt.Init_obj(null);
|
||||
}
|
||||
public boolean GetExpandedArgument(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
int frame_arg_adj = Scrib_frame_.Get_arg_adj(frame.Frame_tid());
|
||||
String idx_str = args.Pull_str(1);
|
||||
int idx_int = Int_.parse_or(idx_str, Int_.Min_value); // NOTE: should not receive int value < -1; idx >= 0
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.New(); // NOTE: do not make modular level variable, else random failures; DATE:2013-10-14
|
||||
if (idx_int != Int_.Min_value) { // idx is integer
|
||||
Arg_nde_tkn nde = Get_arg(frame, idx_int, frame_arg_adj);
|
||||
//frame.Args_eval_by_idx(core.Ctx().Src(), idx_int); // NOTE: arg[0] is always MW function name; EX: {{#invoke:Mod_0|Func_0|Arg_1}}; arg_x = "Mod_0"; args[0] = "Func_0"; args[1] = "Arg_1"
|
||||
if (nde == null) return rslt.Init_ary_empty();
|
||||
nde.Val_tkn().Tmpl_evaluate(ctx, src, core.Frame_parent(), tmp_bfr);
|
||||
return rslt.Init_obj(tmp_bfr.To_str_and_clear());
|
||||
}
|
||||
else {
|
||||
Arg_nde_tkn nde = frame.Args_get_by_key(src, Bry_.new_u8(idx_str));
|
||||
if (nde == null) return rslt.Init_ary_empty(); // idx_str does not exist;
|
||||
nde.Val_tkn().Tmpl_evaluate(ctx, src, core.Frame_parent(), tmp_bfr);
|
||||
return rslt.Init_obj(tmp_bfr.To_str_and_clear_and_trim()); // NOTE: must trim if key_exists; DUPE:TRIM_IF_KEY
|
||||
}
|
||||
}
|
||||
private Arg_nde_tkn Get_arg(Xot_invk invk, int idx, int frame_arg_adj) { // DUPE:MW_ARG_RETRIEVE
|
||||
int cur = List_adp_.Base1, len = invk.Args_len() - frame_arg_adj;
|
||||
for (int i = 0; i < len; i++) { // iterate over list to find nth *non-keyd* arg; SEE:NOTE_1
|
||||
Arg_nde_tkn nde = (Arg_nde_tkn)invk.Args_get_by_idx(i + frame_arg_adj);
|
||||
if (nde.KeyTkn_exists()) { // BLOCK:ignore_args_with_empty_keys;
|
||||
if (Verify_arg_key(src, idx, nde))
|
||||
return nde;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (idx == cur) return nde;
|
||||
else ++cur;
|
||||
}
|
||||
return invk.Args_get_by_key(src, Bry_.To_a7_bry(idx + 1, 1));
|
||||
}
|
||||
private static boolean Verify_arg_key(byte[] src, int idx, Arg_nde_tkn nde) {
|
||||
int key_int = Bry_find_.Not_found;
|
||||
byte[] key_dat_ary = nde.Key_tkn().Dat_ary();
|
||||
if (Env_.Mode_testing() && src == null) // some tests will always pass a null src;
|
||||
key_int = Bry_.To_int_or(key_dat_ary, 0, key_dat_ary.length, Bry_find_.Not_found);
|
||||
else {
|
||||
if (Bry_.Len_eq_0(key_dat_ary)) // should be called by current context;
|
||||
key_int = Bry_.To_int_or(src, nde.Key_tkn().Src_bgn(), nde.Key_tkn().Src_end(), Bry_find_.Not_found);
|
||||
else // will be called by parent context; note that this calls Xot_defn_tmpl_.Make_itm which sets a key_dat_ary; DATE:2013-09-23
|
||||
key_int = Bry_.To_int_or(key_dat_ary, 0, key_dat_ary.length, Bry_find_.Not_found);
|
||||
}
|
||||
if (key_int == Bry_find_.Not_found) // key is not-numeric
|
||||
return false;
|
||||
else // key is numeric
|
||||
return idx == key_int;
|
||||
}
|
||||
public boolean GetAllExpandedArguments(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
byte frame_tid = frame.Frame_tid();
|
||||
Xot_invk parent_frame = Scrib_frame_.Get_parent(core, frame_tid);
|
||||
int frame_arg_adj = Scrib_frame_.Get_arg_adj(frame_tid);
|
||||
int args_len = frame.Args_len() - frame_arg_adj;
|
||||
if (args_len < 1) return rslt.Init_obj(Keyval_.Ary_empty); // occurs when "frame:getParent().args" but no parent frame
|
||||
Bry_bfr tmp_bfr = ctx.Wiki().Utl__bfr_mkr().Get_b128(); // NOTE: do not make modular level variable, else random failures; DATE:2013-10-14
|
||||
List_adp rv = List_adp_.New();
|
||||
int arg_idx = 0;
|
||||
for (int i = 0; i < args_len; i++) {
|
||||
Arg_nde_tkn nde = frame.Args_get_by_idx(i + frame_arg_adj);
|
||||
if (nde.KeyTkn_exists()) { // BLOCK:ignore_args_with_empty_keys;
|
||||
byte[] key_dat_ary = nde.Key_tkn().Dat_ary();
|
||||
int key_dat_len = Bry_.Len(key_dat_ary);
|
||||
if (Env_.Mode_testing() && src == null) {
|
||||
if (key_dat_len == 0) continue;
|
||||
}
|
||||
else {
|
||||
if (key_dat_len == 0) // should be called by current context;
|
||||
if (nde.Key_tkn().Src_end() - nde.Key_tkn().Src_bgn() == 0) continue;
|
||||
}
|
||||
}
|
||||
nde.Key_tkn().Tmpl_evaluate(ctx, src, parent_frame, tmp_bfr);
|
||||
int key_len = tmp_bfr.Len();
|
||||
boolean key_missing = key_len == 0;
|
||||
String key_as_str = null; int key_as_int = Int_.Min_value;
|
||||
boolean key_is_str = false;
|
||||
if (key_missing) // key missing; EX: {{a|val}}
|
||||
key_as_int = ++arg_idx;// NOTE: MW requires a key; if none, then default to int index; NOTE: must be int, not String; NOTE: must be indexed to keyless args; EX: in "key1=val1,val2", "val2" must be "1" (1st keyless arg) not "2" (2nd arg); DATE:2013-11-09
|
||||
else { // key exists; EX:{{a|key=val}}
|
||||
if (key_len > 0 && tmp_bfr.Bfr()[0] != Byte_ascii.Num_0) // do not convert zero-padded numbers to int; EX: "01" -> "01" x> 1; PAGE:ru.w:Красноказарменный_проезд; DATE:2016-11-23
|
||||
key_as_int = Bry_.To_int_or(tmp_bfr.Bfr(), 0, tmp_bfr.Len(), Int_.Min_value);
|
||||
if (key_as_int == Int_.Min_value) { // key is not int; create str
|
||||
key_as_str = tmp_bfr.To_str_and_clear();
|
||||
key_is_str = true;
|
||||
}
|
||||
else { // key is int; must return int for key b/c lua treats table[1] different than table["1"]; DATE:2014-02-13
|
||||
tmp_bfr.Clear(); // must clear bfr, else key will be added to val;
|
||||
}
|
||||
}
|
||||
// ctx.Scribunto = Bool_.Y; // CHART
|
||||
nde.Val_tkn().Tmpl_evaluate(ctx, src, parent_frame, tmp_bfr);
|
||||
// ctx.Scribunto = Bool_.N;
|
||||
String val = key_missing ? tmp_bfr.To_str_and_clear() : tmp_bfr.To_str_and_clear_and_trim(); // NOTE: must trim if key_exists; DUPE:TRIM_IF_KEY
|
||||
Keyval kv = key_is_str ? Keyval_.new_(key_as_str, val) : Keyval_.int_(key_as_int, val);
|
||||
rv.Add(kv);
|
||||
}
|
||||
tmp_bfr.Mkr_rls();
|
||||
return rslt.Init_obj((Keyval[])rv.To_ary(Keyval.class));
|
||||
}
|
||||
public boolean FrameExists(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
return rslt.Init_obj(frame != null);
|
||||
}
|
||||
public boolean ParentFrameExists(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(!core.Frame_parent().Frame_is_root());
|
||||
}
|
||||
public boolean Preprocess(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
byte frame_tid = frame.Frame_tid();
|
||||
Xot_invk parent_frame = Scrib_frame_.Get_parent(core, frame_tid);
|
||||
String text_str = args.Pull_str(1);
|
||||
byte[] text_bry = Bry_.new_u8(text_str);
|
||||
Xop_root_tkn tmp_root = ctx.Tkn_mkr().Root(text_bry);
|
||||
Xop_ctx tmp_ctx = Xop_ctx.New__sub__reuse_page(core.Ctx());
|
||||
int args_adj = Scrib_frame_.Get_arg_adj(frame_tid);
|
||||
int args_len = frame.Args_len() - args_adj;
|
||||
Keyval[] kv_args = new Keyval[args_len];
|
||||
Bry_bfr tmp_bfr = core.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
for (int i = 0; i < args_len; i++) {
|
||||
Arg_nde_tkn arg = frame.Args_get_by_idx(i + args_adj);
|
||||
arg.Key_tkn().Tmpl_evaluate(ctx, src, frame, tmp_bfr);
|
||||
String key = tmp_bfr.To_str_and_clear();
|
||||
if (String_.Eq(key, "")) key = Int_.To_str(i);
|
||||
arg.Val_tkn().Tmpl_evaluate(ctx, src, parent_frame, tmp_bfr); // NOTE: must evaluate against parent_frame; evaluating against current frame may cause stack-overflow; DATE:2013-04-04
|
||||
String val = tmp_bfr.To_str_and_clear();
|
||||
kv_args[i] = Keyval_.new_(key, val);
|
||||
}
|
||||
Xot_invk_mock mock_frame = Xot_invk_mock.new_(Bry_.new_u8(frame_id), kv_args); // use frame_id for Frame_ttl; in lieu of a better candidate; DATE:2014-09-21
|
||||
tmp_ctx.Parse_tid_(Xop_parser_tid_.Tid__tmpl); // default xnde names to template; needed for test, but should be in place; DATE:2014-06-27
|
||||
cur_wiki.Parser_mgr().Main().Expand_tmpl(tmp_root, tmp_ctx, tmp_ctx.Tkn_mkr(), text_bry);
|
||||
tmp_root.Tmpl_evaluate(tmp_ctx, text_bry, mock_frame, tmp_bfr);
|
||||
return rslt.Init_obj(tmp_bfr.To_str_and_rls());
|
||||
}
|
||||
public boolean CallParserFunction(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
int frame_tid = Scrib_frame_.Get_frame_tid(frame_id);
|
||||
Xot_invk parent_frame = frame_tid == Scrib_frame_.Tid_current ? core.Frame_current() : core.Frame_parent();
|
||||
byte[] fnc_name = args.Pull_bry(1);
|
||||
int fnc_name_len = fnc_name.length;
|
||||
Bry_obj_ref argx_ref = Bry_obj_ref.New_empty();
|
||||
Bry_obj_ref fnc_name_ref = Bry_obj_ref.New(fnc_name);
|
||||
Keyval[] parser_func_args = CallParserFunction_parse_args(cur_wiki.Appe().Utl_num_parser(), argx_ref, fnc_name_ref, args.Ary());
|
||||
Xot_invk_mock frame = Xot_invk_mock.new_(parent_frame.Defn_tid(), 0, fnc_name, parser_func_args); // pass something as frame_ttl; choosng fnc_name; DATE:2014-09-21
|
||||
|
||||
Xol_func_itm finder = new Xol_func_itm(); // TS.MEM: DATE:2016-07-12
|
||||
cur_wiki.Lang().Func_regy().Find_defn(finder, fnc_name, 0, fnc_name_len);
|
||||
Xot_defn defn = finder.Func();
|
||||
|
||||
if (defn == Xot_defn_.Null) throw Err_.new_wo_type("callParserFunction: function was not found", "function", String_.new_u8(fnc_name));
|
||||
Bry_bfr bfr = cur_wiki.Utl__bfr_mkr().Get_k004();
|
||||
Xop_ctx fnc_ctx = Xop_ctx.New__sub__reuse_page(core.Ctx());
|
||||
fnc_ctx.Parse_tid_(Xop_parser_tid_.Tid__tmpl); // default xnde names to template; needed for test, but should be in place; DATE:2014-06-27
|
||||
Xot_invk_tkn_.Eval_func(fnc_ctx, src, parent_frame, frame, bfr, defn, argx_ref.Val());
|
||||
bfr.Mkr_rls();
|
||||
return rslt.Init_obj(bfr.To_str_and_clear());
|
||||
}
|
||||
private Keyval[] CallParserFunction_parse_args(Gfo_number_parser num_parser, Bry_obj_ref argx_ref, Bry_obj_ref fnc_name_ref, Keyval[] args) {
|
||||
List_adp rv = List_adp_.New();
|
||||
// flatten args
|
||||
int args_len = args.length;
|
||||
for (int i = 2; i < args_len; i++) {
|
||||
Keyval arg = args[i];
|
||||
if (Is_kv_ary(arg)) {
|
||||
Keyval[] arg_kv_ary = (Keyval[])arg.Val();
|
||||
int arg_kv_ary_len = arg_kv_ary.length;
|
||||
for (int j = 0; j < arg_kv_ary_len; j++) {
|
||||
Keyval sub_arg = arg_kv_ary[j];
|
||||
rv.Add(sub_arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
rv.Add(arg);
|
||||
}
|
||||
rv.Sort_by(Scrib_lib_mw_callParserFunction_sorter.Instance);
|
||||
// get argx
|
||||
byte[] fnc_name = fnc_name_ref.Val();
|
||||
int fnc_name_len = fnc_name.length;
|
||||
int fnc_name_colon_pos = Bry_find_.Find_fwd(fnc_name, Byte_ascii.Colon, 0, fnc_name_len);
|
||||
if (fnc_name_colon_pos == Bry_find_.Not_found) {
|
||||
if (rv.Len() > 0) { // some parser_functions can pass 0 args; PAGE:en.w:Paris EX:{{#coordinates}} DATE:2016-10-12
|
||||
Keyval arg_argx = (Keyval)rv.Get_at(0);
|
||||
argx_ref.Val_(arg_argx.Val_to_bry());
|
||||
rv.Del_at(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
argx_ref.Val_(Bry_.Mid(fnc_name, fnc_name_colon_pos + 1, fnc_name_len));
|
||||
fnc_name = Bry_.Mid(fnc_name, 0, fnc_name_colon_pos);
|
||||
fnc_name_ref.Val_(fnc_name);
|
||||
}
|
||||
return (Keyval[])rv.To_ary(Keyval.class);
|
||||
}
|
||||
private static boolean Is_kv_ary(Keyval kv) {return Type_adp_.Eq_typeSafe(kv.Val(), Keyval[].class);}
|
||||
public boolean ExpandTemplate(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String ttl_str = args.Pull_str(1);
|
||||
byte[] ttl_bry = Bry_.new_u8(ttl_str);
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(cur_wiki, ttl_bry); // parse directly; handles titles where template is already part of title; EX: "Template:A"
|
||||
if (ttl == null) return rslt.Init_ary_empty(); // invalid ttl;
|
||||
if (!ttl.ForceLiteralLink() && ttl.Ns().Id_is_main()) // title is not literal and is not prefixed with Template; parse again as template; EX: ":A" and "Template:A" are fine; "A" is parsed again as "Template:A"
|
||||
ttl = Xoa_ttl.Parse(cur_wiki, Bry_.Add(cur_wiki.Ns_mgr().Ns_template().Name_db_w_colon(), ttl_bry)); // parse again, but add "Template:"
|
||||
Keyval[] args_ary = args.Pull_kv_ary_safe(2);
|
||||
// BLOCK.bgn:Xot_invk_tkn.Transclude; cannot reuse b/c Transclude needs invk_tkn, and invk_tkn is manufactured late; DATE:2014-01-02
|
||||
byte[] sub_src = null;
|
||||
if (ttl.Ns().Id_is_tmpl()) { // ttl is template; check tmpl_regy first before going to data_mgr
|
||||
Xot_defn_tmpl tmpl = (Xot_defn_tmpl)core.Wiki().Cache_mgr().Defn_cache().Get_by_key(ttl.Page_db());
|
||||
if (tmpl != null) sub_src = tmpl.Data_raw();
|
||||
}
|
||||
if (sub_src == null) // ttl is not in template cache, or is a ttl in non-Template ns; load title
|
||||
sub_src = core.Wiki().Cache_mgr().Page_cache().Get_or_load_as_src(ttl);
|
||||
if (sub_src != null) {
|
||||
Xot_invk_mock sub_frame = Xot_invk_mock.new_(core.Frame_current().Defn_tid(), 0, ttl.Full_txt_w_ttl_case(), args_ary); // NOTE: (1) must have ns (Full); (2) must be txt (space, not underscore); EX:Template:Location map+; DATE:2014-09-21
|
||||
Xot_defn_tmpl transclude_tmpl = ctx.Wiki().Parser_mgr().Main().Parse_text_to_defn_obj(ctx, ctx.Tkn_mkr(), ttl.Ns(), ttl.Page_db(), sub_src);
|
||||
Bry_bfr sub_bfr = cur_wiki.Utl__bfr_mkr().Get_k004();
|
||||
transclude_tmpl.Tmpl_evaluate(ctx, sub_frame, sub_bfr);
|
||||
return rslt.Init_obj(sub_bfr.To_str_and_rls());
|
||||
}
|
||||
else {
|
||||
return rslt.Init_fail("expandTemplate: template \"" + ttl_str + "\" does not exist"); // NOTE: must return error if template is missing; PAGE:en.w:Flag_of_Greenland DATE:2016-05-02
|
||||
}
|
||||
// BLOCK.end:Xot_invk_tkn.Transclude
|
||||
}
|
||||
|
||||
public boolean IncrementExpensiveFunctionCount(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(Keyval_.Ary_empty);} // NOTE: for now, always return null (XOWA does not care about expensive parser functions)
|
||||
public boolean IsSubsting(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
boolean is_substing = false;
|
||||
Xot_invk current_frame = core.Frame_current();
|
||||
if (current_frame != null && Xot_defn_.Tid_is_substing(current_frame.Defn_tid())) // check current frame first
|
||||
is_substing = true;
|
||||
else { // check owner frame next
|
||||
Xot_invk parent_frame = core.Frame_parent();
|
||||
if (parent_frame != null && Xot_defn_.Tid_is_substing(parent_frame.Defn_tid()))
|
||||
is_substing = true;
|
||||
}
|
||||
return rslt.Init_obj(is_substing);
|
||||
}
|
||||
public boolean NewChildFrame(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Ordered_hash frame_list = core.Frame_created_list();
|
||||
int frame_list_len = frame_list.Count();
|
||||
if (frame_list_len > 100) throw Err_.new_wo_type("newChild: too many frames");
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
Object ttl_obj = args.Cast_obj_or_null(1); // NOTE: callers must pass named title else title will be false; EX: frame:newChild{'current', 'title0'} -> false; frame:newChild{'current', title='title0'} -> 'title0'; DATE:2014-05-20
|
||||
Xoa_ttl ttl = null;
|
||||
if (Type_adp_.ClassOf_obj(ttl_obj) != String.class) { // title = false
|
||||
byte[] ttl_bry = frame.Frame_ttl();
|
||||
ttl = Xoa_ttl.Parse(core.Wiki(), ttl_bry);
|
||||
}
|
||||
else {
|
||||
ttl = Xoa_ttl.Parse(cur_wiki, Bry_.new_u8((String)ttl_obj));
|
||||
if (ttl == null) throw Err_.new_wo_type("newChild: invalid title", "title", (String)ttl_obj);
|
||||
}
|
||||
Keyval[] args_ary = args.Pull_kv_ary_safe(2);
|
||||
Xot_invk_mock new_frame = Xot_invk_mock.new_(core.Frame_current().Defn_tid(), 0, ttl.Full_txt_w_ttl_case(), args_ary); // NOTE: use spaces, not unders; REF.MW:$frame->getTitle()->getPrefixedText(); DATE:2014-08-14
|
||||
String new_frame_id = "frame" + Int_.To_str(frame_list_len);
|
||||
frame_list.Add(new_frame_id, new_frame);
|
||||
return rslt.Init_obj(new_frame_id);
|
||||
}
|
||||
public boolean GetFrameTitle(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String frame_id = args.Pull_str(0);
|
||||
Xot_invk frame = Scrib_frame_.Get_frame(core, frame_id);
|
||||
return rslt.Init_obj(frame.Frame_ttl());
|
||||
}
|
||||
public boolean SetTTL(Scrib_proc_args args, Scrib_proc_rslt rslt) { // needed for {{cite web}} PAGE:en.w:A DATE:2014-07-12
|
||||
int timeToLive = args.Pull_int(0);
|
||||
Xot_invk current_frame = core.Frame_current();
|
||||
current_frame.Frame_lifetime_(timeToLive);
|
||||
return rslt.Init_ary_empty();
|
||||
}
|
||||
}
|
||||
class Scrib_lib_mw_callParserFunction_sorter implements gplx.core.lists.ComparerAble {
|
||||
public int compare(Object lhsObj, Object rhsObj) {
|
||||
Keyval lhs = (Keyval)lhsObj;
|
||||
Keyval rhs = (Keyval)rhsObj;
|
||||
Object lhs_key = lhs.Key_as_obj();
|
||||
Object rhs_key = rhs.Key_as_obj();
|
||||
boolean lhs_is_int = Int_.TypeMatch(lhs_key.getClass());
|
||||
boolean rhs_is_int = Int_.TypeMatch(rhs_key.getClass());
|
||||
if (lhs_is_int != rhs_is_int) // different types (int vs String or String vs int)
|
||||
return lhs_is_int ? CompareAble_.Less : CompareAble_.More; // sort ints before strings
|
||||
if (lhs_is_int) // both are ints
|
||||
return Int_.Compare(Int_.cast(lhs_key), Int_.cast(rhs_key));
|
||||
else // both are strings
|
||||
return String_.Compare(String_.cast(lhs_key), String_.cast(rhs_key));
|
||||
}
|
||||
public static final Scrib_lib_mw_callParserFunction_sorter Instance = new Scrib_lib_mw_callParserFunction_sorter(); Scrib_lib_mw_callParserFunction_sorter() {}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_lib_mw__invoke_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_invoke();
|
||||
lib = fxt.Core().Lib_mw().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Test public void GetAllExpandedArguments_ws_prm_key_exists() { // PURPOSE: trim val if key exists; parameterized value ("key={{{1}}}")
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Prc_0|key={{{1}}}}}");
|
||||
fxt.Init_page("{{test| a }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("current"), "\n a"); // " a " -> "a"
|
||||
}
|
||||
@Test public void GetAllExpandedArguments_ws_prm_key_missing() { // PURPOSE: do not trim val if key missing; parameterized value ("{{{1}}}")
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Prc_0|{{{1}}}}}");
|
||||
fxt.Init_page("{{test| a }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("current"), "\n a "); // " a " -> " a "
|
||||
}
|
||||
@Test public void GetAllExpandedArguments__ignore_empty_key() {// PURPOSE: ignore arguents that have an empty key (|=8|); EX:w:Fool's_mate; DATE:2014-03-05
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Init_page("{{test|a1||a2|=a3|a4}}");
|
||||
fxt.Init_server_print_key_y_();
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("parent"), "\n 1:a1;2:;3:a2;4:a4"); // NOTE: || is not ignored but |=a3| is
|
||||
fxt.Init_server_print_key_n_();
|
||||
}
|
||||
@Test public void GetExpandedArgument_ws_key_exists() { // PURPOSE: trim val if key exists; literal value
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0| key1 = val1 }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "key1") , "val1"); // "key1" -> "key1"
|
||||
}
|
||||
@Test public void GetExpandedArgument_ws_key_missing() { // PURPOSE: do not trim val if key missing; literal value
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0| a }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "1") , " a "); // " a " -> " a "
|
||||
}
|
||||
@Test public void GetExpandedArgument_ws_key_prm_key_exists() { // PURPOSE: trim val if key exists; parameterized value ("key={{{1}}}")
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Prc_0|key1={{{1}}}}}");
|
||||
fxt.Init_page("{{test| a }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "key1") , "a"); // " a " -> "a"
|
||||
}
|
||||
@Test public void GetExpandedArgument_ws_key_prm_key_missing() { // PURPOSE: do not trim val if key missing; parameterized value ("{{{1}}}")
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Prc_0|{{{1}}}}}");
|
||||
fxt.Init_page("{{test| a }}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "1") , " a "); // " a " -> " a "
|
||||
}
|
||||
@Test public void Preprocess() {
|
||||
this.Init_preprocess();
|
||||
this.Exec_preprocess(Scrib_core.Frame_key_module , "1", "c");
|
||||
this.Exec_preprocess(Scrib_core.Frame_key_module , "2", "d");
|
||||
this.Exec_preprocess(Scrib_core.Frame_key_template , "1", "a");
|
||||
this.Exec_preprocess(Scrib_core.Frame_key_template , "2", "b");
|
||||
}
|
||||
@Test public void Preprocess_duplicate_key() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0|key1=a|key2=b|key1=c}}"); // add key1 twice
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_preprocess, Object_.Ary("current", "{{#ifeq:1|1|{{{key1}}}|{{{key2}}}}}"), "c");
|
||||
}
|
||||
@Test public void CallParserFunction() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Test_lib_proc_kv(lib, Scrib_lib_mw.Invk_callParserFunction, Scrib_kv_utl_.base1_many_ary_("current", "#expr", "1") , "1"); // named: args is scalar
|
||||
fxt.Test_lib_proc_kv(lib, Scrib_lib_mw.Invk_callParserFunction, Scrib_kv_utl_.base1_many_ary_("current", "#if", Scrib_kv_utl_.base1_many_("", "y", "n")) , "n"); // named: args is table
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_callParserFunction, Object_.Ary("current", "#if", "", "y", "n") , "n"); // list: args is ary
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_callParserFunction, Object_.Ary("current", "#if", Scrib_kv_utl_.base1_many_("", "y", "n")) , "n"); // list: args is table
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_callParserFunction, Object_.Ary("current", "#if:", "y", "n") , "n"); // colon_in_name
|
||||
}
|
||||
@Test public void CallParserFunction_tag() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Test_lib_proc_kv(lib, Scrib_lib_mw.Invk_callParserFunction, Scrib_kv_utl_.flat_many_(1, "current", 2, "#tag", 3, Scrib_kv_utl_.flat_many_("3", "id=1", "2", "text", "1", "pre")), "<pre 3=\"id=1\">2=text</pre>");// named: sort args; NOTE: keys should probably be stripped
|
||||
}
|
||||
@Test public void CallParserFunction__no_args() { // PURPOSE.fix: 0 args should not fail
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Test_lib_proc_kv(lib, Scrib_lib_mw.Invk_callParserFunction, Scrib_kv_utl_.flat_many_(1, "current", 2, "#tag", 3, Keyval_.Ary_empty), "");// failed with "Script error: index is out of bounds"
|
||||
}
|
||||
@Test public void CallParserFunction_displayTitle() { // PURPOSE: DISPLAYTITLE not being set when called through CallParserFunction; DATE:2013-08-05
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Test_lib_proc_kv(lib, Scrib_lib_mw.Invk_callParserFunction, Scrib_kv_utl_.base1_many_ary_("current", "DISPLAYTITLE", "''a''"), "");
|
||||
Tfds.Eq("<i>a</i>", String_.new_a7(fxt.Parser_fxt().Ctx().Page().Html_data().Display_ttl()));
|
||||
}
|
||||
@Test public void ExpandTemplate_tmpl() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Data_create("Template:A", "b{{{key1}}}c");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "A", Scrib_kv_utl_.flat_many_("key1", "val1")) , "bval1c"); // list: args is ary
|
||||
}
|
||||
@Test public void ExpandTemplate() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Init_page_create("Template:Format", "{{{1}}}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "Format", Scrib_kv_utl_.base1_many_("a")), "a");
|
||||
}
|
||||
@Test public void ExpandTemplate_ns_specified() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Init_page_create("Template:Format", "{{{1}}}");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "Template:Format", Scrib_kv_utl_.base1_many_("a")), "a"); // NOTE: "Template:" specified
|
||||
}
|
||||
@Test public void ExpandTemplate_tmpl_bool() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Data_create("Template:Scribunto_bool", "bool_true={{{bool_true}}};bool_false={{{bool_false}}};");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "Scribunto_bool", Scrib_kv_utl_.flat_many_("bool_true", true, "bool_false", false)), "bool_true=1;bool_false={{{bool_false}}};");
|
||||
}
|
||||
@Test public void ExpandTemplate_page() {
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Data_create("A", "b{{{key1}}}c");
|
||||
fxt.Test_lib_proc(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", ":A", Scrib_kv_utl_.flat_many_("key1", "val1")) , "bval1c"); // list: args is ary
|
||||
}
|
||||
@Test public void Err_mod_blank() {fxt.Test_parse_err("{{#invoke:}}" , Scrib_invoke_func.Err_mod_missing);}
|
||||
@Test public void Err_mod_missing() {fxt.Test_parse_err("{{#invoke:Missing}}" , Scrib_invoke_func.Err_mod_missing);}
|
||||
@Test public void Err_mod_custom() {
|
||||
fxt.Test_error(Err_.new_("err_type", "fail", "key0", "val0"), "<strong class=\"error\"><span class=\"scribunto-error\" id=\"mw-scribunto-error-0\">Script error: fail</span></strong>");
|
||||
}
|
||||
private void Init_preprocess() {
|
||||
fxt.Init_tmpl("{{#invoke:Mod_0|Func_0|1|c|d}}"); // current
|
||||
fxt.Init_page("{{test|1|a|b|c}}"); // parent
|
||||
fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_mw(), Scrib_lib_mw.Invk_preprocess);
|
||||
}
|
||||
private void Exec_preprocess(String frame, String arg_idx, String expd) {
|
||||
fxt.Parser_fxt().Wiki().Cache_mgr().Tmpl_result_cache().Clear();
|
||||
fxt.Init_lua_module();
|
||||
fxt.Init_lua_rcvd_preprocess(frame, "{{#ifeq:" + arg_idx + "|{{{1}}}|{{{2}}}|{{{3}}}}}");
|
||||
fxt.Test_invoke(expd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_lib_mw__lib_tst {
|
||||
private final Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_mw().Init();
|
||||
}
|
||||
@Test public void ParentFrameExists() {
|
||||
fxt.Init_frame_parent("test");
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_mw.Invk_parentFrameExists, Object_.Ary_empty, true);
|
||||
}
|
||||
@Test public void ParentFrameExists_false() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_mw.Invk_parentFrameExists, Object_.Ary_empty, false);
|
||||
}
|
||||
@Test public void GetAllExpandedArguments() {
|
||||
fxt.Init_frame_current(Keyval_.new_("k1", "v1"));
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("current"), "1=\n k1=v1");
|
||||
}
|
||||
@Test public void GetAllExpandedArguments_parent() {
|
||||
fxt.Init_frame_parent("test", Keyval_.new_("1", "a1"), Keyval_.new_("2", "a2"));
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("parent"), "1=\n 1=a1\n 2=a2");
|
||||
}
|
||||
@Test public void GetAllExpandedArguments__zero_padded_number() { // PURPOSE: DATE:2016-11-23
|
||||
fxt.Init_frame_current(Keyval_.new_("01", "v1"));
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_mw.Invk_getAllExpandedArguments, Object_.Ary("current"), "1=\n 01=v1");
|
||||
}
|
||||
@Test public void GetExpandedArgument() {
|
||||
fxt.Init_frame_current(Keyval_.int_(1, "val_1"), Keyval_.new_("key_2", "val_2"), Keyval_.int_(3, "val_3"));
|
||||
fxt.Test_scrib_proc_str (lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "1") , "val_1"); // get 1st by idx
|
||||
fxt.Test_scrib_proc_str (lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "2") , "val_3"); // get 2nd by idx (which is "3", not "key_2)
|
||||
fxt.Test_scrib_proc_empty (lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "3")); // get 3rd by idx (which is n/a, not "val_3")
|
||||
fxt.Test_scrib_proc_str (lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "key_2") , "val_2"); // get key_2
|
||||
fxt.Test_scrib_proc_empty (lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "key_3")); // key_3 n/a
|
||||
}
|
||||
@Test public void GetExpandedArgument_parent() {
|
||||
fxt.Init_frame_parent ("test", Keyval_.new_("1", "a1"), Keyval_.new_("2", "a2"));
|
||||
fxt.Init_frame_current(Keyval_.new_("2", "b2"));
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("parent", "1"), "a1");
|
||||
}
|
||||
@Test public void GetExpandedArgument_numeric_key() { // PURPOSE.FIX: frame.args[1] was ignoring "1=val_1" b/c it was looking for 1st unnamed arg (and 1 is the name for "1=val_1")
|
||||
fxt.Init_frame_current(Keyval_.new_("1", "val_1"));
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("current", "1"), "val_1"); // get 1st by idx, even though idx is String
|
||||
}
|
||||
@Test public void GetExpandedArgument_numeric_key_2() { // PURPOSE.FIX: same as above, but for parent context; DATE:2013-09-23
|
||||
fxt.Init_frame_parent ("test", Keyval_.new_("2", "a1"));
|
||||
fxt.Init_frame_current(Keyval_.new_("2", "a2"));
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("parent", "2"), "a1"); // get 1st by idx, even though idx is String
|
||||
}
|
||||
@Test public void GetExpandedArgument_out_of_bounds() {
|
||||
fxt.Init_frame_parent ("test");
|
||||
fxt.Test_scrib_proc_empty(lib, Scrib_lib_mw.Invk_getExpandedArgument, Object_.Ary("parent", "2"));
|
||||
}
|
||||
@Test public void IsSubsting() {
|
||||
fxt.Test_scrib_proc_bool(lib, Scrib_lib_mw.Invk_isSubsting, Object_.Ary_empty, false);
|
||||
}
|
||||
@Test public void GetFrameTitle_current() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getFrameTitle, Object_.Ary("current") , "Module:Mod_0");
|
||||
}
|
||||
@Test public void GetFrameTitle_parent() {
|
||||
fxt.Init_frame_parent("Template:Test A");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getFrameTitle, Object_.Ary("parent") , "Template:Test A");
|
||||
}
|
||||
@Test public void GetFrameTitle_empty() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_getFrameTitle, Object_.Ary("empty") , Scrib_invoke_func_fxt.Null_rslt);
|
||||
}
|
||||
@Test public void NewChildFrame() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_newChildFrame, Object_.Ary("current", "Page_0", Scrib_kv_utl_.flat_many_("key1", "val1")), "frame0");
|
||||
}
|
||||
@Test public void ExpandTemplate__null_arg() { // PURPOSE: auto-fill in arg "1" b/c "2" is specified; PAGE:en.w:Category:Nouns_by_language DATE:2016-04-29
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Parser_fxt().Data_create("Template:A", "b{{{1}}}c");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "A", Scrib_kv_utl_.flat_many_(2, "x")), "bc"); // fails if "bxc"; note that "2" is passed, but should not be read as "1"
|
||||
}
|
||||
@Test public void ExpandTemplate__missing_template() {// PURPOSE: return error if template is missing; PAGE:en.w:Flag_of_Greenland DATE:2016-05-02
|
||||
fxt.Init_page("{{#invoke:Mod_0|Prc_0}}");
|
||||
fxt.Test_scrib_proc_err(lib, Scrib_lib_mw.Invk_expandTemplate, Object_.Ary("current", "A", Scrib_kv_utl_.flat_many_(1, "a")), "expandTemplate: template \"A\" does not exist");
|
||||
}
|
||||
@Test public void SetTTL() {
|
||||
fxt.Test_scrib_proc_empty(lib, Scrib_lib_mw.Invk_setTTL, Object_.Ary(123));
|
||||
Tfds.Eq(123, fxt.Core().Frame_current().Frame_lifetime());
|
||||
}
|
||||
@Test public void LoadPHPLibrary() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_mw.Invk_loadPHPLibrary, Object_.Ary("mock_library") , Scrib_invoke_func_fxt.Null_rslt);
|
||||
}
|
||||
}
|
||||
214
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_site.java
Normal file
214
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_site.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
|
||||
import gplx.xowa.wikis.nss.*; import gplx.xowa.addons.wikis.ctgs.*;
|
||||
import gplx.xowa.wikis.metas.*; import gplx.xowa.wikis.data.site_stats.*; import gplx.xowa.wikis.xwikis.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_site implements Scrib_lib {
|
||||
public Scrib_lib_site(Scrib_core core) {this.core = core;} private final Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_site(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.site.lua"));// NOTE: info not passed by default; rely on Init_for_wiki
|
||||
notify_wiki_changed_fnc = mod.Fncs_get_by_key("notify_wiki_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_wiki_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private final Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_getNsIndex: return GetNsIndex(args, rslt);
|
||||
case Proc_pagesInCategory: return PagesInCategory(args, rslt);
|
||||
case Proc_pagesInNs: return PagesInNs(args, rslt);
|
||||
case Proc_usersInGroup: return UsersInGroup(args, rslt);
|
||||
case Proc_interwikiMap: return InterwikiMap(args, rslt);
|
||||
case Proc_init_site_for_wiki: return Init_site_for_wiki(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_getNsIndex = 0, Proc_pagesInCategory = 1, Proc_pagesInNs = 2, Proc_usersInGroup = 3, Proc_interwikiMap = 4, Proc_init_site_for_wiki = 5;
|
||||
public static final String Invk_getNsIndex = "getNsIndex", Invk_pagesInCategory = "pagesInCategory", Invk_pagesInNs = "pagesInName"+"space", Invk_usersInGroup = "usersInGroup", Invk_interwikiMap = "interwikiMap", Invk_init_site_for_wiki = "init_site_for_wiki";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_getNsIndex, Invk_pagesInCategory, Invk_pagesInNs, Invk_usersInGroup, Invk_interwikiMap, Invk_init_site_for_wiki);
|
||||
public boolean GetNsIndex(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ns_name = args.Pull_bry(0);
|
||||
Object ns_obj = core.Wiki().Ns_mgr().Names_get_or_null(ns_name, 0, ns_name.length);
|
||||
return ns_obj == null ? rslt.Init_ary_empty() : rslt.Init_obj(((Xow_ns)ns_obj).Id());
|
||||
}
|
||||
public boolean PagesInCategory(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ctg_name = args.Pull_bry(0);
|
||||
String ctg_type = args.Cast_str_or(1, "all");
|
||||
Xoa_ttl ctg_ttl = core.Wiki().Ttl_parse(Xow_ns_.Tid__category, ctg_name);
|
||||
if (ctg_ttl == null) return rslt.Init_obj(0);
|
||||
Xoax_ctg_addon ctg_mgr = Xoax_ctg_addon.Get(core.Wiki());
|
||||
Xoctg_ctg_itm ctg_itm = ctg_mgr.Itms__get_or_null(ctg_name);
|
||||
if (ctg_itm == null) {
|
||||
core.Increment_expensive_function_count();
|
||||
ctg_itm = ctg_mgr.Itms__load(ctg_name);
|
||||
}
|
||||
if (String_.Eq(ctg_type, "*")) {
|
||||
Keyval[] rv = new Keyval[4];
|
||||
rv[0] = Keyval_.new_("all", ctg_itm.All);
|
||||
rv[1] = Keyval_.new_("pages", ctg_itm.Pages);
|
||||
rv[2] = Keyval_.new_("subcats", ctg_itm.Subcs);
|
||||
rv[3] = Keyval_.new_("files", ctg_itm.Files);
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
else {
|
||||
int rv_count = 0;
|
||||
if (String_.Eq(ctg_type, "all")) rv_count = ctg_itm.All;
|
||||
else if (String_.Eq(ctg_type, "pages")) rv_count = ctg_itm.Pages;
|
||||
else if (String_.Eq(ctg_type, "subcats")) rv_count = ctg_itm.Subcs;
|
||||
else if (String_.Eq(ctg_type, "files")) rv_count = ctg_itm.Files;
|
||||
else throw Scrib_err.Make__err__arg(Invk_pagesInCategory, 2, ctg_type, "one of '*', 'all', 'pages', 'subcats', or 'files'");
|
||||
return rslt.Init_obj(rv_count);
|
||||
}
|
||||
}
|
||||
public boolean PagesInNs(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
int ns_id = args.Pull_int(0);
|
||||
Xow_ns ns = core.Wiki().Ns_mgr().Ids_get_or_null(ns_id);
|
||||
int ns_count = ns == null ? 0 : ns.Count();
|
||||
return rslt.Init_obj(ns_count);
|
||||
}
|
||||
public boolean UsersInGroup(Scrib_proc_args args, Scrib_proc_rslt rslt) { // TODO_OLD.9: get user_groups table
|
||||
// byte[] grp_name = args.Pull_bry(0);
|
||||
return rslt.Init_obj(0);
|
||||
}
|
||||
public boolean InterwikiMap(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String filter = args.Cast_str_or_null(0);
|
||||
int local = -1;
|
||||
if (String_.Eq(filter, "local"))
|
||||
local = 1;
|
||||
else if (String_.Eq(filter, "!local"))
|
||||
local = 0;
|
||||
else if (filter != null)
|
||||
throw Err_.new_wo_type("bad argument #1 to 'interwikiMap' (unknown filter '$filter')", "filter", filter);
|
||||
Hash_adp misc_cache = core.Wiki().Cache_mgr().Misc_cache();
|
||||
String cache_key = "scribunto.interwikimap." + core.Wiki().Domain_str() + "." + filter;
|
||||
Keyval[] rv = (Keyval[])misc_cache.Get_by(cache_key);
|
||||
if (rv == null) {
|
||||
Xow_xwiki_mgr xwiki_mgr = core.Wiki().Xwiki_mgr();
|
||||
int xwiki_len = xwiki_mgr.Len();
|
||||
List_adp list = List_adp_.New();
|
||||
for (int i = 0; i < xwiki_len; ++i) {
|
||||
Xow_xwiki_itm itm = xwiki_mgr.Get_at(i);
|
||||
boolean itm_is_local = itm.Offline();
|
||||
if (local == 1 && !itm_is_local) continue;
|
||||
if (local == 0 && itm_is_local) continue;
|
||||
String prefix = itm.Key_str();
|
||||
list.Add(Keyval_.new_(prefix, InterwikiMap_itm(itm, prefix, itm_is_local)));
|
||||
}
|
||||
rv = (Keyval[])list.To_ary_and_clear(Keyval.class);
|
||||
misc_cache.Add(cache_key, rv);
|
||||
}
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
private Keyval[] InterwikiMap_itm(Xow_xwiki_itm itm, String prefix, boolean itm_is_local) {
|
||||
boolean is_extralanguage_link = false;
|
||||
int rv_len = 7;
|
||||
if (is_extralanguage_link) rv_len += 2;
|
||||
String url = String_.new_u8(itm.Domain_bry());
|
||||
boolean url_is_relative = String_.Has_at_bgn(url, "//");
|
||||
Keyval[] rv = new Keyval[rv_len];
|
||||
rv[ 0] = Keyval_.new_("prefix" , prefix);
|
||||
rv[ 1] = Keyval_.new_("url" , url); // wfExpandUrl( $row['iw_url'], PROTO_RELATIVE ),
|
||||
rv[ 2] = Keyval_.new_("isProtocolRelative" , url_is_relative); // substr( $row['iw_url'], 0, 2 ) === '//',
|
||||
rv[ 3] = Keyval_.new_("isLocal" , itm_is_local); // isset( $row['iw_local'] ) && $row['iw_local'] == '1',
|
||||
rv[ 4] = Keyval_.new_("isTranscludable" , Bool_.N); // isset( $row['iw_trans'] ) && $row['iw_trans'] == '1',
|
||||
rv[ 5] = Keyval_.new_("isCurrentWiki" , Bool_.N); // in_array( $prefix, $wgLocalInterwikis ),
|
||||
rv[ 6] = Keyval_.new_("isExtraLanguageLink" , is_extralanguage_link); // in_array( $prefix, $wgExtraInterlanguageLinkPrefixes ),
|
||||
if (is_extralanguage_link) {
|
||||
rv[7] = Keyval_.new_("displayText" , "displayText_TODO"); // $displayText = wfMessage( "interlanguage-link-$prefix" ); if ( !$displayText->isDisabled() ) ...
|
||||
rv[7] = Keyval_.new_("tooltip" , "tooltip_TODO"); // $tooltip = wfMessage( "interlanguage-link-sitename-$prefix" );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void Notify_wiki_changed() {if (notify_wiki_changed_fnc != null) core.Interpreter().CallFunction(notify_wiki_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean Init_site_for_wiki(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Keyval[] rv = new Keyval[7];
|
||||
Bld_info(rv);
|
||||
rv[5] = Keyval_.new_("name" + "spaces", Bld_ns_ary(wiki));
|
||||
rv[6] = Keyval_.new_("stats", Bld_stats(wiki));
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
private void Bld_info(Keyval[] rv) {
|
||||
Xow_wiki_props props = core.Wiki().Props();
|
||||
rv[0] = Keyval_.new_("siteName" , props.Site_name());
|
||||
rv[1] = Keyval_.new_("server" , Bry_.Add(gplx.core.net.Gfo_protocol_itm.Bry_relative, props.Server_name())); // NOTE: should generate "//en.wikipedia.org", not "de.wikipedia.org"; PAGE:de.w:Giro_d<5F>Italia_1996 DATE:2016-04-17
|
||||
rv[2] = Keyval_.new_("scriptPath" , props.ScriptPath());
|
||||
rv[3] = Keyval_.new_("stylePath" , props.StylePath());
|
||||
rv[4] = Keyval_.new_("currentVersion" , props.Current_version());
|
||||
}
|
||||
private Keyval[] Bld_ns_ary(Xowe_wiki wiki) {
|
||||
Xow_ns_mgr ns_mgr = wiki.Ns_mgr();
|
||||
int len = ns_mgr.Ids_len();
|
||||
Keyval[] rv = new Keyval[len];
|
||||
int rv_idx = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Xow_ns ns = ns_mgr.Ids_get_at(i);
|
||||
if (ns == null) continue;
|
||||
int ns_id = ns.Id();
|
||||
rv[rv_idx++] = Keyval_.int_(ns_id, Bld_ns(wiki, ns, ns_id));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private Keyval[] Bld_ns(Xowe_wiki wiki, Xow_ns ns, int ns_id) {
|
||||
int len = 16;
|
||||
if (ns_id < Xow_ns_.Tid__main) len = 14;
|
||||
else if (ns_id == Xow_ns_.Tid__main) len = 17;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
rv[ 0] = Keyval_.new_("id" , ns_id);
|
||||
rv[ 1] = Keyval_.new_("name" , ns.Name_ui());
|
||||
rv[ 2] = Keyval_.new_("canonicalName" , ns.Name_db_str()); // strtr( $canonical, "_", " " ),
|
||||
rv[ 3] = Keyval_.new_("hasSubpages" , ns.Subpages_enabled()); // MWNs::hasSubpages( $ns ),
|
||||
rv[ 4] = Keyval_.new_("hasGenderDistinction" , ns.Is_gender_aware()); // MWNs::hasGenderDistinction( $ns ),
|
||||
rv[ 5] = Keyval_.new_("isCapitalized" , ns.Is_capitalized()); // MWNs::isCapitalized( $ns ),
|
||||
rv[ 6] = Keyval_.new_("isContent" , ns.Is_content()); // MWNs::isContent( $ns ),
|
||||
rv[ 7] = Keyval_.new_("isIncludable" , ns.Is_includable()); // !MWNs::isNonincludable( $ns ),
|
||||
rv[ 8] = Keyval_.new_("isMovable" , ns.Is_movable()); // MWNs::isMovable( $ns ),
|
||||
rv[ 9] = Keyval_.new_("isSubject" , ns.Id_is_subj());
|
||||
rv[10] = Keyval_.new_("isTalk" , ns.Id_is_talk());
|
||||
rv[11] = Keyval_.new_("defaultContentModel" , null); // MWNs::getNsContentModel( $ns ), ASSUME: always null?
|
||||
rv[12] = Keyval_.new_("aliases" , ns.Aliases_as_scrib_ary()); // DATE:2014-02-15
|
||||
if (ns_id < 0)
|
||||
rv[13] = Keyval_.new_("subject" , ns_id); // MWNs::getSubject( $ns );
|
||||
else {
|
||||
rv[13] = Keyval_.new_("subject" , ns_id); // MWNs::getSubject( $ns );
|
||||
rv[14] = Keyval_.new_("talk" , ns.Id_talk_id()); // MWNs::getTalk( $ns );
|
||||
rv[15] = Keyval_.new_("associated" , ns.Id_alt_id()); // MWNs::getAssociated( $ns );
|
||||
if (ns_id == Xow_ns_.Tid__main)
|
||||
rv[16] = Keyval_.new_("displayName" , wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_ns_blankns)); // MWNs::getAssociated( $ns );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private Keyval[] Bld_stats(Xowe_wiki wiki) {
|
||||
Xowd_site_stats_mgr stats = wiki.Stats();
|
||||
Keyval[] rv = new Keyval[8];
|
||||
rv[0] = Keyval_.new_("pages" , stats.Num_pages()); // SiteStats::pages(),
|
||||
rv[1] = Keyval_.new_("articles" , stats.Num_articles()); // SiteStats::articles(),
|
||||
rv[2] = Keyval_.new_("files" , stats.Num_files()); // SiteStats::images(),
|
||||
rv[3] = Keyval_.new_("edits" , stats.Num_edits()); // SiteStats::edits(),
|
||||
rv[4] = Keyval_.new_("views" , stats.Num_views()); // $wgDisableCounters ? null : (int)SiteStats::views(),
|
||||
rv[5] = Keyval_.new_("users" , stats.Num_users()); // SiteStats::users(),
|
||||
rv[6] = Keyval_.new_("activeUsers" , stats.Num_active()); // SiteStats::activeUsers(),
|
||||
rv[7] = Keyval_.new_("admins" , stats.Num_admins()); // SiteStats::activeUsers(),
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.wikis.nss.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_site_tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear();
|
||||
lib = fxt.Core().Lib_site().Init();
|
||||
}
|
||||
@Test public void GetNsIndex__valid() {
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_getNsIndex, Object_.Ary("Help"), 12);
|
||||
}
|
||||
@Test public void GetNsIndex__invalid() {
|
||||
fxt.Test__proc__objs__empty(lib, Scrib_lib_site.Invk_getNsIndex, Object_.Ary("Helpx")); // unknown ns; return empty String
|
||||
}
|
||||
@Test public void UsersInGroup() {
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_usersInGroup, Object_.Ary("sysop"), 0); // SELECT * FROM user_groups;
|
||||
}
|
||||
@Test public void PagesInCategory__invalid() {
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A|"), 0);
|
||||
}
|
||||
@Test public void PagesInCategory__exists() {
|
||||
gplx.xowa.addons.wikis.ctgs.Xoax_ctg_addon.Get(fxt.Core().Wiki()).Itms__add(Bry_.new_a7("A"), 3, 2, 1);
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A", "pages") , 3);
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A", "subcats") , 2);
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A", "files") , 1);
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A", "all") , 6);
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_site.Invk_pagesInCategory, Object_.Ary("A", "*") , String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " all=6"
|
||||
, " pages=3"
|
||||
, " subcats=2"
|
||||
, " files=1"
|
||||
));
|
||||
}
|
||||
@Test public void PagesInNs() {
|
||||
fxt.Test__proc__ints(lib, Scrib_lib_site.Invk_pagesInNs, Object_.Ary("12"), 0);
|
||||
}
|
||||
@Test public void InterwikiMap() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_site.Invk_interwikiMap, Object_.Ary("!local"), String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " en.wikipedia.org="
|
||||
, " prefix=en.wikipedia.org"
|
||||
, " url=en.wikipedia.org"
|
||||
, " isProtocolRelative=false"
|
||||
, " isLocal=false"
|
||||
, " isTranscludable=false"
|
||||
, " isCurrentWiki=false"
|
||||
, " isExtraLanguageLink=false"
|
||||
));
|
||||
}
|
||||
@Test public void Init_lib_site() {
|
||||
Xowe_wiki wiki = fxt.Core().Wiki();
|
||||
wiki.Stats().Load_by_db(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
wiki.Ns_mgr()
|
||||
.Clear()
|
||||
.Add_new(Xow_ns_.Tid__module , Xow_ns_.Key__module)
|
||||
.Add_new(Xow_ns_.Tid__module_talk , Xow_ns_.Key__module_talk)
|
||||
.Add_new(Xow_ns_.Tid__special , Xow_ns_.Key__special)
|
||||
.Add_new(Xow_ns_.Tid__main , "")
|
||||
.Add_new(Xow_ns_.Tid__talk , Xow_ns_.Key__talk)
|
||||
.Init_w_defaults()
|
||||
;
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_site.Invk_init_site_for_wiki, Object_.Ary_empty, String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " siteName=Wikipedia"
|
||||
, " server=//en.wikipedia.org"
|
||||
, " scriptPath=/wiki"
|
||||
, " stylePath=/wiki/skins"
|
||||
, " currentVersion=1.21wmf11"
|
||||
, " namespaces="
|
||||
, " -1="
|
||||
, " id=-1"
|
||||
, " name=Special"
|
||||
, " canonicalName=Special"
|
||||
, " hasSubpages=false"
|
||||
, " hasGenderDistinction=false"
|
||||
, " isCapitalized=false"
|
||||
, " isContent=false"
|
||||
, " isIncludable=true"
|
||||
, " isMovable=false"
|
||||
, " isSubject=true"
|
||||
, " isTalk=false"
|
||||
, " defaultContentModel=<<NULL>>"
|
||||
, " aliases="
|
||||
, " subject=-1"
|
||||
, " 0="
|
||||
, " id=0"
|
||||
, " name="
|
||||
, " canonicalName="
|
||||
, " hasSubpages=false"
|
||||
, " hasGenderDistinction=false"
|
||||
, " isCapitalized=false"
|
||||
, " isContent=true"
|
||||
, " isIncludable=true"
|
||||
, " isMovable=true"
|
||||
, " isSubject=true"
|
||||
, " isTalk=false"
|
||||
, " defaultContentModel=<<NULL>>"
|
||||
, " aliases="
|
||||
, " subject=0"
|
||||
, " talk=1"
|
||||
, " associated=1"
|
||||
, " displayName=(Main)"
|
||||
, " 1="
|
||||
, " id=1"
|
||||
, " name=Talk"
|
||||
, " canonicalName=Talk"
|
||||
, " hasSubpages=false"
|
||||
, " hasGenderDistinction=false"
|
||||
, " isCapitalized=false"
|
||||
, " isContent=false"
|
||||
, " isIncludable=true"
|
||||
, " isMovable=true"
|
||||
, " isSubject=false"
|
||||
, " isTalk=true"
|
||||
, " defaultContentModel=<<NULL>>"
|
||||
, " aliases="
|
||||
, " subject=1"
|
||||
, " talk=1"
|
||||
, " associated=0"
|
||||
, " 828="
|
||||
, " id=828"
|
||||
, " name=Module"
|
||||
, " canonicalName=Module"
|
||||
, " hasSubpages=false"
|
||||
, " hasGenderDistinction=false"
|
||||
, " isCapitalized=false"
|
||||
, " isContent=false"
|
||||
, " isIncludable=true"
|
||||
, " isMovable=true"
|
||||
, " isSubject=true"
|
||||
, " isTalk=false"
|
||||
, " defaultContentModel=<<NULL>>"
|
||||
, " aliases="
|
||||
, " subject=828"
|
||||
, " talk=829"
|
||||
, " associated=829"
|
||||
, " 829="
|
||||
, " id=829"
|
||||
, " name=Module talk"
|
||||
, " canonicalName=Module_talk"
|
||||
, " hasSubpages=false"
|
||||
, " hasGenderDistinction=false"
|
||||
, " isCapitalized=false"
|
||||
, " isContent=false"
|
||||
, " isIncludable=true"
|
||||
, " isMovable=true"
|
||||
, " isSubject=false"
|
||||
, " isTalk=true"
|
||||
, " defaultContentModel=<<NULL>>"
|
||||
, " aliases="
|
||||
, " subject=829"
|
||||
, " talk=829"
|
||||
, " associated=828"
|
||||
, " stats="
|
||||
, " pages=1"
|
||||
, " articles=2"
|
||||
, " files=3"
|
||||
, " edits=4"
|
||||
, " views=5"
|
||||
, " users=6"
|
||||
, " activeUsers=7"
|
||||
, " admins=8"
|
||||
));
|
||||
}
|
||||
// @Test public void LoadSiteStats() { // deprecated by Scribunto; DATE:2013-04-12
|
||||
// fxt.Parser_fxt().Wiki().Stats().NumPages_(1).NumArticles_(2).NumFiles_(3).NumEdits_(4).NumViews_(5).NumUsers_(6).NumUsersActive_(7);
|
||||
// fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_site.Invk_loadSiteStats, Object_.Ary_empty, "1;2;3;4;5;6;7");
|
||||
// }
|
||||
}
|
||||
142
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_text.java
Normal file
142
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_text.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.bits.*;
|
||||
import gplx.xowa.langs.msgs.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_text implements Scrib_lib {
|
||||
private final Scrib_lib_text__json_util json_util = new Scrib_lib_text__json_util();
|
||||
private final Scrib_lib_text__reindex_data reindex_data = new Scrib_lib_text__reindex_data();
|
||||
public Scrib_lib_text(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_text(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.text.lua"));
|
||||
notify_wiki_changed_fnc = mod.Fncs_get_by_key("notify_wiki_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_wiki_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private final Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_unstrip: return Unstrip(args, rslt);
|
||||
case Proc_unstripNoWiki: return UnstripNoWiki(args, rslt);
|
||||
case Proc_killMarkers: return KillMarkers(args, rslt);
|
||||
case Proc_getEntityTable: return GetEntityTable(args, rslt);
|
||||
case Proc_init_text_for_wiki: return Init_text_for_wiki(args, rslt);
|
||||
case Proc_jsonEncode: return JsonEncode(args, rslt);
|
||||
case Proc_jsonDecode: return JsonDecode(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_unstrip = 0, Proc_unstripNoWiki = 1, Proc_killMarkers = 2, Proc_getEntityTable = 3, Proc_init_text_for_wiki = 4, Proc_jsonEncode = 5, Proc_jsonDecode = 6;
|
||||
public static final String Invk_unstrip = "unstrip", Invk_unstripNoWiki = "unstripNoWiki", Invk_killMarkers = "killMarkers", Invk_getEntityTable = "getEntityTable"
|
||||
, Invk_init_text_for_wiki = "init_text_for_wiki", Invk_jsonEncode = "jsonEncode", Invk_jsonDecode = "jsonDecode";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_unstrip, Invk_unstripNoWiki, Invk_killMarkers, Invk_getEntityTable, Invk_init_text_for_wiki, Invk_jsonEncode, Invk_jsonDecode);
|
||||
public boolean Unstrip(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
|
||||
public boolean UnstripNoWiki(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
|
||||
public boolean KillMarkers(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
|
||||
public boolean GetEntityTable(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
if (html_entities == null) html_entities = Scrib_lib_text_html_entities.new_();
|
||||
return rslt.Init_obj(html_entities);
|
||||
} private static Keyval[] html_entities;
|
||||
public boolean JsonEncode(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Object itm = args.Pull_obj(0);
|
||||
|
||||
// try to determine if node or array; EX: {a:1, b:2} vs [a:1, b:2]
|
||||
Keyval[] itm_as_nde = null;
|
||||
Object itm_as_ary = null;
|
||||
Class<?> itm_type = itm.getClass();
|
||||
boolean itm_is_nde = Type_adp_.Eq(itm_type, Keyval[].class);
|
||||
|
||||
// additional logic to classify "[]" as ary, not nde; note that this is done by checking len of itm_as_nde
|
||||
if (itm_is_nde) {
|
||||
itm_as_nde = (Keyval[])itm;
|
||||
int itm_as_nde_len = itm_as_nde.length;
|
||||
if (itm_as_nde_len == 0) { // Keyval[0] could be either "[]" or "{}"; for now, classify as "[]" per TextLibraryTests.lua; 'json encode, empty table (could be either [] or {}, but change should be announced)'; DATE:2016-08-01
|
||||
itm_as_nde = null;
|
||||
itm_is_nde = false;
|
||||
}
|
||||
}
|
||||
if (!itm_is_nde)
|
||||
itm_as_ary = Array_.cast(itm);
|
||||
|
||||
// reindex ndes unless preserve_keys
|
||||
int flags = args.Cast_int_or(1, 0);
|
||||
if ( itm_is_nde
|
||||
&& !Bitmask_.Has_int(flags, Scrib_lib_text__json_util.Flag__preserve_keys)
|
||||
) {
|
||||
json_util.Reindex_arrays(reindex_data, itm_as_nde, true);
|
||||
if (reindex_data.Rv_is_kvy()) {
|
||||
itm_as_nde = reindex_data.Rv_as_kvy();
|
||||
itm_as_ary = null;
|
||||
}
|
||||
else {
|
||||
itm_as_ary = reindex_data.Rv_as_ary();
|
||||
itm_as_nde = null;
|
||||
itm_is_nde = false;
|
||||
}
|
||||
}
|
||||
|
||||
// encode and return
|
||||
byte[] rv = itm_is_nde
|
||||
? json_util.Encode_as_nde(itm_as_nde, flags & Scrib_lib_text__json_util.Flag__pretty, Scrib_lib_text__json_util.Skip__all)
|
||||
: json_util.Encode_as_ary(itm_as_ary, flags & Scrib_lib_text__json_util.Flag__pretty, Scrib_lib_text__json_util.Skip__all)
|
||||
;
|
||||
if (rv == null) throw Err_.new_("scribunto", "mw.text.jsonEncode: Unable to encode value");
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean JsonDecode(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
// init
|
||||
byte[] json = args.Pull_bry(0);
|
||||
int flags = args.Cast_int_or(1, 0);
|
||||
int opts = Scrib_lib_text__json_util.Opt__force_assoc;
|
||||
if (Bitmask_.Has_int(flags, Scrib_lib_text__json_util.Flag__try_fixing))
|
||||
opts = Bitmask_.Add_int(opts, Scrib_lib_text__json_util.Flag__try_fixing);
|
||||
|
||||
// decode json to Object; note that Bool_.Y means ary and Bool_.N means ary
|
||||
byte rv_tid = json_util.Decode(core.App().Utl__json_parser(), json, opts);
|
||||
if (rv_tid == Bool_.__byte) throw Err_.new_("scribunto", "mw.text.jsonEncode: Unable to decode String " + String_.new_u8(json));
|
||||
if (rv_tid == Bool_.Y_byte) {
|
||||
Keyval[] rv_as_kvy = (Keyval[])json_util.Decode_rslt_as_nde();
|
||||
|
||||
// reindex unless preserve_keys passed
|
||||
if (!(Bitmask_.Has_int(flags, Scrib_lib_text__json_util.Flag__preserve_keys))) {
|
||||
json_util.Reindex_arrays(reindex_data, rv_as_kvy, false);
|
||||
rv_as_kvy = reindex_data.Rv_is_kvy() ? (Keyval[])reindex_data.Rv_as_kvy() : (Keyval[])reindex_data.Rv_as_ary();
|
||||
}
|
||||
return rslt.Init_obj(rv_as_kvy);
|
||||
}
|
||||
else
|
||||
return rslt.Init_obj(json_util.Decode_rslt_as_ary());
|
||||
}
|
||||
public void Notify_wiki_changed() {if (notify_wiki_changed_fnc != null) core.Interpreter().CallFunction(notify_wiki_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean Init_text_for_wiki(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xow_msg_mgr msg_mgr = core.Wiki().Msg_mgr();
|
||||
Keyval[] rv = new Keyval[4];
|
||||
rv[0] = Keyval_.new_("comma", Init_lib_text_get_msg(msg_mgr, "comma-separator"));
|
||||
rv[1] = Keyval_.new_("and", Init_lib_text_get_msg(msg_mgr, "and") + Init_lib_text_get_msg(msg_mgr, "word-separator"));
|
||||
rv[2] = Keyval_.new_("ellipsis", Init_lib_text_get_msg(msg_mgr, "ellipsis"));
|
||||
rv[3] = Keyval_.new_("nowiki_protocols", Keyval_.Ary_empty); // NOTE: code implemented, but waiting for it to be used; DATE:2014-03-20
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
private String Init_lib_text_get_msg(Xow_msg_mgr msg_mgr, String msg_key) {
|
||||
return String_.new_u8(msg_mgr.Val_by_key_obj(Bry_.new_u8(msg_key)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.net.*;
|
||||
class Scrib_lib_text_ {
|
||||
public static Keyval[] Init_nowiki_protocols(Xowe_wiki wiki) {
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b128();
|
||||
Ordered_hash protocols = Gfo_protocol_itm.Regy;
|
||||
int len = protocols.Count();
|
||||
List_adp rv = List_adp_.New();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Gfo_protocol_itm itm = (Gfo_protocol_itm)protocols.Get_at(i);
|
||||
if (itm.Text_ends_w_colon()) { // To convert the protocol into a case-insensitive Lua pattern, we need to replace letters with a character class like [Xx] and insert a '%' before various punctuation.
|
||||
Keyval kv = Init_nowiki_protocols_itm(bfr, itm);
|
||||
rv.Add(kv);
|
||||
}
|
||||
}
|
||||
bfr.Mkr_rls();
|
||||
return (Keyval[])rv.To_ary(Keyval.class);
|
||||
}
|
||||
private static Keyval Init_nowiki_protocols_itm(Bry_bfr bfr, Gfo_protocol_itm itm) {
|
||||
byte[] key = itm.Key_wo_colon_bry();
|
||||
int end = key.length - 1; // -1 to ignore final colon
|
||||
for (int i = 0; i < end; i++) {
|
||||
byte b = key[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E:
|
||||
case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J:
|
||||
case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O:
|
||||
case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T:
|
||||
case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z:
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(b).Add_byte(Byte_ascii.Case_lower(b)).Add_byte(Byte_ascii.Brack_end); // [Aa]
|
||||
break;
|
||||
case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e:
|
||||
case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j:
|
||||
case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o:
|
||||
case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t:
|
||||
case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z:
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Case_upper(b)).Add_byte(b).Add_byte(Byte_ascii.Brack_end); // [Aa]
|
||||
break;
|
||||
case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Pow: case Byte_ascii.Dollar: case Byte_ascii.Percent: case Byte_ascii.Dot:
|
||||
case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end: case Byte_ascii.Star: case Byte_ascii.Plus: case Byte_ascii.Question: case Byte_ascii.Dash:
|
||||
bfr.Add_byte(Byte_ascii.Percent).Add_byte(b); // regex is '/([a-zA-Z])|([()^$%.\[\]*+?-])/'
|
||||
break;
|
||||
default: // ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
bfr.Add(Colon_encoded);
|
||||
return Keyval_.new_(itm.Key_wo_colon_str(), bfr.To_str_and_clear());
|
||||
} private static final byte[] Colon_encoded = Bry_.new_a7(":");
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.langs.jsons.*;
|
||||
class Scrib_lib_text__json_util {
|
||||
private final Json_wtr wtr = new Json_wtr();
|
||||
public void Reindex_arrays(Scrib_lib_text__reindex_data rv, Keyval[] kv_ary, boolean is_encoding) {
|
||||
int next = 0;
|
||||
if (is_encoding) {
|
||||
Array_.Sort(kv_ary, KeyVal__sorter__key_is_numeric.Instance);
|
||||
next = 1;
|
||||
}
|
||||
boolean is_sequence = true;
|
||||
int len = kv_ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval kv = kv_ary[i];
|
||||
Object kv_val = kv.Val();
|
||||
if (kv_val != null && Type_adp_.Eq(kv_val.getClass(), Keyval[].class)) {
|
||||
Reindex_arrays(rv, (Keyval[])kv_val, is_encoding);
|
||||
if (!rv.Rv_is_kvy())
|
||||
kv.Val_(rv.Rv_as_ary());
|
||||
}
|
||||
if (is_sequence) {
|
||||
if (kv.Key_tid() == Type_adp_.Tid__int) {
|
||||
int kv_key_as_int = Int_.cast(kv.Key_as_obj());
|
||||
is_sequence = next++ == kv_key_as_int;
|
||||
}
|
||||
else {
|
||||
int kv_key_to_int = Bry_.To_int_or__strict(Bry_.new_a7(kv.Key()), -1); // NOTE: a7 b/c proc is only checking for digits; none a7 bytes will be replaced by ?
|
||||
if (is_encoding && kv_key_to_int != -1) {
|
||||
is_sequence = next == kv_key_to_int;
|
||||
++next;
|
||||
}
|
||||
else
|
||||
is_sequence = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_sequence) {
|
||||
if (is_encoding) {
|
||||
Object rv_as_ary = To_array_values(kv_ary);
|
||||
rv.Init(Bool_.N, null, rv_as_ary);
|
||||
return;
|
||||
} else {
|
||||
Convert_to_base1(kv_ary); // PHP: return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr;
|
||||
}
|
||||
}
|
||||
rv.Init(Bool_.Y, kv_ary, null);
|
||||
}
|
||||
private static Object[] To_array_values(Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
Object[] rv = new Object[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval itm = ary[i];
|
||||
rv[i] = itm.Val();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static void Convert_to_base1(Keyval[] ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval itm = ary[i];
|
||||
itm.Key_(i + 1);
|
||||
}
|
||||
}
|
||||
public Keyval[] Decode_rslt_as_nde() {return decode_rslt_as_nde;} private Keyval[] decode_rslt_as_nde;
|
||||
public Keyval[] Decode_rslt_as_ary() {return decode_rslt_as_ary;} private Keyval[] decode_rslt_as_ary;
|
||||
public byte Decode(Json_parser parser, byte[] src, int flag) {
|
||||
synchronized (wtr) {
|
||||
Json_doc jdoc = parser.Parse(src);
|
||||
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__ary) {
|
||||
this.decode_rslt_as_ary = Decode_ary_top(jdoc.Root_ary());
|
||||
return Bool_.N_byte;
|
||||
}
|
||||
else {
|
||||
Json_nde root = (Json_nde)jdoc.Root_grp();
|
||||
int len = root.Len();
|
||||
this.decode_rslt_as_nde = new Keyval[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_kv json_kv = root.Get_at_as_kv(i);
|
||||
String kv_str = json_kv.Key_as_str();
|
||||
Object kv_val = Decode_obj(json_kv.Val());
|
||||
int kv_int = Int_.parse_or(kv_str, Int_.Min_value);
|
||||
decode_rslt_as_nde[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
|
||||
}
|
||||
return Bool_.Y_byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
private Object Decode_obj(Json_itm itm) {
|
||||
int itm_tid = itm.Tid();
|
||||
switch (itm_tid) {
|
||||
case Json_itm_.Tid__ary: return Decode_ary_sub(Json_ary.cast(itm));
|
||||
case Json_itm_.Tid__nde: return Decode_nde(Json_nde.cast(itm));
|
||||
default: return itm.Data();
|
||||
}
|
||||
}
|
||||
private Keyval[] Decode_ary_top(Json_ary ary) { // NOTE: top-level arrays must be returned as numbered nodes; EX: [{1:a}, {2:b}, {3:c}] not [a, b, c]; DATE:2016-08-01
|
||||
int len = ary.Len();
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_itm itm = ary.Get_at(i);
|
||||
rv[i] = Keyval_.int_(i + List_adp_.Base1, Decode_obj(itm));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private Object Decode_ary_sub(Json_ary ary) {
|
||||
int len = ary.Len();
|
||||
Object[] rv = new Object[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_itm itm = ary.Get_at(i);
|
||||
rv[i] = Decode_obj(itm);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private Keyval[] Decode_nde(Json_nde nde) {
|
||||
int len = nde.Len();
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Json_kv itm = nde.Get_at_as_kv(i);
|
||||
String kv_str = itm.Key_as_str();
|
||||
int kv_int = Int_.parse_or(kv_str, Int_.Min_value);
|
||||
Object kv_val = Decode_obj(itm.Val());
|
||||
rv[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public byte[] Encode_as_nde(Keyval[] itm, int flag, int skip) {
|
||||
synchronized (wtr ) {
|
||||
wtr.Clear().Doc_nde_bgn();
|
||||
Encode_kv_ary(itm);
|
||||
return wtr.Doc_nde_end().To_bry_and_clear();
|
||||
}
|
||||
}
|
||||
public byte[] Encode_as_ary(Object ary, int flag, int skip) {
|
||||
synchronized (wtr ) {
|
||||
wtr.Clear().Doc_ary_bgn();
|
||||
Encode_ary(ary);
|
||||
return wtr.Doc_ary_end().To_bry_and_clear();
|
||||
}
|
||||
}
|
||||
private void Encode_kv_ary(Keyval[] kv_ary) {
|
||||
int len = kv_ary.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Keyval kv = kv_ary[i];
|
||||
Encode_kv(kv);
|
||||
}
|
||||
}
|
||||
private void Encode_kv(Keyval kv) {
|
||||
Object kv_val = kv.Val();
|
||||
Class<?> type = Type_adp_.ClassOf_obj(kv_val);
|
||||
if (Type_adp_.Eq(type, Keyval[].class)) {
|
||||
wtr.Nde_bgn(kv.Key());
|
||||
Encode_kv_ary((Keyval[])kv_val);
|
||||
wtr.Nde_end();
|
||||
}
|
||||
else if (Type_adp_.Is_array(type)) { // encode as array
|
||||
wtr.Ary_bgn(kv.Key());
|
||||
Encode_ary(kv_val);
|
||||
wtr.Ary_end();
|
||||
}
|
||||
else if (Type_adp_.Eq(type, Int_.Cls_ref_type)) wtr.Kv_int(kv.Key(), Int_.cast(kv_val));
|
||||
else if (Type_adp_.Eq(type, Long_.Cls_ref_type)) wtr.Kv_long(kv.Key(), Long_.cast(kv_val));
|
||||
else if (Type_adp_.Eq(type, Float_.Cls_ref_type)) wtr.Kv_float(kv.Key(), Float_.cast(kv_val));
|
||||
else if (Type_adp_.Eq(type, Double_.Cls_ref_type)) wtr.Kv_double(kv.Key(), Double_.cast(kv_val));
|
||||
else if (Type_adp_.Eq(type, Bool_.Cls_ref_type)) wtr.Kv_bool(kv.Key(), Bool_.Cast(kv_val));
|
||||
else wtr.Kv_str(kv.Key(), Object_.Xto_str_strict_or_null(kv_val));
|
||||
}
|
||||
private void Encode_ary(Object ary) {
|
||||
int ary_len = Array_.Len(ary);
|
||||
for (int j = 0; j < ary_len; ++j)
|
||||
wtr.Ary_itm_obj(Array_.Get_at(ary, j));
|
||||
}
|
||||
public static final int
|
||||
Flag__none = 0
|
||||
, Flag__preserve_keys = 1
|
||||
, Flag__try_fixing = 2
|
||||
, Flag__pretty = 4
|
||||
;
|
||||
public static final int
|
||||
Skip__utf8 = 1
|
||||
, Skip__xml = 2
|
||||
, Skip__all = 3
|
||||
;
|
||||
public static final int
|
||||
Opt__force_assoc = 1
|
||||
;
|
||||
}
|
||||
class KeyVal__sorter__key_is_numeric implements gplx.core.lists.ComparerAble {
|
||||
public int compare(Object lhsObj, Object rhsObj) {
|
||||
Keyval lhs_itm = (Keyval)lhsObj;
|
||||
Keyval rhs_itm = (Keyval)rhsObj;
|
||||
int lhs_int = Int_.parse_or(lhs_itm.Key(), Int_.Min_value);
|
||||
int rhs_int = Int_.parse_or(rhs_itm.Key(), Int_.Min_value);
|
||||
return CompareAble_.Compare(lhs_int, rhs_int);
|
||||
}
|
||||
public static final KeyVal__sorter__key_is_numeric Instance = new KeyVal__sorter__key_is_numeric(); KeyVal__sorter__key_is_numeric() {}
|
||||
}
|
||||
class Scrib_lib_text__reindex_data {
|
||||
public boolean Rv_is_kvy() {return rv_is_kvy;} private boolean rv_is_kvy;
|
||||
public Keyval[] Rv_as_kvy() {return rv_as_kvy;} private Keyval[] rv_as_kvy;
|
||||
public Object Rv_as_ary() {return rv_as_ary;} private Object rv_as_ary;
|
||||
public void Init(boolean rv_is_kvy, Keyval[] rv_as_kvy, Object rv_as_ary) {
|
||||
this.rv_is_kvy = rv_is_kvy;
|
||||
this.rv_as_kvy = rv_as_kvy;
|
||||
this.rv_as_ary = rv_as_ary;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.langs.jsons.*;
|
||||
public class Scrib_lib_text_json_tst {
|
||||
private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib_text lib;
|
||||
private Scrib_lib_json_fxt json_fxt = new Scrib_lib_json_fxt();
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_text();
|
||||
lib.Init();
|
||||
}
|
||||
@Test public void Nde__key_obj__primitives() { // NOTE: based on MW
|
||||
json_fxt.Test_json_roundtrip(fxt, lib
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ 'int':1"
|
||||
, ", 'String':'abc'"
|
||||
, ", 'true':true"
|
||||
, ", 'array':"
|
||||
, " [ 1"
|
||||
, " , 2"
|
||||
, " , 3"
|
||||
, " ]"
|
||||
, ", 'node':"
|
||||
, " { 'key':'val'"
|
||||
, " }"
|
||||
, "}"
|
||||
)
|
||||
, Keyval_.Ary
|
||||
( Keyval_.new_("int", 1)
|
||||
, Keyval_.new_("String", "abc")
|
||||
, Keyval_.new_("true", true)
|
||||
, Keyval_.new_("array", new int[] {1, 2, 3})
|
||||
, Keyval_.new_("node", Keyval_.Ary(Keyval_.new_("key", "val")))
|
||||
));
|
||||
}
|
||||
@Test public void Nde__obj_in_obj() {
|
||||
json_fxt.Test_json_roundtrip(fxt, lib
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ 'x':"
|
||||
, " [ 1"
|
||||
, " , 2"
|
||||
, " , { 'y':'x'"
|
||||
, " }"
|
||||
, " ]"
|
||||
, "}"
|
||||
)
|
||||
, Keyval_.Ary
|
||||
( Keyval_.new_("x", new Object[]
|
||||
{ 1, 2, Keyval_.Ary
|
||||
( Keyval_.new_("y", "x")
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@Test public void Nde__ary_in_obj() { // NOTE: based on MW
|
||||
json_fxt.Test_json_roundtrip(fxt, lib
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ 'x':"
|
||||
, " [ 1"
|
||||
, " , 2"
|
||||
, " , { 'y':"
|
||||
, " [ 3"
|
||||
, " , 4"
|
||||
, " ]"
|
||||
, " }"
|
||||
, " ]"
|
||||
, "}"
|
||||
)
|
||||
, Keyval_.Ary
|
||||
( Keyval_.new_("x"
|
||||
, new Object[] {1, 2, Keyval_.Ary
|
||||
( Keyval_.new_("y"
|
||||
, new Object[] {3, 4}
|
||||
))}))
|
||||
);
|
||||
}
|
||||
@Test public void Nde__key_int__mixed() {// NOTE: based on MW
|
||||
json_fxt.Test_json_roundtrip(fxt, lib
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ 'x':'x'"
|
||||
, ", '1':1"
|
||||
, ", '2':2"
|
||||
, "}"
|
||||
)
|
||||
, Keyval_.Ary
|
||||
( Keyval_.new_("x", "x")
|
||||
, Keyval_.new_("1", 1)
|
||||
, Keyval_.new_("2", 2)
|
||||
));
|
||||
}
|
||||
@Test public void Nde__key_int__auto() {// NOTE: based on MW
|
||||
json_fxt.Test_json_encode(fxt, lib
|
||||
, Scrib_lib_text__json_util.Flag__preserve_keys
|
||||
, Kv_ary_utl.new_(Bool_.Y, new Object[]
|
||||
{ 1
|
||||
, "abc"
|
||||
, true
|
||||
, false
|
||||
})
|
||||
, Json_doc.Make_str_by_apos // NOTE: numbering is done by Kv_ary_utl, not Reindex_arrays
|
||||
( "{ '1':1"
|
||||
, ", '2':'abc'"
|
||||
, ", '3':true"
|
||||
, ", '4':false"
|
||||
, "}"
|
||||
)
|
||||
);
|
||||
json_fxt.Test_json_decode(fxt, lib
|
||||
, Scrib_lib_text__json_util.Flag__preserve_keys
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ '1':1"
|
||||
, ", '2':'abc'"
|
||||
, ", '3':true"
|
||||
, ", '4':false"
|
||||
, "}"
|
||||
)
|
||||
, Kv_ary_utl.new_(Bool_.Y, new Object[]
|
||||
{ 1
|
||||
, "abc"
|
||||
, true
|
||||
, false
|
||||
}
|
||||
));
|
||||
}
|
||||
// @Test public void Nde__empty() { // NOTE: based on MW
|
||||
// json_fxt.Test_json_roundtrip(fxt, lib
|
||||
// , Json_doc.Make_str_by_apos
|
||||
// ( "{"
|
||||
// , "}"
|
||||
// )
|
||||
// , Keyval_.Ary_empty
|
||||
// );
|
||||
// }
|
||||
@Test public void Ary__empty() { // NOTE: based on MW
|
||||
json_fxt.Test_json_encode(fxt, lib, Scrib_lib_text__json_util.Flag__none
|
||||
, Kv_ary_utl.new_(Bool_.Y, new Object[] {})
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "["
|
||||
, "]"
|
||||
)
|
||||
);
|
||||
}
|
||||
@Test public void Ary__obj() { // NOTE: based on MW
|
||||
json_fxt.Test_json_encode(fxt, lib, Scrib_lib_text__json_util.Flag__none
|
||||
, Kv_ary_utl.new_(Bool_.Y, 1, "abc", true)
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "[ 1"
|
||||
, ", 'abc'"
|
||||
, ", true"
|
||||
, "]"
|
||||
)
|
||||
);
|
||||
}
|
||||
@Test public void Ary__nested() { // NOTE: based on MW
|
||||
json_fxt.Test_json_roundtrip(fxt, lib
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "[ 1"
|
||||
, ", 2"
|
||||
, ", 3"
|
||||
, ", "
|
||||
, " [ 4"
|
||||
, " , 5"
|
||||
, " , "
|
||||
, " [ 6"
|
||||
, " , 7"
|
||||
, " , 8"
|
||||
, " ]"
|
||||
, " , 9"
|
||||
, " ]"
|
||||
, "]"
|
||||
)
|
||||
, Kv_ary_utl.new_(Bool_.Y, new Object[] {1, 2, 3, new Object[] {4, 5, new Object[] {6, 7, 8}, 9}})
|
||||
);
|
||||
}
|
||||
@Test public void Nde__smoke() {
|
||||
json_fxt.Test_json_encode(fxt, lib
|
||||
, Scrib_lib_text__json_util.Flag__none
|
||||
, Keyval_.Ary
|
||||
( Keyval_.new_("axes", Keyval_.Ary
|
||||
( Keyval_.int_(1, Keyval_.Ary
|
||||
( Keyval_.new_("type", "x")
|
||||
))
|
||||
, Keyval_.int_(2, Keyval_.Ary
|
||||
( Keyval_.new_("type", "y")
|
||||
))
|
||||
))
|
||||
)
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ 'axes':"
|
||||
, " ["
|
||||
, " { 'type':'x'"
|
||||
, " }"
|
||||
, " , { 'type':'y'"
|
||||
, " }"
|
||||
, " ]"
|
||||
, "}"
|
||||
)
|
||||
);
|
||||
}
|
||||
@Test public void Decode__key__int() {
|
||||
Keyval[] kv_ary = (Keyval[])json_fxt.Test_json_decode(fxt, lib
|
||||
, Scrib_lib_text__json_util.Flag__none
|
||||
, Json_doc.Make_str_by_apos
|
||||
( "{ '1':"
|
||||
, " { '11':'aa'"
|
||||
, " }"
|
||||
, ", '2':'b'"
|
||||
, "}"
|
||||
)
|
||||
, Keyval_.Ary
|
||||
( Keyval_.int_(1, Keyval_.Ary
|
||||
( Keyval_.int_(11, "aa")
|
||||
))
|
||||
, Keyval_.int_(2, "b")
|
||||
)
|
||||
);
|
||||
Tfds.Eq(kv_ary[0].Key_as_obj(), 1);
|
||||
Tfds.Eq(((Keyval[])kv_ary[0].Val())[0].Key_as_obj(), 11);
|
||||
}
|
||||
}
|
||||
class Scrib_lib_json_fxt {
|
||||
private final Json_wtr wtr = new Json_wtr();
|
||||
public void Test_json_roundtrip(Scrib_invoke_func_fxt fxt, Scrib_lib_text lib, String json, Object obj) {
|
||||
Test_json_decode(fxt, lib, Scrib_lib_text__json_util.Flag__none, json, obj);
|
||||
Test_json_encode(fxt, lib, Scrib_lib_text__json_util.Flag__none, obj, json);
|
||||
}
|
||||
public Object Test_json_decode(Scrib_invoke_func_fxt fxt, Scrib_lib_text lib, int flag, String raw, Object expd) {
|
||||
Object actl = fxt.Test_scrib_proc_rv_as_obj(lib, Scrib_lib_text.Invk_jsonDecode, Object_.Ary(raw, flag));
|
||||
Tfds.Eq_str_lines(To_str(expd), To_str(actl), raw);
|
||||
return actl;
|
||||
}
|
||||
public void Test_json_encode(Scrib_invoke_func_fxt fxt, Scrib_lib_text lib, int flag, Object raw, String expd) {
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_text.Invk_jsonEncode, Object_.Ary(raw, flag), "1=" + String_.Replace(expd, "'", "\""));
|
||||
}
|
||||
private String To_str(Object o) {
|
||||
if (o == null) return "<< NULL >>";
|
||||
Class<?> type = o.getClass();
|
||||
if (Type_adp_.Eq(type, Keyval[].class)) return Kv_ary_utl.Ary_to_str(wtr, (Keyval[])o);
|
||||
else if (Type_adp_.Is_array(type)) return Array_.To_str_nested_obj(o);
|
||||
else return Object_.Xto_str_strict_or_null(o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.langs.jsons.*;
|
||||
public class Scrib_lib_text_tst {
|
||||
private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib_text lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_text();
|
||||
lib.Init();
|
||||
}
|
||||
@Test public void Unstrip() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_text.Invk_unstrip, Object_.Ary("a"), "a");
|
||||
}
|
||||
@Test public void GetEntityTable() {
|
||||
Keyval[] actl = fxt.Test_scrib_proc_rv_as_kv_ary(lib, Scrib_lib_text.Invk_getEntityTable, Object_.Ary());
|
||||
Tfds.Eq(1510, actl.length); // large result; only test # of entries
|
||||
}
|
||||
}
|
||||
229
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_title.java
Normal file
229
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_title.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.primitives.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.wikis.caches.*; import gplx.xowa.xtns.pfuncs.ttls.*; import gplx.xowa.wikis.xwikis.*; import gplx.xowa.wikis.data.tbls.*;
|
||||
import gplx.xowa.files.commons.*; import gplx.xowa.files.origs.*;
|
||||
import gplx.xowa.apps.wms.apis.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_title implements Scrib_lib {
|
||||
public Scrib_lib_title(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_title(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.title.lua")
|
||||
, Keyval_.new_("thisTitle", "") // NOTE: pass blank; will be updated by GetCurrentTitle
|
||||
, Keyval_.new_("NS_MEDIA", Xow_ns_.Tid__media) // NOTE: MW passes down NS_MEDIA; this should be -2 on all wikis...
|
||||
);
|
||||
notify_page_changed_fnc = mod.Fncs_get_by_key("notify_page_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_page_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_newTitle: return NewTitle(args, rslt);
|
||||
case Proc_makeTitle: return MakeTitle(args, rslt);
|
||||
case Proc_getExpensiveData: return GetExpensiveData(args, rslt);
|
||||
case Proc_getUrl: return GetUrl(args, rslt);
|
||||
case Proc_getContent: return GetContent(args, rslt);
|
||||
case Proc_getFileInfo: return GetFileInfo(args, rslt);
|
||||
case Proc_getCurrentTitle: return GetCurrentTitle(args, rslt);
|
||||
case Proc_protectionLevels: return ProtectionLevels(args, rslt);
|
||||
case Proc_cascadingProtection: return CascadingProtection(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_newTitle = 0, Proc_makeTitle = 1, Proc_getExpensiveData = 2, Proc_getUrl = 3, Proc_getContent = 4, Proc_getFileInfo = 5, Proc_getCurrentTitle = 6, Proc_protectionLevels = 7, Proc_cascadingProtection = 8;
|
||||
public static final String
|
||||
Invk_newTitle = "newTitle", Invk_getExpensiveData = "getExpensiveData", Invk_makeTitle = "makeTitle"
|
||||
, Invk_getUrl = "getUrl", Invk_getContent = "getContent", Invk_getFileInfo = "getFileInfo", Invk_getCurrentTitle = "getCurrentTitle"
|
||||
, Invk_protectionLevels = "protectionLevels", Invk_cascadingProtection = "cascadingProtection"
|
||||
;
|
||||
private static final String[] Proc_names = String_.Ary(Invk_newTitle, Invk_makeTitle, Invk_getExpensiveData, Invk_getUrl, Invk_getContent, Invk_getFileInfo, Invk_getCurrentTitle, Invk_protectionLevels, Invk_cascadingProtection);
|
||||
public boolean NewTitle(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
if (args.Len() == 0) return rslt.Init_obj(null); // invalid title, return null; EX:{{#invoke:Message box|fmbox}} DATE:2015-03-04
|
||||
byte[] ttl_bry = args.Xstr_bry_or_null(0); // NOTE: Pull_bry fails if caller passes int; PAGE:de.w:Wikipedia:Lua/Modul/Pinging/Test/recipients; DATE:2016-04-21
|
||||
Object ns_obj = args.Cast_obj_or_null(1);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
byte[] ns_bry = null;
|
||||
if (ns_obj != null) {
|
||||
ns_bry = Parse_ns(wiki, ns_obj); if (ns_bry == null) throw Err_.new_wo_type("unknown ns", "ns", Object_.Xto_str_strict_or_empty(ns_obj));
|
||||
}
|
||||
if (ns_bry != null) {
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
ttl_bry = bfr.Add(ns_bry).Add_byte(Byte_ascii.Colon).Add(ttl_bry).To_bry_and_rls();
|
||||
}
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(core.Wiki(), ttl_bry);
|
||||
if (ttl == null) return rslt.Init_obj(null); // invalid title; exit; matches MW logic
|
||||
return rslt.Init_obj(GetInexpensiveTitleData(ttl));
|
||||
}
|
||||
public void Notify_page_changed() {if (notify_page_changed_fnc != null) core.Interpreter().CallFunction(notify_page_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean GetUrl(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
byte[] url_func_bry = args.Pull_bry(1);
|
||||
Object url_func_obj = url_func_hash.Get_by(url_func_bry);
|
||||
if (url_func_obj == null) throw Err_.new_wo_type("url_function is not valid", "url_func", String_.new_u8(url_func_bry));
|
||||
byte url_func_tid = ((Byte_obj_val)url_func_obj).Val();
|
||||
byte[] qry_bry = args.Extract_qry_args(wiki, 2);
|
||||
// byte[] proto = Scrib_kv_utl_.Val_to_bry_or(values, 3, null); // NOTE: Scribunto has more conditional logic around argument 2 and setting protocols; DATE:2014-07-07
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry); if (ttl == null) return rslt.Init_obj(null);
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
//if (url_func_tid == Pfunc_urlfunc.Tid_full) {
|
||||
// if (proto == null) proto = Proto_relative;
|
||||
// Object proto_obj = proto_hash.Get_by(proto); if (proto_obj == null) throw Err_.new_fmt_("protocol is not valid: {0}", proto);
|
||||
// //qry_bry = (byte[])proto_obj;
|
||||
// byte proto_tid = ((Byte_obj_val)proto_obj).Val();
|
||||
// bfr.Add();
|
||||
//}
|
||||
Pfunc_urlfunc.UrlString(core.Ctx(), url_func_tid, false, ttl_bry, bfr, qry_bry);
|
||||
return rslt.Init_obj(bfr.To_str_and_rls());
|
||||
}
|
||||
private static final Hash_adp_bry url_func_hash = Hash_adp_bry.ci_a7()
|
||||
.Add_str_byte("fullUrl", Pfunc_urlfunc.Tid_full)
|
||||
.Add_str_byte("localUrl", Pfunc_urlfunc.Tid_local)
|
||||
.Add_str_byte("canonicalUrl", Pfunc_urlfunc.Tid_canonical);
|
||||
// private static final byte[] Proto_relative = Bry_.new_a7("relative");
|
||||
// private static final Hash_adp_bry proto_hash = Hash_adp_bry.ci_a7().Add_str_obj("http", Bry_.new_a7("http://")).Add_str_obj("https", Bry_.new_a7("https://")).Add_str_obj("relative", Bry_.new_a7("//")).Add_str_obj("canonical", Bry_.new_a7("1"));
|
||||
private byte[] Parse_ns(Xowe_wiki wiki, Object ns_obj) {
|
||||
if (Type_adp_.Eq_typeSafe(ns_obj, String.class))
|
||||
return Bry_.new_u8(String_.cast(ns_obj));
|
||||
else {
|
||||
int ns_id = Int_.cast(ns_obj);
|
||||
Xow_ns ns = wiki.Ns_mgr().Ids_get_or_null(ns_id);
|
||||
if (ns != null)
|
||||
return ns.Name_db();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean MakeTitle(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
byte[] ns_bry = Parse_ns(wiki, args.Cast_obj_or_null(0));
|
||||
String ttl_str = args.Pull_str(1);
|
||||
String anchor_str = args.Cast_str_or_null(2);
|
||||
String xwiki_str = args.Cast_str_or_null(3);
|
||||
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_k004();
|
||||
if (xwiki_str != null) tmp_bfr.Add_str_u8(xwiki_str).Add_byte(Byte_ascii.Colon);
|
||||
if (Bry_.Len_gt_0(ns_bry)) // only prefix ns if available; EX:"Template:Title"; else will get ":Title"; DATE:2014-10-30
|
||||
tmp_bfr.Add(ns_bry).Add_byte(Byte_ascii.Colon);
|
||||
tmp_bfr.Add_str_u8(ttl_str);
|
||||
if (anchor_str != null) tmp_bfr.Add_byte(Byte_ascii.Hash).Add_str_u8(anchor_str);
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, tmp_bfr.To_bry_and_rls());
|
||||
if (ttl == null) return rslt.Init_obj(null); // invalid title; exit;
|
||||
return rslt.Init_obj(GetInexpensiveTitleData(ttl));
|
||||
}
|
||||
public boolean GetExpensiveData(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(core.Wiki(), ttl_bry);
|
||||
if (ttl == Xoa_ttl.Null) return rslt.Init_null();
|
||||
// TODO_OLD: MW does extra logic here to cache ttl in ttl cache to avoid extra title lookups
|
||||
boolean ttl_exists = false, ttl_redirect = false; int ttl_id = 0;
|
||||
Xowd_page_itm db_page = Xowd_page_itm.new_tmp();
|
||||
ttl_exists = core.Wiki().Db_mgr().Load_mgr().Load_by_ttl(db_page, ttl.Ns(), ttl.Page_db());
|
||||
if (ttl_exists) {
|
||||
ttl_redirect = db_page.Redirected();
|
||||
ttl_id = db_page.Id();
|
||||
}
|
||||
Keyval[] rv = new Keyval[4];
|
||||
rv[ 0] = Keyval_.new_("isRedirect" , ttl_redirect); // title.isRedirect
|
||||
rv[ 1] = Keyval_.new_("id" , ttl_id); // $title->getArticleID(),
|
||||
rv[ 2] = Keyval_.new_("contentModel" , Key_wikitext); // $title->getContentModel(); see Defines.php and CONTENT_MODEL_
|
||||
rv[ 3] = Keyval_.new_("exists" , ttl_exists); // $ret['id'] > 0; TODO_OLD: if Special: check regy of implemented pages
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean GetFileInfo(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
// init; get ttl
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry);
|
||||
if ( ttl == null
|
||||
|| !ttl.Ns().Id_is_file_or_media()
|
||||
) return rslt.Init_obj(GetFileInfo_absent);
|
||||
if (ttl.Ns().Id_is_media()) ttl = Xoa_ttl.Parse(wiki, Xow_ns_.Tid__file, ttl.Page_db()); // if [[Media:]] change to [[File:]]; theoretically, this should be changed in Get_page, but not sure if I want to put this logic that low; DATE:2014-01-07
|
||||
|
||||
// get file info from db / wmf
|
||||
wiki.File_mgr().Init_file_mgr_by_load(wiki);
|
||||
Xof_orig_itm itm = wiki.File__orig_mgr().Find_by_ttl_or_null(ttl.Page_db()); // NOTE: MW registers image if deleted; XOWA doesn't register b/c needs width / height also, not just image name
|
||||
Keyval[] rv = itm == Xof_orig_itm.Null
|
||||
? GetFileInfo_absent
|
||||
: Keyval_.Ary
|
||||
( Keyval_.new_("exists" , true)
|
||||
, Keyval_.new_("width" , itm.W())
|
||||
, Keyval_.new_("height" , itm.H())
|
||||
, Keyval_.new_("pages" , null) // TODO_OLD: get pages info
|
||||
);
|
||||
return rslt.Init_obj(rv);
|
||||
} private static final Keyval[] GetFileInfo_absent = Keyval_.Ary(Keyval_.new_("exists", false), Keyval_.new_("width", 0), Keyval_.new_("height", 0)); // NOTE: must supply non-null values for w / h, else Modules will fail with nil errors; PAGE:pl.w:Andrespol DATE:2016-08-01
|
||||
public boolean GetContent(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry); if (ttl == null) return rslt.Init_obj(null);
|
||||
Xow_page_cache_itm page_itm = wiki.Cache_mgr().Page_cache().Get_or_load_as_itm_2(ttl);
|
||||
byte[] rv = null;
|
||||
if (page_itm != null) {
|
||||
byte[] redirected_src = page_itm.Wtxt__redirect();
|
||||
if (redirected_src != null) { // page is redirect; use its src, not its target's src; DATE:2014-07-11
|
||||
rv = redirected_src;
|
||||
core.Frame_parent().Rslt_is_redirect_(true); // flag frame as redirect, so that \n won't be prepended; EX:"#REDIRECT" x> "\n#REDIRECT"
|
||||
}
|
||||
else
|
||||
rv = page_itm.Wtxt__direct();
|
||||
}
|
||||
return rv == null ? rslt.Init_obj(null) : rslt.Init_obj(String_.new_u8(rv));
|
||||
}
|
||||
public boolean GetCurrentTitle(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(GetInexpensiveTitleData(core.Page().Ttl()));
|
||||
}
|
||||
public boolean ProtectionLevels(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(protectionLevels_dflt);
|
||||
}
|
||||
private static final Keyval[] protectionLevels_dflt = Keyval_.Ary(Keyval_.new_("move", Keyval_.int_(1, "sysop")), Keyval_.new_("edit", Keyval_.int_(1, "sysop"))); // protectionLevels are stored in different table which is currently not mirrored; per en.w:Module:Effective_protection_level; DATE:2014-04-09; 2016-09-07
|
||||
public boolean CascadingProtection(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry); if (ttl == null) return rslt.Init_obj(null);
|
||||
return rslt.Init_obj(CascadingProtection_rv);
|
||||
}
|
||||
public static final Keyval[] CascadingProtection_rv = Keyval_.Ary(Keyval_.new_("sources", Keyval_.Ary_empty), Keyval_.new_("restrictions", Keyval_.Ary_empty)); // changed sources from "false" to "{}"; DATE:2016-09-09
|
||||
private Keyval[] GetInexpensiveTitleData(Xoa_ttl ttl) {
|
||||
Xow_ns ns = ttl.Ns();
|
||||
boolean ns_file_or_media = ns.Id_is_file_or_media(), ns_special = ns.Id_is_special();
|
||||
int rv_len = 7, rv_idx = 7;
|
||||
if (ns_special) ++rv_len;
|
||||
if (!ns_file_or_media) ++rv_len;
|
||||
Xow_xwiki_itm xwiki_itm = ttl.Wik_itm();
|
||||
String xwiki_str = xwiki_itm == null ? "" : xwiki_itm.Key_str();
|
||||
Keyval[] rv = new Keyval[rv_len];
|
||||
rv[ 0] = Keyval_.new_("isLocal" , true); // title.isLocal; NOTE: always true; passing "http:" also returns true; not sure how to handle "Interwiki::fetch( $this->mInterwiki )->isLocal()"
|
||||
rv[ 1] = Keyval_.new_("interwiki" , xwiki_str); // $title->getInterwiki(),
|
||||
rv[ 2] = Keyval_.new_("namespace" , ns.Id()); // $ns,
|
||||
rv[ 3] = Keyval_.new_("nsText" , ns.Name_db()); // $title->getNsText(), NOTE: must be local language's version; Russian "Шаблон" not English "Template"; PAGE:ru.w:Королевство_Нидерландов DATE:2016-11-23
|
||||
rv[ 4] = Keyval_.new_("text" , ttl.Page_txt()); // $title->getText(),
|
||||
rv[ 5] = Keyval_.new_("fragment" , ttl.Anch_txt()); // $title->getFragment(),
|
||||
rv[ 6] = Keyval_.new_("thePartialUrl" , ttl.Page_db()); // $title->getPartialUrl(),
|
||||
if (ns_special)
|
||||
rv[rv_idx++] = Keyval_.new_("exists" , false); // TODO_OLD: lookup specials
|
||||
if (!ns_file_or_media)
|
||||
rv[rv_idx++] = Keyval_.new_("file" , false); // REF.MW: if ( $ns !== NS_FILE && $ns !== NS_MEDIA ) $ret['file'] = false;
|
||||
return rv;
|
||||
}
|
||||
public static final String Key_wikitext = "wikitext";
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_title_tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
gplx.dbs.Db_conn_bldr.Instance.Reg_default_mem();
|
||||
fxt.Clear();
|
||||
fxt.Core().Wiki().File__fsdb_mode().Tid__v2__bld__y_();
|
||||
lib = fxt.Core().Lib_title().Init();
|
||||
}
|
||||
@Test public void NewTitle() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_newTitle, Object_.Ary("Page_0") , ttl_fast(0 , "", "Page 0", "", "", "Page_0"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_newTitle, Object_.Ary("A", "Template") , ttl_fast(10 , "Template", "A"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_newTitle, Object_.Ary("a[b") , Scrib_invoke_func_fxt.Null_rslt_ary); // invalid
|
||||
}
|
||||
@Test public void NewTitle_int() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_newTitle, Object_.Ary(1234) , ttl_fast(0 , "", "1234", "", "", "1234"));
|
||||
}
|
||||
@Test public void NewTitle__foreign() {// PURPOSE: must be local language's version; Russian "Шаблон" not English "Template"; PAGE:ru.w:Королевство_Нидерландов DATE:2016-11-23
|
||||
fxt.Core().Wiki().Ns_mgr().Ns_template().Name_bry_(Bry_.new_a7("Template_in_nonenglish_name"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_newTitle, Object_.Ary("A", "Template") , ttl_fast(10 , "Template_in_nonenglish_name", "A")); // "Template_in_nonenglish_name" not "Template"
|
||||
}
|
||||
@Test public void GetUrl() {
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "fullUrl") , "//en.wikipedia.org/wiki/Main_Page");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "fullUrl", "action=edit") , "//en.wikipedia.org/wiki/Main_Page?action=edit");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "localUrl") , "/wiki/Main_Page");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "canonicalUrl") , "https://en.wikipedia.org/wiki/Main_Page");
|
||||
// fxt.Test_scrib_proc_str(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "fullUrl", "", "http") , "http://en.wikipedia.org/wiki/Main_Page"); // TODO_OLD
|
||||
}
|
||||
@Test public void GetUrl__args_many() { // PUPROSE: GetUrl sometimes passes in kvs for qry_args; fr.w:Wikipédia:Image_du_jour/Date; DATE:2013-12-24
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getUrl, Object_.Ary("Main_Page", "canonicalUrl", Keyval_.Ary(Keyval_.new_("action", "edit"), Keyval_.new_("preload", "b"))), "https://en.wikipedia.org/wiki/Main_Page?action=edit&preload=b");
|
||||
}
|
||||
@Test public void MakeTitle() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_makeTitle, Object_.Ary("Module", "A") , ttl_fast(828, "Module", "A"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_makeTitle, Object_.Ary(828, "A") , ttl_fast(828, "Module", "A"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_makeTitle, Object_.Ary("Template", "A", "b") , ttl_fast(10, "Template", "A", "b"));
|
||||
fxt.Parser_fxt().Wiki().Xwiki_mgr().Add_by_atrs("fr", "fr.wikipedia.org");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_makeTitle, Object_.Ary("Template", "A", "b", "fr") , ttl_fast(0, "", "Template:A", "b", "fr"));
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_makeTitle, Object_.Ary("Template", "a[b"), Scrib_invoke_func_fxt.Null_rslt_ary); // PURPOSE: handle bad MakeTitle cmds; PAGE:en.w:Disney; DATE:2013-10-15
|
||||
}
|
||||
@Test public void GetExpensiveData_absent() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getExpensiveData, Object_.Ary("A") , ttl_slow(Bool_.N, 0, Bool_.N));
|
||||
}
|
||||
@Test public void GetExpensiveData_exists() {
|
||||
fxt.Parser_fxt().Init_page_create("A");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getExpensiveData, Object_.Ary("A") , ttl_slow(Bool_.Y, 0, Bool_.N));
|
||||
}
|
||||
@Test public void GetFileInfo() {
|
||||
Wiki_orig_tbl__create(fxt.Core().Wiki());
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("A") , file_info_absent());
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("Template:A") , file_info_absent());
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("File:A.png") , file_info_absent());
|
||||
fxt.Parser_fxt().Init_page_create("File:A.png");
|
||||
Wiki_orig_tbl__insert(fxt.Core().Wiki(), "A.png", 220, 200);
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("File:A.png") , file_info_exists("A.png", 220, 200));
|
||||
}
|
||||
@Test public void GetFileInfo_commons() { // PURPOSE: check that Scribunto GetFileInfo calls filepath.FileExists; DATE:2014-01-07
|
||||
Xowe_wiki commons_wiki = fxt.Parser_fxt().Wiki().Appe().Wiki_mgr().Get_by_or_make(gplx.xowa.wikis.domains.Xow_domain_itm_.Bry__commons).Init_assert();
|
||||
Wiki_orig_tbl__create(fxt.Core().Wiki());
|
||||
Wiki_orig_tbl__insert(fxt.Core().Wiki(), "A.png", 220, 200);
|
||||
fxt.Parser_fxt().Init_page_create(commons_wiki, "File:A.png", "text_is_blank");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("File:A.png") , file_info_exists("A.png", 220, 200));
|
||||
}
|
||||
@Test public void GetFileInfo_media() { // PURPOSE: [[Media:]] ns should find entries in [[File:]]; DATE:2014-01-07
|
||||
Wiki_orig_tbl__create(fxt.Core().Wiki());
|
||||
Wiki_orig_tbl__insert(fxt.Core().Wiki(), "A.png", 220, 200);
|
||||
fxt.Parser_fxt().Init_page_create("File:A.png");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_getFileInfo, Object_.Ary("Media:A.png") , file_info_exists("A.png", 220, 200));
|
||||
}
|
||||
@Test public void GetContent() {
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getContent, Object_.Ary("A") , Scrib_invoke_func_fxt.Null_rslt);
|
||||
|
||||
fxt.Parser_fxt().Ctx().Wiki().Cache_mgr().Page_cache().Free_mem(true);
|
||||
fxt.Parser_fxt().Init_page_create("A", "test");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getContent, Object_.Ary("A") , "test");
|
||||
}
|
||||
@Test public void GetContent_redirect() {// PURPOSE: GetContent should return source text for redirect, not target; PAGE:de.w:Wikipedia:Autorenportal DATE:2014-07-11
|
||||
fxt.Parser_fxt().Init_page_create("A", "#REDIRECT [[B]]");
|
||||
fxt.Parser_fxt().Init_page_create("B", "C");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getContent, Object_.Ary("A") , "#REDIRECT [[B]]"); // should not be "C"
|
||||
}
|
||||
@Test public void GetContent__redirect_missing() {// PURPOSE: // page redirects to missing page; note that page.Missing == true and page.Redirected_src() != null; PAGE: en.w:Shah_Rukh_Khan; DATE:2016-05-02
|
||||
fxt.Parser_fxt().Init_page_create("A", "#REDIRECT [[B]]");
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_title.Invk_getContent, Object_.Ary("A") , "#REDIRECT [[B]]"); // fails with null
|
||||
}
|
||||
@Test public void ProtectionLevels() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_protectionLevels, Object_.Ary("A") , String_.Concat_lines_nl_skip_last("1=", " move=1=sysop", " edit=1=sysop"));
|
||||
}
|
||||
@Test public void CascadingProtection() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_title.Invk_cascadingProtection, Object_.Ary("A") , Scrib_lib_title.CascadingProtection_rv);
|
||||
}
|
||||
private static void Wiki_orig_tbl__create(Xowe_wiki wiki) {
|
||||
Xowe_wiki_.Create(wiki, 1, "dump.xml");
|
||||
gplx.xowa.wikis.data.Xow_db_file text_db = wiki.Data__core_mgr().Dbs__make_by_tid(gplx.xowa.wikis.data.Xow_db_file_.Tid__text); text_db.Tbl__text().Create_tbl();
|
||||
gplx.fsdb.Fsdb_db_mgr__v2_bldr.Get_or_make(wiki, Bool_.Y);
|
||||
wiki.File_mgr().Init_file_mgr_by_load(wiki);
|
||||
}
|
||||
private static void Wiki_orig_tbl__insert(Xowe_wiki wiki, String ttl_str, int w, int h) {
|
||||
byte[] ttl_bry = Bry_.new_u8(ttl_str);
|
||||
wiki.File__orig_mgr().Insert(gplx.xowa.files.repos.Xof_repo_tid_.Tid__remote, ttl_bry, gplx.xowa.files.Xof_ext_.new_by_ttl_(ttl_bry).Id(), w, h, Bry_.Empty);
|
||||
}
|
||||
private static String ttl_fast(int ns_id, String ns_str, String ttl) {return ttl_fast(ns_id, ns_str, ttl, "", "", ttl);}
|
||||
private static String ttl_fast(int ns_id, String ns_str, String ttl, String anchor) {return ttl_fast(ns_id, ns_str, ttl, anchor, "", ttl);}
|
||||
private static String ttl_fast(int ns_id, String ns_str, String ttl, String anchor, String xwiki) {return ttl_fast(ns_id, ns_str, ttl, anchor, xwiki, ttl);}
|
||||
private static String ttl_fast(int ns_id, String ns_str, String ttl, String anchor, String xwiki, String partial_url) {
|
||||
return String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " isLocal=true"
|
||||
, " interwiki=" + xwiki
|
||||
, " namespace=" + Int_.To_str(ns_id)
|
||||
, " nsText=" + ns_str
|
||||
, " text=" + ttl
|
||||
, " fragment=" + anchor
|
||||
, " thePartialUrl=" + partial_url
|
||||
, " file=false"
|
||||
);
|
||||
}
|
||||
private static String ttl_slow(boolean exists, int ttl_id, boolean redirect) {
|
||||
return String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " isRedirect=" + Bool_.To_str_lower(redirect)
|
||||
, " id=" + Int_.To_str(ttl_id)
|
||||
, " contentModel=" + Scrib_lib_title.Key_wikitext
|
||||
, " exists=" + Bool_.To_str_lower(exists)
|
||||
);
|
||||
}
|
||||
private static String file_info_absent() {
|
||||
return String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " exists=false"
|
||||
, " width=0"
|
||||
, " height=0"
|
||||
);
|
||||
}
|
||||
private static String file_info_exists(String ttl, int w, int h) {
|
||||
return String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " exists=true"
|
||||
, " width=" + Int_.To_str(w)
|
||||
, " height=" + Int_.To_str(h)
|
||||
, " pages=<<NULL>>"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.pfuncs.ttls.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_uri implements Scrib_lib {
|
||||
public Scrib_lib_uri(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_uri(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.uri.lua")); // NOTE: defaultUrl handled by Init_lib_url
|
||||
notify_page_changed_fnc = mod.Fncs_get_by_key("notify_page_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_page_changed_fnc;
|
||||
public void Notify_page_changed() {if (notify_page_changed_fnc != null) core.Interpreter().CallFunction(notify_page_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_anchorEncode: return AnchorEncode(args, rslt);
|
||||
case Proc_localUrl: return Url_func(args, rslt, Pfunc_urlfunc.Tid_local);
|
||||
case Proc_fullUrl: return Url_func(args, rslt, Pfunc_urlfunc.Tid_full);
|
||||
case Proc_canonicalUrl: return Url_func(args, rslt, Pfunc_urlfunc.Tid_canonical);
|
||||
case Proc_init_uri_for_page: return Init_uri_for_page(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_anchorEncode = 0, Proc_localUrl = 1, Proc_fullUrl = 2, Proc_canonicalUrl = 3, Proc_init_uri_for_page = 4;
|
||||
public static final String Invk_anchorEncode = "anchorEncode", Invk_localUrl = "localUrl", Invk_fullUrl = "fullUrl", Invk_canonicalUrl = "canonicalUrl", Invk_init_uri_for_page = "init_uri_for_page";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_anchorEncode, Invk_localUrl, Invk_fullUrl, Invk_canonicalUrl, Invk_init_uri_for_page);
|
||||
public boolean AnchorEncode(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] raw_bry = args.Pull_bry(0);
|
||||
Bry_bfr bfr = core.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
// Pfunc_anchorencode.Func_init(core.Ctx());
|
||||
Pfunc_anchorencode.Anchor_encode(bfr, core.Ctx(), raw_bry);
|
||||
// Bry_bfr tmp_bfr = core.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
// tmp_bfr.Clear_and_rls();
|
||||
return rslt.Init_obj(bfr.To_str_and_rls());
|
||||
}
|
||||
public boolean Url_func(Scrib_proc_args args, Scrib_proc_rslt rslt, byte url_tid) {
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
byte[] qry_bry = args.Extract_qry_args(wiki, 1);
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry);
|
||||
if (ttl == null) return rslt.Init_null();
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
if (ttl.Ns().Id() == Xow_ns_.Tid__media) { // change "Media:" -> "File:"
|
||||
bfr.Add(wiki.Ns_mgr().Ns_file().Name_db_w_colon());
|
||||
bfr.Add(ttl.Page_db());
|
||||
ttl_bry = bfr.To_bry_and_clear();
|
||||
}
|
||||
Pfunc_urlfunc.UrlString(core.Ctx(), url_tid, false, ttl_bry, bfr, qry_bry);
|
||||
return rslt.Init_obj(bfr.To_str_and_rls());
|
||||
}
|
||||
private boolean Init_uri_for_page(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xop_ctx ctx = core.Ctx();
|
||||
byte[] ttl_bry = ctx.Page().Ttl().Raw();
|
||||
Bry_bfr tmp_bfr = ctx.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
Pfunc_urlfunc.UrlString(ctx, Pfunc_urlfunc.Tid_full, false, ttl_bry, tmp_bfr, Bry_.Empty);
|
||||
return rslt.Init_obj(tmp_bfr.To_bry_and_rls());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_lib_uri_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_uri().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Test public void Url() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_localUrl , Object_.Ary("a&b! c" ), "/wiki/A%26b!_c");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_fullUrl , Object_.Ary("a&b! c" ), "//en.wikipedia.org/wiki/A%26b!_c");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_canonicalUrl , Object_.Ary("a&b! c" ), "https://en.wikipedia.org/wiki/A%26b!_c");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_localUrl , Object_.Ary("a&b! c" , "action=edit" ), "/wiki/A%26b!_c?action=edit");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_localUrl , Object_.Ary("Media:A.png" ), "/wiki/File:A.png");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_localUrl , Object_.Ary("[bad]" ), Scrib_invoke_func_fxt.Null_rslt); // handle invalid titles; EX:it.w:Billy_the_Kid; DATE:2014-01-20
|
||||
}
|
||||
@Test public void Url__args_many() { // PUPROSE: GetUrl sometimes passes in kvs for qry_args; it.w:Astronomie; DATE:2014-01-18
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_fullUrl, Object_.Ary("A", Keyval_.Ary(Keyval_.new_("action", "edit"))), "//en.wikipedia.org/wiki/A?action=edit");
|
||||
}
|
||||
@Test public void AnchorEncode() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_anchorEncode , Object_.Ary("[irc://a b c]" ), "b_c");
|
||||
}
|
||||
@Test public void Init_uri_for_page() {
|
||||
fxt.Parser_fxt().Page_ttl_("Page_1");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_uri.Invk_init_uri_for_page , Object_.Ary_empty , "//en.wikipedia.org/wiki/Page_1");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.langs.regxs.*; import gplx.core.intls.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_ustring implements Scrib_lib {
|
||||
private final String_surrogate_utl surrogate_utl = new String_surrogate_utl();
|
||||
public Scrib_lib_ustring(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public int String_len_max() {return string_len_max;} public Scrib_lib_ustring String_len_max_(int v) {string_len_max = v; return this;} private int string_len_max = Xoa_page_.Page_len_max;
|
||||
public int Pattern_len_max() {return pattern_len_max;} public Scrib_lib_ustring Pattern_len_max_(int v) {pattern_len_max = v; return this;} private int pattern_len_max = 10000;
|
||||
private Scrib_regx_converter regx_converter = new Scrib_regx_converter();
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_ustring(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.ustring.lua")
|
||||
, Keyval_.new_("stringLengthLimit", string_len_max)
|
||||
, Keyval_.new_("patternLengthLimit", pattern_len_max)
|
||||
);
|
||||
return mod;
|
||||
}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_find: return Find(args, rslt);
|
||||
case Proc_match: return Match(args, rslt);
|
||||
case Proc_gmatch_init: return Gmatch_init(args, rslt);
|
||||
case Proc_gmatch_callback: return Gmatch_callback(args, rslt);
|
||||
case Proc_gsub: return Gsub(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_find = 0, Proc_match = 1, Proc_gmatch_init = 2, Proc_gmatch_callback = 3, Proc_gsub = 4;
|
||||
public static final String Invk_find = "find", Invk_match = "match", Invk_gmatch_init = "gmatch_init", Invk_gmatch_callback = "gmatch_callback", Invk_gsub = "gsub";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_find, Invk_match, Invk_gmatch_init, Invk_gmatch_callback, Invk_gsub);
|
||||
public boolean Find(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String text_str = args.Xstr_str_or_null(0);
|
||||
String regx = args.Pull_str(1);
|
||||
int bgn_char_idx = args.Cast_int_or(2, 1);
|
||||
boolean plain = args.Cast_bool_or_n(3);
|
||||
synchronized (surrogate_utl) {
|
||||
byte[] text_bry = Bry_.new_u8(text_str); int text_bry_len = text_bry.length;
|
||||
bgn_char_idx = Bgn_adjust(text_str, bgn_char_idx);
|
||||
int bgn_adj = surrogate_utl.Count_surrogates__char_idx(text_bry, text_bry_len, 0, bgn_char_idx); // NOTE: convert from lua / php charidx to java regex codepoint; PAGE:zh.w:南北鐵路 (越南) DATE:2014-08-27
|
||||
int bgn_codepoint_idx = bgn_char_idx + bgn_adj;
|
||||
int bgn_byte_pos = surrogate_utl.Byte_pos();
|
||||
if (String_.Len_eq_0(regx)) // regx of "" should return (bgn, bgn - 1) regardless of whether plain is true or false
|
||||
return rslt.Init_many_objs(bgn_codepoint_idx + Scrib_lib_ustring.Base1, bgn_codepoint_idx + Scrib_lib_ustring.Base1 - 1);
|
||||
if (plain) {
|
||||
int pos = String_.FindFwd(text_str, regx, bgn_codepoint_idx);
|
||||
boolean found = pos != Bry_find_.Not_found;
|
||||
return found
|
||||
? rslt.Init_many_objs(pos + Scrib_lib_ustring.Base1, pos + Scrib_lib_ustring.Base1 + String_.Len(regx) - Scrib_lib_ustring.End_adj)
|
||||
: rslt.Init_ary_empty()
|
||||
;
|
||||
}
|
||||
regx = regx_converter.Parse(Bry_.new_u8(regx), Scrib_regx_converter.Anchor_G);
|
||||
Regx_adp regx_adp = Scrib_lib_ustring.RegxAdp_new_(core.Ctx(), regx);
|
||||
Regx_match[] regx_rslts = regx_adp.Match_all(text_str, bgn_codepoint_idx); // NOTE: MW calculates an offset to handle mb strings. however, java's regex always takes offset in chars (not bytes like PHP preg_match); DATE:2014-03-04
|
||||
int len = regx_rslts.length;
|
||||
if (len == 0) return rslt.Init_ary_empty();
|
||||
List_adp tmp_list = List_adp_.New();
|
||||
Regx_match match = regx_rslts[0]; // NOTE: take only 1st result; DATE:2014-08-27
|
||||
int match_find_bgn_codepoint = match.Find_bgn(); // NOTE: java regex returns results in codepoint; PAGE:zh.w:南北鐵路 (越南) DATE:2014-08-27
|
||||
int match_find_bgn_adj = -surrogate_utl.Count_surrogates__codepoint_idx1(text_bry, text_bry_len, bgn_byte_pos, match_find_bgn_codepoint - bgn_codepoint_idx); // NOTE: convert from java regex codepoint to lua / php char_idx; PAGE:zh.w:南北鐵路 (越南) DATE:2014-08-27
|
||||
tmp_list.Add(match_find_bgn_codepoint + match_find_bgn_adj + -bgn_adj + Scrib_lib_ustring.Base1);
|
||||
tmp_list.Add(match.Find_end() + match_find_bgn_adj + -bgn_adj + Scrib_lib_ustring.Base1 - Scrib_lib_ustring.End_adj);
|
||||
//Tfds.Dbg (match_find_bgn_codepoint + match_find_bgn_adj + -bgn_adj + Scrib_lib_ustring.Base1
|
||||
// ,match.Find_end() + match_find_bgn_adj + -bgn_adj + Scrib_lib_ustring.Base1 - Scrib_lib_ustring.End_adj);
|
||||
AddCapturesFromMatch(tmp_list, match, text_str, regx_converter.Capt_ary(), false);
|
||||
return rslt.Init_many_list(tmp_list);
|
||||
}
|
||||
}
|
||||
private int Bgn_adjust(String text, int bgn) { // adjust to handle bgn < 0 or bgn > len (which PHP allows)
|
||||
if (bgn > 0) bgn -= Scrib_lib_ustring.Base1;
|
||||
int text_len = String_.Len(text);
|
||||
if (bgn < 0) // negative number means search from rear of String
|
||||
bgn += text_len; // NOTE: PHP has extra + 1 for Base 1
|
||||
else if (bgn > text_len) // bgn > text_len; confine to text_len; NOTE: PHP has extra + 1 for Base 1
|
||||
bgn = text_len; // NOTE: PHP has extra + 1 for Base 1
|
||||
return bgn;
|
||||
}
|
||||
public boolean Match(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String text = args.Xstr_str_or_null(0); // Module can pass raw ints; PAGE:en.w:Budget_of_the_European_Union; DATE:2015-01-22
|
||||
if (text == null) return rslt.Init_many_list(List_adp_.Noop); // if no text is passed, do not fail; return empty; EX:d:changed; DATE:2014-02-06
|
||||
String regx = regx_converter.Parse(args.Cast_bry_or_null(1), Scrib_regx_converter.Anchor_G);
|
||||
int bgn = args.Cast_int_or(2, 1);
|
||||
bgn = Bgn_adjust(text, bgn);
|
||||
Regx_adp regx_adp = Scrib_lib_ustring.RegxAdp_new_(core.Ctx(), regx);
|
||||
Regx_match[] regx_rslts = regx_adp.Match_all(text, bgn);
|
||||
int len = regx_rslts.length;
|
||||
if (len == 0) return rslt.Init_null(); // return null if no matches found; EX:w:Mount_Gambier_(volcano); DATE:2014-04-02; confirmed with en.d:民; DATE:2015-01-30
|
||||
List_adp tmp_list = List_adp_.New();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Regx_match match = regx_rslts[i];
|
||||
AddCapturesFromMatch(tmp_list, match, text, regx_converter.Capt_ary(), true);
|
||||
}
|
||||
return rslt.Init_many_list(tmp_list);
|
||||
}
|
||||
private Scrib_lib_ustring_gsub_mgr[] gsub_mgr_ary = Scrib_lib_ustring_gsub_mgr.Ary_empty;
|
||||
private int gsub_mgr_max = 0, gsub_mgr_len = -1;
|
||||
private final Object gsub_mgr_lock = new Object();
|
||||
public boolean Gsub(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
boolean rv = false;
|
||||
synchronized (gsub_mgr_lock) { // handle recursive gsub calls; PAGE:en.d:כלב; DATE:2016-01-22
|
||||
int new_len = gsub_mgr_len + 1;
|
||||
if (new_len == gsub_mgr_max) {
|
||||
this.gsub_mgr_max = new_len == 0 ? 2 : new_len * 2;
|
||||
Scrib_lib_ustring_gsub_mgr[] new_gsub_mgr_ary = new Scrib_lib_ustring_gsub_mgr[gsub_mgr_max];
|
||||
Array_.Copy(gsub_mgr_ary, new_gsub_mgr_ary);
|
||||
gsub_mgr_ary = new_gsub_mgr_ary;
|
||||
}
|
||||
Scrib_lib_ustring_gsub_mgr cur = gsub_mgr_ary[new_len];
|
||||
if (cur == null) {
|
||||
cur = new Scrib_lib_ustring_gsub_mgr(core, regx_converter);
|
||||
gsub_mgr_ary[new_len] = cur;
|
||||
}
|
||||
this.gsub_mgr_len = new_len;
|
||||
rv = cur.Exec(args, rslt);
|
||||
--gsub_mgr_len;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public boolean Gmatch_init(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
// String text = Scrib_kv_utl_.Val_to_str(values, 0);
|
||||
byte[] regx = args.Pull_bry(1);
|
||||
String pcre = regx_converter.Parse(regx, Scrib_regx_converter.Anchor_null);
|
||||
return rslt.Init_many_objs(pcre, regx_converter.Capt_ary());
|
||||
}
|
||||
public boolean Gmatch_callback(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String text = args.Xstr_str_or_null(0); // NOTE: UstringLibrary.php!ustringGmatchCallback calls preg_match directly; $s can be any type, and php casts automatically;
|
||||
String regx = args.Pull_str(1);
|
||||
Keyval[] capt = args.Cast_kv_ary_or_null(2);
|
||||
int pos = args.Pull_int(3);
|
||||
Regx_adp regx_adp = Scrib_lib_ustring.RegxAdp_new_(core.Ctx(), regx);
|
||||
Regx_match[] regx_rslts = regx_adp.Match_all(text, pos);
|
||||
int len = regx_rslts.length;
|
||||
if (len == 0) return rslt.Init_many_objs(pos, Keyval_.Ary_empty);
|
||||
Regx_match match = regx_rslts[0]; // NOTE: take only 1st result
|
||||
List_adp tmp_list = List_adp_.New();
|
||||
AddCapturesFromMatch(tmp_list, match, text, capt, true); // NOTE: was incorrectly set as false; DATE:2014-04-23
|
||||
return rslt.Init_many_objs(match.Find_end(), Scrib_kv_utl_.base1_list_(tmp_list));
|
||||
}
|
||||
private void AddCapturesFromMatch(List_adp tmp_list, Regx_match rslt, String text, Keyval[] capts, boolean op_is_match) {// NOTE: this matches behavior in UstringLibrary.php!addCapturesFromMatch
|
||||
Regx_group[] grps = rslt.Groups();
|
||||
int grps_len = grps.length;
|
||||
int capts_len = capts == null ? 0 : capts.length;
|
||||
if (grps_len > 0) {
|
||||
for (int j = 0; j < grps_len; j++) {
|
||||
Regx_group grp = grps[j];
|
||||
if ( j < capts_len // bounds check b/c null can be passed
|
||||
&& Bool_.Cast(capts[j].Val()) // check if true; indicates that group is "()" or "anypos" see regex converter; DATE:2014-04-23
|
||||
)
|
||||
tmp_list.Add(grp.Bgn() + Scrib_lib_ustring.Base1); // return index only for "()"; NOTE: do not return as String; callers expect int and will fail typed comparisons; DATE:2016-01-21
|
||||
else
|
||||
tmp_list.Add(grp.Val()); // return match
|
||||
}
|
||||
}
|
||||
else if ( op_is_match // if op_is_match, and no captures, extract find_txt; note that UstringLibrary.php says "$arr[] = $m[0][0];" which means get the 1st match;
|
||||
&& tmp_list.Count() == 0) // only add match once; EX: "aaaa", "a" will have four matches; get 1st; DATE:2014-04-02
|
||||
tmp_list.Add(String_.Mid(text, rslt.Find_bgn(), rslt.Find_end()));
|
||||
}
|
||||
public static Regx_adp RegxAdp_new_(Xop_ctx ctx, String regx) {
|
||||
Regx_adp rv = Regx_adp_.new_(regx);
|
||||
if (rv.Pattern_is_invalid()) {
|
||||
ctx.App().Usr_dlg().Warn_many("", "", "regx is invalid: regx=~{0} page=~{1}", regx, String_.new_u8(ctx.Page().Ttl().Page_db()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static final int Base1 = 1
|
||||
, End_adj = 1; // lua / php uses "end" as <= not <; EX: "abc" and bgn=0, end= 1; for XOWA, this is "a"; for MW / PHP it is "ab"
|
||||
}
|
||||
class Scrib_lib_ustring_gsub_mgr {
|
||||
private Scrib_regx_converter regx_converter;
|
||||
public Scrib_lib_ustring_gsub_mgr(Scrib_core core, Scrib_regx_converter regx_converter) {this.core = core; this.regx_converter = regx_converter;} private Scrib_core core;
|
||||
private byte tmp_repl_tid = Repl_tid_null; private byte[] tmp_repl_bry = null;
|
||||
private Hash_adp repl_hash = null; private Scrib_lua_proc repl_func = null;
|
||||
private int repl_count = 0;
|
||||
public boolean Exec(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Object text_obj = args.Cast_obj_or_null(0);
|
||||
String text = String_.as_(text_obj);
|
||||
if (text == null) text = Object_.Xto_str_strict_or_empty(text_obj);
|
||||
String regx = args.Xstr_str_or_null(1); // NOTE: @pattern sometimes int; PAGE:en.d:λύω; DATE:2014-09-02
|
||||
if (args.Len() == 2) return rslt.Init_obj(text); // if no replace arg, return self; PAGE:en.d:'orse; DATE:2013-10-13
|
||||
Object repl_obj = args.Cast_obj_or_null(2);
|
||||
regx = regx_converter.Parse(Bry_.new_u8(regx), Scrib_regx_converter.Anchor_pow);
|
||||
int limit = args.Cast_int_or(3, -1);
|
||||
repl_count = 0;
|
||||
Identify_repl(repl_obj);
|
||||
String repl = Exec_repl(tmp_repl_tid, tmp_repl_bry, text, regx, limit);
|
||||
return rslt.Init_many_objs(repl, repl_count);
|
||||
}
|
||||
private void Identify_repl(Object repl_obj) {
|
||||
Class<?> repl_type = repl_obj.getClass();
|
||||
if (Object_.Eq(repl_type, String_.Cls_ref_type)) {
|
||||
tmp_repl_tid = Repl_tid_string;
|
||||
tmp_repl_bry = Bry_.new_u8((String)repl_obj);
|
||||
}
|
||||
else if (Object_.Eq(repl_type, Int_.Cls_ref_type)) { // NOTE:@replace sometimes int; PAGE:en.d:λύω; DATE:2014-09-02
|
||||
tmp_repl_tid = Repl_tid_string;
|
||||
tmp_repl_bry = Bry_.new_u8(Int_.To_str(Int_.cast(repl_obj)));
|
||||
}
|
||||
else if (Object_.Eq(repl_type, Keyval[].class)) {
|
||||
tmp_repl_tid = Repl_tid_table;
|
||||
Keyval[] repl_tbl = (Keyval[])repl_obj;
|
||||
if (repl_hash == null)
|
||||
repl_hash = Hash_adp_.New();
|
||||
else
|
||||
repl_hash.Clear();
|
||||
int repl_tbl_len = repl_tbl.length;
|
||||
for (int i = 0; i < repl_tbl_len; i++) {
|
||||
Keyval repl_itm = repl_tbl[i];
|
||||
String repl_itm_val = repl_itm.Val_to_str_or_empty();
|
||||
repl_hash.Add(repl_itm.Key(), Bry_.new_u8(repl_itm_val));
|
||||
}
|
||||
}
|
||||
else if (Object_.Eq(repl_type, Scrib_lua_proc.class)) {
|
||||
tmp_repl_tid = Repl_tid_luacbk;
|
||||
repl_func = (Scrib_lua_proc)repl_obj;
|
||||
}
|
||||
else if (Object_.Eq(repl_type, Double_.Cls_ref_type)) { // NOTE:@replace sometimes double; PAGE:de.v:Wikivoyage:Wikidata/Test_Modul:Wikidata2; DATE:2016-04-21
|
||||
tmp_repl_tid = Repl_tid_string;
|
||||
tmp_repl_bry = Bry_.new_u8(Double_.To_str(Double_.cast(repl_obj)));
|
||||
}
|
||||
else throw Err_.new_unhandled(Type_adp_.NameOf_type(repl_type));
|
||||
}
|
||||
private String Exec_repl(byte repl_tid, byte[] repl_bry, String text, String regx, int limit) {
|
||||
Regx_adp regx_mgr = Scrib_lib_ustring.RegxAdp_new_(core.Ctx(), regx);
|
||||
Regx_match[] rslts = regx_mgr.Match_all(text, 0);
|
||||
if ( rslts.length == 0 // PHP: If matches are found, the new subject will be returned, otherwise subject will be returned unchanged.; http://php.net/manual/en/function.preg-replace-callback.php
|
||||
|| regx_mgr.Pattern_is_invalid() // NOTE: invalid patterns should return self; EX:[^]; DATE:2014-09-02
|
||||
) return text;
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.New();
|
||||
int len = rslts.length;
|
||||
int pos = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (limit > -1 && repl_count == limit) break;
|
||||
Regx_match rslt = rslts[i];
|
||||
tmp_bfr.Add_str_u8(String_.Mid(text, pos, rslt.Find_bgn())); // NOTE: regx returns char pos (not bry); must add as String, not bry; DATE:2013-07-17
|
||||
Exec_repl_itm(tmp_bfr, repl_tid, repl_bry, text, rslt);
|
||||
pos = rslt.Find_end();
|
||||
++repl_count;
|
||||
}
|
||||
int text_len = String_.Len(text);
|
||||
if (pos < text_len)
|
||||
tmp_bfr.Add_str_u8(String_.Mid(text, pos, text_len)); // NOTE: regx returns char pos (not bry); must add as String, not bry; DATE:2013-07-17
|
||||
return tmp_bfr.To_str_and_clear();
|
||||
}
|
||||
private void Exec_repl_itm(Bry_bfr tmp_bfr, byte repl_tid, byte[] repl_bry, String text, Regx_match match) {
|
||||
switch (repl_tid) {
|
||||
case Repl_tid_string:
|
||||
int len = repl_bry.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte b = repl_bry[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Percent: {
|
||||
++i;
|
||||
if (i == len) // % at end of stream; just add %;
|
||||
tmp_bfr.Add_byte(b);
|
||||
else {
|
||||
b = repl_bry[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
int idx = b - Byte_ascii.Num_0;
|
||||
if (idx == 0) // NOTE: 0 means take result; REF.MW:if ($x === '0'); return $m[0]; PAGE:Wikipedia:Wikipedia_Signpost/Templates/Voter/testcases; DATE:2015-08-02
|
||||
tmp_bfr.Add_str_u8(String_.Mid(text, match.Find_bgn(), match.Find_end()));
|
||||
else { // NOTE: > 0 means get from groups if it exists; REF.MW:elseif (isset($m["m$x"])) return $m["m$x"]; PAGE:Wikipedia:Wikipedia_Signpost/Templates/Voter/testcases; DATE:2015-08-02
|
||||
idx -= List_adp_.Base1;
|
||||
if (idx < match.Groups().length) { // retrieve numbered capture; TODO_OLD: support more than 9 captures
|
||||
Regx_group grp = match.Groups()[idx];
|
||||
tmp_bfr.Add_str_u8(String_.Mid(text, grp.Bgn(), grp.End())); // NOTE: grp.Bgn() / .End() is for String pos (bry pos will fail for utf8 strings)
|
||||
}
|
||||
else {
|
||||
tmp_bfr.Add_byte(Byte_ascii.Percent);
|
||||
tmp_bfr.Add_byte(b);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Byte_ascii.Percent:
|
||||
tmp_bfr.Add_byte(Byte_ascii.Percent);
|
||||
break;
|
||||
default: // not a number; add literal
|
||||
tmp_bfr.Add_byte(Byte_ascii.Percent);
|
||||
tmp_bfr.Add_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tmp_bfr.Add_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Repl_tid_table: {
|
||||
int match_bgn = -1, match_end = -1;
|
||||
Regx_group[] grps = match.Groups();
|
||||
if (grps.length == 0) {
|
||||
match_bgn = match.Find_bgn();
|
||||
match_end = match.Find_end();
|
||||
}
|
||||
else { // group exists, take first one (logic matches Scribunto); PAGE:en.w:Bannered_routes_of_U.S._Route_60; DATE:2014-08-15
|
||||
Regx_group grp = grps[0];
|
||||
match_bgn = grp.Bgn();
|
||||
match_end = grp.End();
|
||||
}
|
||||
String find_str = String_.Mid(text, match_bgn, match_end); // NOTE: rslt.Bgn() / .End() is for String pos (bry pos will fail for utf8 strings)
|
||||
Object actl_repl_obj = repl_hash.Get_by(find_str);
|
||||
if (actl_repl_obj == null) // match found, but no replacement specified; EX:"abc", "[ab]", "a:A"; "b" in regex but not in tbl; EX:d:DVD; DATE:2014-03-31
|
||||
tmp_bfr.Add_str_u8(find_str);
|
||||
else
|
||||
tmp_bfr.Add((byte[])actl_repl_obj);
|
||||
break;
|
||||
}
|
||||
case Repl_tid_luacbk: {
|
||||
Keyval[] luacbk_args = null;
|
||||
Regx_group[] grps = match.Groups();
|
||||
int grps_len = grps.length;
|
||||
if (grps_len == 0) { // no match; use original String
|
||||
String find_str = String_.Mid(text, match.Find_bgn(), match.Find_end());
|
||||
luacbk_args = Scrib_kv_utl_.base1_obj_(find_str);
|
||||
}
|
||||
else { // match; build ary of matches; (see UStringLibrary.php)
|
||||
luacbk_args = new Keyval[grps_len];
|
||||
for (int i = 0; i < grps_len; i++) {
|
||||
Regx_group grp = grps[i];
|
||||
String find_str = String_.Mid(text, grp.Bgn(), grp.End());
|
||||
luacbk_args[i] = Keyval_.int_(i + Scrib_core.Base_1, find_str);
|
||||
}
|
||||
}
|
||||
Keyval[] rslts = core.Interpreter().CallFunction(repl_func.Id(), luacbk_args);
|
||||
if (rslts.length > 0) { // ArrayIndex check
|
||||
Object rslt_obj = rslts[0].Val(); // 0th idx has result
|
||||
tmp_bfr.Add_str_u8(Object_.Xto_str_strict_or_empty(rslt_obj)); // NOTE: always convert to String; rslt_obj can be int; PAGE:en.d:seven DATE:2016-04-27
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: throw Err_.new_unhandled(repl_tid);
|
||||
}
|
||||
}
|
||||
private static final byte Repl_tid_null = 0, Repl_tid_string = 1, Repl_tid_table = 2, Repl_tid_luacbk = 3;
|
||||
public static final Scrib_lib_ustring_gsub_mgr[] Ary_empty = new Scrib_lib_ustring_gsub_mgr[0];
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_ustring__find__tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear();
|
||||
lib = fxt.Core().Lib_ustring().Init();
|
||||
}
|
||||
@Test public void Basic() {
|
||||
Exec_find("abcd" , "b" , 1, Bool_.N, "2;2"); // basic
|
||||
Exec_find("abac" , "a" , 2, Bool_.N, "3;3"); // bgn
|
||||
Exec_find("()()" , "(" , 2, Bool_.Y, "3;3"); // plain; note that ( would "break" regx
|
||||
Exec_find("a bcd e" , "(b(c)d)" , 2, Bool_.N, "3;5;bcd;c"); // groups
|
||||
Exec_find("a bcd e" , "()(b)" , 2, Bool_.N, "3;3;3;b"); // groups; empty capture
|
||||
Exec_find("abcd" , "x" , 1, Bool_.N, ""); // empty
|
||||
Exec_find("abcd" , "" , 2, Bool_.Y, "2;1"); // empty regx should return values; plain; EX:w:Fool's_mate; DATE:2014-03-04
|
||||
Exec_find("abcd" , "" , 2, Bool_.N, "2;1"); // empty regx should return values; regx; EX:w:Fool's_mate; DATE:2014-03-04
|
||||
Exec_find("abcd" , "^(c)" , 3, Bool_.N, "3;3;c"); // ^ should be converted to \G; regx; EX:cs.n:Category:1._září_2008; DATE:2014-05-07
|
||||
}
|
||||
@Test public void Arg_int() { // PURPOSE: allow int find; PAGE:ro.w:Innsbruck DATE:2015-09-12
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_ustring.Invk_find, Scrib_kv_utl_.base1_many_(123, "2", 1, Bool_.N), "2;2");
|
||||
}
|
||||
@Test public void Return_int() {
|
||||
fxt.Test__proc__kvps__vals(lib, Scrib_lib_ustring.Invk_find, Scrib_kv_utl_.base1_many_("a", "()", 2, Bool_.N), 2, 1, 2);
|
||||
}
|
||||
@Test public void Surrogate() { // PURPOSE: handle surrogates in Find PAGE:zh.w:南北鐵路_(越南); DATE:2014-08-28
|
||||
Exec_find("aé𡼾\nbî𡼾\n" , "\n" , 1, Bool_.N, "4;4"); // 4 b/c \n starts at pos 4 (super 1)
|
||||
Exec_find("aé𡼾\nbî𡼾\n" , "\n" , 5, Bool_.N, "8;8"); // 8 b/c \n starts at pos 8 (super 1)
|
||||
}
|
||||
private void Exec_find(String text, String regx, int bgn, boolean plain, String expd) {
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_ustring.Invk_find, Scrib_kv_utl_.base1_many_(text, regx, bgn, plain), expd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_ustring__gmatch__tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear();
|
||||
lib = fxt.Core().Lib_ustring().Init();
|
||||
}
|
||||
@Test public void Init__basic() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_init, Object_.Ary("abcabc", "a(b)") , "1=a(b)\n2=\n 1=false");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_init, Object_.Ary("abcabc", "a()(b)") , "1=a()(b)\n2=\n 1=true\n 2=false");
|
||||
}
|
||||
@Test public void Callback__basic() {
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary("abcabc", "a(b)", Scrib_kv_utl_.base1_many_(false), 0) , "1=2\n2=\n 1=b");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary("abcabc", "a(b)", Scrib_kv_utl_.base1_many_(false), 2) , "1=5\n2=\n 1=b");
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary("abcabc", "a(b)", Scrib_kv_utl_.base1_many_(false), 8) , "1=8\n2=");
|
||||
}
|
||||
@Test public void Callback__nomatch() {// PURPOSE.fix: was originally returning "" instead of original String; EX:vi.d:trở_thành; DATE:2014-04-23
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary("a", "a" , Keyval_.Ary_empty, 0) , "1=1\n2=\n 1=a");
|
||||
}
|
||||
@Test public void Callback__anypos() {// PURPOSE.fix: was not handling $capt argument; EX:vi.d:trở_thành; DATE:2014-04-23
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary("a bcd e", "()(b)" , Scrib_kv_utl_.base1_many_(true, false), 0), String_.Concat_lines_nl_skip_last
|
||||
( "1=3"
|
||||
, "2="
|
||||
, " 1=3"
|
||||
, " 2=b"
|
||||
));
|
||||
}
|
||||
@Test public void Callback__text_as_number() { // PURPOSE: Gmatch_callback must be able to take non String value; DATE:2013-12-20
|
||||
fxt.Test__proc__objs__nest(lib, Scrib_lib_ustring.Invk_gmatch_callback, Object_.Ary(1234, "1(2)", Scrib_kv_utl_.base1_many_(false), 0), String_.Concat_lines_nl_skip_last
|
||||
( "1=2"
|
||||
, "2="
|
||||
, " 1=2"
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.langs.regxs.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_ustring__gsub__tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear();
|
||||
lib = fxt.Core().Lib_ustring().Init();
|
||||
}
|
||||
@Test public void Replace__basic() {
|
||||
Exec_gsub("abcd", "[a]" , -1, "A" , "Abcd;1");
|
||||
Exec_gsub("aaaa", "[a]" , 2, "A" , "AAaa;2");
|
||||
Exec_gsub("a" , "(a)" , 1, "%%%1" , "%a;1");
|
||||
Exec_gsub("à{b}c", "{b}" , 1, "b" , "àbc;1"); // utf8
|
||||
Exec_gsub("àbc", "^%s*(.-)%s*$" , 1, "%1" , "àbc;1"); // utf8; regx is for trim line
|
||||
Exec_gsub("a" , "[^]" , 1, "b" , "a;0"); // invalid regx should not fail; should return self; DATE:2013-10-20
|
||||
}
|
||||
@Test public void Replace__none() {// PURPOSE: gsub with no replace argument should not fail; EX:d:'orse; DATE:2013-10-14
|
||||
fxt.Test__proc__objs__flat(lib, Scrib_lib_ustring.Invk_gsub, Object_.Ary("text", "regx") , "text"); // NOTE: repl, limit deliberately omitted
|
||||
}
|
||||
@Test public void Replace__int() { // PURPOSE: do not fail if integer is passed in for @replace; PAGE:en.d:λύω DATE:2014-09-02
|
||||
Exec_gsub("abcd", 1 , -1, 1 , "abcd;0");
|
||||
}
|
||||
@Test public void Replace__double() { // PURPOSE: do not fail if double is passed in for @replace; PAGE:de.v:Wikivoyage:Wikidata/Test_Modul:Wikidata2 DATE:2016-04-21
|
||||
Exec_gsub("abcd", 1 , -1, 1.23d , "abcd;0");
|
||||
}
|
||||
@Test public void Replace__table() {
|
||||
Exec_gsub("abcd", "[ac]" , -1, Scrib_kv_utl_.flat_many_("a", "A", "c", "C") , "AbCd;2");
|
||||
Exec_gsub("abc" , "[ab]" , -1, Scrib_kv_utl_.flat_many_("a", "A") , "Abc;2"); // PURPOSE: match not in regex should still print itself; in this case [c] is not in tbl regex; DATE:2014-03-31
|
||||
}
|
||||
@Test public void Replace__table__match() {// PURPOSE: replace using group, not found term; EX:"b" not "%b%" PAGE:en.w:Bannered_routes_of_U.S._Route_60; DATE:2014-08-15
|
||||
Exec_gsub("a%b%c", "%%(%w+)%%" , -1, Scrib_kv_utl_.flat_many_("b", "B") , "aBc;1");
|
||||
}
|
||||
@Test public void Replace__proc__recursive() { // PURPOSE:handle recursive gsub calls; PAGE:en.d:כלב; DATE:2016-01-22
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
Mock_proc__recursive proc_lvl2 = new Mock_proc__recursive(fxt, lib, bfr, 2, null);
|
||||
Mock_proc__recursive proc_lvl1 = new Mock_proc__recursive(fxt, lib, bfr, 1, proc_lvl2);
|
||||
Mock_proc__recursive proc_root = new Mock_proc__recursive(fxt, lib, bfr, 0, proc_lvl1);
|
||||
fxt.Init__cbk(proc_root, proc_lvl1, proc_lvl2);
|
||||
Exec_gsub("ab", ".", -1, proc_root.To_scrib_lua_proc(), "ab;2"); // fails if "ab;4"
|
||||
Tfds.Eq_str("0;1;2;0;1;2;", bfr.To_str_and_clear()); // fails if "0;1;1;1"
|
||||
}
|
||||
@Test public void Replace__proc__number() { // PURPOSE:handle replace-as-number in gproc; PAGE:en.d:seven; DATE:2016-04-27
|
||||
Mock_proc__number proc = new Mock_proc__number(0);
|
||||
fxt.Init__cbk(proc);
|
||||
Exec_gsub("ab", ".", -1, proc.To_scrib_lua_proc(), "12;2"); // fails if "ab;4"
|
||||
}
|
||||
@Test public void Regx__int() { // PURPOSE: do not fail if integer is passed in for @regx; PAGE:en.d:λύω DATE:2014-09-02
|
||||
Exec_gsub("abcd", 1 , -1, "A" , "abcd;0");
|
||||
}
|
||||
@Test public void Regx__dash() { // PURPOSE: "-" at end of regx should be literal; EX:[A-]; PAGE:en.d:frei DATE:2016-01-23
|
||||
Exec_gsub("abc", "[a-]", -1, "d", "dbc;1");
|
||||
}
|
||||
@Test public void Regx__word_class() { // PURPOSE: handle %w in extended regex; PAGE:en.w:A♯_(musical_note) DATE:2015-06-10
|
||||
Exec_gsub("(a b)", "[^%w%p%s]", -1, "x", "(a b);0"); // was returning "(x x)" b/c ^%w was incorrectly matching "a" and "b"
|
||||
}
|
||||
@Test public void Regx__balanced_group() { // PURPOSE: handle balanced group regex; EX:"%b()"; NOTE:test will fail if run in 1.6 environment; DATE:2013-12-20
|
||||
Exec_gsub("(a)", "%b()", 1, "c", "c;1");
|
||||
}
|
||||
@Test public void Regx__capture() {
|
||||
Exec_gsub("aa" , "(a)%1" , 1, "%0z", "aaz;1"); // capture; handle %0; PAGE:en.w:Wikipedia:Wikipedia_Signpost/Templates/Voter/testcases; DATE:2015-08-02
|
||||
Exec_gsub("aa" , "(a)%1" , 1, "%1z", "az;1"); // capture; handle %1+; PAGE:en.w:Wikipedia:Wikipedia_Signpost/Templates/Voter/testcases; DATE:2015-08-02
|
||||
Exec_gsub("a\"b'c\"d" , "([\"'])(.-)%1" , 1, "%1z", "a\"zd;1"); // capture; http://www.lua.org/pil/20.3.html; {{#invoke:test|gsub_string|a"b'c"d|(["'])(.-)%1|%1z}}
|
||||
}
|
||||
@Test public void Regx__frontier_pattern() { // PURPOSE: handle frontier pattern; EX:"%f[%a]"; DATE:2015-07-21
|
||||
Exec_gsub("a b c", "%f[%W]", 5, "()", "a() b() c();3");
|
||||
Exec_gsub("abC DEF gHI JKm NOP", "%f[%a]%u+%f[%A]", Int_.Max_value, "()", "abC () gHI JKm ();2"); // based on http://lua-users.org/wiki/FrontierPattern
|
||||
}
|
||||
@Test public void Regx__frontier_pattern_utl() {// PURPOSE: standalone test for \0 logic in frontier pattern; note that verified against PHP: echo(preg_match( "/[\w]/us", "\0" )); DATE:2015-07-21
|
||||
Tfds.Eq(Bool_.N, Regx_adp_.Match("\0", "a")); // \0 not matched by a
|
||||
Tfds.Eq(Bool_.N, Regx_adp_.Match("\0", "0")); // \0 not matched by numeric 0
|
||||
Tfds.Eq(Bool_.N, Regx_adp_.Match("\0", "[\\w]")); // \0 not matched by word_char
|
||||
Tfds.Eq(Bool_.Y, Regx_adp_.Match("\0", "[\\W]")); // \0 matched by !word_char
|
||||
Tfds.Eq(Bool_.Y, Regx_adp_.Match("\0", "[\\x]")); // \0 matched by any_char
|
||||
Tfds.Eq(Bool_.Y, Regx_adp_.Match("\0", "[\\X]")); // \0 matched by !any_char
|
||||
}
|
||||
private void Exec_gsub(String text, Object regx, int limit, Object repl, String expd) {
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_(text, regx, repl, limit), expd);
|
||||
}
|
||||
}
|
||||
class Mock_proc__recursive extends Mock_proc_fxt { private final Mock_scrib_fxt fxt; private final Scrib_lib lib; private final Mock_proc__recursive inner;
|
||||
private final Bry_bfr bfr;
|
||||
public Mock_proc__recursive(Mock_scrib_fxt fxt, Scrib_lib lib, Bry_bfr bfr, int id, Mock_proc__recursive inner) {super(id, "recur");
|
||||
this.fxt = fxt; this.lib = lib; this.inner = inner;
|
||||
this.bfr = bfr;
|
||||
}
|
||||
@Override public Keyval[] Exec_by_scrib(Keyval[] args) {
|
||||
bfr.Add_int_variable(this.Id()).Add_byte_semic();
|
||||
if (inner != null)
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_("a", ".", inner.To_scrib_lua_proc(), -1), "a;1");
|
||||
return args;
|
||||
}
|
||||
}
|
||||
class Mock_proc__number extends Mock_proc_fxt { private int counter = 0;
|
||||
public Mock_proc__number(int id) {super(id, "number");}
|
||||
@Override public Keyval[] Exec_by_scrib(Keyval[] args) {
|
||||
args[0].Val_(++counter); // set replace-val to int
|
||||
return args;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.xtns.scribunto.engines.mocks.*;
|
||||
public class Scrib_lib_ustring__match__tst {
|
||||
private final Mock_scrib_fxt fxt = new Mock_scrib_fxt(); private Scrib_lib lib;
|
||||
@Before public void init() {
|
||||
fxt.Clear();
|
||||
lib = fxt.Core().Lib_ustring().Init();
|
||||
}
|
||||
@Test public void Basic() {
|
||||
Exec_match("abcd" , "bc" , 1, "bc"); // basic
|
||||
Exec_match("abcd" , "x" , 1, String_.Null_mark); // empty
|
||||
Exec_match("abcd" , "a" , 2, String_.Null_mark); // bgn
|
||||
Exec_match("abcd" , "b(c)" , 1, "c"); // group
|
||||
Exec_match(" a b " , "^%s*(.-)%s*$" , 1, "a b;"); // trim; NOTE: changed from "a b" to "a b;"; DATE:2015-01-30
|
||||
Exec_match("abcd" , "a" , 0, "a"); // handle 0; note that php/lua is super-1, but some modules pass in 0; ru.w:Module:Infocards; DATE:2013-11-08
|
||||
Exec_match("abcd" , "." , -1, "d"); // -1
|
||||
Exec_match("aaa" , "a" , 1, "a"); // should return 1st match not many
|
||||
Exec_match("aaa" , "(a)" , 1, "a;a;a"); // should return all matches
|
||||
Exec_match("a b" , "%S" , 1, "a"); // %S was returning every match instead of 1st; PAGE:en.w:Bertrand_Russell; DATE:2014-04-02
|
||||
Exec_match(1 , "a" , 1, String_.Null_mark); // Module can pass raw ints; PAGE:en.w:Budget_of_the_European_Union; DATE:2015-01-22
|
||||
Exec_match("" , "a?" , 1, ""); // no results with ? should return "" not nil; PAGE:en.d:民; DATE:2015-01-30
|
||||
}
|
||||
@Test public void Args_out_of_order() {
|
||||
fxt.Test__proc__kvps__empty(lib, Scrib_lib_ustring.Invk_match, Keyval_.Ary(Keyval_.int_(2, "[a]")));
|
||||
}
|
||||
// @Test public void Match_viwiktionary() {
|
||||
// fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_ustring(), Scrib_lib_ustring.Invk_match);
|
||||
// Exec_match("tr" , "()(r)", 1, ";"); // should return all matches
|
||||
// Exec_match("tr" , "^([b]*).-([c]*)$", 1, ";"); // should return all matches
|
||||
// }
|
||||
private void Exec_match(Object text, String regx, int bgn, String expd) {
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_ustring.Invk_match, Scrib_kv_utl_.base1_many_(text, regx, bgn), expd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
public class Scrib_lib_ustring__shell_cmd__tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_invoke();
|
||||
fxt.Init_page("{{#invoke:Mod_0|Func_0}}");
|
||||
fxt.Core().Lib_ustring().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt();
|
||||
@Test public void Gsub_proc() {
|
||||
fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_ustring(), Scrib_lib_ustring.Invk_gsub);
|
||||
Exec_gsub_regx_func_0("abcd", "([a])", "Abcd;1");
|
||||
}
|
||||
@Test public void Gsub_proc_w_grouped() { // PURPOSE: gsub_proc should pass matched String, not entire String; DATE:2013-12-01
|
||||
fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_ustring(), Scrib_lib_ustring.Invk_gsub);
|
||||
Exec_gsub_regx_func_1("[[a]]", "%[%[([^#|%]]-)%]%]" , "A;1");
|
||||
fxt.Test_log_rcvd(3, "000000370000006D{[\"op\"]=\"call\",[\"id\"]=1,[\"nargs\"]=1,[\"args\"]={[1]=\"a\"}}"); // should be "a", not "[[a]]"
|
||||
}
|
||||
@Test public void Gsub_proc_w_grouped_2() {// PURPOSE: gsub_proc failed when passing multiple matches; DATE:2013-12-01
|
||||
fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_ustring(), Scrib_lib_ustring.Invk_gsub);
|
||||
Exec_gsub_regx_func_2("[[a]] [[b]]", "%[%[([^#|%]]-)%]%]" , "A B;2");
|
||||
fxt.Test_log_rcvd(3, "000000370000006D{[\"op\"]=\"call\",[\"id\"]=1,[\"nargs\"]=1,[\"args\"]={[1]=\"a\"}}"); // should be "a", not "[[a]]"
|
||||
fxt.Test_log_rcvd(4, "000000370000006D{[\"op\"]=\"call\",[\"id\"]=1,[\"nargs\"]=1,[\"args\"]={[1]=\"b\"}}"); // should be "b", not "[[b]]"
|
||||
}
|
||||
@Test public void Gsub_int() { // PURPOSE: gsub with integer arg should not fail; DATE:2013-11-06
|
||||
fxt.Init_cbk(Scrib_core.Key_mw_interface, fxt.Core().Lib_ustring(), Scrib_lib_ustring.Invk_gsub);
|
||||
fxt.Init_lua_module();
|
||||
fxt.Init_lua_rcvd(Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_(1, "[1]", "2", 1)); // NOTE: text is integer (lua / php are type-less)
|
||||
fxt.Init_lua_rcvd_rv();
|
||||
fxt.Test_invoke("2;1");
|
||||
}
|
||||
private void Exec_gsub_regx_func_0(String text, String regx, String expd) {
|
||||
fxt.Init_lua_module();
|
||||
fxt.Init_lua_rcvd(Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_(text, regx, new Scrib_lua_proc("ignore_key", 1)));
|
||||
fxt.Init_lua_rcvd_raw("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:1:\"A\";}}");
|
||||
fxt.Init_lua_rcvd_rv();
|
||||
fxt.Test_invoke(expd);
|
||||
}
|
||||
private void Exec_gsub_regx_func_1(String text, String regx, String expd) {
|
||||
fxt.Init_lua_module();
|
||||
fxt.Init_lua_rcvd(Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_(text, regx, new Scrib_lua_proc("ignore_key", 1)));
|
||||
fxt.Init_lua_rcvd_raw("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:1:\"A\";}}");
|
||||
fxt.Init_lua_rcvd_rv();
|
||||
fxt.Test_invoke(expd);
|
||||
}
|
||||
private void Exec_gsub_regx_func_2(String text, String regx, String expd) {
|
||||
fxt.Init_lua_module();
|
||||
fxt.Init_lua_rcvd(Scrib_lib_ustring.Invk_gsub, Scrib_kv_utl_.base1_many_(text, regx, new Scrib_lua_proc("ignore_key", 1)));
|
||||
fxt.Init_lua_rcvd_raw("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:1:\"A\";}}");
|
||||
fxt.Init_lua_rcvd_raw("a:3:{s:2:\"op\";s:6:\"return\";s:7:\"nvalues\";i:1;s:6:\"values\";a:1:{i:1;s:1:\"B\";}}");
|
||||
fxt.Init_lua_rcvd_rv();
|
||||
fxt.Init_lua_rcvd_rv();
|
||||
fxt.Test_invoke(expd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.langs.jsons.*; import gplx.xowa.xtns.wbases.*; import gplx.xowa.xtns.wbases.parsers.*;
|
||||
import gplx.xowa.wikis.domains.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_wikibase implements Scrib_lib {
|
||||
public Scrib_lib_wikibase(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_wikibase(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.wikibase.lua"));
|
||||
notify_page_changed_fnc = mod.Fncs_get_by_key("notify_page_changed");
|
||||
return mod;
|
||||
} private Scrib_lua_proc notify_page_changed_fnc;
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_getLabel: return GetLabel(args, rslt);
|
||||
case Proc_getEntity: return GetEntity(args, rslt);
|
||||
case Proc_getSetting: return GetSetting(args, rslt);
|
||||
case Proc_getEntityUrl: return GetEntityUrl(args, rslt);
|
||||
case Proc_renderSnak: return RenderSnak(args, rslt);
|
||||
case Proc_renderSnaks: return RenderSnaks(args, rslt);
|
||||
case Proc_getEntityId: return GetEntityId(args, rslt);
|
||||
case Proc_getUserLang: return GetUserLang(args, rslt);
|
||||
case Proc_getDescription: return GetDescription(args, rslt);
|
||||
case Proc_resolvePropertyId: return ResolvePropertyId(args, rslt);
|
||||
case Proc_getSiteLinkPageName: return GetSiteLinkPageName(args, rslt);
|
||||
case Proc_incrementExpensiveFunctionCount: return IncrementExpensiveFunctionCount(args, rslt);
|
||||
case Proc_getPropertyOrder: return GetPropertyOrder(args, rslt);
|
||||
case Proc_orderProperties: return OrderProperties(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int
|
||||
Proc_getLabel = 0, Proc_getEntity = 1, Proc_getSetting = 2, Proc_getEntityUrl = 3, Proc_renderSnak = 4, Proc_renderSnaks = 5, Proc_getEntityId = 6, Proc_getUserLang = 7
|
||||
, Proc_getDescription = 8, Proc_resolvePropertyId = 9, Proc_getSiteLinkPageName = 10, Proc_incrementExpensiveFunctionCount = 11, Proc_getPropertyOrder = 12, Proc_orderProperties = 13;
|
||||
public static final String Invk_getLabel = "getLabel", Invk_getEntity = "getEntity", Invk_getSetting = "getSetting", Invk_getEntityUrl = "getEntityUrl"
|
||||
, Invk_renderSnak = "renderSnak", Invk_renderSnaks = "renderSnaks", Invk_getEntityId = "getEntityId", Invk_getUserLang = "getUserLang"
|
||||
, Invk_getDescription = "getDescription", Invk_resolvePropertyId = "resolvePropertyId", Invk_getSiteLinkPageName = "getSiteLinkPageName", Invk_incrementExpensiveFunctionCount = "incrementExpensiveFunctionCount"
|
||||
, Invk_getPropertyOrder = "getPropertyOrder", Invk_orderProperties = "orderProperties"
|
||||
;
|
||||
private static final String[] Proc_names = String_.Ary
|
||||
( Invk_getLabel, Invk_getEntity, Invk_getSetting, Invk_getEntityUrl, Invk_renderSnak, Invk_renderSnaks, Invk_getEntityId, Invk_getUserLang
|
||||
, Invk_getDescription, Invk_resolvePropertyId, Invk_getSiteLinkPageName, Invk_incrementExpensiveFunctionCount, Invk_getPropertyOrder, Invk_orderProperties
|
||||
);
|
||||
public void Notify_page_changed() {if (notify_page_changed_fnc != null) core.Interpreter().CallFunction(notify_page_changed_fnc.Id(), Keyval_.Ary_empty);}
|
||||
public boolean GetLabel(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Wdata_doc wdoc = Get_wdoc_or_null(args, core); if (wdoc == null) return rslt.Init_ary_empty();
|
||||
return rslt.Init_obj(wdoc.Label_list__get_or_fallback(core.Lang()));
|
||||
}
|
||||
public boolean GetEntity(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Wdata_doc wdoc = Get_wdoc_or_null(args, core); if (wdoc == null) return rslt.Init_ary_empty();
|
||||
Wbase_prop_mgr prop_mgr = core.Wiki().Appe().Wiki_mgr().Wdata_mgr().Prop_mgr();
|
||||
return rslt.Init_obj(Scrib_lib_wikibase_srl.Srl(prop_mgr, wdoc, true, false)); // "false": wbase now always uses v2; PAGE:ja.w:東京競馬場; DATE:2015-07-28
|
||||
}
|
||||
public boolean GetEntityUrl(Scrib_proc_args args, Scrib_proc_rslt rslt) {throw Err_.new_("wbase", "getEntityUrl not implemented", "url", core.Page().Url().To_str());}
|
||||
public boolean GetSetting(Scrib_proc_args args, Scrib_proc_rslt rslt) {throw Err_.new_("wbase", "getSetting not implemented", "url", core.Page().Url().To_str());}
|
||||
public boolean RenderSnak(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Wdata_wiki_mgr wdata_mgr = wiki.Appe().Wiki_mgr().Wdata_mgr();
|
||||
String rv = Wdata_prop_val_visitor_.Render_snak(wdata_mgr, wiki, core.Page().Url_bry_safe(), args.Pull_kv_ary_safe(0));
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean RenderSnaks(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
String rv = Wdata_prop_val_visitor_.Render_snaks(core.Wiki(), core.Page().Url_bry_safe(), args.Pull_kv_ary_safe(0));
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean GetEntityId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] ttl_bry = args.Pull_bry(0);
|
||||
Xowe_wiki wiki = core.Wiki();
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry);
|
||||
byte[] rv = wiki.Appe().Wiki_mgr().Wdata_mgr().Qid_mgr.Get_or_null(wiki, ttl); if (rv == null) rv = Bry_.Empty;
|
||||
return rslt.Init_obj(rv);
|
||||
}
|
||||
public boolean GetUserLang(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(core.App().Usere().Lang().Key_bry());
|
||||
}
|
||||
public boolean GetDescription(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Wdata_doc wdoc = Get_wdoc_or_null(args, core); if (wdoc == null) return rslt.Init_ary_empty();
|
||||
return rslt.Init_obj(wdoc.Descr_list__get_or_fallback(core.Lang()));
|
||||
}
|
||||
public boolean ResolvePropertyId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Wdata_doc wdoc = Get_wdoc_or_null(args, core); if (wdoc == null) return rslt.Init_ary_empty(); // NOTE: prop should be of form "P123"; do not add "P"; PAGE:no.w:Anne_Enger; DATE:2015-10-27
|
||||
return rslt.Init_obj(wdoc.Label_list__get_or_fallback(core.Lang()));
|
||||
}
|
||||
public boolean GetSiteLinkPageName(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
Wdata_doc wdoc = Get_wdoc_or_null(args, core); if (wdoc == null) return rslt.Init_ary_empty(); // NOTE: prop should be of form "P123"; do not add "P"; PAGE:no.w:Anne_Enger; DATE:2015-10-27
|
||||
Xow_domain_itm domain_itm = core.Wiki().Domain_itm();
|
||||
return rslt.Init_obj(wdoc.Slink_list__get_or_fallback(domain_itm.Abrv_wm()));
|
||||
}
|
||||
public boolean IncrementExpensiveFunctionCount(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(Keyval_.Ary_empty);} // NOTE: for now, always return null (XOWA does not care about expensive parser functions)
|
||||
public boolean GetGlobalSiteId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(core.Wiki().Domain_abrv()); // ;siteGlobalID: This site's global ID (e.g. <code>'itwiki'</code>), as used in the sites table. Default: <code>$wgDBname</code>.; REF:/xtns/Wikibase/docs/options.wiki
|
||||
}
|
||||
private static Wdata_doc Get_wdoc_or_null(Scrib_proc_args args, Scrib_core core) {
|
||||
// get qid / pid from scrib_arg[0]; if none, return null;
|
||||
byte[] xid_bry = args.Pull_bry(0); if (Bry_.Len_eq_0(xid_bry)) return null; // NOTE: some Modules do not pass in an argument; return early, else spurious warning "invalid qid for ttl" (since ttl is blank); EX:w:Module:Authority_control; DATE:2013-10-27
|
||||
|
||||
// get wdoc
|
||||
Wdata_doc wdoc = core.Wiki().Appe().Wiki_mgr().Wdata_mgr().Doc_mgr.Get_by_xid_or_null(xid_bry); // NOTE: by_xid b/c Module passes just "p1" not "Property:P1"
|
||||
if (wdoc == null) Wdata_wiki_mgr.Log_missing_qid(core.Ctx(), xid_bry);
|
||||
return wdoc;
|
||||
}
|
||||
public boolean GetPropertyOrder(Scrib_proc_args args, Scrib_proc_rslt rslt) {throw Err_.new_("wbase", "getPropertyOrder not implemented", "url", core.Page().Url().To_str());}
|
||||
public boolean OrderProperties(Scrib_proc_args args, Scrib_proc_rslt rslt) {throw Err_.new_("wbase", "orderProperties not implemented", "url", core.Page().Url().To_str());}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.wbases.*;
|
||||
import gplx.langs.jsons.*;
|
||||
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*;
|
||||
import gplx.xowa.xtns.scribunto.procs.*;
|
||||
public class Scrib_lib_wikibase_entity implements Scrib_lib {
|
||||
public Scrib_lib_wikibase_entity(Scrib_core core) {this.core = core;} private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_wikibase_entity(core);}
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, script_dir.GenSubFil("mw.wikibase.entity.lua"));
|
||||
return mod;
|
||||
}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_getGlobalSiteId: return GetGlobalSiteId(args, rslt);
|
||||
case Proc_formatPropertyValues: return FormatPropertyValues(args, rslt);
|
||||
default: throw Err_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_getGlobalSiteId = 0, Proc_formatPropertyValues = 1;
|
||||
public static final String Invk_getGlobalSiteId = "getGlobalSiteId", Invk_formatPropertyValues = "formatPropertyValues";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_getGlobalSiteId, Invk_formatPropertyValues);
|
||||
public boolean GetGlobalSiteId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
return rslt.Init_obj(core.Wiki().Domain_abrv()); // ;siteGlobalID: This site's global ID (e.g. <code>'itwiki'</code>), as used in the sites table. Default: <code>$wgDBname</code>.; REF:/xtns/Wikibase/docs/options.wiki
|
||||
}
|
||||
public boolean FormatPropertyValues(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] qid = args.Pull_bry(0);
|
||||
byte[] pid = args.Pull_bry(1);
|
||||
Xoae_app app = core.App(); Xowe_wiki wiki = core.Wiki();
|
||||
Wdata_wiki_mgr wdata_mgr = app.Wiki_mgr().Wdata_mgr();
|
||||
byte[] lang = wiki.Wdata_wiki_lang();
|
||||
Wdata_doc wdoc = wdata_mgr.Doc_mgr.Get_by_bry_or_null(qid); if (wdoc == null) {Wdata_wiki_mgr.Log_missing_qid(core.Ctx(), qid); return rslt.Init_str_empty();} // NOTE: return empty String, not nil; PAGE:fr.s:Henri_Bergson; DATE:2014-08-13
|
||||
int pid_int = Wbase_pid_mgr.To_int_or_null(pid); // parse as num; EX: p123 -> 123; PAGE:hr.w:Hepatitis DATE:2015-11-08
|
||||
if (pid_int == Wdata_wiki_mgr.Pid_null) pid_int = wdata_mgr.Pid_mgr.Get_or_null(lang, pid); // parse as name; EX: name > 123
|
||||
if (pid_int == Wdata_wiki_mgr.Pid_null) return rslt.Init_str_empty();
|
||||
Wbase_claim_grp prop_grp = wdoc.Claim_list_get(pid_int); if (prop_grp == null) return rslt.Init_str_empty();
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
wdata_mgr.Resolve_to_bfr(bfr, prop_grp, lang);
|
||||
return rslt.Init_obj(bfr.To_bry_and_rls());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.xtns.wbases.*;
|
||||
public class Scrib_lib_wikibase_entity_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = fxt.Core().Lib_wikibase_entity().Init();
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
@Test public void GetGlobalSiteId() {
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase_entity.Invk_getGlobalSiteId, Object_.Ary_empty, "enwiki");
|
||||
}
|
||||
@Test public void FormatPropertyValues() {
|
||||
Wdata_wiki_mgr_fxt wdata_fxt = new Wdata_wiki_mgr_fxt().Init(fxt.Parser_fxt(), false);
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("Q2").Add_claims(wdata_fxt.Make_claim_string(3, "P3_val")).Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase_entity.Invk_formatPropertyValues, Object_.Ary("Q2", "P3") , "P3_val"); // lookup by id
|
||||
wdata_fxt.Init_pids_add("en", "P3_val", 3);
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase_entity.Invk_formatPropertyValues, Object_.Ary("Q2", "P3_val") , "P3_val"); // lookup by name
|
||||
}
|
||||
@Test public void FormatPropertyValues__not_found() { // PURPOSE: should return "" not null; PAGE:fr.s:Auteur:Henri_Bergson; DATE:2014-08-13
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase_entity.Invk_formatPropertyValues, Object_.Ary("Q2", "P3"), "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.wbases.*; import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*; import gplx.xowa.xtns.wbases.parsers.*;
|
||||
class Scrib_lib_wikibase_srl {
|
||||
public static Keyval[] Srl(Wbase_prop_mgr prop_mgr, Wdata_doc wdoc, boolean header_enabled, boolean legacy_style) {// REF.MW:/Wikibase/lib/includes/serializers/EntitySerializer.php!getSerialized; http://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
|
||||
int base_adj = legacy_style ? 0 : 1;
|
||||
List_adp rv = List_adp_.New();
|
||||
if (header_enabled) {
|
||||
byte[] qid = wdoc.Qid();
|
||||
boolean doc_is_qid = Bry_.Has_at_bgn(qid, Byte_ascii.Ltr_q) || Bry_.Has_at_bgn(qid, Byte_ascii.Ltr_Q);
|
||||
rv.Add(Keyval_.new_("id", qid));
|
||||
rv.Add(Keyval_.new_("type", doc_is_qid ? Wbase_claim_entity_type_.Itm__item.Key_str() : Wbase_claim_entity_type_.Itm__property.Key_str())); // type should be "property"; PAGE:ru.w:Викитека:Проект:Викиданные DATE:2016-11-23
|
||||
rv.Add(Keyval_.new_("schemaVersion", base_adj + 1)); // NOTE: needed by mw.wikibase.lua
|
||||
}
|
||||
Srl_root(rv, Wdata_doc_parser_v2.Str_labels , Srl_langtexts (Wdata_dict_langtext.Itm__language.Key_str(), Wdata_dict_langtext.Itm__value.Key_str(), wdoc.Label_list()));
|
||||
Srl_root(rv, Wdata_doc_parser_v2.Str_descriptions , Srl_langtexts (Wdata_dict_langtext.Itm__language.Key_str(), Wdata_dict_langtext.Itm__value.Key_str(), wdoc.Descr_list()));
|
||||
Srl_root(rv, Wdata_doc_parser_v2.Str_sitelinks , Srl_sitelinks (Wdata_dict_sitelink.Itm__site.Key_str() , Wdata_dict_sitelink.Itm__title.Key_str(), wdoc.Slink_list(), base_adj));
|
||||
Srl_root(rv, Wdata_doc_parser_v2.Str_aliases , Srl_aliases (base_adj, wdoc.Alias_list()));
|
||||
Srl_root(rv, Wdata_doc_parser_v2.Str_claims , Srl_claims (base_adj, legacy_style, prop_mgr, wdoc.Claim_list()));
|
||||
return (Keyval[])rv.To_ary(Keyval.class);
|
||||
}
|
||||
private static void Srl_root(List_adp rv, String label, Keyval[] ary) {
|
||||
if (ary == null) return; // don't add node if empty; EX: labels:{} should not add "labels" kv
|
||||
rv.Add(Keyval_.new_(label, ary));
|
||||
}
|
||||
private static Keyval[] Srl_langtexts(String lang_label, String text_label, Ordered_hash list) {
|
||||
int len = list.Count(); if (len == 0) return null;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Wdata_langtext_itm itm = (Wdata_langtext_itm)list.Get_at(i);
|
||||
String lang = String_.new_u8(itm.Lang());
|
||||
String text = String_.new_u8(itm.Text());
|
||||
rv[i] = Keyval_.new_(lang, Keyval_.Ary(Keyval_.new_(lang_label, lang), Keyval_.new_(text_label, text)));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_sitelinks(String key_label, String val_label, Ordered_hash list, int base_adj) {
|
||||
int len = list.Count(); if (len == 0) return null;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Wdata_sitelink_itm itm = (Wdata_sitelink_itm)list.Get_at(i);
|
||||
String site = String_.new_u8(itm.Site());
|
||||
String name = String_.new_u8(itm.Name());
|
||||
rv[i] = Keyval_.new_(site, Keyval_.Ary(Keyval_.new_(key_label, site), Keyval_.new_(val_label, name), Srl_sitelinks_badges(itm.Badges(), base_adj)));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval Srl_sitelinks_badges(byte[][] badges, int base_adj) { // DATE:2014-11-13
|
||||
if (badges == null) badges = Bry_.Ary_empty; // null badges -> badges:[]
|
||||
int len = badges.length;
|
||||
Keyval[] kvs = len == 0 ? Keyval_.Ary_empty : new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte[] badge = badges[i];
|
||||
kvs[i] = Keyval_.int_(i + base_adj, String_.new_u8(badge));
|
||||
}
|
||||
return Keyval_.new_("badges", kvs);
|
||||
}
|
||||
private static Keyval[] Srl_aliases(int base_adj, Ordered_hash list) {
|
||||
int len = list.Count(); if (len == 0) return null;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Wdata_alias_itm itm = (Wdata_alias_itm)list.Get_at(i);
|
||||
String lang = String_.new_u8(itm.Lang());
|
||||
rv[i] = Keyval_.new_(lang, Srl_aliases_langs(base_adj, lang, itm.Vals()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_aliases_langs(int base_adj, String lang, byte[][] ary) {
|
||||
int len = ary.length;
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte[] itm = ary[i];
|
||||
rv[i] = Keyval_.int_(i + base_adj, Keyval_.Ary(Keyval_.new_(Wdata_dict_langtext.Itm__language.Key_str(), lang), Keyval_.new_(Wdata_dict_langtext.Itm__value.Key_str(), String_.new_u8(itm)))); // NOTE: using same base_adj logic as claims
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_claims(int base_adj, boolean legacy_style, Wbase_prop_mgr prop_mgr, Ordered_hash claim_grps) {
|
||||
int len = claim_grps.Count(); if (len == 0) return null;
|
||||
Scrib_lib_wikibase_srl_visitor visitor = new Scrib_lib_wikibase_srl_visitor();
|
||||
int rv_len = legacy_style ? len * 2 : len; // NOTE: legacyStyle returns 2 sets of properties: official "P" and legacy "p"; DATE:2014-05-11
|
||||
Keyval[] rv = new Keyval[rv_len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Wbase_claim_grp grp = (Wbase_claim_grp)claim_grps.Get_at(i);
|
||||
String pid_str = Int_.To_str(grp.Id());
|
||||
Keyval[] grp_val = Srl_claims_prop_grp(prop_mgr, visitor, "P" + pid_str, grp, base_adj);
|
||||
rv[i] = Keyval_.new_("P" + pid_str, grp_val);
|
||||
if (legacy_style)
|
||||
rv[i + len] = Keyval_.new_("p" + pid_str, grp_val); // SEE:WikibaseLuaBindings.php; This is a B/C hack to allow existing lua code to use hardcoded IDs in both lower (legacy) and upper case.; DATE:2014-05-11
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_claims_prop_grp(Wbase_prop_mgr prop_mgr, Scrib_lib_wikibase_srl_visitor visitor, String pid, Wbase_claim_grp grp, int base_adj) {
|
||||
int len = grp.Len();
|
||||
Keyval[] rv = new Keyval[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Wbase_claim_base itm = grp.Get_at(i);
|
||||
rv[i] = Keyval_.int_(i + base_adj, Srl_claims_prop_itm(prop_mgr, visitor, pid, itm, base_adj)); // NOTE: must be super 0 or super 1; DATE:2014-05-09
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_claims_prop_itm(Wbase_prop_mgr prop_mgr, Scrib_lib_wikibase_srl_visitor visitor, String pid, Wbase_claim_base itm, int base_adj) {
|
||||
List_adp list = List_adp_.New();
|
||||
list.Add(Keyval_.new_("id", pid));
|
||||
list.Add(Keyval_.new_("mainsnak", Srl_claims_prop_itm_core(prop_mgr, visitor, pid, itm)));
|
||||
list.Add(Keyval_.new_(Wdata_dict_claim_v1.Str_rank, Wbase_claim_rank_.Reg.Get_str_or_fail(itm.Rank_tid())));
|
||||
list.Add(Keyval_.new_("type", itm.Prop_type()));
|
||||
Srl_root(list, Wdata_dict_claim.Itm__qualifiers.Key_str(), Srl_qualifiers(prop_mgr, visitor, itm.Qualifiers(), base_adj));
|
||||
return (Keyval[])list.To_ary_and_clear(Keyval.class);
|
||||
}
|
||||
private static Keyval[] Srl_qualifiers(Wbase_prop_mgr prop_mgr, Scrib_lib_wikibase_srl_visitor visitor, Wbase_claim_grp_list list, int base_adj) {
|
||||
if (list == null) return null;
|
||||
int list_len = list.Len(); if (list_len == 0) return Keyval_.Ary_empty;
|
||||
List_adp rv = List_adp_.New();
|
||||
List_adp pid_list = List_adp_.New();
|
||||
for (int i = 0; i < list_len; ++i) {
|
||||
Wbase_claim_grp grp = list.Get_at(i);
|
||||
int grp_len = grp.Len();
|
||||
pid_list.Clear();
|
||||
String itm_pid = grp.Id_str();
|
||||
for (int j = 0; j < grp_len; ++j) {
|
||||
Wbase_claim_base itm = grp.Get_at(j);
|
||||
pid_list.Add(Keyval_.int_(j + base_adj, Srl_claims_prop_itm_core(prop_mgr, visitor, itm_pid, itm))); // NOTE: was originally "+ 1"; changed to base_adj; PAGE:ru.w:Tor ru.w:Кактусовые DATE:2014-10-25
|
||||
}
|
||||
rv.Add(Keyval_.new_(itm_pid, (Keyval[])pid_list.To_ary_and_clear(Keyval.class)));
|
||||
}
|
||||
return (Keyval[])rv.To_ary_and_clear(Keyval.class);
|
||||
}
|
||||
private static Keyval[] Srl_claims_prop_itm_core(Wbase_prop_mgr prop_mgr, Scrib_lib_wikibase_srl_visitor visitor, String pid, Wbase_claim_base itm) {
|
||||
boolean snak_is_valued = itm.Snak_tid() == Wbase_claim_value_type_.Tid__value; // PURPOSE: was != Wbase_claim_value_type_.Tid__novalue; PAGE:it.s:Autore:Anonimo DATE:2015-12-06
|
||||
int snak_is_valued_adj = snak_is_valued ? 1 : 0;
|
||||
Keyval[] rv = new Keyval[3 + snak_is_valued_adj];
|
||||
if (snak_is_valued) // NOTE: novalue must not return slot (no datavalue node in json); PAGE:ru.w:Лимонов,_Эдуард_Вениаминович; DATE:2015-02-16; ALSO: sv.w:Joseph_Jaquet; DATE:2015-07-31
|
||||
rv[0] = Keyval_.new_("datavalue", Srl_claims_prop_itm_core_val(visitor, itm));
|
||||
rv[0 + snak_is_valued_adj] = Keyval_.new_("property", pid);
|
||||
rv[1 + snak_is_valued_adj] = Keyval_.new_("snaktype", Wbase_claim_value_type_.Reg.Get_str_or_fail(itm.Snak_tid()));
|
||||
|
||||
// get prop datatype; NOTE: datatype needed for Modules; PAGE:eo.w:WikidataKoord; DATE:2015-11-08
|
||||
String datatype = prop_mgr.Get_or_null(pid);
|
||||
if (datatype == null) // if null, fallback to value based on tid; needed for (a) tests and (b) old wbase dbs that don't have wbase_prop tbl; DATE:2016-12-01
|
||||
datatype = Wbase_claim_type_.Get_scrib_or_unknown(itm.Val_tid());
|
||||
rv[2 + snak_is_valued_adj] = Keyval_.new_("datatype", datatype);
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Srl_claims_prop_itm_core_val(Scrib_lib_wikibase_srl_visitor visitor, Wbase_claim_base itm) {
|
||||
switch (itm.Snak_tid()) {
|
||||
case Wbase_claim_value_type_.Tid__somevalue: return Datavalue_somevalue;
|
||||
case Wbase_claim_value_type_.Tid__novalue: return Datavalue_novalue; // TODO_OLD: throw exc
|
||||
default:
|
||||
itm.Welcome(visitor);
|
||||
return visitor.Rv();
|
||||
}
|
||||
}
|
||||
public static final String Key_type = "type", Key_value = "value";
|
||||
private static final Keyval[] Datavalue_somevalue = Keyval_.Ary_empty; // changed to not return value-node; PAGE:it.s:Autore:Anonimo DATE:2015-12-06 // new Keyval[] {Keyval_.new_(Key_type, ""), Keyval_.new_(Key_value, "")}; // NOTE: must return ""; null fails; EX:w:Joseph-François_Malgaigne; DATE:2014-04-07
|
||||
private static final Keyval[] Datavalue_novalue = Keyval_.Ary_empty;
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.core.tests.*;
|
||||
import gplx.langs.jsons.*; import gplx.xowa.xtns.wbases.*; import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.itms.*; import gplx.xowa.xtns.wbases.parsers.*;
|
||||
public class Scrib_lib_wikibase_srl_tst {
|
||||
@Before public void init() {fxt.Clear();} private Scrib_lib_wikibase_srl_fxt fxt = new Scrib_lib_wikibase_srl_fxt();
|
||||
@Test public void Label() {
|
||||
fxt.Init_label("en", "Earth").Init_label("fr", "Terre").Init_label("de", "Erde");
|
||||
fxt.Test
|
||||
( "labels:"
|
||||
, " en:"
|
||||
, " language:'en'"
|
||||
, " value:'Earth'"
|
||||
, " fr:"
|
||||
, " language:'fr'"
|
||||
, " value:'Terre'"
|
||||
, " de:"
|
||||
, " language:'de'"
|
||||
, " value:'Erde'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Description() {
|
||||
fxt.Init_description("en", "Earth").Init_description("fr", "Terre").Init_description("de", "Erde");
|
||||
fxt.Test
|
||||
( "descriptions:"
|
||||
, " en:"
|
||||
, " language:'en'"
|
||||
, " value:'Earth'"
|
||||
, " fr:"
|
||||
, " language:'fr'"
|
||||
, " value:'Terre'"
|
||||
, " de:"
|
||||
, " language:'de'"
|
||||
, " value:'Erde'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Sitelinks() {
|
||||
fxt.Init_link("enwiki", "Earth").Init_link("frwiki", "Terre").Init_link("dewiki", "Erde");
|
||||
fxt.Test
|
||||
( "sitelinks:"
|
||||
, " enwiki:"
|
||||
, " site:'enwiki'"
|
||||
, " title:'Earth'"
|
||||
, " badges:"
|
||||
, " frwiki:"
|
||||
, " site:'frwiki'"
|
||||
, " title:'Terre'"
|
||||
, " badges:"
|
||||
, " dewiki:"
|
||||
, " site:'dewiki'"
|
||||
, " title:'Erde'"
|
||||
, " badges:"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Sitelinks_both_formats() { // PURPOSE: check that both formats are serializable; DATE:2014-02-06
|
||||
Json_doc jdoc = fxt.Wdata_fxt().App().Utl__json_parser().Parse_by_apos_ary
|
||||
( "{ 'entity':['item',2]"
|
||||
, ", 'links':"
|
||||
, " {"
|
||||
, " 'enwiki':'Earth'" // old format
|
||||
, " , 'frwiki':{'name':'Terre','badges':['Q3']}" // new format
|
||||
, " }"
|
||||
, "}"
|
||||
);
|
||||
Wdata_doc wdoc = new Wdata_doc(Bry_.new_a7("q2"), fxt.Wdata_fxt().App().Wiki_mgr().Wdata_mgr(), jdoc);
|
||||
fxt.Test
|
||||
( wdoc
|
||||
, "sitelinks:"
|
||||
, " enwiki:"
|
||||
, " site:'enwiki'"
|
||||
, " title:'Earth'"
|
||||
, " badges:"
|
||||
, " frwiki:"
|
||||
, " site:'frwiki'"
|
||||
, " title:'Terre'"
|
||||
, " badges:"
|
||||
, " 1:'Q3'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Aliases() {
|
||||
fxt.Init_alias("en", "en_0", "en_1", "en_2").Init_alias("fr", "fr_0").Init_alias("de", "de_0", "de_1");
|
||||
fxt.Test
|
||||
( "aliases:"
|
||||
, " en:"
|
||||
, " 1:"
|
||||
, " language:'en'"
|
||||
, " value:'en_0'"
|
||||
, " 2:"
|
||||
, " language:'en'"
|
||||
, " value:'en_1'"
|
||||
, " 3:"
|
||||
, " language:'en'"
|
||||
, " value:'en_2'"
|
||||
, " fr:"
|
||||
, " 1:"
|
||||
, " language:'fr'"
|
||||
, " value:'fr_0'"
|
||||
, " de:"
|
||||
, " 1:"
|
||||
, " language:'de'"
|
||||
, " value:'de_0'"
|
||||
, " 2:"
|
||||
, " language:'de'"
|
||||
, " value:'de_1'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_str() {
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_string(2, "Moon"));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'string'"
|
||||
, " value:'Moon'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'string'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_somevalue() { // PURPOSE: changed to not return value-node; PAGE:it.s:Autore:Anonimo DATE:2015-12-06 // somevalue should always return value node; EX:w:Joseph-François_Malgaigne; DATE:2014-04-07;
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_somevalue(2));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'somevalue'"
|
||||
, " datatype:'unknown'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_novalue() { // PURPOSE: novalue must return empty array (no datavalue node in json); PAGE:ru.w:Лимонов,_Эдуард_Вениаминович; DATE:2015-02-16
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_novalue(2));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'novalue'"
|
||||
, " datatype:'unknown'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_entity() {
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_entity_qid(2, 3));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'wikibase-entityid'"
|
||||
, " value:"
|
||||
, " entity-type:'item'"
|
||||
, " numeric-id:'3'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'wikibase-item'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_base_0() { // PURPOSE: test for legacyStyle (aka base_0); used by pl.w:Module:Wikidane; DATE:2014-05-09
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_entity_qid(2, 3));
|
||||
fxt.Test(true
|
||||
, "claims:"
|
||||
, " P2:"
|
||||
, " 0:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'wikibase-entityid'"
|
||||
, " value:"
|
||||
, " entity-type:'item'"
|
||||
, " numeric-id:'3'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'wikibase-item'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, " p2:"
|
||||
, " 0:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'wikibase-entityid'"
|
||||
, " value:"
|
||||
, " entity-type:'item'"
|
||||
, " numeric-id:'3'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'wikibase-item'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_time() {
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_time(2, "2001-02-03 04:05:06", 9));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'time'"
|
||||
, " value:"
|
||||
, " time:'+00000002001-02-03T04:05:06Z'"
|
||||
, " precision:'9'"
|
||||
, " before:'0'"
|
||||
, " after:'0'"
|
||||
, " timezone:'0'"
|
||||
, " calendarmodel:'http://www.wikidata.org/entity/Q1985727'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'time'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_globecoordinate() {
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_geo(2, "6.789", "1.2345"));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'globecoordinate'"
|
||||
, " value:"
|
||||
, " latitude:'1.2345'"
|
||||
, " longitude:'6.789'"
|
||||
, " altitude:null"
|
||||
, " globe:'http://www.wikidata.org/entity/Q2'"
|
||||
, " precision:'1.0E-5'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'globe-coordinate'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_quantity() {
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_quantity(2, "+1,234", "2", "+1,236", "+1232"));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'quantity'"
|
||||
, " value:"
|
||||
, " amount:'1234'"
|
||||
, " unit:'2'"
|
||||
, " upperBound:'1236'"
|
||||
, " lowerBound:'1232'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'quantity'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_monolingualtext() {// PURPOSE.fix: type was mistakenly "language" instead of "monolingualtext" DATE:2014-10-21
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_monolingual(2, "en", "en_text"));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'monolingualtext'"
|
||||
, " value:"
|
||||
, " text:'en_text'"
|
||||
, " language:'en'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'monolingualtext'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Qualifiers() {
|
||||
Wdata_wiki_mgr_fxt wdata_fxt = fxt.Wdata_fxt();
|
||||
fxt.Init_prop(wdata_fxt.Make_claim_string(2, "Earth").Qualifiers_(wdata_fxt.Make_qualifiers(wdata_fxt.Make_qualifiers_grp(3, wdata_fxt.Make_claim_time(3, "2001-02-03 04:05:06")))));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'string'"
|
||||
, " value:'Earth'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'string'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, " qualifiers:"
|
||||
, " P3:"
|
||||
, " 1:"
|
||||
, " datavalue:"
|
||||
, " type:'time'"
|
||||
, " value:"
|
||||
, " time:'+00000002001-02-03T04:05:06Z'"
|
||||
, " precision:'14'"
|
||||
, " before:'0'"
|
||||
, " after:'0'"
|
||||
, " timezone:'0'"
|
||||
, " calendarmodel:'http://www.wikidata.org/entity/Q1985727'"
|
||||
, " property:'P3'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'time'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Claims_time_typed() {
|
||||
Wbase_claim_time claim = (Wbase_claim_time)fxt.Wdata_fxt().Make_claim_time(2, "2001-02-03 04:05:06", 9);
|
||||
Scrib_lib_wikibase_srl_visitor visitor = new Scrib_lib_wikibase_srl_visitor();
|
||||
visitor.Visit_time(claim);
|
||||
Keyval keyval = Keyval_find_.Find(true, visitor.Rv(), "value", "timezone");
|
||||
Gftest.Eq__str("timezone", keyval.Key());
|
||||
Gftest.Eq__int(0, (int)keyval.Val()); // fails when keyval.Val() is String; DATE:2016-10-28
|
||||
}
|
||||
@Test public void Claims__commonsMedia() {
|
||||
fxt.Wdata_fxt().Wdata_mgr().Prop_mgr().Loader_(Wbase_prop_mgr_loader_.New_mock(Keyval_.new_("P2", "commonsMedia")));
|
||||
fxt.Init_prop(fxt.Wdata_fxt().Make_claim_string(2, "abc"));
|
||||
fxt.Test
|
||||
( "claims:"
|
||||
, " P2:"
|
||||
, " 1:"
|
||||
, " id:'P2'"
|
||||
, " mainsnak:"
|
||||
, " datavalue:"
|
||||
, " type:'string'"
|
||||
, " value:'abc'"
|
||||
, " property:'P2'"
|
||||
, " snaktype:'value'"
|
||||
, " datatype:'commonsMedia'"
|
||||
, " rank:'normal'"
|
||||
, " type:'statement'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Type_is_property() { // PURPOSE: type should be "property"; PAGE:ru.w:Викитека:Проект:Викиданные DATE:2016-11-23
|
||||
fxt.Init_header_enabled_y_();
|
||||
fxt.Wdata_fxt().doc_("Property:P1", fxt.Wdata_fxt().Make_claim_string(123, "abc"));
|
||||
fxt.Test
|
||||
( "id:'Property:P1'"
|
||||
, "type:'property'"
|
||||
, "schemaVersion:'2'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Type_is_item() { // PURPOSE: type should be "item"; PAGE:ru.w:Викитека:Проект:Викиданные DATE:2016-11-23
|
||||
fxt.Init_header_enabled_y_();
|
||||
fxt.Wdata_fxt().doc_("Q2", fxt.Wdata_fxt().Make_claim_string(123, "abc"));
|
||||
fxt.Test
|
||||
( "id:'Q2'"
|
||||
, "type:'item'"
|
||||
, "schemaVersion:'2'"
|
||||
, ""
|
||||
);
|
||||
}
|
||||
@Test public void Numeric_id_is_int() { // PURPOSE: assert that numeric-id is integer, not String, else will fail when comparing directly to integer; PAGE:en.w:Hollywood_Walk_of_Fame DATE:2016-12-17
|
||||
Wbase_claim_entity claim = (Wbase_claim_entity)fxt.Wdata_fxt().Make_claim_entity_qid(123, 456);
|
||||
Scrib_lib_wikibase_srl_visitor visitor = new Scrib_lib_wikibase_srl_visitor();
|
||||
visitor.Visit_entity(claim);
|
||||
Keyval keyval = Keyval_find_.Find(true, visitor.Rv(), "value", "numeric-id");
|
||||
Gftest.Eq__int(456, (int)keyval.Val()); // NOTE: must be 456 not "456"
|
||||
}
|
||||
}
|
||||
class Scrib_lib_wikibase_srl_fxt {
|
||||
private Wdata_doc_bldr wdoc_bldr;
|
||||
private Wbase_prop_mgr prop_mgr;
|
||||
public void Clear() {
|
||||
wdata_fxt = new Wdata_wiki_mgr_fxt();
|
||||
wdata_fxt.Init();
|
||||
wdoc_bldr = wdata_fxt.Wdoc_bldr("q2");
|
||||
header_enabled = false;
|
||||
this.prop_mgr = wdata_fxt.App().Wiki_mgr().Wdata_mgr().Prop_mgr();
|
||||
}
|
||||
public Wdata_wiki_mgr_fxt Wdata_fxt() {return wdata_fxt;} private Wdata_wiki_mgr_fxt wdata_fxt;
|
||||
private boolean header_enabled;
|
||||
public Scrib_lib_wikibase_srl_fxt Init_header_enabled_y_() {header_enabled = true; return this;}
|
||||
public Scrib_lib_wikibase_srl_fxt Init_label(String lang, String label) {
|
||||
wdoc_bldr.Add_label(lang, label);
|
||||
return this;
|
||||
}
|
||||
public Scrib_lib_wikibase_srl_fxt Init_description(String lang, String description) {
|
||||
wdoc_bldr.Add_description(lang, description);
|
||||
return this;
|
||||
}
|
||||
public Scrib_lib_wikibase_srl_fxt Init_link(String xwiki, String val) {
|
||||
wdoc_bldr.Add_sitelink(xwiki, val);
|
||||
return this;
|
||||
}
|
||||
public Scrib_lib_wikibase_srl_fxt Init_alias(String lang, String... ary) {
|
||||
wdoc_bldr.Add_alias(lang, ary);
|
||||
return this;
|
||||
}
|
||||
public Scrib_lib_wikibase_srl_fxt Init_prop(Wbase_claim_base prop) {wdoc_bldr.Add_claims(prop); return this;}
|
||||
public Scrib_lib_wikibase_srl_fxt Test(String... expd) {return Test(false, expd);}
|
||||
public Scrib_lib_wikibase_srl_fxt Test(boolean base0, String... expd) {
|
||||
Keyval[] actl = Scrib_lib_wikibase_srl.Srl(prop_mgr, wdoc_bldr.Xto_wdoc(), header_enabled, base0);
|
||||
Tfds.Eq_ary_str(expd, String_.SplitLines_nl(Xto_str(actl)));
|
||||
return this;
|
||||
}
|
||||
public Scrib_lib_wikibase_srl_fxt Test(Wdata_doc wdoc, String... expd) {return Test(false, wdoc, expd);}
|
||||
public Scrib_lib_wikibase_srl_fxt Test(boolean base0, Wdata_doc wdoc, String... expd) {
|
||||
Keyval[] actl = Scrib_lib_wikibase_srl.Srl(prop_mgr, wdoc, header_enabled, base0);
|
||||
Tfds.Eq_ary_str(expd, String_.SplitLines_nl(Xto_str(actl)));
|
||||
return this;
|
||||
}
|
||||
private String Xto_str(Keyval[] ary) {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
Xto_str(bfr, ary, 0);
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
private void Xto_str(Bry_bfr bfr, Keyval[] ary, int depth) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval kv = ary[i];
|
||||
Xto_str(bfr, kv, depth);
|
||||
}
|
||||
}
|
||||
private void Xto_str(Bry_bfr bfr, Keyval kv, int depth) {
|
||||
bfr.Add_byte_repeat(Byte_ascii.Space, depth * 2);
|
||||
bfr.Add_str_u8(kv.Key()).Add_byte(Byte_ascii.Colon);
|
||||
Object kv_val = kv.Val();
|
||||
if (kv_val == null) {bfr.Add_str_a7("null").Add_byte_nl(); return;}
|
||||
Class<?> kv_val_cls = kv_val.getClass();
|
||||
if (Type_adp_.Eq(kv_val_cls, Keyval[].class)) {bfr.Add_byte_nl(); Xto_str(bfr, (Keyval[])kv_val, depth + 1);}
|
||||
else if (Type_adp_.Eq(kv_val_cls, Keyval[].class)) {bfr.Add_byte_nl(); Xto_str(bfr, (Keyval)kv_val, depth + 1);}
|
||||
else bfr.Add_byte(Byte_ascii.Apos).Add_str_u8(Object_.Xto_str_strict_or_empty(kv_val)).Add_byte(Byte_ascii.Apos).Add_byte_nl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
|
||||
class Scrib_lib_wikibase_srl_visitor implements Wbase_claim_visitor {
|
||||
public Keyval[] Rv() {return rv;} Keyval[] rv;
|
||||
public void Visit_str(Wbase_claim_string itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Reg.Get_str_or(itm.Val_tid(), Wbase_claim_type_.Itm__unknown.Key_str()));
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, String_.new_u8(itm.Val_bry()));
|
||||
}
|
||||
public void Visit_entity(Wbase_claim_entity itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Itm__entity.Key_str());
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, Entity_value(itm));
|
||||
}
|
||||
private static Keyval[] Entity_value(Wbase_claim_base itm) {
|
||||
Wbase_claim_entity claim_entity = (Wbase_claim_entity)itm;
|
||||
Keyval[] rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Wbase_claim_entity_.Itm__entity_type.Key_str(), claim_entity.Entity_tid_str());
|
||||
rv[1] = Keyval_.new_(Wbase_claim_entity_.Itm__numeric_id.Key_str(), claim_entity.Entity_id()); // NOTE: must be int, not String, else will fail when comparing directly to integer; PAGE:en.w:Hollywood_Walk_of_Fame DATE:2016-12-17
|
||||
return rv;
|
||||
}
|
||||
public void Visit_monolingualtext(Wbase_claim_monolingualtext itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Itm__monolingualtext.Key_str());
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, Monolingualtext_value(itm));
|
||||
}
|
||||
private static Keyval[] Monolingualtext_value(Wbase_claim_monolingualtext itm) {
|
||||
Keyval[] rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Wbase_claim_monolingualtext_.Itm__text.Key_str() , String_.new_u8(itm.Text()));
|
||||
rv[1] = Keyval_.new_(Wbase_claim_monolingualtext_.Itm__language.Key_str() , String_.new_u8(itm.Lang()));
|
||||
return rv;
|
||||
}
|
||||
public void Visit_quantity(Wbase_claim_quantity itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Itm__quantity.Key_str());
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, Quantity_value(itm));
|
||||
}
|
||||
private static Keyval[] Quantity_value(Wbase_claim_quantity itm) {
|
||||
Keyval[] rv = new Keyval[4];
|
||||
rv[0] = Keyval_.new_(Wbase_claim_quantity_.Itm__amount.Key_str() , itm.Amount_as_num().To_str()); // NOTE: must be num b/c Module code will directly do math calc on it; EX: "99" not "+99"; PAGE:eo.w:Mud<75>; DATE:2015-11-08
|
||||
rv[1] = Keyval_.new_(Wbase_claim_quantity_.Itm__unit.Key_str() , String_.new_u8(itm.Unit()));
|
||||
rv[2] = Keyval_.new_(Wbase_claim_quantity_.Itm__upperbound.Key_str() , itm.Ubound_as_num().To_str());
|
||||
rv[3] = Keyval_.new_(Wbase_claim_quantity_.Itm__lowerbound.Key_str() , itm.Lbound_as_num().To_str());
|
||||
return rv;
|
||||
}
|
||||
public void Visit_time(Wbase_claim_time itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Itm__time.Key_str());
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, Time_value(itm));
|
||||
}
|
||||
private static Keyval[] Time_value(Wbase_claim_time itm) {
|
||||
Keyval[] rv = new Keyval[6];
|
||||
rv[0] = Keyval_.new_(Wbase_claim_time_.Itm__time.Key_str() , String_.new_a7(itm.Time()));
|
||||
rv[1] = Keyval_.new_(Wbase_claim_time_.Itm__precision.Key_str() , itm.Precision_int()); // NOTE: must return int, not str; DATE:2014-02-18
|
||||
rv[2] = Keyval_.new_(Wbase_claim_time_.Itm__before.Key_str() , itm.Before_int());
|
||||
rv[3] = Keyval_.new_(Wbase_claim_time_.Itm__after.Key_str() , itm.After_int());
|
||||
rv[4] = Keyval_.new_(Wbase_claim_time_.Itm__timezone.Key_str() , Wbase_claim_time_.Dflt__timezone.Val_int()); // ASSUME: always 0 b/c UTC?; DATE:2015-09-21
|
||||
rv[5] = Keyval_.new_(Wbase_claim_time_.Itm__calendarmodel.Key_str() , Wbase_claim_time_.Dflt__calendarmodel.Val_str());
|
||||
return rv;
|
||||
}
|
||||
public void Visit_globecoordinate(Wbase_claim_globecoordinate itm) {
|
||||
rv = new Keyval[2];
|
||||
rv[0] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_type, Wbase_claim_type_.Itm__globecoordinate.Key_str());
|
||||
rv[1] = Keyval_.new_(Scrib_lib_wikibase_srl.Key_value, Globecoordinate_value(itm));
|
||||
}
|
||||
private static Keyval[] Globecoordinate_value(Wbase_claim_globecoordinate itm) {
|
||||
Keyval[] rv = new Keyval[5];
|
||||
rv[0] = Keyval_.new_(Wbase_claim_globecoordinate_.Itm__latitude.Key_str() , Double_.parse(String_.new_a7(itm.Lat())));
|
||||
rv[1] = Keyval_.new_(Wbase_claim_globecoordinate_.Itm__longitude.Key_str() , Double_.parse(String_.new_a7(itm.Lng())));
|
||||
rv[2] = Keyval_.new_(Wbase_claim_globecoordinate_.Itm__altitude.Key_str() , String_.new_u8(itm.Alt()));
|
||||
rv[3] = Keyval_.new_(Wbase_claim_globecoordinate_.Itm__globe.Key_str() , String_.new_u8(itm.Glb()));
|
||||
rv[4] = Keyval_.new_(Wbase_claim_globecoordinate_.Itm__precision.Key_str() , itm.Prc_as_num().To_double());
|
||||
return rv;
|
||||
}
|
||||
public void Visit_system(Wbase_claim_value itm) {
|
||||
rv = Keyval_.Ary_empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.xowa.xtns.wbases.*; import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.itms.*;
|
||||
public class Scrib_lib_wikibase_tst {
|
||||
private final Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Scrib_lib lib;
|
||||
private final Wdata_wiki_mgr_fxt wdata_fxt = new Wdata_wiki_mgr_fxt();
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib("en.wikipedia.org", "zh-hans");
|
||||
lib = fxt.Core().Lib_wikibase().Init();
|
||||
wdata_fxt.Init(fxt.Parser_fxt(), false);
|
||||
wdata_fxt.Init_lang_fallbacks("zh-hant", "zh-hk");
|
||||
}
|
||||
// @Test public void GetGlobalSiteId() {
|
||||
// fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getGlobalSiteId, Object_.Ary_empty, "enwiki");
|
||||
// }
|
||||
@Test public void GetEntityId() {
|
||||
wdata_fxt.Init_links_add("enwiki", "Earth", "q2");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getEntityId, Object_.Ary("Earth" ), "q2");
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getEntityId, Object_.Ary("missing_page" ), "");
|
||||
}
|
||||
@Test public void GetLabel__cur() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("zh-hans", "s").Add_label("zh-hant", "t").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getLabel, Object_.Ary("q2"), "s"); // do not get fallback
|
||||
}
|
||||
@Test public void GetLabel__fallback_1() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("zh-hant", "t").Add_label("zh-hk", "h").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getLabel, Object_.Ary("q2"), "t"); // get 1st fallback
|
||||
}
|
||||
@Test public void GetLabel__fallback_2() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("zh-hk", "hk").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getLabel, Object_.Ary("q2"), "hk"); // get 2nd fallback
|
||||
}
|
||||
@Test public void GetLabel__fallback_en() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("en", "en").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getLabel, Object_.Ary("q2"), "en"); // get en
|
||||
}
|
||||
@Test public void GetDescr() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_description("zh-hans", "s").Add_description("zh-hant", "t").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getDescription, Object_.Ary("q2"), "s");
|
||||
}
|
||||
@Test public void GetSlink() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_sitelink("enwiki", "a").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getSiteLinkPageName, Object_.Ary("q2"), "a");
|
||||
}
|
||||
@Test public void GetEntity() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("en", "b").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_wikibase.Invk_getEntity, Object_.Ary("q2", false), String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " id=q2"
|
||||
, " type=item"
|
||||
, " schemaVersion=2"
|
||||
, " labels="
|
||||
, " en="
|
||||
, " language=en"
|
||||
, " value=b"
|
||||
));
|
||||
}
|
||||
@Test public void GetEntity_property() { // PURPOSE: getEntity should be able to convert "p2" to "Property:P2"; EX:es.w:Arnold_Gesell; DATE:2014-02-18
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("Property:p2").Add_label("en", "b").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str_ary(lib, Scrib_lib_wikibase.Invk_getEntity, Object_.Ary("p2", false), String_.Concat_lines_nl_skip_last
|
||||
( "1="
|
||||
, " id=Property:p2" // only difference from above
|
||||
, " type=property" // also, type should be "property"; PAGE:ru.w:Викитека:Проект:Викиданные DATE:2016-11-23
|
||||
, " schemaVersion=2"
|
||||
, " labels="
|
||||
, " en="
|
||||
, " language=en"
|
||||
, " value=b"
|
||||
));
|
||||
}
|
||||
@Test public void ResolvePropertyId() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("Property:p2").Add_label("zh-hans", "prop_a").Xto_wdoc());
|
||||
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_resolvePropertyId, Object_.Ary("p2"), "prop_a");
|
||||
}
|
||||
@Test public void RenderSnaks() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snaks_ary(wdata_fxt, wdata_fxt.Make_claim_monolingual(3, "en", "P3_en"), wdata_fxt.Make_claim_monolingual(3, "de", "P3_de"));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnaks, args, "P3_en, P3_de");
|
||||
}
|
||||
@Test public void RenderSnak__entity() {
|
||||
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q3").Add_label("en", "test_label").Xto_wdoc());
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_entity_qid(2, 3));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "test_label");
|
||||
}
|
||||
@Test public void RenderSnak__str() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_string(3, "test_str"));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "test_str");
|
||||
}
|
||||
@Test public void RenderSnak__quantity() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_quantity(3, "123", "1", "125", "121")); // NOTE: entity-less units output "1"; EX:wd:Q493409 DATE:2016-11-08
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "123±2");
|
||||
}
|
||||
@Test public void RenderSnak__quantity__null_bounds() { // PURPOSE: handle null lbound / ubound; PAGE:wd.q:183 DATE:2016-12-03
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_quantity(3, "123", "1", null, null));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "123");
|
||||
}
|
||||
@Test public void RenderSnak__time() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_time(3, "2012-01-02 03:04:05"));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "30405 2 Jan 2012"); // NOTE: format is missing ":" b/c test does not init messages for html_wtr; DATE:2015-08-03
|
||||
}
|
||||
@Test public void RenderSnak__geo() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_geo(3, "3.4", "1.2"));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "1° 12' 0" E, 3° 24' 0" N (<a href='/wiki/Q2'>http://www.wikidata.org/entity/Q2</a>)");
|
||||
}
|
||||
@Test public void RenderSnak__monolingual() {
|
||||
Keyval[] args = Wbase_snak_utl_.Get_snak(wdata_fxt, wdata_fxt.Make_claim_monolingual(3, "en", "abc_en"));
|
||||
fxt.Test__proc__kvps__flat(lib, Scrib_lib_wikibase.Invk_renderSnak, args, "abc_en");
|
||||
}
|
||||
}
|
||||
class Wbase_snak_utl_ {
|
||||
public static Keyval[] Get_snaks_ary(Wdata_wiki_mgr_fxt wdata_fxt, Wbase_claim_base... ary) {
|
||||
Wdata_doc wdoc = wdata_fxt.Wdoc_bldr("q2").Add_claims(ary).Xto_wdoc();
|
||||
return Keyval_.Ary(Keyval_.int_(1, Get_snaks(wdata_fxt, wdoc)));
|
||||
}
|
||||
public static Keyval[] Get_snak(Wdata_wiki_mgr_fxt wdata_fxt, Wbase_claim_base itm) {
|
||||
Wdata_doc wdoc = wdata_fxt.Wdoc_bldr("q2").Add_claims(itm).Xto_wdoc();
|
||||
Keyval[] snak_props = Get_subs_by_path(Get_snaks(wdata_fxt, wdoc), 0);
|
||||
return Keyval_.Ary(Keyval_.int_(1, snak_props));
|
||||
}
|
||||
private static Keyval[] Get_snaks(Wdata_wiki_mgr_fxt wdata_fxt, Wdata_doc wdoc) {
|
||||
Keyval[] wdoc_root = Scrib_lib_wikibase_srl.Srl(wdata_fxt.Wdata_mgr().Prop_mgr(), wdoc, false, false);
|
||||
Keyval[] snaks = Get_subs_by_path(wdoc_root, 0, 0);
|
||||
int snaks_len = snaks.length;
|
||||
Keyval[] rv = new Keyval[snaks_len];
|
||||
for (int i = 0; i < snaks_len; ++i) {
|
||||
rv[i] = Keyval_.int_(i + List_adp_.Base1, Get_subs_by_path(snaks, i, 1));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Keyval[] Get_subs_by_path(Keyval[] root, int... levels) {
|
||||
int len = levels.length;
|
||||
Keyval[] rv = root;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
int idx = levels[i];
|
||||
rv = (Keyval[])rv[idx].Val();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.core.brys.fmtrs.*;
|
||||
import gplx.langs.regxs.*;
|
||||
public class Scrib_regx_converter {
|
||||
private final List_adp capt_list = List_adp_.New(), grps_parens = List_adp_.New(); private final List_adp grps_open = List_adp_.New();
|
||||
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
|
||||
public Scrib_regx_converter() {Init();}
|
||||
public String Regx() {return regx;} private String regx;
|
||||
public List_adp Capt_list() {return capt_list;}
|
||||
public Keyval[] Capt_ary() {return capt_list.Count() == 0 ? null : (Keyval[])capt_list.To_ary(Keyval.class);}
|
||||
private Bry_fmtr fmtr_balanced; private Bry_bfr bfr_balanced;
|
||||
public String Parse(byte[] src, byte[] anchor) {
|
||||
int len = src.length;
|
||||
boolean q_flag = false;
|
||||
capt_list.Clear(); grps_open.Clear(); grps_parens.Clear();
|
||||
int grps_len = 0;
|
||||
int bct = 0;
|
||||
// bfr.Add_byte(Byte_ascii.Slash); // NOTE: do not add PHP "/" at start
|
||||
for (int i = 0; i < len; i++) {
|
||||
q_flag = false; // must be reset; REF.MW:UstringLibrary.php|patternToRegex; DATE:2014-02-08
|
||||
byte cur = src[i];
|
||||
switch (cur) {
|
||||
case Byte_ascii.Pow:
|
||||
q_flag = i != 0;
|
||||
bfr.Add(anchor == Anchor_null || q_flag ? Bry_pow_escaped : anchor); // NOTE: must add anchor \G when using offsets; EX:cs.n:Category:1._zárí_2008; DATE:2014-05-07
|
||||
break;
|
||||
case Byte_ascii.Dollar:
|
||||
q_flag = i < len - 1;
|
||||
bfr.Add(q_flag ? Bry_dollar_escaped : Bry_dollar_literal);
|
||||
break;
|
||||
case Byte_ascii.Paren_bgn: {
|
||||
if (i + 1 >= len) throw Err_.new_wo_type("Unmatched open-paren at pattern character " + Int_.To_str(i));
|
||||
boolean capt_itm = src[i + 1] == Byte_ascii.Paren_end; // current is "()"
|
||||
++grps_len;
|
||||
capt_list.Add(Keyval_.int_(grps_len, capt_itm));
|
||||
bfr.Add_byte(Byte_ascii.Paren_bgn);
|
||||
grps_open.Add(grps_len);
|
||||
grps_parens.Add(i + 1);
|
||||
break;
|
||||
}
|
||||
case Byte_ascii.Paren_end:
|
||||
if (grps_open.Count() == 0)
|
||||
throw Err_.new_wo_type("Unmatched close-paren at pattern character " + Int_.To_str(i));
|
||||
List_adp_.Del_at_last(grps_open);
|
||||
bfr.Add_byte(Byte_ascii.Paren_end);
|
||||
break;
|
||||
case Byte_ascii.Percent:
|
||||
++i;
|
||||
if (i >= len) throw Err_.new_wo_type("malformed pattern (ends with '%')");
|
||||
Object percent_obj = percent_hash.Get_by_mid(src, i, i + 1);
|
||||
if (percent_obj != null) {
|
||||
bfr.Add((byte[])percent_obj);
|
||||
q_flag = true;
|
||||
}
|
||||
else {
|
||||
byte nxt = src[i];
|
||||
switch (nxt) {
|
||||
case Byte_ascii.Ltr_b: // EX: "%b()"
|
||||
i += 2;
|
||||
if (i >= len) throw Err_.new_wo_type("malformed pattern (missing arguments to '%b')");
|
||||
byte char_0 = src[i - 1];
|
||||
byte char_1 = src[i];
|
||||
if (char_0 == char_1) { // same char: easier regex; REF.MW: $bfr .= "{$d1}[^$d1]*$d1";
|
||||
bfr.Add(Bry_bf0_seg_0);
|
||||
Regx_quote(bfr, char_0);
|
||||
bfr.Add(Bry_bf0_seg_1);
|
||||
Regx_quote(bfr, char_0);
|
||||
bfr.Add(Bry_bf0_seg_2);
|
||||
Regx_quote(bfr, char_0);
|
||||
}
|
||||
else { // diff char: harder regex; REF.MW: $bfr .= "(?<b$bct>$d1(?:(?>[^$d1$d2]+)|(?P>b$bct))*$d2)";
|
||||
if (fmtr_balanced == null) {
|
||||
fmtr_balanced = Bry_fmtr.new_("(?<b~{0}>\\~{1}(?:(?>[^\\~{1}\\~{2}]*)|\\~{1}[^\\~{1}\\~{2}]*\\~{2})*\\~{2})", "0", "1", "2"); // NOTE: complicated regex; represents 3 level depth of balanced parens; 4+ won't work; EX:(3(2(1)2)3) PAGE:en.w:Electricity_sector_in_Switzerland DATE:2015-01-23
|
||||
bfr_balanced = Bry_bfr_.Reset(255);
|
||||
}
|
||||
synchronized (fmtr_balanced) {
|
||||
++bct;
|
||||
fmtr_balanced.Bld_bfr(bfr_balanced, Int_.To_bry(bct), Byte_.Ary(char_0), Byte_.Ary(char_1));
|
||||
bfr.Add(bfr_balanced.To_bry_and_clear());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Byte_ascii.Ltr_f: { // EX: lua frontier pattern; "%f[%a]"; DATE:2015-07-21
|
||||
++i;
|
||||
if (i + 1 >= len || src[i] != Byte_ascii.Brack_bgn) throw Err_.new_("scribunto", "missing '[' after %f in pattern at pattern character $ii");
|
||||
// %f always followed by bracketed term; convert lua bracketed term to regex
|
||||
i = bracketedCharSetToRegex(tmp_bfr, src, i, len);
|
||||
byte[] bracketed_regx = tmp_bfr.To_bry_and_clear();
|
||||
|
||||
// scrib has following comment: 'Because %f considers the beginning and end of the String to be \0, determine if $re2 matches that and take it into account with "^" and "$".'
|
||||
// if the bracketed_regx is a negative class it will match \0; so, \W means anything not a word char, which will match \0; \w means word char which will not match \0
|
||||
if (Regx_adp_.Match("\0", String_.new_u8(bracketed_regx)))
|
||||
bfr.Add_str_a7("(?<!^)(?<!").Add(bracketed_regx).Add_str_a7(")(?=").Add(bracketed_regx).Add_str_a7("|$)"); // match bgn / end of String
|
||||
else
|
||||
bfr .Add_str_a7("(?<!").Add(bracketed_regx).Add_str_a7(")(?=").Add(bracketed_regx).Add_str_a7( ")");
|
||||
break;
|
||||
}
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
grps_len = nxt - Byte_ascii.Num_0;
|
||||
if (grps_len == 0 || grps_len > capt_list.Count() || grps_open_Has(grps_open, grps_len))
|
||||
throw Err_.new_wo_type("invalid capture index %" + grps_len + " at pattern character " + Int_.To_str(i));
|
||||
bfr.Add(Bry_bf2_seg_0).Add_int_variable(grps_len);//.Add(Bry_bf2_seg_1); // $bfr .= "\\g{m$grps_len}";
|
||||
break;
|
||||
default:
|
||||
Regx_quote(bfr, nxt);
|
||||
q_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Byte_ascii.Brack_bgn:
|
||||
i = bracketedCharSetToRegex(bfr, src, i, len);
|
||||
q_flag = true;
|
||||
break;
|
||||
case Byte_ascii.Brack_end: throw Err_.new_wo_type("Unmatched close-bracket at pattern character " + Int_.To_str(i));
|
||||
case Byte_ascii.Dot:
|
||||
q_flag = true;
|
||||
bfr.Add_byte(Byte_ascii.Dot);
|
||||
break;
|
||||
default:
|
||||
q_flag = true;
|
||||
Regx_quote(bfr, cur);
|
||||
break;
|
||||
}
|
||||
if (q_flag && i + 1 < len) {
|
||||
byte tmp_b = src[i + 1];
|
||||
switch (tmp_b) {
|
||||
case Byte_ascii.Star:
|
||||
case Byte_ascii.Plus:
|
||||
case Byte_ascii.Question:
|
||||
bfr.Add_byte(tmp_b);
|
||||
++i;
|
||||
break;
|
||||
case Byte_ascii.Dash:
|
||||
bfr.Add(Bry_regx_dash);
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (grps_open.Count() > 0) throw Err_.new_wo_type("Unclosed capture beginning at pattern character " + Int_.cast(grps_open.Get_at(0)));
|
||||
// bfr.Add(Bry_regx_end); // NOTE: do not add PHP /us at end; u=PCRE_UTF8 which is not needed for Java; s=PCRE_DOTALL which will be specified elsewhere
|
||||
regx = bfr.To_str_and_clear();
|
||||
return regx;
|
||||
} private Bry_bfr bfr = Bry_bfr_.New();
|
||||
private int bracketedCharSetToRegex(Bry_bfr bfr, byte[] src, int i, int len) {
|
||||
bfr.Add_byte(Byte_ascii.Brack_bgn);
|
||||
++i;
|
||||
if (i < len && src[i] == Byte_ascii.Pow) { // ^
|
||||
bfr.Add_byte(Byte_ascii.Pow);
|
||||
++i;
|
||||
}
|
||||
boolean stop = false;
|
||||
for (; i < len; i++) {
|
||||
byte tmp_b = src[i];
|
||||
switch (tmp_b) {
|
||||
case Byte_ascii.Brack_end:
|
||||
stop = true;
|
||||
break;
|
||||
case Byte_ascii.Percent:
|
||||
++i;
|
||||
if (i >= len)
|
||||
stop = true;
|
||||
else {
|
||||
Object brack_obj = brack_hash.Get_by_mid(src, i, i + 1);
|
||||
if (brack_obj != null)
|
||||
bfr.Add((byte[])brack_obj);
|
||||
else
|
||||
Regx_quote(bfr, src[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
boolean normal = true;
|
||||
int lhs_pos = i; // NOTE: following block handles MBCS; EX:[𠀀-] PAGE:en.d:どう DATE:2016-01-22
|
||||
int lhs_len = gplx.core.intls.Utf8_.Len_of_char_by_1st_byte(src[lhs_pos]);
|
||||
int dash_pos = i + lhs_len;
|
||||
if (dash_pos < len) {
|
||||
byte dash_char = src[dash_pos];
|
||||
if (dash_char == Byte_ascii.Dash) {
|
||||
int rhs_pos = dash_pos + 1;
|
||||
if (rhs_pos < len) {
|
||||
byte rhs_byte = src[rhs_pos];
|
||||
if (rhs_byte != Byte_ascii.Brack_end) {// ignore dash if followed by brack_end; EX: [a-]; PAGE:en.d:frei; DATE:2016-01-23
|
||||
int rhs_len = gplx.core.intls.Utf8_.Len_of_char_by_1st_byte(rhs_byte);
|
||||
if (lhs_len == 1)
|
||||
Regx_quote(bfr, src[i]);
|
||||
else
|
||||
bfr.Add_mid(src, i, i + lhs_len);
|
||||
bfr.Add_byte(Byte_ascii.Dash);
|
||||
if (rhs_len == 1)
|
||||
Regx_quote(bfr, src[rhs_pos]);
|
||||
else
|
||||
bfr.Add_mid(src, rhs_pos, rhs_pos + rhs_len);
|
||||
i = rhs_pos + rhs_len - 1; // -1 b/c for() will do ++i
|
||||
normal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (normal)
|
||||
Regx_quote(bfr, src[i]);
|
||||
break;
|
||||
}
|
||||
if (stop) break;
|
||||
}
|
||||
if (i >= len) throw Err_.new_wo_type("Missing close-bracket for character set beginning at pattern character $nxt_pos");
|
||||
bfr.Add_byte(Byte_ascii.Brack_end);
|
||||
return i;
|
||||
}
|
||||
boolean grps_open_Has(List_adp list, int v) {
|
||||
int len = list.Count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Object o = list.Get_at(i);
|
||||
if (Int_.cast(o) == v) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void Regx_quote(Bry_bfr bfr, byte b) {
|
||||
if (Regx_char(b)) bfr.Add_byte(Byte_ascii.Backslash);
|
||||
bfr.Add_byte(b);
|
||||
}
|
||||
private boolean Regx_char(byte b) {
|
||||
switch (b) {
|
||||
case Byte_ascii.Dot: case Byte_ascii.Slash: case Byte_ascii.Plus: case Byte_ascii.Star: case Byte_ascii.Question:
|
||||
case Byte_ascii.Pow: case Byte_ascii.Dollar: case Byte_ascii.Eq: case Byte_ascii.Bang: case Byte_ascii.Pipe:
|
||||
case Byte_ascii.Colon: case Byte_ascii.Dash:
|
||||
case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end: case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Curly_bgn: case Byte_ascii.Curly_end:
|
||||
case Byte_ascii.Lt: case Byte_ascii.Gt:
|
||||
case Byte_ascii.Backslash: // \ must be preg_quote'd; DATE:2014-01-06
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private static final byte[] Bry_pow_escaped = Bry_.new_a7("\\^")
|
||||
, Bry_dollar_literal = Bry_.new_a7("$"), Bry_dollar_escaped = Bry_.new_a7("\\$")
|
||||
, Bry_bf0_seg_0 = Bry_.new_a7("{"), Bry_bf0_seg_1 = Bry_.new_a7("}[^"), Bry_bf0_seg_2 = Bry_.new_a7("]*")
|
||||
, Bry_bf2_seg_0 = Bry_.new_a7("\\")//, Bry_bf2_seg_1 = Bry_.new_a7("")
|
||||
, Bry_regx_dash = Bry_.new_a7("*?") // was *?
|
||||
;
|
||||
public static final byte[] Anchor_null = null, Anchor_G = Bry_.new_a7("\\G"), Anchor_pow = Bry_.new_a7("^");
|
||||
private void Init() {
|
||||
String regx_w = "\\w"; // JRE.7: \w not support in JRE.6; PAGE:en.w:A♯_(musical_note) DATE:2015-06-10
|
||||
String regx_W = "\\W"; // JRE.7: \w not support in JRE.6; PAGE:en.w:A♯_(musical_note) DATE:2015-06-10
|
||||
Init_itm(Bool_.Y, "d", "\\p{Nd}");
|
||||
Init_itm(Bool_.Y, "l", "\\p{Ll}");
|
||||
Init_itm(Bool_.Y, "u", "\\p{Lu}");
|
||||
Init_itm(Bool_.Y, "a", "\\p{L}");
|
||||
Init_itm(Bool_.Y, "c", "\\p{Cc}");
|
||||
Init_itm(Bool_.Y, "p", "\\p{P}");
|
||||
Init_itm(Bool_.Y, "s", "\\s");
|
||||
Init_itm(Bool_.Y, "w", regx_w);
|
||||
Init_itm(Bool_.Y, "x", "[0-9A-Fa-f0-9A-Fa-f]");
|
||||
Init_itm(Bool_.Y, "z", "\\x00");
|
||||
Init_itm(Bool_.Y, "D", "\\P{Nd}");
|
||||
Init_itm(Bool_.Y, "L", "\\P{Ll}");
|
||||
Init_itm(Bool_.Y, "U", "\\P{Lu}");
|
||||
Init_itm(Bool_.Y, "A", "\\P{L}");
|
||||
Init_itm(Bool_.Y, "C", "\\P{Cc}");
|
||||
Init_itm(Bool_.Y, "P", "\\P{P}");
|
||||
Init_itm(Bool_.Y, "S", "\\S"); // JAVA: \P{Xps} not valid
|
||||
Init_itm(Bool_.Y, "W", regx_W);
|
||||
Init_itm(Bool_.Y, "X", "[^0-9A-Fa-f0-9A-Fa-f]");
|
||||
Init_itm(Bool_.Y, "Z", "[^\\x00]");
|
||||
Init_itm(Bool_.N, "w", regx_w);
|
||||
Init_itm(Bool_.N, "x", "0-9A-Fa-f0-9A-Fa-f");
|
||||
Init_itm(Bool_.N, "W", regx_W);
|
||||
Init_itm(Bool_.N, "X", "\\x00-\\x2f\\x3a-\\x40\\x47-\\x60\\x67-\\x{ff0f}\\x{ff1a}-\\x{ff20}\\x{ff27}-\\x{ff40}\\x{ff47}-\\x{10ffff}");
|
||||
Init_itm(Bool_.N, "Z", "\\x01-\\x{10ffff}");
|
||||
}
|
||||
private void Init_itm(boolean add_to_percent_hash, String lua, String php) {
|
||||
byte[] lua_bry = Bry_.new_a7(lua);
|
||||
byte[] php_bry = Bry_.new_a7(php);
|
||||
if (add_to_percent_hash) {
|
||||
percent_hash.Add_bry_obj(lua_bry, php_bry);
|
||||
brack_hash.Add_bry_obj(lua_bry, php_bry); // always add to brack_hash; brack_hash = percent_hash + other characters
|
||||
}
|
||||
else {
|
||||
brack_hash.Add_if_dupe_use_nth(lua_bry, php_bry); // replace percent_hash definitions
|
||||
}
|
||||
}
|
||||
private final Hash_adp_bry percent_hash = Hash_adp_bry.cs(), brack_hash = Hash_adp_bry.cs();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.langs.regxs.*;
|
||||
public class Scrib_regx_converter_tst {
|
||||
@Before public void init() {fxt.Clear();} private Scrib_regx_converter_fxt fxt = new Scrib_regx_converter_fxt();
|
||||
@Test public void Basic() {fxt.Test_parse("abc012ABC" , "abc012ABC");}
|
||||
@Test public void Pow_0() {fxt.Test_parse("^a" , "\\Ga");}
|
||||
@Test public void Pow_1() {fxt.Test_parse("a^b" , "a\\^b");}
|
||||
@Test public void Dollar_n() {fxt.Test_parse("$a" , "\\$a");}
|
||||
@Test public void Dollar_last() {fxt.Test_parse("a$" , "a$");}
|
||||
@Test public void Dot() {fxt.Test_parse("a." , "a.");}
|
||||
// @Test public void Paren() {fxt.Test_parse("(a)" , "(?<m1>a)");}
|
||||
@Test public void Percent_has() {fxt.Test_parse("%a" , "\\p{L}");}
|
||||
@Test public void Percent_na() {fxt.Test_parse("%y" , "y");}
|
||||
@Test public void Percent_b00() {fxt.Test_parse("%b00" , "{0}[^0]*0");}
|
||||
@Test public void Percent_b01() {fxt.Test_parse("%b01" , "(?<b1>\\0(?:(?>[^\\0\\1]*)|\\0[^\\0\\1]*\\1)*\\1)");}
|
||||
// @Test public void Percent_num() {fxt.Test_parse("()%1" , "(?<m1>)\\g{m1}");}
|
||||
@Test public void Percent_text() {fxt.Test_parse("%e" , "e");}
|
||||
@Test public void Brack_pow() {fxt.Test_parse("[^a]" , "[^a]");}
|
||||
@Test public void Brack_percent_a() {fxt.Test_parse("[%a]" , "[\\p{L}]");} // NOTE: was previously [a]; DATE:2013-11-08
|
||||
@Test public void Brack_dash() {fxt.Test_parse("[a-z]" , "[a-z]");}
|
||||
@Test public void Brack_num() {fxt.Test_parse("[%d]" , "[\\p{Nd}]");}
|
||||
@Test public void Brack_text() {fxt.Test_parse("[abc]" , "[abc]");}
|
||||
@Test public void Null() {fxt.Test_parse("[%z]" , "[\\x00]");}
|
||||
@Test public void Null_not() {fxt.Test_parse("%Z" , "[^\\x00]");}
|
||||
@Test public void Backslash() {fxt.Test_parse("\\" , "\\\\");} // PURPOSE: make sure \ is preg_quote'd; DATE:2014-01-06
|
||||
@Test public void Ex_url() {fxt.Test_parse("^%s*(.-)%s*$" , "\\G\\s*(.*?)\\s*$");}
|
||||
@Test public void Balanced() {
|
||||
fxt.Test_replace("a(1)c" , "%b()", "b", "abc");
|
||||
fxt.Test_replace("a(2(1)2)c" , "%b()", "b", "abc");
|
||||
fxt.Test_replace("a(3(2(1)2)3)c" , "%b()", "b", "a(3b3)c");
|
||||
}
|
||||
@Test public void Mbcs() { // PURPOSE: handle regex for multi-byte chars; PAGE:en.d:どう; DATE:2016-01-22; .NET.REGX:fails
|
||||
fxt.Test_replace("𠀀" , "[𠀀-]" , "a", "a");
|
||||
}
|
||||
}
|
||||
class Scrib_regx_converter_fxt {
|
||||
private Scrib_regx_converter under;
|
||||
public void Clear() {
|
||||
if (under == null) {
|
||||
under = new Scrib_regx_converter();
|
||||
}
|
||||
}
|
||||
public void Test_parse(String raw, String expd) {
|
||||
under.Parse(Bry_.new_u8(raw), Scrib_regx_converter.Anchor_G);
|
||||
Tfds.Eq(expd, under.Regx());
|
||||
}
|
||||
public void Test_replace(String text, String find, String replace, String expd) {
|
||||
String regex_str = under.Parse(Bry_.new_u8(find), Scrib_regx_converter.Anchor_G);
|
||||
String actl = Regx_adp_.Replace(text, regex_str, replace);
|
||||
Tfds.Eq(expd, actl);
|
||||
}
|
||||
}
|
||||
41
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Xow_wiki_tst.java
Normal file
41
400_xowa/src/gplx/xowa/xtns/scribunto/libs/Xow_wiki_tst.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*;
|
||||
public class Xow_wiki_tst {
|
||||
@Before public void init() {fxt.Clear();} private Xow_wiki_fxt fxt = new Xow_wiki_fxt();
|
||||
@Test public void Load_page_and_parse() { // PURPOSE.fix: unknown page causes null reference error in scribunto; DATE:2013-08-27
|
||||
fxt.Fxt().Wiki().Parser_mgr().Scrib().Core_init(fxt.Fxt().Ctx());
|
||||
fxt.Test_getPageByTtl("Does_not_exist", null);
|
||||
}
|
||||
}
|
||||
class Xow_wiki_fxt {
|
||||
public void Clear() {
|
||||
fxt = new Xop_fxt();
|
||||
}
|
||||
public Xop_fxt Fxt() {return fxt;} private Xop_fxt fxt;
|
||||
public void Test_getPageByTtl(String ttl_str, String expd) {
|
||||
Xowe_wiki wiki = fxt.Wiki();
|
||||
byte[] ttl_bry = Bry_.new_a7(ttl_str);
|
||||
Xoa_url url = Xoa_url.New(wiki.Domain_bry(), ttl_bry);
|
||||
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry);
|
||||
Xoae_page actl = fxt.Wiki().Data_mgr().Load_page_and_parse(url, ttl);
|
||||
if (expd == null) Tfds.Eq_true(actl.Db().Page().Exists_n());
|
||||
else Tfds.Eq(expd, String_.new_u8(actl.Ttl().Raw()));
|
||||
}
|
||||
}
|
||||
32
400_xowa/src/gplx/xowa/xtns/scribunto/procs/Scrib_proc.java
Normal file
32
400_xowa/src/gplx/xowa/xtns/scribunto/procs/Scrib_proc.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.procs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import gplx.xowa.xtns.scribunto.libs.*;
|
||||
public class Scrib_proc {
|
||||
private Scrib_lib lib;
|
||||
public Scrib_proc(Scrib_lib lib, String proc_name, int proc_id) {
|
||||
this.lib = lib;
|
||||
this.proc_name = proc_name;
|
||||
this.proc_key = Scrib_core.Key_mw_interface + "-" + proc_name;
|
||||
this.proc_id = proc_id;
|
||||
}
|
||||
public String Proc_name() {return proc_name;} private String proc_name;
|
||||
public int Proc_id() {return proc_id;} private int proc_id;
|
||||
public String Proc_key() {return proc_key;} private String proc_key;
|
||||
public boolean Proc_exec(Scrib_proc_args args, Scrib_proc_rslt rslt) {return lib.Procs_exec(proc_id, args, rslt);}
|
||||
}
|
||||
186
400_xowa/src/gplx/xowa/xtns/scribunto/procs/Scrib_proc_args.java
Normal file
186
400_xowa/src/gplx/xowa/xtns/scribunto/procs/Scrib_proc_args.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.procs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public class Scrib_proc_args {
|
||||
private Keyval[] ary; private int ary_len;
|
||||
public Scrib_proc_args(Keyval[] v) {
|
||||
// if 0 members, standardize to Keyval_.Ary_empty; could possibly find all callers of new Scrib_arg() and make sure that 0 == empty, but this is easier
|
||||
int v_len = v.length;
|
||||
if (v_len == 0) {
|
||||
ary = Keyval_.Ary_empty;
|
||||
ary_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// find ary_len
|
||||
int v_max = -1;
|
||||
for (int i = 0; i < v_len; ++i) {
|
||||
Keyval kv = v[i];
|
||||
int idx = Int_.cast(kv.Key_as_obj());
|
||||
if (v_max < idx) v_max = idx;
|
||||
}
|
||||
this.ary_len = v_max;
|
||||
|
||||
// keys are in sequential order; EX: [1:a,2:b,3:c]
|
||||
if (v_max == v_len)
|
||||
this.ary = v;
|
||||
// keys are not in sequential order, or there are gaps; EX: [1:a,3:c]
|
||||
else {
|
||||
ary = new Keyval[ary_len];
|
||||
for (int i = 0; i < v_len; i++) {
|
||||
Keyval kv = v[i];
|
||||
int idx = Int_.cast(kv.Key_as_obj());
|
||||
ary[idx - List_adp_.Base1] = kv;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Len() {return ary_len;}
|
||||
public Keyval[] Ary() {return ary;}
|
||||
public Object Pull_obj(int i) {return Get_or_fail(i);}
|
||||
public boolean Pull_bool(int i) {return Bool_.Cast(Get_or_fail(i));}
|
||||
public String Pull_str(int i) {return String_.cast(Get_or_fail(i));}
|
||||
public byte[] Pull_bry(int i) {return Bry_.new_u8(String_.cast(Get_or_fail(i)));}
|
||||
public int Pull_int(int i) {
|
||||
try {return Int_.coerce_(Get_or_fail(i));} // coerce to handle "1" and 1; will still fail if "abc" is passed
|
||||
catch (Exception e) {
|
||||
Err_.Noop(e);
|
||||
throw Err_.new_wo_type("bad argument; int expected", "idx", i, "len", ary_len);
|
||||
}
|
||||
}
|
||||
public long Pull_long(int i) {return (long)Pull_double(i);}
|
||||
public double Pull_double(int i) {
|
||||
Object rv = Get_or_fail(i);
|
||||
try {return Int_.coerce_(rv);} // coerce to handle "1" and 1; will still fail if "abc" is passed
|
||||
catch (Exception e) {
|
||||
Err_.Noop(e);
|
||||
try {return Double_.coerce_(rv);} // coerce to handle "1" and 1; will still fail if "abc" is passed
|
||||
catch (Exception e2) {
|
||||
Err_.Noop(e2);
|
||||
throw Err_.new_wo_type("bad argument; int expected", "idx", i, "len", ary_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
public Keyval[] Pull_kv_ary_safe(int idx) { // NOTE: must check for null array items; EX:[1:a,3:c] -> [1:a,2:null,3:c]; PAGE:en.d:Category:Nouns_by_language DATE:2016-04-29
|
||||
Keyval[] rv = (Keyval[])Get_or_fail(idx);
|
||||
int rv_len = rv.length;
|
||||
|
||||
List_adp list = null; // list for out-of-order; lazy-instantiation
|
||||
int prv_key = -1; // mark previous itm_key; needed to reconstruct keys for gaps
|
||||
// loop itms and handle out-of-order; note that in most cases, itms should be in-order and proc will just return rv; DATE:2016-09-12
|
||||
for (int i = 0; i < rv_len; ++i) {
|
||||
Keyval kv = rv[i];
|
||||
// get integer-key; needed to handle gaps
|
||||
if ( kv.Key_tid() == Type_adp_.Tid__int // luaj will be int
|
||||
|| kv.Key_tid() == Type_adp_.Tid__obj) { // lua will be obj; note that luaj will also have other non-key objects
|
||||
Object key_obj = kv.Key_as_obj();
|
||||
if (key_obj.getClass() == Int_.Cls_ref_type) { // key is int; cast it
|
||||
int expd_key = i + List_adp_.Base1; // EX: i=1; expd_key=2
|
||||
int actl_key = Int_.cast(kv.Key_as_obj()); // EX: i=1; actl_key=3
|
||||
if (actl_key != expd_key) { // mismatch; gaps exist; EX:[1:a,3:c]
|
||||
// 1st mismatch; create list, and add everything before itm in array to list;
|
||||
if (list == null) {
|
||||
list = List_adp_.New();
|
||||
for (int j = 0; j < i; ++j)
|
||||
list.Add(rv[j]); // NOTE: everything before i is in sequence, so just add it directly
|
||||
prv_key = i + 1; // EX: i=1; prv_key=2;
|
||||
}
|
||||
for (int j = prv_key; j < actl_key; ++j) // add everything up to actl_key as null; EX: [1:a,3:c] -> [1:a,2:null]
|
||||
list.Add(Keyval_.int_(j, null));
|
||||
prv_key = actl_key + 1; // EX: i=3; prv_key=4
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
list.Add(kv);
|
||||
}
|
||||
return (list == null)
|
||||
? rv
|
||||
: (Keyval[])list.To_ary(Keyval.class);
|
||||
}
|
||||
public String Cast_str_or(int i, String or) {Object rv = Get_or_null(i); return rv == null ? or : String_.cast (rv);}
|
||||
public String Cast_str_or_null(int i) {Object rv = Get_or_null(i); return rv == null ? null : String_.cast (rv);}
|
||||
public byte[] Cast_bry_or_null(int i) {Object rv = Get_or_null(i); return rv == null ? null : Bry_.new_u8(String_.cast (rv));} // NOTE: cast is deliberate; Scrib call checkType whi
|
||||
public byte[] Cast_bry_or_empty(int i) {Object rv = Get_or_null(i); return rv == null ? Bry_.Empty : Bry_.new_u8(String_.cast (rv));}
|
||||
public byte[] Cast_bry_or(int i, byte[] or) {Object rv = Get_or_null(i); return rv == null ? or : Bry_.new_u8(String_.cast (rv));}
|
||||
public Object Cast_obj_or_null(int i) {return Get_or_null(i);}
|
||||
public boolean Cast_bool_or_y(int i) {Object rv = Get_or_null(i); return rv == null ? Bool_.Y : Bool_.Cast(rv);}
|
||||
public boolean Cast_bool_or_n(int i) {Object rv = Get_or_null(i); return rv == null ? Bool_.N : Bool_.Cast(rv);}
|
||||
public int Cast_int_or(int i, int or) {Object rv = Get_or_null(i); return rv == null ? or : Int_.coerce_(rv);} // coerce to handle "1" and 1;
|
||||
public Keyval[] Cast_kv_ary_or_null(int i) {Object rv = Get_or_null(i); return rv == null ? null : (Keyval[])rv;}
|
||||
public byte[][] Cast_params_as_bry_ary_or_rest_of_ary(int params_idx) { // PAGE:ru.w:Ленин,_Владимир_Ильич; DATE:2014-07-01 MW:LanguageLibrary.php|ConvertPlural: if (is_array($args[0])) $args = $args[0]; $forms = array_values(array_map('strval', $args));
|
||||
if (params_idx < 0 || params_idx >= ary_len) return Bry_.Ary_empty;
|
||||
Object o = ary[params_idx].Val();
|
||||
if (Type_adp_.Eq_typeSafe(o, Keyval[].class)) {
|
||||
Keyval[] tbl = (Keyval[])o;
|
||||
int rv_len = tbl.length;
|
||||
byte[][] rv = new byte[rv_len][];
|
||||
for (int i = 0; i < rv_len; i++) {
|
||||
Keyval itm = tbl[i];
|
||||
rv[i] = Bry_.new_u8(String_.cast(itm.Val()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
int rv_len = ary_len - params_idx;
|
||||
byte[][] rv = new byte[rv_len][];
|
||||
for (int i = 0; i < rv_len; i++) {
|
||||
Keyval itm = ary[i + params_idx];
|
||||
rv[i] = Bry_.new_u8(String_.cast(itm.Val()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
public String Xstr_str_or_null(int i) {Object rv = Get_or_null(i); return rv == null ? null : Object_.Xto_str_loose_or(rv, null);} // NOTE: Modules can throw exceptions in which return value is nothing; do not fail; return ""; EX: -logy; DATE:2013-10-14
|
||||
public byte[] Xstr_bry_or_null(int i) {Object rv = Get_or_null(i); return rv == null ? null : Bry_.new_u8(Object_.Xto_str_loose_or(rv, null));}
|
||||
public byte[] Extract_qry_args(Xowe_wiki wiki, int idx) {
|
||||
Object qry_args_obj = Cast_obj_or_null(idx);
|
||||
if (qry_args_obj == null) return Bry_.Empty;
|
||||
Class<?> qry_args_cls = Type_adp_.ClassOf_obj(qry_args_obj);
|
||||
if (qry_args_cls == String.class)
|
||||
return Bry_.new_u8((String)qry_args_obj);
|
||||
else if (qry_args_cls == Keyval[].class) {
|
||||
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b128();
|
||||
Keyval[] kvs = (Keyval[])qry_args_obj;
|
||||
int len = kvs.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Keyval kv = kvs[i];
|
||||
if (i != 0) bfr.Add_byte(Byte_ascii.Amp);
|
||||
bfr.Add_str_u8(kv.Key());
|
||||
bfr.Add_byte(Byte_ascii.Eq);
|
||||
bfr.Add_str_u8(kv.Val_to_str_or_empty());
|
||||
}
|
||||
return bfr.To_bry_and_rls();
|
||||
}
|
||||
else {
|
||||
wiki.Appe().Usr_dlg().Warn_many("", "", "unknown type for GetUrl query args: ~{0}", Type_adp_.NameOf_type(qry_args_cls));
|
||||
return Bry_.Empty;
|
||||
}
|
||||
}
|
||||
private Object Get_or_null(int i) {
|
||||
if (i < 0 || i >= ary_len) return null;
|
||||
Keyval kv = ary[i];
|
||||
return kv == null ? null : kv.Val();
|
||||
}
|
||||
private Object Get_or_fail(int i) {
|
||||
if (i < 0 || i >= ary_len) throw Err_.new_wo_type("bad argument: nil", "idx", i, "len", ary_len);
|
||||
Keyval kv = ary[i];
|
||||
Object rv = kv == null ? null : kv.Val();
|
||||
if (rv == null) throw Err_.new_wo_type("scrib arg is null", "idx", i, "len", ary_len);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.procs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
import org.junit.*; import gplx.core.tests.*;
|
||||
public class Scrib_proc_args__tst {
|
||||
private final Scrib_proc_args__fxt fxt = new Scrib_proc_args__fxt();
|
||||
@Test public void Pull_kv_ary__basic() { // PURPOSE.assert:
|
||||
fxt.Init(Keyval_.int_(1, Keyval_.Ary(Keyval_.int_(1, "a"), Keyval_.int_(2, "b"), Keyval_.int_(3, "c"))));
|
||||
fxt.Test__pull_kv_ary(0, Keyval_.int_(1, "a"), Keyval_.int_(2, "b"), Keyval_.int_(3, "c"));
|
||||
}
|
||||
@Test public void Pull_kv_ary__gaps() { // PURPOSE.fix: gaps cause null-ref; PAGE:en.w:Shalkar_District DATE:2016-09-12
|
||||
fxt.Init(Keyval_.int_(1, Keyval_.Ary(Keyval_.int_(1, "a"), Keyval_.int_(3, "c"), Keyval_.int_(5, "e"))));
|
||||
fxt.Test__pull_kv_ary(0, Keyval_.int_(1, "a"), Keyval_.int_(2, null), Keyval_.int_(3, "c"), Keyval_.int_(4, null), Keyval_.int_(5, "e"));
|
||||
}
|
||||
@Test public void Pull_kv_ary__gaps__many() { // PURPOSE.assert:
|
||||
fxt.Init(Keyval_.int_(1, Keyval_.Ary(Keyval_.int_(1, "a"), Keyval_.int_(4, "d"), Keyval_.int_(5, "e"), Keyval_.int_(8, "h"))));
|
||||
fxt.Test__pull_kv_ary(0
|
||||
, Keyval_.int_(1, "a"), Keyval_.int_(2, null), Keyval_.int_(3, null), Keyval_.int_(4, "d"), Keyval_.int_(5, "e")
|
||||
, Keyval_.int_(6, null), Keyval_.int_(7, null), Keyval_.int_(8, "h")
|
||||
);
|
||||
}
|
||||
}
|
||||
class Scrib_proc_args__fxt {
|
||||
private Scrib_proc_args args;
|
||||
public void Init(Keyval... ary) {this.args = new Scrib_proc_args(ary);}
|
||||
public void Test__pull_kv_ary(int idx, Keyval... expd) {
|
||||
Keyval[] actl = args.Pull_kv_ary_safe(idx);
|
||||
Gftest.Eq__str(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.procs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public class Scrib_proc_mgr {
|
||||
private final Ordered_hash hash = Ordered_hash_.New();
|
||||
public void Clear() {hash.Clear();}
|
||||
public Scrib_proc Get_by_key(String key) {synchronized (hash) {return (Scrib_proc)hash.Get_by(key);}}
|
||||
public Scrib_proc Get_at(int i) {synchronized (hash) {return (Scrib_proc)hash.Get_at(i);}}
|
||||
public void Set(String key, Scrib_proc proc) {
|
||||
hash.Add_if_dupe_use_nth(key, proc); // WORKAROUND: Add_if_dupe_use_nth b/c some libraries reuse proc name; EX: getGlobalSiteId is used by mw.wikibase.lua and mw.wikibase.entity.lua
|
||||
}
|
||||
public Scrib_proc Set(Scrib_lib lib, String proc_name, int proc_id) {
|
||||
Scrib_proc proc = new Scrib_proc(lib, proc_name, proc_id);
|
||||
Set(proc.Proc_key(), proc);
|
||||
return proc;
|
||||
}
|
||||
public int Len() {synchronized (hash) {return hash.Count();}}
|
||||
public void Init_by_lib(Scrib_lib lib, String[] proc_names) {
|
||||
synchronized (hash) {
|
||||
hash.Clear();
|
||||
int len = proc_names.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
String proc_name = proc_names[i];
|
||||
Scrib_proc proc = new Scrib_proc(lib, proc_name, i); // ASSUME: Proc_id consts matches order in which Init is called
|
||||
hash.Add(proc_name, proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.scribunto.procs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
|
||||
public class Scrib_proc_rslt {
|
||||
private Keyval[] ary;
|
||||
public Keyval[] Ary() {return ary;}
|
||||
public String Fail_msg() {return fail_msg;} private String fail_msg;
|
||||
public boolean Init_fail(String v) {fail_msg = v; return false;}
|
||||
public boolean Init_null() {Init_obj(null); return true;} // return array(null);
|
||||
public boolean Init_str_empty() {Init_obj(""); return true;}
|
||||
public boolean Init_ary_empty() {ary = Keyval_.Ary_empty; return true;}
|
||||
public boolean Init_obj(Object val) {
|
||||
ary = new Keyval[] {Keyval_.int_(Scrib_core.Base_1, val)};
|
||||
return true;
|
||||
}
|
||||
public boolean Init_many_objs(Object... vals) {
|
||||
int len = vals.length;
|
||||
ary = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
ary[i] = Keyval_.int_(i + Scrib_core.Base_1, vals[i]);
|
||||
return true;
|
||||
}
|
||||
public boolean Init_many_kvs(Keyval... kvs) {
|
||||
ary = kvs;
|
||||
return true;
|
||||
}
|
||||
public boolean Init_many_list(List_adp list) {
|
||||
int len = list.Count();
|
||||
ary = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
ary[i] = Keyval_.int_(i + Scrib_core.Base_1, list.Get_at(i));
|
||||
list.Clear();
|
||||
return true;
|
||||
}
|
||||
public boolean Init_many_empty() {
|
||||
ary = Keyval_.Ary_empty;
|
||||
return true;
|
||||
}
|
||||
public boolean Init_bry_ary(byte[][] v) { // NOTE:fallbacks should return "table {fallback_1, fallback_2}"; PAGE:wd:Main_Page DATE:2015-04-21
|
||||
int len = v.length;
|
||||
Keyval[] itms = new Keyval[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
itms[i] = Keyval_.int_(i + Scrib_core.Base_1, String_.new_u8(v[i]));
|
||||
this.ary = new Keyval[] {Keyval_.int_(Scrib_core.Base_1, itms)};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user