How to use mandatory field in dart args package - dart

I am trying to add a Mandatory field option for the argument in my dart script. I am using addOption() as visible in the code below. and to run the code in the terminal.
$dart args_demo.dart -h
If I run the code without mandatory: true in the method addOption(), I get no error and a help text is shown, everything works fine.
But, when I add this part mandatory: true in the method addOption(), and run the script with above command, I get this error massage
Unhandled exception:
FormatException: Option name is mandatory.
#0 Parser.parse.<anonymous closure> (package:args/src/parser.dart:101:9)
#1 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:397:8)
#2 MapView.forEach (dart:collection/maps.dart:342:10)
#3 Parser.parse (package:args/src/parser.dart:95:22)
#4 ArgParser.parse (package:args/src/arg_parser.dart:335:42)
#5 main (file:///home/penguine/Desktop/codeTesting/argPackage/args_demo.dart:12:26)
#6 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:281:32)
#7 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
Please explain how can I use the mandatory field without getting error.
thanks in advance.
import 'dart:io';
import 'package:args/args.dart';
void main(List<String> args){
final parser = ArgParser()
..addSeparator('===options and flags and help===')
..addOption('name', abbr: 'n', help: 'Provide your name', mandatory: true)
..addFlag('help', abbr: 'h', help: 'Provide usage instruction', negatable: false)
..addOption('paas', help: 'what is your favorite PaaS', allowed: ['AWS', 'GCP', 'Heroku', 'MSA'], defaultsTo: 'GCP');
final results = parser.parse(args);
//print(results);
if (results.wasParsed('help')){
print(parser.usage);
exit(0);
}
if (results.wasParsed('name')) {
print('=>> ${results['name']}');
}
print('PAAS =>> ${results['paas']}');
}

Note that there is nothing special about the -h/--help option itself. It is a boolean flag like any other. Consequently, since you've made -n/--name mandatory, it is exactly that: it is always required, even if you're just trying to print usage text.
The way that -h/--help is handled provides its own clue how you can make an option conditionally required: check ArgResults.wasParsed() and explicitly fail if it's not provided:
final results = parser.parse(args);
if (results.wasParsed('help')){
print(parser.usage);
exit(0);
}
if (!results.wasParsed('name')) {
stderr.writeln('--name is required.');
exit(1);
}
I agree that this behavior makes mandatory: true not very useful. It's a relatively recent addition to package:args, and I've filed https://github.com/dart-lang/args/issues/194.

Related

Dart testing Command line program

Suppose I have the following program increment.dart,
import 'dart:io';
void main() {
var input = int.parse(stdin.readLineSync());
print(++input);
}
and I want to test it similar to expect() from test package like,
test('Increment', () {
expect(/*call program with input 0*/ , equals(1));
});
Elaborating my use case:
I use this website to practice by solving the puzzles. They do have an online IDE but it doesn't have any debugging tools and the programs use std io. So what I have to do for debugging my code locally is to replace every stdin.readLineSync() with hardcoded test values and then repeat for every test. I'm looking a way to automate this.(Much like how things work on their site)
Following #jamesdlin's suggestion, I looked up info about Processes and found this example and whipped up the following test:
#TestOn('vm')
import 'dart:convert';
import 'dart:io';
import 'package:test/test.dart';
void main() {
test('Increment 0', () async {
final input = 0;
final path = 'increment.dart';
final process = await Process.start('dart', ['$path']);
// Send input to increment.dart's stdin.
process.stdin.writeln(input);
final lineStream =
process.stdout.transform(Utf8Decoder()).transform(LineSplitter());
// Test output of increment.dart
expect(
lineStream,
emitsInOrder([
// Values match individual events.
'${input + 1}',
// By default, more events are allowed after the matcher finishes
// matching. This asserts instead that the stream emits a done event and
// nothing else.
emitsDone
]));
});
}
Trivia:
#TestOn()
Used to specify a Platform Selector.
Process.start()
Used to run commands from the program itself like, ls -l (code: Process.start('ls', ['-l'])). First argument takes the command to be executed and second argument takes the list of arguments to be passed.
Testing stream

WithNewWindow() returns MultipleCompilationErrorsException in Geb

I am getting weird error in my geb functional tests.
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Spec expression: 1: expecting '}', found 'assert' # line 1, column 71.
} ) { at(JobOfferDetailPage) assert des
My test looks like this. I click on a link which opens a new window with details of the job offer. Than I want to assert some text on the new page using Page Pattern.
Test:
withNewWindow( { quickShowOption.click() } ) { //TODO fix me
at(JobOfferDetailPage)
assert description.text() == 'some text'
assert requirements.text() == 'some text'
assert advatages.text() == 'some text.'
assert categories.text() == 'some text'
assert locality.text() == 'some text'
}
Page:
class JobOfferDetailPage extends Page {
static at = {$('#contactLabel').text() == 'Contact'}
static content = {
description {$('#jobOfferDescription')}
requirements {$('#jobOfferRequirements')}
advatages {$('#jobOfferAdvantages')}
jobOfferType {$('#jobOfferType')}
categories {$('#categories')}
locality {$('#locality')}
startDate {$('#startDate')}
requiredLanguages {$('#requiredLanguages')}
}
}
I get compilation error after my conditions are asserted. If I make a typo in asserted text than the test will fail normally, but if it passes, than it fails with this weird error.
Thank you #Erdi.
I use spock,geb versions "0.13.1" and selenium version "2.51.0".
If one was to believe this comment in one of Geb's own tests, which was nota bene written by me some time ago, this indeed seems like some sort of bug in Spock. What is interesting is that I just now moved that statement to an expect block and it works as long as the last statement in the second closure passed to newWindow() evaluates to true. This makes me think that it is an issue with old version of Spock and/or Groovy. Which versions of the aforementioned tools are you using?
One possible workaround would be to move your statement from expect/then to one that is not asserting (given or when) as shown in the test I linked to.

How to gracefully abort yeoman generator on error?

I'm writing a yeoman generator and want to check some prerequisites, for example a git being installed. I can easily check this using .exec, but how do i gracefully abort generator and report error to user? I searched docs, but it seems that i'm missing some obvious way to do it. Any hints?
Throwing exception will of course abort generator, but is it a best way? Maybe something more user friendly? Not all yeoman users are able to read js exceptions.
The current state of error handling in the popular generators is quite diverse:
in the most cases they just log the error and return from the action and let the subsequnt actions run and return 0 status code:
generator-karma's setupTravis method:
if (err) {
this.log.error('Could not open package.json for reading.', err);
done();
return;
}
or set a custom abort property on error and skip further actions with cheking on the abort property but still return 0 status code:
generator-jhipster's CloudFoundryGenerator:
CloudFoundryGenerator.prototype.checkInstallation = function checkInstallation() {
if(this.abort) return;
var done = this.async();
exec('cf --version', function (err) {
if (err) {
this.log.error('cloudfoundry\'s cf command line interface is not available. ' +
'You can install it via https://github.com/cloudfoundry/cli/releases');
this.abort = true;
}
done();
}.bind(this));
};
or manually end the process with process.exit:
generator-mobile's configuringmethod:
if (err) {
self.log.error(err);
process.exit(1);
}
However none of these methods provide a good way to signal to the environment that something went wrong except the last one but directly calling process.exit is a design smell.
Throwing an exception is also an option but this presents also the stackstrace to the user which is not always a good idea.
The best option would be use the Environment.error method, which has some nice advantages:
the Environment is exposed thorough the env property of the yeoman.generators.Base
an error event is emitted which is handled by the yo cli code
the execution will result in a non zero (error) status code which is override-able
by default yo will display only the message and no stacktrace
the stacktrace can be optionally displayed with providing the --debug built-in option when re-running the generator.
With using this technique your action method would look like this:
module.exports = generators.Base.extend({
method1: function () {
console.log('method 1 just ran');
this.env.error("something bad is happened");
console.log('this won't be executed');
},
method2: function () {
console.log('this won't be executed');
}
});

grails changelog preconditions not doing anything

I am trying to make changes to the database using the changelog. Since I cannot guarantee that the values currently exist for the specific code, but could exist, I need to be able to check for them in order to either do an insert or an update.
Here is what I have been testing, which doesn't appear to do anything. Any words of advice are welcome.
databaseChangeLog = {
changeSet(author:'kmert', id:'tubecap-insert-update-1') {
preConditions(onFail="WARN",onFailMessage:"Tube cap does not exist,skipping because it cannot be updated."){
sqlCheck(expectedResult='1', 'SELECT * FROM [ltc2_tube_cap] WHERE code=11')
}
grailsChange {
change {
sql.execute("""
UPDATE [ltc2_tube_cap]
SET [name] = 'White'
WHERE [code] = 11;
""")
}
rollback {
}
}
}
}
UPDATE: I got the changelog script running, but I am now getting this error. I found the code from an online source. I cannot find a lot of documentation on preconditions...
| Starting dbm-update for database hapi_app_user # jdbc:jtds:sqlserver://localhost;databaseName=LabTraffic;MVCC=TRUE;LOCK_TIMEOUT=10000
problem parsing TubeCapUpdate.groovy: No signature of method: grails.plugin.databasemigration.DslBuilder.sqlCheck() is applicable for argument types: (java.lang.String, java.lang.String) values: [1, SELECT * FROM ltc2_tube_cap WHERE code=11] (re-run with --verbose to see the stacktrace)
problem parsing changelog.groovy: No signature of method: grails.plugin.databasemigration.DslBuilder.sqlCheck() is applicable for argument types: (java.lang.String, java.lang.String) values: [1, SELECT * FROM ltc2_tube_cap WHERE code=11] (re-run with --verbose to see the stacktrace)
groovy.lang.MissingMethodException: No signature of method: grails.plugin.databasemigration.DslBuilder.sqlCheck() is applicable for argument types: (java.lang.String, java.lang.String) values: [1, SELECT * FROM ltc2_tube_cap WHERE code=11]
at grails.plugin.databasemigration.DslBuilder.invokeMethod(DslBuilder.groovy:117)
at Script1$_run_closure1_closure2_closure3.doCall(Script1.groovy:13)
at grails.plugin.databasemigration.DslBuilder.invokeMethod(DslBuilder.groovy:117)
at Script1$_run_closure1_closure2.doCall(Script1.groovy:12)
at grails.plugin.databasemigration.DslBuilder.invokeMethod(DslBuilder.groovy:117)
at Script1$_run_closure1.doCall(Script1.groovy:11)
at grails.plugin.databasemigration.GrailsChangeLogParser.parse(GrailsChangeLogParser.groovy:84)
at grails.plugin.databasemigration.DslBuilder.handleIncludedChangeLog(DslBuilder.groovy:747)
at grails.plugin.databasemigration.DslBuilder.createNode(DslBuilder.groovy:139)
at grails.plugin.databasemigration.DslBuilder.createNode(DslBuilder.groovy:590)
at grails.plugin.databasemigration.DslBuilder.invokeMethod(DslBuilder.groovy:117)
at Script1$_run_closure1.doCall(Script1.groovy:6)
at grails.plugin.databasemigration.GrailsChangeLogParser.parse(GrailsChangeLogParser.groovy:84)
at liquibase.Liquibase.update(Liquibase.java:107)
at DbmUpdate$_run_closure1_closure2.doCall(DbmUpdate:26)
at _DatabaseMigrationCommon_groovy$_run_closure2_closure11.doCall(_DatabaseMigrationCommon_groovy:59)
at grails.plugin.databasemigration.MigrationUtils.executeInSession(MigrationUtils.groovy:133)
at _DatabaseMigrationCommon_groovy$_run_closure2.doCall(_DatabaseMigrationCommon_groovy:51)
at DbmUpdate$_run_closure1.doCall(DbmUpdate:25)
Your syntax is incorrect for the sqlCheck preCondition.
sqlCheck(expectedResult:'1', 'SELECT * FROM [ltc2_tube_cap] WHERE code=11')
Notice in your code the first argument is an assignment statement expectedResult=1 and it should be a map entry expectedResult:1.
I found the answer buried on this Jira page. https://jira.grails.org/browse/GPDATABASEMIGRATION-40 which ironically is about adding lots of examples to the DB migration DSL to the documentation.
Make sure the following
grails dbm-gorm-diff add-your-file-forupdate.groovy -add
then inside your-file-forupdate.groovy is expected to see
databaseChangeLog = {
changeSet(author:'kmert', id:'tubecap-insert-update-1') {
.
.
.
}
}
Then ,the Big deal is either you have included this as migration script file to be executed as follow:
just manually add a line like the following to the end of grails-app/migrations/changelog.groovy:
include file: 'your-file-forupdate.groovy'
The changelog.groovy is always run from beginning to end, so make sure that you always add newly created migrations to the end.
Cheers! for more info see this

Jslint can't pass through object

I just started to use jslint with backbone. At the beginning of project I create object:
App = {
Models: {},
Views: {},
Controller: {}
}
and get error:" 'App' was used before it was defined."
Then later I use it as:
App.Models.Task = Backbone.Model.extend({})
and at this point jslint can't pass me through. it says
unexpected 'App'. App.Models.Task = Backbone.Model.extend({}) // Line 17, Pos 1
#8 Stopping. (7% scanned).
I've read that probably jslint sees it as critical error because it stopped but it is not an error. what should I do?
It should be var App (or window.App, depending on your goals; but, in my opinion, even global variables are better defined as local ones first, then exported into outer space within a single statement). Otherwise JSLint (quite rightly) thinks that you just forgot to define this variable in some other place OR made a typo in its name.

Resources