express_templates 0.2.7 → 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.
- checksums.yaml +4 -4
 - data/lib/core_extensions/proc.rb +72 -20
 - data/lib/express_templates/compiler.rb +9 -1
 - data/lib/express_templates/components/base.rb +1 -1
 - data/lib/express_templates/components/capabilities/building.rb +8 -0
 - data/lib/express_templates/components/capabilities/conditionality.rb +8 -6
 - data/lib/express_templates/components/capabilities/configurable.rb +3 -4
 - data/lib/express_templates/components/capabilities/iterating.rb +18 -23
 - data/lib/express_templates/components/capabilities/parenting.rb +4 -18
 - data/lib/express_templates/components/capabilities/rendering.rb +2 -65
 - data/lib/express_templates/components/capabilities/templating.rb +24 -22
 - data/lib/express_templates/components/capabilities/wrapping.rb +23 -39
 - data/lib/express_templates/components/column.rb +1 -1
 - data/lib/express_templates/components/for_each.rb +28 -0
 - data/lib/express_templates/components/form_for.rb +19 -0
 - data/lib/express_templates/components/form_rails_support.rb +1 -1
 - data/lib/express_templates/components/null_wrap.rb +9 -0
 - data/lib/express_templates/components/row.rb +1 -1
 - data/lib/express_templates/components/table_for.rb +119 -0
 - data/lib/express_templates/components/tree_for.rb +41 -0
 - data/lib/express_templates/components/unless_block.rb +40 -0
 - data/lib/express_templates/components.rb +4 -0
 - data/lib/express_templates/expander.rb +15 -4
 - data/lib/express_templates/indenter.rb +8 -5
 - data/lib/express_templates/markup/tag.rb +62 -30
 - data/lib/express_templates/markup/wrapper.rb +1 -1
 - data/lib/express_templates/version.rb +1 -1
 - data/test/components/base_test.rb +5 -38
 - data/test/components/conditionality_test.rb +1 -1
 - data/test/components/configurable_test.rb +2 -2
 - data/test/components/container_test.rb +1 -1
 - data/test/components/iterating_test.rb +30 -9
 - data/test/components/table_for_test.rb +116 -0
 - data/test/core_extensions/proc_test.rb +35 -5
 - data/test/dummy/log/test.log +645 -0
 - data/test/fixtures/{a_big_page.html → a_big_page2.html} +0 -0
 - data/test/indenter_test.rb +6 -4
 - data/test/markup/tag_test.rb +15 -2
 - data/test/performance_test.rb +1 -1
 - data/test/test_helper.rb +2 -0
 - metadata +26 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 16e00189a36058717818d7a7c66638c0164fcef6
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 559bf6b66e66bf2caacd9c7594a9227ed2208cee
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: bfbbac386e1b3db30466f8517dc7c9a82f65ebce01c548357ba2754399f3808ef9601eb157cc78775fc67f571930f06dfc4da57ed7ee57e267b5624ad9a82b83
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 20b4d748cb8780f9366ae4875f1795af827ce0db5b59c128d096a5cb47de38d7639bb90d55d53183ce4df2349341d68d52e6084f328e510090cc899ae706fb07
         
     | 
    
        data/lib/core_extensions/proc.rb
    CHANGED
    
    | 
         @@ -2,9 +2,13 @@ require 'ripper' 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require 'pp'
         
     | 
| 
       3 
3 
     | 
    
         
             
            class Proc
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              TLAMBEG = [:on_tlambeg, "{"]
         
     | 
| 
      
 6 
     | 
    
         
            +
              TLAMBDA = [:on_tlambda, "->"]
         
     | 
| 
      
 7 
     | 
    
         
            +
              LBRACE  = [:on_lbrace, '{']
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              TOKEN_PAIRS = {LBRACE             => [:on_rbrace, '}'],
         
     | 
| 
       6 
10 
     | 
    
         
             
                             [:on_kw, 'do']     => [:on_kw, 'end'],
         
     | 
| 
       7 
     | 
    
         
            -
                              
     | 
| 
      
 11 
     | 
    
         
            +
                             TLAMBDA            => [:on_rbrace, '}']}
         
     | 
| 
       8 
12 
     | 
    
         | 
| 
       9 
13 
     | 
    
         
             
              # Make a best effort to provide the original source for a block
         
     | 
| 
       10 
14 
     | 
    
         
             
              # based on extracting a string from the file identified in
         
     | 
| 
         @@ -18,25 +22,73 @@ class Proc 
     | 
|
| 
       18 
22 
     | 
    
         
             
              # If you require only the source of blocks-within-other-blocks, start them
         
     | 
| 
       19 
23 
     | 
    
         
             
              # on a new line as would be best practice for clarity and readability.
         
     | 
| 
       20 
24 
     | 
    
         
             
              def source
         
     | 
| 
       21 
     | 
    
         
            -
                 
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                   
     | 
| 
      
 25 
     | 
    
         
            +
                @source ||= begin
         
     | 
| 
      
 26 
     | 
    
         
            +
                  file, line_no = source_location
         
     | 
| 
      
 27 
     | 
    
         
            +
                  raise "no line number provided for source_location: #{self}" if line_no.nil?
         
     | 
| 
      
 28 
     | 
    
         
            +
                  tokens =  Ripper.lex File.read(file)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  tokens_on_line = tokens.select {|pos, lbl, str| pos[0].eql?(line_no) }
         
     | 
| 
      
 30 
     | 
    
         
            +
                  starting_token = tokens_on_line.detect do |pos, lbl, str|
         
     | 
| 
      
 31 
     | 
    
         
            +
                      TOKEN_PAIRS.keys.include? [lbl, str]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  starting_token_type = [starting_token[1], starting_token[2]]
         
     | 
| 
      
 34 
     | 
    
         
            +
                  ending_token_type = TOKEN_PAIRS[starting_token_type]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  source_str = ""
         
     | 
| 
      
 36 
     | 
    
         
            +
                  remaining_tokens = tokens[tokens.index(starting_token)..-1]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  nesting = -1
         
     | 
| 
      
 38 
     | 
    
         
            +
                  starting_nesting_token_types = if [TLAMBDA, LBRACE].include?(starting_token_type)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    [TLAMBDA, LBRACE]
         
     | 
| 
      
 40 
     | 
    
         
            +
                  else
         
     | 
| 
      
 41 
     | 
    
         
            +
                    [starting_token_type]
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  while token = remaining_tokens.shift
         
     | 
| 
      
 45 
     | 
    
         
            +
                    token = [token[1], token[2]] # strip position
         
     | 
| 
      
 46 
     | 
    
         
            +
                    source_str << token[1]
         
     | 
| 
      
 47 
     | 
    
         
            +
                    nesting += 1 if starting_nesting_token_types.include? token
         
     | 
| 
      
 48 
     | 
    
         
            +
                    is_ending_token = token.eql?(ending_token_type)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    break if is_ending_token && nesting.eql?(0)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    nesting -= 1 if is_ending_token
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  source_str
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              # Examines the source of a proc to extract the body by
         
     | 
| 
      
 57 
     | 
    
         
            +
              # removing the outermost block delimiters and any surrounding.
         
     | 
| 
      
 58 
     | 
    
         
            +
              # whitespace.
         
     | 
| 
      
 59 
     | 
    
         
            +
              #
         
     | 
| 
      
 60 
     | 
    
         
            +
              # Raises exception if the block takes arguments.
         
     | 
| 
      
 61 
     | 
    
         
            +
              #
         
     | 
| 
      
 62 
     | 
    
         
            +
              def source_body
         
     | 
| 
      
 63 
     | 
    
         
            +
                raise "Cannot extract proc body on non-zero arity" unless arity.eql?(0)
         
     | 
| 
      
 64 
     | 
    
         
            +
                tokens = Ripper.lex source
         
     | 
| 
      
 65 
     | 
    
         
            +
                body_start_idx = 2
         
     | 
| 
      
 66 
     | 
    
         
            +
                body_end_idx = -1
         
     | 
| 
      
 67 
     | 
    
         
            +
                if tokens[0][1].eql?(:on_tlambda)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  body_start_idx = tokens.index(tokens.detect { |t| t[1].eql?(:on_tlambeg) }) + 1
         
     | 
| 
       27 
69 
     | 
    
         
             
                end
         
     | 
| 
       28 
     | 
    
         
            -
                 
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                 
     | 
| 
       31 
     | 
    
         
            -
                 
     | 
| 
       32 
     | 
    
         
            -
                 
     | 
| 
       33 
     | 
    
         
            -
                while  
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
      
 70 
     | 
    
         
            +
                body_tokens = tokens[body_start_idx..-1]
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                body_tokens.pop # ending token of proc
         
     | 
| 
      
 73 
     | 
    
         
            +
                # remove trailing whitespace
         
     | 
| 
      
 74 
     | 
    
         
            +
                whitespace = [:on_sp, :on_nl, :on_ignored_nl]
         
     | 
| 
      
 75 
     | 
    
         
            +
                body_tokens.pop while whitespace.include?(body_tokens[-1][1])
         
     | 
| 
      
 76 
     | 
    
         
            +
                # remove leading whitespace
         
     | 
| 
      
 77 
     | 
    
         
            +
                body_tokens.shift while whitespace.include?(body_tokens[0][1])
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # put them back together
         
     | 
| 
      
 80 
     | 
    
         
            +
                body_tokens.map {|token| token[2] }.join
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              def self.from_source(prc_src)
         
     | 
| 
      
 84 
     | 
    
         
            +
                raise ArgumentError unless prc_src.kind_of?(String)
         
     | 
| 
      
 85 
     | 
    
         
            +
                prc = begin
         
     | 
| 
      
 86 
     | 
    
         
            +
                  eval(prc_src)
         
     | 
| 
      
 87 
     | 
    
         
            +
                rescue ArgumentError => e
         
     | 
| 
      
 88 
     | 
    
         
            +
                  binding.pry
         
     | 
| 
       39 
89 
     | 
    
         
             
                end
         
     | 
| 
       40 
     | 
    
         
            -
                 
     | 
| 
      
 90 
     | 
    
         
            +
                prc.instance_variable_set(:@source, prc_src)
         
     | 
| 
      
 91 
     | 
    
         
            +
                prc
         
     | 
| 
       41 
92 
     | 
    
         
             
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
       42 
94 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,7 +5,15 @@ module ExpressTemplates 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
                  expander = Expander.new(template)
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
      
 8 
     | 
    
         
            +
                  Thread.current[:first_whitepace_removed] ||= 0
         
     | 
| 
      
 9 
     | 
    
         
            +
                  Thread.current[:first_whitepace_removed] += 1
         
     | 
| 
      
 10 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 11 
     | 
    
         
            +
                    compiled = expander.expand(src, &block).map(&:compile)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    compiled.first.sub!(/^"\n+/, '"') if Thread.current[:first_whitepace_removed].eql?(1)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    Thread.current[:first_whitepace_removed] -= 1
         
     | 
| 
      
 14 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 15 
     | 
    
         
            +
                    Thread.current[:first_whitepace_removed] = nil if Thread.current[:first_whitepace_removed].eql?(0)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
       9 
17 
     | 
    
         | 
| 
       10 
18 
     | 
    
         
             
                  return compiled.join("+").gsub('"+"', '').tap do |s|
         
     | 
| 
       11 
19 
     | 
    
         
             
                    puts("\n"+template.inspect+"\n"+s) if ENV['DEBUG'].eql?('true')
         
     | 
| 
         @@ -37,12 +37,14 @@ module ExpressTemplates 
     | 
|
| 
       37 
37 
     | 
    
         
             
                      end
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
                      def only_if condition_proc
         
     | 
| 
       40 
     | 
    
         
            -
                        @condition_proc = condition_proc
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 40 
     | 
    
         
            +
                        @condition_proc = Proc.from_source "-> {!(#{condition_proc.source_body})}"
         
     | 
| 
      
 41 
     | 
    
         
            +
                        inner_src = self[:markup]
         
     | 
| 
      
 42 
     | 
    
         
            +
                        fragment_src = %Q(-> {
         
     | 
| 
      
 43 
     | 
    
         
            +
              unless_block(Proc.from_source(#{@condition_proc.source.inspect})) {
         
     | 
| 
      
 44 
     | 
    
         
            +
                #{inner_src.source_body}
         
     | 
| 
      
 45 
     | 
    
         
            +
              }
         
     | 
| 
      
 46 
     | 
    
         
            +
            })
         
     | 
| 
      
 47 
     | 
    
         
            +
                        _store :markup, Proc.from_source(fragment_src)
         
     | 
| 
       46 
48 
     | 
    
         
             
                      end
         
     | 
| 
       47 
49 
     | 
    
         | 
| 
       48 
50 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -28,7 +28,6 @@ module ExpressTemplates 
     | 
|
| 
       28 
28 
     | 
    
         
             
                        # Stores arguments for later processing, eg., compile time
         
     | 
| 
       29 
29 
     | 
    
         
             
                        def initialize(*args)
         
     | 
| 
       30 
30 
     | 
    
         
             
                          @args = args.dup
         
     | 
| 
       31 
     | 
    
         
            -
                          @config = {}
         
     | 
| 
       32 
31 
     | 
    
         
             
                          _process_args!(args)
         
     | 
| 
       33 
32 
     | 
    
         
             
                          super(*args)
         
     | 
| 
       34 
33 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -57,7 +56,7 @@ module ExpressTemplates 
     | 
|
| 
       57 
56 
     | 
    
         
             
                    module InstanceMethods
         
     | 
| 
       58 
57 
     | 
    
         | 
| 
       59 
58 
     | 
    
         
             
                      def config
         
     | 
| 
       60 
     | 
    
         
            -
                        @config
         
     | 
| 
      
 59 
     | 
    
         
            +
                        @config ||= {}
         
     | 
| 
       61 
60 
     | 
    
         
             
                      end
         
     | 
| 
       62 
61 
     | 
    
         | 
| 
       63 
62 
     | 
    
         
             
                      alias :my :config
         
     | 
| 
         @@ -67,8 +66,8 @@ module ExpressTemplates 
     | 
|
| 
       67 
66 
     | 
    
         
             
                      end
         
     | 
| 
       68 
67 
     | 
    
         | 
| 
       69 
68 
     | 
    
         
             
                      # Override Templating#lookup to pass locals
         
     | 
| 
       70 
     | 
    
         
            -
                      def lookup(fragment_name)
         
     | 
| 
       71 
     | 
    
         
            -
                         
     | 
| 
      
 69 
     | 
    
         
            +
                      def lookup(fragment_name, options = {})
         
     | 
| 
      
 70 
     | 
    
         
            +
                        super(fragment_name, options.merge(expand_locals))
         
     | 
| 
       72 
71 
     | 
    
         
             
                      end
         
     | 
| 
       73 
72 
     | 
    
         | 
| 
       74 
73 
     | 
    
         | 
| 
         @@ -47,31 +47,26 @@ module ExpressTemplates 
     | 
|
| 
       47 
47 
     | 
    
         
             
                      # An <tt>:empty</tt> option specifies a fragment to use for the
         
     | 
| 
       48 
48 
     | 
    
         
             
                      # empty state when the iterator returns an empty collection.
         
     | 
| 
       49 
49 
     | 
    
         
             
                      def for_each(iterator, as: :item, emit: :markup, empty: nil)
         
     | 
| 
       50 
     | 
    
         
            -
                         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 50 
     | 
    
         
            +
                        as = as.to_sym
         
     | 
| 
      
 51 
     | 
    
         
            +
                        emit = emit.to_sym
         
     | 
| 
      
 52 
     | 
    
         
            +
                        iterator = iterator.kind_of?(Proc) ? iterator.source : iterator
         
     | 
| 
      
 53 
     | 
    
         
            +
                        fragment_src = if empty
         
     | 
| 
      
 54 
     | 
    
         
            +
            %Q(-> {
         
     | 
| 
      
 55 
     | 
    
         
            +
              unless_block(Proc.from_source("-> {#{iterator}.call.empty?}"), alt: #{self[empty].source}) {
         
     | 
| 
      
 56 
     | 
    
         
            +
                for_each(Proc.from_source("#{iterator}"), as: #{as.inspect}) {
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #{self[emit].source_body}
         
     | 
| 
      
 58 
     | 
    
         
            +
                }
         
     | 
| 
      
 59 
     | 
    
         
            +
              }
         
     | 
| 
      
 60 
     | 
    
         
            +
            })
         
     | 
| 
       52 
61 
     | 
    
         
             
                        else
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                              instance_exec(options, &iterator)
         
     | 
| 
       59 
     | 
    
         
            -
                            else
         
     | 
| 
       60 
     | 
    
         
            -
                              instance_exec &iterator
         
     | 
| 
       61 
     | 
    
         
            -
                            end
         
     | 
| 
       62 
     | 
    
         
            -
                          else
         
     | 
| 
       63 
     | 
    
         
            -
                            eval(iterator.to_s)
         
     | 
| 
       64 
     | 
    
         
            -
                          end
         
     | 
| 
       65 
     | 
    
         
            -
                          if collection.empty?
         
     | 
| 
       66 
     | 
    
         
            -
                            empty ? component[empty] : ''
         
     | 
| 
       67 
     | 
    
         
            -
                          else
         
     | 
| 
       68 
     | 
    
         
            -
                            collection.map do |item|
         
     | 
| 
       69 
     | 
    
         
            -
                              b = binding
         
     | 
| 
       70 
     | 
    
         
            -
                              b.local_variable_set(var_name, item)
         
     | 
| 
       71 
     | 
    
         
            -
                              b.eval(component[emit], __FILE__)
         
     | 
| 
       72 
     | 
    
         
            -
                            end.join
         
     | 
| 
       73 
     | 
    
         
            -
                          end
         
     | 
| 
      
 62 
     | 
    
         
            +
            %Q(-> {
         
     | 
| 
      
 63 
     | 
    
         
            +
              for_each(Proc.from_source("#{iterator}"), as: #{as.inspect}) {
         
     | 
| 
      
 64 
     | 
    
         
            +
                #{self[emit].source_body}
         
     | 
| 
      
 65 
     | 
    
         
            +
              }
         
     | 
| 
      
 66 
     | 
    
         
            +
            })
         
     | 
| 
       74 
67 
     | 
    
         
             
                        end
         
     | 
| 
      
 68 
     | 
    
         
            +
                        fragment = Proc.from_source(fragment_src)
         
     | 
| 
      
 69 
     | 
    
         
            +
                        _store :markup, fragment
         
     | 
| 
       75 
70 
     | 
    
         
             
                      end
         
     | 
| 
       76 
71 
     | 
    
         
             
                    end
         
     | 
| 
       77 
72 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -30,20 +30,10 @@ module ExpressTemplates 
     | 
|
| 
       30 
30 
     | 
    
         
             
                    #
         
     | 
| 
       31 
31 
     | 
    
         
             
                    def self.included(base)
         
     | 
| 
       32 
32 
     | 
    
         
             
                      base.class_eval do
         
     | 
| 
       33 
     | 
    
         
            -
                        extend ClassMethods
         
     | 
| 
       34 
33 
     | 
    
         
             
                        include InstanceMethods
         
     | 
| 
       35 
34 
     | 
    
         
             
                      end
         
     | 
| 
       36 
35 
     | 
    
         
             
                    end
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                    module ClassMethods
         
     | 
| 
       39 
     | 
    
         
            -
                      def render_with_children(context, locals = {}, child_markup_src = nil)
         
     | 
| 
       40 
     | 
    
         
            -
                        _wrap_it(context, locals) do |component|
         
     | 
| 
       41 
     | 
    
         
            -
                          child_markup_src
         
     | 
| 
       42 
     | 
    
         
            -
                        end
         
     | 
| 
       43 
     | 
    
         
            -
                      end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                    end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
37 
     | 
    
         
             
                    module InstanceMethods
         
     | 
| 
       48 
38 
     | 
    
         
             
                      def children
         
     | 
| 
       49 
39 
     | 
    
         
             
                        @children ||= []
         
     | 
| 
         @@ -54,13 +44,9 @@ module ExpressTemplates 
     | 
|
| 
       54 
44 
     | 
    
         
             
                      end
         
     | 
| 
       55 
45 
     | 
    
         | 
| 
       56 
46 
     | 
    
         
             
                      def compile
         
     | 
| 
       57 
     | 
    
         
            -
                         
     | 
| 
       58 
     | 
    
         
            -
                         
     | 
| 
       59 
     | 
    
         
            -
                         
     | 
| 
       60 
     | 
    
         
            -
                        compiled_children = compile_children
         
     | 
| 
       61 
     | 
    
         
            -
                        args << compiled_children unless compiled_children.empty?
         
     | 
| 
       62 
     | 
    
         
            -
                        closing_paren = compiled_children.empty? ? ')' : "\n#{Indenter.for(:compile)})"
         
     | 
| 
       63 
     | 
    
         
            -
                        "#{self.class.to_s}.render_with_children(#{args.join(', ')}#{closing_paren}"
         
     | 
| 
      
 47 
     | 
    
         
            +
                        null_wrapped_children = "null_wrap { #{compile_children} }"
         
     | 
| 
      
 48 
     | 
    
         
            +
                        wrap_children_src = self.class[:markup].source.gsub(/\W_yield\W/, null_wrapped_children)
         
     | 
| 
      
 49 
     | 
    
         
            +
                        _compile_fragment(Proc.from_source(wrap_children_src))
         
     | 
| 
       64 
50 
     | 
    
         
             
                      end
         
     | 
| 
       65 
51 
     | 
    
         | 
| 
       66 
52 
     | 
    
         
             
                      def compile_children
         
     | 
| 
         @@ -69,7 +55,7 @@ module ExpressTemplates 
     | 
|
| 
       69 
55 
     | 
    
         
             
                          compiled_children = children.map do |child|
         
     | 
| 
       70 
56 
     | 
    
         
             
                            indent_with_newline +
         
     | 
| 
       71 
57 
     | 
    
         
             
                            (child.compile rescue %Q("#{child}")) # Bare strings may be children
         
     | 
| 
       72 
     | 
    
         
            -
                          end.join(" 
     | 
| 
      
 58 
     | 
    
         
            +
                          end.join("+\n")
         
     | 
| 
       73 
59 
     | 
    
         
             
                          compiled_children.gsub!('"+"', '') # avoid unnecessary string concatenation
         
     | 
| 
       74 
60 
     | 
    
         
             
                        end
         
     | 
| 
       75 
61 
     | 
    
         
             
                        return compiled_children
         
     | 
| 
         @@ -15,78 +15,15 @@ module ExpressTemplates 
     | 
|
| 
       15 
15 
     | 
    
         
             
                    def self.included(base)
         
     | 
| 
       16 
16 
     | 
    
         
             
                      base.class_eval do
         
     | 
| 
       17 
17 
     | 
    
         
             
                        extend ClassMethods
         
     | 
| 
       18 
     | 
    
         
            -
                        include InstanceMethods
         
     | 
| 
       19 
18 
     | 
    
         
             
                      end
         
     | 
| 
       20 
19 
     | 
    
         
             
                    end
         
     | 
| 
       21 
20 
     | 
    
         | 
| 
       22 
21 
     | 
    
         
             
                    module ClassMethods
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                      # during rendering.
         
     | 
| 
       26 
     | 
    
         
            -
                      #
         
     | 
| 
       27 
     | 
    
         
            -
                      # The block will be passed a reference to the component's class.
         
     | 
| 
       28 
     | 
    
         
            -
                      #
         
     | 
| 
       29 
     | 
    
         
            -
                      def using_logic(&block)
         
     | 
| 
       30 
     | 
    
         
            -
                        @control_flow = block
         
     | 
| 
       31 
     | 
    
         
            -
                      end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                      # Returns a string containing markup generated by evaluating
         
     | 
| 
       34 
     | 
    
         
            -
                      # blocks of supplied logic or compiled template code in a <tt>context</tt>.
         
     | 
| 
       35 
     | 
    
         
            -
                      #
         
     | 
| 
       36 
     | 
    
         
            -
                      # The context may be any object however, it is generally an
         
     | 
| 
       37 
     | 
    
         
            -
                      # ActionView::Context.
         
     | 
| 
       38 
     | 
    
         
            -
                      #
         
     | 
| 
       39 
     | 
    
         
            -
                      # Components when compiled may yield something like:
         
     | 
| 
       40 
     | 
    
         
            -
                      #
         
     | 
| 
       41 
     | 
    
         
            -
                      #     "MyComponent.render(self, {id: 'foo'})"
         
     | 
| 
       42 
     | 
    
         
            -
                      #
         
     | 
| 
       43 
     | 
    
         
            -
                      # The supplied options hash may be used to modify any fragments
         
     | 
| 
       44 
     | 
    
         
            -
                      # or the behavior of any logic.
         
     | 
| 
       45 
     | 
    
         
            -
                      #
         
     | 
| 
       46 
     | 
    
         
            -
                      # If a fragment identifier is passed as a symbol in the first
         
     | 
| 
       47 
     | 
    
         
            -
                      # option position, this will render that fragment only.
         
     | 
| 
       48 
     | 
    
         
            -
                      #
         
     | 
| 
       49 
     | 
    
         
            -
                      def render(context, *opts, &context_logic_block)
         
     | 
| 
       50 
     | 
    
         
            -
                        fragment = opts.shift if opts.first.is_a?(Symbol)
         
     | 
| 
       51 
     | 
    
         
            -
                        begin
         
     | 
| 
       52 
     | 
    
         
            -
                          if fragment
         
     | 
| 
       53 
     | 
    
         
            -
                            context.instance_eval(_lookup(fragment, opts)) || ''
         
     | 
| 
       54 
     | 
    
         
            -
                          else
         
     | 
| 
       55 
     | 
    
         
            -
                            flow = context_logic_block || @control_flow
         
     | 
| 
       56 
     | 
    
         
            -
                            exec_args = [self, opts].take(flow.arity)
         
     | 
| 
       57 
     | 
    
         
            -
                            context.instance_exec(*exec_args, &flow) || ''
         
     | 
| 
       58 
     | 
    
         
            -
                          end
         
     | 
| 
       59 
     | 
    
         
            -
                        rescue => e
         
     | 
| 
       60 
     | 
    
         
            -
                          binding.pry if ENV['DEBUG'].eql?("true")
         
     | 
| 
       61 
     | 
    
         
            -
                          raise "Rendering error in #{self}: #{e.to_s}"
         
     | 
| 
       62 
     | 
    
         
            -
                        end
         
     | 
| 
      
 22 
     | 
    
         
            +
                      def render_in(context, &view_code)
         
     | 
| 
      
 23 
     | 
    
         
            +
                        context.instance_eval(&view_code)
         
     | 
| 
       63 
24 
     | 
    
         
             
                      end
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
                      private
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                        def _control_flow
         
     | 
| 
       68 
     | 
    
         
            -
                          @control_flow
         
     | 
| 
       69 
     | 
    
         
            -
                        end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
25 
     | 
    
         
             
                    end
         
     | 
| 
       72 
26 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                    module InstanceMethods
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                      def compile
         
     | 
| 
       76 
     | 
    
         
            -
                        if _provides_logic?
         
     | 
| 
       77 
     | 
    
         
            -
                          "#{self.class.to_s}.render(self)"
         
     | 
| 
       78 
     | 
    
         
            -
                        else
         
     | 
| 
       79 
     | 
    
         
            -
                          lookup :markup
         
     | 
| 
       80 
     | 
    
         
            -
                        end
         
     | 
| 
       81 
     | 
    
         
            -
                      end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                      private
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                        def _provides_logic?
         
     | 
| 
       86 
     | 
    
         
            -
                          !!self.class.send(:_control_flow)
         
     | 
| 
       87 
     | 
    
         
            -
                        end
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                    end
         
     | 
| 
       90 
27 
     | 
    
         
             
                  end
         
     | 
| 
       91 
28 
     | 
    
         
             
                end
         
     | 
| 
       92 
29 
     | 
    
         
             
              end
         
     | 
| 
         @@ -51,11 +51,13 @@ module ExpressTemplates 
     | 
|
| 
       51 
51 
     | 
    
         
             
                      # 
         
     | 
| 
       52 
52 
     | 
    
         
             
                      def emits(*args, &template_code)
         
     | 
| 
       53 
53 
     | 
    
         
             
                        if args.first.respond_to?(:call) or template_code
         
     | 
| 
       54 
     | 
    
         
            -
                           
     | 
| 
      
 54 
     | 
    
         
            +
                          fragment = (args.first||template_code)
         
     | 
| 
      
 55 
     | 
    
         
            +
                          raise "must use stabby lambda" unless fragment.lambda?
         
     | 
| 
      
 56 
     | 
    
         
            +
                          _store :markup, fragment# default fragment is named :markup
         
     | 
| 
       55 
57 
     | 
    
         
             
                        else
         
     | 
| 
       56 
58 
     | 
    
         
             
                          args.first.to_a.each do |name, block|
         
     | 
| 
       57 
59 
     | 
    
         
             
                            raise ArgumentError unless name.is_a?(Symbol) and block.is_a?(Proc)
         
     | 
| 
       58 
     | 
    
         
            -
                            _store(name,  
     | 
| 
      
 60 
     | 
    
         
            +
                            _store(name, block)
         
     | 
| 
       59 
61 
     | 
    
         
             
                          end
         
     | 
| 
       60 
62 
     | 
    
         
             
                        end
         
     | 
| 
       61 
63 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -116,26 +118,9 @@ module ExpressTemplates 
     | 
|
| 
       116 
118 
     | 
    
         
             
                        # Returns a string containing ruby code which evaluates to markup.
         
     | 
| 
       117 
119 
     | 
    
         
             
                        def _lookup(name, options = {})
         
     | 
| 
       118 
120 
     | 
    
         
             
                          @fragments ||= Hash.new
         
     | 
| 
       119 
     | 
    
         
            -
                           
     | 
| 
       120 
     | 
    
         
            -
                          if fragment.kind_of?(Proc)
         
     | 
| 
       121 
     | 
    
         
            -
                            _compile_fragment(fragment, options)
         
     | 
| 
       122 
     | 
    
         
            -
                          else
         
     | 
| 
       123 
     | 
    
         
            -
                            fragment
         
     | 
| 
       124 
     | 
    
         
            -
                          end
         
     | 
| 
      
 121 
     | 
    
         
            +
                          @fragments[name] or binding.pry #raise "no template fragment supplied for: #{name}"
         
     | 
| 
       125 
122 
     | 
    
         
             
                        end
         
     | 
| 
       126 
123 
     | 
    
         | 
| 
       127 
     | 
    
         
            -
                        # Expands and compiles the supplied block representing a
         
     | 
| 
       128 
     | 
    
         
            -
                        # template fragment.
         
     | 
| 
       129 
     | 
    
         
            -
                        #
         
     | 
| 
       130 
     | 
    
         
            -
                        # Any supplied options are passed as locals for use during expansion.
         
     | 
| 
       131 
     | 
    
         
            -
                        #
         
     | 
| 
       132 
     | 
    
         
            -
                        # Returns a string containing ruby code which evaluates to markup.
         
     | 
| 
       133 
     | 
    
         
            -
                        def _compile_fragment(block, options = {})
         
     | 
| 
       134 
     | 
    
         
            -
                          expander = ExpressTemplates::Expander.new(nil, special_handlers, options)
         
     | 
| 
       135 
     | 
    
         
            -
                          expander.expand(&block).map(&:compile).join("+")
         
     | 
| 
       136 
     | 
    
         
            -
                        end
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
124 
     | 
    
         
             
                      private
         
     | 
| 
       140 
125 
     | 
    
         | 
| 
       141 
126 
     | 
    
         | 
| 
         @@ -183,10 +168,27 @@ module ExpressTemplates 
     | 
|
| 
       183 
168 
     | 
    
         | 
| 
       184 
169 
     | 
    
         
             
                    module InstanceMethods
         
     | 
| 
       185 
170 
     | 
    
         | 
| 
       186 
     | 
    
         
            -
                      def lookup(fragment_name)
         
     | 
| 
       187 
     | 
    
         
            -
                        self.class[fragment_name]
         
     | 
| 
      
 171 
     | 
    
         
            +
                      def lookup(fragment_name, options={})
         
     | 
| 
      
 172 
     | 
    
         
            +
                        fragment = self.class[fragment_name]
         
     | 
| 
      
 173 
     | 
    
         
            +
                        if fragment.kind_of?(Proc)
         
     | 
| 
      
 174 
     | 
    
         
            +
                          _compile_fragment(fragment, options)
         
     | 
| 
      
 175 
     | 
    
         
            +
                        else
         
     | 
| 
      
 176 
     | 
    
         
            +
                          fragment
         
     | 
| 
      
 177 
     | 
    
         
            +
                        end
         
     | 
| 
       188 
178 
     | 
    
         
             
                      end
         
     | 
| 
       189 
179 
     | 
    
         | 
| 
      
 180 
     | 
    
         
            +
                      # Expands and compiles the supplied block representing a
         
     | 
| 
      
 181 
     | 
    
         
            +
                      # template fragment.
         
     | 
| 
      
 182 
     | 
    
         
            +
                      #
         
     | 
| 
      
 183 
     | 
    
         
            +
                      # Any supplied options are passed as locals for use during expansion.
         
     | 
| 
      
 184 
     | 
    
         
            +
                      #
         
     | 
| 
      
 185 
     | 
    
         
            +
                      # Returns a string containing ruby code which evaluates to markup.
         
     | 
| 
      
 186 
     | 
    
         
            +
                      def _compile_fragment(block, options = {})
         
     | 
| 
      
 187 
     | 
    
         
            +
                        initialize_expander(nil, self.class.special_handlers, options)
         
     | 
| 
      
 188 
     | 
    
         
            +
                        expand(&block).map(&:compile).join("+").gsub('"+"', '')
         
     | 
| 
      
 189 
     | 
    
         
            +
                      end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
       190 
192 
     | 
    
         
             
                    end
         
     | 
| 
       191 
193 
     | 
    
         | 
| 
       192 
194 
     | 
    
         | 
| 
         @@ -30,6 +30,13 @@ module ExpressTemplates 
     | 
|
| 
       30 
30 
     | 
    
         
             
                    def self.included(base)
         
     | 
| 
       31 
31 
     | 
    
         
             
                      base.class_eval do
         
     | 
| 
       32 
32 
     | 
    
         
             
                        extend ClassMethods
         
     | 
| 
      
 33 
     | 
    
         
            +
                        include InstanceMethods
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    module InstanceMethods
         
     | 
| 
      
 38 
     | 
    
         
            +
                      def compile
         
     | 
| 
      
 39 
     | 
    
         
            +
                        lookup :markup
         
     | 
| 
       33 
40 
     | 
    
         
             
                      end
         
     | 
| 
       34 
41 
     | 
    
         
             
                    end
         
     | 
| 
       35 
42 
     | 
    
         | 
| 
         @@ -37,19 +44,24 @@ module ExpressTemplates 
     | 
|
| 
       37 
44 
     | 
    
         | 
| 
       38 
45 
     | 
    
         
             
                      # Enclose whatever the component would already generate
         
     | 
| 
       39 
46 
     | 
    
         
             
                      # inside the specified fragment wherever we encounter _yield
         
     | 
| 
       40 
     | 
    
         
            -
                       
     | 
| 
       41 
     | 
    
         
            -
                      # Note: this must come after any statements that affect the logic
         
     | 
| 
       42 
     | 
    
         
            -
                      # flow.
         
     | 
| 
       43 
     | 
    
         
            -
                      def wrap_with(fragment, dont_wrap_if: -> {false} )
         
     | 
| 
      
 47 
     | 
    
         
            +
                      def wrap_with(fragment, dont_wrap_if: false )
         
     | 
| 
       44 
48 
     | 
    
         
             
                        wrapper_name(fragment)
         
     | 
| 
       45 
     | 
    
         
            -
                         
     | 
| 
       46 
     | 
    
         
            -
                         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                        wrapper_src = _lookup(fragment).source
         
     | 
| 
      
 50 
     | 
    
         
            +
                        inner_src = _lookup(:markup).source_body
         
     | 
| 
      
 51 
     | 
    
         
            +
                        wrapped_src = wrapper_src.gsub!(/\W_yield\W/, inner_src)
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                        fragment_src = if dont_wrap_if
         
     | 
| 
      
 54 
     | 
    
         
            +
                          %Q(-> {
         
     | 
| 
      
 55 
     | 
    
         
            +
              unless_block(Proc.from_source(#{dont_wrap_if.source.inspect}), alt: Proc.from_source(%q(-> {#{inner_src}}))) {
         
     | 
| 
      
 56 
     | 
    
         
            +
                #{Proc.from_source(wrapped_src).source_body}
         
     | 
| 
      
 57 
     | 
    
         
            +
              }
         
     | 
| 
      
 58 
     | 
    
         
            +
            })
         
     | 
| 
      
 59 
     | 
    
         
            +
                        else
         
     | 
| 
      
 60 
     | 
    
         
            +
                          wrapped_src
         
     | 
| 
       52 
61 
     | 
    
         
             
                        end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                        _store :markup, Proc.from_source(fragment_src)
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
       53 
65 
     | 
    
         
             
                      end
         
     | 
| 
       54 
66 
     | 
    
         | 
| 
       55 
67 
     | 
    
         
             
                      def wrapper_name(name = nil)
         
     | 
| 
         @@ -60,34 +72,6 @@ module ExpressTemplates 
     | 
|
| 
       60 
72 
     | 
    
         
             
                        end
         
     | 
| 
       61 
73 
     | 
    
         
             
                      end
         
     | 
| 
       62 
74 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                      # added back in for compatability with prior interface
         
     | 
| 
       64 
     | 
    
         
            -
                      # should probably be refactored away
         
     | 
| 
       65 
     | 
    
         
            -
                      def _wrap_using(fragment, context=nil, options={}, &to_be_wrapped)
         
     | 
| 
       66 
     | 
    
         
            -
                        old_wrapper_name = @wrapper_name
         
     | 
| 
       67 
     | 
    
         
            -
                        @wrapper_name = fragment
         
     | 
| 
       68 
     | 
    
         
            -
                        result = _wrap_it(context, options, &to_be_wrapped)
         
     | 
| 
       69 
     | 
    
         
            -
                        @wrapper_name = old_wrapper_name
         
     | 
| 
       70 
     | 
    
         
            -
                        return result
         
     | 
| 
       71 
     | 
    
         
            -
                      end
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                      def _wrap_it(context=nil, options={}, &to_be_wrapped)
         
     | 
| 
       74 
     | 
    
         
            -
                        body = ''
         
     | 
| 
       75 
     | 
    
         
            -
                        if to_be_wrapped
         
     | 
| 
       76 
     | 
    
         
            -
                          body = render((context||Object.new), &to_be_wrapped)
         
     | 
| 
       77 
     | 
    
         
            -
                        end
         
     | 
| 
       78 
     | 
    
         
            -
                        if compiled_src = _lookup(wrapper_name, options)
         
     | 
| 
       79 
     | 
    
         
            -
                          if context.nil?
         
     | 
| 
       80 
     | 
    
         
            -
                            eval(compiled_src).gsub(/\{\{_yield\}\}/, body)
         
     | 
| 
       81 
     | 
    
         
            -
                          else
         
     | 
| 
       82 
     | 
    
         
            -
                            ctx = context.instance_eval("binding")
         
     | 
| 
       83 
     | 
    
         
            -
                            ctx.local_variable_set(:_yield, body)
         
     | 
| 
       84 
     | 
    
         
            -
                            ctx.eval(compiled_src)
         
     | 
| 
       85 
     | 
    
         
            -
                          end
         
     | 
| 
       86 
     | 
    
         
            -
                        else
         
     | 
| 
       87 
     | 
    
         
            -
                          raise "No wrapper fragment provided for '#{wrapper_name}'"
         
     | 
| 
       88 
     | 
    
         
            -
                        end
         
     | 
| 
       89 
     | 
    
         
            -
                      end
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
75 
     | 
    
         
             
                      def _yield(*args)
         
     | 
| 
       92 
76 
     | 
    
         
             
                        "{{_yield}}"
         
     | 
| 
       93 
77 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ExpressTemplates
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Components
         
     | 
| 
      
 3 
     | 
    
         
            +
                class ForEach < Components::Container
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr :collection, :member
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(*args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    iterator = args.shift
         
     | 
| 
      
 8 
     | 
    
         
            +
                    options = args.first.kind_of?(Hash) ? args.shift : {}
         
     | 
| 
      
 9 
     | 
    
         
            +
                    expander = args.shift
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @collection, @member = nil, (options[:as]||"item")
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if iterator.kind_of?(Symbol)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @collection = iterator.to_s
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @member = collection.sub(/^@/, '').singularize
         
     | 
| 
      
 14 
     | 
    
         
            +
                    elsif iterator.kind_of?(Proc)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @collection = "(#{iterator.source}.call)"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    elsif iterator.kind_of?(String)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @collection = "(#{iterator}.call)"
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      raise "ForEach unknown iterator: #{iterator}"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def compile
         
     | 
| 
      
 24 
     | 
    
         
            +
                    %Q((#{@collection}.each_with_index.map do |#{@member}, #{@member}_index|#{compile_children}\nend).join)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ExpressTemplates
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Components
         
     | 
| 
      
 3 
     | 
    
         
            +
                #
         
     | 
| 
      
 4 
     | 
    
         
            +
                # Create an html <tt>form</tt> for a model object.
         
     | 
| 
      
 5 
     | 
    
         
            +
                #
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Example:
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # ```ruby
         
     | 
| 
      
 9 
     | 
    
         
            +
                # form_for(:people) do |t|
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   t.text_field  :name
         
     | 
| 
      
 11 
     | 
    
         
            +
                #   t.email_field :email
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   t.phone_field :phone
         
     | 
| 
      
 13 
     | 
    
         
            +
                # end
         
     | 
| 
      
 14 
     | 
    
         
            +
                # ```
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                class FormFor < Container
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     |