mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-23 02:00:25 +01:00
764 lines
21 KiB
GDScript
764 lines
21 KiB
GDScript
|
# ##############################################################################
|
||
|
#(G)odot (U)nit (T)est class
|
||
|
#
|
||
|
# ##############################################################################
|
||
|
# The MIT License (MIT)
|
||
|
# =====================
|
||
|
#
|
||
|
# Copyright (c) 2020 Tom "Butch" Wesley
|
||
|
#
|
||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
# of this software and associated documentation files (the "Software"), to deal
|
||
|
# in the Software without restriction, including without limitation the rights
|
||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
# copies of the Software, and to permit persons to whom the Software is
|
||
|
# furnished to do so, subject to the following conditions:
|
||
|
#
|
||
|
# The above copyright notice and this permission notice shall be included in
|
||
|
# all copies or substantial portions of the Software.
|
||
|
#
|
||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
# THE SOFTWARE.
|
||
|
#
|
||
|
# ##############################################################################
|
||
|
# Description
|
||
|
# -----------
|
||
|
# ##############################################################################
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Utility class to hold the local and built in methods separately. Add all local
|
||
|
# methods FIRST, then add built ins.
|
||
|
# ------------------------------------------------------------------------------
|
||
|
class ScriptMethods:
|
||
|
# List of methods that should not be overloaded when they are not defined
|
||
|
# in the class being doubled. These either break things if they are
|
||
|
# overloaded or do not have a "super" equivalent so we can't just pass
|
||
|
# through.
|
||
|
var _blacklist = [
|
||
|
"has_method",
|
||
|
"get_script",
|
||
|
"get",
|
||
|
"_notification",
|
||
|
"get_path",
|
||
|
"_enter_tree",
|
||
|
"_exit_tree",
|
||
|
"_process",
|
||
|
"_draw",
|
||
|
"_physics_process",
|
||
|
"_input",
|
||
|
"_unhandled_input",
|
||
|
"_unhandled_key_input",
|
||
|
"_set",
|
||
|
"_get", # probably
|
||
|
"emit_signal", # can't handle extra parameters to be sent with signal.
|
||
|
"draw_mesh", # issue with one parameter, value is `Null((..), (..), (..))``
|
||
|
"_to_string", # nonexistant function ._to_string
|
||
|
"_get_minimum_size", # Nonexistent function _get_minimum_size
|
||
|
]
|
||
|
|
||
|
# These methods should not be included in the double.
|
||
|
var _skip = [
|
||
|
# There is an init in the template. There is also no real reason
|
||
|
# to include this method since it will always be called, it has no
|
||
|
# return value, and you cannot prevent super from being called.
|
||
|
"_init"
|
||
|
]
|
||
|
|
||
|
var built_ins = []
|
||
|
var local_methods = []
|
||
|
var _method_names = []
|
||
|
|
||
|
func is_blacklisted(method_meta):
|
||
|
return _blacklist.find(method_meta.name) != -1
|
||
|
|
||
|
func _add_name_if_does_not_have(method_name):
|
||
|
if _skip.has(method_name):
|
||
|
return false
|
||
|
var should_add = _method_names.find(method_name) == -1
|
||
|
if should_add:
|
||
|
_method_names.append(method_name)
|
||
|
return should_add
|
||
|
|
||
|
func add_built_in_method(method_meta):
|
||
|
var did_add = _add_name_if_does_not_have(method_meta.name)
|
||
|
if did_add and !is_blacklisted(method_meta):
|
||
|
built_ins.append(method_meta)
|
||
|
|
||
|
func add_local_method(method_meta):
|
||
|
var did_add = _add_name_if_does_not_have(method_meta.name)
|
||
|
if did_add:
|
||
|
local_methods.append(method_meta)
|
||
|
|
||
|
func to_s():
|
||
|
var text = "Locals\n"
|
||
|
for i in range(local_methods.size()):
|
||
|
text += str(" ", local_methods[i].name, "\n")
|
||
|
text += "Built-Ins\n"
|
||
|
for i in range(built_ins.size()):
|
||
|
text += str(" ", built_ins[i].name, "\n")
|
||
|
return text
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Helper class to deal with objects and inner classes.
|
||
|
# ------------------------------------------------------------------------------
|
||
|
class ObjectInfo:
|
||
|
var _path = null
|
||
|
var _subpaths = []
|
||
|
var _utils = load("res://addons/gut/utils.gd").get_instance()
|
||
|
var _lgr = _utils.get_logger()
|
||
|
var _method_strategy = null
|
||
|
var make_partial_double = false
|
||
|
var scene_path = null
|
||
|
var _native_class = null
|
||
|
var _native_class_name = null
|
||
|
var _singleton_instance = null
|
||
|
var _singleton_name = null
|
||
|
|
||
|
func _init(path, subpath = null):
|
||
|
_path = path
|
||
|
if subpath != null:
|
||
|
_subpaths = Array(subpath.split("/"))
|
||
|
|
||
|
# Returns an instance of the class/inner class
|
||
|
func instantiate():
|
||
|
var to_return = null
|
||
|
|
||
|
if _singleton_instance != null:
|
||
|
to_return = _singleton_instance
|
||
|
elif is_native():
|
||
|
to_return = _native_class.new()
|
||
|
else:
|
||
|
to_return = get_loaded_class().new()
|
||
|
|
||
|
return to_return
|
||
|
|
||
|
# Can't call it get_class because that is reserved so it gets this ugly name.
|
||
|
# Loads up the class and then any inner classes to give back a reference to
|
||
|
# the desired Inner class (if there is any)
|
||
|
func get_loaded_class():
|
||
|
var LoadedClass = load(_path)
|
||
|
for i in range(_subpaths.size()):
|
||
|
LoadedClass = LoadedClass.get(_subpaths[i])
|
||
|
return LoadedClass
|
||
|
|
||
|
func to_s():
|
||
|
return str(_path, "[", get_subpath(), "]")
|
||
|
|
||
|
func get_path():
|
||
|
return _path
|
||
|
|
||
|
func get_subpath():
|
||
|
return PoolStringArray(_subpaths).join("/")
|
||
|
|
||
|
func has_subpath():
|
||
|
return _subpaths.size() != 0
|
||
|
|
||
|
func get_method_strategy():
|
||
|
return _method_strategy
|
||
|
|
||
|
func set_method_strategy(method_strategy):
|
||
|
_method_strategy = method_strategy
|
||
|
|
||
|
func is_native():
|
||
|
return _native_class != null
|
||
|
|
||
|
func set_native_class(native_class):
|
||
|
_native_class = native_class
|
||
|
var inst = native_class.new()
|
||
|
_native_class_name = inst.get_class()
|
||
|
_path = _native_class_name
|
||
|
if !inst is Reference:
|
||
|
inst.free()
|
||
|
|
||
|
func get_native_class_name():
|
||
|
return _native_class_name
|
||
|
|
||
|
func get_singleton_instance():
|
||
|
return _singleton_instance
|
||
|
|
||
|
func get_singleton_name():
|
||
|
return _singleton_name
|
||
|
|
||
|
func set_singleton_name(singleton_name):
|
||
|
_singleton_name = singleton_name
|
||
|
_singleton_instance = _utils.get_singleton_by_name(_singleton_name)
|
||
|
|
||
|
func is_singleton():
|
||
|
return _singleton_instance != null
|
||
|
|
||
|
func get_extends_text():
|
||
|
var extend = null
|
||
|
if is_singleton():
|
||
|
extend = str("# Double of singleton ", _singleton_name, ", base class is Reference")
|
||
|
elif is_native():
|
||
|
var native = get_native_class_name()
|
||
|
if native.begins_with("_"):
|
||
|
native = native.substr(1)
|
||
|
extend = str("extends ", native)
|
||
|
else:
|
||
|
extend = str("extends '", get_path(), "'")
|
||
|
|
||
|
if has_subpath():
|
||
|
extend += str(".", get_subpath().replace("/", "."))
|
||
|
|
||
|
return extend
|
||
|
|
||
|
func get_constants_text():
|
||
|
if !is_singleton():
|
||
|
return ""
|
||
|
|
||
|
# do not include constants defined in the super class which for
|
||
|
# singletons stubs is Reference.
|
||
|
var exclude_constants = Array(ClassDB.class_get_integer_constant_list("Reference"))
|
||
|
var text = str("# -----\n# ", _singleton_name, " Constants\n# -----\n")
|
||
|
var constants = ClassDB.class_get_integer_constant_list(_singleton_name)
|
||
|
for c in constants:
|
||
|
if !exclude_constants.has(c):
|
||
|
var value = ClassDB.class_get_integer_constant(_singleton_name, c)
|
||
|
text += str("const ", c, " = ", value, "\n")
|
||
|
|
||
|
return text
|
||
|
|
||
|
func get_properties_text():
|
||
|
if !is_singleton():
|
||
|
return ""
|
||
|
|
||
|
var text = str("# -----\n# ", _singleton_name, " Properties\n# -----\n")
|
||
|
var props = ClassDB.class_get_property_list(_singleton_name)
|
||
|
for prop in props:
|
||
|
var accessors = {"setter": null, "getter": null}
|
||
|
var prop_text = str("var ", prop["name"])
|
||
|
|
||
|
var getter_name = "get_" + prop["name"]
|
||
|
if ClassDB.class_has_method(_singleton_name, getter_name):
|
||
|
accessors.getter = getter_name
|
||
|
else:
|
||
|
getter_name = "is_" + prop["name"]
|
||
|
if ClassDB.class_has_method(_singleton_name, getter_name):
|
||
|
accessors.getter = getter_name
|
||
|
|
||
|
var setter_name = "set_" + prop["name"]
|
||
|
if ClassDB.class_has_method(_singleton_name, setter_name):
|
||
|
accessors.setter = setter_name
|
||
|
|
||
|
var setget_text = ""
|
||
|
if accessors.setter != null and accessors.getter != null:
|
||
|
setget_text = str("setget ", accessors.setter, ", ", accessors.getter)
|
||
|
else:
|
||
|
# never seen this message show up, but it should show up if we
|
||
|
# get misbehaving singleton.
|
||
|
_lgr.error(
|
||
|
str(
|
||
|
"Could not find setget methods for property: ",
|
||
|
_singleton_name,
|
||
|
".",
|
||
|
prop["name"]
|
||
|
)
|
||
|
)
|
||
|
|
||
|
text += str(prop_text, " ", setget_text, "\n")
|
||
|
|
||
|
return text
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Allows for interacting with a file but only creating a string. This was done
|
||
|
# to ease the transition from files being created for doubles to loading
|
||
|
# doubles from a string. This allows the files to be created for debugging
|
||
|
# purposes since reading a file is easier than reading a dumped out string.
|
||
|
# ------------------------------------------------------------------------------
|
||
|
class FileOrString:
|
||
|
extends File
|
||
|
|
||
|
var _do_file = false
|
||
|
var _contents = ""
|
||
|
var _path = null
|
||
|
|
||
|
func open(path, mode):
|
||
|
_path = path
|
||
|
if _do_file:
|
||
|
return .open(path, mode)
|
||
|
else:
|
||
|
return OK
|
||
|
|
||
|
func close():
|
||
|
if _do_file:
|
||
|
return .close()
|
||
|
|
||
|
func store_string(s):
|
||
|
if _do_file:
|
||
|
.store_string(s)
|
||
|
_contents += s
|
||
|
|
||
|
func get_contents():
|
||
|
return _contents
|
||
|
|
||
|
func get_path():
|
||
|
return _path
|
||
|
|
||
|
func load_it():
|
||
|
if _contents != "":
|
||
|
var script = GDScript.new()
|
||
|
script.set_source_code(get_contents())
|
||
|
script.reload()
|
||
|
return script
|
||
|
else:
|
||
|
return load(_path)
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# A stroke of genius if I do say so. This allows for doubling a scene without
|
||
|
# having to write any files. By overloading the "instance" method we can
|
||
|
# make whatever we want.
|
||
|
# ------------------------------------------------------------------------------
|
||
|
class PackedSceneDouble:
|
||
|
extends PackedScene
|
||
|
var _script = null
|
||
|
var _scene = null
|
||
|
|
||
|
func set_script_obj(obj):
|
||
|
_script = obj
|
||
|
|
||
|
func instance(edit_state = 0):
|
||
|
var inst = _scene.instance(edit_state)
|
||
|
if _script != null:
|
||
|
inst.set_script(_script)
|
||
|
return inst
|
||
|
|
||
|
func load_scene(path):
|
||
|
_scene = load(path)
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# START Doubler
|
||
|
# ------------------------------------------------------------------------------
|
||
|
var _utils = load("res://addons/gut/utils.gd").get_instance()
|
||
|
|
||
|
var _ignored_methods = _utils.OneToMany.new()
|
||
|
var _stubber = _utils.Stubber.new()
|
||
|
var _lgr = _utils.get_logger()
|
||
|
var _method_maker = _utils.MethodMaker.new()
|
||
|
|
||
|
var _output_dir = "user://gut_temp_directory"
|
||
|
var _double_count = 0 # used in making files names unique
|
||
|
var _spy = null
|
||
|
var _gut = null
|
||
|
var _strategy = null
|
||
|
var _base_script_text = _utils.get_file_as_text(
|
||
|
"res://addons/gut/double_templates/script_template.txt"
|
||
|
)
|
||
|
var _make_files = false
|
||
|
# used by tests for debugging purposes.
|
||
|
var _print_source = false
|
||
|
|
||
|
|
||
|
func _init(strategy = _utils.DOUBLE_STRATEGY.PARTIAL):
|
||
|
set_logger(_utils.get_logger())
|
||
|
_strategy = strategy
|
||
|
|
||
|
|
||
|
# ###############
|
||
|
# Private
|
||
|
# ###############
|
||
|
func _get_indented_line(indents, text):
|
||
|
var to_return = ""
|
||
|
for _i in range(indents):
|
||
|
to_return += "\t"
|
||
|
return str(to_return, text, "\n")
|
||
|
|
||
|
|
||
|
func _stub_to_call_super(obj_info, method_name):
|
||
|
if _utils.non_super_methods.has(method_name):
|
||
|
return
|
||
|
|
||
|
var path = obj_info.get_path()
|
||
|
if obj_info.is_singleton():
|
||
|
path = obj_info.get_singleton_name()
|
||
|
elif obj_info.scene_path != null:
|
||
|
path = obj_info.scene_path
|
||
|
|
||
|
var params = _utils.StubParams.new(path, method_name, obj_info.get_subpath())
|
||
|
params.to_call_super()
|
||
|
_stubber.add_stub(params)
|
||
|
|
||
|
|
||
|
func _get_base_script_text(obj_info, override_path):
|
||
|
var path = obj_info.get_path()
|
||
|
if override_path != null:
|
||
|
path = override_path
|
||
|
|
||
|
var stubber_id = -1
|
||
|
if _stubber != null:
|
||
|
stubber_id = _stubber.get_instance_id()
|
||
|
|
||
|
var spy_id = -1
|
||
|
if _spy != null:
|
||
|
spy_id = _spy.get_instance_id()
|
||
|
|
||
|
var gut_id = -1
|
||
|
if _gut != null:
|
||
|
gut_id = _gut.get_instance_id()
|
||
|
|
||
|
var values = {
|
||
|
# Top sections
|
||
|
"extends": obj_info.get_extends_text(),
|
||
|
"constants": obj_info.get_constants_text(),
|
||
|
"properties": obj_info.get_properties_text(),
|
||
|
# metadata values
|
||
|
"path": path,
|
||
|
"subpath": obj_info.get_subpath(),
|
||
|
"stubber_id": stubber_id,
|
||
|
"spy_id": spy_id,
|
||
|
"gut_id": gut_id,
|
||
|
"singleton_name": _utils.nvl(obj_info.get_singleton_name(), ""),
|
||
|
"is_partial": str(obj_info.make_partial_double).to_lower()
|
||
|
}
|
||
|
|
||
|
return _base_script_text.format(values)
|
||
|
|
||
|
|
||
|
func _write_file(obj_info, dest_path, override_path = null):
|
||
|
var base_script = _get_base_script_text(obj_info, override_path)
|
||
|
var script_methods = _get_methods(obj_info)
|
||
|
var super_name = ""
|
||
|
var path = ""
|
||
|
|
||
|
if obj_info.is_singleton():
|
||
|
super_name = obj_info.get_singleton_name()
|
||
|
else:
|
||
|
path = obj_info.get_path()
|
||
|
|
||
|
var f = FileOrString.new()
|
||
|
f._do_file = _make_files
|
||
|
var f_result = f.open(dest_path, f.WRITE)
|
||
|
|
||
|
if f_result != OK:
|
||
|
_lgr.error(str("Error creating file ", dest_path))
|
||
|
_lgr.error(str("Could not create double for :", obj_info.to_s()))
|
||
|
return
|
||
|
|
||
|
f.store_string(base_script)
|
||
|
|
||
|
for i in range(script_methods.local_methods.size()):
|
||
|
f.store_string(_get_func_text(script_methods.local_methods[i], path, super_name))
|
||
|
|
||
|
for i in range(script_methods.built_ins.size()):
|
||
|
_stub_to_call_super(obj_info, script_methods.built_ins[i].name)
|
||
|
f.store_string(_get_func_text(script_methods.built_ins[i], path, super_name))
|
||
|
|
||
|
f.close()
|
||
|
if _print_source:
|
||
|
print(f.get_contents())
|
||
|
return f
|
||
|
|
||
|
|
||
|
func _double_scene_and_script(scene_info):
|
||
|
var to_return = PackedSceneDouble.new()
|
||
|
to_return.load_scene(scene_info.get_path())
|
||
|
|
||
|
var inst = load(scene_info.get_path()).instance()
|
||
|
var script_path = null
|
||
|
if inst.get_script():
|
||
|
script_path = inst.get_script().get_path()
|
||
|
inst.free()
|
||
|
|
||
|
if script_path:
|
||
|
var oi = ObjectInfo.new(script_path)
|
||
|
oi.set_method_strategy(scene_info.get_method_strategy())
|
||
|
oi.make_partial_double = scene_info.make_partial_double
|
||
|
oi.scene_path = scene_info.get_path()
|
||
|
to_return.set_script_obj(_double(oi, scene_info.get_path()).load_it())
|
||
|
|
||
|
return to_return
|
||
|
|
||
|
|
||
|
func _get_methods(object_info):
|
||
|
var obj = object_info.instantiate()
|
||
|
# any method in the script or super script
|
||
|
var script_methods = ScriptMethods.new()
|
||
|
var methods = obj.get_method_list()
|
||
|
|
||
|
if !object_info.is_singleton() and !(obj is Reference):
|
||
|
obj.free()
|
||
|
|
||
|
# first pass is for local methods only
|
||
|
for i in range(methods.size()):
|
||
|
if object_info.is_singleton():
|
||
|
#print(methods[i].name, " :: ", methods[i].flags, " :: ", methods[i].id)
|
||
|
#print(" ", methods[i])
|
||
|
|
||
|
# It appears that the ID for methods upstream from a singleton are
|
||
|
# below 200. Initially it was thought that singleton specific methods
|
||
|
# were above 1000. This was true for Input but not for OS. I've
|
||
|
# changed the condition to be > 200 instead of > 1000. It will take
|
||
|
# some investigation to figure out if this is right, but it works
|
||
|
# for now. Someone either find an issue and open a bug, or this will
|
||
|
# just exist like this. Sorry future me (or someone else).
|
||
|
if methods[i].id > 200 and methods[i].flags in [1, 9]:
|
||
|
script_methods.add_local_method(methods[i])
|
||
|
|
||
|
# 65 is a magic number for methods in script, though documentation
|
||
|
# says 64. This picks up local overloads of base class methods too.
|
||
|
# See MethodFlags in @GlobalScope
|
||
|
elif (
|
||
|
methods[i].flags == 65
|
||
|
and !_ignored_methods.has(object_info.get_path(), methods[i]["name"])
|
||
|
):
|
||
|
script_methods.add_local_method(methods[i])
|
||
|
|
||
|
if object_info.get_method_strategy() == _utils.DOUBLE_STRATEGY.FULL:
|
||
|
# second pass is for anything not local
|
||
|
for j in range(methods.size()):
|
||
|
# 65 is a magic number for methods in script, though documentation
|
||
|
# says 64. This picks up local overloads of base class methods too.
|
||
|
if (
|
||
|
methods[j].flags != 65
|
||
|
and !_ignored_methods.has(object_info.get_path(), methods[j]["name"])
|
||
|
):
|
||
|
script_methods.add_built_in_method(methods[j])
|
||
|
|
||
|
return script_methods
|
||
|
|
||
|
|
||
|
func _get_inst_id_ref_str(inst):
|
||
|
var ref_str = "null"
|
||
|
if inst:
|
||
|
ref_str = str("instance_from_id(", inst.get_instance_id(), ")")
|
||
|
return ref_str
|
||
|
|
||
|
|
||
|
func _get_func_text(method_hash, path, super = ""):
|
||
|
var override_count = null
|
||
|
if _stubber != null:
|
||
|
override_count = _stubber.get_parameter_count(path, method_hash.name)
|
||
|
|
||
|
var text = _method_maker.get_function_text(method_hash, path, override_count, super) + "\n"
|
||
|
|
||
|
return text
|
||
|
|
||
|
|
||
|
# returns the path to write the double file to
|
||
|
func _get_temp_path(object_info):
|
||
|
var file_name = null
|
||
|
var extension = null
|
||
|
|
||
|
if object_info.is_singleton():
|
||
|
file_name = str(object_info.get_singleton_instance())
|
||
|
extension = "gd"
|
||
|
elif object_info.is_native():
|
||
|
file_name = object_info.get_native_class_name()
|
||
|
extension = "gd"
|
||
|
else:
|
||
|
file_name = object_info.get_path().get_file().get_basename()
|
||
|
extension = object_info.get_path().get_extension()
|
||
|
|
||
|
if object_info.has_subpath():
|
||
|
file_name += "__" + object_info.get_subpath().replace("/", "__")
|
||
|
|
||
|
file_name += str("__dbl", _double_count, "__.", extension)
|
||
|
|
||
|
var to_return = _output_dir.plus_file(file_name)
|
||
|
return to_return
|
||
|
|
||
|
|
||
|
func _double(obj_info, override_path = null):
|
||
|
var temp_path = _get_temp_path(obj_info)
|
||
|
var result = _write_file(obj_info, temp_path, override_path)
|
||
|
_double_count += 1
|
||
|
return result
|
||
|
|
||
|
|
||
|
func _double_script(path, make_partial, strategy):
|
||
|
var oi = ObjectInfo.new(path)
|
||
|
oi.make_partial_double = make_partial
|
||
|
oi.set_method_strategy(strategy)
|
||
|
return _double(oi).load_it()
|
||
|
|
||
|
|
||
|
func _double_inner(path, subpath, make_partial, strategy):
|
||
|
var oi = ObjectInfo.new(path, subpath)
|
||
|
oi.set_method_strategy(strategy)
|
||
|
oi.make_partial_double = make_partial
|
||
|
return _double(oi).load_it()
|
||
|
|
||
|
|
||
|
func _double_scene(path, make_partial, strategy):
|
||
|
var oi = ObjectInfo.new(path)
|
||
|
oi.set_method_strategy(strategy)
|
||
|
oi.make_partial_double = make_partial
|
||
|
return _double_scene_and_script(oi)
|
||
|
|
||
|
|
||
|
func _double_gdnative(native_class, make_partial, strategy):
|
||
|
var oi = ObjectInfo.new(null)
|
||
|
oi.set_native_class(native_class)
|
||
|
oi.set_method_strategy(strategy)
|
||
|
oi.make_partial_double = make_partial
|
||
|
return _double(oi).load_it()
|
||
|
|
||
|
|
||
|
func _double_singleton(singleton_name, make_partial, strategy):
|
||
|
var oi = ObjectInfo.new(null)
|
||
|
oi.set_singleton_name(singleton_name)
|
||
|
oi.set_method_strategy(_utils.DOUBLE_STRATEGY.PARTIAL)
|
||
|
oi.make_partial_double = make_partial
|
||
|
return _double(oi).load_it()
|
||
|
|
||
|
|
||
|
# ###############
|
||
|
# Public
|
||
|
# ###############
|
||
|
func get_output_dir():
|
||
|
return _output_dir
|
||
|
|
||
|
|
||
|
func set_output_dir(output_dir):
|
||
|
if output_dir != null:
|
||
|
_output_dir = output_dir
|
||
|
if _make_files:
|
||
|
var d = Directory.new()
|
||
|
d.make_dir_recursive(output_dir)
|
||
|
|
||
|
|
||
|
func get_spy():
|
||
|
return _spy
|
||
|
|
||
|
|
||
|
func set_spy(spy):
|
||
|
_spy = spy
|
||
|
|
||
|
|
||
|
func get_stubber():
|
||
|
return _stubber
|
||
|
|
||
|
|
||
|
func set_stubber(stubber):
|
||
|
_stubber = stubber
|
||
|
|
||
|
|
||
|
func get_logger():
|
||
|
return _lgr
|
||
|
|
||
|
|
||
|
func set_logger(logger):
|
||
|
_lgr = logger
|
||
|
_method_maker.set_logger(logger)
|
||
|
|
||
|
|
||
|
func get_strategy():
|
||
|
return _strategy
|
||
|
|
||
|
|
||
|
func set_strategy(strategy):
|
||
|
_strategy = strategy
|
||
|
|
||
|
|
||
|
func get_gut():
|
||
|
return _gut
|
||
|
|
||
|
|
||
|
func set_gut(gut):
|
||
|
_gut = gut
|
||
|
|
||
|
|
||
|
func partial_double_scene(path, strategy = _strategy):
|
||
|
return _double_scene(path, true, strategy)
|
||
|
|
||
|
|
||
|
# double a scene
|
||
|
func double_scene(path, strategy = _strategy):
|
||
|
return _double_scene(path, false, strategy)
|
||
|
|
||
|
|
||
|
# double a script/object
|
||
|
func double(path, strategy = _strategy):
|
||
|
return _double_script(path, false, strategy)
|
||
|
|
||
|
|
||
|
func partial_double(path, strategy = _strategy):
|
||
|
return _double_script(path, true, strategy)
|
||
|
|
||
|
|
||
|
func partial_double_inner(path, subpath, strategy = _strategy):
|
||
|
return _double_inner(path, subpath, true, strategy)
|
||
|
|
||
|
|
||
|
# double an inner class in a script
|
||
|
func double_inner(path, subpath, strategy = _strategy):
|
||
|
return _double_inner(path, subpath, false, strategy)
|
||
|
|
||
|
|
||
|
# must always use FULL strategy since this is a native class and you won't get
|
||
|
# any methods if you don't use FULL
|
||
|
func double_gdnative(native_class):
|
||
|
return _double_gdnative(native_class, false, _utils.DOUBLE_STRATEGY.FULL)
|
||
|
|
||
|
|
||
|
# must always use FULL strategy since this is a native class and you won't get
|
||
|
# any methods if you don't use FULL
|
||
|
func partial_double_gdnative(native_class):
|
||
|
return _double_gdnative(native_class, true, _utils.DOUBLE_STRATEGY.FULL)
|
||
|
|
||
|
|
||
|
func double_singleton(name):
|
||
|
return _double_singleton(name, false, _utils.DOUBLE_STRATEGY.PARTIAL)
|
||
|
|
||
|
|
||
|
func partial_double_singleton(name):
|
||
|
return _double_singleton(name, true, _utils.DOUBLE_STRATEGY.PARTIAL)
|
||
|
|
||
|
|
||
|
func clear_output_directory():
|
||
|
if !_make_files:
|
||
|
return false
|
||
|
|
||
|
var did = false
|
||
|
if _output_dir.find("user://") == 0:
|
||
|
var d = Directory.new()
|
||
|
var result = d.open(_output_dir)
|
||
|
# BIG GOTCHA HERE. If it cannot open the dir w/ erro 31, then the
|
||
|
# directory becomes res:// and things go on normally and gut clears out
|
||
|
# out res:// which is SUPER BAD.
|
||
|
if result == OK:
|
||
|
d.list_dir_begin(true)
|
||
|
var f = d.get_next()
|
||
|
while f != "":
|
||
|
d.remove(f)
|
||
|
f = d.get_next()
|
||
|
did = true
|
||
|
return did
|
||
|
|
||
|
|
||
|
func delete_output_directory():
|
||
|
var did = clear_output_directory()
|
||
|
if did:
|
||
|
var d = Directory.new()
|
||
|
d.remove(_output_dir)
|
||
|
|
||
|
|
||
|
func add_ignored_method(path, method_name):
|
||
|
_ignored_methods.add(path, method_name)
|
||
|
|
||
|
|
||
|
func get_ignored_methods():
|
||
|
return _ignored_methods
|
||
|
|
||
|
|
||
|
func get_make_files():
|
||
|
return _make_files
|
||
|
|
||
|
|
||
|
func set_make_files(make_files):
|
||
|
_make_files = make_files
|
||
|
set_output_dir(_output_dir)
|
||
|
|
||
|
|
||
|
func get_method_maker():
|
||
|
return _method_maker
|