liquid 2.5.5 → 2.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/History.md +26 -11
- data/MIT-LICENSE +1 -1
- data/README.md +6 -0
- data/lib/extras/liquid_view.rb +9 -9
- data/lib/liquid.rb +1 -0
- data/lib/liquid/block.rb +16 -5
- data/lib/liquid/context.rb +17 -9
- data/lib/liquid/document.rb +1 -1
- data/lib/liquid/errors.rb +2 -1
- data/lib/liquid/file_system.rb +12 -12
- data/lib/liquid/htmltags.rb +1 -1
- data/lib/liquid/module_ex.rb +1 -1
- data/lib/liquid/standardfilters.rb +44 -22
- data/lib/liquid/strainer.rb +3 -3
- data/lib/liquid/tag.rb +1 -1
- data/lib/liquid/tags/assign.rb +14 -12
- data/lib/liquid/tags/break.rb +2 -2
- data/lib/liquid/tags/capture.rb +1 -0
- data/lib/liquid/tags/case.rb +28 -28
- data/lib/liquid/tags/continue.rb +1 -1
- data/lib/liquid/tags/cycle.rb +21 -21
- data/lib/liquid/tags/decrement.rb +7 -7
- data/lib/liquid/tags/for.rb +26 -26
- data/lib/liquid/tags/if.rb +3 -3
- data/lib/liquid/tags/ifchanged.rb +9 -9
- data/lib/liquid/tags/include.rb +42 -14
- data/lib/liquid/tags/increment.rb +7 -7
- data/lib/liquid/tags/raw.rb +5 -4
- data/lib/liquid/tags/unless.rb +8 -8
- data/lib/liquid/template.rb +11 -5
- data/lib/liquid/utils.rb +0 -1
- data/lib/liquid/variable.rb +2 -2
- data/lib/liquid/version.rb +4 -0
- data/test/liquid/assign_test.rb +1 -1
- data/test/liquid/condition_test.rb +1 -1
- data/test/liquid/hash_ordering_test.rb +25 -0
- data/test/liquid/output_test.rb +2 -2
- data/test/liquid/standard_filter_test.rb +18 -0
- data/test/liquid/tags/for_tag_test.rb +47 -34
- data/test/liquid/tags/html_tag_test.rb +2 -2
- data/test/liquid/tags/if_else_tag_test.rb +0 -6
- data/test/liquid/tags/include_tag_test.rb +28 -1
- data/test/liquid/tags/raw_tag_test.rb +11 -2
- data/test/liquid/template_test.rb +72 -0
- data/test/liquid/variable_test.rb +6 -0
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZTIwZjU2MjYxMGExMjE4NWMxM2YwMzdlOGY4ZThmNDFmZGMzZGYzMA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTgxNTU0ODAxMGEyZGNlN2VkMDgxNDAxZGZkZmNiZjJjZjdhZmJiNA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjQ4YTI3NWZjYmE2ZTZiYzkzOTI1NDE0NTQ3M2EwN2Q4NGNiYjUxM2NjZmEy
|
10
|
+
NWNhMmVlNzY1YTM4NWU1NzNjYjAzMzI2NzhlOWYyMTkxYTA5NTkyYjBiMjJj
|
11
|
+
NzdkMDAzNzRjNmIwODk1MGJjNjNjZjY2MTg3MmVjNGM4NjhkMTU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDQ1ZWE4MDM0NTU5MmFlOWU3ZmQzMWE2NTEyOTMzYjVjODViZDJkNGM3ODQ1
|
14
|
+
NmYyNDM1M2NiYjAzZmFhMThmNDIyOGJmN2E5NmFmODQ4YWY3MTY3MjZlMTg0
|
15
|
+
Y2I1ODVlMmJkZDQyYTMwOTY1MWM5ZDkyOTQ0NTA1MmE0NTEzYWQ=
|
data/History.md
CHANGED
@@ -1,16 +1,30 @@
|
|
1
1
|
# Liquid Version History
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
*
|
12
|
-
|
13
|
-
|
3
|
+
IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
|
4
|
+
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
|
5
|
+
|
6
|
+
## 2.6.0 (not yet released)
|
7
|
+
|
8
|
+
* ...
|
9
|
+
* Bugfix for #106: fix example servlet [gnowoel]
|
10
|
+
* Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss, joliss]
|
11
|
+
* Bugfix for #114: strip_html filter supports style tags [James Allardice, jamesallardice]
|
12
|
+
* Bugfix for #117: 'now' support for date filter in Ruby 1.9 [Notre Dame Webgroup, ndwebgroup]
|
13
|
+
* Bugfix for #166: truncate filter on UTF-8 strings with Ruby 1.8 [Florian Weingarten, fw42]
|
14
|
+
* Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
|
15
|
+
* Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
|
16
|
+
* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
|
17
|
+
* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
|
18
|
+
* Resource limits [Florian Weingarten, fw42]
|
19
|
+
* Add reverse filter [Jay Strybis, unreal]
|
20
|
+
* Add utf-8 support
|
21
|
+
* Use array instead of Hash to keep the registered filters [Tasos Stathopoulos, astathopoulos]
|
22
|
+
* Cache tokenized partial templates [Tom Burns, boourns]
|
23
|
+
* Avoid warnings in Ruby 1.9.3 [Marcus Stollsteimer, stomar]
|
24
|
+
* Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
|
25
|
+
* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
|
26
|
+
|
27
|
+
## 2.5.3 / branch "2.5-stable"
|
14
28
|
|
15
29
|
* #232, #234, #237: Fix map filter bugs [Florian Weingarten, fw42]
|
16
30
|
|
@@ -30,6 +44,7 @@ Yanked from rubygems, as it contained too many changes that broke compatibility.
|
|
30
44
|
* Fix filter parser for args without space separators
|
31
45
|
* Add support for filter keyword arguments
|
32
46
|
|
47
|
+
|
33
48
|
## 2.4.0 / 2012-08-03
|
34
49
|
|
35
50
|
* Performance improvements
|
data/MIT-LICENSE
CHANGED
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Liquid template engine
|
2
2
|
|
3
|
+
* [Contributing guidelines](CONTRIBUTING.md)
|
4
|
+
* [Version history](History.md)
|
5
|
+
* [Liquid documentation from Shopify](http://docs.shopify.com/themes/liquid-basics)
|
6
|
+
* [Liquid Wiki from Shopify](http://wiki.shopify.com/Liquid)
|
7
|
+
* [Website](http://liquidmarkup.org/)
|
8
|
+
|
3
9
|
## Introduction
|
4
10
|
|
5
11
|
Liquid is a template engine which was written with very specific requirements:
|
data/lib/extras/liquid_view.rb
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# and use liquid as an template system for .liquid files
|
3
3
|
#
|
4
4
|
# Example
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# ActionView::Base::register_template_handler :liquid, LiquidView
|
7
7
|
class LiquidView
|
8
8
|
PROTECTED_ASSIGNS = %w( template_root response _session template_class action_name request_origin session template
|
9
9
|
_response url _request _cookies variables_added _flash params _headers request cookies
|
10
10
|
ignore_missing_templates flash _params logger before_filter_chain_aborted headers )
|
11
|
-
PROTECTED_INSTANCE_VARIABLES = %w( @_request @controller @_first_render @_memoized__pick_template @view_paths
|
11
|
+
PROTECTED_INSTANCE_VARIABLES = %w( @_request @controller @_first_render @_memoized__pick_template @view_paths
|
12
12
|
@helpers @assigns_added @template @_render_stack @template_format @assigns )
|
13
|
-
|
13
|
+
|
14
14
|
def self.call(template)
|
15
15
|
"LiquidView.new(self).render(template, local_assigns)"
|
16
16
|
end
|
@@ -18,10 +18,10 @@ class LiquidView
|
|
18
18
|
def initialize(view)
|
19
19
|
@view = view
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def render(template, local_assigns = nil)
|
23
23
|
@view.controller.headers["Content-Type"] ||= 'text/html; charset=utf-8'
|
24
|
-
|
24
|
+
|
25
25
|
# Rails 2.2 Template has source, but not locals
|
26
26
|
if template.respond_to?(:source) && !template.respond_to?(:locals)
|
27
27
|
assigns = (@view.instance_variables - PROTECTED_INSTANCE_VARIABLES).inject({}) do |hash, ivar|
|
@@ -31,15 +31,15 @@ class LiquidView
|
|
31
31
|
else
|
32
32
|
assigns = @view.assigns.reject{ |k,v| PROTECTED_ASSIGNS.include?(k) }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
source = template.respond_to?(:source) ? template.source : template
|
36
36
|
local_assigns = (template.respond_to?(:locals) ? template.locals : local_assigns) || {}
|
37
|
-
|
37
|
+
|
38
38
|
if content_for_layout = @view.instance_variable_get("@content_for_layout")
|
39
39
|
assigns['content_for_layout'] = content_for_layout
|
40
40
|
end
|
41
41
|
assigns.merge!(local_assigns.stringify_keys)
|
42
|
-
|
42
|
+
|
43
43
|
liquid = Liquid::Template.parse(source)
|
44
44
|
liquid.render(assigns, :filters => [@view.controller.master_helper_module], :registers => {:action_view => @view, :controller => @view.controller})
|
45
45
|
end
|
@@ -48,4 +48,4 @@ class LiquidView
|
|
48
48
|
false
|
49
49
|
end
|
50
50
|
|
51
|
-
end
|
51
|
+
end
|
data/lib/liquid.rb
CHANGED
data/lib/liquid/block.rb
CHANGED
@@ -16,7 +16,7 @@ module Liquid
|
|
16
16
|
when IsTag
|
17
17
|
if token =~ FullToken
|
18
18
|
|
19
|
-
# if we found the proper block
|
19
|
+
# if we found the proper block delimiter just end parsing here and let the outer block
|
20
20
|
# proceed
|
21
21
|
if block_delimiter == $1
|
22
22
|
end_tag
|
@@ -43,8 +43,8 @@ module Liquid
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
# Make sure that
|
47
|
-
# Effectively this method will throw
|
46
|
+
# Make sure that it's ok to end parsing in the current block.
|
47
|
+
# Effectively this method will throw an exception unless the current block is
|
48
48
|
# of type Document
|
49
49
|
assert_missing_delimitation!
|
50
50
|
end
|
@@ -90,20 +90,31 @@ module Liquid
|
|
90
90
|
|
91
91
|
def render_all(list, context)
|
92
92
|
output = []
|
93
|
+
context.resource_limits[:render_length_current] = 0
|
94
|
+
context.resource_limits[:render_score_current] += list.length
|
95
|
+
|
93
96
|
list.each do |token|
|
94
97
|
# Break out if we have any unhanded interrupts.
|
95
98
|
break if context.has_interrupt?
|
96
99
|
|
97
100
|
begin
|
98
101
|
# If we get an Interrupt that means the block must stop processing. An
|
99
|
-
# Interrupt is any command that stops block execution such as {% break %}
|
102
|
+
# Interrupt is any command that stops block execution such as {% break %}
|
100
103
|
# or {% continue %}
|
101
104
|
if token.is_a? Continue or token.is_a? Break
|
102
105
|
context.push_interrupt(token.interrupt)
|
103
106
|
break
|
104
107
|
end
|
105
108
|
|
106
|
-
|
109
|
+
token_output = (token.respond_to?(:render) ? token.render(context) : token)
|
110
|
+
context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
|
111
|
+
if context.resource_limits_reached?
|
112
|
+
context.resource_limits[:reached] = true
|
113
|
+
raise MemoryError.new("Memory limits exceeded")
|
114
|
+
end
|
115
|
+
output << token_output
|
116
|
+
rescue MemoryError => e
|
117
|
+
raise e
|
107
118
|
rescue ::StandardError => e
|
108
119
|
output << (context.handle_error(e))
|
109
120
|
end
|
data/lib/liquid/context.rb
CHANGED
@@ -13,19 +13,26 @@ module Liquid
|
|
13
13
|
#
|
14
14
|
# context['bob'] #=> nil class Context
|
15
15
|
class Context
|
16
|
-
attr_reader :scopes, :errors, :registers, :environments
|
17
|
-
|
18
|
-
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false)
|
19
|
-
@environments
|
20
|
-
@scopes
|
21
|
-
@registers
|
22
|
-
@errors
|
23
|
-
@rethrow_errors
|
16
|
+
attr_reader :scopes, :errors, :registers, :environments, :resource_limits
|
17
|
+
|
18
|
+
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = {})
|
19
|
+
@environments = [environments].flatten
|
20
|
+
@scopes = [(outer_scope || {})]
|
21
|
+
@registers = registers
|
22
|
+
@errors = []
|
23
|
+
@rethrow_errors = rethrow_errors
|
24
|
+
@resource_limits = (resource_limits || {}).merge!({ :render_score_current => 0, :assign_score_current => 0 })
|
24
25
|
squash_instance_assigns_with_environments
|
25
26
|
|
26
27
|
@interrupts = []
|
27
28
|
end
|
28
29
|
|
30
|
+
def resource_limits_reached?
|
31
|
+
(@resource_limits[:render_length_limit] && @resource_limits[:render_length_current] > @resource_limits[:render_length_limit]) ||
|
32
|
+
(@resource_limits[:render_score_limit] && @resource_limits[:render_score_current] > @resource_limits[:render_score_limit] ) ||
|
33
|
+
(@resource_limits[:assign_score_limit] && @resource_limits[:assign_score_current] > @resource_limits[:assign_score_limit] )
|
34
|
+
end
|
35
|
+
|
29
36
|
def strainer
|
30
37
|
@strainer ||= Strainer.create(self)
|
31
38
|
end
|
@@ -46,7 +53,7 @@ module Liquid
|
|
46
53
|
|
47
54
|
# are there any not handled interrupts?
|
48
55
|
def has_interrupt?
|
49
|
-
|
56
|
+
@interrupts.any?
|
50
57
|
end
|
51
58
|
|
52
59
|
# push an interrupt to the stack. this interrupt is considered not handled.
|
@@ -165,6 +172,7 @@ module Liquid
|
|
165
172
|
# Fetches an object starting at the local scope and then moving up the hierachy
|
166
173
|
def find_variable(key)
|
167
174
|
scope = @scopes.find { |s| s.has_key?(key) }
|
175
|
+
variable = nil
|
168
176
|
|
169
177
|
if scope.nil?
|
170
178
|
@environments.each do |e|
|
data/lib/liquid/document.rb
CHANGED
data/lib/liquid/errors.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Error < ::StandardError; end
|
3
|
-
|
3
|
+
|
4
4
|
class ArgumentError < Error; end
|
5
5
|
class ContextError < Error; end
|
6
6
|
class FilterNotFound < Error; end
|
@@ -8,4 +8,5 @@ module Liquid
|
|
8
8
|
class StandardError < Error; end
|
9
9
|
class SyntaxError < Error; end
|
10
10
|
class StackLevelError < Error; end
|
11
|
+
class MemoryError < Error; end
|
11
12
|
end
|
data/lib/liquid/file_system.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Liquid
|
2
|
-
# A Liquid file system is way to let your templates retrieve other templates for use with the include tag.
|
2
|
+
# A Liquid file system is a way to let your templates retrieve other templates for use with the include tag.
|
3
3
|
#
|
4
|
-
# You can implement subclasses that retrieve templates from the database, from the file system using a different
|
4
|
+
# You can implement subclasses that retrieve templates from the database, from the file system using a different
|
5
5
|
# path structure, you can provide them as hard-coded inline strings, or any manner that you see fit.
|
6
6
|
#
|
7
7
|
# You can add additional instance variables, arguments, or methods as needed.
|
@@ -18,7 +18,7 @@ module Liquid
|
|
18
18
|
raise FileSystemError, "This liquid context does not allow includes."
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
# This implements an abstract file system which retrieves template files named in a manner similar to Rails partials,
|
23
23
|
# ie. with the template name prefixed with an underscore. The extension ".liquid" is also added.
|
24
24
|
#
|
@@ -27,36 +27,36 @@ module Liquid
|
|
27
27
|
# Example:
|
28
28
|
#
|
29
29
|
# file_system = Liquid::LocalFileSystem.new("/some/path")
|
30
|
-
#
|
30
|
+
#
|
31
31
|
# file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
|
32
32
|
# file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
|
33
33
|
#
|
34
34
|
class LocalFileSystem
|
35
35
|
attr_accessor :root
|
36
|
-
|
36
|
+
|
37
37
|
def initialize(root)
|
38
38
|
@root = root
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def read_template_file(template_path, context)
|
42
42
|
full_path = full_path(template_path)
|
43
43
|
raise FileSystemError, "No such template '#{template_path}'" unless File.exists?(full_path)
|
44
|
-
|
44
|
+
|
45
45
|
File.read(full_path)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def full_path(template_path)
|
49
49
|
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /^[^.\/][a-zA-Z0-9_\/]+$/
|
50
|
-
|
50
|
+
|
51
51
|
full_path = if template_path.include?('/')
|
52
52
|
File.join(root, File.dirname(template_path), "_#{File.basename(template_path)}.liquid")
|
53
53
|
else
|
54
54
|
File.join(root, "_#{template_path}.liquid")
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path) =~ /^#{File.expand_path(root)}/
|
58
|
-
|
58
|
+
|
59
59
|
full_path
|
60
60
|
end
|
61
61
|
end
|
62
|
-
end
|
62
|
+
end
|
data/lib/liquid/htmltags.rb
CHANGED
@@ -57,7 +57,7 @@ module Liquid
|
|
57
57
|
|
58
58
|
result << "<td class=\"col#{col}\">" << render_all(@nodelist, context) << '</td>'
|
59
59
|
|
60
|
-
if col == cols and
|
60
|
+
if col == cols and (index != length - 1)
|
61
61
|
col = 0
|
62
62
|
row += 1
|
63
63
|
result << "</tr>\n<tr class=\"row#{row}\">"
|
data/lib/liquid/module_ex.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# This library is free software. It may be used, redistributed and/or modified
|
3
3
|
# under the same terms as Ruby itself
|
4
4
|
#
|
5
|
-
# This extension is
|
5
|
+
# This extension is used in order to expose the object of the implementing class
|
6
6
|
# to liquid as it were a Drop. It also limits the liquid-callable methods of the instance
|
7
7
|
# to the allowed method passed with the liquid_methods call
|
8
8
|
# Example:
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'cgi'
|
2
|
+
require 'bigdecimal'
|
2
3
|
|
3
4
|
module Liquid
|
4
5
|
|
@@ -10,12 +11,12 @@ module Liquid
|
|
10
11
|
input.respond_to?(:size) ? input.size : 0
|
11
12
|
end
|
12
13
|
|
13
|
-
# convert
|
14
|
+
# convert an input string to DOWNCASE
|
14
15
|
def downcase(input)
|
15
16
|
input.to_s.downcase
|
16
17
|
end
|
17
18
|
|
18
|
-
# convert
|
19
|
+
# convert an input string to UPCASE
|
19
20
|
def upcase(input)
|
20
21
|
input.to_s.upcase
|
21
22
|
end
|
@@ -42,7 +43,8 @@ module Liquid
|
|
42
43
|
if input.nil? then return end
|
43
44
|
l = length.to_i - truncate_string.length
|
44
45
|
l = 0 if l < 0
|
45
|
-
|
46
|
+
truncated = RUBY_VERSION[0,3] == "1.8" ? input.scan(/./mu)[0...l].to_s : input[0...l]
|
47
|
+
input.length > length.to_i ? truncated + truncate_string : input
|
46
48
|
end
|
47
49
|
|
48
50
|
def truncatewords(input, words = 15, truncate_string = "...")
|
@@ -63,15 +65,14 @@ module Liquid
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def strip_html(input)
|
66
|
-
input.to_s.gsub(/<script.*?<\/script
|
68
|
+
input.to_s.gsub(/<script.*?<\/script>/m, '').gsub(/<!--.*?-->/m, '').gsub(/<style.*?<\/style>/m, '').gsub(/<.*?>/m, '')
|
67
69
|
end
|
68
70
|
|
69
71
|
# Remove all newlines from the string
|
70
72
|
def strip_newlines(input)
|
71
|
-
input.to_s.gsub(/\n/, '')
|
73
|
+
input.to_s.gsub(/\r?\n/, '')
|
72
74
|
end
|
73
75
|
|
74
|
-
|
75
76
|
# Join elements of the array with certain character between them
|
76
77
|
def join(input, glue = ' ')
|
77
78
|
[input].flatten.join(glue)
|
@@ -90,6 +91,12 @@ module Liquid
|
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
94
|
+
# Reverse the elements of an array
|
95
|
+
def reverse(input)
|
96
|
+
ary = [input].flatten
|
97
|
+
ary.reverse
|
98
|
+
end
|
99
|
+
|
93
100
|
# map/collect on a given property
|
94
101
|
def map(input, property)
|
95
102
|
ary = [input].flatten
|
@@ -178,14 +185,23 @@ module Liquid
|
|
178
185
|
input = Time.at(input.to_i)
|
179
186
|
end
|
180
187
|
|
181
|
-
date = input.is_a?(String)
|
188
|
+
date = if input.is_a?(String)
|
189
|
+
case input.downcase
|
190
|
+
when 'now', 'today'
|
191
|
+
Time.now
|
192
|
+
else
|
193
|
+
Time.parse(input)
|
194
|
+
end
|
195
|
+
else
|
196
|
+
input
|
197
|
+
end
|
182
198
|
|
183
199
|
if date.respond_to?(:strftime)
|
184
200
|
date.strftime(format.to_s)
|
185
201
|
else
|
186
202
|
input
|
187
203
|
end
|
188
|
-
rescue
|
204
|
+
rescue
|
189
205
|
input
|
190
206
|
end
|
191
207
|
|
@@ -209,41 +225,47 @@ module Liquid
|
|
209
225
|
|
210
226
|
# addition
|
211
227
|
def plus(input, operand)
|
212
|
-
|
228
|
+
apply_operation(input, operand, :+)
|
213
229
|
end
|
214
230
|
|
215
231
|
# subtraction
|
216
232
|
def minus(input, operand)
|
217
|
-
|
233
|
+
apply_operation(input, operand, :-)
|
218
234
|
end
|
219
235
|
|
220
236
|
# multiplication
|
221
237
|
def times(input, operand)
|
222
|
-
|
238
|
+
apply_operation(input, operand, :*)
|
223
239
|
end
|
224
240
|
|
225
241
|
# division
|
226
242
|
def divided_by(input, operand)
|
227
|
-
|
243
|
+
apply_operation(input, operand, :/)
|
228
244
|
end
|
229
245
|
|
230
246
|
def modulo(input, operand)
|
231
|
-
|
247
|
+
apply_operation(input, operand, :%)
|
232
248
|
end
|
233
249
|
|
234
250
|
private
|
235
251
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
252
|
+
def to_number(obj)
|
253
|
+
case obj
|
254
|
+
when Float
|
255
|
+
BigDecimal.new(obj.to_s)
|
256
|
+
when Numeric
|
257
|
+
obj
|
258
|
+
when String
|
259
|
+
(obj.strip =~ /^\d+\.\d+$/) ? BigDecimal.new(obj) : obj.to_i
|
260
|
+
else
|
261
|
+
0
|
245
262
|
end
|
263
|
+
end
|
246
264
|
|
265
|
+
def apply_operation(input, operand, operation)
|
266
|
+
result = to_number(input).send(operation, to_number(operand))
|
267
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
268
|
+
end
|
247
269
|
end
|
248
270
|
|
249
271
|
Template.register_filter(StandardFilters)
|