h2o 0.2 → 0.3.0
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/.autotest +11 -0
- data/.gitignore +1 -0
- data/.project +17 -0
- data/README.md +0 -0
- data/Rakefile +32 -0
- data/TODO.md +5 -0
- data/VERSION +1 -0
- data/benchmark/parser.rb +57 -0
- data/benchmark/source.html +4212 -0
- data/example/h2o/base.html +0 -1
- data/example/h2o/index.html +10 -0
- data/example/h2o/layout.html +11 -0
- data/example/request.html +0 -0
- data/example/server +1 -1
- data/h2o.gemspec +101 -41
- data/init.rb +1 -0
- data/lib/.DS_Store +0 -0
- data/lib/core_ext/object.rb +0 -0
- data/lib/h2o.rb +29 -39
- data/lib/h2o/constants.rb +2 -2
- data/lib/h2o/context.rb +3 -10
- data/lib/h2o/error.rb +9 -0
- data/lib/h2o/filters/default.rb +0 -0
- data/lib/h2o/nodes.rb +5 -1
- data/lib/h2o/tags.rb +1 -6
- data/lib/h2o/tags/block.rb +0 -30
- data/lib/h2o/tags/extends.rb +33 -0
- data/lib/h2o/tags/for.rb +7 -6
- data/lib/h2o/tags/with.rb +0 -0
- data/lib/h2o/template.rb +33 -0
- data/spec/fixtures/_partial.html +0 -0
- data/spec/fixtures/a.html +1 -0
- data/spec/fixtures/b.html +0 -0
- data/spec/fixtures/deep/folder/c.html +0 -0
- data/spec/h2o/context_spec.rb +134 -0
- data/spec/h2o/default.html +93 -0
- data/spec/h2o/file_loader_spec.rb +35 -0
- data/spec/h2o/filters_spec.rb +57 -0
- data/spec/h2o/parser_spec.rb +78 -0
- data/spec/h2o/tags/block_spec.rb +26 -0
- data/spec/h2o/tags/for_spec.rb +65 -0
- data/spec/h2o/tags/if_spec.rb +58 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +24 -0
- metadata +81 -27
- data/lib/h2o/errors.rb +0 -7
- data/lib/h2o/tags/recurse.rb +0 -55
    
        data/lib/h2o/tags/with.rb
    CHANGED
    
    | 
            File without changes
         | 
    
        data/lib/h2o/template.rb
    ADDED
    
    | @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module H2o
         | 
| 2 | 
            +
              class Template
         | 
| 3 | 
            +
                attr_reader :context
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def initialize (file, env = {})
         | 
| 6 | 
            +
                  @file = file
         | 
| 7 | 
            +
                  @nodelist = Template.load(@file, env)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                def render (context = {})
         | 
| 11 | 
            +
                  @context = Context.new(context)
         | 
| 12 | 
            +
                  output_stream = []
         | 
| 13 | 
            +
                  @nodelist.render(@context, output_stream)
         | 
| 14 | 
            +
                  output_stream.join
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def self.parse source, env = {}
         | 
| 18 | 
            +
                  parser = Parser.new(source, false, env)
         | 
| 19 | 
            +
                  parsed = parser.parse
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                def self.load file, env = {}
         | 
| 23 | 
            +
                  unless H2o.loader
         | 
| 24 | 
            +
                    env[:searchpath] ||= File.expand_path('../', file)
         | 
| 25 | 
            +
                    H2o.loader = H2o::FileLoader.new(env[:searchpath])
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  source = H2o.loader.read(file)
         | 
| 28 | 
            +
                  
         | 
| 29 | 
            +
                  parser = Parser.new(source, file, env)
         | 
| 30 | 
            +
                  parser.parse
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| 
            File without changes
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            {{ hello }}
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| @@ -0,0 +1,134 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class User
         | 
| 4 | 
            +
              h2o_expose :name, :age
         | 
| 5 | 
            +
              attr_accessor :name, :age
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def initialize name, age
         | 
| 8 | 
            +
                @name, @age = name, age
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              def to_h2o
         | 
| 12 | 
            +
                {
         | 
| 13 | 
            +
                  :name => self.name,
         | 
| 14 | 
            +
                  :age => self.age
         | 
| 15 | 
            +
                }
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            describe H2o::Context do
         | 
| 20 | 
            +
              before do
         | 
| 21 | 
            +
                @scope = {
         | 
| 22 | 
            +
                  :person => {'name' => 'peter', 'age' => 18},
         | 
| 23 | 
            +
                  :weather => 'sunny and warm',
         | 
| 24 | 
            +
                  :items => ['apple', 'orange', 'pear'],
         | 
| 25 | 
            +
                  :user => User.new('taylor', 19)
         | 
| 26 | 
            +
                }
         | 
| 27 | 
            +
                @context = H2o::Context.new(@scope)    
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
              describe "Resolve name" do
         | 
| 32 | 
            +
                it "should resolve name with either string or symbol" do
         | 
| 33 | 
            +
                  @context.resolve(:person).should == @scope[:person]
         | 
| 34 | 
            +
                  @context.resolve(:person).should == @scope[:person]
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              
         | 
| 37 | 
            +
                it "should return nil for non existing name context" do
         | 
| 38 | 
            +
                  @context.resolve(:something).should be_nil
         | 
| 39 | 
            +
                  @context.resolve(:where_is_that).should be_nil
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                it "should be able to resolve local variables" do
         | 
| 43 | 
            +
                  @context.resolve(:person).should_not be_nil
         | 
| 44 | 
            +
                  @context.resolve(:'person.name').should == 'peter'
         | 
| 45 | 
            +
                  @context.resolve(:'person.age').should == 18
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
                it "should resolve array index using (dot)" do
         | 
| 49 | 
            +
                  @context.resolve(:'items.0').should == 'apple'
         | 
| 50 | 
            +
                  @context.resolve(:'items.1').should == 'orange'
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              
         | 
| 53 | 
            +
                it "should resolve array methods such as length, count ..." do
         | 
| 54 | 
            +
                  @context.resolve(:'items.length').should == @scope[:items].length
         | 
| 55 | 
            +
                  @context.resolve(:'items.first').should == 'apple'
         | 
| 56 | 
            +
                  @context.resolve(:'items.last').should == 'pear'
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              
         | 
| 59 | 
            +
                it "should resolve object methods" do
         | 
| 60 | 
            +
                
         | 
| 61 | 
            +
                  @context.resolve(:'user.name').should == 'taylor'
         | 
| 62 | 
            +
                  @context.resolve(:'user.age').should == 19
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              
         | 
| 66 | 
            +
                it "should resolve proc object and cache inline" do
         | 
| 67 | 
            +
                  @context.stack do
         | 
| 68 | 
            +
                    @context['procs'] = {
         | 
| 69 | 
            +
                      :test => lambda{ "testing" },
         | 
| 70 | 
            +
                      :generation => lambda{ Time.now }
         | 
| 71 | 
            +
                    }
         | 
| 72 | 
            +
                  
         | 
| 73 | 
            +
                    # Resolve a proc object
         | 
| 74 | 
            +
                    @context.resolve(:'procs.test').should == 'testing'
         | 
| 75 | 
            +
                    result = @context.resolve(:'procs.generation')
         | 
| 76 | 
            +
                    result.should be_a(Time)
         | 
| 77 | 
            +
                
         | 
| 78 | 
            +
                    # Cached inline
         | 
| 79 | 
            +
                    @context.resolve(:'procs.generation').usec.should == result.usec
         | 
| 80 | 
            +
                    @context.resolve(:'procs.generation').usec.should == result.usec
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              describe "Local lookup" do      
         | 
| 86 | 
            +
                it "should allow local variable lookup with using symbol" do
         | 
| 87 | 
            +
                  @context[:person].should be_kind_of(Hash)
         | 
| 88 | 
            +
                  @context[:weather].should =~ /sunny/
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                it "should able to set new name and value into context" do
         | 
| 93 | 
            +
                  @context[:city] = 'five dock'
         | 
| 94 | 
            +
                  @context[:state] = 'nsw'
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  @context[:city].should == 'five dock'
         | 
| 97 | 
            +
                  @context[:state].should == 'nsw'
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              describe "Context stack" do
         | 
| 102 | 
            +
                it "should allow pushing and popping local context layer in the stack" do
         | 
| 103 | 
            +
                  @context.push
         | 
| 104 | 
            +
                  @context[:ass] = 'hole'
         | 
| 105 | 
            +
                  @context[:ass].should == 'hole'
         | 
| 106 | 
            +
                  @context.pop
         | 
| 107 | 
            +
                
         | 
| 108 | 
            +
                  @context.push(:bowling => 'on sunday')
         | 
| 109 | 
            +
                  @context[:bowling].should_not be_nil
         | 
| 110 | 
            +
                  @context.pop    
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
              
         | 
| 113 | 
            +
                it "should allow using stack method to ease push/pop and remain in local context" do
         | 
| 114 | 
            +
                  @context.stack do
         | 
| 115 | 
            +
                    @context[:name] = 'a'
         | 
| 116 | 
            +
              
         | 
| 117 | 
            +
                    @context.stack do
         | 
| 118 | 
            +
                      @context[:name] = 'b'
         | 
| 119 | 
            +
                
         | 
| 120 | 
            +
                      @context.stack do
         | 
| 121 | 
            +
                        @context[:age] = 19
         | 
| 122 | 
            +
                        @context[:name] = 'c'
         | 
| 123 | 
            +
                        @context.resolve(:'name').should == 'c'
         | 
| 124 | 
            +
                      end
         | 
| 125 | 
            +
                    
         | 
| 126 | 
            +
                      @context.resolve(:'age').should == nil
         | 
| 127 | 
            +
                      @context.resolve(:'name').should == 'b'
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                    @context.resolve(:'name') == 'a'
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
            end
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
         | 
| 2 | 
            +
            <html xmlns="http://www.w3.org/1999/xhtml">
         | 
| 3 | 
            +
            <head>
         | 
| 4 | 
            +
              <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type" />
         | 
| 5 | 
            +
              <title>{{ site.title | capitalize }} - Design, Development and New Media Marketing</title>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            {{ 'stylesheets/layout.css'| css_tag }}
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                <!--[if IE]>
         | 
| 10 | 
            +
            	<style type="text/css">
         | 
| 11 | 
            +
            		@import "ie_layout.css";
         | 
| 12 | 
            +
            	</style>
         | 
| 13 | 
            +
            	<![endif]-->
         | 
| 14 | 
            +
            </head>
         | 
| 15 | 
            +
            <body>
         | 
| 16 | 
            +
            <div id="centered">
         | 
| 17 | 
            +
            	<div id="top">
         | 
| 18 | 
            +
            		<!-- Left column -->
         | 
| 19 | 
            +
            		<div id="left">
         | 
| 20 | 
            +
            			<!-- Logo -->
         | 
| 21 | 
            +
            			<a href="#" id="logo">jnCentral.com</a>
         | 
| 22 | 
            +
            			<!-- Mini navigation -->
         | 
| 23 | 
            +
            			<ul id="mininav">
         | 
| 24 | 
            +
             | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
                  {% if page.children %}
         | 
| 28 | 
            +
                    <li><a href="#" class="active"><span class="homepage">Homepage</span></a></li>
         | 
| 29 | 
            +
                    <ul>
         | 
| 30 | 
            +
                    {% for page in page.children %}
         | 
| 31 | 
            +
                      <li>{{ page.title | links_to page.url }}</li>
         | 
| 32 | 
            +
                    {% endfor %}
         | 
| 33 | 
            +
                    </ul>
         | 
| 34 | 
            +
                  {% endif %}
         | 
| 35 | 
            +
            				
         | 
| 36 | 
            +
            				<li><a href="#"><span class="products">View our products catalog</span></a></li>
         | 
| 37 | 
            +
            				<li><a href="#"><span class="services">Check out our wide range of services</span></a></li>
         | 
| 38 | 
            +
            				<li><a href="#"><span class="about">Find out about our company</span></a></li>
         | 
| 39 | 
            +
            				<li><a href="#"><span class="contact">Get in contact with us</span></a></li>
         | 
| 40 | 
            +
            			</ul>
         | 
| 41 | 
            +
            			<!-- Gallery -->
         | 
| 42 | 
            +
            			<div id="gallery">
         | 
| 43 | 
            +
            				<div>
         | 
| 44 | 
            +
            					<ul>
         | 
| 45 | 
            +
            						<li><a href="#"><img src="images/img1.gif" alt="" /></a></li>
         | 
| 46 | 
            +
            						<li><a href="#"><img src="images/img2.gif" alt="" /></a></li>
         | 
| 47 | 
            +
            						<li><a href="#"><img src="images/img3.gif" alt="" /></a></li>
         | 
| 48 | 
            +
            					</ul>
         | 
| 49 | 
            +
            					<ul>
         | 
| 50 | 
            +
            						<li><a href="#"><img src="images/img5.gif" alt="" /></a></li>
         | 
| 51 | 
            +
            						<li><a href="#"><img src="images/img6.gif" alt="" /></a></li>
         | 
| 52 | 
            +
            						<li><a href="#"><img src="images/img7.gif" alt="" /></a></li>
         | 
| 53 | 
            +
            					</ul>
         | 
| 54 | 
            +
            				</div>
         | 
| 55 | 
            +
            				<img src="{{'images/mypics.gif'| base_url}}" alt="" class="floatright" />
         | 
| 56 | 
            +
            			</div>
         | 
| 57 | 
            +
            			<!-- Latest News -->
         | 
| 58 | 
            +
            			<div id="news">
         | 
| 59 | 
            +
            				<h2 id="latestnews">Latest News</h2>
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  {% for article in site.latest_articles %}
         | 
| 62 | 
            +
                    {{ article.title| links_to article.url }}  <span class="date">{{article.published_at}}</span><br />
         | 
| 63 | 
            +
            <p>{{ article.excerpt}}</p>
         | 
| 64 | 
            +
                  {% endfor %}
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            				<br />
         | 
| 67 | 
            +
            			</div>
         | 
| 68 | 
            +
            		</div>
         | 
| 69 | 
            +
            		<!-- Right column -->
         | 
| 70 | 
            +
            		<div id="right">
         | 
| 71 | 
            +
            			<!-- Main navigation -->
         | 
| 72 | 
            +
            			<ul id="navigation">
         | 
| 73 | 
            +
            				<li><a href="#"><span>Home</span></a></li>
         | 
| 74 | 
            +
            				<li><a href="#"><span>Products</span></a></li>
         | 
| 75 | 
            +
            				<li><a href="#"><span>Services</span></a></li>
         | 
| 76 | 
            +
            				<li><a href="#"><span>Contact us</span></a></li>
         | 
| 77 | 
            +
            			</ul>
         | 
| 78 | 
            +
            			{{ content_for_layout }}
         | 
| 79 | 
            +
            		</div>
         | 
| 80 | 
            +
            	</div>
         | 
| 81 | 
            +
            </div>
         | 
| 82 | 
            +
            <!-- Footer -->
         | 
| 83 | 
            +
            <div id="footer">
         | 
| 84 | 
            +
            	<div class="copyright">
         | 
| 85 | 
            +
            		<h4>Copyright © jnCentral.com.  All rights reserved.</h4>
         | 
| 86 | 
            +
            		<!-- Mini navigation -->
         | 
| 87 | 
            +
            		<div class="nav">
         | 
| 88 | 
            +
            			<a href="#">Home</a>     <a href="#">Products</a>     <a href="#">Services</a>     <a href="#">About us</a>     <a href="#">Contact</a>
         | 
| 89 | 
            +
            		</div>
         | 
| 90 | 
            +
            	</div>
         | 
| 91 | 
            +
            </div>
         | 
| 92 | 
            +
            </body>
         | 
| 93 | 
            +
            </html>
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe H2o::FileLoader do
         | 
| 4 | 
            +
              before do
         | 
| 5 | 
            +
                path = File.expand_path("../../fixtures", __FILE__)
         | 
| 6 | 
            +
                @loader = H2o::FileLoader.new(path)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              it "search for template on a search path on file system" do
         | 
| 10 | 
            +
                @loader.exist?('a.html').should == true
         | 
| 11 | 
            +
                @loader.exist?('deep/folder/c.html').should == true
         | 
| 12 | 
            +
                @loader.exist?('non-existence.html').should == false
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              it "read for files on the searchpath" do
         | 
| 16 | 
            +
                @loader.read('a.html').should == '{{ hello }}'
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              it "raises error when template doesn't exist" do
         | 
| 20 | 
            +
                expect { @loader.read('non-existence.html') }.should raise_error
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            describe "H2o::HashLoader" do
         | 
| 25 | 
            +
              it "read file on the same namespace in a hash" do
         | 
| 26 | 
            +
                H2o.loader = H2o::HashLoader.new(
         | 
| 27 | 
            +
                  'base.html' => '{% block content %}test{% endblock %}',
         | 
| 28 | 
            +
                  'a.html' => "{% extends 'base.html' %}{% block content %}test2{% endblock %}"
         | 
| 29 | 
            +
                )
         | 
| 30 | 
            +
                H2o.loader.read('base.html').should == '{% block content %}test{% endblock %}'
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                H2o::Template.new('base.html').render.should == 'test'
         | 
| 33 | 
            +
                H2o::Template.new('a.html').render.should == 'test2'
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe H2o::Filters do
         | 
| 4 | 
            +
              it "should pass input object as first param" do    
         | 
| 5 | 
            +
                H2o::Filters << TestFilters
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                # try a standard filter
         | 
| 8 | 
            +
                render('{{ "something" | upper }}').should == 'SOMETHING'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # # try a array input object
         | 
| 11 | 
            +
                list = ["man","women"]
         | 
| 12 | 
            +
                render('{{ object| test_filter }}', :object => list).should == list.inspect
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                # Try a array subclass
         | 
| 15 | 
            +
                list = CustomCollection.new(["man", "woman"])
         | 
| 16 | 
            +
                render('{{ object| test_filter }}', :object => list).should == list.inspect
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              it "should be able to pass aditional parameters" do
         | 
| 20 | 
            +
                render('{{ "test"| test_filter_2 1, 2 }}').should == 'test-1-2'
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            describe DefaultFilters do
         | 
| 25 | 
            +
              it "should privide a set of default filters" do
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                render('{{ "test" |upper }}').should == 'TEST'
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                render('{{ "TEST" |lower }}').should == 'test'
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                render('{{ "test" |capitalize }}').should == 'Test'
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                render('{{ list |first }}', :list => [1,2]).should == "1"
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                render('{{ list |last }}', :list => [1,2]).should == "2"
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                render('{{ list |join }}', :list => [1,2]).should == "1, 2"
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            # 
         | 
| 42 | 
            +
            module TestFilters
         | 
| 43 | 
            +
              def test_filter (input)
         | 
| 44 | 
            +
                "#{input.inspect}"
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
              
         | 
| 47 | 
            +
              def test_filter_2 (string, param1, param2)
         | 
| 48 | 
            +
               "#{string}-#{param1}-#{param2}"
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            class CustomCollection < Array
         | 
| 53 | 
            +
            end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            def render(src, context = {})
         | 
| 56 | 
            +
              H2o::Template.parse(src).render(context)
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "Parser regex" do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              it "should match whitespace" do
         | 
| 6 | 
            +
                H2o::WHITESPACE_RE.should =~ '   '
         | 
| 7 | 
            +
                H2o::WHITESPACE_RE.should =~ ' '
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              it "should match variable names" do
         | 
| 11 | 
            +
                H2o::NAME_RE.should =~ 'variable'
         | 
| 12 | 
            +
                H2o::NAME_RE.should =~ 'variable.property'
         | 
| 13 | 
            +
                H2o::NAME_RE.should =~ 'variable.property'
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
              it "should match string" do
         | 
| 17 | 
            +
                H2o::STRING_RE.should =~ '"this is a string"'
         | 
| 18 | 
            +
                H2o::STRING_RE.should =~ '"She has \"The thing\""'
         | 
| 19 | 
            +
                H2o::STRING_RE.should =~ "'the doctor is good'"
         | 
| 20 | 
            +
                H2o::STRING_RE.should =~ "'She can\'t do it'"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              it "should match numeric values" do
         | 
| 24 | 
            +
                H2o::NUMBER_RE.should =~ '1.2'
         | 
| 25 | 
            +
                H2o::NUMBER_RE.should =~ '-3.2'
         | 
| 26 | 
            +
                H2o::NUMBER_RE.should =~ '100000'
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
              it "should match operators" do
         | 
| 30 | 
            +
                %w(== > < >= <= != ! not and or).each do |operator|
         | 
| 31 | 
            +
                  H2o::OPERATOR_RE.should =~ operator
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              it "should match named arguments" do
         | 
| 36 | 
            +
                named_args = ["name: 'peter'", 'name: object.property', 'price: 2.3', 'age: 29', 'alt: "my company logo"']
         | 
| 37 | 
            +
                named_args.each do |arg|
         | 
| 38 | 
            +
                  H2o::NAMED_ARGS_RE.should =~ arg
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            describe 'H2o::Parser argument parsing' do
         | 
| 44 | 
            +
              
         | 
| 45 | 
            +
              it "should parse named arguments" do
         | 
| 46 | 
            +
                r = H2o::Parser.parse_arguments(
         | 
| 47 | 
            +
                  "something | filter 11, name: 'something', age: 18, var: variable, active: true"
         | 
| 48 | 
            +
                )
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                r.should == [:something, 
         | 
| 51 | 
            +
                  [:filter, 11, { 
         | 
| 52 | 
            +
                    :name=> "something", 
         | 
| 53 | 
            +
                    :age => 18, 
         | 
| 54 | 
            +
                    :var=> :variable, 
         | 
| 55 | 
            +
                    :active => true }
         | 
| 56 | 
            +
                  ]
         | 
| 57 | 
            +
                ]
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
            end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            describe "Whitespace stripping syntax" do
         | 
| 62 | 
            +
              it "should rstrip previous text node for {%- %}" do
         | 
| 63 | 
            +
                H2o::Template.parse('   {%- if true %}{% endif %}').render.should == ''
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
                
         | 
| 66 | 
            +
              it "should lstrip next text node for {% -%}" do
         | 
| 67 | 
            +
                H2o::Template.parse('{% if true -%}   {% endif %}').render.should == ''
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              it "should strip whitespace on both site with {%- -%}" do
         | 
| 71 | 
            +
                H2o::Template.parse('
         | 
| 72 | 
            +
                  {%- if true -%}
         | 
| 73 | 
            +
                    hello
         | 
| 74 | 
            +
                  {%- endif -%}   
         | 
| 75 | 
            +
                ').render.should == 'hello'
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe H2o::Tags::Block do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              it "should render block content" do
         | 
| 6 | 
            +
                parse('{% block something %}content{% endblock %}').render.should == 'content'
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              context "block variable" do
         | 
| 11 | 
            +
                it "should return block name" do
         | 
| 12 | 
            +
                  parse(block(:something, '{{ block.name }}')).render.should == 'something'
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                it "should return current block depth" do
         | 
| 16 | 
            +
                  source = block(:something, '{{ block.depth }}')
         | 
| 17 | 
            +
                  parse(source).render.should == "1"
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                it "should return parent block content"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def block(name, content)
         | 
| 24 | 
            +
                "{% block #{name.to_s} %}#{content}{% endblock %}"
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         |