Text Templates in Ada

Ada provides support for creating dynamic content or showing customized output to the user with the Ada.Text_IO.Text_Templates package.

with Ada.Text_IO;
with Ada.Text_IO.Text_Templates;
with Ada.Strings.Unbounded;

procedure Text_Templates_Example is
   use Ada.Text_IO;
   use Ada.Text_IO.Text_Templates;
   use Ada.Strings.Unbounded;

   -- We can create a new template and parse its body from a string.
   -- Templates are a mix of static text and "actions" enclosed in
   -- '{...}' that are used to dynamically insert content.
   T1 : Template;

begin
   Set_Template (T1, "Value is {0}");

   -- By "instantiating" the template we generate its text with
   -- specific values for its actions. The '{0}' action is
   -- replaced by the value passed as a parameter to Instantiate.
   Put_Line (Instantiate (T1, To_Unbounded_String ("some text")));
   Put_Line (Instantiate (T1, To_Unbounded_String ("5")));

   -- For more complex data structures, we can use named
   -- placeholders in our templates.
   Set_Template (T1, "Name: {name}");

   declare
      Person : constant Template_Map := Create_Mapping
        (Assoc ("name", "Jane Doe"));
   begin
      Put_Line (Instantiate (T1, Person));
   end;

   -- The same applies to associative arrays.
   declare
      Mickey : constant Template_Map := Create_Mapping
        (Assoc ("name", "Mickey Mouse"));
   begin
      Put_Line (Instantiate (T1, Mickey));
   end;

   -- Ada.Text_IO.Text_Templates doesn't provide direct support for
   -- conditional execution or loops within templates. For such
   -- functionality, you would typically use Ada control structures
   -- in combination with template instantiation.

   -- Here's an example of how you might implement conditional output:
   declare
      procedure Print_Condition (Value : String) is
      begin
         if Value /= "" then
            Put_Line ("yes");
         else
            Put_Line ("no");
         end if;
      end Print_Condition;
   begin
      Print_Condition ("not empty");
      Print_Condition ("");
   end;

   -- And here's an example of how you might implement a loop:
   declare
      Languages : constant array (Positive range <>) of Unbounded_String :=
        (To_Unbounded_String ("Ada"),
         To_Unbounded_String ("SPARK"),
         To_Unbounded_String ("C++"),
         To_Unbounded_String ("Rust"));
   begin
      Put ("Range: ");
      for Lang of Languages loop
         Put (To_String (Lang) & " ");
      end loop;
      New_Line;
   end;
end Text_Templates_Example;

To run the program, compile it with an Ada compiler (like GNAT) and then execute the resulting binary:

$ gnatmake text_templates_example.adb
$ ./text_templates_example
Value is some text
Value is 5
Name: Jane Doe
Name: Mickey Mouse
yes
no
Range: Ada SPARK C++ Rust

This Ada example demonstrates the basic usage of text templates. Note that Ada’s template functionality is more limited compared to some other languages. For more complex templating needs, you might need to use additional libraries or implement custom solutions.

Ada’s Text_Templates package focuses on simple string substitution. For conditional execution, loops, and more complex operations, you typically use Ada’s standard control structures in combination with template instantiation, as shown in the examples above.

Remember to handle potential exceptions that may be raised during template operations in a real-world application.