<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/java/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:51 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/java/index.xml" rel="self" type="application/rss+xml"/><item><title>Natural Language Generation in Ruby (with JRuby + SimpleNLG)</title><link>https://akitaonrails.github.io/en/2016/10/28/natural-language-generation-in-ruby-with-jruby-simplenlg/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/10/28/natural-language-generation-in-ruby-with-jruby-simplenlg/</guid><pubDate>Fri, 28 Oct 2016 17:53:00 -0200</pubDate><description>&lt;p&gt;I am building a project which needs to generate proper English sentences. The first version I built used the super naive way of just creating a string template and doing simple sub-string replacements or concatenations.&lt;/p&gt;
&lt;p&gt;But you can imagine that it quickly becomes cumbersome when you have to deal with pluralization, inflection, and it starts to become something like this:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;There &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;is&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;are&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; user&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or use Rails I18n support like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>I am building a project which needs to generate proper English sentences. The first version I built used the super naive way of just creating a string template and doing simple sub-string replacements or concatenations.</p>
<p>But you can imagine that it quickly becomes cumbersome when you have to deal with pluralization, inflection, and it starts to become something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="s2">&#34;There </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="s1">&#39;is&#39;</span> <span class="p">:</span> <span class="s1">&#39;are&#39;</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span><span class="si">}</span><span class="s2"> user</span><span class="si">#{</span><span class="s1">&#39;s&#39;</span> <span class="k">unless</span> <span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span><span class="si">}</span><span class="s2">.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or use Rails I18n support like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">backend</span><span class="o">.</span><span class="n">store_translations</span> <span class="ss">:en</span><span class="p">,</span> <span class="ss">:user_msg</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:one</span> <span class="o">=&gt;</span> <span class="s1">&#39;There is 1 user&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:other</span> <span class="o">=&gt;</span> <span class="s1">&#39;There are %{count} users&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">translate</span> <span class="ss">:user_msg</span><span class="p">,</span> <span class="ss">:count</span> <span class="o">=&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#39;There are 2 users&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For simple transactional phrases (such as flash messages), this is more than enough.</p>
<p>But if you want to generate an entire article in plain English from data structures, then the logic becomes very convoluted very fast.</p>
<p>I looked around and found a few Ruby projects that could help, for example:</p>
<ul>
<li><a href="https://github.com/chorn/nameable"target="_blank" rel="noopener">&ldquo;nameable&rdquo;</a> which can do useful stuff like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Chris&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">gender</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; :male</span>
</span></span><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Janine&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">female?</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; true</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<ul>
<li><a href="https://github.com/maetl/calyx"target="_blank" rel="noopener">&ldquo;calyx&rdquo;</a> which can be used to generate simple phrases like this:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GreenBottle</span> <span class="o">&lt;</span> <span class="no">Calyx</span><span class="o">::</span><span class="no">Grammar</span>
</span></span><span class="line"><span class="cl">  <span class="n">mapping</span> <span class="ss">:pluralize</span><span class="p">,</span> <span class="sr">/(.+)/</span> <span class="o">=&gt;</span> <span class="s1">&#39;\\1s&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">start</span> <span class="s1">&#39;One green {bottle}.&#39;</span><span class="p">,</span> <span class="s1">&#39;Two green {bottle.pluralize}.&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">bottle</span> <span class="s1">&#39;bottle&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;One green bottle.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;Two green bottles.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Nice and dandy, but still useless for the more complex needs I have in mind.</p>
<p>So I decided to dig a bit deeper, into the dark world of NLG, or <strong>Natural Language Generation</strong> (not to be confused with NLP, which stands for Natural Language Processing, which is the opposite of what I want. NLP gets plain English text and returns a parsed data structure).</p>
<p>For <strong>NLP</strong> (parsing, tokenization, etc) I&rsquo;d highly recommend <a href="http://stanfordnlp.github.io/CoreNLP/"target="_blank" rel="noopener">&ldquo;Stanford CoreNLP&rdquo;</a>. It seems to be one of the most robust and comprehensive out there (come on, it&rsquo;s from Stanford). Again a Java project, and a big download (more than 300MB!). Those linguistics projects are super heavy because they have to download entire dictionaries and lexicon databases.</p>
<p>But focusing on my problem at hand, <strong>NLG</strong>, there are <a href="https://aclweb.org/aclwiki/index.php?title=Downloadable_NLG_systems"target="_blank" rel="noopener">several options</a> out there. In all honesty, I did not do very extensive research, so if you are aware of which is the most robust and also well maintained and with an easy to use interface, let me know in the comments section below.</p>
<p>My choice was <a href="https://github.com/simplenlg/simplenlg"target="_blank" rel="noopener">SimpleNLG</a>. From its GitHub page we can see that it seems to be quite well maintained to this day, it&rsquo;s a simple Java library and it is one of the &ldquo;simpler&rdquo; alternatives. <a href="http://www.fb10.uni-bremen.de/anglistik/langpro/kpml/README.html"target="_blank" rel="noopener">KPML</a> is on the opposite spectrum: it seems to be one of the oldest (since the 80&rsquo;s!) and most robust ones. But seriously, it feels like you need a Ph.D to even get started.</p>
<p>Reading the SimpleNLG Java source code was boring but easy enough. Give yourself one full day of study to get used to the code and you&rsquo;re in business.</p>
<p>The main problem is that it&rsquo;s written in Java and I don&rsquo;t intend to write anything in Java (or any derivative) for now. For a short while I considered the endeavor of rewriting the damn thing in something more portable such as Rust, which I could load anywhere through FFI.</p>
<p>But even though SimpleNLG has &ldquo;Simple&rdquo; in its name it has a few hairy dependencies to load the lexicon database. And the database itself is an HSQLDB dump, which is a Java-written database. And then, there would be the issue of maintaining a fork.</p>
<p>I quickly gave up on that idea and instead I worked around this by wrapping the library under a simple <a href="https://github.com/rails-api/rails-api"target="_blank" rel="noopener">Rails-API</a> endpoint. I had a few issues because I had Git LFS tracking jar files in my system and Heroku doesn&rsquo;t support it and I ended up with a corrupted deployment (beware of those quirks, by the way!)</p>
<p>Finally, I was able to deploy a working JRuby + Rails-API project embedding SimpleNLG at Heroku. You can deploy your own copy by cloning my <a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a>. It works fine with the latest JRuby 9.1.5.0. You should pay for at least a Hobby tier over Heroku. Java takes a ridiculous amount of time to start up and more time to warm up. Heroku&rsquo;s free tier shuts down your dyno if it sits idle and a subsequent web request will definitely time out or take an absurd amount of time to return.</p>
<p>Once deployed it starts up Rails, then loads <a href="https://github.com/Codeminer42/nlg_service/blob/master/config/initializers/simple_nlg.rb"target="_blank" rel="noopener">this initializer</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;java&#39;</span>
</span></span><span class="line"><span class="cl"><span class="no">Java</span><span class="o">::</span><span class="no">JavaLang</span><span class="o">::</span><span class="no">System</span><span class="o">.</span><span class="n">set_property</span> <span class="s2">&#34;file.encoding&#34;</span><span class="p">,</span><span class="s2">&#34;UTF-8&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_DEFAULT_LEXICON_PATH</span> <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG/resources/default-lexicon.xml&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_PATH</span>                 <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Dir</span><span class="o">[</span><span class="s2">&#34;</span><span class="si">#{</span><span class="no">SIMPLE_NLG_PATH</span><span class="si">}</span><span class="s2">/*.jar&#34;</span><span class="o">].</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">jar</span><span class="o">|</span> <span class="nb">require</span> <span class="n">jar</span> <span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And then I map the classes <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/models/simple_nlg.rb"target="_blank" rel="noopener">like this</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">SimpleNLG</span>
</span></span><span class="line"><span class="cl">  <span class="sx">%w(
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.aggregation
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.features
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.format.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.framework
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.lexicon
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.morphology.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.orthography.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.phrasespec
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.realiser.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.syntax.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser.wrapper
</span></span></span><span class="line"><span class="cl"><span class="sx">  )</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">package</span><span class="o">|</span> <span class="n">include_package</span> <span class="n">package</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, I have a simple endpoint mapped to a <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/controllers/api/realisers_controller.rb"target="_blank" rel="noopener">controller</a> action:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Api</span><span class="o">::</span><span class="no">RealisersController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">create</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">java</span><span class="o">::</span><span class="n">io</span><span class="o">::</span><span class="no">StringReader</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:xml</span><span class="o">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">begin</span>
</span></span><span class="line"><span class="cl">      <span class="n">records</span> <span class="o">=</span> <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">getRecording</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">output</span> <span class="o">=</span> <span class="n">records</span><span class="o">.</span><span class="n">getRecord</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">record</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">realise</span><span class="p">(</span><span class="n">record</span><span class="o">&amp;.</span><span class="n">getDocument</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="vi">@realisation</span> <span class="o">=</span> <span class="n">output</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span>
</span></span><span class="line"><span class="cl">      <span class="n">render</span> <span class="ss">plain</span><span class="p">:</span> <span class="vi">@realisation</span>
</span></span><span class="line"><span class="cl">    <span class="k">ensure</span>
</span></span><span class="line"><span class="cl">      <span class="n">reader</span><span class="o">.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The process of generating the final English text is called <strong>&ldquo;realisation&rdquo;</strong>. SimpleNLG has a comprehensive Java API but it also exposes it as a simpler XML format. The full <a href="https://github.com/simplenlg/simplenlg/blob/master/src/main/resources/xml/RealizerSchema.xsd"target="_blank" rel="noopener">XML Realiser Schema</a> is available as an XSD.</p>
<p>If I want to write this sentence:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>This is the XML that I need to assemble:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;NLGSpec</span> <span class="na">xmlns=</span><span class="s">&#34;http://simplenlg.googlecode.com/svn/trunk/res/xml&#34;</span> <span class="na">xmlns:xsd=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema&#34;</span> <span class="na">xmlns:xsi=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;Recording&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Record&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;Document</span> <span class="na">cat=</span><span class="s">&#34;PARAGRAPH&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;child</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;subj</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;ADVERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>there<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/subj&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">PERSON=</span><span class="s">&#34;THIRD&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>be<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span> <span class="na">NUMBER=</span><span class="s">&#34;PLURAL&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;NOUN&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>story<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;spec</span> <span class="na">xsi:type=</span><span class="s">&#34;WordElement&#34;</span> <span class="na">cat=</span><span class="s">&#34;DETERMINER&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>a<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/spec&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;preMod</span> <span class="na">xsi:type=</span><span class="s">&#34;CoordinatedPhraseElement&#34;</span> <span class="na">conj=</span><span class="s">&#34;and&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>finish<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>deliver<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/preMod&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span> <span class="na">MODAL=</span><span class="s">&#34;may&#34;</span> <span class="na">PASSIVE=</span><span class="s">&#34;true&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span> <span class="na">NEGATED=</span><span class="s">&#34;true&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>test<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/child&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;/Document&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Record&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/Recording&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/NLGSpec&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ok, this is preposterous, I know.</p>
<p>Which is why I decided to go ahead and use one of Ruby&rsquo;s most recognized strengths: creating <strong>DSLs</strong> or <strong>Domain Specific Languages</strong>.</p>
<p>The result of my initial endeavor to simplify this process is the <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a> ruby gem. Simply add the following to your <code>Gemfile</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>gem &#39;nlg_xml_realiser_builder&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And the humongous XML above becomes something more manageable like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="s1">&#39;PLURAL&#39;</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span><span class="o">.</span><span class="n">to_xml</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Understanding the intricacies of an <code>NPPhraseSpec</code> vs a <code>VPPhraseSpec</code> or the difference between a <code>WordElement</code> or <code>StringElement</code> are beyond this blog post. But most of the original XSD has been mapped through <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/lib/nlg_xml_realiser_builder/consts.rb"target="_blank" rel="noopener">this constants file</a>.</p>
<p>I have a <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/spec/nlg_xml_realiser_builder_spec.rb"target="_blank" rel="noopener">few acceptance specs</a> that are generating XMLs like the above, posting to my live online NLG Web Service and fetching the resulting English sentences. I will change this process in the future but you can test it out yourself.</p>
<p>The advantages start here. Now let&rsquo;s check out the previous example more closely. Again, it renders this phrase:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>Now, it&rsquo;s in plural form because I am talking about &lsquo;stories&rsquo;, but what if I want a singular version?</p>
<p>Below is the new version where I just wrap it around a method and make the attribute &lsquo;NUMBER&rsquo; accept both &lsquo;PLURAL&rsquo; or &lsquo;SINGULAR&rsquo;:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">example</span><span class="p">(</span><span class="n">plural</span> <span class="o">=</span> <span class="s1">&#39;PLURAL&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="n">plural</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">          <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span><span class="o">.</span><span class="n">to_xml</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And I can run the singular version like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>puts example(&#39;SINGULAR&#39;)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is the resulting phrase:</p>
<blockquote>
  <p>&ldquo;There is a finished and delivered story that may not have been tested.&rdquo;</p>

</blockquote>
<p>Check out how it changed the verb from &ldquo;are&rdquo; to &ldquo;is&rdquo; and the noun determiner from &ldquo;some&rdquo; to &ldquo;a&rdquo; on its own! And of course, this is a contrived example. Now imagine an entire customizable article, full of paragraphs and sentences that I can customize depending on several variables I have.</p>
<p>While I was studying and writing this DSL I got a good enough grasp of the SimpleNLG structure, but if you have more examples for more complex phrase structures, please let me know in the comments section down below.</p>
<p>Most of the specs were copied from the XML Realiser tests from the original Java project to make sure I am covering most cases.</p>
<p>It will be interesting to see if this DSL makes it easier for more people to experiment with NLG. As usual, send your Pull Requests, ideas and suggestions on my GitHub public repositories:</p>
<ul>
<li><a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a></li>
<li><a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a></li>
</ul>
<p>And if you&rsquo;re interested in the subject of NLP and NLG I found <a href="https://github.com/diasks2/ruby-nlp"target="_blank" rel="noopener">this list</a> of Ruby related open source projects as well.</p>
]]></content:encoded><category>ruby</category><category>java</category><category>rails</category></item></channel></rss>