Skip to content
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

Added Template feature so documents can be generated using the built in functions #266

Merged
merged 23 commits into from
Nov 19, 2023

Conversation

Mrpye
Copy link
Contributor

@Mrpye Mrpye commented Nov 1, 2023

Not sure if this is something you want to add, but I have found it a very useful feature, so spent the time making it a feature.

  • Added the ability to generate forms using Go's template engine.
  • You can pass in a template with the functions and it populates a document.
  • You can also specify the number of lines if your template has a range.
{{range $y := IntRange 1 .Lines}}

example

http://localhost:8080/template?template="{{Name}} {{LastName}}"&lines=3

output:
Markus Moen Pagac
Matteo    Krajcik
Modesta   Hilpert
  • Added 4 data templates email, fixed_format, markdown and html.
http://localhost:8080/template?template_type="fixed_format"&lines=3

output:
FIRSTNAME LASTNAME  Gender  Job            Hobby               CreditCard          Address
Markus    Moen      male    Developer      Lacrosse            39800889982276      369 North Cornerbury, Miami, North Dakota 24259
Matteo    Krajcik   female  Manager        Tour skating        569586614968023     4090 Lake Unionport, Pittsburgh, Iowa 73720
Modesta   Hilpert   female  Representative Volleyball          6495603064524543520 976 Forgeport, Aurora, Minnesota 92470

I have created unit tests for the template and functions.

To make the functions available to the template engine there is a function called BuildFunctionMap, that gets the methods from globalFaker and checks that the parameters are compatible with GO's template engine, and then adds them to a function map.

See what you think,

Thanks Andrew

@brianvoe brianvoe changed the base branch from master to develop November 2, 2023 15:17
@brianvoe
Copy link
Owner

brianvoe commented Nov 2, 2023

Wow! I really like the direction of your thought process on this. I definitely think this idea is something we can get in.

Im going to try to do my best to describe my thoughts on adjustments I think you should make that would get this integrated the best.

  1. Template - So the first one I think we should tackle is simplifying it down to only the primary functions that people will run and not having a function that passes a string to lookup a template. Instead lets just keep it simple and list out the 5 functions you want. Ex: Template(Love your first example!) TemplateEmail, TemplateMarkdown, TemplateHtml and TemplateFixedFormat(Might want to think maybe about a different name, as this might clash with a future development of static generators in the future. Or i can be convinced with more example usages.)
  2. Public functions - We have to be super careful about making sure we only create a small necessary amount of public functions. The one that pops up is the BuildFunctionMap. If the function purpose is for the use of templates only then we just make them private. I dont normally make general helper functions that are generally only used for a gofakeit function public.
  3. Misc functions - If they are general functions that the whole package can use I put them in the helpers file and make sure they have specific test for it. Minor thing but it helps organize this and removes potential similar functions from being created.

I added some comments in your files to start off. We can keep going back and fourth on adjustments and ideas and well see where we end on this.

Thanks again and nice job.

Copy link
Owner

@brianvoe brianvoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First quick round of comments.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
data/template.go Outdated Show resolved Hide resolved
lookup.go Outdated Show resolved Hide resolved
template.go Outdated Show resolved Hide resolved
template.go Outdated Show resolved Hide resolved
template.go Outdated Show resolved Hide resolved
template_test.go Outdated Show resolved Hide resolved
template_test.go Outdated Show resolved Hide resolved
template.go Outdated Show resolved Hide resolved
@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 2, 2023

I am glad you like the idea, I thought it would be useful
This is my first contribution to another project.

I'll take a look and make changes I like the idea of separate functions for each template type.

Thanks for the feed back and ill get to work

@brianvoe
Copy link
Owner

brianvoe commented Nov 2, 2023

Sounds good. Good luck!

@brianvoe
Copy link
Owner

brianvoe commented Nov 2, 2023

And make sure tests are passing too. :)

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 2, 2023

The FixedFormat name, how about 'Fixed Width' seems to be an official name for that format.

@brianvoe
Copy link
Owner

brianvoe commented Nov 2, 2023

That template is tricky, I dont know if i fully see the benefit of that one. My thought with that one is instead of fixed with in the main template function you would have an option of fixed width and header. And with that I feel like it should tackle what the fixedformat one was trying to accomplish. Not sure if that makes sense but we can always swing back around to that one and figure something out.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 5, 2023

I have removed the fixed width for now, will revisit yes it perhaps should work similar to the csv function.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 5, 2023

I am just adding better html template data. I have basic page and multiple content items that get randomly generated depending on how many sections you pass.
Sro we now have
TemplateDocument
TemplateEmail
TemplateMarkdown
TemplateHtml(sections int)
TemplateHtmlContent

Unfortunately I managed to injury myself, so lost a few days in hospital but back on it now.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 6, 2023

Hi @brianvoe,

How did you feel about using the go:embed? I am only asking because it feels messy adding templates as code, having them as files means keeping the code clean and it's easier to manage and edit files.

I thought I would ask the question, but I am happy to go with what you feel is best.

Andrew

@brianvoe
Copy link
Owner

brianvoe commented Nov 6, 2023

Glad to see your doing well. Welcome back.

Lets start by getting it cleaned up and perfected on a simple scale then it makes it easier when you want to add more.

Lets stay away from go:embed. Just makes it more difficult to use the package. String templates in a Go file are perfectly fine.

Let me know if you need anything. Thanks!

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 6, 2023

Summary of updates

Split the Template function into individual functions

Template(template string, lines int) ([]byte, error) // Custom templates
TemplateDocument() (string, error) // Random Document from HTML,markdown,Email
TemplateHtml(sections int) (string, error) //Email Document
TemplateHtmlContent() (string, error) // HTML Content
TemplateMarkdown(sections int) (string, error) // markdown Document
TemplateMarkdownContent() (string, error) // markdown content
TemplateEmail() (string, error) // Email text and HTML

Moved the Template functions in the readme to its own Template section

Added a couple of different templates to the data

Added Unit tests for each function and also a big test to make sure all the templates compile properly

Several other changes

.vscode/launch.json Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
@brianvoe
Copy link
Owner

brianvoe commented Nov 6, 2023

Ok that was a good round of changes. Lets talk about the next set of updates. I like your ambition for having "full" template but the templates you have are really bloated. Think MUCH simpler. Try to remove all the extra stuff. The goal is to get as broad amount of normal usage as possible and leave it open for others to build upon if they have more demanding situations(hence why just template where they can add there own and generate the amount of lines is a nice one)

For email just have your basic title, message, signature and get really creative in those locations.

  • title - randomly select (hi, hello, etc...) {{name}},
  • content - randomly build sentences, questions, paragraphs. Mix them in together to make is feel various.
  • signature - randomly select a goodbye type ending. whether or not to have thanks or your contact info in it.

Markdown looks a little better but instead of multiple "templates" think one template and randomly generating certain areas to fill out.

The html is a tricky one. I would say leave that out for now as I have a ticket for the one specifically and that will need a different level of heaving building to get that one right.

Hopefully that helps and look forward to your updates

@Mrpye Mrpye requested a review from brianvoe November 7, 2023 14:56
.vscode/settings.json Outdated Show resolved Hide resolved
@Mrpye Mrpye requested a review from brianvoe November 7, 2023 17:38
@brianvoe
Copy link
Owner

Good Morning,

I had an ah ha moment this morning. Im going to layout my thoughts and you let me know what you think.

// Templates
Template(template string, options TemplateOptions)
EmailText(options EmailOptions)
Markdown(options MarkdownOptions)
FixedWidth(options FixedWidthOptions)

We can get rid of the word Template in front of the function name. They are all still in the category of template but just dont need to say it. I dont know why i didnt realize it sooner, but most other functions dont need to preceed the function name with the category.

For the main template let them define the lines if they want to in there own template. I think the issue I have with lines being a param is I can think of a bunch of scenarios that I would want to output a template that dont require lines. That being said I feel like it should take in a second param for options and if they want to pass in lines as a dataset to be used in there template they can.

type TemplateOptions struct {
    Data interface{}
    Funcs template.FuncMap
}

I want to get your fixed width back in and i think the original issue is we were the ones defining the template instead of just letting them pass in the functions they want to use.

type FixedWidthOptions struct {
    Header []string
    Funcs []string
    Count int
}

opts := {
    Header: {"Name", "Email"}
    Funcs: {"{firstname} {lastname}", "{email}"} // Same as struct tags
    Count: 3
}

FixedWidth(opts)
Name           Email
Billy White    [email protected]
Sally Fields   [email protected]
Frank Bard     [email protected]

I think this gets your FixedWidth function back in with the most versatility possible.

Let me know your thoughts. If your burnt out just let me know I can always wrap things up if you want.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 13, 2023

Sorry for the slowness in my response, I had an op on my hand so was out of action for a bit.

While waiting for pre-op, I was also thinking about the Implementation of the options (Waiting for an op and thinking about code :-}), It just felt a bit messy and confusing for the user with the lines in the TemplateOption. I came to the same conclusion having a data field and making the FuncMap public.
I then saw your message, separate Options, simple, I like it :-)
having the template parameter makes sense as it is a requirement, not an option.

Regarding the FixedWidth function, It's funny because generating FixedWidth data was the reason I started down the route with Templates, so happy to put it back in.

Another thing we need to consider is how to pass the width, alignment, and padding char of each field.
I have had use cases with fields padded out and aligned so it is needed.
Adding Spacing, Align, and Padding options to control this would work what are your thoughts?

opts := {
    Header: {"Name", "Email", "Account"}
    Spacing: {30,20,10}
    Align: {"",">","^"}
    Padding: {"","", "0"}
    Funcs: {"{firstname} {lastname}", "{email}", "{AchRouting}"} // Same as struct tags
    Count: 3
}

Name                        Email                                      Account
Billy White                 [email protected]      000123456789
Sally Fields                 [email protected]         000123456789
Frank Bard                 [email protected]          000123456789

I'll get started with the first lot of changes and wait for your thoughts on the extra options.

@brianvoe
Copy link
Owner

We are on the same page! Agree with the first two parts and the third, just wanted to add my two cents to the fixed width part.

Totally agree with adding spacing, align and padding. I dont understand the align part but Im sure that makes sense to you. Is there a reason to have an array for those values instead of just a single value? and i just want to make sure those are optional and we have a default for those if they dont pass any in.

P.S. If you code this thing with one hand you are a badass!

Super duper close!

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 14, 2023 via email

@brianvoe
Copy link
Owner

No worries take your time.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 16, 2023

Hi,

So a summary of the latest push.
Template EmailText and Markdown now have their Options
The template option has a Data field and the developer can access the function map.

The FixedWidth has been added.
I ended up changing the FixedWidth options from slices to fields, as it was getting complete validation
of the inputs. using fields has simplified the code and gives some consistency as it is very similar usage to the CSV function,

You can hide the header, footer
change the alignment of each column
change the padding char used for header, row, footer
set the column width or -1 auto calcs column width (default)
the function param uses template functions or faker functions
also if a column has numeric data you can display the total in footer.

// Output:
// name************last_nameEmail********************password****Account No.**Money
// Markus Moen     Daniel   [email protected]  W8DAkpLjYoBW364599489953    35
// Amie Feil       Kuvalis  [email protected]    16
// Trystan GislasonKeebler  [email protected]  J41S7H76KwYZ323202027613    61
//                                                                           112.00 

@brianvoe
Copy link
Owner

Looking good! Make sure to think super simple, a lot of the times if something has too many options people are less prone to use it. Less is more type mentality. The separator per column and the footer are two examples of that.

Let me know when your done and ill review it then.

Thanks

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 17, 2023

Ok, I have stripped it down to just spacing and alignment.
It defaults to left align and the spacing will auto-calc default.

@brianvoe
Copy link
Owner

So much cleaner!!! Nice job. Sorry i dont mean to poo poo on your ideas I am just trying to give it the best possible success it can be. Cause i really want people to use this.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 17, 2023

I do get carried away :-), You have a vision and it is quite a task making sure random people keep to it, I respect that.
It's my first contribution to a project, and it's been a good learning experience.

@brianvoe
Copy link
Owner

sounds good. let me know when your ready so we can get this in!!!

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 19, 2023

I am ready

@brianvoe
Copy link
Owner

ok im gonna merge this into develop and play around with it. Maybe find some way to simplify stuff.

@brianvoe brianvoe merged commit ed285f9 into brianvoe:develop Nov 19, 2023
@brianvoe
Copy link
Owner

Ok first round I did cleanup and simplification of your fixed width function. Let me know what you think

e3cd440

@brianvoe
Copy link
Owner

@Mrpye 082638f

Ok i did a bunch of cleanup and get things in line with the rest of the package. Take a look at the commit.

What i need from you is to basically just get the test working again and get a decent amount of additional tests in so we know we are covering our bases.

Take note that i have to use the rand that is passed to them. The rand they pass in need to be the bases for for how things are generated.

I tried building the FuncMap based upon the lookup setup but I think what you originally had by using reflect to pull the methods might be the better option.

I ran out of time today so ill let you run the finish line.

Just make sure you do a pr into the develop branch.

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 24, 2023 via email

@brianvoe
Copy link
Owner

no worries just let me know when your done

@brianvoe
Copy link
Owner

@Mrpye I submitted it to golang weekly newsletter and you made it first link!!!

https://golangweekly.com/issues/486

@Mrpye
Copy link
Contributor Author

Mrpye commented Nov 28, 2023 via email

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

Successfully merging this pull request may close these issues.

2 participants