What is the role of underscore in gjs? - gnome

In gjs docs I found that underscore is used to denote private variables, but what does it do when creating objects with new or calling methods? For example in default code that gets generated when creating extension:
...
let item = new PopupMenu.PopupMenuItem(_('Show Notification'));
item.connect('activate', () => {
Main.notify(_('Whatʼs up, folks?'));
});
this.menu.addMenuItem(item);
...

What you see there is the _() function, which is a shorthand for gettext(). In other words, it marks a string as translatable, and will load the translated string (if available) when it's run by the user.

Related

Can you use a Map instance as an easy-peasy store property?

ie.
const store = {
values: new Map(),
// (gross trivial accessor)
setValue: action( (state, payload) => {
state.values.set(payload.key, payload.value);
}
}
I'm curious because easy-peasy uses a Proxy on the store object (and objects nested within) so that in your action you can safely mutate the state object directly (https://easy-peasy.now.sh/docs/tutorials/primary-api.html#modifying-the-state). I don't know if this also works when using non Plain Old JavaScript Objects, such as Maps.
It looks like this is possible on certain versions, but not without first declaring support for the feature (so the code above will not work right out of the box, as of now). See here for more info: https://github.com/ctrlplusb/easy-peasy/issues/440

Calling function with callback defined as string

var method = 'serviceName.MethodName'
I Just want to call it like
serviceName.methodName(function(output callback){
});
Is there any approach to call it.thanks
There are two methods that I can think of now.
JS eval
You can use the javascript eval function to convert any string into code snippet like below. Although eval is a quick solution but should not be used unless you dont have any other option by your side.
var method = 'UserService.getData';
eval(method)();
Factory pattern
Use a below pattern to get the service
You would need to define the services in such a manner that you can access them using a pattern.
var Services = {
// UserService and AccountsService are again objects having some callable functions.
UserService : {getData: function(){}, getAge: function(){}},
AccountsService : {getData: function(){}, getAge: function(){}},
// getService is the heart of the code which will get you the required service depending on the string paramter you pass.
getService : function(serviceName){
var service = '';
switch(serviceName){
case 'User':
service = this.UserService;
break;
case 'Accounts':
service = this.AccountsService;
break;
}
return service;
}
}
You can use get the required service with below code
Services.getService('User')
I'm not aware of any way you can resolve the serviceName part of that string to an object, without using eval. So obviously you need to be extremely careful.
Perhaps:
if (method.match(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$/) {
var servicePart = eval(method.split('.')[0]);
var methodPart = method.split('.')[1];
servicePart[methodPart](...)
}
There are two separate problems in your question:
How to access object property by property name (string)?
How to access object by it's name (string)?
Regarding the first problem - it is easy to access object property by string using the following notation:
const myObject = {
myProp: 1,
};
console.log(myObject['myProp']);
And regarding the second problem - it depends on what serviceName is:
if it is a property of some other object, then use someObject['serviceName']['MethodName']
if it is a local variable, consider using a Map (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) to associate strings with objects;

Polymer camelCase attributes

I'm writing a wrapper around a js library with Polymer components. Basically, I need to be able to assign attributes to a component, and forward them to an instance of a js object.
The problem is that Polymer (or webcomponents in general?) forces attribute names to be lowercase.
Declaring the element
<some-element fooBar="baz"></some-element>
Generic change listener
attributeChanged: function(attrName, oldVal, newVal){
// attrName -> foobar, which is not a member of someInstance
this.someInstance[attrName] = newVal;
}
Is there some way to get the camel-cased name? Maybe I can create a hash from the publish object on the prototype... but how do I reference that?
Aha! publish is actually available on the component instance! This allows me to grab the names and make a map from lowercase to camelcase.
var map = {};
Object.keys(this.publish).forEach(function(key){
map[key.toLowerCase()] = key;
});

dart method calling context

I used the below to see how dart calls methods passed in to other methods to see what context the passed in method would/can be called under.
void main() {
var one = new IDable(1);
var two = new IDable(2);
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
}
class IDable{
int id;
IDable(this.id);
int getMyId(){
return id;
}
}
caller(fn){
return fn();
}
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
So how does caller manager to call its argument fn without a context i.e. one.fn(), and why does callerJustForThree fail to call a passed in fn on an object which has that function defined for it?
In Dart there is a difference between an instance-method, declared as part of a class, and other functions (like closures and static functions).
Instance methods are the only ones (except for constructors) that can access this. Conceptually they are part of the class description and not the object. That is, when you do a method call o.foo() Dart first extracts the class-type of o. Then it searches for foo in the class description (recursively going through the super classes, if necessary). Finally it applies the found method with this set to o.
In addition to being able to invoke methods on objects (o.foo()) it is also possible to get a bound closure: o.foo (without the parenthesis for the invocation). However, and this is crucial, this form is just syntactic sugar for (<args>) => o.foo(<args>). That is, this just creates a fresh closure that captures o and redirects calls to it to the instance method.
This whole setup has several important consequences:
You can tear off instance methods and get a bound closure. The result of o.foo is automatically bound to o. No need to bind it yourself (but also no way to bind it to a different instance). This is way, in your example, one.getMyId works. You are actually getting the following closure: () => one.getMyId() instead.
It is not possible to add or remove methods to objects. You would need to change the class description and this is something that is (intentionally) not supported.
var f = o.foo; implies that you get a fresh closure all the time. This means that you cannot use this bound closure as a key in a hashtable. For example, register(o.foo) followed by unregister(o.foo) will most likely not work, because each o.foo will be different. You can easily see this by trying print(o.foo == o.foo).
You cannot transfer methods from one object to another. However you try to access instance methods, they will always be bound.
Looking at your examples:
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
These lines are equivalent to:
print('one ${caller(() => one.getMyId())}');
print('two ${caller(() => two.getMyId())}');
print('one ${callerJustForThree(() => one.getMyId())}';
Inside callerJustForThree:
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
The given argument fn is completely ignored. When doing three.fn() in the last line Dart will find the class description of three (which is IDable) and then search for fn in it. Since it doesn't find one it will call the noSuchMethod fallback. The fn argument is ignored.
If you want to call an instance member depending on some argument you could rewrite the last example as follows:
main() {
...
callerJustForThree((o) => o.getMyId());
}
callerJustForThree(invokeIDableMember){
var three = new IDable(3);
invokeIDableMember(three);
}
I'll try to explain, which is not necessarily a strength of mine. If something I wrote isn't understandable, feel free to give me a shout.
Think of methods as normal objects, like every other variable, too.
When you call caller(one.getMyId), you aren't really passing a reference to the method of the class definition - you pass the method "object" specific for instance one.
In callerJustForThree, you pass the same method "object" of instance one. But you don't call it. Instead of calling the object fn in the scope if your method, you are calling the object fn of the instance three, which doesn't exist, because you didn't define it in the class.
Consider this code, using normal variables:
void main() {
var one = new IDable(1);
var two = new IDable(2);
caller(one.id);
caller(two.id);
callerJustForThree(one.id);
}
class IDable{
int id;
IDable(this.id);
}
caller(param){
print(param);
}
callerJustForThree(param){
var three = new IDable(3);
print(three.id); // This works
print(param); // This works, too
print(three.param); // But why should this work?
}
It's exactly the same concept. Think of your callbacks as normal variables, and everything makes sense. At least I hope so, if I explained it good enough.

System.Linq.Dynamic .Select("new ...") does not appear to be thread safe

I grabbed System.Linq.Dynamic.DynamicQueryable from here:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
The issue that I am running into is in code that looks like this:
var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
It appears that if that line of code is executed by multiple threads near simultaneously, Microsoft's dynamic Linq code crashes in their ClassFactory.GetDynamicClass() method, which looks like this:
public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
{
rwLock.AcquireReaderLock(Timeout.Infinite);
try
{
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type))
{
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type); // <-- crashes over here!
}
return type;
}
finally
{
rwLock.ReleaseReaderLock();
}
}
The crash is a simple dictionary error: "An item with the same key has already been added."
In Ms code, The rwLock variable is a ReadWriterLock class, but it does nothing to block multiple threads from getting inside classes.TryGetValue() if statement, so clearly, the Add will fail.
I can replicate this error pretty easily in any code that creates a two or more threads that try to execute the Select("new") statement.
Anyways, I'm wondering if anyone else has run into this issue, and if there are fixes or workarounds I can implement.
Thanks.
I did the following (requires .NET 4 or later to use System.Collections.Concurrent):
changed the classes field to a ConcurrentDictionary<Signature, Type> ,
removed all the ReaderWriterLock rwLock field and all the code referring to it,
updated GetDynamicClass to:
public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) {
var signature = new Signature(properties);
return classes.GetOrAdd(signature, sig => CreateDynamicClass(sig.properties));
}
removed the classCount field and updated CreateDynamicClass to use classes.Count instead:
Type CreateDynamicClass(DynamicProperty[] properties) {
string typeName = "DynamicClass" + Guid.NewGuid().ToString("N");
...

Resources