express_templates 0.11.10 → 0.11.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +45 -110
- data/lib/express_templates/compiler.rb +8 -3
- data/lib/express_templates/components/base.rb +14 -14
- data/lib/express_templates/components/forms/basic_fields.rb +0 -7
- data/lib/express_templates/components/forms/form_component.rb +1 -1
- data/lib/express_templates/template/handler.rb +0 -2
- data/lib/express_templates/version.rb +1 -1
- data/lib/express_templates.rb +2 -3
- data/test/dummy/app/views/hello/show.html.et +2 -2
- data/test/express_templates_test.rb +20 -0
- data/test/test_helper.rb +7 -3
- metadata +6 -30
- data/LICENSE +0 -21
- data/lib/express_templates/indenter.rb +0 -47
- data/lib/express_templates/interpolator.rb +0 -36
- data/test/indenter_test.rb +0 -27
- data/test/interpolator_test.rb +0 -80
- data/test/performance_test.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e40896f62363f0d0d56561edadcfc3bed0ff65c
|
4
|
+
data.tar.gz: eed5459b88dbba34fbbb3b333aa3d7b84deb7bb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 730210a7b8ea70b45d4668d7da93e0756e52f1e1a3771919b547e74e75958efac1baa6c374a100f04f9da7a710e9dde9265b76265daf704065d761c0c88bde16
|
7
|
+
data.tar.gz: e1d8537af4ef7094e9d29ae3b67f9083dfb3e14aa583849811b07ba741bf16b5cf1d684b55fa973cc469e8a5d4c4d319a4b50d0e1eadf3cbbd85902e0aeeeb87
|
data/README.md
CHANGED
@@ -1,142 +1,77 @@
|
|
1
|
-
|
1
|
+
## ExpressTemplates - Reusable view components in Ruby
|
2
2
|
|
3
|
-
|
3
|
+
### Write templates in Ruby
|
4
4
|
|
5
|
-
|
6
|
-
this gem now uses [ActiveAdmin's arbre](https://github.com/activeadmin/arbre). Arbre is widely
|
7
|
-
used as part of ActiveAdmin, has a long history and many contributors and is conceptually much simpler.
|
8
|
-
|
9
|
-
## Usage
|
10
|
-
|
11
|
-
Add this to your gemfile:
|
5
|
+
Use a declarative style of Ruby to write template code based on [Arbre](https://github.com/aelogica/arbre).
|
12
6
|
|
13
7
|
```ruby
|
14
|
-
|
8
|
+
content_for :title, "Hello, world"
|
9
|
+
|
10
|
+
div {
|
11
|
+
h1 "#{hello}"
|
12
|
+
p 'Find me in app/views/hello/show.html.et'
|
13
|
+
}
|
15
14
|
```
|
16
15
|
|
17
|
-
|
16
|
+
[Learn more](https://github.com/aelogica/express-gems/wiki/Express-Templates-HOWTO)
|
18
17
|
|
19
|
-
|
18
|
+
### Use Rails' form tag helpers
|
20
19
|
|
21
20
|
```ruby
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
title {
|
27
|
-
content_for(:title)
|
28
|
-
}
|
29
|
-
stylesheet_link_tag "application", media: 'all', 'data-turbolinks-track' => true
|
30
|
-
csrf_meta_tags
|
31
|
-
}
|
32
|
-
body {
|
33
|
-
current_arbre_element.add_child yield
|
34
|
-
javascript_include_tag "application"
|
21
|
+
form(action: invites_path, method: "POST") {
|
22
|
+
div(class: 'form-group') {
|
23
|
+
label_tag(:invite_code, "Invite Code:")
|
24
|
+
text_field_tag('invite_code', '', class: 'form-control')
|
35
25
|
}
|
36
26
|
}
|
37
27
|
```
|
38
28
|
|
39
|
-
|
40
|
-
|
41
|
-
Set your editor syntax for .et files to Ruby.
|
42
|
-
|
43
|
-
You can now utilize components which are found with documentation and examples in <tt>ExpressTemplates::Components</tt>.
|
44
|
-
|
45
|
-
Components are the real strength of both arbre and express_templates.
|
46
|
-
|
47
|
-
express_templates now *is* arbre + some components + some conventions. ExpressTemplates::Components::Base provides a little syntactic sugar in the form of the emits class method.
|
29
|
+
### Compose templates to build components
|
48
30
|
|
49
|
-
|
50
|
-
|
51
|
-
Control flow should only be used in Components. This is currently not enforced but it will be in the future.
|
52
|
-
|
53
|
-
The purpose of express_templates is to provide a foundation for a library of reusable UX components which we can enhance for drag-and-drop style UX construction and template editing.
|
54
|
-
|
55
|
-
## Dependencies
|
56
|
-
|
57
|
-
To set a label's "for" value, you must use a version of arbre that allows for this. Place this in your app:
|
31
|
+
Components are reusable pieces of user interface code. See [Express UI](https://github.com/express-gems/tree/master/express_ui).
|
58
32
|
|
59
33
|
```ruby
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
li %Q(#{@three})
|
76
|
-
}
|
34
|
+
class PageHeader < ExpressTemplates::Components::Base
|
35
|
+
|
36
|
+
contains -> {
|
37
|
+
if content_for?(:page_header)
|
38
|
+
h1 {
|
39
|
+
content_for(:page_header)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
if content_for?(:page_header_lead)
|
43
|
+
para(class: 'lead') {
|
44
|
+
content_for(:page_header_lead)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
77
49
|
```
|
78
50
|
|
79
|
-
|
51
|
+
[Learn more](https://example.com)
|
80
52
|
|
81
|
-
|
82
|
-
<ul>
|
83
|
-
<li>one</li>
|
84
|
-
<li>two</li>
|
85
|
-
<li>three</li>
|
86
|
-
</ul>
|
87
|
-
```
|
88
|
-
|
89
|
-
## Components
|
53
|
+
### Philosophy
|
90
54
|
|
91
|
-
|
55
|
+
1. It's just Ruby.
|
92
56
|
|
93
|
-
|
57
|
+
2. Write less markup code with reusable components.
|
94
58
|
|
95
|
-
|
59
|
+
[Learn more](https://example.com)
|
96
60
|
|
97
|
-
|
98
|
-
@list = %w(one two three)
|
99
|
-
```
|
61
|
+
### Download and installation
|
100
62
|
|
101
|
-
|
63
|
+
Download the latest version of ExpressTemplates from RubyGems:
|
102
64
|
|
103
|
-
```ruby
|
104
|
-
class ListComponent < ExpressTemplates::Components::Base
|
105
|
-
emits -> {
|
106
|
-
ul {
|
107
|
-
# assumes view provides list
|
108
|
-
list.each do |item|
|
109
|
-
li {
|
110
|
-
item
|
111
|
-
}
|
112
|
-
end
|
113
|
-
}
|
114
|
-
}
|
115
|
-
end
|
116
65
|
```
|
117
|
-
|
118
|
-
This would be used in a view template just as if it were a tag, like so:
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
div(class: "active") {
|
122
|
-
list_component
|
123
|
-
}
|
66
|
+
$ gem install express_templates
|
124
67
|
```
|
125
68
|
|
126
|
-
|
69
|
+
Source code is on GitHub as part of the express-gems project:
|
127
70
|
|
128
|
-
|
129
|
-
<div class="active">
|
130
|
-
<ul>
|
131
|
-
<li>one</li>
|
132
|
-
<li>two</li>
|
133
|
-
<li>three</li>
|
134
|
-
</ul>
|
135
|
-
</div>
|
136
|
-
```
|
71
|
+
* https://github.com/aelogica/express-gems/tree/master/express_templates
|
137
72
|
|
138
|
-
|
73
|
+
### License
|
139
74
|
|
140
|
-
ExpressTemplates is
|
75
|
+
ExpressTemplates is released under the MIT license:
|
141
76
|
|
142
|
-
|
77
|
+
* http://www.opensource.org/licenses/MIT
|
@@ -1,10 +1,15 @@
|
|
1
1
|
module ExpressTemplates
|
2
2
|
module Compiler
|
3
3
|
def compile(template_or_src=nil, &block)
|
4
|
-
|
5
4
|
template, src = _normalize(template_or_src)
|
6
|
-
|
7
|
-
|
5
|
+
%Q{
|
6
|
+
assigns.merge!(template_virtual_path: @virtual_path)
|
7
|
+
if defined?(local_assigns)
|
8
|
+
Arbre::Context.new(assigns.merge(local_assigns), self) { #{src || block.source_body} }.to_s
|
9
|
+
else
|
10
|
+
Arbre::Context.new(assigns, self) { #{src || block.source_body} }.to_s
|
11
|
+
end
|
12
|
+
}
|
8
13
|
end
|
9
14
|
|
10
15
|
private
|
@@ -7,9 +7,11 @@ module ExpressTemplates
|
|
7
7
|
#
|
8
8
|
module Components
|
9
9
|
|
10
|
-
# Components::Base is the base class for ExpressTemplates view components.
|
10
|
+
# ExpressTemplates::Components::Base is the base class for ExpressTemplates view components.
|
11
11
|
#
|
12
|
+
# Subclasses can attach hooks.
|
12
13
|
#
|
14
|
+
# An ET component may adopt other capabilities (e.g. support RESTful options).
|
13
15
|
class Base < Arbre::Component
|
14
16
|
|
15
17
|
class_attribute :before_build_hooks
|
@@ -32,9 +34,7 @@ module ExpressTemplates
|
|
32
34
|
|
33
35
|
abstract_component
|
34
36
|
|
35
|
-
#
|
36
|
-
# in Express Designer unless parent is present
|
37
|
-
#
|
37
|
+
# Define the parent component (i.e., can't be used in Express Designer unless parent is present)
|
38
38
|
@parent_component = nil
|
39
39
|
|
40
40
|
def self.require_parent(component)
|
@@ -46,14 +46,18 @@ module ExpressTemplates
|
|
46
46
|
@parent_component
|
47
47
|
end
|
48
48
|
|
49
|
+
# Defines an instance method using Arbre's BuilderMethods
|
50
|
+
#
|
51
|
+
# @param String method_name (component)
|
52
|
+
#
|
53
|
+
# @param Class klass
|
49
54
|
def self.builder_method_and_class(method_name, klass)
|
50
55
|
Arbre::Element::BuilderMethods.class_eval <<-EOF, __FILE__, __LINE__
|
51
|
-
def #{method_name}(*args, &block)
|
52
|
-
insert_tag ::#{klass.name}, *args, &block
|
53
|
-
end
|
56
|
+
def #{method_name}(*args, &block) # def checkbox(*args, &block)
|
57
|
+
insert_tag ::#{klass.name}, *args, &block # insert_tag ::Checkbox, *args, &block
|
58
|
+
end # end
|
54
59
|
EOF
|
55
60
|
self.builder_method_name = method_name
|
56
|
-
# puts "added #{method_name} -> #{klass.name}"
|
57
61
|
end
|
58
62
|
|
59
63
|
def initialize(*)
|
@@ -100,12 +104,9 @@ module ExpressTemplates
|
|
100
104
|
}
|
101
105
|
end
|
102
106
|
|
103
|
-
def resource
|
104
|
-
helpers.resource
|
105
|
-
end
|
106
|
-
|
107
107
|
def self.inherited(subclass)
|
108
|
-
|
108
|
+
method_name = subclass.to_s.demodulize.underscore
|
109
|
+
subclass.builder_method_and_class(method_name, subclass)
|
109
110
|
end
|
110
111
|
|
111
112
|
def self.builder_method(name)
|
@@ -149,7 +150,6 @@ module ExpressTemplates
|
|
149
150
|
def self._default_classes=(classes)
|
150
151
|
@default_classes = classes
|
151
152
|
end
|
152
|
-
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
@@ -21,13 +21,6 @@ RUBY
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
# class Email < FormComponent
|
25
|
-
# contains {
|
26
|
-
# label_tag label_name, label_text
|
27
|
-
# email_field field_name_attribute, field_value, field_helper_options
|
28
|
-
# }
|
29
|
-
# end
|
30
|
-
|
31
24
|
class File < FormComponent
|
32
25
|
contains {
|
33
26
|
label_tag(label_name, label_text)
|
@@ -8,8 +8,6 @@ module ExpressTemplates
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(template)
|
11
|
-
# call ripper stuff method
|
12
|
-
|
13
11
|
# returns a string to be eval'd
|
14
12
|
source = "(#{ExpressTemplates.compile(template)}).html_safe"
|
15
13
|
warn_contains_logic(source) if ENV['NO_TEMPLATE_WARN'].nil? # pass the source code
|
data/lib/express_templates.rb
CHANGED
@@ -3,16 +3,15 @@ module ExpressTemplates
|
|
3
3
|
require 'arbre/patches'
|
4
4
|
require 'core_extensions/proc'
|
5
5
|
require 'core_extensions/string'
|
6
|
-
require 'express_templates/indenter'
|
7
6
|
require 'express_templates/components'
|
8
7
|
require 'express_templates/template/handler'
|
9
8
|
require 'express_templates/renderer'
|
10
9
|
require 'express_templates/compiler'
|
11
|
-
|
10
|
+
|
12
11
|
extend Renderer
|
13
12
|
extend Compiler
|
13
|
+
|
14
14
|
if defined?(Rails)
|
15
15
|
::ActionView::Template.register_template_handler :et, ExpressTemplates::Template::Handler
|
16
16
|
end
|
17
|
-
|
18
17
|
end
|
@@ -20,4 +20,24 @@ class ExpressTemplatesTest < ActiveSupport::TestCase
|
|
20
20
|
assert_equal "<ul>\n <li>one</li>\n <li>two</li>\n <li>three</li>\n</ul>\n", result
|
21
21
|
end
|
22
22
|
|
23
|
+
test "ExpressTemplates.render renders a template with local_assigns" do
|
24
|
+
class Foo
|
25
|
+
def assigns
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
|
29
|
+
def local_assigns
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
f = Foo.new
|
35
|
+
|
36
|
+
result = ExpressTemplates.render(f) do
|
37
|
+
para { 'All your base are belong to us.' }
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_equal "<p>All your base are belong to us.</p>\n", result
|
41
|
+
end
|
42
|
+
|
23
43
|
end
|
data/test/test_helper.rb
CHANGED
@@ -21,7 +21,6 @@ end
|
|
21
21
|
ECB = ExpressTemplates::Components::Base
|
22
22
|
ETC = ExpressTemplates::Components
|
23
23
|
ET = ExpressTemplates
|
24
|
-
Interpolator = ExpressTemplates::Interpolator
|
25
24
|
|
26
25
|
require 'arbre'
|
27
26
|
Tag = Arbre::HTML::Tag
|
@@ -47,7 +46,6 @@ end
|
|
47
46
|
|
48
47
|
module ActiveSupport
|
49
48
|
class TestCase
|
50
|
-
|
51
49
|
class Context
|
52
50
|
def assigns
|
53
51
|
{}
|
@@ -61,12 +59,15 @@ module ActiveSupport
|
|
61
59
|
def arbre(additional_assigns = {}, &block)
|
62
60
|
Arbre::Context.new assigns.merge(additional_assigns), helpers, &block
|
63
61
|
end
|
62
|
+
|
64
63
|
def assigns
|
65
64
|
@arbre_assigns ||={}
|
66
65
|
end
|
66
|
+
|
67
67
|
def helpers
|
68
68
|
mock_action_view
|
69
69
|
end
|
70
|
+
|
70
71
|
def mock_action_view &block
|
71
72
|
controller = ActionView::TestCase::TestController.new
|
72
73
|
ActionView::Base.send :include, ActionView::Helpers
|
@@ -91,7 +92,6 @@ module ActiveSupport
|
|
91
92
|
gender: 'Male'
|
92
93
|
)
|
93
94
|
end
|
94
|
-
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -190,3 +190,7 @@ end
|
|
190
190
|
false
|
191
191
|
end
|
192
192
|
end
|
193
|
+
|
194
|
+
# Setup code coverage
|
195
|
+
require 'simplecov'
|
196
|
+
SimpleCov.start if ENV["COVERAGE"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: express_templates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Talcott Smith
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -25,20 +25,6 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '4.2'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: parslet
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - "~>"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '1.6'
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '1.6'
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: arbre
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,9 +151,7 @@ dependencies:
|
|
165
151
|
- - ">="
|
166
152
|
- !ruby/object:Gem::Version
|
167
153
|
version: '0'
|
168
|
-
description:
|
169
|
-
declartive style of Ruby. With ExpressTemplates you may easily create a library
|
170
|
-
of components for use across projects.
|
154
|
+
description: Write templates in Ruby for building reusable view components
|
171
155
|
email:
|
172
156
|
- steve@aelogica.com
|
173
157
|
- eumir@aelogica.com
|
@@ -175,7 +159,6 @@ executables: []
|
|
175
159
|
extensions: []
|
176
160
|
extra_rdoc_files: []
|
177
161
|
files:
|
178
|
-
- LICENSE
|
179
162
|
- README.md
|
180
163
|
- Rakefile
|
181
164
|
- lib/arbre/patches.rb
|
@@ -201,8 +184,6 @@ files:
|
|
201
184
|
- lib/express_templates/components/forms/select_collection.rb
|
202
185
|
- lib/express_templates/components/forms/submit.rb
|
203
186
|
- lib/express_templates/components/tree_for.rb
|
204
|
-
- lib/express_templates/indenter.rb
|
205
|
-
- lib/express_templates/interpolator.rb
|
206
187
|
- lib/express_templates/renderer.rb
|
207
188
|
- lib/express_templates/template/handler.rb
|
208
189
|
- lib/express_templates/version.rb
|
@@ -257,9 +238,6 @@ files:
|
|
257
238
|
- test/dummy/test/helpers/hello_helper_test.rb
|
258
239
|
- test/express_templates_test.rb
|
259
240
|
- test/handler_test.rb
|
260
|
-
- test/indenter_test.rb
|
261
|
-
- test/interpolator_test.rb
|
262
|
-
- test/performance_test.rb
|
263
241
|
- test/test_helper.rb
|
264
242
|
homepage: https://github.com/aelogica/express_templates
|
265
243
|
licenses:
|
@@ -281,10 +259,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
281
259
|
version: '0'
|
282
260
|
requirements: []
|
283
261
|
rubyforge_project:
|
284
|
-
rubygems_version: 2.
|
262
|
+
rubygems_version: 2.5.1
|
285
263
|
signing_key:
|
286
264
|
specification_version: 4
|
287
|
-
summary:
|
265
|
+
summary: Reusable view components
|
288
266
|
test_files:
|
289
267
|
- test/compiler_test.rb
|
290
268
|
- test/components/base_test.rb
|
@@ -336,7 +314,5 @@ test_files:
|
|
336
314
|
- test/dummy/test/helpers/hello_helper_test.rb
|
337
315
|
- test/express_templates_test.rb
|
338
316
|
- test/handler_test.rb
|
339
|
-
- test/indenter_test.rb
|
340
|
-
- test/interpolator_test.rb
|
341
|
-
- test/performance_test.rb
|
342
317
|
- test/test_helper.rb
|
318
|
+
has_rdoc:
|
data/LICENSE
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2014 ÆLOGICA | Build it better here.
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module ExpressTemplates
|
2
|
-
|
3
|
-
# Tracks current indent level scoped to the current thread.
|
4
|
-
#
|
5
|
-
# May be used to track multiple indents simultaneously through
|
6
|
-
# namespacing.
|
7
|
-
class Indenter
|
8
|
-
|
9
|
-
DEFAULT = 2
|
10
|
-
WHITESPACE = " "*DEFAULT
|
11
|
-
|
12
|
-
# Returns whitespace for the named indenter or yields to a block
|
13
|
-
# for the named indentor.
|
14
|
-
#
|
15
|
-
# The block is passed the current whitespace indent.
|
16
|
-
#
|
17
|
-
# For convenience an optional second parameter is passed to the block
|
18
|
-
# containing a newline at the beginning of the indent.
|
19
|
-
def self.for name
|
20
|
-
if block_given?
|
21
|
-
current_indenters[name] += 1
|
22
|
-
begin
|
23
|
-
indent = WHITESPACE * current_indenters[name]
|
24
|
-
yield indent, "\n#{indent}"
|
25
|
-
ensure
|
26
|
-
if current_indenters[name].eql?(-1)
|
27
|
-
# if we have long-lived threads for some reason
|
28
|
-
# we want to clean up after ourselves
|
29
|
-
current_indenters.delete(name)
|
30
|
-
else
|
31
|
-
current_indenters[name] -= 1
|
32
|
-
end
|
33
|
-
end
|
34
|
-
else
|
35
|
-
return WHITESPACE * current_indenters[name]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
# For thread safety, scope indentation to the current thread
|
41
|
-
def self.current_indenters
|
42
|
-
Thread.current[:indenters] ||= Hash.new {|hsh, key| hsh[key] = -1 }
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'parslet'
|
2
|
-
|
3
|
-
module ExpressTemplates
|
4
|
-
class Interpolator < Parslet::Parser
|
5
|
-
rule(:lbrace) { str('{{') }
|
6
|
-
rule(:rbrace) { str('}}') }
|
7
|
-
rule(:delim) { lbrace | rbrace }
|
8
|
-
rule(:lpart) { (lbrace.absnt? >> any).repeat.as(:lpart) }
|
9
|
-
rule(:rpart) { (rbrace.absnt? >> any).repeat.as(:rpart) }
|
10
|
-
rule(:expression) { (text_with_interpolations).as(:expression) }
|
11
|
-
rule(:interpolation) { (lbrace>>expression>>rbrace).as(:interpolation) }
|
12
|
-
rule(:text) { (delim.absnt? >> any).repeat(1) }
|
13
|
-
rule(:text_with_interpolations) { (text.as(:text) | interpolation).repeat }
|
14
|
-
root(:text_with_interpolations)
|
15
|
-
|
16
|
-
def self.transform(s)
|
17
|
-
begin
|
18
|
-
Transformer.new.apply(new.parse(s)).flatten.join
|
19
|
-
rescue Parslet::ParseFailed => failure
|
20
|
-
puts s
|
21
|
-
puts failure.cause.ascii_tree
|
22
|
-
raise failure
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class Transformer < Parslet::Transform
|
28
|
-
rule(:interpolation => simple(:expression)) {
|
29
|
-
'#{'+expression+'}'
|
30
|
-
}
|
31
|
-
rule(:expression => sequence(:exp)) do
|
32
|
-
exp.map(&:to_s).join.gsub('\\"', '"')
|
33
|
-
end
|
34
|
-
rule(:text => simple(:s)) { s.to_s }
|
35
|
-
end
|
36
|
-
end
|
data/test/indenter_test.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class IndenterTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
Indenter = ExpressTemplates::Indenter
|
6
|
-
|
7
|
-
test ".for(:name) takes a block receiving whitespace" do
|
8
|
-
Indenter.for(:foo) do
|
9
|
-
assert_equal "\n ", Indenter.for(:foo) { |indent, indent_with_newline| indent_with_newline }
|
10
|
-
assert_equal " ", Indenter.for(:foo) { |indent, indent_with_newline| indent }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
test "nesting blocks increases whitespace accordingly" do
|
15
|
-
nested_whitespace = Indenter.for(:foo) do |ws1|
|
16
|
-
Indenter.for(:foo) do |ws2|
|
17
|
-
ws2
|
18
|
-
end
|
19
|
-
end
|
20
|
-
assert_equal " ", nested_whitespace
|
21
|
-
end
|
22
|
-
|
23
|
-
test ".for(:name) returns current indent without newline when block is not given" do
|
24
|
-
assert_equal "", Indenter.for(:foo) { |_| Indenter.for(:foo) }
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
data/test/interpolator_test.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'express_templates/interpolator'
|
3
|
-
require 'parslet/convenience'
|
4
|
-
|
5
|
-
class InterpolatorTest < ActiveSupport::TestCase
|
6
|
-
|
7
|
-
def parse(s)
|
8
|
-
parser = ExpressTemplates::Interpolator.new
|
9
|
-
parsed = parser.parse_with_debug(s)
|
10
|
-
pp parsed if ENV['DEBUG'].eql?('true')
|
11
|
-
parsed
|
12
|
-
end
|
13
|
-
|
14
|
-
def transform(s)
|
15
|
-
trans = ExpressTemplates::Transformer.new
|
16
|
-
trans.apply(parse(s)).flatten.join
|
17
|
-
end
|
18
|
-
|
19
|
-
test "simplest expression parses" do
|
20
|
-
tree = parse("{{something}}")
|
21
|
-
expected = [{:interpolation=>{:expression=>[{:text=>"something"}]}}]
|
22
|
-
assert_equal expected, tree
|
23
|
-
end
|
24
|
-
|
25
|
-
test "simple expression with surrounding text parses" do
|
26
|
-
tree = parse('whatever {{something}} something else')
|
27
|
-
expected = [{:text=>"whatever "},
|
28
|
-
{:interpolation=>{:expression=>[{:text=>"something"}]}},
|
29
|
-
{:text=>" something else"}]
|
30
|
-
assert_equal expected, tree
|
31
|
-
end
|
32
|
-
|
33
|
-
test "nested without outer text parses" do
|
34
|
-
tree = parse('{{some {{thing}} foo}}')
|
35
|
-
expected = [{:interpolation=>
|
36
|
-
{:expression=>
|
37
|
-
[{:text=>"some "},
|
38
|
-
{:interpolation=>{:expression=>[{:text=>"thing"}]}},
|
39
|
-
{:text=>" foo"}]}}]
|
40
|
-
assert_equal expected, tree
|
41
|
-
end
|
42
|
-
|
43
|
-
test "nested with outer text parses" do
|
44
|
-
tree = parse('a lot of {{something {{good}}}}')
|
45
|
-
expected = [{:text=>"a lot of "},
|
46
|
-
{:interpolation=>
|
47
|
-
{:expression=>
|
48
|
-
[{:text=>"something "},
|
49
|
-
{:interpolation=>{:expression=>[{:text=>"good"}]}}]}}]
|
50
|
-
assert_equal expected, tree
|
51
|
-
end
|
52
|
-
|
53
|
-
test 'nested with multiple nested expressions parses' do
|
54
|
-
tree = parse(%q(%Q({{foo("{{xyz}}", "{{zyx}}", bar: "baz")}})))
|
55
|
-
expected = [{:text=>"%Q("},
|
56
|
-
{:interpolation=>
|
57
|
-
{:expression=>
|
58
|
-
[{:text=>"foo(\""},
|
59
|
-
{:interpolation=>{:expression=>[{:text=>"xyz"}]}},
|
60
|
-
{:text=>"\", \""},
|
61
|
-
{:interpolation=>{:expression=>[{:text=>"zyx"}]}},
|
62
|
-
{:text=>"\", bar: \"baz\")"}]}},
|
63
|
-
{:text=>")"}]
|
64
|
-
assert_equal expected, tree
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
test '"{{something}}" transforms to "#{something}"' do
|
69
|
-
assert_equal '#{something}', transform("{{something}}")
|
70
|
-
end
|
71
|
-
|
72
|
-
test '"{{some {{thing}} foo}}" transforms to "#{some #{thing} foo}"' do
|
73
|
-
assert_equal '#{some #{thing} foo}', transform("{{some {{thing}} foo}}")
|
74
|
-
end
|
75
|
-
|
76
|
-
test %('a lot of {{something "{{good}}"}}' transforms) do
|
77
|
-
assert_equal 'a lot of #{something "#{good}"}', transform('a lot of {{something "{{good}}"}}')
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
data/test/performance_test.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'haml'
|
3
|
-
|
4
|
-
class PerformanceTest < ActiveSupport::TestCase
|
5
|
-
|
6
|
-
GARA_EXAMPLE =<<-RUBY
|
7
|
-
html(lang: "en") {
|
8
|
-
head {
|
9
|
-
meta charset: 'utf-8'
|
10
|
-
meta name: 'viewport', content: "width=device-width, initial-scale=1.0"
|
11
|
-
stylesheet_link_tag "application", media: 'all', 'data-turbolinks-track' => true
|
12
|
-
csrf_meta_tags
|
13
|
-
}
|
14
|
-
body {
|
15
|
-
h1 "Hello"
|
16
|
-
para "Some text"
|
17
|
-
javascript_include_tag "application"
|
18
|
-
}
|
19
|
-
}
|
20
|
-
RUBY
|
21
|
-
|
22
|
-
ERB_EXAMPLE = <<-ERB
|
23
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
24
|
-
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
25
|
-
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
26
|
-
<meta charset="utf-8" />
|
27
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
28
|
-
<%= stylesheet_link_tag 'application' %>
|
29
|
-
<%= csrf_meta_tags %>
|
30
|
-
</head>
|
31
|
-
<body>
|
32
|
-
<h1>Hello</h1>
|
33
|
-
<p>Some text</p>
|
34
|
-
<%= javascript_include_tag 'application' %>
|
35
|
-
</body>
|
36
|
-
</html>
|
37
|
-
ERB
|
38
|
-
|
39
|
-
HAML_EXAMPLE = <<-HAML
|
40
|
-
%html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => "en", 'xml:lang' => "en"}
|
41
|
-
%head
|
42
|
-
%meta{'http-equiv' => "Content-Type", 'content' => "text/html; charset=UTF-8"}
|
43
|
-
%meta{ 'charset' => 'utf-8'}
|
44
|
-
%meta{'name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'}
|
45
|
-
= stylesheet_link_tag 'application'
|
46
|
-
= csrf_meta_tags
|
47
|
-
%body
|
48
|
-
%h1 Hello
|
49
|
-
%p Some text
|
50
|
-
= javascript_include_tag 'application'
|
51
|
-
HAML
|
52
|
-
# class Context
|
53
|
-
def javascript_include_tag(name, *args)
|
54
|
-
%Q(<script data-turbolinks-track="true" src="/assets/#{name}.js"></script>)
|
55
|
-
end
|
56
|
-
|
57
|
-
def stylesheet_link_tag(name, *args)
|
58
|
-
%Q(<link data-turbolinks-track="true" href="/assets/#{name}.css" media="all" rel="stylesheet" />)
|
59
|
-
end
|
60
|
-
def csrf_meta_tags
|
61
|
-
%Q(<meta content="authenticity_token" name="csrf-param" />
|
62
|
-
<meta content="NF7iiBSErALM5A24Iw07wMH9e8rzxehE50Sv6iPYo98=" name="csrf-token" />
|
63
|
-
)
|
64
|
-
end
|
65
|
-
# end
|
66
|
-
|
67
|
-
def assigns
|
68
|
-
{}
|
69
|
-
end
|
70
|
-
|
71
|
-
def measure_time(count)
|
72
|
-
start_time = Time.now
|
73
|
-
1.upto(100) { yield }
|
74
|
-
end_time = Time.now
|
75
|
-
return end_time - start_time
|
76
|
-
end
|
77
|
-
|
78
|
-
# test "performance is okay" do
|
79
|
-
# duration = measure_time(100) { ExpressTemplates.render(self, "#{GARA_EXAMPLE}") }
|
80
|
-
# assert_operator 1.0, :>, duration
|
81
|
-
# end
|
82
|
-
|
83
|
-
# test "performance no more than 3.5x slower than erubis" do
|
84
|
-
# eruby = Erubis::Eruby.new
|
85
|
-
# duration_erb = measure_time(100) { eval(eruby.convert(ERB_EXAMPLE)) }
|
86
|
-
# duration_express_templates = measure_time(100) { ExpressTemplates.render(self, "#{GARA_EXAMPLE}") }
|
87
|
-
# assert_operator 4.0, :>, (duration_express_templates/duration_erb)
|
88
|
-
# end
|
89
|
-
|
90
|
-
# test "performance better than haml" do
|
91
|
-
# duration_haml = measure_time(100) { Haml::Engine.new(HAML_EXAMPLE).render(self) }
|
92
|
-
# duration_express_templates = measure_time(100) { ExpressTemplates.render(self, "#{GARA_EXAMPLE}") }
|
93
|
-
# assert_operator 0.5, :>, (duration_express_templates/duration_haml)
|
94
|
-
# end
|
95
|
-
|
96
|
-
end
|
97
|
-
|