about summary refs log tree commit diff stats
                               ━━━━━━━━━
                                  ARA

                                Andinus
                               ━━━━━━━━━


Table of Contents
─────────────────

Documentation
Demo Videos


Ara is a simple cli program that prints Covid-19 stats. Currently it
only prints India's Covid stats.


Documentation
═════════════

  `ara' by default will first look for the file in `$XDG_CACHE_HOME', if
  that is not set then `HOME/.cache' is used, the file name is assumed
  to be `ara.json', there is currently no option to override this or the
  full path.

  If you run `ara' on OpenBSD then it should use `OpenBSD::Unveil'.

  Default logic is to check if the file is available locally & if it's
  not older than 8 minutes, in any other case it fetches the latest
  data. This can be controlled with `local' & `latest' option.

  The file is downloaded over a secure connection & the server's
  identity is verified.


Options
───────

local
╌╌╌╌╌

  This option forces `ara' to use the data available locally, it will
  only override this option when the file doesn't exist on disk.


latest
╌╌╌╌╌╌

  This will force `ara' to fetch the latest data.

  *Note*: `local' & `latest' option cannot be used together, `ara' will
  print a warning & latest option will be ignored.


notes
╌╌╌╌╌

  Only state notes will be printed if this option is passed.


rows
╌╌╌╌

  `rows' option takes an integer as argument which can be passed as
  `--rows n', where `n' is an integer.

  `ara' will only print maximum these many number of rows, if you pass 0
  or a negative number then `ara' will ignore it & print all the rows.


showdelta
╌╌╌╌╌╌╌╌╌

  This will show delta values for every row, default is to show delta
  only on rows that were updated "Today".

  *Note*: This can be disabled by `autohide' option.


nodelta
╌╌╌╌╌╌╌

  This will remove delta values from every column.


nototal
╌╌╌╌╌╌╌

  This will remove the "Total" or "India" row from the table.

  `hide' option should be used for this purpose, this option is only
  kept for backwards compatibility.


nowords
╌╌╌╌╌╌╌

  "Confirmed", "Recovered" & "Deaths" column format numbers in words.
  For example, "1.6 lakhs" instead of "1,60,000" which makes it easier
  to read. This option will disable this behaviour.

  "Active" column doesn't format numbers in words because it's alignment
  is set as "right" & formatting it this way doesn't look good. There is
  currently no option to change this behaviour.


autohide
╌╌╌╌╌╌╌╌

  This will automatically hide some columns if the term size is smaller
  than expected, it's just a bunch of `if' blocks.

  ┌────
  │ push @to_hide, "updated" if $t_columns < 110;
  │ push @to_hide, "active" if $t_columns < 100;
  │ undef $show_delta if $t_columns < 80;
  │ $no_delta = 0 if $t_columns < 80;
  └────

  Currently (2020-08-03) it's just these lines pasted above but that
  might change so look at the source for latest rules.


hide
╌╌╌╌

  `hide' is able to hide states & columns from the table, the values
  should be space seperated like `--hide active "last updated"
  recovered'. These are case sensitive & should be lowercase.

  Arguments can be passed as they're printed, for example `--hide "jammu
  and kashmir"' is equivalent to `--hide jk' because "JK" is what's
  printed on the table.

  Only "States" & "Notes" column cannot be hidden, `ara' will print a
  warning if you try to do so.

  *Note*: "updated" is aliased to "last updated", so you can pass
  `--hide updated' & it would hide the "last updated" column.

  *Note*: The feature to get space seperated values is marked as
  experimental in `Getopt::Long' so the behaviour can change in future,
  worse even get removed. To guarantee backwards compatibility pass each
  value by itself like `--hide jk --hide active', this is equivalent to
  `--hide jk active'.


◊ Implementation

  `%hide' hash is created from `@to_hide' which was created from user
  arguments by `Getopt::Long'.

  ┌────
  │ undef @hide{ @to_hide }
  │     if scalar @to_hide;
  └────

  `%hide' contains values of `@to_hide' as keys & the value to those
  keys is not defined, hence `undef'. This one line says Perl to "undef
  these keys from the hash `%hide'" where these refers to the values of
  `@to_hide'. This will fail if `@to_hide' is empty so we have to check
  for that.

  Alternatively we can do `@hide { @to_hide } = ()' which works even if
  `@to_hide' is empty & does the same thing otherwise, this looks more
  cryptic so I use the first way.

  To check if a specific column is to be hidden or not we use `exists'
  like `exists $hide{something}'.

  There are other ways of doing this & maybe those would be better, I
  didn't test which one was the best.


  ◊ Columns

    To make `hide' work we put create `@columns' & push columns to it
    unless the user has asked to hide it.

    ┌────
    │ my @columns;
    │
    │ push @columns, 'Confirmed' unless exists $hide{confirmed};
    │ push @columns, 'Active'    unless exists $hide{active};
    └────


  ◊ States

    The whole block is skipped if the user has asked to hide the state.
    As said above, statecode is also check if that's what is printed in
    the table which is true only if `length $state > 16'. There is no
    good reason for not checking statecode for everything.

    ┌────
    │ next
    │     if exists $hide{lc $state}
    │     # User sees the statecode if length $state > 16 so we also match
    │     # against that.
    │     or ( length $state > 16
    │              and exists $hide{lc $statewise->[$i]{statecode}});
    └────


show
╌╌╌╌

  `show' also accepts space seperated values & just like in `hide''s
  case it's experimental & can change in future.

  `show' will only show states that are passed. For example, `--show jk'
  will only print data for Jammu & Kashmir. If both `show' & `hide' is
  used for states then `hide' is ignored. `show' for states can be used
  with `hide' for columns.


◊ Implementation

  `show''s implementation is similar to `hide''s. `%show' hash is
  created from `@to_show'.

  ┌────
  │ undef @show{ @to_show }
  │     if scalar @to_show;
  └────

  If user has used `show' then `hide' is ignored, this is achieved by an
  if-else block. This also means that invalid values in state would
  cause `hide' to be ignored, for example passing `--show invalid'
  wouldn't match anything but `hide' will still be ignored. This is
  intentional.

  ┌────
  │ if ( scalar @to_show ) {
  │     next
  │         unless exists $show{lc $state}
  │         or ( length $state > 16
  │              and exists $show{lc $statewise->[$i]{statecode}});
  │ } else { ... }
  └────


help
╌╌╌╌

  `help' will print help for `ara' which will have little information
  about all these options listed above.

  • `nototal' was removed from `help' because `hide' option does the
    same thing & is recommended.


Cross-platform compatibility
────────────────────────────

  Previously `ara' had OpenBSD specific code & would simply fail to run
  on other OSes, now it runs on all platforms. There is still OpenBSD
  specific code but it's used only when `ara' detects to be running on
  OpenBSD.

  ┌────
  │ use constant is_OpenBSD => $^O eq "openbsd";
  │ require OpenBSD::Unveil
  │     if is_OpenBSD;
  │ sub unveil {
  │     if (is_OpenBSD) {
  │         return OpenBSD::Unveil::unveil(@_);
  │     } else {
  │         return 1;
  │     }
  │ }
  └────

  `is_OpenBSD' is a constant so the if-else block is optimized at
  compile time. Another way would be to define the sub inside the
  if-else block which is what I did initially but that is not the same
  thing as this.

  You cannot define sub like that in Perl because this step happens at
  compile time & so the if-else block is ignored, which means the code
  will be equivalent to else block being true all the time because
  that's what comes later.

  ┌────
  │ if (is_OpenBSD) {
  │     require OpenBSD::Unveil;
  │     OpenBSD::Unveil->import;
  │ } else {
  │     sub unveil { return 1; }
  │ }
  └────

  Above code block will override the unveil sub to be `return 1;'
  everytime, this was fixed in commit
  `245aebe3da915afc0feafc7257f025e2e66a987f'.

  This will still fail on OpenBSD if users don't have `OpenBSD::Unveil'
  in `@INC', this shouldn't be an issue with Perl in base but if user
  runs custom Perl then it might not be in `@INC', in that case user is
  expected to fix this by adding the path to `OpenBSD::' in `@INC'.


Demo Videos
═══════════

  • [Ara 2020-06-14] (new options)
  • [Ara 2020-06-06]


[Ara 2020-06-14]
<https://diode.zone/videos/watch/95868534-8aae-497b-806e-5766236bb058>

[Ara 2020-06-06]
<https://diode.zone/videos/watch/03be044d-6ab7-4f01-8769-0084674dec93>