-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add extensions API #868
base: extensions-api
Are you sure you want to change the base?
Add extensions API #868
Conversation
c0c2751
to
8bea089
Compare
7503c8d
to
0aac23c
Compare
I think it would be helpful to have a specific environment lookup function or even better to have |
I think that should already be the case, according to the rules documented here: https://hspec.github.io/options.html#specifying-options-through-environment-variables |
The reason that the example specifically looks up the |
It would be nice if the |
How exactly would that look like? Right now you can say things like registerOption $ flag "ci" setCiFlag
"include itmes that are marked as \"CI only\"" or registerOption $ option "tags" (argument "TAGS" return addTagFilters)
"TAGS can be a list of tag names." How would you want to express this instead? |
In my pr I used the below
So, it would be useful to have optionalArg :: Read a => String -> String -> (a -> Config -> Config) -> Option
optionNoArg :: String -> (Config -> Config) -> Option these are more clear than trying to figure out which constructor to use with
|
I think this is currently not covered by the API, I'll try to look into it tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some thoughts
argument :: String -> (String -> Maybe a) -> (a -> Config -> Config) -> OptionSetter | ||
argument name parser setter = OptionSetter (Core.argument name parser setter) | ||
|
||
registerOption :: HasCallStack => Option -> SpecWith a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that registerOption
will be used every time flag
and option
are used. I know you want to use them as internal functions but it would be better for the extension writers to have them return SpecWith a
instead of Option
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's now registerOptions
that expects a list of Option
values.
Keeping the Option
type Might allow for reuse of Test.Hspec.Core.Extension.Option
for #870. So let's not abandon it, at least not yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok sounds good.
flag :: String -> (Bool -> Config -> Config) -> String -> Option | ||
flag name setter = Option . Core.flag name setter | ||
|
||
option :: String -> OptionSetter -> String -> Option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OptionSetter
makes this hard to use and it would be better just have interface functions for all the common cases like
flag :: String -> Maybe String -> (Bool -> Config -> Config) -> String -> Option
optionalArg :: Read a => String -> Maybe String -> String -> (a -> Config -> Config) -> String -> Option
optionNoArg :: String -> Maybe String -> (Config -> Config) -> String -> Option
argument :: Read a => String -> (a -> Config -> Config) -> String -> Option
these are more clear than trying to figure out which constructor to use with option
.
option
and argument
could then be moved to GetOpt.Declarative.Types
for more advanced uses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this along the lines of what you had in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sold on it, as it's not as clear anymore, which string is the option name, and which string is the name for the parameter. But let's give this a try, provisionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right about the which string is which. Perhaps aliases would be helpful.
argument :: CliName -> CliArgName -> CliHelp -> (Bool -> Config -> Config) -> Option
type CliName = String
type CliArgName = String
type CliHelp = String
I rearranged the arguments because I like having functions at the end which allows multiline lambdas without parenthaseses and hanging arguments. This should be applied to all the option functions if you choose to use it.
|
||
import Test.Hspec.Core.Extension.Tree (SpecTree) | ||
|
||
data Config = Config { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems strange to me to have 2 Config types especially when the other is not exported.
Also, since this is exported it locks in a lot of options in core that could actually be extensions. For example smallcheck is being deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's possible to remove some of those options after #870. However, only from this Config
type. The fields of the core Config
can only be deprecated, not removed, for backwards compatibility.
That's also the reason why I duplicated the type, so that the extension API doesn't "know about" legacy stuff.
It probably makes sense to finish #870 before the extensions API lands on main
.
That's the approach I'm taking for now:
- The provisional API is on Make Hspec extensible #894, I use this as a staging ground
- Support custom options for examples #870 will go on Make Hspec extensible #894 once it's done
- Any additional changes will be merged to Make Hspec extensible #894
- Once everything looks good Make Hspec extensible #894 will go on
main
This PR is now against #894, with the options and documentation changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank your for outlining the dev plan for extensions. Is there anything you want me to specifcally look at?
a6b7401
to
c0bc302
Compare
This PR adds an extension API that can be used to extend Hspec with additional functionality without the need to modify
hspec-core
.An example extension that addresses #338: