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

Add reflection-related template functions #4081

Closed
moorereason opened this issue Nov 14, 2017 · 12 comments
Closed

Add reflection-related template functions #4081

moorereason opened this issue Nov 14, 2017 · 12 comments

Comments

@moorereason
Copy link
Contributor

See https://discourse.gohugo.io/t/how-to-test-if-a-variable-is-of-a-certain-type/9207.

Related to #2427.

moorereason added a commit to moorereason/hugo that referenced this issue Dec 15, 2017
Adds KindIs, KindOf, TypeIs, TypeIsLike, and TypeOf funcs in a reflect
namespace.

Fixes gohugoio#4081
moorereason added a commit to moorereason/hugo that referenced this issue Dec 16, 2017
Adds KindIs, KindOf, TypeIs, TypeIsLike, and TypeOf funcs in a reflect
namespace.

Fixes gohugoio#4081
@stale
Copy link

stale bot commented Feb 12, 2018

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

@stale stale bot added the Stale label Feb 12, 2018
@kaushalmodi
Copy link
Contributor

Oh no! Please keep this.

@stale stale bot removed the Stale label Feb 12, 2018
@kaushalmodi
Copy link
Contributor

kaushalmodi commented Feb 12, 2018

I have to resort to this:

{{ $value              := . }}
{{ $type               := (printf "%T" $value) }}
{{ $typeIsBool         := (eq "bool" $type) }}
{{ $typeIsNumber       := (or (eq "int" $type) (eq "int64" $type) (eq "float64" $type)) }}
{{ $typeIsString       := (eq "string" $type) }}
{{ $typeIsTime         := (eq "time.Time" $type) }}
{{ $typeIsSlice        := (findRE "^([[][]]|.*TaxonomyList|output\\.Formats|resource\\.Resources|\\*?hugolib\\.Menu$|\\*?hugolib\\.Pages$)" $type) }} <!-- match ^[] -->
{{ $typeIsMap          := (findRE "^(map[[].+[]]|.*SiteSocial|\\*hugolib\\.Menus|hugolib\\.AuthorList)" $type) }} <!-- match ^map[*] -->

{{ $typeIsSiteInfo     := (eq "*hugolib.SiteInfo" $type) }}
{{ $typeIsGitInfo      := (findRE "^.*gitmap\\.GitInfo" $type) }}
{{ $typeIsOutputFormat := (eq "output.Format" $type) }}
{{ $typeIsResource     := (findRE "^\\*resource" $type) }}
{{ $typeIsPage         := (findRE "^\\*hugolib\\.Page" $type) }}
{{ $typeIsFileInfo     := (findRE "^\\*(hugolib|source)\\.[fF]ileInfo$" $type) }} <!-- terms pages for e.g. uses source.FileInfo, regular pages using hugolib.fileInfo -->
{{ $typeIsMenuEntry    := (eq "*hugolib.MenuEntry" $type) }}
{{ $typeIsStruct       := (or $typeIsSiteInfo $typeIsGitInfo $typeIsOutputFormat $typeIsFileInfo $typeIsPage $typeIsMenuEntry) }}
{{ $typeIsInterface := (or $typeIsResource) }}

My current solution (above) is very hacky. As you see, there's no easy way to figure out if a variable is a slice/map/struct/interface.


Full code

@kaushalmodi
Copy link
Contributor

kaushalmodi commented Feb 12, 2018

Proposal for reflect template functions

@bep @moorereason

Here's a very rough proposal. For many Hugo users, they would generally be interested in knowing if a variable is a string (doesn't matter if it is string, or template.HTML, or template.URL, ..), or a number (doesn't matter int vs int64 vs float64 vs ..), or a slice (so that range can be used), or a map (so that range $i, $j := .. can be used), or just knowing that something is a struct or an interface (to know enough that range cannot be used).

To a user wanting to know these things in a template, it's not important (please comment below if this is wrong) to know a specific Type and Kind. The functions added to Hugo template functions are user-level functions, and not for internal Go debugging.. it's just to debug the Hugo layout templates and such.

With that introduction, I would propose adding these functions:

  • reflect.IsBool
  • reflect.IsNumber (if this is too coarse, then may be reflect.IsInteger and reflect.IsFloat?)
  • reflect.IsString
  • reflect.IsTime
  • reflect.IsSlice
  • reflect.IsMap
  • reflect.IsStruct
  • reflect.IsInterface

All of these functions should return a boolean value.

@regisphilibert
Copy link
Member

That sounds great, but couldn't we have a function returning the type? (similar to javascript's typeof).

This means we could both "retrieve" the type and test it in conjunction with eq. And this limit the addition to one single template function.

{{ with .Params.stuff }}
   {{ if eq (getType .) "slice" }}
      {{ range . }}
       that code
      {{ end }}
   {{ end }}
{{ end}}

@kaushalmodi
Copy link
Contributor

kaushalmodi commented May 3, 2018

@regisphilibert That would be fine too, but I would still weigh on the reflect.Is.. functions as they look sweeter (I meant, a better syntactic sugar 😄).

It would be nicer to see {{ if reflect.IsSlice . }} instead of {{ if eq (getType .) "slice" }}. There too, if we go down the getType route, it would be good to add the reflect namespace, to prevent confusion with the Hugo types used in layouts and the variable Type (slice, map, etc.). But then it becomes even wordier..

{{ if reflect.IsSlice . }}

vs

{{ if eq (reflect.getType .) "slice" }}

Also, there are only handful data Types that we care about here.. so the effort to get all those reflect.Is.. should not be too bad.

@bep
Copy link
Member

bep commented May 3, 2018

@regisphilibert you can do similar with printf today, e.g. {{ if eq (printf "%T" .) "string" }}. But I think you will get a little dizzy about the myriad of types out there ...

As @kaushalmodi points out, you really do not care too much if it is a "slice of apples", just that it is a slice that you can iterate over, a map with keys/values etc.

@kaushalmodi
Copy link
Contributor

But I think you will get a little dizzy about the myriad of types out there

He probably meant a "getKind", again not to confuse with page kinds :)

But yes, talking about the myriad of types, I am probably covering a veery small fraction of all Hugo types here ;-)

@regisphilibert
Copy link
Member

Yeah, I in the end, all we really need is a CanWeRangeOnThis function.

I agree the boolean version of @kaushalmodi is cleaner and I'd happily settle for a reflect.getType.

@moorereason moorereason self-assigned this Nov 27, 2018
@moorereason moorereason added this to the v0.52 milestone Nov 27, 2018
@moorereason
Copy link
Contributor Author

I have a subset of @kaushalmodi's proposal ready.

I'm omitting IsTime because I'm sticking with Kind tests, and that would be a Type test. Use printf for Type tests.

I'm omitting IsInterface because I'm not yet convinced of its usefulness. How would this be useful?

I currently have IsBool, IsMap, IsNumber, IsSlice, IsString, and IsStruct.

Any comments before I submit a PR?

Cc: @bep

@bep
Copy link
Member

bep commented Nov 28, 2018

IsSlice and IsMap have clear use cases. I'm not convinced about the "general usefulness" of the others? And note that @kaushalmodi 's "debug printer" does not fall into the "general useful" category.

What is IsStruct used for?

@bep bep modified the milestones: v0.52, v0.53 Nov 28, 2018
moorereason added a commit to moorereason/hugo that referenced this issue Nov 28, 2018
Add a reflect namespace that offers a two boolean functions for
testing if a value is a map or slice.

Fixes gohugoio#4081
@bep bep closed this as completed in c84f506 Dec 7, 2018
gerrywastaken added a commit to ContainerSolutions/runbooks that referenced this issue Jul 1, 2020
There has unfortunately been some pushback with adding general debugging
tools to Hugo

gohugoio/hugo#4081 (comment)
gohugoio/hugo#3957 (comment)

I've found this can make things a lot more difficult than it needs
to be. There appears to be a belief that adding debugging tools will
lead to people using things that are undocumented. Unfortunately in my
experience I've had trouble with values that are documented but where
the documentation isn't very clear.

Even where debugging tools are provided the output is minified and
requests to change this have so far been rejected for the same reason as
above.

A user has developed a theme which can work around many of these issues
and add a convenient debugging partial to allow you to clearly see the
contents of most variables. (see README changes for more specifics.)
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants