How do I eliminate the repetition in this template helper? - coffeescript

I have a Meteor Handlebars template helper that is representative of most of my template helpers as shown below.
# Address Form Controls Template
Template.AddressFormControls.helpers
address1: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building?.address?.address1
address2: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building.address.address2
city: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building.address.city
state: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building.address.state
zip_code: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building.address.zip_code
main: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building?.phone?.main
fax: () ->
if typeof Session.get('edit-building') is 'string'
building = Buildings.findOne(Session.get('edit-building'))
return building?.phone?.fax
You will notice that every helper contains an if statement to see if the Session variable is a string. If it's a string, then it should be an ID that can be used to perform the search for the needed object.
It seems like such a waste to have that repeated throughout a project for the various collections that one uses.
How can I DRY this up?
Help me Obiwan you're my only hope!

You could shorten it with something like
js:
main:function() {
building = Buildings.findOne({_id:Session.get('edit-building')})
return building && building.phone && building.phone.main;
}
coffee:
main: () ->
building = Buildings.findOne(_id: Session.get("edit-building"))
building and building.phone and building.phone.main
The key difference being explicitly saying you want the _id to match. So in the case the Session variable for edit-building doesn't exist, isn't a string or doesn't match any records nothing is returned.
Just this might shorten your code a lot too:
building: () ->
Buildings.findOne(_id: Session.get("edit-building"))
Then in your html (in the AddressFormControls template) you could do:
{{#if building}}
Phone: {{building.phone.main}}
Fax: {{building.phone.fax}}
....
{{/if}}

Related

Flutter functions Null safety errors

Got the following errors and don't know how to update the code to solve it.
Error: Can't use an expression of type 'Function?' as a function because it's potentially null.
'Function' is from 'dart:core'.
Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
The code:
enum PageName {
welcomePage,
register,
login,
editProfile,
showProfile,
resetPassword,
errorUserExists,
}
Map<PageName, Function> pageName_pageFunction_map = {
PageName.welcomePage: showWelcomePage,
PageName.register: showRegisterPage,
PageName.login: showLoginPage,
PageName.editProfile: showEditProfile,
PageName.showProfile: showUserProfile,
PageName.resetPassword: showResetPassword,
PageName.errorUserExists: showErrorUserExists,
};
void main() {
PageName nextPage = pageName_pageFunction_map[PageName.welcomePage]();
if (nextPage != null) {
while (true) {
PageName nextPage2 = pageName_pageFunction_map[nextPage]();
if (nextPage2 != null) {
nextPage = nextPage2;
}
}
}
}
Can you help me? Thank you
The error message tell that you can't execute a function because this one might be null, and if you execute a function on a null value it will break the program. You have two solution :
First you can make sure that your function isn't null with a test :
if (myFunction != null) {
myFunction()
}
Or you can tell the compiler that your function is not null with the ! operator
myFunction!()
Error: Can't use an expression of type 'Function?' as a function
because it's potentially null.
When you look up one of your functions from the map like pageName_pageFunction_map[PageName.welcomePage] you get a value of type Function?. This is because if you enter a key which does not have a corresponding value, you will get back null from the expression.
The following error message gives you a suggestion on how to solve this problem.
'Function' is from 'dart:core'. Try calling using ?.call instead.
PageName nextPage = pageName_pageFunction_mapPageName.welcomePage;
PageName nextPage2 = pageName_pageFunction_mapnextPage;
You can place ?.call directly before the argument list () to safely call the function;
pageName_pageFunction_map[PageName.welcomePage]?.call();

Null-aware .firstWhere, .singleWhere, .lastWhere in Dart's List?

I often use .firstWhere((E element) -> bool) -> E in my project. When porting it to support null safety I couldn't cleanly handle a scenario when an element is not found in a List instance.
.firstWhere, .singleWhere and .lastWhere returns E, not E? so when handling a case when a List does not contain required element there's no other way to return null other than casting a whole list from eg. List<String> to List<String?> which makes testing function worried about each element being potentially null, which it can't be. Before null safety I was able to just use orElse: () => null but with null safety orElse have to return element of type E so troublesome casting is required.
Do I have to have a null substitute for each type to use in orElse or are there other methods to make list checking support missing element scenario with null?
You can just use firstWhereOrNull which should work exactly as you expect.
The solution would be to create an extension on the Iterable type:
extension IterableModifier<E> on Iterable<E> {
E? firstWhereOrNull(bool Function(E) test) =>
cast<E?>().firstWhere((v) => v != null && test(v), orElse: () => null);
}
Then use it like this:
final myList = <String?>['A', 'B', null, 'C'];
String? result = myList.firstWhereOrNull((e) => e == 'D');
print(result); // output: null
result = myList.firstWhereOrNull((e) => e == 'A');
print(result); // output: "A"
Try the full example on DartPad

Why is Unit in PureScript's Prelude {} in JavaScript?

I'm a beginner to FP and Type-level programming.
I learned Void and Unit recently.
Prelude's unit is defined as {} in JavaScript.
"use strict";
exports.unit = {};
My question is "Why not null but {}?"
Maybe this is a trivial question, but I'd like to learn its philosophy.
From my understanding, unit corresponds to null in JavaScript.
For example, I can call a function with no arguments in JavaScript.
// hello :: Void -> String
function hello () {
return "hello"
}
const h1 = hello() // "hello"
// However, I do not have any members of `Void` in PureScript, so I cannot call like above.
If I have to specify some arguments of hello function, I choose null rather than {}.
// hello :: forall a. a -> String
function hello (a) {
return "hello"
}
// 'hello :: Unit -> String'-like
const h1 = hello(null) // "hello"
// undefined also works, but weird to me
const h2 = hello(undefined)
// also works, but weird
const h3 = hello(42)
const h4 = hello({})
const h5 = hello([])
If unit represents a side-effect, probably is it undefined or something null?
// 'log1 :: String -> Effect Void'-like
function log1 (s) {
return s => () => console.log(s) // console.log return undefined
}
// however, function must return a value
// 'log2 :: String -> Effect Unit'-like
function log2 (s) {
return s => () => {
console.log(s) // side-effect
return null
}
}
// foreign Effect.Console.log (ECMAScript-style)
function log3 (s) {
return s => () => {
console.log(s)
return {} // weird to me; it seems like 'return 42'
}
}
Am I missing something?
It doesn't actually matter what value you use for Unit. {} is a pretty arbitrary choice - undefined or null, or just not returning a value are all fine too if you're writing something in the FFI. Since Unit is only supposed to have one inhabitant, there's never a time that the actual runtime value for it is examined.
It's quite a long time since the choice of {} was made - it's probably a historical accident, leftover from the time that all non-Prim PS values were constructed as anonymous objects.

Access to the elements of the page in the Page-Worker

I've created a page-worker in the extension
dup = pageWorker.Page({
contentScript: "self.port.on('alert', function(message) {"+
"console.log(message);"+
"document.querySelector('.test-element').title = message;"+
"});",
contentScriptWhen: "ready",
contentURL: "http://example.com/Licznik-beta/addon.html"
});
In "contentScript" I can relate to "document".
But I can not relate to the window, or function, or variable.
console.log(window) in contentScript return "TypeError: cyclic object value timers.js:43".
I do not understand how it works.
Can someone explain to me?
How to change it?
EDIT
I've added a few lines to the test:
self.port.on('addon-licznik', function () {
console.log(document);
console.log(window); // TypeError: cyclic object value timers.js:43
runFromAddon(); // ReferenceError: runFromAddon is not defined timers.js:43
});
Function: runFromAddon(); Of course there is.
Second test:
function funSet (tresc) {
var addonScript = document.querySelector(".addon-script");
if ( addonScript != undefined ) {
document.querySelector('head').removeChild( addonScript );
}
var script = document.createElement("script");
script.className = "addon-script";
script.textContent = tresc;
document.querySelector('head').appendChild(script);
}
function marmo (message) {
console.log(message);
funSet("console.log(window); runFromAddon();");
}
self.port.on('addon-licznik', marmo);
It works well.
Window → http://example.com/Licznik-beta/addon.html
runFromAddon-Log
If you're writing the HTML yourself, then use addon instead of self and attach the script to the page using <script></script> instead of contentScript(File). See Scripting trusted page content.
If you're not writing the HTML, then see Communicating with Page Scripts.

Object from comprehension in CoffeeScript [dict/hash comprehensions]

is there a way to return an object from a comprehension in coffeescript? something so that i could express this:
form_values = () ->
ret = {}
ret[f.name] = f.value for f in $('input, textarea, select')
return ret
like this:
form_values = () -> f.name, f.value for f in $('input, textarea, select')
i'd like to construct a single object (not an array of objects). so if the markup looks something like this:
<form name=blah>
<input type=text name=blah1 value=111 />
<textarea name=blah2>222</textarea>
<select name=blah3>
<option value=333a>
<option value=333b>
</select>
</form>
the returned object would be something like this:
{
blah1: '111',
blah2: '222',
blah3: ''
}
form_values = new ->
#[f.name] = f.value for f in $ 'input, textarea, select'
this
or
form_values = new class then constructor: ->
#[f.name] = f.value for f in $ 'input, textarea, select'
Nope. Comprehensions only return arrays in CoffeeScript. Search the issue tracker for object comprehensions, and you'll find several proposals, but none were found suitable.
Check the functional library underscore and the extension _.mash from this mixin:
form_values = ->
_($('input, textarea, select')).mash f -> [f.name, f.value]
Using underscore's object function, you can do this:
form_values = _.object([f.name, f.value] for f in $('input, textarea, select'))
This has already been answered but probably lack of some explanations as this idiom is rather cryptic at first sight:
form_values = (new -> #[f.name] = f.value for f in $ 'input, textarea, select'; #)
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
// create with |
// a new that |
// empty anonymous |
// object constructor |
// don't forget -/
// to return the
// newly created object
The key idea is to create an empty object (new) with an anonymous constructor (-> ...) that will create the various fields.
CoffeeScript's creator suggests using a helper function to convert an array of pairs into an object:
form_values = toObject([f.name, f.value] for f in $('input, textarea, select'))
This is arguably the most readable way of doing it, within the current language syntax. It's also very similar to how Python and other languages do it, except for the missing syntactic sugar.
The helper function can be easily written once, using for example the technique from #matyr's and #Sylvain's answers:
// Create a new object from an array of [key, value] pairs.
toObject = (pairs) ->
new -> #[key] = value for [key, value] in pairs; #
I believe you can do this with no added libraries right in CoffeeScript.
It should be something to the effect of:
$('input, textarea, select').each (item) => #form_values || #form_values = {}; #form_values[$(item).name] = $(item).value
You could simplify the syntax of that by pre-creating the form_values:
form_values = {}
$('input, textarea, select').each (item) -> form_values[$(item).name] = $(item).value
Here is a lengthier response with canned examples:
Take a very simple example where you wanted to map the obj to name value:
items = [ { a: 1 }, { b: 2 }, { c: 3 } ]
items.map((item) -> {name: Object.keys(item)[0], value: item[Object.keys(item)[0]]})
[ { name: 'a', value: 1 },
{ name: 'b', value: 2 },
{ name: 'c', value: 3 } ]
Note that the above is not really an Object comprehension, just demonstrating an example.
Now let's say there is a bit more structure and you just want to map a known unique key:
items = [{key: "abc", someVar: 1}, {key: "def", someVar: 2}]
In Python you'd do something simple like this: {x['key']:x for x in items}
In CoffeeScript you can get all of this down to one single line though with a caveat:
items.forEach (item) => #x || #x = {}; #x[item['key']] = item
{ abc: { key: 'abc', someVar: 1 },
def: { key: 'def', someVar: 2 } }
In the above code x was not previously defined in the scope, so using => and # allowed us to bind x with the #x || #x = {} if not previously found, then set the key.
If you don't want to use => and # you have to define x beforehand:
x = {}
items.forEach (item) => x || x = {}; x[item['key']] = item
{ abc: { key: 'abc', someVar: 1 },
def: { key: 'def', someVar: 2 } }
Not to beat a dead horse, but I personally thing this is readable and satisfies the 'one line' requirement without needing extra modules:
form_values = {}; form_values[f.name] = f.value for f in $('input, textarea, select')
Don't forget you can still use a semi-colon to combine lines in Coffeescript!