hmote 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6f391daf28188242490899c275ffeae71b3aab6
4
- data.tar.gz: bc569d4bb4e614bc7a6ddbeeee38e8cb5dbecf7d
3
+ metadata.gz: 2bd46a8c3c5b7fdccdbc4bc125330763de517667
4
+ data.tar.gz: a049d0e48e684f6471b1fec0a4f1354c40263e30
5
5
  SHA512:
6
- metadata.gz: f367bf5d0fe6fecd1a5276f4ea1a22d89f5dac7b9712f45a5097f38db2b6b5cb660e4d0e399c06d5f745782001ccf00bdaee4e23dcccc6f2da889c6a30085974
7
- data.tar.gz: 63b4f9a3d394726212b89d3fa0a0182db3c38c1e147b0b6afdc93df74eba11da454ff06d12d95a058382085341705b9495294efc84ef9c94f212cfe632cd2dba
6
+ metadata.gz: 99f43f5f506bdbbf8e9613c1e1bd8f5239ff90fae229c9976b7d08d9365109bc0f76d89aaa09e34e0d984420c6f040087f5c5520b06411cd007579affb2f9903
7
+ data.tar.gz: 262abfe709226712b17c044a1b5567b3a5d66b9a5c51773a4a9ece75e43fe745a94830ee27cf7e94766cb00fec1be5ccc20f79489c4831fda93806fafb0f70d0
data/.gems CHANGED
@@ -1,2 +1,4 @@
1
- cutest -v 1.2.1
1
+ cutest -v 1.2.2
2
2
  hache -v 1.1.0
3
+ cuba -v 3.3.0
4
+ rack-test -v 0.6.2
data/LICENSE CHANGED
@@ -1,5 +1,4 @@
1
- Copyright (c) 2014 Francesco Rodríguez
2
- Copyright (c) 2011-2014 Michel Martens
1
+ Copyright (c) 2014-Present Francesco Rodríguez, Mayn Kjær
3
2
 
4
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,29 +1,202 @@
1
1
  hmote
2
2
  =====
3
3
 
4
- Minimum Operational Template. Same as [mote][mote] but it escapes HTML
5
- tag characters by default. It uses [hache][hache] to do the escaping.
4
+ Minimal template engine with default escaping.
6
5
 
7
- Usage
8
- -----
6
+ Basic Usage
7
+ -----------
9
8
 
10
- HMote escapes tag characters by default:
9
+ This is a basic example:
11
10
 
12
11
  ```ruby
13
- {{ '<img src="img.jpeg">' }}
14
- # => &lt;img src=&quot;img.jpeg&quot;&gt;
12
+ require "hmote"
13
+
14
+ template = HMote.parse("your template goes here!")
15
+ template.call
16
+ # => "your template goes here!"
17
+ ```
18
+
19
+ HMote recognizes two tags to evaluate Ruby code: `%` and `{{}}`.
20
+ The difference between them is that while the `%` tag only evaluates
21
+ the code, the `{{}}` tag also prints the result to the template.
22
+
23
+ Imagine that your template looks like this:
24
+
25
+ ```ruby
26
+ % gems = ["rack", "cuba", "hmote"]
27
+
28
+ <ul>
29
+ % # this is a comment.
30
+ % gems.sort.each do |gem|
31
+ <li>{{ gem }}</li>
32
+ % end
33
+ </ul>
34
+ ```
35
+
36
+ The generated result will be:
37
+
38
+ ```html
39
+ <ul>
40
+ <li>cuba</li>
41
+ <li>hmote</li>
42
+ <li>rack</li>
43
+ </ul>
44
+ ```
45
+
46
+ Parameters
47
+ ----------
48
+
49
+ The values passed to the template are available as local variables:
50
+
51
+ ```ruby
52
+ template = HMote.parse("Hello {{ name }}", self, [:name])
53
+ template.call(name: "Ruby")
54
+ # => Hello Ruby
55
+ ```
56
+
57
+ You can also use the `params` local variable to access the given
58
+ parameters:
59
+
60
+ ```ruby
61
+ template = HMote.parse("Hello {{ params[:name] }}", self)
62
+ template.call(name: "Ruby")
63
+ # => Hello Ruby
64
+ ```
65
+
66
+ Auto-escaping
67
+ -------------
68
+
69
+ By default, HMote escapes HTML special characters to prevent [XSS][xss]
70
+ attacks. You can start the expression with an exclamation mark to disable
71
+ escaping for that expression:
72
+
73
+ ```ruby
74
+ template = HMote.parse("Hello {{ name }}", self, [:name])
75
+ template.call(name: "<b>World</b>")
76
+ # => Hello &lt;b&gt;World&lt;b&gt;
77
+
78
+ template = HMote.parse("Hello {{! name }}", self, [:name])
79
+ template.call(name: "<b>World</b>")
80
+ # => Hello <b>World</b>
81
+ ```
82
+
83
+ HMote::Helpers
84
+ --------------
85
+
86
+ There's a helper available in the `HMote::Helpers` module, and you are
87
+ free to include it in your code. To do it, just type:
88
+
89
+ ```ruby
90
+ include HMote::Helpers
91
+ ```
92
+
93
+ ### Using the hmote helper
94
+
95
+ The `hmote` helper receives a file name and a hash and returns the rendered
96
+ version of its content. The compiled template is cached for subsequent calls.
97
+
98
+ ```ruby
99
+ hmote("test/basic.mote", n: 3)
100
+ # => "***\n"
15
101
  ```
16
102
 
17
- If you want to print content without escaping, then add `>` as
18
- shown below:
103
+ ### Template caching
104
+
105
+ When the `hmote` helper is first called with a template name, the
106
+ file is read and parsed, and a proc is created and stored in the
107
+ current thread. The parameters passed are defined as local variables
108
+ in the template. If you want to provide more parameters once the template
109
+ was cached, you won't be able to access the values as local variables,
110
+ but you can always access the `params` hash.
111
+
112
+ For example:
19
113
 
20
114
  ```ruby
21
- {{> '<img src="img.jpeg">' }}
22
- # => <img src="img.jpeg">
115
+ # First call
116
+ hmote("foo.mote", a: 1, b: 2)
23
117
  ```
24
118
 
25
- For more information about the usage, check the
26
- [Mote project homepage](https://github.com/soveran/mote).
119
+ HMote::Render
120
+ -------------
121
+
122
+ To use HMote in [Cuba][cuba], you need to load the `HMote::Render`
123
+ plugin as shown below:
124
+
125
+ ```ruby
126
+ require "hmote"
127
+ require "hmote/render"
128
+
129
+ Cuba.plugin(HMote::Render)
130
+ ```
131
+
132
+ `HMote::Render` provides three helper methods for rendering templates:
133
+ `partial`, `view` and `render`.
134
+
135
+ ```ruby
136
+ Cuba.define do
137
+ on "about" do
138
+ # `partial` renders a template without a layout.
139
+ res.write partial("about")
140
+ end
141
+
142
+ on "home" do
143
+ # `view` renders a template within a layout.
144
+ res.write view("about")
145
+ end
146
+
147
+ on "contact" do
148
+ # `render` is a shortcut to `res.write view(...)`
149
+ render("contact")
150
+ end
151
+ end
152
+ ```
153
+
154
+ By default, `HMote::Render` assumes that all view templates are placed
155
+ in a folder named `views` and that they use the `.mote` extension. Also
156
+ for `view` and `render` methods, it assumes that the layout template is
157
+ called `layout.mote`.
158
+
159
+ The defaults can be changed through the `Cuba.settings` method:
160
+
161
+ ```ruby
162
+ Cuba.settings[:hmote][:views] = "./views/admin/"
163
+ Cuba.settings[:hmote][:layout] = "admin"
164
+ ```
165
+
166
+ ### Layouts
167
+
168
+ To render inner content into a layout, use the `{{! content }}` tag.
169
+
170
+ ```html
171
+ <html>
172
+ <head>
173
+ <title>Mote Layout</title>
174
+ </head>
175
+ <body>
176
+ <h1>Hello, world!</h1>
177
+
178
+ {{! content }}
179
+ </body>
180
+ </html>
181
+ ```
182
+
183
+ ### Helpers
184
+
185
+ You can use the `app` variable to access the application helpers.
186
+
187
+ ```ruby
188
+ Cuba.define do
189
+ def h(unsafe)
190
+ ...
191
+ end
192
+ end
193
+ ```
194
+
195
+ ```html
196
+ <h1>{{! app.h("unsafe") }}</h1>
197
+
198
+ {{ app.partial("list") }}
199
+ ```
27
200
 
28
201
  Installation
29
202
  ------------
@@ -32,5 +205,5 @@ Installation
32
205
  $ gem install hmote
33
206
  ```
34
207
 
35
- [mote]: https://github.com/soveran/mote
36
- [hache]: https://github.com/frodsan/hache
208
+ [cuba]: http://cuba.is
209
+ [xss]: http://en.wikipedia.org/wiki/Cross-Site_Scripting
data/benchmarks/.gems ADDED
@@ -0,0 +1,2 @@
1
+ actionview -v 4.1.8
2
+ benchmark-ips -v 2.1.0
@@ -0,0 +1,17 @@
1
+ require_relative "helper"
2
+ require_relative "hmote_helper"
3
+ require_relative "rails_helper"
4
+
5
+ text = %q(some < text > inside & these " escapable' characters/1234)
6
+
7
+ Benchmark.ips do |x|
8
+ x.report("hmote") { hmote(text: text) }
9
+ x.report("rails") { rails(text: text) }
10
+ end
11
+
12
+ # Calculating -------------------------------------
13
+ # hmote 13.122k i/100ms
14
+ # rails 7.907k i/100ms
15
+ # -------------------------------------------------
16
+ # hmote 148.020k (± 3.6%) i/s - 747.954k
17
+ # rails 88.623k (± 2.7%) i/s - 442.792k
@@ -0,0 +1,8 @@
1
+ require "benchmark/ips"
2
+
3
+ def template_path(template)
4
+ File.join(File.expand_path("templates", __dir__), template)
5
+ end
6
+
7
+ MOTE_TEMPLATE = template_path("mote")
8
+ ERB_TEMPLATE = template_path("erb")
@@ -0,0 +1,7 @@
1
+ require_relative "../lib/hmote"
2
+
3
+ include HMote::Helpers
4
+
5
+ def hmote(params)
6
+ super(MOTE_TEMPLATE, params)
7
+ end
@@ -0,0 +1,28 @@
1
+ require "action_view"
2
+
3
+ class Context
4
+ class LookupContext
5
+ def disable_cache
6
+ yield
7
+ end
8
+
9
+ def find_template(*args)
10
+ end
11
+ end
12
+
13
+ def lookup_context
14
+ @lookup_context ||= LookupContext.new
15
+ end
16
+ end
17
+
18
+ ACTIONVIEW_CONTEXT = Context.new
19
+ ACTIONVIEW_TEMPLATE = ActionView::Template.new(
20
+ File.read(ERB_TEMPLATE), "template",
21
+ ActionView::Template::Handlers::ERB.new,
22
+ format: :html, virtual_path: "template"
23
+ )
24
+ ACTIONVIEW_TEMPLATE.locals = [:text]
25
+
26
+ def rails(params)
27
+ ACTIONVIEW_TEMPLATE.render(ACTIONVIEW_CONTEXT, params)
28
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "helper"
2
+ require_relative "hmote_helper"
3
+ require_relative "rails_helper"
4
+
5
+ text = %q(some text without escapable characters).html_safe
6
+
7
+ Benchmark.ips do |x|
8
+ x.report("hmote") { hmote(text: text) }
9
+ x.report("rails") { rails(text: text) }
10
+ end
11
+
12
+ # Calculating -------------------------------------
13
+ # hmote 29.035k i/100ms
14
+ # rails 14.607k i/100ms
15
+ # -------------------------------------------------
16
+ # hmote 367.044k (± 5.9%) i/s - 1.829M
17
+ # rails 157.936k (± 5.9%) i/s - 788.778k
@@ -0,0 +1 @@
1
+ <%= text %>
@@ -0,0 +1 @@
1
+ {{ text }}
data/hmote.gemspec CHANGED
@@ -1,11 +1,11 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "hmote"
3
- s.version = "1.0.0"
3
+ s.version = "1.1.0"
4
4
  s.summary = "A minimum operational template that escapes HTML tags by default."
5
5
  s.description = s.summary
6
- s.authors = ["Francesco Rodríguez"]
7
- s.email = ["frodsan@me.com"]
8
- s.homepage = "http://github.com/frodsan/hmote"
6
+ s.authors = ["Francesco Rodríguez", "Mayn Kjær"]
7
+ s.email = ["frodsan@me.com", "mayn.kjaer@gmail.com"]
8
+ s.homepage = "https://github.com/harmoni-io/hmote"
9
9
  s.license = "MIT"
10
10
 
11
11
  s.files = `git ls-files`.split("\n")
@@ -0,0 +1,31 @@
1
+ require_relative "../hmote"
2
+
3
+ module HMote::Render
4
+ include HMote::Helpers
5
+
6
+ def self.setup(app)
7
+ app.settings[:hmote] ||= {}
8
+ app.settings[:hmote][:views] ||= File.expand_path("views", Dir.pwd)
9
+ app.settings[:hmote][:layout] ||= "layout"
10
+ end
11
+
12
+ def render(template, params = {}, layout = settings[:hmote][:layout])
13
+ res.write(view(template, params, layout))
14
+ end
15
+
16
+ def view(template, params = {}, layout = settings[:hmote][:layout])
17
+ return partial(layout, params.merge(content: partial(template, params)))
18
+ end
19
+
20
+ def partial(template, params = {})
21
+ return hmote(template_path(template), params.merge(app: self), TOPLEVEL_BINDING)
22
+ end
23
+
24
+ def template_path(template)
25
+ if template.end_with?(".mote")
26
+ return template
27
+ else
28
+ return File.join(settings[:hmote][:views], "#{template}.mote")
29
+ end
30
+ end
31
+ end
data/lib/hmote.rb CHANGED
@@ -1,11 +1,14 @@
1
1
  require "hache"
2
2
 
3
- class Mote
4
- PATTERN = /^(\n)|^\s*(%)\s*(.*?)(?:\n|\Z)|(<\?)\s+(.*?)\s+\?>|(\{\{>?)(.*?)\}\}/m
3
+ class HMote
4
+ PATTERN = /^(\n)| # new lines.
5
+ ^\s*(%)\s*(.*?)(?:\n|\Z)| # % code
6
+ (<\?)\s+(.*?)\s+\?>| # <? multi-line code ?>
7
+ (\{\{!?)(.*?)\}\} # {{ escaped }} or {{! unescaped }}
8
+ /mx
5
9
 
6
10
  def self.parse(template, context = self, vars = [])
7
11
  terms = template.split(PATTERN)
8
-
9
12
  parts = "Proc.new do |params, __o|\n params ||= {}; __o ||= ''\n"
10
13
 
11
14
  vars.each do |var|
@@ -17,7 +20,7 @@ class Mote
17
20
  when "<?" then parts << "#{terms.shift}\n"
18
21
  when "%" then parts << "#{terms.shift}\n"
19
22
  when "{{" then parts << "__o << Hache.h((#{terms.shift}).to_s)\n"
20
- when "{{>" then parts << "__o << (#{terms.shift}).to_s\n"
23
+ when "{{!" then parts << "__o << (#{terms.shift}).to_s\n"
21
24
  else parts << "__o << #{term.dump}\n"
22
25
  end
23
26
  end
@@ -32,13 +35,13 @@ class Mote
32
35
  end
33
36
 
34
37
  module Helpers
35
- def mote(file, params = {}, context = self)
36
- mote_cache[file] ||= Mote.parse(File.read(file), context, params.keys)
37
- mote_cache[file][params]
38
+ def hmote(file, params = {}, context = self)
39
+ hmote_cache[file] ||= HMote.parse(File.read(file), context, params.keys)
40
+ hmote_cache[file].call(params)
38
41
  end
39
42
 
40
- def mote_cache
41
- Thread.current[:_mote_cache] ||= {}
43
+ def hmote_cache
44
+ Thread.current[:_hmote_cache] ||= {}
42
45
  end
43
46
  end
44
47
  end
data/makefile CHANGED
@@ -1,4 +1,7 @@
1
1
  .PHONY: test
2
2
 
3
+ gem:
4
+ gem build hmote.gemspec
5
+
3
6
  test:
4
7
  cutest test/*.rb
@@ -0,0 +1 @@
1
+ <h1>Custom</h1>
@@ -0,0 +1,2 @@
1
+ <title>{{ title }}</title>
2
+ {{! content }}
data/test/helper.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "cutest"
2
+ require_relative "../lib/hmote"
data/test/helpers.rb CHANGED
@@ -1,29 +1,25 @@
1
- require_relative "../lib/hmote"
1
+ require_relative "helper"
2
2
 
3
3
  class Cutest::Scope
4
- include Mote::Helpers
4
+ include HMote::Helpers
5
5
 
6
6
  def foo
7
7
  "foo"
8
8
  end
9
9
  end
10
10
 
11
- scope do
11
+ scope("helpers") do
12
12
  prepare do
13
- mote_cache.clear
14
- end
15
-
16
- test "helpers" do
17
- assert_equal " *\n *\n *\n", mote("test/fixtures/basic.mote", n: 3)
13
+ hmote_cache.clear
18
14
  end
19
15
 
20
16
  test "using functions in the context" do
21
- assert_equal "foo\n", mote("test/fixtures/foo.mote")
17
+ assert_equal("foo\n", hmote("test/foo.mote"))
22
18
  end
23
19
 
24
20
  test "passing in a context" do
25
21
  assert_raise(NameError) do
26
- mote("test/fixtures/foo.mote", {}, TOPLEVEL_BINDING)
22
+ hmote("test/foo.mote", {}, TOPLEVEL_BINDING)
27
23
  end
28
24
  end
29
25
  end
data/test/parsing.rb ADDED
@@ -0,0 +1,108 @@
1
+ require_relative "helper"
2
+
3
+ scope("parsing") do
4
+ test "assignment" do
5
+ template = HMote.parse("{{ 1 + 2 }}")
6
+
7
+ assert_equal("3", template.call)
8
+ end
9
+
10
+ test "control flow" do
11
+ template = (<<-EOT).gsub(/ {4}/, "")
12
+ % if false
13
+ false
14
+ % else
15
+ true
16
+ % end
17
+ EOT
18
+
19
+ result = HMote.parse(template).call
20
+
21
+ assert_equal(" true\n", result)
22
+ end
23
+
24
+ test "parameters" do
25
+ template = (<<-EOT).gsub(/ {4}/, "")
26
+ % params[:n].times do
27
+ *
28
+ % end
29
+ EOT
30
+
31
+ example = HMote.parse(template)
32
+
33
+ assert_equal("*\n*\n*\n", example[n: 3])
34
+ assert_equal("*\n*\n*\n*\n", example[n: 4])
35
+ end
36
+
37
+ test "multiline" do
38
+ example = HMote.parse("The\nMan\nAnd\n{{\"The\"}}\nSea")
39
+ assert_equal("The\nMan\nAnd\nThe\nSea", example[n: 3])
40
+ end
41
+
42
+ test "quotes" do
43
+ example = HMote.parse("'foo' 'bar' 'baz'")
44
+ assert_equal("'foo' 'bar' 'baz'", example.call)
45
+ end
46
+
47
+ test "context" do
48
+ context = Object.new
49
+ def context.user; "Bruno"; end
50
+
51
+ example = HMote.parse("{{ user }}", context)
52
+
53
+ assert_equal("Bruno", example.call)
54
+ end
55
+
56
+ test "locals" do
57
+ example = HMote.parse("{{ user }}", TOPLEVEL_BINDING, [:user])
58
+
59
+ assert_equal("Mayn", example.call(user: "Mayn"))
60
+ end
61
+
62
+ test "nil" do
63
+ example = HMote.parse("{{ params[:user] }}", TOPLEVEL_BINDING)
64
+
65
+ assert_equal("", example.call(user: nil))
66
+ end
67
+
68
+ test "multi-line XML-style directives" do
69
+ template = (<<-EOT).gsub(/^ /, "")
70
+ <? res = ""
71
+ [1, 2, 3].each_with_index do |item, idx|
72
+ res << "%d. %d\n" % [idx + 1, item * item]
73
+ end
74
+ ?>
75
+ {{ res }}
76
+ EOT
77
+
78
+ example = HMote.parse(template)
79
+
80
+ assert_equal("\n1. 1\n2. 4\n3. 9\n\n", example.call)
81
+ end
82
+
83
+ test "preserve XML directives" do
84
+ template = (<<-EOT).gsub(/^ /, "")
85
+ <?xml "hello" ?>
86
+ EOT
87
+
88
+ example = HMote.parse(template)
89
+
90
+ assert_equal("<?xml \"hello\" ?>\n", example.call)
91
+ end
92
+
93
+ test "escapes by default" do
94
+ text = %q(<>&"'/)
95
+ template = HMote.parse("{{ params[:text] }}")
96
+ result = template.call(text: text)
97
+
98
+ assert_equal("&lt;&gt;&amp;&quot;&#x27;&#x2F;", result)
99
+ end
100
+
101
+ test "no escaping please" do
102
+ text = %q(<>&"'/)
103
+ template = HMote.parse("{{! params[:text] }}")
104
+ result = template.call(text: text)
105
+
106
+ assert_equal(text, result)
107
+ end
108
+ end
data/test/render.rb ADDED
@@ -0,0 +1,78 @@
1
+ require_relative "helper"
2
+ require "cuba/test"
3
+ require_relative "../lib/hmote/render"
4
+
5
+ Cuba.plugin(HMote::Render)
6
+ Cuba.settings[:hmote][:views] = "./test/views"
7
+
8
+ Cuba.define do
9
+ def name
10
+ "App"
11
+ end
12
+
13
+ on "partial" do
14
+ res.write partial("home")
15
+ end
16
+
17
+ on "view" do
18
+ res.write view("home", title: "Hello")
19
+ end
20
+
21
+ on "render" do
22
+ render("home", title: "Hola")
23
+ end
24
+
25
+ on "context" do
26
+ res.write partial("context")
27
+ end
28
+
29
+ on "absolute" do
30
+ render("./test/custom_views/custom.mote", title: "Custom")
31
+ end
32
+
33
+ on "absolute_layout" do
34
+ render("./test/custom_views/custom.mote", title: "Custom Layout")
35
+ end
36
+ end
37
+
38
+ scope do
39
+ test "view renders view with layout" do
40
+ expected = "<title>Hello</title>\n<h1>Home</h1>"
41
+
42
+ get "/view"
43
+
44
+ assert last_response.body[expected]
45
+ end
46
+
47
+ test "partial renders view without layout" do
48
+ get "/partial"
49
+
50
+ assert last_response.body["<h1>Home</h1>"]
51
+ end
52
+
53
+ test "render renders view with layout" do
54
+ get "/render"
55
+
56
+ assert last_response.body["<title>Hola</title>\n<h1>Home</h1>"]
57
+ end
58
+
59
+ test "access to application context" do
60
+ get "/context"
61
+
62
+ assert last_response.body["App"]
63
+ end
64
+
65
+ test "use of absolute path for template" do
66
+ get "/absolute"
67
+
68
+ assert last_response.body["<title>Custom</title>\n<h1>Custom</h1>"]
69
+ end
70
+
71
+ test "use of absolute path for layout" do
72
+ Cuba.settings[:hmote][:layout] = "./test/custom_views/layout.mote"
73
+
74
+ get "/absolute_layout"
75
+
76
+ assert last_response.body["<title>Custom Layout</title>\n<h1>Custom</h1>"]
77
+ end
78
+ end
@@ -0,0 +1 @@
1
+ {{ app.name }}
@@ -0,0 +1 @@
1
+ <h1>Home</h1>
@@ -0,0 +1,2 @@
1
+ <title>{{ title }}</title>
2
+ {{! content }}
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hmote
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Rodríguez
8
+ - Mayn Kjær
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-08-05 00:00:00.000000000 Z
12
+ date: 2014-12-14 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: hache
@@ -41,6 +42,7 @@ dependencies:
41
42
  description: A minimum operational template that escapes HTML tags by default.
42
43
  email:
43
44
  - frodsan@me.com
45
+ - mayn.kjaer@gmail.com
44
46
  executables: []
45
47
  extensions: []
46
48
  extra_rdoc_files: []
@@ -48,14 +50,29 @@ files:
48
50
  - ".gems"
49
51
  - LICENSE
50
52
  - README.md
53
+ - benchmarks/.gems
54
+ - benchmarks/escaping.rb
55
+ - benchmarks/helper.rb
56
+ - benchmarks/hmote_helper.rb
57
+ - benchmarks/rails_helper.rb
58
+ - benchmarks/safe.rb
59
+ - benchmarks/templates/erb
60
+ - benchmarks/templates/mote
51
61
  - hmote.gemspec
52
62
  - lib/hmote.rb
63
+ - lib/hmote/render.rb
53
64
  - makefile
54
- - test/fixtures/basic.mote
55
- - test/fixtures/foo.mote
65
+ - test/custom_views/custom.mote
66
+ - test/custom_views/layout.mote
67
+ - test/foo.mote
68
+ - test/helper.rb
56
69
  - test/helpers.rb
57
- - test/hmote.rb
58
- homepage: http://github.com/frodsan/hmote
70
+ - test/parsing.rb
71
+ - test/render.rb
72
+ - test/views/context.mote
73
+ - test/views/home.mote
74
+ - test/views/layout.mote
75
+ homepage: https://github.com/harmoni-io/hmote
59
76
  licenses:
60
77
  - MIT
61
78
  metadata: {}
@@ -1,3 +0,0 @@
1
- % 3.times do
2
- *
3
- % end
data/test/hmote.rb DELETED
@@ -1,151 +0,0 @@
1
- require_relative "../lib/hmote"
2
-
3
- scope do
4
- test "empty lines" do
5
- example = Mote.parse("\n\n \n")
6
- assert_equal "\n\n \n", example.call
7
- end
8
-
9
- test "empty lines with mixed code" do
10
- example = Mote.parse("\n% true\n\n% false\n\n")
11
- assert_equal "\n\n\n", example.call
12
- end
13
-
14
- test "empty lines with control flow" do
15
- example = Mote.parse("\n% if true\n\n\n% else\n\n% end\n")
16
- assert_equal "\n\n\n", example.call
17
- end
18
-
19
- test "control flow without final newline" do
20
- example = Mote.parse("\n% if true\n\n\n% else\n\n% end")
21
- assert_equal "\n\n\n", example.call
22
- end
23
-
24
- test "assignment" do
25
- example = Mote.parse("{{ \"***\" }}")
26
- assert_equal "***", example.call
27
- end
28
-
29
- test "comment" do
30
- template = (<<-EOT).gsub(/ {4}/, "")
31
- *
32
- % # "*"
33
- *
34
- EOT
35
-
36
- example = Mote.parse(template)
37
- assert_equal "*\n*\n", example.call.squeeze("\n")
38
- end
39
-
40
- test "control flow" do
41
- template = (<<-EOT).gsub(/ {4}/, "")
42
- % if false
43
- *
44
- % else
45
- ***
46
- % end
47
- EOT
48
-
49
- example = Mote.parse(template)
50
- assert_equal " ***\n", example.call
51
- end
52
-
53
- test "block evaluation" do
54
- template = (<<-EOT).gsub(/ {4}/, "")
55
- % 3.times {
56
- *
57
- % }
58
- EOT
59
-
60
- example = Mote.parse(template)
61
- assert_equal "*\n*\n*\n", example.call
62
- end
63
-
64
- test "parameters" do
65
- template = (<<-EOT).gsub(/ {4}/, "")
66
- % params[:n].times {
67
- *
68
- % }
69
- EOT
70
-
71
- example = Mote.parse(template)
72
- assert_equal "*\n*\n*\n", example[:n => 3]
73
- assert_equal "*\n*\n*\n*\n", example[:n => 4]
74
- end
75
-
76
- test "multiline" do
77
- example = Mote.parse("The\nMan\nAnd\n{{\"The\"}}\nSea")
78
- assert_equal "The\nMan\nAnd\nThe\nSea", example[:n => 3]
79
- end
80
-
81
- test "quotes" do
82
- example = Mote.parse("'foo' 'bar' 'baz'")
83
- assert_equal "'foo' 'bar' 'baz'", example.call
84
- end
85
-
86
- test "context" do
87
- context = Object.new
88
- def context.user; "Bruno"; end
89
-
90
- example = Mote.parse("{{ context.user }}", context, [:context])
91
- assert_equal "Bruno", example.call(context: context)
92
- end
93
-
94
- test "locals" do
95
- example = Mote.parse("{{ user }}", TOPLEVEL_BINDING, [:user])
96
- assert_equal "Bruno", example.call(user: "Bruno")
97
- end
98
-
99
- test "nil" do
100
- example = Mote.parse("{{ params[:user] }}", TOPLEVEL_BINDING, [:user])
101
- assert_equal "", example.call(user: nil)
102
- end
103
-
104
- test "curly bug" do
105
- example = Mote.parse("{{ [1, 2, 3].map { |i| i * i }.join(',') }}")
106
- assert_equal "1,4,9", example.call
107
- end
108
-
109
- test "multi-line XML-style directives" do
110
- template = (<<-EOT).gsub(/^ /, "")
111
- <? res = ""
112
- [1, 2, 3].each_with_index do |item, idx|
113
- res << "%d. %d\n" % [idx + 1, item * item]
114
- end
115
- ?>
116
- {{ res }}
117
- EOT
118
-
119
- example = Mote.parse(template)
120
- assert_equal "\n1. 1\n2. 4\n3. 9\n\n", example.call
121
- end
122
-
123
- test "preserve XML directives" do
124
- template = (<<-EOT).gsub(/^ /, "")
125
- <?xml "hello" ?>
126
- EOT
127
-
128
- example = Mote.parse(template)
129
- assert_equal "<?xml \"hello\" ?>\n", example.call
130
- end
131
-
132
- test "escapes html" do
133
- template = (<<-EOT).gsub(/^ /, "")
134
- % res = '<img src="img.jpeg">'
135
- {{ res }}
136
- EOT
137
-
138
- example = Mote.parse(template)
139
- assert_equal "&lt;img src=&quot;img.jpeg&quot;&gt;\n", example.call
140
- end
141
-
142
- test "outputs raw html" do
143
- template = (<<-EOT).gsub(/^ /, "")
144
- % res = '<img src="img.jpeg">'
145
- {{> res }}
146
- EOT
147
-
148
- example = Mote.parse(template)
149
- assert_equal "<img src=\"img.jpeg\">\n", example.call
150
- end
151
- end
File without changes