How best to expose a class instance in DWScript - delphi

I am putting together a built-in script capability using the excellent Pascal DWScript. I have also add my own Delphi-side class definition (TDemo) to DWScript using:
dwsUnit.ExposeRTTI( TDemo.ClassInfo )
This just works and is a great way of quickly adding properties and methods.
I also wish to add an existing instance in a similar way, so I have created my instance FDemo of type TDemo and then performed:
dwsUnit.ExposeInstanceToUnit( 'Demo', 'TDemo', FDemo );
This looks a promising routine to call but I get an AV from an uninitialised unit table. I've also looked in the unit test code of the SVN source to see the use of this function but to no avail. Can anyone point me at what I should add / change?

ExposeInstanceToUnit has to be used from within the TdwsUnit table initialization, see RTTIExposeTests/ExposeInstancesAfterInitTable for some sample code. It allows directly exposing dynamic instances.
The other approach is to use the Instances collection of a TdwsUnit component, you get design-time support, and more controls over your instances and their lifetime.
Also keep in mind you have to make sure the instances you expose will properly behave even if the script misbehaves, f.i. when the user attempts to manually destroys an instance you exposed, and that instance shouldn't be destroyed. By default ExposeRTTI will map the destructors, so you may want to restrict that by specifying eoNoFreeOnCleanup.
edit: a last approach recently added is to use the TdwsRttiConnector, which basically allows exposing and connection to anything that's reachable through RTTI. That's very lightweight in terms of code to setup, but the downside is you don't get any form of compile-time checks.

Related

Upgrading from Play 2.6 to 2.7: How to refactor this Play.current statement to use DI

In my Java 8 Play 2.6 application I have this particular line in a MessageConsumer class that reads a "Rule" record in the DB and sends the JSON message (node) to a specific processor based on the type configured on the rule column. ProcessType is an enum of Sub Classes that all extend from a base (Super class) process.
Play.current().injector().instanceOf(ProcessType.getClass(matchingRule.getProcessType())).processMessage(node, matchingRule);
I'm having trouble figuring out how to refactor this and don't want to add the allowGlobalApplication = true config parameter if I can avoid it.
The most straightforward approach is to inject the Injector into the component that contains this call (the MessageConsumer). This can be done the same way as any other Play component.
You can also inject the Application instance, which would return the same thing as Play.current(). This could be useful if you need more information from the Application object, but if not, injecting the Injector directly would be preferable, as it would create less coupling between the MessageConsumer and other components.
This assumes that the MessageConsumer is created by DI itself. If not, please add more details to the question, including the context code.

Best practice for resolving in Spring4D?

In the spring4d demos, ServiceLocator.GetService<MyType>('Name') is used to resolve the types. But why not use GlobalContainer.Resolve<MyType>('Name')? I don't see any advantage in this approach...
There is one use case, where I use ServiceLocator:
when coding to make legacy code projects unit-testable...
There is an old project, where in mulitiple places, there are constructor calls of an object, which I write tests for (new and changed methods only, in classes, where injection is not possible, e.g. when a Form is created and destroyed in a button event).
In unit-tests, spring4d is helpful to instantiate the class-under-test:
I can use the GlobalContainer in the dpr for the production project and a special (test-only) TContainer-object which is constructed in Testfixture.Setup and destroyed in Testfixture.TearDown... I also re-initialize the global Service-Locator to use my Test-Container (Reason: I have bad experiences to use GlobalContainer in Test, you cannot un-register a type from GlobalContainer in Testfixture.TearDown).
So now, I got a big method in the dpr, where I register all types to GlobalContainer in the production-code project. In the Setup-Method of my test-fixture-class, I register all types needed for the test to my Testing-Container. And in the Methods, that I changed to make them unit-testable, I construct the classes-under-test with ServiceLocator, where formerly constructor-calls where used.
For me, it is the only way to make such a legacy-code project unit-testable... But my strategic goal is to replace most of this code (part-by-part, including the re-initialized ServiceLocators) one day. It is just not possible to replace it now (too much costs, too much risk...).

Using Dart as a DSL

I am trying to use Dart to tersely define entities in an application, following the idiom of code = configuration. Since I will be defining many entities, I'd like to keep the code as trim and concise and readable as possible.
In an effort to keep boilerplate as close to 0 lines as possible, I recently wrote some code like this:
// man.dart
part of entity_component_framework;
var _man = entity('man', (entityBuilder) {
entityBuilder.add([TopHat, CrookedTeeth]);
})
// test.dart
part of entity_component_framework;
var man = EntityBuilder.entities['man']; // null, since _man wasn't ever accessed.
The entity method associates the entityBuilder passed into the function with a name ('man' in this case). var _man exists because only variable assignments can be top-level in Dart. This seems to be the most concise way possible to use Dart as a DSL.
One thing I wasn't counting on, though, is lazy initialization. If I never access _man -- and I had no intention to, since the entity function neatly stored all the relevant information I required in another data structure -- then the entity function is never run. This is a feature, not a bug.
So, what's the cleanest way of using Dart as a DSL given the lazy initialization restriction?
So, as you point out, it's a feature that Dart doesn't run any code until it's told to. So if you want something to happen, you need to do it in code that runs. Some possibilities
Put your calls to entity() inside the main() function. I assume you don't want to do that, and probably that you want people to be able to add more of these in additional files without modifying the originals.
If you're willing to incur the overhead of mirrors, which is probably not that much if they're confined to this library, use them to find all the top-level variables in that library and access them. Or define them as functions or getters. But I assume that you like the property that variables are automatically one-shot. You'd want to use a MirrorsUsed annotation.
A variation on that would be to use annotations to mark the things you want to be initialized. Though this is similar in that you'd have to iterate over the annotated things, which I think would also require mirrors.

Intercepting RegisterClass method in Classes.pas Delphi7

Is there a way of doing that? The list of registered classes is in the TRegGroups instance in Classes.pas unit, but problem is that instance is declared in the implementation section of unit. Is there a way of obtaining an address of RegisterClass procedure, or RegGroups.RegisterClass method?
Using KOLDetours.pas you can intercept calls to the method and then call the original method.
You can find it here: http://code.google.com/p/asmprofiler/source/browse/trunk/SRC/KOLDetours.pas
The file contains examples of how to use it.
To answer your specific question:
You may get the address of Classes.RegisterClass simply by using #Classes.RegisterClass as it is exposed in the interface section of Classes.pas.
The address TRegGroup.RegisterClass will be a bit tricky as it is not exposed in the interface section. Using the address of Classes.RegisterClass you could read the offset of TRegGroup.RegisterClass from the compiled code and then calculate the absolute address as a function of Classes.RegisterClass's address. Ultimately, this will be fragile across different version of the compiler.
As an alternative, if you are willing to make a small modification to each package, you could create a unit containing a function named RegisterClass and ensure that the unit is included in your registration unit before Classes.pas. Your unit would then link against your new RegisterClass function which could call some notification method before calling Classes.RegisterClass.
As you have indicated that you are statically linking to the packages, this is all somewhat moot because you will not have an opportunity to connect whatever notification routine you devise. To solve that issue you will want to dynamically load your packages after you have created your splash screen and are prepared to pump messages for it.
Alternatively, you could modify your package registration unit to use InitProc to delay registration until your TApplication instance is created. This would give you an opportunity to create some visual means of indicating registration progress before the registration actually take place.
In a comment you state:
I have 22 packages. Each package has (besides others) a unit with all the units in that package placed in interface section, and a procedure with simple RegisterClass(TSomeClass) for every class in that package.
In which case the answer is obvious. Define your own function, named MyRegisterClass for instance, and call that function instead.

I found the ComClass, now how do I reference it?

I've written a small COM Server in Delphi 2010 that acts as a plug-in into a retail application. The retail application looks for a "discover" interface which registers any number of additional interfaces calling TAutoObjectFactory.Create for each one. This is working just fine--all the plug-in interfaces function as designed.
But now I'd like to call a public method of one interface from another interface so I don't have to duplicate code. Seems simple enough, just call ComClassManager.ForEachFactory looking for the ClassID of the interface I need to use. Got that working, too!
But now that I found the class, I'm stumped by a seemingly trivial final step: how to use or cast the class (or class reference?) I've located to actually call one of its methods.
In the "FactoryProc" I've sent to ForEachFactory, I assume the ComClass property of TComObjectFactory is what I'm after, but it's of type TClass, a class reference to the actual class object to which it points (at least I hope I'm understanding this correctly). I'm a little fuzzy on class references and my attempts to cast or otherwise de-reference this property has resulted in access violations or compiler errors.
Any suggestions?
You're right in your comment, ComClassManager deals with classes, not instances. What you need is (your application-local implementation of) running object table (or something similar), so plugin instances can interact with each other.
How to actually implement it depends on what you really need, e.g. call methods on all running instances, or only on instances of specific classes.

Resources