How to use a different properties filename in Koin? - kotlin

The default properties file for Koin is koin.properties.
How to use a different properties file name instead?
A snippet from the documentation:
startKoin {
// Load properties from the default location
// (i.e. `/src/main/resources/koin.properties`)
fileProperties()
}

(sharing my findings)
fileProperties() accepts an optional fileName argument which defaults to '/koin.properties'.
To use a different filename, it must be passed to fileProperties with a leading slash.
For example, to use application.properties, call:
fileProperties("/application.properties")

Related

Get gradle property from settings

So i am trying to transition my app to Kotlin DSL the issue i am facing is with accessing gradle.properties the way i was doing with groovy was like that, i am trying to access gradle.properties props from my settings.gradle.kts file
def propName = 'prop.name.something'
def propDisabled = Boolean.valueOf(properties[propName])
I tried several ways of accessing it with settings.extra[propName].toBoolean. It just seems there should be more straight way to access those properties?
The proper way to access a property declared in gradle.properties in settings.gradle.kts is by delegating it to the settings object:
val myProperty: String by settings
Note that it is mandatory to specify the property type String explicitly here.
This will get the property myProperty from the gradle.properties file. Note that if you use it in the pluginManagement { ... } block, then the property declaration needs to be placed inside pluginManagement { ... }, too, as this block is evaluated before everything else in the script.
However, if a property name contains symbols that are illegal in Kotlin identifiers, such as ., which is not allowed even in backticked identifiers, then you can't access it as a delegated property. There's no way to access such a property from the Gradle model as of Gradle 6.7, but, given that gradle.properties is just a .properties file, you can read it into a Java Properties instance:
val properties = File(rootDir, "gradle.properties").inputStream().use {
java.util.Properties().apply { load(it) }
}
val propNameSomething = properties.getValue("prop.name.something") as String

Companion object with extension function in kotlin?

I would like to have extension function and use logger from kotlin-logging and have constants inside companion object.
My function:
fun String.toFoo(): Foo {
logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
...
}
Question is where I should put val logger = KotlinLogging.logger {} and MY_CONST since I cannot use companion object with an extension function?
If you just want you logger to be a singleton you can make an object that contains and instance of the logger and reach it from there.
Object LoggerSingleton( val logger = KotlinLogging.logger{})
Then in your extension function
fun String.toFoo(): Foo {
LoggerSingleton.logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
}
Since an Object in Kotlin is guaranteed to have only one instance you won't have a different logger for each use of toFoo.
EDIT
To keep the desired class name
Use this signature
Like so:
Object StringLoggerSingleton( val logger = KotlinLogging.logger("String"))
I do not know what you want to accomplish with your logger, but I show you what I did already ;-)
Usually I put extension functions in its own file named similar to what the function is actually extending (e.g. either StringExtensionFunction or if is more related to its purpose and maybe only available if certain dependencies are available, I also did something like, e.g. JsoupExtensionFunctions (where there was a String.toJsoupHtml(), File.toJsoupXml(), etc.)).
If I then need constants I just place them within that file, e.g. by just writing something like:
private const val MY_CONST = "my_const_value"
No surrounding class, no surrounding object.
Regarding the logger... as loggers are usually tied to a certain name/class, I usually put a logger inside every (important) class or associate some logger to specific names... So I am not completely sure what your intent is here... If it's ok for you that the logger is returning the container of your extension function (maybe StringExtensionFunction.kt), then you can also put a logger-val inside that file similar to what I showed with MY_CONST.
If your intention was rather to reuse the callers logger, that might not work so easily... (the easiest would then probably be to pass it to the function, but usually you do not want that)... and other mechanisms may not really be worth it ;-)

Recommended pattern for setting initialization parameters to custom widget

I'm creating my own template based widgets and I was trying to pass some objects through the constructor on creation like this
var widget = new myWidget(obj1, obj2, obj3);
where my constructor of the widget looks like
constructor: function(param1, param2, param3)
However I was getting some errors and found they were due to _WidgetBase functionality (specifically the create method) that is expecting something special in the first and second parameters.
create: function(params, srcNodeRef)
So in order to avoid my parameters nuking the params, and srcNodeRef that was expected in position one and two, I had to move my parameters to after the second position like this
constructor: function (params, srcNodeRef, myParam1, myparam2, myParam3)
But naturally this is not an expected way to solve this compared to the usual way to instantiate objects in normal object oriented languages (ex. c#)
My question is, is there a recommended pattern for passing initialization parameters to a custom widgets constructor, that avoids this issue of having to remember the first and second parameter positions are reserved?
NOTE:
An important note is that whatever parameters I send into the widget, must be acted on or made available before postCreate executes, just like it is if I passed them to the constructor.
Actually, there is a "dojo" way to pass parameters into your widget:
var widget = new myWidget({obj1: obj1, obj2: obj2});
In instance of your widget these object will refer to
this.obj1, this.obj2. You don't have to override constructor.
Some comments from dojo source of _WidgetBase on this topic:
//////////// INITIALIZATION METHODS ///////////////////////////////////////
/*=====
constructor: function(params, srcNodeRef){
// summary:
// Create the widget.
// params: Object|null
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
// and functions, typically callbacks like onClick.
// The hash can contain any of the widget's properties, excluding read-only properties.
// srcNodeRef: DOMNode|String?
// If a srcNodeRef (DOM node) is specified:
//
// - use srcNodeRef.innerHTML as my contents
// - if this is a behavioral widget then apply behavior to that srcNodeRef
// - otherwise, replace srcNodeRef with my generated DOM tree
},
=====*/
I +1'd Kirill's answer as that's the easiest. But from the other comments it sounds like you might need to massage the input or initialize other variables based on the input.
If so, take a look at the postMixinProperties lifecycle method and override it in your widget. If your widget is templated and the template expects the massaged data, you'll need this. In here you refer to your properties with this as you expect.
postMixInProperties: function(){
// summary:
// Called after the parameters to the widget have been read-in,
// but before the widget template is instantiated. Especially
// useful to set properties that are referenced in the widget
// template.
// tags:
// protected
},
Don't forget to invoke this.inherited(arguments); in here as you should in all of the dijit lifecycle methods.
Defining setters for you properties is another way to massage these properties. You'll want this if a template will use these properties. Example of a setter from the Writing Widgets page. So here 'open' would be the name of the parameter as passed to the contructor, or in a widget template.
_setOpenAttr: function(/*Boolean*/ open){
this._set("open", open);
domStyle.set(this.domNode, "display", open ? "block" : "none");
}

Define global namespace/variable within a TypeScript module

In TypeScript I can define a global/top-level namespace and use it in another file like so:
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
And in another file, this works:
foo.blah.baz();
However, if I then import something from another module:
import Thing from 'boo';
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
Suddenly my whole file is a module, the foo.blah namespace is local, not global, and the foo.blah.baz() call in the other file fails. export namespace ... just causes the namespace to become part of the module's export, not a global.
Is there a way to write a TypeScript file which imports from other modules but also defines global/top-level symbols?
At the moment I'm doing this:
import Thing from 'boo';
import * as $ from 'jquery';
namespace foo.blah {
export function baz() {
console.log('hello');
}
}
$.extend(true, window, {foo});
Which works, but the TypeScript compiler still can't see that foo.blah... exists as a global in other files.
(The file is the entry point for Webpack, and I'm trying to import things from other modules in the Webpack bundle and assign them to globals so they can be used in <script> tags on the page.)
When you add the import, you switch from internal modules to external ones, as the spec says:
In external modules, relationships between files are specified in
terms of imports and exports at the file level. In TypeScript, any
file containing a top-level import or export is considered an external
module.
http://www.typescriptlang.org/Handbook#modules-going-external
The philosophy behind external modules is to avoid global objects, why don't you create a new module with foo.blah (and all the stuff you need) and import it as TypeScript expects it?
The solution is to declare namespace in global.
declare global {
namespace foo.blah {
function baz() {
console.log('hello');
}
}
}
create a global.d.ts and put your type there
reference: cannot use d.ts file to load declaration merging
For me, the problem was to call the google-one-tap library from a module. The library is only available as script, but a types package exists: #types/google-one-tap.
Code snippet from the types package #types/google-one-tap/index.d.ts:
export as namespace google;
export const accounts: accounts;
export interface accounts {
id: {
initialize: (idConfiguration: IdConfiguration) => void;
disableAutoSelect: () => void;
[...]
As you can see in the above declarations file, there is a namespace google that contains objects/interfaces.
My code calling the library from a module:
google.accounts.id.initialize(...)
Without the fix (see below) the above code returns an exception when building: error TS2686: 'google' refers to a UMD global, but the current file is a module. Consider adding an import instead.
To be able to see the types and to get successful compilation, I declared a variable for the namespace google as follows. There is no code generated for declarations.
declare var google: {
accounts: google.accounts
};
// Now this works without errors.
google.accounts.id.initialize(...)
All of this is actually not recommended and red flags per documentation. Moreover it says that:
Multiple files that have the same export namespace Foo { at top-level (don’t think that these are going to combine into one Foo!)
That being said, I also had to preserve namespaced construct when migrating to ES6 modules because some systems don't offer a simple way to suddenly change namespace references like find & replace (MS Power Apps for example) or maybe you are really developing a library and want to preserve the entry point foo
If you had different first part of namespace per file, this would be enought:
(window as any).foo = foo
But having multiple, each file would overwrite previous window.foo
But there are ways what you can do when migrating to modules. With some webpack configuration, namespaces CAN be exposed as a public variables.
/*
Merge foonamespace between multiple files and expose it as a global variable. Otherwise foo namespace stays as module scoped variable.
exports global variable foo (because library.name is foo), and it uses a construct that:
- Copy the return value to a target object if it exists, otherwise create the target object first: Basically copies foo.* to foo object. This turns out to be a merge of namespaces.
- Namespace MUST BE exported.
- export: 'foo' means that instead of having global variable foo.foo.blah I have foo.blah (basically this should be the value whatever namespace starts with)
*/
output: {
...
library: {
name: 'foo', //or [name] if you have namespace same as entry point name
type: 'assign-properties' //or var or window if same namespace doesn't span multiple modules
export: 'foo'
},
}
There are many more ways to expose stuff to global scope (different type values available). Refer to webpack documentation
P.S. A module (having import or export statement) means variables get scoped as a module (rightly so) and that brings these challenges in the first place to preserve namespaced construct. Reference
Modules are executed within their own scope, not in the global scope; this means that variables, functions, classes, etc. declared in a module are not visible outside the module
P.S.2 How does webpack achieve it? The output looks something like:
var __webpack_export_target__ = (foo = typeof foo === "undefined" ? {} : foo);
var __webpack_exports_export__ = __webpack_exports__.foo;
for(var i in __webpack_exports_export__) __webpack_export_target__[i] = __webpack_exports_export__[i];
if(__webpack_exports_export__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
Implication is second level namespace must be unique.

Difference between extra properties and variables in Gradle tasks?

What exactly is difference between these two tasks in Gradle:
task sampleTask {
String myFile = "sample.txt"
delete myFile
}
task sampleTask {
ext.myFile = "sample.txt"
delete myFile
}
Are they basically the same or do they differ somehow?
The first snippet declares a local variable which is only visible within the enclosing block. The second snippet adds an extra property that extends Gradle's object model and is visible everywhere the task is visible. Unless you have a reason to extend the object model, use a local variable.