CategoryFixing

How to support promised predicates in Array find

I’m building ACL support in NodeJS. For example, I’ll allow to write:

if (Can(currentUser, 'edit', theDocument)) {
    buttons.push('Edit');
}

For any given action, my ´Can´ function must check a list of permissions. If one matches, then the action ´Can´ asks for is granted, otherwise (no permission exists) it’s denied. Of course I’m only interested in the first permission to match, and to allow for optimizations, I want permissions to be checked in the order I provide.

It’s easy to see that my problem is solved by the Array.prototype.find method. The problem I have, though, is that it only works with immediate predicates, but my checks can entail both immediate and promised predicates. For example, I allow predicates to access the database.

I googled my problem and found this StackOverflow page. Bergi’s answer gives both recursive and non-recursive solutions. (Side note. There was a time when recursive was opposed to iterative. With promises, that’s no longer the case. In fact, the non-recursive solution is a chain of ´catch´ handlers. An iteration is used to build the chain but promises themselves, throwing exceptions, control the iteration.) Benjamin Gruenbaum’s answer gives a recursive solution.

Here are their issues.

  1. The predicate is hacky because it signals a ´false´ by throwing an exception.
  2. The promise management is hacky because (a) it must cater for the predicate with ´.catch()´, and (b) it signals the “not found” outcome with ´reject()´.
  3. The promise management and the predicate are very coupled.
  4. The contract is different from that of the Array.prototype.find method.

So I came up with this one.

function ArrayFind(array, Predicate, thisArg) {
    function MyPredicate(element, index, arr) {
        return Promise.resolve(Predicate.call(thisArg, element, index, arr))
            .then(function (value) {
                return value ? element : undefined;
            });
    }
    function MyResult(element) {
        this.element = element;
    }

    return array.reduce(function(sequence, element, index, arr) {
        return sequence
            .then(function(found) {
                if (found) {
                    throw new MyResult(found);
                }
                return MyPredicate(element, index, arr);
            });
        }, Promise.resolve())
        .catch(function(reason) {
            if (reason instanceof MyResult) {
                return reason.element;
            }
            throw reason;
        });
}

Apart from being a global function instead of an Array instance method, the contract is exactly the same as that of the Array.prototype.find method.

  1. The only hack I used is to immediately exit when an element is found instead of continuing until the end of the ´.then()´ chain. But how I implemented it is both robust (as in Robustness) and hidden (as in Information Hiding). To make sure I do not mistake a rightful exception with my hack, I throw my own fake exception which is a wrapper around the found element. Thus, my fake exception is caught by the last ´.catch()´ and the element is returned.
  2. The predicate can be both immediate or a promise, thanks to ´Promise.resolve(Predicate…)´. If it’s immediate, it can throw an exception if it has to, not if it doesn’t hold true. If it’s a promise, it can reject() if it has to, not if it doesn’t hold true.

Examples

Here are some examples.

    function ImmediatePredicate(n) {
        console.log('-- ' + n);
        if (n % 3 == 0) throw 'dirty'; 
        return n % 2 == 0;
    }

    function PromisePredicate(n) { 
      return new Promise(function(resolve, reject) { 
        window.setTimeout(function() {
          console.log('-- ' + n);
          if (n % 3 == 0) reject('dirty'); 
          resolve(n % 2 == 0);
        }, Math.random() * 2000 + 1000); 
      }); 
    }

    function MixedPredicate(n) {
        if (n < 10) return ImmediatePredicate(n);
        return PromisePredicate(n);
    }

The result is a promise

Here is how ArrayFind compares to Array.prototype.find when no exceptions are thrown:

[1,13,5,4,7].find(ImmediatePredicate)
VM834:3 -- 1
VM834:3 -- 13
VM834:3 -- 5
VM834:3 -- 4
4

ArrayFind([1,13,5,4,7], ImmediatePredicate)
VM834:3 -- 1
VM834:3 -- 13
VM834:3 -- 5
VM834:3 -- 4
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

Of course the result is a Promise instead of the found element, but we can append additional handlers, like

ArrayFind([1,13,5,4,7], ImmediatePredicate)
  .then(function(result){
    console.log(result);
  })
  .catch(function(reason){
    console.warn(reason)
  })

VM834:3 -- 1
VM834:3 -- 13
VM834:3 -- 5
VM834:3 -- 4
VM880:4 4
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

An exception makes the promise reject

Here is how ArrayFind compares to Array.prototype.find when an exception is thrown:

[1,3,5,4,7].find(ImmediatePredicate)
VM834:3 -- 1
VM834:3 -- 3
VM834:4 Uncaught dirty

ArrayFind([1,3,5,4,7], ImmediatePredicate)
  .then(function(result){
    console.log(result);
  })
  .catch(function(reason){
    console.warn(reason)
  })

VM834:3 -- 1
VM834:3 -- 3
VM925:7 dirty
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

Immediate and promised predicates work equally well

Here you can see how ArrayFind supports at the same time immediate and promised predicates:

ArrayFind([1,13,5,4,7], MixedPredicate)
  .then(function(result){
    console.log(result);
  })
  .catch(function(reason){
    console.warn(reason)
  })

VM834:3 -- 1
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
VM834:12 -- 13
VM834:3 -- 5
VM834:3 -- 4
VM955:4 4


ArrayFind([1,3,5,4,7], MixedPredicate)
  .then(function(result){
    console.log(result);
  })
  .catch(function(reason){
    console.warn(reason)
  })

VM834:3 -- 1
VM834:3 -- 3
VM974:7 dirty
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}


ArrayFind([1,12,5,4,7], MixedPredicate)
  .then(function(result){
    console.log(result);
  })
  .catch(function(reason){
    console.warn(reason)
  })

VM834:3 -- 1
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
VM834:12 -- 12
VM975:7 dirty

You can’t appreciate from the output above, but the immediate predicate really outputs immediately. :-)

Also notice that in the second to last example the warned ´dirty´ comes from the immediate predicate because 3 < 10, while in the last example it comes from the promised predicate because 12 >= 10.

How to run WordPress tests in VVV using WP-CLI and PHPStorm 8

Some time ago I wrote an analogous reminder: How to run WordPress tests in VVV using PHPStorm 8. Today I can do it again. And I really mean can instead of a simpler and also possible must. In fact, only some minutes ago I was able to solve this issue.

In my mentioned article, I explained how to do everything for the ´wordpress-develop´ site. It is what allows you to develop the WordPress core, for example for fixing a bug. And with the help of VVV / Vagrant / VirtualBox, setting up the environment is almost a painless task.

At some point I decided it was time to start developing the new version of my very old Enzymes plugin. I thought that it would make a lot of sense to take advantage of the ´wordpress-default´ site which VVV provides too, so I checked out my plugin code from wordpress.org, and, for some days, I could think and write my new code in a PHPStorm project, as I use to.

When I needed to debug an intermittently failing test, I recalled that I had written a reminder about that, and happily read it and applied all those steps again… to no avail. Oops.

Of course there had to be some difference. The first one I could think of was that before I had used the ´phpunit.xml.dist´ configuration file that came packaged with VVV, while now I was trying to use the ´phpunit.xml´ generated by the ´wp scaffold plugin-tests´ command. However it didn’t seem the right issue here.

What absolutely I could not understand was why I could run my PHPUnit tests smoothly from the command line but not from PHPStorm, not even following my own fabulous how-to instructions that had worked so well before. It drove me crazy, and more so because I couldn’t solve it.

From time to time I got back to having a need for debugging my tests, and tried to configure PHPStorm again, but never succeeded.

Today I also tried an alternative I found on the PHPStorm issue tracking site. WI-25653: Path mapping not considered when running PHPUnit tests with remote interpreter… I really wanted the solution outlined in the comment to be the one, but I couldn’t make that work either.

I was very sad. It had to be the solution, because that was almost exactly the problem I had:

Screen Shot 2015-02-12 at 22.25.29

Of course the problem I had was that PHPStorm was trying to access a path in my hosting environment (OSX) thinking it was a path in the hosted environment (Ubuntu). In fact my ´phpunit.xml´ file not only was very real, but I had previously selected it with PHPStorm itself !!

Screen Shot 2015-02-12 at 22.33.05

So I deleted that field, unchecked the Use alternative configuration file, and clicked on that last icon on the right… Just because.

Screen Shot 2015-02-12 at 22.03.27

It opened the PHPUnit dialog, which I knew very well already.

Screen Shot 2015-02-12 at 22.38.44

Well, better to look at the remote configuration.

Screen Shot 2015-02-12 at 22.40.24

Then, all of a sudden, I noticed something that I saw many many times before.

Screen Shot 2015-02-12 at 22.44.43

I checked the Default configuration file and clicked on the button on the right. It opened this:

Screen Shot 2015-02-12 at 22.50.27

Tah-Dah!! That’s it: Remote browsing!!

So I selected my ´phpunit.xml´ file.

Screen Shot 2015-02-12 at 22.53.51

Lastly, the dialog for the PHPUnit / Remote configuration looked like this:

Screen Shot 2015-02-12 at 22.54.14

After the click on OK I had this:

Screen Shot 2015-02-12 at 23.06.09

Simple to solve issue this one. Just refresh the Run/Debug Configurations dialog by checking and unchecking the Use alternative configuration file. And we’re ready to go:

Screen Shot 2015-02-12 at 23.09.31

Wow ! Almost there. Notice how the configuration file is working perfectly fine now.

Hm… I saw this piece of path ´/tmp/wordpress-tests-lib´ in the ´bootstrap.php´ file… right.

Screen Shot 2015-02-12 at 23.22.49

What is the value of ´WP_TESTS_DIR´ when I execute PHPUnit from the CLI?

Screen Shot 2015-02-12 at 23.26.54

If I put that in my Run/Debug Configurations dialog?

Screen Shot 2015-02-12 at 23.30.10

Alleluia, alleluia, alleluia.

Screen Shot 2015-02-12 at 23.32.30

(The backtrace is part of my stuff.)

Actually, no! It’s not working YET !!!

I can run and debug, I mean, I can click on the run and on the debug buttons and PHPStorm completes without any difference with respect to what I have when I run PHPUnit from the CLI. When I get reds in the CLI, I also get reds in PHPStorm, and when I get greens in the CLI, I also get greens in PHPStorm.

BUT there is no way to make PHPStorm see my breakpoints !! It simply ignores them.

To be fair, PHPStorm tells me something. There is an x on the breakpoint icon. Hovering, it displays this message: “File path is not mapped to any file path on server. Edit path mappings to fix the problem.” Very cryptic, or very wrong. I remember that I set my path mappings before.

Screen Shot 2015-02-13 at 1.34.29

So??

Clicking on Validate remote environment I got this:

Screen Shot 2015-02-13 at 1.39.07

Well, not exactly, because this is what it’s supposed to look like when it’s fixed :-) In my case, the Deployment server was empty and its selection list was empty too, so there was no other option than to click on the top-right button.

Same as above, this is what the Deployment / Connection panel is supposed to look like when it’s fixed.

  1. The Type must be ´SFTP´.
  2. The SFTP Host and Root path must be respectively ´local.wordpress.dev´ and ´/vagrant/www/wordpress-default´ which are the host name and the root directory for the ´wordpress-default´ site.
  3. Upload/download project files / Test SFTP connection… and Browse files on server / Open must work fine.
  4. I decided to set the Name equal to the SFTP Host (easier for me).
  5. User name and Password are both ´vagrant´, as per VVV setup.
  6. Autodetect does not work. For me it got ´/home/vagrant´ but that didn’t work (it didn’t make much sense either…).
  7. Last, but not least: check Save password.

And now the infamous Deployment / Mappings panel.

Screen Shot 2015-02-13 at 1.57.56

Here you could have a couple of entries: if so, remove one and make your panel look like the one above.

  1. Local path must be the path corresponding to the Root path on the Connection panel, thus ´~/dev/wp/vvv/www/wordpress-default´.
  2. Deployment path… must be the path corresponding to Local path, but considering the Root path on the Connection panel, thus ´/´.
  3. Web path… well… I think this one should be the same as the previous one, according to how all other fields are configured.

Lastly, after clicking the Validate Remote Environment / Validate button, I got:

Screen Shot 2015-02-13 at 2.22.23

Is that right? No idea, but at least it doesn’t say it’s wrong either :D. Funny, no OK button here… use Cancel.

Will it work now? NO!

There is yet another step, which (luckily?) I could find in this forum thread: PHPStorm 8 / Vagrant / Xdebug.

The crucial last point is… to tell PHPStorm to mind that whatever we were doing in the last couple of hours we really meant it. And how do we do it? Like this.

Open again the dialog for the PHPUnit / Remote configuration (I showed it above) and click on the top-right button, next to the Interpreter selection box.

Screen Shot 2015-02-13 at 1.17.54

Once again, this is how the Interpreters dialog is supposed to look like when it’s fixed. In my dialog I had selected Remote / Vagrant, but of course, the correct option is… Remote / Deployment configuration. And make sure Test connection really works.

Now… NOW IT DOES WORK !!

Screen Shot 2015-02-13 at 2.38.02

After using it a few hours, here is a better configuration, to have path mappings also for debugging into the WordPress code that my testing bash file downloads and installs: ´bash bin/install-wp-tests.sh test-db root root localhost latest´.

First, Deployment / Connection.

Screen Shot 2015-02-13 at 16.31.35

And then, Deployment / Mappings.

Screen Shot 2015-02-13 at 16.32.03

It works fine because my ´wordpress-default´ site is actually the latest stable version, so anything in ´/tmp/wordpress´ and in ´~/dev/wp/vvv/www/wordpress-default´ corresponds to each other one to one.

Unchecked property overloading is detrimental to OOP

 

A couple of issues with the HTML Standard

While reading the HTML Standard specification, I reported a couple of issues:

  • Bug 27339 – Tag omission for p element
  • Bug 27445 – Suggestion for a Simpler Description of Transparent Elements

 

Class RegularExpression for PHP

UPDATE

This is a small class for handling Regular Expressions in PHP. I often have to use backreferences and it’s very cumbersome to compose simple expressions with them into more complex ones, because I have to manually count all capturing groups many times in a row. This class basically solves that issue for me.

{[ .class | 1.hilite(=php=) ]}

 

© 2017 Notes Log

Theme by Anders NorenUp ↑