ruby-handlebars 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ae92539214ecdf59a678a44935f42fdb2f2264a6
4
- data.tar.gz: 6e0da52049ff769f168933b3fd8b0f0832c42e8a
2
+ SHA256:
3
+ metadata.gz: 5bb7ada122dcffa528888da4c6a4b1e2822cbecd5626d14e559081a8881670b8
4
+ data.tar.gz: aeed1a35e4a57bee75e9fa0f67ddfd0c26a07fd33c613608974492f258eb6c06
5
5
  SHA512:
6
- metadata.gz: 8931ee0570230133d9f0f09fb38595e5362a01412890c4ce43d35be5b9335d5dc15ba7c0c09e465c50bdf2e46dedbbe758c1fbd6ce169cb31cb182224ee788f5
7
- data.tar.gz: fe7e970a5d0626e90044268ccaf4e5c1aa8380a77bb2f5f9782d422e129d9c3ad098b66db0f3638157db620bb52b885e7def81ca02a4e441c4a5ecb5d19407dc
6
+ metadata.gz: 6505f37bb31fbdd0d344d5404c1bc5b5a6259e97120039037dc9ae2aa45635cfa2f7b2c40be1c4b5faced929dab3404665a451e495465c94e446c66dbb0362bf
7
+ data.tar.gz: ca528f8a90911381216fa5af4fe7aba5d36ca83c84dd88f084023860fe3dc6067970f5b5155f9a296ee2baf814024ff32b5fcdc14edc120f75b4257ef6220e0b
data/README.md CHANGED
@@ -105,9 +105,7 @@ Limitations and roadmap
105
105
 
106
106
  This gem does not reuse the real Handlebars code (the JS one) and not everything is handled yet (but it will be someday ;) ):
107
107
 
108
- - there is no escaping, all strings are considered as safe (so ``{{{ my_var }}}`` and ``{{ my_var }}``) will output the same thing
109
108
  - the parser is not fully tested yet, it may complain with spaces ...
110
- - curly bracket are __not__ usable in the template content yet. one workaround is to create simple helpers to generate them
111
109
  - parsing errors are, well, not helpful at all
112
110
 
113
111
  Aknowledgements
@@ -115,3 +113,5 @@ Aknowledgements
115
113
 
116
114
  This gem would simply not exist if the handlebars team was not here. Thanks a lot for this awesome templating system.
117
115
  Thanks a lot to @cowboyd for the [handlebars.rb](https://github.com/cowboyd/handlebars.rb) gem. We used it for a while and it's great (and as told at the beginning of the README, if you do not need any Windows support, use handlebars.rb instead ;) )
116
+
117
+ Thanks a lot to the contributors @mvz and @schuetzm for making it a way better Handlebars renderer :)
@@ -2,15 +2,18 @@ require_relative 'ruby-handlebars/parser'
2
2
  require_relative 'ruby-handlebars/tree'
3
3
  require_relative 'ruby-handlebars/template'
4
4
  require_relative 'ruby-handlebars/helper'
5
+ require_relative 'ruby-handlebars/escapers/html_escaper'
5
6
 
6
7
  module Handlebars
7
8
  class Handlebars
8
9
  include Context
10
+ attr_reader :escaper
9
11
 
10
- def initialize
12
+ def initialize()
11
13
  @helpers = {}
12
14
  @partials = {}
13
15
  register_default_helpers
16
+ set_escaper
14
17
  end
15
18
 
16
19
  def compile(template)
@@ -37,6 +40,10 @@ module Handlebars
37
40
  @data = ctx
38
41
  end
39
42
 
43
+ def set_escaper(escaper = nil)
44
+ @escaper = escaper || Escapers::HTMLEscaper
45
+ end
46
+
40
47
  private
41
48
 
42
49
  PARSER = Parser.new
@@ -67,20 +74,18 @@ module Handlebars
67
74
 
68
75
  def register_each_helper
69
76
  register_helper('each') do |context, items, block, else_block|
70
- current_this = context.get('this')
71
-
72
77
  if (items.nil? || items.empty?)
73
78
  if else_block
74
79
  result = else_block.fn(context)
75
80
  end
76
81
  else
77
- result = items.map do |item|
78
- context.add_item(:this, item)
79
- block.fn(context)
80
- end.join('')
82
+ context.with_temporary_context(:this => nil, :@index => 0, :@first => false, :@last => false) do
83
+ result = items.each_with_index.map do |item, index|
84
+ context.add_items(:this => item, :@index => index, :@first => (index == 0), :@last => (index == items.length - 1))
85
+ block.fn(context)
86
+ end.join('')
87
+ end
81
88
  end
82
-
83
- context.add_item(:this, current_this)
84
89
  result
85
90
  end
86
91
  end
@@ -2,8 +2,12 @@ module Handlebars
2
2
  module Context
3
3
  def get(path)
4
4
  items = path.split('.'.freeze)
5
+ if locals.key? items.first.to_sym
6
+ current = locals
7
+ else
8
+ current = @data
9
+ end
5
10
 
6
- current = @data
7
11
  until items.empty?
8
12
  current = get_attribute(current, items.shift)
9
13
  end
@@ -12,16 +16,32 @@ module Handlebars
12
16
  end
13
17
 
14
18
  def add_item(key, value)
15
- @data[key] = value
19
+ locals[key.to_sym] = value
20
+ end
21
+
22
+ def add_items(hash)
23
+ hash.map { |k, v| add_item(k, v) }
24
+ end
25
+
26
+ def with_temporary_context(args = {})
27
+ saved = args.keys.collect { |key| [key, get(key.to_s)] }.to_h
28
+
29
+ add_items(args)
30
+ yield
31
+ locals.merge!(saved)
16
32
  end
17
33
 
18
34
  private
19
35
 
36
+ def locals
37
+ @locals ||= {}
38
+ end
39
+
20
40
  def get_attribute(item, attribute)
21
41
  sym_attr = attribute.to_sym
22
42
  str_attr = attribute.to_s
23
43
 
24
- if item.respond_to?(:[])
44
+ if item.respond_to?(:[]) && item.respond_to?(:has_key?)
25
45
  if item.has_key?(sym_attr)
26
46
  return item[sym_attr]
27
47
  elsif item.has_key?(str_attr)
@@ -29,10 +49,6 @@ module Handlebars
29
49
  end
30
50
  end
31
51
 
32
- if item.instance_variables.include?("@#{attribute}")
33
- return item.instance_variable_get("@#{attribute}")
34
- end
35
-
36
52
  if item.respond_to?(sym_attr)
37
53
  return item.send(sym_attr)
38
54
  end
@@ -0,0 +1,9 @@
1
+ module Handlebars
2
+ module Escapers
3
+ class DummyEscaper
4
+ def self.escape(value)
5
+ value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Handlebars
2
+ module Escapers
3
+ class HTMLEscaper
4
+ def self.escape(value)
5
+ CGI::escapeHTML(value)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -13,24 +13,37 @@ module Handlebars
13
13
 
14
14
  rule(:docurly) { ocurly >> ocurly }
15
15
  rule(:dccurly) { ccurly >> ccurly }
16
+ rule(:tocurly) { ocurly >> ocurly >> ocurly }
17
+ rule(:tccurly) { ccurly >> ccurly >> ccurly }
16
18
 
17
- rule(:identifier) { match['a-zA-Z0-9_\?'].repeat(1) }
19
+ rule(:identifier) { match['@a-zA-Z0-9_\?'].repeat(1) }
18
20
  rule(:path) { identifier >> (dot >> identifier).repeat }
19
21
 
20
- rule(:template_content) { match('[^{}]').repeat(1).as(:template_content) }
22
+ rule(:nocurly) { match('[^{}]') }
23
+ rule(:eof) { any.absent? }
24
+ rule(:template_content) {
25
+ (
26
+ ocurly >> nocurly | # Opening curly that doesn't start a {{}}
27
+ ocurly >> eof | # Opening curly that doesn't start a {{}} because it's the end
28
+ ccurly | # Closing curly that is not inside a {{}}
29
+ nocurly
30
+ ).repeat(1).as(:template_content) }
21
31
 
22
- rule(:replacement) { docurly >> space? >> path.as(:replaced_item) >> space? >> dccurly}
23
- rule(:safe_replacement) { ocurly >> replacement >> ccurly }
32
+ rule(:unsafe_replacement) { docurly >> space? >> path.as(:replaced_unsafe_item) >> space? >> dccurly }
33
+ rule(:safe_replacement) { tocurly >> space? >> path.as(:replaced_safe_item) >> space? >> tccurly }
24
34
 
25
- rule(:sq_string) { match("'") >> match("[^']").repeat(1).as(:str_content) >> match("'") }
26
- rule(:dq_string) { match('"') >> match('[^"]').repeat(1).as(:str_content) >> match('"') }
35
+ rule(:sq_string) { match("'") >> match("[^']").repeat.maybe.as(:str_content) >> match("'") }
36
+ rule(:dq_string) { match('"') >> match('[^"]').repeat.maybe.as(:str_content) >> match('"') }
27
37
  rule(:string) { sq_string | dq_string }
28
38
 
29
- rule(:parameter) { (path | string).as(:parameter_name) }
39
+ rule(:parameter) {
40
+ (path | string).as(:parameter_name) |
41
+ (str('(') >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> str(')'))
42
+ }
30
43
  rule(:parameters) { parameter >> (space >> parameter).repeat }
31
44
 
32
- rule(:unsafe_helper) { docurly >> space? >> identifier.as(:helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly}
33
- rule(:safe_helper) { ocurly >> helper >> ccurly }
45
+ rule(:unsafe_helper) { docurly >> space? >> identifier.as(:unsafe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly }
46
+ rule(:safe_helper) { tocurly >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> tccurly }
34
47
 
35
48
  rule(:helper) { unsafe_helper | safe_helper }
36
49
 
@@ -58,8 +71,8 @@ module Handlebars
58
71
  dccurly
59
72
  }
60
73
 
61
- rule(:block) { (template_content | replacement | safe_replacement | helper | partial | block_helper ).repeat.as(:block_items) }
74
+ rule(:block) { (template_content | unsafe_replacement | safe_replacement | helper | partial | block_helper ).repeat.as(:block_items) }
62
75
 
63
76
  root :block
64
77
  end
65
- end
78
+ end
@@ -7,12 +7,12 @@ module Handlebars
7
7
  @ast = ast
8
8
  end
9
9
 
10
- def call(args)
11
- if args.is_a? Hash
10
+ def call(args = nil)
11
+ if args
12
12
  @hbs.set_context(args)
13
13
  end
14
14
 
15
15
  @ast.eval(@hbs)
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -1,5 +1,3 @@
1
- require 'colorize'
2
-
3
1
  module Handlebars
4
2
  module Tree
5
3
  class TreeItem < Struct
@@ -28,6 +26,12 @@ module Handlebars
28
26
  end
29
27
  end
30
28
 
29
+ class EscapedReplacement < Replacement
30
+ def _eval(context)
31
+ context.escaper.escape(super(context).to_s)
32
+ end
33
+ end
34
+
31
35
  class String < TreeItem.new(:content)
32
36
  def _eval(context)
33
37
  return content
@@ -50,9 +54,15 @@ module Handlebars
50
54
  end
51
55
  end
52
56
 
57
+ class EscapedHelper < Helper
58
+ def _eval(context)
59
+ context.escaper.escape(super(context).to_s)
60
+ end
61
+ end
62
+
53
63
  class Partial < TreeItem.new(:partial_name)
54
64
  def _eval(context)
55
- context.get_partial(partial_name.to_s).call(context)
65
+ context.get_partial(partial_name.to_s).call
56
66
  end
57
67
  end
58
68
 
@@ -70,12 +80,19 @@ module Handlebars
70
80
 
71
81
  class Transform < Parslet::Transform
72
82
  rule(template_content: simple(:content)) {Tree::TemplateContent.new(content)}
73
- rule(replaced_item: simple(:item)) {Tree::Replacement.new(item)}
83
+ rule(replaced_unsafe_item: simple(:item)) {Tree::EscapedReplacement.new(item)}
84
+ rule(replaced_safe_item: simple(:item)) {Tree::Replacement.new(item)}
74
85
  rule(str_content: simple(:content)) {Tree::String.new(content)}
75
86
  rule(parameter_name: simple(:name)) {Tree::Parameter.new(name)}
76
87
 
77
88
  rule(
78
- helper_name: simple(:name),
89
+ unsafe_helper_name: simple(:name),
90
+ parameters: subtree(:parameters)
91
+ ) {
92
+ Tree::EscapedHelper.new(name, parameters)
93
+ }
94
+ rule(
95
+ safe_helper_name: simple(:name),
79
96
  parameters: subtree(:parameters)
80
97
  ) {
81
98
  Tree::Helper.new(name, parameters)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-handlebars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vincent Pretre
@@ -9,88 +9,68 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-02-12 00:00:00.000000000 Z
12
+ date: 2019-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parslet
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: 1.6.2
21
18
  - - "~>"
22
19
  - !ruby/object:Gem::Version
23
20
  version: '1.6'
24
- type: :runtime
25
- prerelease: false
26
- version_requirements: !ruby/object:Gem::Requirement
27
- requirements:
28
21
  - - ">="
29
22
  - !ruby/object:Gem::Version
30
23
  version: 1.6.2
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.6'
34
- - !ruby/object:Gem::Dependency
35
- name: colorize
36
- requirement: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 0.7.5
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '0.7'
44
24
  type: :runtime
45
25
  prerelease: false
46
26
  version_requirements: !ruby/object:Gem::Requirement
47
27
  requirements:
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 0.7.5
51
28
  - - "~>"
52
29
  - !ruby/object:Gem::Version
53
- version: '0.7'
30
+ version: '1.6'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.2
54
34
  - !ruby/object:Gem::Dependency
55
35
  name: pry
56
36
  requirement: !ruby/object:Gem::Requirement
57
37
  requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 0.10.1
61
38
  - - "~>"
62
39
  - !ruby/object:Gem::Version
63
40
  version: '0.10'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.10.1
64
44
  type: :development
65
45
  prerelease: false
66
46
  version_requirements: !ruby/object:Gem::Requirement
67
47
  requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: 0.10.1
71
48
  - - "~>"
72
49
  - !ruby/object:Gem::Version
73
50
  version: '0.10'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.10.1
74
54
  - !ruby/object:Gem::Dependency
75
55
  name: pry-stack_explorer
76
56
  requirement: !ruby/object:Gem::Requirement
77
57
  requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: 0.4.9.1
81
58
  - - "~>"
82
59
  - !ruby/object:Gem::Version
83
60
  version: '0.4'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.4.9.1
84
64
  type: :development
85
65
  prerelease: false
86
66
  version_requirements: !ruby/object:Gem::Requirement
87
67
  requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- version: 0.4.9.1
91
68
  - - "~>"
92
69
  - !ruby/object:Gem::Version
93
70
  version: '0.4'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.4.9.1
94
74
  - !ruby/object:Gem::Dependency
95
75
  name: rspec
96
76
  requirement: !ruby/object:Gem::Requirement
@@ -115,62 +95,62 @@ dependencies:
115
95
  name: rspec-mocks
116
96
  requirement: !ruby/object:Gem::Requirement
117
97
  requirements:
118
- - - ">="
119
- - !ruby/object:Gem::Version
120
- version: 3.1.3
121
98
  - - "~>"
122
99
  - !ruby/object:Gem::Version
123
100
  version: '3.1'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.1.3
124
104
  type: :development
125
105
  prerelease: false
126
106
  version_requirements: !ruby/object:Gem::Requirement
127
107
  requirements:
128
- - - ">="
129
- - !ruby/object:Gem::Version
130
- version: 3.1.3
131
108
  - - "~>"
132
109
  - !ruby/object:Gem::Version
133
110
  version: '3.1'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 3.1.3
134
114
  - !ruby/object:Gem::Dependency
135
115
  name: codeclimate-test-reporter
136
116
  requirement: !ruby/object:Gem::Requirement
137
117
  requirements:
138
- - - ">="
139
- - !ruby/object:Gem::Version
140
- version: 0.4.6
141
118
  - - "~>"
142
119
  - !ruby/object:Gem::Version
143
120
  version: '0.4'
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 0.4.6
144
124
  type: :development
145
125
  prerelease: false
146
126
  version_requirements: !ruby/object:Gem::Requirement
147
127
  requirements:
148
- - - ">="
149
- - !ruby/object:Gem::Version
150
- version: 0.4.6
151
128
  - - "~>"
152
129
  - !ruby/object:Gem::Version
153
130
  version: '0.4'
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: 0.4.6
154
134
  - !ruby/object:Gem::Dependency
155
135
  name: jeweler
156
136
  requirement: !ruby/object:Gem::Requirement
157
137
  requirements:
158
- - - ">="
159
- - !ruby/object:Gem::Version
160
- version: 2.0.1
161
138
  - - "~>"
162
139
  - !ruby/object:Gem::Version
163
140
  version: '2.0'
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: 2.0.1
164
144
  type: :development
165
145
  prerelease: false
166
146
  version_requirements: !ruby/object:Gem::Requirement
167
147
  requirements:
168
- - - ">="
169
- - !ruby/object:Gem::Version
170
- version: 2.0.1
171
148
  - - "~>"
172
149
  - !ruby/object:Gem::Version
173
150
  version: '2.0'
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: 2.0.1
174
154
  description:
175
155
  email: v.pretre@hiptest.net
176
156
  executables: []
@@ -183,6 +163,8 @@ files:
183
163
  - README.md
184
164
  - lib/ruby-handlebars.rb
185
165
  - lib/ruby-handlebars/context.rb
166
+ - lib/ruby-handlebars/escapers/dummy_escaper.rb
167
+ - lib/ruby-handlebars/escapers/html_escaper.rb
186
168
  - lib/ruby-handlebars/helper.rb
187
169
  - lib/ruby-handlebars/parser.rb
188
170
  - lib/ruby-handlebars/template.rb
@@ -205,8 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
187
  - !ruby/object:Gem::Version
206
188
  version: '0'
207
189
  requirements: []
208
- rubyforge_project:
209
- rubygems_version: 2.6.10
190
+ rubygems_version: 3.0.4
210
191
  signing_key:
211
192
  specification_version: 4
212
193
  summary: Pure Ruby library for Handlebars templates