mvz-ruby-handlebars 0.0.8 → 0.0.9

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
  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