Skip to content
This repository has been archived by the owner on Dec 14, 2024. It is now read-only.

Url support #51

Merged
merged 16 commits into from
Feb 28, 2020
Merged

Url support #51

merged 16 commits into from
Feb 28, 2020

Conversation

gnojus
Copy link
Contributor

@gnojus gnojus commented Nov 29, 2019

Hi,
added url support as requested in #47.
Also implemented general argument parsing with a single function to avoid hacking each time.
Because of positional arguments the Submit function still needed some extra work.
I'm new to go and this probably isn't perfect, but I hope it's useful.

Accepts contest/problemset/gym urls.

@user202729
Copy link
Contributor

user202729 commented Dec 6, 2019

  1. All the \/ in the regex can be replaced with /. This isn't JavaScript regex literal.
  2. I think you should either use ^... $ to be explicit that it should match the whole string, or just drop the initial (https?)?, it's useless.
  3. I think it's better to use a struct (for required and the parse result) instead of map[string]string. That way spelling error are detected at run time + better completion (depends on the editor). The list of possible values are fixed anyway.
  4. I suppose it isn't possible to get the submission just from the submission ID with Codeforces CLI? Why is it necessary to provide the contest ID/URL?

@gnojus
Copy link
Contributor Author

gnojus commented Dec 6, 2019

  1. Didn't know that, but I can easily replace that
  2. That makes sense. I should probably just delete all the first block of the regex
  3. Not sure how to implement that elegantly in go
  4. Codeforces URL does require contest ID along with submission ID. You don't need to specify it if you are in the correct folder though. It is possible to find the contest ID using official Codeforces API by iterating all the submissions by user, but that wouldn't be too efficient.

@user202729
Copy link
Contributor

user202729 commented Dec 6, 2019

  1. Not sure how to implement that elegantly in go

Something like this: (note that the code doesn't compile)

user202729@bacf07f#diff-f8528230b76c77a45f085693ebe846d5R53-R61

The parsed command-line argument is represented as map[string]string because that's what docopt provides... Actually it's possible to use struct for that too (https://godoc.org/github.com/docopt/docopt-go#Opts.Bind). I guess xalanq is more familiar with dynamic languages (for example JS object types are always (equivalent to) map[string]interface{}) but that's not really efficient (I don't know if it's considered idiomatic)

@gnojus
Copy link
Contributor Author

gnojus commented Dec 7, 2019

Current implementation uses the fact that in a map an element might not even exist. Therefore in the required map[string]bool true means that the argument is required, and false that it's optional. If the argument is not in the required map it won't even be parsed. And if an argument is optional, the parser won't throw an error.

This behavior could be removed by parsing all arguments and returning errors on the required ones, but that would mean that you would need to call the parser like this:

parseArgs(args, ParseRequirement{
    problemID: true,
    contestId: true,
    filename: true,
})

So you would need to add all the extra true's that doesn't change anything. It's not very elegant, but I guess it's ok?

I do like the idea about having result struct though.

@user202729
Copy link
Contributor

I guess you can choose one of those:

  • Parse all, require true fields. (in the caller code it's equivalent to deleting all x: false entries. why would it be necessary to add extra true fields?)
  • Use an enum. https://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-go (required / not required / not parse) Although I guess because parsing or not doesn't change the behavior, and it doesn't affect the performance, parsing all is okay.
  • Filter after parse (includes parse all). (Because the requirement is independent from the parse) Something like:
func ParseArgs(args map[string]interface{}) (ParseResult, error) // ...
func CheckRequirement(ParseResult, ParseRequirement) error // ...

// caller code
parsed, err := ParseArgs(args)
if err { return }
err = CheckRequirement(parsed)
if err { return }
  • Combine the method above

@gnojus
Copy link
Contributor Author

gnojus commented Dec 8, 2019

why would it be necessary to add extra true fields?

you would need to pass that to the constructor.
But I guess we should stay with the first option.

@gnojus
Copy link
Contributor Author

gnojus commented Dec 12, 2019

It's now implemented.
Good to merge, @xalanq?

@gnojus gnojus requested a review from xalanq February 5, 2020 15:28
@gnojus
Copy link
Contributor Author

gnojus commented Feb 5, 2020

Will this get merged?
Because I have some other features implemented based on argument parsing introduced in this PR.

@xalanq
Copy link
Owner

xalanq commented Feb 27, 2020

Thanks for your great work! I'll handle it on this weekend or next weekend

@gnojus
Copy link
Contributor Author

gnojus commented Feb 27, 2020

I see you changed a lot. Do you want me to resolve the conflicts?

@xalanq
Copy link
Owner

xalanq commented Feb 27, 2020

I see you changed a lot. Do you want me to resolve the conflicts?

If you can resolve the conflicts, I'll greatly appreciate your great works!

@gnojus
Copy link
Contributor Author

gnojus commented Feb 27, 2020

All right, I'm onto it. This may take some time though.

@gnojus
Copy link
Contributor Author

gnojus commented Feb 27, 2020

Okay, I re-based it and it should be good to merge. Could contain some bugs, so you might want to test it.

@xalanq xalanq merged commit ec5e4d0 into xalanq:master Feb 28, 2020
@xalanq
Copy link
Owner

xalanq commented Feb 28, 2020

Great works!
I have an idea. Let's make the parameters simpler and more intelligent.

cf submit [-f <filename>]
cf list [<url|contest-id>]
cf parse [<url|contest-id>] [<problem-id>]
...

->

cf submit [--filename=<filename> | -f <filename>] [<argument>...]
cf list [<argument>...]
cf parse [<argument>...]

Then use your ParseArgs to parse that arguments.

@xalanq
Copy link
Owner

xalanq commented Feb 28, 2020

I'll handle this

@xalanq
Copy link
Owner

xalanq commented Feb 28, 2020

Usage:
  cf config
  cf submit [-f <file>] [<argument>...]
  cf list [<argument>...]
  cf parse [<argument>...]
  cf gen [<alias>]
  cf test [<file>]
  cf watch [all] [<argument>...]
  cf open [<argument>...]
  cf stand [<argument>...]
  cf sid [<argument>...]
  cf race [<argument>...]
  cf pull [ac] [<argument>...]
  cf clone [ac] [<argument>...]
  cf upgrade

Options:
  -h --help            Show this screen.
  --version            Show version.
  -f <file>, --file <file>
                       Path to file. E.g. "a.cpp", "./temp/a.cpp"
  <argument>           Any useful format. E.g. "https://codeforces.com/contest/100",
                       "1111A", "a"
  <alias>              Template's alias. E.g. "cpp"
  ac                   The status of the submission is Accepted.

@gnojus
Copy link
Contributor Author

gnojus commented Feb 28, 2020

Ok. Though I would suggest to rename argument to specifier, as thats what it does - specifies contest and/or problem if I understand correctly.

@xalanq
Copy link
Owner

xalanq commented Feb 28, 2020

Ok. Though I would suggest to rename argument to specifier, as thats what it does - specifies contest and/or problem if I understand correctly.

Ok~

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants