radius 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/DSL-SPEC +151 -0
 - data/QUICKSTART +98 -0
 - data/README +49 -0
 - data/ROADMAP +18 -0
 - data/Rakefile +41 -0
 - data/lib/radius.rb +126 -0
 - data/test/radius_test.rb +122 -0
 - metadata +55 -0
 
    
        data/DSL-SPEC
    ADDED
    
    | 
         @@ -0,0 +1,151 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            =DSL Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            I haven't implemented a domain specific languages for Contexts yet, but I am hoping to
         
     | 
| 
      
 4 
     | 
    
         
            +
            do so in a future release. Below are some thoughts (in code) for how I would like it to
         
     | 
| 
      
 5 
     | 
    
         
            +
            work. Note that with a robust DSL you will be able to define that certain tags are
         
     | 
| 
      
 6 
     | 
    
         
            +
            only valid within certain containing tags.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              class StoreContext < Radius::Context
         
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @prefix = "r" # all tags must be prefixed with "r"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @user = options[:user]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @cart = options[:cart]
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @session = options[:session]
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
                # expose the @user object variable
         
     | 
| 
      
 17 
     | 
    
         
            +
                container(:user, :exposes => :user) do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # Use protect() on an object that has been exposed to prevent access to
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # an attribute in a template. Conversely you could use the expose() method
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # to expose specific attributes to the template and protect all others.
         
     | 
| 
      
 21 
     | 
    
         
            +
                  protect :password
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # add a single tag that returns the session_id
         
     | 
| 
      
 24 
     | 
    
         
            +
                  tag :session_id do |attributes|
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @session.id
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
                # expose the @cart object as the basket tag
         
     | 
| 
      
 30 
     | 
    
         
            +
                container(:basket, :exposes => :cart) do
         
     | 
| 
      
 31 
     | 
    
         
            +
                  expand do |attributes|
         
     | 
| 
      
 32 
     | 
    
         
            +
                    #
         
     | 
| 
      
 33 
     | 
    
         
            +
                    # some initialization code with attributes before handling
         
     | 
| 
      
 34 
     | 
    
         
            +
                    # content block
         
     | 
| 
      
 35 
     | 
    
         
            +
                    #
         
     | 
| 
      
 36 
     | 
    
         
            +
                    yeild
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                  container(:items, :exposes => :item) do
         
     | 
| 
      
 40 
     | 
    
         
            +
                    expand do |attributes|
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @cart.items.each do |@item|
         
     | 
| 
      
 42 
     | 
    
         
            +
                        yield
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
                container :cart do
         
     | 
| 
      
 49 
     | 
    
         
            +
                  expand do |attributes|
         
     | 
| 
      
 50 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              class User
         
     | 
| 
      
 56 
     | 
    
         
            +
                attr_accessor :name, :login, :password, :email
         
     | 
| 
      
 57 
     | 
    
         
            +
                def initialize(name, login, password, email)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @name, @login, @password, @email = name, login, password, email
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              class Session
         
     | 
| 
      
 63 
     | 
    
         
            +
                attr_accessor :id
         
     | 
| 
      
 64 
     | 
    
         
            +
                def initialize(id)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @id = id
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              class Cart
         
     | 
| 
      
 70 
     | 
    
         
            +
                attr_accessor :items
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
                def initialize(*items)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @items = [items].flatten
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              
         
     | 
| 
      
 76 
     | 
    
         
            +
                def total
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @items.map { |line_item| line_item.total }
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              class LineItem
         
     | 
| 
      
 82 
     | 
    
         
            +
                attr_accessor :name, :description, :quantity, :item_price
         
     | 
| 
      
 83 
     | 
    
         
            +
                def intialize(name, description, price, quantity)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  @name, @description, @price, @quantity = name, description, price, quantity
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
                def full_price
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @price * @quantity
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
              receipt = <<-RECEIPT
         
     | 
| 
      
 92 
     | 
    
         
            +
              <p><r:user:name />, thank you for shopping with us! An order summary
         
     | 
| 
      
 93 
     | 
    
         
            +
                is printed below for your convinience. Please print a copy for your records.</p>
         
     | 
| 
      
 94 
     | 
    
         
            +
              <r:cart>
         
     | 
| 
      
 95 
     | 
    
         
            +
                <table>
         
     | 
| 
      
 96 
     | 
    
         
            +
                  <thead>
         
     | 
| 
      
 97 
     | 
    
         
            +
                    <tr>
         
     | 
| 
      
 98 
     | 
    
         
            +
                      <td>Product</td>
         
     | 
| 
      
 99 
     | 
    
         
            +
                      <td>Price</td>
         
     | 
| 
      
 100 
     | 
    
         
            +
                      <td>Quantity</td>
         
     | 
| 
      
 101 
     | 
    
         
            +
                      <td>Totals</td>
         
     | 
| 
      
 102 
     | 
    
         
            +
                    </tr>
         
     | 
| 
      
 103 
     | 
    
         
            +
                  </thead>
         
     | 
| 
      
 104 
     | 
    
         
            +
                  <tbody>
         
     | 
| 
      
 105 
     | 
    
         
            +
                    <r:items>
         
     | 
| 
      
 106 
     | 
    
         
            +
                      <tr>
         
     | 
| 
      
 107 
     | 
    
         
            +
                        <td>
         
     | 
| 
      
 108 
     | 
    
         
            +
                          <strong><r:name /></strong><br >
         
     | 
| 
      
 109 
     | 
    
         
            +
                          <r:description />
         
     | 
| 
      
 110 
     | 
    
         
            +
                        </td>
         
     | 
| 
      
 111 
     | 
    
         
            +
                        <td><r:price /></td>
         
     | 
| 
      
 112 
     | 
    
         
            +
                        <td><r:quanity /></td>
         
     | 
| 
      
 113 
     | 
    
         
            +
                        <td><r:full_price /></td>
         
     | 
| 
      
 114 
     | 
    
         
            +
                      </tr>
         
     | 
| 
      
 115 
     | 
    
         
            +
                    </r:items>
         
     | 
| 
      
 116 
     | 
    
         
            +
                  </tbody>
         
     | 
| 
      
 117 
     | 
    
         
            +
                  <tr>
         
     | 
| 
      
 118 
     | 
    
         
            +
                    <td colspan="3">Total</td>
         
     | 
| 
      
 119 
     | 
    
         
            +
                    <td><r:total /></td>
         
     | 
| 
      
 120 
     | 
    
         
            +
                  </tr>
         
     | 
| 
      
 121 
     | 
    
         
            +
                </table>
         
     | 
| 
      
 122 
     | 
    
         
            +
              </r:cart>
         
     | 
| 
      
 123 
     | 
    
         
            +
              RECEIPT
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              user = User.new('John', 'johnboy', 'm@x!mu5', 'johnboy@maximus.com')
         
     | 
| 
      
 126 
     | 
    
         
            +
              cart = Cart.new(
         
     | 
| 
      
 127 
     | 
    
         
            +
                LineItem.new('15in PowerBook', "Apple's premium notebook computer.", 1995.98, 1),
         
     | 
| 
      
 128 
     | 
    
         
            +
                LineItem.new('Mac Notebook Case', "A beautiful black notebook case designed for Apple Powerbooks.", 54.05, 1)
         
     | 
| 
      
 129 
     | 
    
         
            +
              )
         
     | 
| 
      
 130 
     | 
    
         
            +
              session = Session.new('a4bd386e512bacd581')
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
              context = StoreContext.new(
         
     | 
| 
      
 133 
     | 
    
         
            +
                :user => user,
         
     | 
| 
      
 134 
     | 
    
         
            +
                :cart => cart,
         
     | 
| 
      
 135 
     | 
    
         
            +
                :session => session
         
     | 
| 
      
 136 
     | 
    
         
            +
              )
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
              template = Radius::Template.new(
         
     | 
| 
      
 139 
     | 
    
         
            +
                :text => receipt,
         
     | 
| 
      
 140 
     | 
    
         
            +
                :context => context
         
     | 
| 
      
 141 
     | 
    
         
            +
              )
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
              template.compile! # based on context parses text into abstract syntax tree
         
     | 
| 
      
 144 
     | 
    
         
            +
              puts template.expand # outputs expanded template
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
              # alternate usage
         
     | 
| 
      
 147 
     | 
    
         
            +
              parser = Radius::Parser.new(context)
         
     | 
| 
      
 148 
     | 
    
         
            +
              puts parser.parse(receipt) # compiles and outputs expanded template
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
              # another alternate
         
     | 
| 
      
 151 
     | 
    
         
            +
              puts Radius.parse(receipt, context)
         
     | 
    
        data/QUICKSTART
    ADDED
    
    | 
         @@ -0,0 +1,98 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            =Quick Start
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Before you can parse a template with Radius you need to create a Context object which defines
         
     | 
| 
      
 4 
     | 
    
         
            +
            the tags that will be used in the template. This is pretty simple:
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              require 'radius'
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              class MyContext < Radius::Context
         
     | 
| 
      
 9 
     | 
    
         
            +
                def hello(attr)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  "Hello #{attr['name'] || 'World'}!"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            Once you have defined a context you can create a Parser and parse to your heart's content:
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              parser = Radius::Parser.new(MyContext.new)
         
     | 
| 
      
 17 
     | 
    
         
            +
              puts parser.parse('<p><radius:hello /></p>')
         
     | 
| 
      
 18 
     | 
    
         
            +
              puts parser.parse('<p><radius:hello name="John" /></p>')
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            This will output:
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              <p>Hello World!</p>
         
     | 
| 
      
 23 
     | 
    
         
            +
              <p>Hello John!</p>
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            Note how you can pass attributes from the template to the context using the attributes hash
         
     | 
| 
      
 26 
     | 
    
         
            +
            (which is passed in as the first parameter.). Above the first tag that was parsed didn't have
         
     | 
| 
      
 27 
     | 
    
         
            +
            a name attribute so the code in the +hello+ method uses "World" instead. The second time the
         
     | 
| 
      
 28 
     | 
    
         
            +
            tag is parsed the name attribute is set to "John" which is used to create the string "Hello
         
     | 
| 
      
 29 
     | 
    
         
            +
            John!".
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            Radius also allows you to define "container" tags. That is, tags that contain content and
         
     | 
| 
      
 32 
     | 
    
         
            +
            that may optionally manipulate it in some way. For example, if you have RedCloth installed
         
     | 
| 
      
 33 
     | 
    
         
            +
            you could define another tag to parse and create Textile output:
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              require 'redcloth'
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
              class MyContext < Radius::Context
         
     | 
| 
      
 38 
     | 
    
         
            +
                def textile(attr)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  contents = yield
         
     | 
| 
      
 40 
     | 
    
         
            +
                  RedCloth.new(contents).to_html
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            With the code above your parser can easily handle Textile:
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              parser.parse('<radius:textile>h1. Hello **World**!</radius:textile>')
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            This will output:
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              <h1>Hello <strong>World</strong>!</h1>
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            But wait!--it gets better. Because container tags can manipulate what they contain you can use
         
     | 
| 
      
 53 
     | 
    
         
            +
            them to iterate over collections:
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              class ThreeStoogesContext < Radius::Context
         
     | 
| 
      
 56 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @prefix = 'ts'
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                def stooge(attr)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  content = ''
         
     | 
| 
      
 61 
     | 
    
         
            +
                  ["Larry", "Moe", "Curly"].each do |name|
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @name = name
         
     | 
| 
      
 63 
     | 
    
         
            +
                    content << yield
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  content
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
                def name(attr)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @name
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
              parser = Radius::Parser.new(ThreeStoogesContext.new)
         
     | 
| 
      
 73 
     | 
    
         
            +
              
         
     | 
| 
      
 74 
     | 
    
         
            +
              template = <<-TEMPLATE
         
     | 
| 
      
 75 
     | 
    
         
            +
              <ul>
         
     | 
| 
      
 76 
     | 
    
         
            +
              <ts:stooge>
         
     | 
| 
      
 77 
     | 
    
         
            +
              <li><ts:name /></li>
         
     | 
| 
      
 78 
     | 
    
         
            +
              </ts:stooge>
         
     | 
| 
      
 79 
     | 
    
         
            +
              </ul>
         
     | 
| 
      
 80 
     | 
    
         
            +
              TEMPLATE
         
     | 
| 
      
 81 
     | 
    
         
            +
              
         
     | 
| 
      
 82 
     | 
    
         
            +
              puts parser.parse(template)
         
     | 
| 
      
 83 
     | 
    
         
            +
              
         
     | 
| 
      
 84 
     | 
    
         
            +
            This will output:
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
              <ul>
         
     | 
| 
      
 87 
     | 
    
         
            +
              
         
     | 
| 
      
 88 
     | 
    
         
            +
                <li>Larry</li>
         
     | 
| 
      
 89 
     | 
    
         
            +
              
         
     | 
| 
      
 90 
     | 
    
         
            +
                <li>Moe</li>
         
     | 
| 
      
 91 
     | 
    
         
            +
              
         
     | 
| 
      
 92 
     | 
    
         
            +
                <li>Curly</li>
         
     | 
| 
      
 93 
     | 
    
         
            +
              
         
     | 
| 
      
 94 
     | 
    
         
            +
              </ul>
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            The above code also illustrates how you can set the prefix instance variable to control the
         
     | 
| 
      
 97 
     | 
    
         
            +
            string that prefixes Radius tags. By setting the prefix to "ts" our tags must begin with "ts"
         
     | 
| 
      
 98 
     | 
    
         
            +
            instead of "radius" like they did in the other examples.
         
     | 
    
        data/README
    ADDED
    
    | 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            = Radius -- Powerful Tag-Based Templates
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Radius is a small, but powerful template language for Ruby inspired by the template languages
         
     | 
| 
      
 4 
     | 
    
         
            +
            used in MovableType <http://www.movabletype.org> and TextPattern <http://www.textpattern.com>.
         
     | 
| 
      
 5 
     | 
    
         
            +
            It uses tags similar to HTML, but can be used to generate any form of plain text (XML, e-mail,
         
     | 
| 
      
 6 
     | 
    
         
            +
            etc...).
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            == Download
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The latest version of Radius can be found on RubyForge:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            http://rubyforge.org/projects/radius/
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            == Installation
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            It is recommended that you install Radius using the RubyGems packaging system:
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              % gem install --remote radius
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            You can also install Radius by copying radius.rb into the Ruby load path.
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            == License
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            Radius is free software and may be redistributed under the same terms and Ruby itself. For
         
     | 
| 
      
 27 
     | 
    
         
            +
            more details, see the readme file in the Ruby distribution.
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            == Quick Start
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            To get up and running fast with Radius read:
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            link:files/QUICKSTART.html
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            == A Call to Action
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            Radius is still very much in the development stages. Take a look at the roadmap to see where
         
     | 
| 
      
 40 
     | 
    
         
            +
            we want to go:
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            link:files/ROADMAP.html
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            If you are a smart developer with a passion for excellence, now is the time to jump on board.
         
     | 
| 
      
 45 
     | 
    
         
            +
            Contact me and we'll talk. :)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            --
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            John Long :: http://wiseheartdesign.com
         
     | 
    
        data/ROADMAP
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            = Roadmap
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This is a prioritized roadmap for future releases:
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            1. Clean up the current code base.
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            2. Add support for multi-level contexts: tags should be able to be
         
     | 
| 
      
 8 
     | 
    
         
            +
               defined to only be valid within other sets of tags.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            3. Create a simple DSL for defining contexts. I had done some thinking
         
     | 
| 
      
 11 
     | 
    
         
            +
               about this in the past. This thread on Ruby-Talk defined part of it:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
               http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/127640/
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
               Update: See link:files/DSL-SPEC.html for a fuller explanation of how
         
     | 
| 
      
 16 
     | 
    
         
            +
               the DSL should behave.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            4. Optimize for speed. Incorporate strscan?
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rake/testtask'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rake/rdoctask'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rake/gempackagetask'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            task :default => :test
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Rake::TestTask.new do |t| 
         
     | 
| 
      
 9 
     | 
    
         
            +
              t.pattern = 'test/**/*_test.rb'
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Rake::RDocTask.new do |rd|
         
     | 
| 
      
 13 
     | 
    
         
            +
              rd.title = 'Radius -- Powerful Tag-Based Templates'
         
     | 
| 
      
 14 
     | 
    
         
            +
              rd.main = "README"
         
     | 
| 
      
 15 
     | 
    
         
            +
              rd.rdoc_files.include("README", "QUICKSTART", "ROADMAP", "DSL-SPEC", "lib/**/*.rb")
         
     | 
| 
      
 16 
     | 
    
         
            +
              rd.rdoc_dir = 'doc'
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            spec = Gem::Specification.new do |s|
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.platform = Gem::Platform::RUBY
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.summary = "Powerful tag-based template system."
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.name = 'radius'
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.version = '0.0.1'
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.requirements << 'none'
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.require_path = 'lib'
         
     | 
| 
      
 26 
     | 
    
         
            +
              s.autorequire = 'radius'
         
     | 
| 
      
 27 
     | 
    
         
            +
              s.has_rdoc = true
         
     | 
| 
      
 28 
     | 
    
         
            +
              s.rdoc_options << '--title' << 'Radius -- Powerful Tag-Based Templates' <<
         
     | 
| 
      
 29 
     | 
    
         
            +
                                '--main' << 'README' <<
         
     | 
| 
      
 30 
     | 
    
         
            +
                                '--line-numbers' << 'ROADMAP' <<
         
     | 
| 
      
 31 
     | 
    
         
            +
                                'QUICKSTART' << 'DSL-SPEC' << 'README'
         
     | 
| 
      
 32 
     | 
    
         
            +
              files = FileList['**/*']
         
     | 
| 
      
 33 
     | 
    
         
            +
              files.exclude 'doc'
         
     | 
| 
      
 34 
     | 
    
         
            +
              s.files = files.to_a
         
     | 
| 
      
 35 
     | 
    
         
            +
              s.description = "Radius is a small, but powerful tag-based template language inspired\nby the template languages used in MovableType and TextPattern."
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            Rake::GemPackageTask.new(spec) do |pkg|
         
     | 
| 
      
 39 
     | 
    
         
            +
              pkg.need_zip = true
         
     | 
| 
      
 40 
     | 
    
         
            +
              pkg.need_tar = true
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/radius.rb
    ADDED
    
    | 
         @@ -0,0 +1,126 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Radius
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ParseError < StandardError # :nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
              end
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
              class MissingEndTagError < ParseError # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(tag_name)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  super("end tag not found for start tag `#{tag_name}'")
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              # An abstract class for creating a Context. A context defines the tags that
         
     | 
| 
      
 13 
     | 
    
         
            +
              # are available for use in a template.
         
     | 
| 
      
 14 
     | 
    
         
            +
              #
         
     | 
| 
      
 15 
     | 
    
         
            +
              class Context
         
     | 
| 
      
 16 
     | 
    
         
            +
                # The prefix attribute controls the string of text that is helps the parser
         
     | 
| 
      
 17 
     | 
    
         
            +
                # identify template tags. By default this attribute is set to "radius", but
         
     | 
| 
      
 18 
     | 
    
         
            +
                # you may want to override this for your own contexts.
         
     | 
| 
      
 19 
     | 
    
         
            +
                attr_accessor :prefix
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                # Creates a new Context object.
         
     | 
| 
      
 22 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @prefix = 'radius'
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
              class Tag # :nodoc:
         
     | 
| 
      
 28 
     | 
    
         
            +
                def initialize(&b)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @block = b
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                def on_parse(&b)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @block = b
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @block.call(self)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              class ContainerTag < Tag # :nodoc:
         
     | 
| 
      
 40 
     | 
    
         
            +
                attr_accessor :name, :attributes, :contents
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                def initialize(name="", attributes={}, contents=[], &b)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @name, @attributes, @contents = name, attributes, contents
         
     | 
| 
      
 44 
     | 
    
         
            +
                  super(&b)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              #
         
     | 
| 
      
 49 
     | 
    
         
            +
              # The Radius parser. Initialize a parser with the Context object that defines
         
     | 
| 
      
 50 
     | 
    
         
            +
              # how tags should be expanded.
         
     | 
| 
      
 51 
     | 
    
         
            +
              #
         
     | 
| 
      
 52 
     | 
    
         
            +
              class Parser
         
     | 
| 
      
 53 
     | 
    
         
            +
                # The Context object used to expand template tags.
         
     | 
| 
      
 54 
     | 
    
         
            +
                attr_accessor :context
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                # Creates a new parser object initialized with a context.
         
     | 
| 
      
 57 
     | 
    
         
            +
                def initialize(context = Context.new)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @context = context
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                # Parse string for tags, expand them, and return the result.
         
     | 
| 
      
 62 
     | 
    
         
            +
                def parse(string)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @stack = [ContainerTag.new { |t| t.contents.to_s }]
         
     | 
| 
      
 64 
     | 
    
         
            +
                  pre_parse(string)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @stack.last.to_s
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
                
         
     | 
| 
      
 68 
     | 
    
         
            +
                def pre_parse(text) # :nodoc:
         
     | 
| 
      
 69 
     | 
    
         
            +
                  re = %r{<#{@context.prefix}:(\w+?)(?:\s+?([^/>]*?)|)>|</#{@context.prefix}:(\w+?)\s*?>}
         
     | 
| 
      
 70 
     | 
    
         
            +
                  if md = re.match(text)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    start_tag, attr, end_tag = $1, $2, $3
         
     | 
| 
      
 72 
     | 
    
         
            +
                    @stack.last.contents << Tag.new { parse_individual(md.pre_match) }
         
     | 
| 
      
 73 
     | 
    
         
            +
                    remaining = md.post_match
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if start_tag
         
     | 
| 
      
 75 
     | 
    
         
            +
                      parse_start_tag(start_tag, attr, remaining)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    else
         
     | 
| 
      
 77 
     | 
    
         
            +
                      parse_end_tag(end_tag, remaining)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
                  else
         
     | 
| 
      
 80 
     | 
    
         
            +
                    if @stack.length == 1
         
     | 
| 
      
 81 
     | 
    
         
            +
                      @stack.last.contents << Tag.new { parse_individual(text) }
         
     | 
| 
      
 82 
     | 
    
         
            +
                    else
         
     | 
| 
      
 83 
     | 
    
         
            +
                      raise MissingEndTagError.new(@stack.last.name)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
                
         
     | 
| 
      
 88 
     | 
    
         
            +
                def parse_start_tag(start_tag, attr, remaining) # :nodoc:
         
     | 
| 
      
 89 
     | 
    
         
            +
                  @stack.push(ContainerTag.new(start_tag, parse_attributes(attr)))
         
     | 
| 
      
 90 
     | 
    
         
            +
                  pre_parse(remaining)
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def parse_end_tag(end_tag, remaining) # :nodoc:
         
     | 
| 
      
 94 
     | 
    
         
            +
                  popped = @stack.pop
         
     | 
| 
      
 95 
     | 
    
         
            +
                  if popped.name == end_tag
         
     | 
| 
      
 96 
     | 
    
         
            +
                    popped.on_parse { |t| @context.send(popped.name, popped.attributes) { t.contents.to_s } }
         
     | 
| 
      
 97 
     | 
    
         
            +
                    tag = @stack.last
         
     | 
| 
      
 98 
     | 
    
         
            +
                    tag.contents << popped
         
     | 
| 
      
 99 
     | 
    
         
            +
                    pre_parse(remaining)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  else
         
     | 
| 
      
 101 
     | 
    
         
            +
                    raise MissingEndTagError.new(popped.name)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
                
         
     | 
| 
      
 105 
     | 
    
         
            +
                def parse_individual(text) # :nodoc:
         
     | 
| 
      
 106 
     | 
    
         
            +
                  re = /<#{@context.prefix}:(\w+?)\s+?(.*?)\s*?\/>/
         
     | 
| 
      
 107 
     | 
    
         
            +
                  if md = re.match(text)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    attr = parse_attributes($2)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    replace = @context.send($1, attr)
         
     | 
| 
      
 110 
     | 
    
         
            +
                    md.pre_match + replace + parse_individual(md.post_match)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  else
         
     | 
| 
      
 112 
     | 
    
         
            +
                    text || ''
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
                
         
     | 
| 
      
 116 
     | 
    
         
            +
                def parse_attributes(text) # :nodoc:
         
     | 
| 
      
 117 
     | 
    
         
            +
                  attr = {}
         
     | 
| 
      
 118 
     | 
    
         
            +
                  re = /(\w+?)\s*=\s*('|")(.*?)\2/
         
     | 
| 
      
 119 
     | 
    
         
            +
                  while md = re.match(text)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    attr[$1] = $3
         
     | 
| 
      
 121 
     | 
    
         
            +
                    text = md.post_match
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  attr
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
              end
         
     | 
| 
      
 126 
     | 
    
         
            +
            end
         
     | 
    
        data/test/radius_test.rb
    ADDED
    
    | 
         @@ -0,0 +1,122 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'radius'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class ContextTest < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
              def test_initialize
         
     | 
| 
      
 6 
     | 
    
         
            +
                c = Radius::Context.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                assert_equal 'radius', c.prefix
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            class RadiusTest < Test::Unit::TestCase
         
     | 
| 
      
 12 
     | 
    
         
            +
              class TestContext < Radius::Context
         
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @prefix = "test"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @items = ["Larry", "Moe", "Curly"]
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                def echo(attr)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  attr["text"]
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                def add(attr)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  (attr["param1"].to_i + attr["param2"].to_i).to_s
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                
         
     | 
| 
      
 26 
     | 
    
         
            +
                def reverse(attr)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  yield.reverse
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def capitalize(attr)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  yield.upcase
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                def count(attr)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  case
         
     | 
| 
      
 36 
     | 
    
         
            +
                  when attr["set"]
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @count = attr["set"].to_i
         
     | 
| 
      
 38 
     | 
    
         
            +
                    ""
         
     | 
| 
      
 39 
     | 
    
         
            +
                  when attr["inc"] == "true"
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @count = (@count || 0) + 1
         
     | 
| 
      
 41 
     | 
    
         
            +
                    ""
         
     | 
| 
      
 42 
     | 
    
         
            +
                  else
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @count.to_s       
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                def loop(attr)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  t = attr["times"].to_i
         
     | 
| 
      
 49 
     | 
    
         
            +
                  result = ""
         
     | 
| 
      
 50 
     | 
    
         
            +
                  t.times { result += yield }
         
     | 
| 
      
 51 
     | 
    
         
            +
                  result
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
                
         
     | 
| 
      
 54 
     | 
    
         
            +
                def each_item(attr)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  result = []
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @items.each { |@item| result << yield }
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @item = nil
         
     | 
| 
      
 58 
     | 
    
         
            +
                  result.join(attr["between"] || "")
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                def item(attr)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @item
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 67 
     | 
    
         
            +
                @t = Radius::Parser.new(TestContext.new )
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
              
         
     | 
| 
      
 70 
     | 
    
         
            +
              def test_parse_individual
         
     | 
| 
      
 71 
     | 
    
         
            +
                r = @t.parse_individual(%{<<test:echo text="hello world!" />>})
         
     | 
| 
      
 72 
     | 
    
         
            +
                assert_equal("<hello world!>", r)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                r = @t.parse_individual(%{<test:add param1="1" param2='2'/>})
         
     | 
| 
      
 75 
     | 
    
         
            +
                assert_equal("3", r)
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                r = @t.parse_individual(%{a <test:echo text="3 + 1 =" /> <test:add param1="3" param2="1"/> b})
         
     | 
| 
      
 78 
     | 
    
         
            +
                assert_equal("a 3 + 1 = 4 b", r)
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
              
         
     | 
| 
      
 81 
     | 
    
         
            +
              def test_parse_attributes
         
     | 
| 
      
 82 
     | 
    
         
            +
                r = @t.parse_attributes(%{ a="1" b='2'c="3"d="'" })
         
     | 
| 
      
 83 
     | 
    
         
            +
                assert_equal({"a" => "1", "b" => "2", "c" => "3", "d" => "'"}, r)
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
              
         
     | 
| 
      
 86 
     | 
    
         
            +
              def test_parse
         
     | 
| 
      
 87 
     | 
    
         
            +
                r = @t.parse(%{<<test:echo text="hello world!" />>})
         
     | 
| 
      
 88 
     | 
    
         
            +
                assert_equal("<hello world!>", r)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                r = @t.parse("<test:reverse>test</test:reverse>")
         
     | 
| 
      
 91 
     | 
    
         
            +
                assert_equal("test".reverse, r)
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                r = @t.parse("<test:reverse>test</test:reverse> <test:capitalize>test</test:capitalize>")
         
     | 
| 
      
 94 
     | 
    
         
            +
                assert_equal("tset TEST", r)
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
                r = @t.parse("<test:echo text='hello world!' /> cool: <test:reverse>a <test:capitalize>test</test:capitalize> b</test:reverse> !")
         
     | 
| 
      
 97 
     | 
    
         
            +
                assert_equal("hello world! cool: b TSET a !", r)
         
     | 
| 
      
 98 
     | 
    
         
            +
                
         
     | 
| 
      
 99 
     | 
    
         
            +
                r = @t.parse("<test:reverse><test:echo text='hello world!' /></test:reverse>")
         
     | 
| 
      
 100 
     | 
    
         
            +
                assert_equal("!dlrow olleh", r)
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                r = @t.parse("<test:reverse><test:capitalize>test</test:capitalize> <test:echo text='hello world!' /></test:reverse>")
         
     | 
| 
      
 103 
     | 
    
         
            +
                assert_equal("!dlrow olleh TSET", r)
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                r = @t.parse("<test:reverse>12<test:capitalize>at</test:capitalize>34</test:reverse>")
         
     | 
| 
      
 106 
     | 
    
         
            +
                assert_equal("43TA21", r)
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
              def test_parse__loop
         
     | 
| 
      
 109 
     | 
    
         
            +
                r = @t.parse(%{<test:count set="0" /><test:loop times="5"><test:count inc="true" /><test:count /></test:loop>})
         
     | 
| 
      
 110 
     | 
    
         
            +
                assert_equal("12345", r)
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                r = @t.parse(%{Three Stooges: <test:each_item between=", ">"<test:item />"</test:each_item>})
         
     | 
| 
      
 113 
     | 
    
         
            +
                assert_equal(%{Three Stooges: "Larry", "Moe", "Curly"}, r)
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
              
         
     | 
| 
      
 116 
     | 
    
         
            +
              def test_parse__fail_on_no_end_tag
         
     | 
| 
      
 117 
     | 
    
         
            +
                assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse>") }
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
              def test_parse__fail_on_no_end_tag_2
         
     | 
| 
      
 120 
     | 
    
         
            +
                assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse><test:capitalize></test:reverse>") }
         
     | 
| 
      
 121 
     | 
    
         
            +
              end
         
     | 
| 
      
 122 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            rubygems_version: 0.8.10
         
     | 
| 
      
 3 
     | 
    
         
            +
            specification_version: 1
         
     | 
| 
      
 4 
     | 
    
         
            +
            name: radius
         
     | 
| 
      
 5 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 6 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 7 
     | 
    
         
            +
            date: 2006-01-21
         
     | 
| 
      
 8 
     | 
    
         
            +
            summary: Powerful tag-based template system.
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 10 
     | 
    
         
            +
              - lib
         
     | 
| 
      
 11 
     | 
    
         
            +
            email: 
         
     | 
| 
      
 12 
     | 
    
         
            +
            homepage: 
         
     | 
| 
      
 13 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            description: "Radius is a small, but powerful tag-based template language inspired by the
         
     | 
| 
      
 15 
     | 
    
         
            +
              template languages used in MovableType and TextPattern."
         
     | 
| 
      
 16 
     | 
    
         
            +
            autorequire: radius
         
     | 
| 
      
 17 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 18 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 19 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 20 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Version::Requirement 
         
     | 
| 
      
 21 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 22 
     | 
    
         
            +
                - 
         
     | 
| 
      
 23 
     | 
    
         
            +
                  - ">"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 25 
     | 
    
         
            +
                    version: 0.0.0
         
     | 
| 
      
 26 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 27 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 28 
     | 
    
         
            +
            authors: []
         
     | 
| 
      
 29 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 30 
     | 
    
         
            +
              - DSL-SPEC
         
     | 
| 
      
 31 
     | 
    
         
            +
              - lib
         
     | 
| 
      
 32 
     | 
    
         
            +
              - QUICKSTART
         
     | 
| 
      
 33 
     | 
    
         
            +
              - Rakefile
         
     | 
| 
      
 34 
     | 
    
         
            +
              - README
         
     | 
| 
      
 35 
     | 
    
         
            +
              - ROADMAP
         
     | 
| 
      
 36 
     | 
    
         
            +
              - test
         
     | 
| 
      
 37 
     | 
    
         
            +
              - lib/radius.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
              - test/radius_test.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 40 
     | 
    
         
            +
            rdoc_options: 
         
     | 
| 
      
 41 
     | 
    
         
            +
              - "--title"
         
     | 
| 
      
 42 
     | 
    
         
            +
              - "Radius -- Powerful Tag-Based Templates"
         
     | 
| 
      
 43 
     | 
    
         
            +
              - "--main"
         
     | 
| 
      
 44 
     | 
    
         
            +
              - README
         
     | 
| 
      
 45 
     | 
    
         
            +
              - "--line-numbers"
         
     | 
| 
      
 46 
     | 
    
         
            +
              - ROADMAP
         
     | 
| 
      
 47 
     | 
    
         
            +
              - QUICKSTART
         
     | 
| 
      
 48 
     | 
    
         
            +
              - DSL-SPEC
         
     | 
| 
      
 49 
     | 
    
         
            +
              - README
         
     | 
| 
      
 50 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 51 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 52 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 53 
     | 
    
         
            +
            requirements: 
         
     | 
| 
      
 54 
     | 
    
         
            +
              - none
         
     | 
| 
      
 55 
     | 
    
         
            +
            dependencies: []
         
     |