-
Notifications
You must be signed in to change notification settings - Fork 8
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 auto-generator #12
Conversation
The only problem with my suggestion is that I have to add |
I've created a branch on my repo called |
Both approaches are interesting, while with a quick look I think I lean towards the alternative one, I need to look at both closer and compare them from the C# point of view too. 🚀 🎉 |
1. Use explicit qualified access to Gen module to make it clear which function is in Hedgehog and which one is in Hedgehog.Experimental. 2. Because of 1., use a namespace 'Hedgehog' and a module 'Gen'. 3. Indent body of Computation Expressions with 4 spaces. 4. open System and remove all occurences of 'System.'. 5. Make 'dateInterval' consistent with other functions, where we have the bounded value starting after the '=' in a new line. We usually do this for functions with lines more than 80 chars. 6. Add a space after each function parameters, even if it's the empty tuple, for example: foo() becomes foo (). 7. Format test code according to this heuristic: http://blog.ploeh.dk/2013/06/24/a-heuristic-for-formatting-code-according-to-the-aaa-pattern/ 8. Start comments with capital letter and end with period, for example: '// this is foo bar' becomes '// This is foo bar.'. 9. Remove redundant parentheses.
Both approaches look interesting, and both have their pros and cons. I think we should focus on how we can easily consume the In the tests I did in both branches, I used these types: type Actions =
{ Tag : string
Contents : obj }
override this.ToString () =
sprintf
"%s %A"
this.Tag
this.Contents
type Type =
{ Tag : string
Contents : Actions }
override this.ToString () =
sprintf
"%s %A"
this.Tag
this.Contents
type Transactions =
{ Timestamp : int64
Signature : string
To : string
Origin : string
Header : Type }
override this.ToString () =
sprintf
"%A %s %s %s %A"
this.Timestamp
this.Signature
this.To
this.Origin
this.Header
type TransactionParams (txs : Transactions) =
member val Method = "Transaction" with get, set
member val Params = txs with get, set
override this.ToString () =
sprintf
"%s %A"
this.Method
this.Params The first issue was the C# compiler complained, since we now have 2 In order to make the following code to compile, I had to rename this project's using Hedgehog;
class Program
{
static void Main(string[] args)
{
var a = GenX.Auto<TransactionParams>();
Gen.printSample(a);
var @default =
GenX.defaults;
var gnConfig =
new AutoGenConfig(
@byte : @default.Byte
, @int16 : @default.Int16
, @int : @default.Int
, @int64 : @default.Int64
, @double : @default.Double
, @decimal : @default.Decimal
, @bool : @default.Bool
, guid : @default.Guid
, @char : Gen.ascii
, @string : @default.String
, dateTime : @default.DateTime
, dateTimeOffset : @default.DateTimeOffset
, range : @default.Range
);
var b = GenX.AutoWith<TransactionParams>(gnConfig);
Gen.printSample(b);
}
} Note that In F#, things are easier thanks to F#'s copy-and-update feature: open Hedgehog
[<EntryPoint>]
let main argv =
Gen.printSample <| GenX.auto'<TransactionParams> { GenX.defaults with Char = Gen.ascii }
|
Housekeeping
What does all the And could we use CompiledName or some other attribute to use |
It's required if a word is reserved, like
No, I don't think that's easy, at least off the top of my head. |
Might I then suggest we add an That is, of course, if we go for the alternative implementation (not this PR). |
The problem (if we can call it like this way) is the C# compiler; it won't allow two |
Perhaps I didn't make myself sufficiently clear in my previous comment. I am talking about just having |
No, you are actually pretty precise 👍 It's just that |
Oh, I see what you mean - Hedgehog.Experimental can't contain a |
Back to the auto-generator: It would be great if the user could also specify overrides for any complex type they desire. For example, say I'm not sure how to do this though, or if it is easy/feasible/possible. |
I'd say; let's go for
That's a good point; currently with the Perhaps, we could pass some dictionary of type First things first, do you agree we should rule out the static member auto<'T> ([<Optional>] ?byte, [<Optional>] ?int16, [<Optional>] ?int [..] And then, the usage is a bit clunky in C#: class Program
{
static void Main(string[] args)
{
var a = GenX.auto<TransactionParams>();
Gen.printSample(a);
var b =
GenX.auto<TransactionParams>(
@char: FSharpOption<Gen<Char>>.Some(Gen.alphaNum));
Gen.printSample(b);
}
} |
Sure.
Not sure how to implement that. Could you sketch out something for me? Just an example so I have something to go on (though I think in this case the distance between example and complete implementation is fairly short).
I agree that it should be invisible to C# users that this library is written in F#, so |
So, if you agree
|
Couldn't we solve this by marking the |
Oh, yes, we can decorate |
Won't we have to use |
That, I don't know off the top of my head (I only have a Haskell compiler in front of me right now) However, I assume this isn't available in F# 4.0; I think they've made it available in F# 4.1... |
I can use What I am talking about is this (C# code): var gens = GenX.defaults;
gens.Char = Gen.alphaNum; Without |
Yes, sounds good if we can do it. Perhaps we can have F# Hedgehog Experimental even target F# 4.1 if that will allow us to use the |
Made requested changes and rebased on current master. See if I've done it correctly. |
Oh fudge. For some reason VS committed loads if irrelevant stuff in the merge commit. I think I'll stick to the command line hereafter. Let me know how to proceed. I can check out the current master and make a new PR of you want. |
No worries
|
Looking at the diff, there seems to be several other strange changes I can't remember making, which I expect was part of #13. I suppose the rebasing got botched somewhere. Should I just create a new "clean" PR with the current implementation? |
We could then also factor out the |
A clean PR (in terms of git commit history) is always welcome, if it's OK for you 👍 |
Yes, I certainly prefer that. |
Talking about having a clean history; have you seen this? https://github.com/blog/2141-squash-your-commits? |
Yes :) |
As discussed in hedgehogqa/fsharp-hedgehog#133. We can continue developing it further in this PR.
Please review it carefully and pay special attention to the questions at the bottom.
Usage in its initial form:
Point for consideration: I think it might be better to place
auto
in a class namedGen
in theHedgehog
namespace, and have optional arguments for all the generators. That way, we get the following benefits:Only one function (
auto
) instead of two (auto
andauto'
), becauseauto'
can just be an overload ofauto
. However, see next point.Instead of overloading, we can use optional arguments for all the generators. Callers of
auto
can then just specify the arguments corresponding to the generators they want to override. This gets rid of theAutoGenConfig
type and thedefaults
value (at least publicly) which didn't really add any inherent value.Considering the previous point, it becomes much more C#-friendly. With the current implementation I think we'd have to mark
AutoGenConfig
with[<CLIMutable>]
and/or[<Struct>]
, and C# users would still have to assigndefault
to a variable and modify its properties before using it.It even gets rid of some F# boilerplate:
Gen.auto(char=Gen.alphaNum)
instead ofGen.auto({Gen.defaults with Char = Gen.alphaNum})
.In short, I think the above speaks fairly well for wrapping this in a class.