Modules - Loading in WebIDE and Testing

Posted on
Page
of 2
/ 2
Next
  • Hi All

    I've written a Date and Clock module. The Date module uses the same API as JS Date (but doesn't implement everything at all), and Clock inherits from it. (It's all a bit rough so want to polish a bit more before sharing :)

    I'm a bit of a newbie at JS, so have a few questions...

    1. Should these be two modules or one? I guess two... any reason why not?

    2. Is there any way to get WebIDE to pull modules from either a) my PC or b) multiple locations? Can it pull them direct from my github account?

    3. These aren't device modules - where would I put them in github?

    4. Is there any convention for unit tests for Espurino modules?

    Thanks

    Martin

  • One way to get a module into the espruino is to put it on a micro SD card in in node_modules directory, then load it from within the Espruino. You need to put the require command in left hand side, or on the right, you need to confuse the IDE like so:

    var d="DHT22dev"
    var dht=require(d).connect(B0)
    

    (if you do require() with a string that the IDE can't find on the website, it'll refuse to send it at the moment....)

    other way is to do:

    modules.addCached("modulename","module source code goes here");

    I think a way to set a local directory to look for modules in is planned

  • 1) 2 modules is probably better... I don't see any real reason why not - people may just want Date and not clock, and then they won't want the extra memory used up...

    2) You should be able to do:

    var x  =require("http://foo/bar.js");
    

    If you have a webserver on your PC, you should be able to load from localhost... @JumJum's made a 'project' extension for the Web IDE that allows local files, but I've yet to integrate it properly I'm afraid.

    3) I'd try https://github.com/espruino/EspruinoDocs­/tree/master/modules

    4) I'm afraid not. It's an interesting thought actually. To date, most of the modules have been interfacing to hardware so tests haven't been an issue. Perhaps we should start a tests folder. If tests were arranged like: https://github.com/espruino/Espruino/tre­e/master/tests then the existing Espruino executable could test them...

  • Gordon, DrAzzy

    Thanks. I got the require("http").. working

    But how do I create a Date() type within a module which is accessible to users of the module using 'new'? So for example

    require("date");

    d=new Date();

    I did have a reasonable look for any other file like this, didn't see one... maybe I missed it?

    Martin

  • Hi Martin,

    d=require('date').connect();

    Sacha

  • Sacha

    Thanks, but I was hoping for something a bit more like 'new'

    Imagine I want three date objects. I guess I'd have to write

    x=require('date');

    d1=x.connect();
    d2=x.connect();

    It's not very elegant, IMHO :)

    There's also the problem of passing constructors.

    d=require('date'.connect(args)

    I think I can do this using 'apply' inside the 'connect'' function but I'm not sure
    how exactly it would look.

    Martin

  • Yeah I also noticed that you can't export a single class. But the example would be:

    var Date = require('date').connect;
    var d1 = new Date()
    var d2 = new Date()

    :)

    You could also call 'connect' something like '_constructor'.

  • As i understand it, the connect function has to return a new object like this:

    exports.connect = function(arg) {

    return new Date(arg);
    

    };
    var Date=function(arg) {
    this.value=arg;

    console.log('Its alle about Date: '+this.value);
    

    };

    Then you are able to create it like this:

    var d1=require('date').connect('Object_1');
    var d2=require('date').connect('Object_2');

    your output should be like this:

    Its alle about Date: Object_1
    Its alle about Date: Object_2

    Sacha

  • @gadicc - your solution looks good, but I don't know what it would look like inside the module source. "connect" is usually declared as a function member of 'exports' and I suspect declaring the date constructor as "exports.connect = function.." might stop it being a date constructor...

    Ah, someone at my work has said that if I declare the date as normal

    Date = function ()...

    Then put a line like this

    exports.Date=Date;

    Then I can use it like this

    Date = require('date').Date;

    var d1 = new Date();

    I'll test this approach soon...

    Martin

    Martin

  • Yes please don't call the constructor for a new Date 'connect' - that wouldn't have any sense!

  • I think this is solved.

    In the module file:

    function Date() 
    {
    // Constructor code
    }
    
    exports.constructor=Date;
    

    In the referring file

    var Date=require("Date.js").constructor;
    
    var d1=new Date();
    var d2=new Date(2014,10,1,12,0,0,0);
    
  • Sorry for the delay here - @mgg1010 has it sorted... There's no need for a connect function - it just makes sense when you're talking about hardware.

    You could change the name so it's new require("Date").Date - I don't know what people normally tend to do for node.js modules?

  • Gordon

    Thanks. However, I hit another problem last night: I now have this

    Main file

    var Clock = require("http://192.168.0.12/clock.js").­constructor;
    

    Clock file:

    var Date= require("http://192.168.0.12/date.js").c­onstructor;
    

    Is there any issue with doing nested requires?

    Note - I previously appeared to have corruption problems, so I turned on the 'throttle' option. It now seems to be missing some of the code in the second require - is there any chance the throttle setting only applies to the first file?

    BTW - throttle is very slow :(

    Thanks

    Martin

  • Do you have 1v61? That will hopefully solve a lot of issues you would have had with lost characters.

    I've just looked at this - there's no issue with recursive module loading, but there is when one module requires the other. Is there any reason that Date requires Clock? IMO it shouldn't (as it defeats the point of having two modules!).

    I've fixed the Web IDE (from GitHub) anyway now, but the Chrome Web Store one probably won't get updated for another 2 weeks because of the Maker Faire,

  • Gordon

    re: 1v61 - yes, I think so. Will check. I am updating quite often, but have multiple devices.

    re: Recursive - Clock requires Date, but Date doesn't require Clock. Clock creates a subclass of Date.

    The error really does look odd - I included print statements in the module, and it seems to just skip some of them and jump to a lower statement and then complain.

    It's not lost characters, more like lost chunks of 100 bytes or more. Hard to debug - I can't see what it's actually getting.

    Martin

  • That does sound pretty strange. Could you paste up your modules and code? maybe as a Gist if it seems too big for the forum?

  • Gordon

    Thanks. Files attached. Please remember this is my first serious piece of JS - feedback appreciated :)

    My current test code for using it looks like this:

    var Date=require("http://192.168.0.12/date.j­s").constructor;
    var Clock2=require("http://192.168.0.12/cloc­k.js").constructor;
    
    print("hello");
    print(Clock2);
    
    var clk=new Clock2(2014,15,4,23,57,0,0);
    
    function showClock() {
      
        print(clk.getClockTime().toString());
    }
    
    setInterval(showClock,1000);
    

    The result on running:

    Date Module - Loading...
    Before date fn
    After date fn
    getDayssinceepoch
    setDayssinceepoch
    Done Loading Clock Module
    Date Module - Loaded.
    Clock Module - Loading
    xLoading Date
    xDone loading Date
    ERROR: Using '.' operator on non-object at line 66 col 29
    print("Clock module - Loaded.");

                             ^
    

    ERROR: Got String:');
    ' expected ID at line 66 col 31
    print("Clock module - Loaded.");

                               ^
    

    hello
    undefined
    ERROR: Constructor should be a function at line 1 col 161
    var Date=require("http://192.168.0.12/date.js").constructo­r,Clock2=require("http://192.168.0.12/cl­ock.js").constructor;print("hello");prin­t(Clock2);var clk=new Clock2(2014,15,4,23,57,0,0);function showClock(){print(clk.getClockTime().toS­tring())}setInterval(showClock,1E3);

                                                                                                                                                                 ^
    

    Throttle sending is ON. Minify is set to 'simple optimisations'

    Martin


    2 Attachments

  • exports.constructor=Date;

    I've always done:

    exports.constructor = function() {
           return new Date();
    }
    

    like the example modules do.

    Last time I tried optimization from WebIDE, it didn't work. Try turning off minification for now. I was asked to provide simplified code that would make it fail, but I've been super busy lately, and haven't had any time to fiddle with that and cut the code that caused it to a smaller size than "my whole project"

  • DrAzzy

    Your method above won't support arguments to the constructor - my code supports zero, 1 and 7 arguments. Gordon seemed to think my method was fine :)

    I just retested with minify off, and I get the same sort of bizarre error.

    I then just copied the whole of Date and Clock modules into RHS, and fixed
    the exports to use a variable - and it all works.

    Just to double-check, I copied the modules to the SD card - again it works fine.

    These errors strongly suggest that throttle isn't working and characters or chunks of source are being dropped. I could just copy the files to SD card and re-test.

    Gordon - I have 1v61, Chrome 34.0.1847.116 on Win 8.1 pro

    I think this may be only happening because I'm nesting requires. Not sure.

    Martin

  • Just to be absolutely clear - I only get this problem when the modules are being sent to the device by loading from a web-server using a require in the RHS.

    In all other cases - code in the RHS directly or on SD card, there's no problem.

    Thanks :)

  • Your method above won't support arguments to the constructor - my code supports zero, 1 and 7 arguments.

    @mgg1010 sorry if I'm missing the point, but you can pass as many arguments as you want

    exports.constructor = function(foo, bar, baz) {
           return new Date(foo, bar, baz);
    }
    
  • @graf - @mgg1010's method should work fine. AFAIK nothing stops you from doing new require("foo").Bar.

    @mgg1010 - very odd about your issues with the files from http. I actually just tried here and got some problems too. Try turning on throttle send in settings and see if that helps (it'll be slower though).

    It looks like it's taking a while for Espruino to receive/execute the module, as it gets turned into a giant string and sent over (rather than being able to be executed line by line). It means it's losing some characters - although I really hoped I'd fixed that in 1v61.

    I guess the easy fix would be to add the option to auto-minify modules, as currently clicking the 'minify' option will minify the RHS, but not any modules it loads.

  • @graf - your method can't handle a varying number of arguments. Note - I have tested my method, and it works fine :) It's actually pretty logical now that I've understood JS a bit better. The constructor is just a function, and I'm just passing a reference to it out :)

    @Gordon

    It does say a few messages back that I'd tried throttle before, and it doesn't help.

    Actually, I'll be more specific. Right now I'm doing the following

    • Requiring date in my RHS test code - this works with throttle on
    • Requiring clock in my RHS test code
    • requiring date again inside my clock code

    It seems to be only the LAST one that generates the odd errors.

    This raises questions

    1. If there's a module cache, why does my second-level require inside clock attempt to re-load date? (I can see it printing log messages, so it is doing
      this)

    2. Hmm - presumably the second-level require inside clock is being handled by the device, not the IDE. Maybe the problem is that the code in the device to read from an HTTP address also needs throttle?

    Martin

    1. It's actually a bug in the Web IDE (causing it to reload a module that was already loaded) that I fixed yesterday - so the Web IDE from GitHub shouldn't have the issue.

    2. The device itself won't get from HTTP at the moment - it just pulls it out of its cache (that got loaded from the Web IDE) when it encounters the require.

  • Does the webIDE recursively check requires? I require a module in RHS from website. webIDE downloads it. Does it check inside the downloaded text for a new require?

    Does the webIDE have some way to tell the device "this is a module, insert it into your cache". What name does it give it? I mean, if I use require("http://....date.js") is it added to the cache with the full path or just the filename? (Just curious)

    I still think there is a throttle bug somewhere. I'll try the gitHub webIDE, but otherwise I'll finalize the modules and put them on SD card... that will work around it for now.

    Thanks

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Modules - Loading in WebIDE and Testing

Posted by Avatar for mgg1010 @mgg1010

Actions