<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Aaron Feng: Lisp ninja 2 - Refactoring</title>
    <link>http://www.aaronfeng.com/articles/2008/05/31/lisp-ninja-2-refactoring</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Adventures in software development</description>
    <item>
      <title>Lisp ninja 2 - Refactoring</title>
      <description>&lt;p&gt;&lt;a href="http://aaronfeng.com/articles/2008/04/29/lisp-ninja"&gt;Last post&lt;/a&gt; I talked about creating an abstraction using Lisp macros to  assist me with my unit tests.  If you look at the code, there is an obvious flaw.  get-result-for-test-case hard codes the target PHP function in it.  It wouldn't be very nice to rewrite a new version of it every time I need to call a different PHP function.&lt;/p&gt;

&lt;p&gt;In the original code from last post, the target PHP function was defined in string format.  Since I'm working in Lisp I would prefer to define it in sexp format to gain the most flexibility.  For example, calling the explode function in PHP would look like the following:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;(explode &amp;quot; &amp;quot; &amp;quot;aaron feng&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's start the refactoring:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;; helper function
(defun quote-string (input)
  (if (typep input 'string)
    (format nil &amp;quot;\&amp;quot;~a\&amp;quot;&amp;quot; input)
    input))

(defun get-function-signature (function-info)
  (let ((function (first function-info))
        (parameters (rest function-info))
        (signature &amp;quot;&amp;quot;) 
        (delimiter &amp;quot;&amp;quot;))
    (setf signature (format nil &amp;quot;~a~a&amp;quot; function &amp;quot;(&amp;quot;))

    (loop for parameter in parameters do
         (setf signature (format nil &amp;quot;~a~a~a&amp;quot; 
                                 signature
                                 delimiter 
                                 (quote-string parameter)))
         (setf delimiter &amp;quot;, &amp;quot;))

    (setf signature (format nil &amp;quot;~a~a&amp;quot; signature &amp;quot;)&amp;quot;))))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;get-function-signature does all the dirty work by converting input function in sexp format to a string that we can eventually send to PHP.  Let's incorporate this function back into get-result-for-test-case, so it can accept other functions.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;(defun get-result-for-test-case (func-info)
  (with-output-to-string (str)
    (let ((func-string
           (concatenate 'string &amp;quot;print_r(&amp;quot; (get-function-signature func-info) &amp;quot;);&amp;quot;)))
      (run-program *php-bin* (list
                              &amp;quot;-r&amp;quot;
                              func-string)
                   :output str))))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With these changes, it will make get-result-for-test-case much more generic.  However, there is another problem, not all PHP functions return a string.  If the function returns an array, the output will always be "Array".  It would be nice if it could convert PHP array back into Lisp list, so it can be used for comparison in the tests.  That is exactly what I'm going to do next.  Notice that I replaced the "echo" with "print_r", so it will output human readable values for data structure such as array.  &lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;(defun parse-php-array (array)
  (let ((parts (split-sequence #\Newline array))
        (output))
    (dolist (part parts)
      (let ((value (get-array-value part)))
        (format t &amp;quot;~a&amp;quot; part)
        (when value (push value output))))
    (reverse output)))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now if I wrap get-result-for-test-case with parse-php-array, it should convert the output into a Lisp list.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;(parse-php-array (get-result-for-test-case `(explode &amp;quot; &amp;quot; &amp;quot;aaron feng&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course, more work can be done to make the code more intelligent, such as, only try to parse array if the output is an array type.  Currently the code can only handle Array and String as return type, but it can be extended further if desired.&lt;/p&gt;</description>
      <pubDate>Sat, 31 May 2008 23:01:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:ba0bad02-af28-44c9-af4e-faf52510a1ca</guid>
      <author>Aaron Feng</author>
      <link>http://www.aaronfeng.com/articles/2008/05/31/lisp-ninja-2-refactoring</link>
      <category>programming</category>
    </item>
    <item>
      <title>"Lisp ninja 2 - Refactoring" by Leslie P. Polzer</title>
      <description>&lt;p&gt;And here's another take on PARSE-PHP-ARRAY using LOOP:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun parse-php-array (array)
  (loop for value in (mapcar #'get-array-value
                            (split-sequence #\Newline array))
        collect value into values
        finally (return (nreverse values))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm not sure why you want to reverse the values at the end, but here it is.&lt;/p&gt;</description>
      <pubDate>Thu, 03 Jul 2008 09:07:28 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:52fcfcec-e7ea-4091-88a0-6c91650d208b</guid>
      <link>http://www.aaronfeng.com/articles/2008/05/31/lisp-ninja-2-refactoring#comment-5985</link>
    </item>
    <item>
      <title>"Lisp ninja 2 - Refactoring" by Leslie P. Polzer</title>
      <description>&lt;p&gt;Wow, lots of spam here. Maybe you should turn on comment approval or some sort of CAPTCHA...&lt;/p&gt;

&lt;p&gt;Anyway, here's my Shinobi take of GET-FUNCTION-SIGNATURE:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun get-function-signature (function-info)
  (let ((name (first function-info))
        (parameters (rest function-info)))
    (format nil "~A(~{~A~^, ~})" name (mapcar #'quote-string parameters))))
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Thu, 03 Jul 2008 08:59:36 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:dc923e81-c0ab-4cc8-bc89-cc1b9b4b4f84</guid>
      <link>http://www.aaronfeng.com/articles/2008/05/31/lisp-ninja-2-refactoring#comment-5984</link>
    </item>
  </channel>
</rss>
