express_templates 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -6
- data/lib/core_extensions/proc.rb +42 -0
- data/lib/express_templates.rb +7 -2
- data/lib/express_templates/compiler.rb +27 -0
- data/lib/express_templates/components.rb +7 -4
- data/lib/express_templates/components/base.rb +54 -0
- data/lib/express_templates/components/capabilities/conditionality.rb +52 -0
- data/lib/express_templates/components/capabilities/configurable.rb +91 -0
- data/lib/express_templates/components/capabilities/iterating.rb +80 -0
- data/lib/express_templates/components/capabilities/parenting.rb +74 -0
- data/lib/express_templates/components/capabilities/rendering.rb +93 -0
- data/lib/express_templates/components/capabilities/templating.rb +196 -0
- data/lib/express_templates/components/capabilities/wrapping.rb +100 -0
- data/lib/express_templates/components/column.rb +13 -0
- data/lib/express_templates/components/container.rb +7 -0
- data/lib/express_templates/components/form_rails_support.rb +19 -0
- data/lib/express_templates/components/row.rb +28 -0
- data/lib/express_templates/expander.rb +51 -35
- data/lib/express_templates/indenter.rb +44 -0
- data/lib/express_templates/macro.rb +44 -0
- data/lib/express_templates/markup.rb +9 -0
- data/lib/express_templates/{components → markup}/html_tag.rb +9 -3
- data/lib/express_templates/markup/tag.rb +118 -0
- data/lib/express_templates/markup/wrapper.rb +88 -0
- data/lib/express_templates/{components → markup}/yielder.rb +2 -2
- data/lib/express_templates/renderer.rb +3 -8
- data/lib/express_templates/template/handler.rb +1 -1
- data/lib/express_templates/version.rb +1 -1
- data/lib/tasks/{gara_tasks.rake → express_templates.rake} +0 -0
- data/test/compiler_test.rb +9 -0
- data/test/components/base_test.rb +77 -0
- data/test/components/column_test.rb +11 -0
- data/test/components/conditionality_test.rb +37 -0
- data/test/components/configurable_test.rb +43 -0
- data/test/components/container_test.rb +49 -0
- data/test/components/iterating_test.rb +85 -0
- data/test/components/row_test.rb +16 -0
- data/test/core_extensions/proc_test.rb +41 -0
- data/test/dummy/log/test.log +72489 -0
- data/test/expander_test.rb +55 -13
- data/test/{gara_test.rb → express_templates_test.rb} +0 -0
- data/test/handler_test.rb +4 -4
- data/test/indenter_test.rb +25 -0
- data/test/markup/tag_test.rb +127 -0
- data/test/markup/wrapper_test.rb +42 -0
- data/test/markup/yielder_test.rb +9 -0
- data/test/performance_test.rb +2 -2
- data/test/test_helper.rb +6 -0
- metadata +78 -24
- data/lib/express_templates/component.rb +0 -92
- data/lib/express_templates/components/wrapper.rb +0 -51
- data/lib/express_templates/html5_emitter.rb +0 -45
- data/test/component_test.rb +0 -77
- data/test/wrapper_test.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00a0446a67ac0022ae2769db3a19f9c0399fa4c1
|
4
|
+
data.tar.gz: 5feea8d4b6a5732aec2f49edfc0ebd4024129f85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd40eaa5f1d713c36084fd91ae72c844cf129b83683aa4a15dd730cc4e5e05a50e2e360ca31eef7fc81b25596075caf9fb54d79af98ab67bbc5ef7f896de36f4
|
7
|
+
data.tar.gz: 873c79cbf53186da5931979d05f62183432ec14426f0f37a2984d9fac64f38ea1210a4156ce40e8fbcf454113bbb21a76141d75f64208a5716f0612083b6fc25
|
data/README.md
CHANGED
@@ -36,18 +36,22 @@ Set your editor syntax for .et files to Ruby.
|
|
36
36
|
|
37
37
|
ExpressTemplates works via a good-enough stand in for a true macro system in Ruby which would make this type of thing considerably easier.
|
38
38
|
|
39
|
-
Basically, we use these "macros" and Ruby's block structure to build up a tree of components corresponding to the HTML structure of a document fragment. Each HTML5 tag is a
|
39
|
+
Basically, we use these "macros" and Ruby's block structure to build up a tree of components corresponding to the HTML structure of a document fragment. Each HTML5 tag is a Component available in the form of a macro. Unrecognized identifiers are wrapped for later evaluation, presumably in a ViewContext.
|
40
40
|
|
41
|
-
yield and local variables which we may expect to be available in a
|
41
|
+
yield and local variables which we may expect to be available in a ViewContext are also wrapped for evaluation later.
|
42
|
+
|
43
|
+
Templates are first "expanded", then "compiled" and then finally "rendered."
|
44
|
+
|
45
|
+
Expanding results in a tree of Component like objects which have children and respond to #compile(). The result of #compile on a component is a Ruby code fragment which may be evaluated in a ViewContext to produce markup. Compiling is similar to what HAML or Erb does.
|
42
46
|
|
43
47
|
## Background
|
44
48
|
|
45
|
-
|
49
|
+
The bondage of HAML is unnecessary. The clutter of Erb is unsightly.
|
46
50
|
|
47
|
-
I
|
51
|
+
I generally prefer "one syntax per file" for reasons of cognative load and maintainability.
|
48
52
|
|
49
|
-
|
53
|
+
The introduction of an macro-like pre-processing step yielding a tree of Components as described above allows us to implement higher-level components which inherit behavior via normal OO Ruby. This points the way to a UX framework and component library that will play nice with Rails caching and conventions.
|
50
54
|
|
51
|
-
ExpressTemplates
|
55
|
+
ExpressTemplates form part of the AppExpress platform at [appexpress.io](http://appexpress.io).
|
52
56
|
|
53
57
|
This project rocks and uses MIT-LICENSE.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
require 'pp'
|
3
|
+
class Proc
|
4
|
+
|
5
|
+
TOKEN_PAIRS = {[:on_lbrace, '{'] => [:on_rbrace, '}'],
|
6
|
+
[:on_kw, 'do'] => [:on_kw, 'end'],
|
7
|
+
[:on_tlambeg, '{'] => [:on_rbrace, '}']}
|
8
|
+
|
9
|
+
# Make a best effort to provide the original source for a block
|
10
|
+
# based on extracting a string from the file identified in
|
11
|
+
# Proc#source_location using Ruby's tokenizer.
|
12
|
+
#
|
13
|
+
# This works for first block declared on a line in a source
|
14
|
+
# file. If additional blocks are specified inside the first block
|
15
|
+
# on the same line as the start of the block, only the outer-most
|
16
|
+
# block declaration will be identified as a the block we want.
|
17
|
+
#
|
18
|
+
# If you require only the source of blocks-within-other-blocks, start them
|
19
|
+
# on a new line as would be best practice for clarity and readability.
|
20
|
+
def source
|
21
|
+
file, line_no = source_location
|
22
|
+
raise "no line number provided for source_location: #{self}" if line_no.nil?
|
23
|
+
tokens = Ripper.lex File.read(file)
|
24
|
+
tokens_on_line = tokens.select {|pos, lbl, str| pos[0].eql?(line_no) }
|
25
|
+
starting_token = tokens_on_line.detect do |pos, lbl, str|
|
26
|
+
TOKEN_PAIRS.keys.include? [lbl, str]
|
27
|
+
end
|
28
|
+
starting_token_type = [starting_token[1], starting_token[2]]
|
29
|
+
ending_token_type = TOKEN_PAIRS[starting_token_type]
|
30
|
+
source_str = ""
|
31
|
+
remaining_tokens = tokens.slice(tokens.index(starting_token)..-1)
|
32
|
+
nesting = -1
|
33
|
+
while token = remaining_tokens.shift
|
34
|
+
source_str << token[2]
|
35
|
+
nesting += 1 if [token[1], token[2]] == starting_token_type
|
36
|
+
is_ending_token = [token[1], token[2]].eql?(ending_token_type)
|
37
|
+
break if is_ending_token && nesting.eql?(0)
|
38
|
+
nesting -= 1 if is_ending_token
|
39
|
+
end
|
40
|
+
source_str
|
41
|
+
end
|
42
|
+
end
|
data/lib/express_templates.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
module ExpressTemplates
|
2
|
+
require 'core_extensions/proc'
|
3
|
+
require 'express_templates/indenter'
|
4
|
+
require 'express_templates/macro'
|
5
|
+
require 'express_templates/markup'
|
6
|
+
require 'express_templates/components'
|
2
7
|
require 'express_templates/template/handler'
|
3
|
-
require 'express_templates/html5_emitter'
|
4
8
|
require 'express_templates/renderer'
|
5
9
|
require 'express_templates/expander'
|
6
|
-
require 'express_templates/
|
10
|
+
require 'express_templates/compiler'
|
7
11
|
extend Renderer
|
12
|
+
extend Compiler
|
8
13
|
if defined?(Rails)
|
9
14
|
::ActionView::Template.register_template_handler :et, ExpressTemplates::Template::Handler
|
10
15
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Compiler
|
3
|
+
def compile(template_or_src=nil, &block)
|
4
|
+
template, src = _normalize(template_or_src)
|
5
|
+
|
6
|
+
expander = Expander.new(template)
|
7
|
+
|
8
|
+
compiled = expander.expand(src, &block).map(&:compile)
|
9
|
+
|
10
|
+
return compiled.join("+").gsub('"+"', '').tap do |s|
|
11
|
+
puts("\n"+template.inspect+"\n"+s) if ENV['DEBUG'].eql?('true')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def _normalize(template_or_src)
|
17
|
+
template, src = nil, nil
|
18
|
+
if template_or_src.respond_to?(:source)
|
19
|
+
template = template_or_src
|
20
|
+
src = template_or_src.source
|
21
|
+
else
|
22
|
+
src = template_or_src
|
23
|
+
end
|
24
|
+
return template, src
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,7 +2,10 @@ module ExpressTemplates
|
|
2
2
|
module Components
|
3
3
|
end
|
4
4
|
end
|
5
|
-
|
6
|
-
require 'express_templates/
|
7
|
-
require 'express_templates/components/
|
8
|
-
require 'express_templates/components/
|
5
|
+
|
6
|
+
require 'express_templates/expander'
|
7
|
+
require 'express_templates/components/base'
|
8
|
+
require 'express_templates/components/container'
|
9
|
+
require 'express_templates/components/row'
|
10
|
+
require 'express_templates/components/column'
|
11
|
+
require 'express_templates/components/form_rails_support'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
capabilities = Dir.glob(File.join(File.dirname(__FILE__), 'capabilities', '*.rb'))
|
2
|
+
capabilities.each {|capability| require capability}
|
3
|
+
|
4
|
+
module ExpressTemplates
|
5
|
+
# Components provide self-contained reusable view code meant to be shared
|
6
|
+
# within a project or across many projects through a library of components
|
7
|
+
#
|
8
|
+
# Components gain their functionality through inclusion of Capabilities.
|
9
|
+
#
|
10
|
+
# Most Components are descendents of Components::Base.
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
|
14
|
+
# Components::Base is the base class for ExpressTemplates view components.
|
15
|
+
#
|
16
|
+
# View components are available as macros in ExpressTemplates and may be
|
17
|
+
# used to encapsulate common view patterns, behavior and functionality in
|
18
|
+
# reusable classes that can be shared within and across projects.
|
19
|
+
#
|
20
|
+
# Components intended to provide a base framework for a library of reusable
|
21
|
+
# components to cut development time across a multitude of projects.
|
22
|
+
#
|
23
|
+
# Components gain their functionality through including Capabilities.
|
24
|
+
#
|
25
|
+
# Example capabilities include:
|
26
|
+
#
|
27
|
+
# * Managing related ExpressTemplate fragments
|
28
|
+
# * Compiling template fragments for evaluation in a View Context
|
29
|
+
# * Specifying rendering logic to be executed in the View Context
|
30
|
+
# * Potentially referencing external assets that may be required
|
31
|
+
# for the component to work.
|
32
|
+
#
|
33
|
+
# Components::Base includes the following capabilities:
|
34
|
+
#
|
35
|
+
# * Capabilities::Templating
|
36
|
+
# * Capabilities::Rendering
|
37
|
+
# * Capabilities::Wrapping
|
38
|
+
# * Capabilities::Iterating
|
39
|
+
#
|
40
|
+
class Base
|
41
|
+
include ExpressTemplates::Macro
|
42
|
+
include Capabilities::Templating
|
43
|
+
include Capabilities::Rendering
|
44
|
+
include Capabilities::Wrapping
|
45
|
+
include Capabilities::Iterating
|
46
|
+
|
47
|
+
def self.inherited(klass)
|
48
|
+
ExpressTemplates::Expander.register_macros_for klass
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Capabilities
|
4
|
+
# Adds the capability for a component to only render
|
5
|
+
# its markup when a condition to be evaluated in the
|
6
|
+
# view is true.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# class PageHeader < ExpressTemplates::Components::Base
|
11
|
+
# include ExpressTemplates::Components::Capabilities::Conditionality
|
12
|
+
#
|
13
|
+
# emits {
|
14
|
+
# h1 { content_for(:page_header) }
|
15
|
+
# }
|
16
|
+
#
|
17
|
+
# only_if -> { content_for?(:page_header) }
|
18
|
+
#
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# The condition supplied to only if in the form of a proc
|
23
|
+
# is evaluated in the view context.
|
24
|
+
#
|
25
|
+
# The component will render an empty string if the proc returns false.
|
26
|
+
module Conditionality
|
27
|
+
def self.included(base)
|
28
|
+
base.class_eval do
|
29
|
+
extend ClassMethods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
|
35
|
+
def condition_proc
|
36
|
+
@condition_proc
|
37
|
+
end
|
38
|
+
|
39
|
+
def only_if condition_proc
|
40
|
+
@condition_proc = condition_proc
|
41
|
+
|
42
|
+
using_logic do |component, options|
|
43
|
+
condition = instance_exec(&component.condition_proc)
|
44
|
+
eval(component[:markup]) if condition
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Capabilities
|
4
|
+
|
5
|
+
# Configurable components accept options which they can use to alter
|
6
|
+
# their markup each time they are invoked within a template.
|
7
|
+
#
|
8
|
+
# They do not compile their markup fragments at load time as simpler
|
9
|
+
# components do for efficiency. Rather they compile their fragments
|
10
|
+
# when they are themselves undergoing compilation. This facilitates
|
11
|
+
# access to arguments which were passed to the component at initialization.
|
12
|
+
#
|
13
|
+
# For example, if we have a Row component that is Configurable:
|
14
|
+
#
|
15
|
+
# row(:main)
|
16
|
+
#
|
17
|
+
# might process to:
|
18
|
+
#
|
19
|
+
# <div id="main" class="row" />
|
20
|
+
#
|
21
|
+
|
22
|
+
module Configurable
|
23
|
+
def self.included(base)
|
24
|
+
base.class_eval do
|
25
|
+
extend ClassMethods
|
26
|
+
include InstanceMethods
|
27
|
+
|
28
|
+
# Stores arguments for later processing, eg., compile time
|
29
|
+
def initialize(*args)
|
30
|
+
@args = args.dup
|
31
|
+
@config = {}
|
32
|
+
_process_args!(args)
|
33
|
+
super(*args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# Override Templating._compile_fragment to delay compilation
|
43
|
+
def _compile_fragment(block, options = {})
|
44
|
+
if options.delete(:force_compile)
|
45
|
+
super(block, options)
|
46
|
+
else
|
47
|
+
block
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def _lookup(name, options = {})
|
52
|
+
super(name, options.merge(force_compile: true))
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
module InstanceMethods
|
58
|
+
|
59
|
+
def config
|
60
|
+
@config
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :my :config
|
64
|
+
|
65
|
+
def expand_locals
|
66
|
+
{my: config}
|
67
|
+
end
|
68
|
+
|
69
|
+
# Override Templating#lookup to pass locals
|
70
|
+
def lookup(fragment_name)
|
71
|
+
self.class.send(:_lookup, fragment_name, expand_locals)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def _process_args!(args)
|
78
|
+
if args.first.kind_of?(Symbol)
|
79
|
+
config.merge!(id: args.shift)
|
80
|
+
end
|
81
|
+
while arg = args.shift
|
82
|
+
if arg.kind_of?(Hash)
|
83
|
+
config.merge!(arg)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Capabilities
|
4
|
+
#
|
5
|
+
# Adds the capability to iterate over a collection repeating a markup
|
6
|
+
# fragment for each member.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# class ParagraphsComponent < ExpressTemplates::Components::Base
|
11
|
+
#
|
12
|
+
# emits -> { p { item } } # item is the default local variable name
|
13
|
+
#
|
14
|
+
# for_each -> { paragraphs } # evaluated in view context
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Must specify an <tt>iterator</tt> either as a proc to be evaluated in the
|
19
|
+
# view context or else as a variable name in the form of a symbol which is
|
20
|
+
# assumed to be available in the view context.
|
21
|
+
#
|
22
|
+
# Provides:
|
23
|
+
#
|
24
|
+
# * Iterating::ClassMethods (for_each)
|
25
|
+
#
|
26
|
+
module Iterating
|
27
|
+
def self.included(base)
|
28
|
+
base.class_eval do
|
29
|
+
extend ClassMethods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
# Sets the component up to use iterating logic to reproduce a fragment
|
35
|
+
# for a collection.
|
36
|
+
#
|
37
|
+
# Parameters include an iterator that may be :@variable assumed to be
|
38
|
+
# available in context or a proc that when evaluated in the context
|
39
|
+
# should return a collection.
|
40
|
+
#
|
41
|
+
# An <tt>:emit</tt> option may specify a fragment to emit.
|
42
|
+
# Defaults to <tt>:markup</tt>
|
43
|
+
#
|
44
|
+
# An <tt>:as</tt> option specifies the local variable name for each
|
45
|
+
# item in the collection for use in the fragment. Defaults to: <tt>item</tt>
|
46
|
+
#
|
47
|
+
# An <tt>:empty</tt> option specifies a fragment to use for the
|
48
|
+
# empty state when the iterator returns an empty collection.
|
49
|
+
def for_each(iterator, as: :item, emit: :markup, empty: nil)
|
50
|
+
if iterator.kind_of?(Symbol)
|
51
|
+
var_name = iterator.to_s.gsub(/^@/,'').singularize.to_sym
|
52
|
+
else
|
53
|
+
var_name = as
|
54
|
+
end
|
55
|
+
using_logic do |component, options|
|
56
|
+
collection = if iterator.kind_of?(Proc)
|
57
|
+
if iterator.arity.eql?(1)
|
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
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Capabilities
|
4
|
+
module Parenting
|
5
|
+
|
6
|
+
# Parenting adds the capability for a component to have and render
|
7
|
+
# children that may be specified in the template fragment which
|
8
|
+
# includes the component.
|
9
|
+
#
|
10
|
+
# Example parenting component:
|
11
|
+
#
|
12
|
+
# class Line < ExpressTemplates::Components::Base
|
13
|
+
# include Capabilities::Parenting
|
14
|
+
#
|
15
|
+
# emits { p.line { _yield } }
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# You might then use this component like so:
|
19
|
+
#
|
20
|
+
# line "In", "Xanadu", "did", "Kubla", "Khan"
|
21
|
+
# line { "A stately pleasure-dome decree :" }
|
22
|
+
# line { "Where Alph, the sacred river, ran" }
|
23
|
+
# line %q(Through caverns measureless to man)
|
24
|
+
# line %q|Down to a sunless sea.|
|
25
|
+
#
|
26
|
+
# Provides
|
27
|
+
#
|
28
|
+
# * ClassMethods for rendering
|
29
|
+
# * InstanceMethods for managing children
|
30
|
+
#
|
31
|
+
def self.included(base)
|
32
|
+
base.class_eval do
|
33
|
+
extend ClassMethods
|
34
|
+
include InstanceMethods
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
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
|
+
module InstanceMethods
|
48
|
+
def children
|
49
|
+
@children ||= []
|
50
|
+
end
|
51
|
+
|
52
|
+
def children=(children)
|
53
|
+
@children =children
|
54
|
+
end
|
55
|
+
|
56
|
+
def compile
|
57
|
+
locals = (expand_locals rescue nil).inspect
|
58
|
+
compiled_children = nil
|
59
|
+
args = %w(self)
|
60
|
+
args << locals
|
61
|
+
Indenter.for(:compile) do |indent, indent_with_newline|
|
62
|
+
compiled_children = children.map { |child| indent_with_newline + child.compile }.join("+")
|
63
|
+
compiled_children.gsub!('"+"', '') # avoid unnecessary string concatenation
|
64
|
+
args << compiled_children unless compiled_children.empty?
|
65
|
+
end
|
66
|
+
closing_paren = compiled_children.empty? ? ')' : "\n#{Indenter.for(:compile)})"
|
67
|
+
"#{self.class.to_s}.render_with_children(#{args.join(', ')}#{closing_paren}"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|