テーブル出力の略記法

ここでは、AmXMLのテーブル関係の機能を説明しますが、その前に、ハッシュと配列以外のオブジェクトの扱いについて説明します。

ハッシュ以外のデータの扱い

以下のテーブル出力のサンプルでは、以下のデータを使用します。

context "table" do
  WebSite = Struct.new(:name, :url)

  class Lang
    include Amrita2::DictionaryData
    attr_reader :name, :author, :website
    def initialize(n, a, w)
      @name, @author, @website = n, a, w
    end
  end

  setup do 
    @data = {
      :lang_list =>[ 
        Lang.new("Ruby", "matz", WebSite.new('Ruby Home Page', 'http://www.ruby-lang.org/')),
        Lang.new("Perl", "Larry Wall", WebSite.new('The Source for Perl', 'http://perl.com/')),
        Lang.new("Python","Guido van Rossum", WebSite.new('Python Programing Language', 'http://www.python.org/'))
      ]
    }
  end

Amrita2では、Structもハッシュと同様にモデルデータとして使用できます。

また、目印としてAmrita2::DictionaryDataというモジュールを include することで、他の任意のオブジェクトをハッシュの代わりに使用することができます。

この場合は、データの取り出しは、対応する名前のメソッド呼び出しになります。

AmXMLのセルライン

AmXMLでは、<<...>> <<<...>>>に加えて、|で区切られた行から、td要素を生成する記述方式があります。

行の先頭が、「|」である行を「セルライン」と呼び、AmXMLプリプロセッサは、この行に対して特殊な処理を行ないます。

  specify "simple" do
    t = Amrita2::Template.new <<-END
    <<table border='1'<
      <<tr:lang_list <
       ||| <<:name>> | <<:author>>|
      >>>
    >>>
    END

    t.render_with(@data).should_be_samexml_as <<-END
      <table border = "1">
        <tr><td>Ruby</td><td>matz</td></tr>
        <tr><td>Perl</td><td>Larry Wall</td></tr>
        <tr><td>Python</td><td>Guido van Rossum</td></tr>
      </table>
    END
  end

一番単純な例では、上記のように、td要素を出力します。

th要素を出力したり、属性を設定することもできます。

  specify "with title and attributes" do
    t = Amrita2::Template.new <<-END
    <<table border='1'<
      <<tr<
       #-------------------------------------------
       |     || name      ||   author   ||cite   ||
       |class|| h_name    ||   h_author ||h_cite ||
       #-------------------------------------------
      >>>
      <<tr:lang_list
           |ToHash[:name=>:name, :author=>:author, :site=>:website]
           |Each[:class=>["odd", "even"]]
           |Attr[:class] <
       #------------------------------------------------------------------------------
       |     || <<:name>> |  <<:author>>|<<a:site\\|Attr[:href=>:url, :body=>:name]>>|
       |class|| name      |  author     |site                                        |
       #------------------------------------------------------------------------------
      >>>
    >>>
    END

    #t.set_trace(STDOUT)
    t.render_with(@data).should_be_samexml_as <<-END
      <table border='1'>
        <tr>
          <th class='h_name'>name</th>
          <th class='h_author'>author</th>
          <th class='h_cite'>cite</th>
        </tr>
        <tr class='odd'>
          <td class='name'>Ruby</td>
          <td class='author'>matz</td>
          <td class='site'>
            <a href='http://www.ruby-lang.org/'>Ruby Home Page</a>
          </td>
       </tr>
       <tr class='even'>
          <td class='name'>Perl</td>
          <td class='author'>Larry Wall</td>
          <td class='site'>
            <a href='http://perl.com/'>The Source for Perl</a>
          </td>
       </tr>
       <tr class='odd'>
          <td class='name'>Python</td>
          <td class='author'>Guido van Rossum</td>
          <td class='site'>
            <a href='http://www.python.org/'>Python Programing Language</a>
          </td>
       </tr>
      </table>
    END
  end

「|属性名||」という行があると、その行の値を属性として設定します。また、セルの右側が、「||」であるセルは、th要素として出力されます。

       #-------------------------------------------
       |     || name      ||   author   ||cite   ||
       |class|| h_name    ||   h_author ||h_cite ||
       #-------------------------------------------

という記述が、次のように展開されます。(#..はコメント行)

          <th class='h_name'>name</th>
          <th class='h_author'>author</th>
          <th class='h_cite'>cite</th>


のclass属性が、1行おきに変化しているのは、セルラインでなく、Eachというフィルターの機能です。

      <<tr:lang_list
           |ToHash[:name=>:name, :author=>:author, :site=>:website]
           |Each[:class=>["odd", "even"]]
           |Attr[:class] <

Each[:class=>["odd", "even"]] によって、コンテキストデータの:class要素に"odd"と"even"がかわりばんこに設定され、それがAttrによって展開されます。


この機能により、clospanやrowspanを使う場合等も、区切りの位置を工夫することで、出力結果に近い形式でテンプレートを記述することができます。

  specify 'rowspan colspan' do 
    # from http://www.y-adagio.com/public/standards/tr_html4/struct/tables.html
=begin    
    A test table with merged cells
    /-----------------------------------------\
    |          |      Average      |   Red    |
    |          |-------------------|  eyes    |
    |          |  height |  weight |          |
    |-----------------------------------------|
    |  Males   | 1.9     | 0.003   |   40%    |
    |-----------------------------------------|
    | Females  | 1.7     | 0.002   |   43%    |
    \-----------------------------------------/
=end
    expected = <<-END 
    <table border="1"
           summary="This table gives some statistics about fruit
                   flies: average height and weight, and percentage
                   with red eyes (for both males and females).">
      <caption><em>A test table with merged cells</em></caption>
      <tr>
        <th rowspan="2" />
        <th colspan="2">Average</th>
        <th rowspan="2">Red<br/>eyes</th>
      </tr>
      <tr>
        <th>height</th>
        <th>weight</th>
      </tr>
      <tr>
        <th>Males</th>
        <td>1.9</td>
        <td>0.003</td>
        <td>40%</td>
      </tr>
      <tr>
        <th>Females</th>
        <td>1.7</td>
        <td>0.002</td>
        <td>43%</td>
      </tr>
    </table>
    END
    t = Amrita2::Template.new <<-END
    <<table border='1':|Attr[:summary]<
      <<caption<
        <<em:caption>>
      >>>
      <<tr<
        #------------------------------------------------------
        | rowspan  || 2      ||               ||     2       ||
        | colspan  ||        || 2             ||             ||
        |          ||        ||Average        ||Red<br />eyes||
      >>>
      <<tr<
        |                    ||       ||      || 
        |                    ||height ||weight||             
        |                    ||       ||      || 
        #------------------------------------------------------
      >>>
      <<tr:data<
        |          ||<<:sex>>||<<:height>>    |
        |          ||        ||        |<<:weight\\|Format['%1.3f']>>|
        |          ||        ||        |      |<<:percent\\|Format['%d%%']>>|          
      >>>
    >>>
    END

    data = {
      :summary=>"This table gives some statistics about fruit
                   flies: average height and weight, and percentage
                   with red eyes (for both males and females).",
      :caption=>'A test table with merged cells',
      :data => [
        { :sex=>'Males' ,   :height=>1.9, :weight=>0.003, :percent=>40 },
        { :sex=>'Females' , :height=>1.7, :weight=>0.002, :percent=>43 }
      ]
    }
    
    t.render_with(data).should_be_samexml_as(expected)

これをw3mレンダリングすると以下のようになります。

┌────┬───────┬──┐
│        │   Average    │Red │
│        ├───┬───┤eyes│
│        │height│weight│    │
├────┼───┼───┼──┤
│ Males  │1.9   │0.003 │40% │
├────┼───┼───┼──┤
│Females │1.7   │0.002 │43% │
└────┴───┴───┴──┘