mvz-ruby-handlebars 0.0.8 → 0.0.9

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
2
  SHA256:
3
- metadata.gz: f21f04865d286b910b694ff3508df456632310bb99aa38b22f9e24d68032bff6
4
- data.tar.gz: d05c3566c291638e663295f8a0f425c09f961257e738d8ef1235f3a1b326fb66
3
+ metadata.gz: c677856bd3e74f5198f64f3b10b9348530b95024889ff1cf6db380c1165c771f
4
+ data.tar.gz: 1ff2e3bba711f257d9412ef9aa074fad8ca87429ab5b2ad0033187b289c586e0
5
5
  SHA512:
6
- metadata.gz: 2554ca12e855afd1777dc31de33d125ff0fb7fd9cc657af834231cdf2e67674bbe7e37d21a0480a382127e12d8477e800f2afc43e5a120b27ed54380c18c07e1
7
- data.tar.gz: 6fcfb339dadb0924ba02d6a1f4f139459a8f01da7b5137978edb13d4121f1e9122f211ef99b09ec8d9f49d03e5bcebf23de8d75c4dcfa6249a518296aff619c4
6
+ metadata.gz: 00be980edd23a6f537a5c7e6354f592826651a795f4a4b7055f26db4d31778c90c7e8a9367e9450578bf0b8c74d690409c52137c337017074edd6163c8148ff2
7
+ data.tar.gz: 2d89f9b244cad437e7ee33b75562197071dac7d0ccb66be0b83d183f86b9774b16c79178f467fa8f72201b9ef563bbc8b7bc7c2288b81462718f0a7aff5b1b07
@@ -0,0 +1,10 @@
1
+ mvz-ruby-handlebars changelog
2
+ =============================
3
+
4
+ 0.0.9 (2021-01-04)
5
+ ------------------
6
+
7
+ - Pull in upstream master. See
8
+ https://github.com/SmartBear/ruby-handlebars/blob/master/CHANGELOG.md for
9
+ included changes.
10
+ - Prefer variable over helper when processing a replacement if the helper has the wrong arity
data/README.md CHANGED
@@ -40,6 +40,13 @@ hbs.compile("Hello {{> full_name}}").call({person: {first_name: 'Pinkie', last_n
40
40
  # Gives: "Hello Pinkie Pie"
41
41
  ```
42
42
 
43
+ Partials support parameters:
44
+ ```ruby
45
+ hbs.register_partial('full_name', "{{fname}} {{lname}}")
46
+ hbs.compile("Hello {{> full_name fname='jon' lname='doe'}}")
47
+ # Gives: "Hello jon doe"
48
+ ```
49
+
43
50
  You can also register inline helpers:
44
51
 
45
52
  ```ruby
@@ -81,22 +88,59 @@ hbs.compile(template).call({description: my_description})
81
88
  # Output will depend on the validity of the 'my_description' variable
82
89
  ```
83
90
 
84
- Two default helpers are provided: ``each`` and ``if``. It is not yet possible to name the current item in an each loop and ``this`` must be used to reference it.
91
+ Default helpers:
92
+ ----------------
93
+
94
+ Three default helpers are provided: ``each``, ``if`` and ``unless``.
95
+
96
+ The each helper let you walk through a list. You can either use the basic notation and referencing the current item as ``this``:
97
+
98
+ ```
99
+ {{#each items}}
100
+ {{{ this }}}
101
+ {{else}}
102
+ No items
103
+ {{/each}}
104
+ ```
105
+
106
+ or the "as |name|" notation:
107
+
108
+ ```
109
+ {{#each items as |item| }}
110
+ {{{ item }}}
111
+ {{else}}
112
+ No items
113
+ {{/each}}
114
+ ```
115
+
116
+ The ``if`` helper can be used to write conditionnal templates:
117
+
118
+ ```
119
+ {{#if my_condition}}
120
+ It's ok
121
+ {{else}}
122
+ or maybe not
123
+ {{/if}}
124
+ ```
125
+
126
+ The ``unless`` helper works the opposite way to ``if``:
127
+
128
+ ```
129
+ {{#unless my_condition}}
130
+ It's not ok
131
+ {{else}}
132
+ or maybe it is
133
+ {{/unless}}
134
+ ```
135
+
136
+ Currently, if you call an unknown helper, it will raise an exception. You can override that by registering your own version of the ``helperMissing`` helper. Note that only the name of the missing helper will be provided.
137
+
138
+ For example:
85
139
 
86
140
  ```ruby
87
- template = [
88
- "{{#each items}}",
89
- " {{{ this }}}",
90
- "{{else}}",
91
- " No items",
92
- "{{/each}}",
93
- "",
94
- "{{#if my_condition}}",
95
- " It's ok",
96
- "{{else}}",
97
- " or maybe not",
98
- "{{/if}}",
99
- ].join("\n")
141
+ hbs.register_helper('helperMissing') do |context, name|
142
+ puts "No helper found with name #{name}"
143
+ end
100
144
  ```
101
145
 
102
146
  Limitations and roadmap
@@ -104,12 +148,10 @@ Limitations and roadmap
104
148
 
105
149
  This gem does not reuse the real Handlebars code (the JS one) and not everything is handled yet (but it will be someday ;) ):
106
150
 
107
- - there is no escaping, all strings are considered as safe (so ``{{{ my_var }}}`` and ``{{ my_var }}``) will output the same thing
108
151
  - the parser is not fully tested yet, it may complain with spaces ...
109
- - curly bracket are __not__ usable in the template content yet. one workaround is to create simple helpers to generate them
110
152
  - parsing errors are, well, not helpful at all
111
153
 
112
154
  Aknowledgements
113
155
  ---------------
114
156
 
115
- This is a fork of the [ruby-handlebars]("https://github.com/vincent-psarga/ruby-handlebars") gem, which sadly seems unmaintained.
157
+ This is a fork of the [ruby-handlebars]("https://github.com/vincent-psarga/ruby-handlebars") gem. Eventually I hope to have all my changes accepted upstream so I can abandon this fork.
@@ -1,17 +1,23 @@
1
1
  require_relative 'ruby-handlebars/version'
2
- require_relative 'ruby-handlebars/helper'
3
2
  require_relative 'ruby-handlebars/context'
4
3
  require_relative 'ruby-handlebars/parser'
5
- require_relative 'ruby-handlebars/template'
6
4
  require_relative 'ruby-handlebars/tree'
5
+ require_relative 'ruby-handlebars/template'
6
+ require_relative 'ruby-handlebars/helper'
7
+ require_relative 'ruby-handlebars/helpers/register_default_helpers'
8
+ require_relative 'ruby-handlebars/escapers/html_escaper'
7
9
 
8
10
  module Handlebars
9
11
  class Handlebars
12
+ attr_reader :escaper
13
+
10
14
  def initialize
15
+ @as_helpers = {}
11
16
  @helpers = {}
12
17
  @partials = {}
13
18
 
14
19
  register_default_helpers
20
+ set_escaper
15
21
  end
16
22
 
17
23
  def compile(template)
@@ -22,10 +28,18 @@ module Handlebars
22
28
  @helpers[name.to_s] = Helper.new(self, fn)
23
29
  end
24
30
 
31
+ def register_as_helper(name, &fn)
32
+ @as_helpers[name.to_s] = Helper.new(self, fn)
33
+ end
34
+
25
35
  def get_helper(name)
26
36
  @helpers[name.to_s]
27
37
  end
28
38
 
39
+ def get_as_helper(name)
40
+ @as_helpers[name.to_s]
41
+ end
42
+
29
43
  def register_partial(name, content)
30
44
  @partials[name.to_s] = Template.new(self, template_to_ast(content))
31
45
  end
@@ -34,6 +48,10 @@ module Handlebars
34
48
  @partials[name.to_s]
35
49
  end
36
50
 
51
+ def set_escaper(escaper = nil)
52
+ @escaper = escaper || Escapers::HTMLEscaper
53
+ end
54
+
37
55
  private
38
56
 
39
57
  PARSER = Parser.new
@@ -44,42 +62,7 @@ module Handlebars
44
62
  end
45
63
 
46
64
  def register_default_helpers
47
- register_if_helper
48
- register_each_helper
49
- end
50
-
51
- def register_if_helper
52
- register_helper('if') do |context, condition, block, else_block|
53
- condition = !condition.empty? if condition.respond_to?(:empty?)
54
-
55
- if condition
56
- block.fn(context)
57
- elsif else_block
58
- else_block.fn(context)
59
- else
60
- ""
61
- end
62
- end
63
- end
64
-
65
- def register_each_helper
66
- register_helper('each') do |context, items, block, else_block|
67
- current_this = context.get('this')
68
-
69
- if (items.nil? || items.empty?)
70
- if else_block
71
- result = else_block.fn(context)
72
- end
73
- else
74
- result = items.map do |item|
75
- context.add_item(:this, item)
76
- block.fn(context)
77
- end.join('')
78
- end
79
-
80
- context.add_item(:this, current_this)
81
- result
82
- end
65
+ Helpers.register_default_helpers(self)
83
66
  end
84
67
  end
85
68
  end
@@ -8,12 +8,12 @@ module Handlebars
8
8
 
9
9
  def get(path)
10
10
  items = path.split('.'.freeze)
11
-
12
- if @locals.key? items.first.to_sym
13
- current = @locals
11
+ if locals.key? items.first.to_sym
12
+ current = locals
14
13
  else
15
14
  current = @data
16
15
  end
16
+
17
17
  until items.empty?
18
18
  current = get_attribute(current, items.shift)
19
19
  end
@@ -21,20 +21,46 @@ module Handlebars
21
21
  current
22
22
  end
23
23
 
24
+ def escaper
25
+ @hbs.escaper
26
+ end
27
+
24
28
  def get_helper(name)
25
29
  @hbs.get_helper(name)
26
30
  end
27
31
 
32
+ def get_as_helper(name)
33
+ @hbs.get_as_helper(name)
34
+ end
35
+
28
36
  def get_partial(name)
29
37
  @hbs.get_partial(name)
30
38
  end
31
39
 
32
40
  def add_item(key, value)
33
- @locals[key.to_sym] = value
41
+ locals[key.to_sym] = value
42
+ end
43
+
44
+ def add_items(hash)
45
+ hash.map { |k, v| add_item(k, v) }
46
+ end
47
+
48
+ def with_temporary_context(args = {})
49
+ saved = args.keys.collect { |key| [key, get(key.to_s)] }.to_h
50
+
51
+ add_items(args)
52
+ block_result = yield
53
+ locals.merge!(saved)
54
+
55
+ block_result
34
56
  end
35
57
 
36
58
  private
37
59
 
60
+ def locals
61
+ @locals ||= {}
62
+ end
63
+
38
64
  def get_attribute(item, attribute)
39
65
  sym_attr = attribute.to_sym
40
66
  str_attr = attribute.to_s
@@ -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
@@ -7,35 +7,39 @@ module Handlebars
7
7
  @fn = fn
8
8
  end
9
9
 
10
- def apply(context, arguments = [], block = [])
10
+ def arity
11
+ @fn.arity
12
+ end
13
+
14
+ def apply(context, arguments = [], block = [], else_block = [])
11
15
  arguments = [arguments] unless arguments.is_a? Array
12
- args = [context] + arguments.map {|arg| arg.eval(context)} + split_block(block || [])
16
+ args = [context] + arguments.map {|arg| arg.eval(context)} + split_block(block, else_block)
13
17
 
14
18
  @fn.call(*args)
15
19
  end
16
20
 
17
- def split_block(block)
18
- helper_block = Tree::Block.new([])
19
- inverse_block = Tree::Block.new([])
20
-
21
- receiver = helper_block
22
- else_found = false
21
+ def apply_as(context, arguments = [], as_arguments = [], block = [], else_block = [])
22
+ arguments = [arguments] unless arguments.is_a? Array
23
+ as_arguments = [as_arguments] unless as_arguments.is_a? Array
24
+ args = [context] + arguments.map {|arg| arg.eval(context)} + as_arguments.map(&:name) + split_block(block, else_block)
23
25
 
24
- block.each do |item|
25
- if item.is_a?(Tree::Helper) && item.is_else?
26
- receiver = inverse_block
27
- else_found = true
28
- next
29
- end
26
+ @fn.call(*args)
27
+ end
30
28
 
31
- receiver.add_item(item)
32
- end
29
+ private
33
30
 
34
- if else_found
35
- return [helper_block, inverse_block]
31
+ def split_block(block, else_block)
32
+ if else_block
33
+ [ensure_block(block), ensure_block(else_block)]
36
34
  else
37
- return [helper_block]
35
+ [ensure_block(block)]
38
36
  end
39
37
  end
38
+
39
+ def ensure_block(block)
40
+ new_block = Tree::Block.new([])
41
+ block.each {|item| new_block.add_item(item) } unless block.nil?
42
+ new_block
43
+ end
40
44
  end
41
45
  end
@@ -0,0 +1,28 @@
1
+ module Handlebars
2
+ module Helpers
3
+ class DefaultHelper
4
+ def self.register(hbs)
5
+ hbs.register_helper(self.registry_name) do |context, parameters, block, else_block|
6
+ self.apply(context, parameters, block, else_block)
7
+ end if self.respond_to?(:apply)
8
+
9
+ hbs.register_as_helper(self.registry_name) do |context, parameters, as_names, block, else_block|
10
+ self.apply_as(context, parameters, as_names, block, else_block)
11
+ end if self.respond_to?(:apply_as)
12
+ end
13
+
14
+ # Should be implemented by sub-classes
15
+ # def self.registry_name
16
+ # 'myHelperName'
17
+ # end
18
+
19
+ # def self.apply(context, parameters, block, else_block)
20
+ # # Do things and stuff
21
+ # end
22
+
23
+ # def self.apply_as(context, parameters, as_names, block, else_block)
24
+ # # Do things and stuffa, but with 'as |param| notation'
25
+ # end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'default_helper'
2
+
3
+ module Handlebars
4
+ module Helpers
5
+ class EachHelper < DefaultHelper
6
+ def self.registry_name
7
+ 'each'
8
+ end
9
+
10
+ def self.apply(context, items, block, else_block)
11
+ self.apply_as(context, items, :this, block, else_block)
12
+ end
13
+
14
+ def self.apply_as(context, items, name, block, else_block)
15
+ if (items.nil? || items.empty?)
16
+ if else_block
17
+ result = else_block.fn(context)
18
+ end
19
+ else
20
+ context.with_temporary_context(name => nil, :@index => 0, :@first => false, :@last => false) do
21
+ result = items.each_with_index.map do |item, index|
22
+ context.add_items(name => item, :@index => index, :@first => (index == 0), :@last => (index == items.length - 1))
23
+ block.fn(context)
24
+ end.join('')
25
+ end
26
+ end
27
+ result
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'default_helper'
2
+
3
+ module Handlebars
4
+ class UnknownHelper < StandardError
5
+ end
6
+
7
+ module Helpers
8
+ class HelperMissingHelper < DefaultHelper
9
+ def self.registry_name
10
+ 'helperMissing'
11
+ end
12
+
13
+ def self.apply(context, name, block, else_block)
14
+ raise(::Handlebars::UnknownHelper, "Helper \"#{name}\" does not exist" )
15
+ end
16
+ end
17
+ end
18
+ end