tempeh 0.1.0 → 0.2.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: e662a14d9152dd7487a8b69e550d16b075886ca8
4
- data.tar.gz: 50a9fb441f3823938a2f8d06b620d902b40389a3
3
+ metadata.gz: 17deec681294c1e4063e5d17506291cc84f0a565
4
+ data.tar.gz: 8a20e0ec8b46118a008db617b56e242fca4e3091
5
5
  SHA512:
6
- metadata.gz: 4bfe92cdcea987941dc31ac079708b86f9c0fbf8926390fc8e92fd42b49594f0408e44a51ea8650dd21d173749c16156d47bc42c20feff2390941b69d3d4b6d3
7
- data.tar.gz: deecdba9c512a409722888a1bbb464ecffe8eb9955cdd9e22bbfbc7e66a3a69e1e8751e2b241dcf706e65cd7aa217e4381cba259f1c33614889b880983675b93
6
+ metadata.gz: 53d84b831ce14d0155e56b84f2608af0cd3ed843a9cdb304de5bd3b4d875ec4400dff52cd32d8e80a19dae9d5291f3f1d762a4ed588de361f5c9a0a966b0cc83
7
+ data.tar.gz: 0e646e35b1542b1b36fdae9861b224be95eed88056767155ff72038791ccdd617a0bb6bd168582485f0ef7624e8caecece01f074499d7705222b9c38e7f2fd87
data/README.md CHANGED
@@ -1,33 +1,67 @@
1
- Tempeh
2
- ======
1
+ # Tempeh
3
2
 
4
3
  Tasty Ruby Templates
5
4
 
6
- Description
7
- -----------
5
+ ## Description
8
6
 
9
7
  Tempeh is an opininated template engine for rendering html. It steals
10
- most of its ideas from Mote and also the Herb fork. That means it is a
11
- small layer on top of Ruby that escapes strings by default. The render API
12
- differs from both, as the context the template gets rendered with does not
13
- get "compiled" with the template, instead the context gets lazily executed
14
- each time when passed to `#render`.
8
+ most of its ideas from [Mote](https://github.com/soveran/mote)
9
+ and the [Herb](https://github.com/frodsan/herb) fork. The motivation for
10
+ a new library is the different rendering API that is designed
11
+ for lazily binding a context with instance_eval for use with view components.
15
12
 
16
- Usage
17
- -----
13
+ ## Installation
14
+
15
+ `gem install tempeh`
16
+
17
+ ## Example
18
18
 
19
19
  ```ruby
20
- template = Tempeh.new("
21
- % if hungry? %
22
- Eat { args[:food] }!
23
- % end %
24
- ")
25
-
26
- module Steve
27
- def self.hungry?
28
- true # always...
20
+ # ./templates/eat.tempeh
21
+ #
22
+ # % if hungry? %
23
+ # Eat {{ food }}!
24
+ # % end %
25
+
26
+ require 'tempeh'
27
+
28
+ class View
29
+ include Tempeh::Helpers
30
+
31
+ def initialize(food)
32
+ @food = food
33
+ end
34
+
35
+ def food
36
+ @food
37
+ end
38
+
39
+ def hungry?
40
+ true
29
41
  end
30
42
  end
31
43
 
32
- template.render(Steve, food: 'Tempeh') # Eat Tempeh!
44
+ View.new('Tempeh').render('./templates/eat.tempeh') # Eat Tempeh!
33
45
  ```
46
+
47
+ ## API
48
+
49
+ ### Templates
50
+
51
+ `% code %`: Ruby to be evaluated but not outputted.
52
+
53
+ `{{ code }}`: Ruby that gets outputted as an escaped string. Safe for user input.
54
+
55
+ `{{& code }}`: Ruby that gets outputted as an unescaped string. Useful for rendering partials and other content that is guarenteed to be safe.
56
+
57
+ ### Module Methods
58
+
59
+ `cache`: Hash of compiled templates, populated by the `render` helper.
60
+
61
+ `compile`: Creates a proc from the the given string.
62
+
63
+ `escape`: HTML escapes the given string.
64
+
65
+ ### Helpers
66
+
67
+ `render`: instance_eval's a template found at a file path. Saves the compiled template in `Tempeh::cache` for reuse.
@@ -0,0 +1,14 @@
1
+ % # this is a comment %
2
+
3
+ % if true %
4
+ {{ 'hello world' }}
5
+ % end %
6
+
7
+ % # multiline blocks work as well %
8
+ % [
9
+ 'foo',
10
+ 'bar',
11
+ ].each do |word| %
12
+ {{& word }} % # word will not be escaped %
13
+ % end %
14
+
@@ -0,0 +1 @@
1
+ % 3.times do %{{ name }}% end %
@@ -0,0 +1,38 @@
1
+ %YAML 1.2
2
+ ---
3
+ name: Tempeh
4
+ file_extensions:
5
+ - tempeh
6
+ scope: text.html
7
+ contexts:
8
+ main:
9
+ - match: ''
10
+ push: 'scope:text.html.basic'
11
+ with_prototype:
12
+ - match: "%\\s*#"
13
+ push:
14
+ - meta_scope: comment.block
15
+ - match: "%"
16
+ pop: true
17
+
18
+ - match: "%"
19
+ push:
20
+ - meta_scope: punctuation.section.braces
21
+ - match: "%"
22
+ pop: true
23
+ - include: 'scope:source.ruby'
24
+
25
+ - match: "{{&"
26
+ push:
27
+ - meta_scope: punctuation.section.braces
28
+ - match: "}}"
29
+ pop: true
30
+ - include: 'scope:source.ruby'
31
+
32
+
33
+ - match: "{{"
34
+ push:
35
+ - meta_scope: punctuation.section.braces
36
+ - match: "}}"
37
+ pop: true
38
+ - include: 'scope:source.ruby'
data/lib/tempeh.rb CHANGED
@@ -1,17 +1,22 @@
1
- class Tempeh
2
- VERSION = "0.1.0"
1
+ module Tempeh
2
+ VERSION = "0.2.0"
3
3
 
4
- BLK_OPEN = '%'
4
+ BLK_OPEN = "%"
5
5
 
6
- BLK_CLOSE = '%'
6
+ BLK_CLOSE = "%"
7
7
 
8
- STR_OPEN = '{'
8
+ RAW_OPEN = "{{&"
9
9
 
10
- STR_CLOSE = '}'
10
+ RAW_CLOSE = "}}"
11
+
12
+ STR_OPEN = "{{"
13
+
14
+ STR_CLOSE = "}}"
11
15
 
12
16
  PATTERN = /
13
- (?<!\\)(#{BLK_OPEN})\s+(.*?)\s+#{BLK_CLOSE} | # Multiline Ruby blocks.
14
- (?<!\\)(#{STR_OPEN})(.*?)#{STR_CLOSE} # Ruby to be evaluated a string.
17
+ (?<!\\)(#{BLK_OPEN})\s+(.*?)\s+#{BLK_CLOSE} | # Multiline blocks.
18
+ (?<!\\)(#{RAW_OPEN})(.*?)#{RAW_CLOSE} | # Evaluated as a string, unescaped
19
+ (?<!\\)(#{STR_OPEN})(.*?)#{STR_CLOSE} # Evaluated as a string, escaped.
15
20
  /mx
16
21
 
17
22
  HTML_ESCAPE = {
@@ -19,25 +24,30 @@ class Tempeh
19
24
  ">" => "&gt;",
20
25
  "<" => "&lt;",
21
26
  '"' => "&#39;",
22
- "'" => "&#34;",
27
+ "'" => "&#34;"
23
28
  }.freeze
24
29
 
25
30
  UNSAFE = /[&"'><]/
26
31
 
27
32
  class << self
33
+ def cache
34
+ @cache ||= {}
35
+ end
36
+
28
37
  def compile(str)
29
38
  terms = str.split(PATTERN)
30
- parts = "proc do |args = {}, __o = ''|"
39
+ parts = "proc { __o = '';"
31
40
 
32
41
  while (term = terms.shift)
33
42
  case term
34
- when BLK_OPEN then parts << terms.shift << "\n"
35
- when STR_OPEN then parts << "__o << Tempeh.escape((" << terms.shift << ").to_s)\n"
36
- else parts << "__o << " << term.dump << "\n"
43
+ when BLK_OPEN then parts << "#{terms.shift}\n"
44
+ when RAW_OPEN then parts << "__o << (#{terms.shift}).to_s\n"
45
+ when STR_OPEN then parts << "__o << Tempeh.escape((#{terms.shift}).to_s)\n"
46
+ else parts << "__o << #{term.dump}\n"
37
47
  end
38
48
  end
39
49
 
40
- parts << "__o; end"
50
+ parts << "__o; }"
41
51
 
42
52
  eval(parts)
43
53
  end
@@ -47,11 +57,13 @@ class Tempeh
47
57
  end
48
58
  end
49
59
 
50
- def initialize(str)
51
- @code = Tempeh.compile(str)
52
- end
60
+ module Helpers
61
+ def render(path)
62
+ instance_eval &tempeh_template_for(path)
63
+ end
53
64
 
54
- def render(context = nil, **args)
55
- context.instance_exec(args, &@code)
65
+ def tempeh_template_for(path)
66
+ Tempeh.cache[path] ||= Tempeh.compile(File.read(path))
67
+ end
56
68
  end
57
69
  end
data/test/all.rb CHANGED
@@ -1,57 +1,76 @@
1
1
  require_relative '../lib/tempeh'
2
2
 
3
3
  test 'empty lines' do
4
- template = Tempeh.new("\n\n \n")
4
+ template = Tempeh.compile("\n\n \n")
5
5
 
6
- assert_equal "\n\n \n", template.render
6
+ assert_equal "\n\n \n", template.call
7
7
  end
8
8
 
9
9
  test 'quotes' do
10
- template = Tempeh.new("'foo' 'bar' 'baz'")
10
+ template = Tempeh.compile("'foo' 'bar' 'baz'")
11
11
 
12
- assert_equal "'foo' 'bar' 'baz'", template.render
12
+ assert_equal "'foo' 'bar' 'baz'", template.call
13
13
  end
14
14
 
15
15
  test 'block expressions' do
16
- template = Tempeh.new("% if true %yes% else %no% end %")
16
+ template = Tempeh.compile("% if true %yes% else %no% end %")
17
17
 
18
- assert_equal "yes", template.render
18
+ assert_equal "yes", template.call
19
19
  end
20
20
 
21
- test 'string expressions' do
22
- template = Tempeh.new("{ 'Hello' }")
21
+ test 'unescaped string expressions' do
22
+ template = Tempeh.compile(%q({{& %q(<>&"') }}))
23
23
 
24
- assert_equal "Hello", template.render
24
+ assert_equal %q(<>&"'), template.call
25
25
  end
26
26
 
27
- test 'escapes string expressions' do
28
- template = Tempeh.new(%q({ %q(<>&"') }))
27
+ test 'escaped string expressions' do
28
+ template = Tempeh.compile(%q({{ %q(<>&"') }}))
29
29
 
30
- assert_equal "&lt;&gt;&amp;&#39;&#34;", template.render
30
+ assert_equal "&lt;&gt;&amp;&#39;&#34;", template.call
31
31
  end
32
32
 
33
33
  test 'nil string expressions' do
34
- template = Tempeh.new("{ nil }")
34
+ template = Tempeh.compile("{{ nil }}")
35
35
 
36
- assert_equal "", template.render
36
+ assert_equal "", template.call
37
37
  end
38
38
 
39
39
  test 'allows escaping expressions' do
40
- template = Tempeh.new('\{ nil }\% hello %')
40
+ template = Tempeh.compile('\{{ nil }}\% hello %')
41
41
 
42
- assert_equal '\{ nil }\% hello %', template.render
42
+ assert_equal '\{{ nil }}\% hello %', template.call
43
43
  end
44
44
 
45
- test 'render with context' do
46
- context = Struct.new(:foo).new('bar')
45
+ test 'contextual rendering' do
46
+ context = Struct.new(:foo).new('bar')
47
+ template = Tempeh.compile("{{ foo }}")
47
48
 
48
- template = Tempeh.new("{ foo }")
49
+ assert_equal "bar", context.instance_eval(&template)
50
+ end
51
+
52
+ class View
53
+ include Tempeh::Helpers
49
54
 
50
- assert_equal "bar", template.render(context)
55
+ def initialize(name)
56
+ @name = name
57
+ end
58
+
59
+ def name
60
+ @name
61
+ end
51
62
  end
52
63
 
53
- test 'render with args' do
54
- template = Tempeh.new("{ args[:foo] }")
64
+ setup do
65
+ View.new('steve')
66
+ end
67
+
68
+ test 'helpers' do |view|
69
+ path = './test/basic.tempeh'
70
+
71
+ assert Tempeh.cache[path].nil?, 'template is already cached'
72
+
73
+ assert_equal 'stevestevesteve', view.render('./examples/basic.tempeh')
55
74
 
56
- assert_equal "bar", template.render(foo: "bar")
75
+ assert Tempeh.cache[path], 'template was not cached'
57
76
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tempeh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Weiss
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-02 00:00:00.000000000 Z
11
+ date: 2017-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cutest
@@ -37,6 +37,9 @@ files:
37
37
  - LICENSE
38
38
  - README.md
39
39
  - Rakefile
40
+ - examples/advanced.tempeh
41
+ - examples/basic.tempeh
42
+ - extras/Tempeh.sublime-syntax
40
43
  - lib/tempeh.rb
41
44
  - tempeh.gemspec
42
45
  - test/all.rb