Giter VIP home page Giter VIP logo

clap-st's People

Contributors

bajger avatar capsulecorplab avatar cdlm avatar clementmastin avatar demarey avatar fniephaus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clap-st's Issues

Compulsory Arguments returning wrong value

Hi,
When I don`t use compulsory args and try this

| pos1 command context match|
	pos1 := (ClapPositional withName: 'inputFile').
	command := (ClapCommand withName: 'MyApp')
		addPositional: pos1. 
 context := ClapContext on: #('MyApp' 'input.txt').
	match := command matchOn: context.
	(match at:pos1) value. "Returns input.txt"

But when I use compulsory args and try 
| pos1 command context match|
	pos1 := (ClapPositional withName: 'inputFile').
	command := (ClapCommand withName: 'MyApp')
		addCompulsory: (pos1) asCompulsory .
 context := ClapContext on: #('MyApp' 'input.txt').
	match := command matchOn: context.
	(match at:pos1) value. "Returns inputFile"

Shouldn`t they both return the same value. The second one is returning the positional name rather than the value. Am I doing it correct?

Specify short form of CLAP flag, when having multiple flags starting with same letter

Enhance ClapFlag with option to specify short form of flag name.

Describe the request
Currently, short form ClapFlag instance is always represented by first letter of long version name. This causes a problem, when having multiple flags starting with same letter, e.g. noHeader and name. There should be an option to specify short name programmatically (when specifying command) in order to avoid name conficts.

Expected behavior

(ClapFlag id: #name)
	description: 'Name description.';
        shortName: 'n';

...
(ClapFlag id: #noHeader)
	description: 'No header description.';
        shortName: 'h';

Expected development cost

  • Add instance variable on ClapFlag class and setter method.
  • Modify shortName getter method to access instance variable and assign first letter substring in initialize method (or lazy assignment).

Version information:

  • reported on CLAP version: 1163bde

Question concerning creating a custom-named command line handler

I'd like to create a custom-named command line handler that I can run in the shell, s.a., the Eval command from How to use the ClapCommandLineHandler in Pharo. However, following the tutorial, am hitting a couple of "Message sent but not implemented" errors. I suspect this is because the tutorial is simply outdated and perhaps warrants the need for a new tutorial as per #22 - In the meantime, is there a "hot-fix" to resolve these errors?
Screenshot from 2023-12-30 23-31-49
Screenshot from 2023-12-30 23-37-23

Discuss the design of flags

Discussion started at pillar-markup/pillar#440

@cdlm:
If flags have side-effects then their order of execution must be clear; however there is no obvious order that would be valid in all situations. Sometimes the order of declaration in the specification makes sense, sometimes it's the order of invocation on the command line, and it could also be some arbitrary order depending on the application. Some flags can also be repeated.

I didn't want to assume how and when an app should use its flags. So they are best seen as optional parameters that you use when you need their value, instead of an imperative API to a stateful builder. The meaning blocks are there to lift the string passed on the command line into an object value that's useful to the app. We tried a version where the block had a side-effect, but then in the meaning block it looked like (args at: #all) value. with no immediate indication of what effect this has.

For commands the situation is different because each subcommand selects a narrower subset of the app's behavior. In the end you have one and only one most-specific subcommand, so that makes a convenient entry point.


@guillep:

If flags have side-effects then their order of execution must be clear

Yes, and Clap could define an order :). Even more, it could have a default one "definition order" for example. And then accept other strategies like "invocation order", and each command could define the order of flags with a strategy, no?

I didn't want to assume how and when an app should use its flags. So they are best seen as optional parameters that you use when you need their value, instead of an imperative API to a stateful builder. The meaning blocks are there to lift the string passed on the command line into an object value that's useful to the app.

I understand. But to me, we should take a stand and favour one usage over the other :).
And maybe give hooks to the user to override those decisions.
We will never make a choice that pleases everybody, I'd take that outside the table :P.
My heuristic here is that we should favour most common usages, and leave the freedom to do less common usages.

We are now using a full-grown framework to parse command line arguments, so we should extract the juice from it, no?

I'd like to discuss alternatives, tell me what you think:

  1. flags with effect. The command executes the flag meaning automatically. This works naturally with optional flags. If some flag is not there, the building method is not called.
myBuilder := MyBuilder new.
ClapCommand new
   add: ((ClapFlag id: #x) meaning: [ myBuilder withX ]);
   add: ((ClapFlag id: #y)
      beIntegerValue; "clap does the parsing and validation for me ;)"
      meaning: [ :anInteger | myBuilder withY: anInteger ]);
   add: ((ClapFlag id: #z) meaning: [ :aString | myBuilder withZ: aString asUppercase ]);
   meaning: [ myBuilder build ].
  1. flags with value as explicit argument. The command executes the flag automatically and sends the associated values as argument of the command meaning. Here the meaning of flags defines actually how to "marshall" the flag, what is their value when used from the command line (otherwise having meaning have no sense, no?...).
    => But, as a side effect, all flags become mandatory, because they are arguments in the block.
ClapCommand new
   add: ((ClapFlag id: #x) meaning: [ SomeObject new ]);
   add: ((ClapFlag id: #y) meaning: [ 17 ]);
   add: ((ClapFlag id: #z) meaning: [ :value | value asInteger ]);
   meaning: [ :x :y :z | MyObject withX: x withY: y withZ: z ].
  1. flags with value in dictionary. The command executes the flag automatically and just stores the associated values in a dictionary. Here the meaning of flags, again, defines how to "marshall" the flag, what is their value when used from the command line.
    In this version, what we have now IIUC, it's the user responsibility to have conditional code to check for the arguments, which I don't like...
ClapCommand new
   add: ((ClapFlag id: #x) meaning: [ SomeObject new ]);
   add: ((ClapFlag id: #y) meaning: [ 17 ]);
   add: ((ClapFlag id: #z) meaning: [ :value | value asInteger ]);
   meaning: [ :args | MyObject withX: (args at: #x) withY: (args at: #y) withZ: (args at: #z ifAbsent: [0]) ].

I prefer solution 1. I think it is easy to understand and that defining a clear order of execution of flags can simplify the task of the developer (I think definition order is the best one because the developer can foresee what will happen more easily).

Solution 2 is too limiting, and solution 3 too verbose.

But please note that solutions 1 and 3 are somewhat compatible ;). We could use solution 1 and, those people wanting fine grained control could use solution 3.

We tried a version where the block had a side-effect, but then in the meaning block it looked like (args at: #all) value. with no immediate indication of what effect this has.

I did not understand this. My point is that nobody should call (args at: #all) value. at all :). It seems superfluous. It should be called automatically.
Otherwise, why should I do value?

ClapCommand new
   add: ((ClapFlag id: #x) meaning: [ SomeObject new ]);
   meaning: [ :args | (args at: #x) value ].

If the evaluation could be done automatically when accessing the argument:

ClapCommand new
   add: ((ClapFlag id: #x) meaning: [ SomeObject new ]);
   meaning: [ :args | args at: #x ].

or even simpler, because people do not need to understand the semantics of meaning:

ClapCommand new
   add: (ClapFlag id: #x);
   meaning: [ :args | args at: #x ifPresent: [ SomeObject new ] ].

I don't know, tell me what you think about these ideas. I am really convinced that clap could do more :)

Mocketry Install

It could be good if when you load Clap, it also load Mocketry because of the tests

Write a proper tutorial

  • command specification messages
  • how to convert arguments into domain values
  • help flag and command
  • any other topics ?

Implement a nameless root command

The clap command line handler tries commands out of a set, but isn't a Clap command itself, making things like root flags and default behavior difficult.

Matching Bug With Subcommand

When I have that:

sub := (ClapCommand withName: 'this') addFlag: (ClapFlag withName: 'force').
pos := ClapPositional withName: 'class'.
command := (ClapCommand withName: 'foo') addPositional: pos;addSubcommand: sub.
context := ClapContext on: #('foo' 'this' 'Object').
command matchOn: context

It returns a ClapCommandMatch with a ClapPositionalMatch

Nested subcommands do not take control

Control is passed down one level of subcommands, but not down to the innermost subcommand (intended behavior… apparently recursion is hard).

I guess the clap help help in the demo was the 1st one describing its positional instead of the 2nd one describing its parent 🤔

Port / redesign existing command line handlers

  • root options (version & copyright, list subcommands, changing/omitting startup preferences…)
  • printVersion — show image/vm version, overlap with option on root command
  • Fuel — materialize Fuel-serialized data in the image
  • loadHermes — load serialized behavior (for bootstrap)
  • get — install catalog project
  • config — load Metacello using Gofer
  • metacello — install configuration/baseline
  • perform — send message to global
  • test — run unit tests
  • st — run code from file
  • eval — run code from arguments
  • clean — clean image for release
  • initializePackages — initialize packages or re-classify selectors in protocols (but… why? 🤔)
  • save — rename image

context>>#hasFlag: does not work when flag is not specified on the last subcommand

When you have a command with one or many level of subcommands, there should be a way to ask the context if some flag is present or not.

exemple:

launcher image create fromPR 9588 --no-launch

In the example, the --no-launch flag is specified on the create subcommand spec.
When asking #hasFlag: #'no-launch' to the context, it will search on the last subcommand: fromPR and by so will not find it.
It should search from the command where it has been specified

Unclear handling of arguments / standard input character encoding

Actual arguments are ByteStrings in the platform encoding…

  • we don't know the platform encoding (in practice, safe to assume UTF-8 on macos and Linux…)
  • some arguments might need to be handled as bytes (unlikely)
  • standard input is more likely to be data, but decoding as text is still the common case

Clap exception in ClapContext>>pragmaCommands

CLAP activation currently fails. Therefore cannot run any unit test on PharoCommandlineLauncher project.

MessageNotUnderstood: Pragma class>> #allNamed:
Pragma class(Object)>>doesNotUnderstand: #allNamed:
ClapContext class>>pragmaCommands
ClapContext class>>withPragmaCommands
[ | tmp2 |
tmp2 := ClapContext withPragmaCommands.
tmp2
	beObeyingExits;
	setStdio: Stdio;
	arguments: self arguments;
	executeToExit: [ :arg1 | self handleExit: arg1 ] ] in ClapCommandLineHandler>>activate in Block: [ | tmp2 |...
[ self value.
Processor terminateActive ] in BlockClosure>>newProcess in Block: [ self value....
testLauncherProcessListCommandWhenNoPharoImageRunningShouldReturnEmptyList

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.