Giter Club home page Giter Club logo

Comments (8)

dave avatar dave commented on May 26, 2024

Yes I understand your frustration. Unfortunately what you're trying to do isn't really possible, and unlikely to be something I'm going to try to incorporate in future. You always have to strike a balance between simplicity of the API, and supporting all the permutations of formatting that people may want in future.

Here's a similar issue: #17

As you've found out, kludging it is tricky too...

Call just separates the items with commas. Here's the config for Call. You've also looked at List, but that doesn't help - it just does the same without the parenthesis.

Here's a kludge that works... Defs is meant for grouping definitions: const, var etc. It separates the items with \n and wraps the list in parenthesis. Here's the config. You can also use Op to get a comma. If you're more interested in the readability of your generated source than the source of your generator, then this is a way to do it:

func ExampleKludge() {
	c := jen.Id("foo").Defs(
		jen.Id("a").Op(",").Comment("foo"),
		jen.Id("b").Op(",").Comment("foo"),
		jen.Id("c").Op(",").Comment("foo"),
	)
	fmt.Printf("%#v\n", c)
	// Output:
	// foo(
	// 	a, // foo
	// 	b, // foo
	// 	c, // foo
	// )
}

p.s. In your examples you didn't mention it, so I'm not sure if you're forgetting the most simple usage of Call:

c := Id("foo").Call(
	Id("a"),
	Id("b"),
	Id("c"),
)
fmt.Printf("%#v", c)
// Output:
// foo(a, b, c)

from jennifer.

dave avatar dave commented on May 26, 2024

There's two things I'm going to investigate in future as a result of this issue:

  1. Right now, adding a Comment("...") in the middle of a statement is usually a bad idea. Jen blindly adds the remaining tokens after rendering the // ... comment. Perhaps comments can be buffered, and only rendered at the end of the statement, perhaps forcing a \n to be added. I can see lots of potential edge cases, so this is a long-shot.

  2. Right now it's not possible to define your own types that satisfy the Code interface, because of the private methods. If the methods were public, it may be possible to create your own Code types that could be added to statements with Add. This would allow unlimited flexibility while keeping code more readable. You could create a CallWithLinefeedsAndComments type. I will investigate the feasibility of this and the potential pitfalls.

from jennifer.

jawnsy avatar jawnsy commented on May 26, 2024

@dave Thanks for the detailed explanation and reference to the other issue. Sorry I didn't find that one & save you some trouble, but I appreciate you explaining things and providing the (admittedly bit kludgey) workaround.

I definitely understand the difficulty of designing an API that is flexible enough to support what people want while maintaining simplicity/ease of use. It's a tough balance and I applaud your focus on developer ergonomics here; given your experience with code generation and the Go grammar, you have a much better understanding of the potential pitfalls involved than I do. 😄

from jennifer.

dave avatar dave commented on May 26, 2024

Hey @jawnsy I just added a feature which might partially solve your problem. Check out the new Custom and CustomFunc methods... https://godoc.org/github.com/dave/jennifer/jen#example-Custom

from jennifer.

jawnsy avatar jawnsy commented on May 26, 2024

@dave Great, thanks! This works perfectly for my use case, and produces more prettier code than doing it by hand (because I'm usually inconsistent with multi-line/single-line invocations)

jen is now spitting out some code like:

		row := txn.QueryRowContext(
			ctx,
			"SELECT account_id, attributes, name, display_name, description, archived FROM accounts WHERE account_id = $1",
			accountID,
		)
		return row.Scan(
			&account.Metadata.ID,
			&account.Metadata.Attributes,
			&account.Name,
			&account.DisplayName,
			&account.Description,
			&account.Archived,
		)

It would be nice if all the existing types were exposed as Option objects, with methods to customize specific fields. For example, there could be:

var CallOptions = jen.Options{
	Close:     ")",
	Multi:     false,
	Open:      "(",
	Separator: ",",
}

and then users could do something like: jen.CallOptions.WithMulti(true) (using the same options for Call, make it a multi-line invocation) or even something like jen.CallOptions.WithOpen("{").WithClose("}") (though of course that would produce invalid syntax)

Also, since dep prefers tagged releases, any ideas when you'll push the next release tag?

Cheers,

Jonathan

from jennifer.

dave avatar dave commented on May 26, 2024

Yeah I'll just do a little bit more testing before tagging this.

from jennifer.

pekim avatar pekim commented on May 26, 2024

The new CustomFunc that you've introduced is very nice.

It's proving handy for some unit tests, where I have a function that accepts a Group and I want to assert that the function generates what's expected. Configuring the Options to produce minimal clutter makes it relatively easy to assert that what's generated is what's expected. For example there are no \ts from formatting to deal with.

I can have a function like this.

func generateAndAssert(t *testing.T, generate func(*jen.Group), expectedLines ...string) {
	options := jen.Options{
		Open:      "",
		Close:     "",
		Separator: "",
		Multi:     true,
	}

	jen.CustomFunc(options, func(group *jen.Group) {
		generate(group)

		generated := group.GoString()
		expected := strings.Join(expectedLines, "\n")

		assert.Equal(t, "\n"+expected, generated)
	})
}

And I can then call it from a unit test.

func SomeTest(t *testing.T) {
	generateAndAssert(t, func(g *jen.Group) {
		functionToBeTestedThatAddsStatementsToTheGroup(g)
	}, "the first expected generated line", "the second line")
}

from jennifer.

dave avatar dave commented on May 26, 2024

@pekim glad it's proving useful! @jawnsy I've released this as v0.19.0, so feel free to pin that. I'll close this now.

from jennifer.

Related Issues (20)

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.