Tuesday, December 9, 2014

Make Javascript apps environment-aware

When writing client apps, we usually need to connect to the data server. However, this connection is typically different for production and test environments. This post describes a simple way I’ve come up with to solve this little problem.

The client scripts are expecting to read in the environment somehow. A JS file reads it in as some variable say:
   var env;
Okay, the client read in the configuration from a config file that we access using jQuery like so:
  var env;
  $.getJSON( 'config.json', function( json ) {
    env = json;
  });
 And in the configuration file, is a JSON structure for example:
   file: config.json
  {
    data_server : 192.168.1.31:4005
  }
However, that value is different for different deployment environments. So let’s say we save all the different configurations in another file e.g:

  file: config_all.json
  { 
    TEST : { data_server : 192.168.1.31:4005 },
    PROD : { data_server : 192.168.1.31:3005 }
  }
And we’ll need a simple script that can generate the config.json from the config_all.json file. Something like:

  $ configure_env PROD
  or
  $ configure_env TEST
From a project directory standpoint, the config.json file needs to be accessible within the browser while the config_all.json file should be outside. So we end up something like the following structure: 
  project/tools/configure_env
  project/tools/config_all.json
  project/www/js/config.json
Here’s a simple implementation of configure_env in perl:

  #!/usr/bin/env perl

  use strict;
  use warnings;
  use Path::Tiny qw/path/;
  use JSON;

  my $env = $ARGV[0] || 'TEST';   # Defaults to TEST environment
  my $source_file = 'tools/config_all.json';
  my $target_file = 'www/js/config.json';

  my $config_all = decode_json path($source_file)->slurp();
  path($target_file)->spew(encode_json $config_all->{$env});

Now, whenever we need to add an environment-specific value, we just open up config_all.js and put in the value we need and on the client, it becomes accessible.

Thursday, November 13, 2014

How to add a transaction programmatically to GnuCash - SQLs

This post describes the SQLs needed to add a transaction that captures the transfer of money from one asset account (Cash) to another asset account (aBank).

Refer to this post and this post for background details that feeds into this post.

Update: I've created a perl module, GnuCash::SQLite to simplify the process of adding transactions to Gnucash.

Caveats:
  1. SQLs below are for transferring money from one Asset account to another Asset account. For transactions to/from Income or Expense accounts, it may be different, so beware.
  2. Assumes single currency.
Input data

Input data structure as follows: {
    tx_date        : 20140102
    tx_description : Transfer
    tx_from_acct   : Cash
    tx_to_acct     : Assets:aBank
    tx_amt         : 1000
    tx_num         : (typically blank, as in this case)
}

Then add derived information as follows: {
    tx_guid        : gen_guid(32),
    tx_currency    : lookup_currency_guid(tx_from_acct),
    tx_post_date   : gen_post_date(tx_date),
    tx_enter_date  : system_timestamp(),
    tx_from_guid   : lookup_account_guid(tx_from_acct),

    tx_to_guid     : lookup_account_guid(tx_to_acct),
    tx_from_numer  : tx_amt * -100,
    tx_to_numer    : tx_amt * 100
}

SQL #1: Insert into Transactions table

INSERT INTO transactions VALUES ( 
    tx_guid,
    tx_currency,
    tx_num,
    tx_post_date,
    tx_enter_date,
    tx_description
);

SQL #2: Insert 2 rows into splits table

For splits, create additional derived data: {
    splt_guid_1 : gen_guid(32),
    splt_guid_2 : gen_guid(32)

}

INSERT INTO splits VALUES (
    splt_guid_1,
    tx_guid,
    tx_from_guid,
    '',
    '',
    'n',
    '',
    tx_from_numer,
    100,
    tx_from_numer,
    100,
    null
);

INSERT INTO splits VALUES (
    splt_guid_2,
    tx_guid,
    tx_to_guid,
    '',
    '',
    'n',
    '',
    tx_to_numer,
    100,
    tx_to_numer,
    100,
    null
);


CREATE TABLE splits (
    guid            CHAR(32) PRIMARY KEY NOT NULL,
    tx_guid         CHAR(32) NOT NULL,
    account_guid    CHAR(32) NOT NULL,
    memo            text(2048) NOT NULL,
    action          text(2048) NOT NULL,
    reconcile_state text(1) NOT NULL,
    reconcile_date  timestamp NOT NULL,
    value_num       integer NOT NULL,
    value_denom     integer NOT NULL,
    quantity_num    integer NOT NULL,
    quantity_denom  integer NOT NULL,
    lot_guid        CHAR(32)
); 

SQL #3: Insert 1 row into slots table

INSERT INTO slots (
    obj_guid,
    name,
    slot_type,
    int64_val,
    string_val,
    double_val,
    timespec_val,
    guid_val,
    numeric_val_num,
    numeric_val_denom,
    gdate_val
) VALUES (
    tx_guid,
    'date-posted',
    '10',
    '0',
    '',
    '0.0',
    '',
    '',
    '0',
    '1',
    tx_date
)

CREATE TABLE slots (
    id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
    obj_guid            CHAR(32) NOT NULL,
    name                text(4096) NOT NULL,
    slot_type           integer NOT NULL,
    int64_val           integer,
    string_val          text(4096),
    double_val          real,
    timespec_val        CHAR(14),
    guid_val            CHAR(32),
    numeric_val_num     integer,
    numeric_val_denom   integer,
    gdate_val           text(8) 
);

----
Sample data below. See the GnuCash series on what the data below means.

** slots **
7|ded5efa287a34e862794b4277f8e0508|date-posted|10|0||0.0|||0|1|20140102
 

** splits ** 
47df2567833d70d7771c99b7dc47154e|ded5efa287a34e862794b4277f8e0508|6a86047e3b12a6c4748fbf8fde76c0c0|||n||-100000|100|-100000|100| 

f8f99cf7d8974bcba4e07d4cb9cb9d3e|ded5efa287a34e862794b4277f8e0508|6b870a6ef2c3fbbff0ec6df32108ac34|||n||100000|100|100000|100| 

** transactions ** 
ded5efa287a34e862794b4277f8e0508|be2788c5c017bb63c859430612e64093||20140101170000|20141111071603|Transfer

Wednesday, November 12, 2014

Javascript - Unit Testing (with Jasmine) on a browser

This post is about unit testing Javascript using Jasmine using a browser.

1. Get Jasmine here.
2. Download and unpack -- mine is in ~/app/jasmine
3. Project directory should be something like:


4. Edit the SpecRunner.html file to include the source files and the test files:


5. The test file should not run the "require" code:


6. Run the tests by viewing on the browser:

Done.

To run tests on nodejs instead of via a browser, see this earlier post.

Javascript - Unit Testing (with Jasmine) using NodeJS

Here's how to implement unit testing (with Jasmine and Node) for a class defined earlier:


Source files in subfolder "src" and test files in subfolder "spec". All test files must end with ".spec.js". Execute the test like so:


Done.

To run tests via a browser instead, see this other post.

Perl - Unit Testing

Here's a screenshot how unit testing can be implemented in Perl for the class we defined earlier.

The testing file should be in the ./t subfolder. Execute the tests like so:

Done.




Perl - Inheritance

Here's how to do inheritance in Perl:























This uses the Moose object system which is should probably be used for all large Perl applications. Compare this against the Javascript version.

See this post on how to unit test the classes.

Javascript - Inheritance

Below is a diagram that summarizes how inheritance is implemented in Javascript:













This came from the Udacity course on OO Javascript by the way. Compare this against the Perl version of inheritance.

See this post on how to unit test the classes above.