Velocity
  1. Velocity
  2. VELOCITY-787

Write to multiple files, controlled by template directives

    Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.x
    • Fix Version/s: None
    • Component/s: Engine
    • Labels:
      None
    • Environment:
      All environments

      Description

      For some purposes, such as code generation, it would be very desirable to output to multiple files from the same context. For example, to generate code for a C++ class, two files must be generated - a header and implementation file. Rendering could be driven by the same context in both cases, which would desribe the class name, method signatures, etc. Currently this must be done by running the engine twice - once with a header template and again with an implementation file template.

      Furthermore, it would desirable to determine the output file names during rendering, based on a combination of template directives and data in the context. To use the code generation example, the header and implementation file names would be determined by the name of the class to be generated.

      This is not possible with the current method signature of Directive:
      public boolean render(InternalContextAdapter context, Writer writer, Node node)
      An output directive would want to change the writer to a different instance of FileWriter, for instance. But since Java passes object references by value, the writer object cannot be replaced.

      The proposal is to provide a method to install a new instance of Writer during rendering of a template. This would support both writing multiple outputs in one run of the engine as well as controlling the file names of the outputs.

      1. FileTool.java
        10 kB
        Christoph Reck

        Activity

        Hide
        Nathan Bubna added a comment -

        I care far more about YAGNI than symmetry, and i don't think most users need it. As for multiple views of one model, i don't see anything consistent about squishing multiple views into a single view template. Multiple templates for multiple views seems much more fitting.

        And while a feature discussion with a use-case is nice, a single use case (w/o even a syntax proposal, much less a patch) is not all that compelling. I find it difficult to imagine any other usecase for this offhand, while i find it easy to imagine many other straightforward ways of handling the C++ header and implementation files.

        Show
        Nathan Bubna added a comment - I care far more about YAGNI than symmetry, and i don't think most users need it. As for multiple views of one model, i don't see anything consistent about squishing multiple views into a single view template. Multiple templates for multiple views seems much more fitting. And while a feature discussion with a use-case is nice, a single use case (w/o even a syntax proposal, much less a patch) is not all that compelling. I find it difficult to imagine any other usecase for this offhand, while i find it easy to imagine many other straightforward ways of handling the C++ header and implementation files.
        Hide
        Don Mendelson added a comment -

        Christoph and Nathan, thanks for the suggestions. I had already tried a workaround using a StringWriter to collect portions of a rendered template until I knew what file to write it to. So clearly there are ways to accomplish the result outside of Velocity.

        However, I argue for the proposal on two grounds:

        First, having an output directive (or at least the ability to create a custom one) would form a symmetry with input directives, such as #include and #parse.

        Second, much of the discussion of template engines and similar rendering tools revolves around separating model from view. My example of generating C++ header and implemention files from a common context is conceptually consistent with the idea of multiple views of one model.

        Show
        Don Mendelson added a comment - Christoph and Nathan, thanks for the suggestions. I had already tried a workaround using a StringWriter to collect portions of a rendered template until I knew what file to write it to. So clearly there are ways to accomplish the result outside of Velocity. However, I argue for the proposal on two grounds: First, having an output directive (or at least the ability to create a custom one) would form a symmetry with input directives, such as #include and #parse. Second, much of the discussion of template engines and similar rendering tools revolves around separating model from view. My example of generating C++ header and implemention files from a common context is conceptually consistent with the idea of multiple views of one model.
        Hide
        Christoph Reck added a comment -

        Nathan was faster than I...
        Here is the tool (from 2001...).
        Maybe you can close the issue if this solves your request.

        Show
        Christoph Reck added a comment - Nathan was faster than I... Here is the tool (from 2001...). Maybe you can close the issue if this solves your request.
        Hide
        Christoph Reck added a comment -

        I don't think this needs to be solved within the engine. In the past I've solved this through a controller template, string interpolation, and a file writer tool. Example:

        #macro( createCode $params )

          1. ... do something wise here
            #end
            ...
            #foreach ($file $list)
            #set( $fileContents = "#createCode(...)" )
            $FileTool.write($file, $fileContents)
            #end
        Show
        Christoph Reck added a comment - I don't think this needs to be solved within the engine. In the past I've solved this through a controller template, string interpolation, and a file writer tool. Example: #macro( createCode $params ) ... do something wise here #end ... #foreach ($file $list) #set( $fileContents = "#createCode(...)" ) $FileTool.write($file, $fileContents) #end
        Hide
        Nathan Bubna added a comment -

        I think this is out of scope for the Engine project, and perhaps Velocity in general. And i think you could support this now with a clever tool instead of Directives, and with no need to modify Velocity.

        public class WriterTool

        { public void switchToWriter(String name)... public void setFilename(String name)... public void whateverMagicYouCanThinkUp()... }

        Then you give this tool the info it needs, drop that instance into your context and viola! You have all the control you want from within the template.

        Show
        Nathan Bubna added a comment - I think this is out of scope for the Engine project, and perhaps Velocity in general. And i think you could support this now with a clever tool instead of Directives, and with no need to modify Velocity. public class WriterTool { public void switchToWriter(String name)... public void setFilename(String name)... public void whateverMagicYouCanThinkUp()... } Then you give this tool the info it needs, drop that instance into your context and viola! You have all the control you want from within the template.

          People

          • Assignee:
            Unassigned
            Reporter:
            Don Mendelson
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development