mirror of
https://github.com/kemko/liquid.git
synced 2026-01-06 02:05:41 +03:00
Compare commits
20 Commits
enable-cla
...
v4.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2f467bdbc | ||
|
|
ff99d92c18 | ||
|
|
39fecd06db | ||
|
|
8013df8ca2 | ||
|
|
14cd011cb5 | ||
|
|
e2d9907df2 | ||
|
|
23d669f5e6 | ||
|
|
ed73794f82 | ||
|
|
f59f6dea83 | ||
|
|
7a81fb821a | ||
|
|
cec27ea326 | ||
|
|
14999e8f7c | ||
|
|
b41fc10d8e | ||
|
|
2b3c81cfd0 | ||
|
|
2a2376bfd9 | ||
|
|
ca9e75db53 | ||
|
|
407c8abf30 | ||
|
|
43f181e211 | ||
|
|
89c1ba2b0e | ||
|
|
479d8fb4a4 |
@@ -71,10 +71,7 @@ Style/Documentation:
|
|||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/TrailingCommaInArrayLiteral:
|
Style/TrailingCommaInLiteral:
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Style/TrailingCommaInHashLiteral:
|
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Layout/IndentHash:
|
Layout/IndentHash:
|
||||||
@@ -125,6 +122,6 @@ Style/TrivialAccessors:
|
|||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Naming/MethodName:
|
Style/MethodName:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'example/server/liquid_servlet.rb'
|
- 'example/server/liquid_servlet.rb'
|
||||||
|
|||||||
@@ -1,30 +1,11 @@
|
|||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config`
|
# `rubocop --auto-gen-config`
|
||||||
# on 2017-11-22 11:35:55 -0500 using RuboCop version 0.49.1.
|
# on 2019-02-03 21:12:39 +0530 using RuboCop version 0.49.1.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
# versions of RuboCop, may require this file to be generated again.
|
||||||
|
|
||||||
# Offense count: 3
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Layout/ClosingParenthesisIndentation:
|
|
||||||
Exclude:
|
|
||||||
- 'test/integration/error_handling_test.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Layout/EmptyLineAfterMagicComment:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid/version.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
|
||||||
Layout/ExtraSpacing:
|
|
||||||
Exclude:
|
|
||||||
- 'test/integration/parsing_quirks_test.rb'
|
|
||||||
|
|
||||||
# Offense count: 5
|
# Offense count: 5
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
@@ -51,31 +32,26 @@ Lint/InheritException:
|
|||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/liquid/interrupts.rb'
|
- 'lib/liquid/interrupts.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 51
|
||||||
Lint/ScriptPermission:
|
|
||||||
Exclude:
|
|
||||||
- 'test/test_helper.rb'
|
|
||||||
|
|
||||||
# Offense count: 52
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 56
|
Max: 56
|
||||||
|
|
||||||
# Offense count: 13
|
# Offense count: 11
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Max: 12
|
Max: 12
|
||||||
|
|
||||||
# Offense count: 620
|
# Offense count: 639
|
||||||
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
||||||
# URISchemes: http, https
|
# URISchemes: http, https
|
||||||
Metrics/LineLength:
|
Metrics/LineLength:
|
||||||
Max: 294
|
Max: 294
|
||||||
|
|
||||||
# Offense count: 102
|
# Offense count: 108
|
||||||
# Configuration parameters: CountComments.
|
# Configuration parameters: CountComments.
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Max: 37
|
Max: 37
|
||||||
|
|
||||||
# Offense count: 9
|
# Offense count: 7
|
||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Max: 11
|
Max: 11
|
||||||
|
|
||||||
@@ -143,23 +119,6 @@ Style/GuardClause:
|
|||||||
- 'lib/liquid/variable.rb'
|
- 'lib/liquid/variable.rb'
|
||||||
- 'test/unit/tokenizer_unit_test.rb'
|
- 'test/unit/tokenizer_unit_test.rb'
|
||||||
|
|
||||||
# Offense count: 4
|
|
||||||
# Configuration parameters: SupportedStyles.
|
|
||||||
# SupportedStyles: snake_case, camelCase
|
|
||||||
Style/MethodName:
|
|
||||||
EnforcedStyle: snake_case
|
|
||||||
|
|
||||||
# Offense count: 6
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Style/MutableConstant:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid/expression.rb'
|
|
||||||
- 'lib/liquid/lexer.rb'
|
|
||||||
- 'lib/liquid/standardfilters.rb'
|
|
||||||
- 'lib/liquid/tags/if.rb'
|
|
||||||
- 'lib/liquid/variable_lookup.rb'
|
|
||||||
- 'lib/liquid/version.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||||
@@ -190,12 +149,6 @@ Style/PercentLiteralDelimiters:
|
|||||||
- 'test/integration/assign_test.rb'
|
- 'test/integration/assign_test.rb'
|
||||||
- 'test/integration/standard_filter_test.rb'
|
- 'test/integration/standard_filter_test.rb'
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Style/RedundantParentheses:
|
|
||||||
Exclude:
|
|
||||||
- 'test/unit/condition_unit_test.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/RedundantSelf:
|
Style/RedundantSelf:
|
||||||
@@ -227,13 +180,6 @@ Style/TernaryParentheses:
|
|||||||
- 'lib/liquid/context.rb'
|
- 'lib/liquid/context.rb'
|
||||||
- 'lib/liquid/utils.rb'
|
- 'lib/liquid/utils.rb'
|
||||||
|
|
||||||
# Offense count: 4
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Style/UnneededInterpolation:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/liquid/i18n.rb'
|
|
||||||
- 'test/integration/standard_filter_test.rb'
|
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 2
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/UnneededPercentQ:
|
Style/UnneededPercentQ:
|
||||||
|
|||||||
53
History.md
53
History.md
@@ -1,5 +1,58 @@
|
|||||||
# Liquid Change Log
|
# Liquid Change Log
|
||||||
|
|
||||||
|
## 4.0.3 / 2019-03-12
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fix break and continue tags inside included templates in loops (#1072) [Justin Li]
|
||||||
|
|
||||||
|
## 4.0.2 / 2019-03-08
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Add `where` filter (#1026) [Samuel Doiron]
|
||||||
|
* Add `ParseTreeVisitor` to iterate the Liquid AST (#1025) [Stephen Paul Weber]
|
||||||
|
* Improve `strip_html` performance (#1032) [printercu]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Add error checking for invalid combinations of inputs to sort, sort_natural, where, uniq, map, compact filters (#1059) [Garland Zhang]
|
||||||
|
* Validate the character encoding in url_decode (#1070) [Clayton Smith]
|
||||||
|
|
||||||
|
## 4.0.1 / 2018-10-09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Add benchmark group in Gemfile (#855) [Jerry Liu]
|
||||||
|
* Allow benchmarks to benchmark render by itself (#851) [Jerry Liu]
|
||||||
|
* Avoid calling `line_number` on String node when rescuing a render error. (#860) [Dylan Thacker-Smith]
|
||||||
|
* Avoid duck typing to detect whether to call render on a node. [Dylan Thacker-Smith]
|
||||||
|
* Clarify spelling of `reversed` on `for` block tag (#843) [Mark Crossfield]
|
||||||
|
* Replace recursion with loop to avoid potential stack overflow from malicious input (#891, #892) [Dylan Thacker-Smith]
|
||||||
|
* Limit block tag nesting to 100 (#894) [Dylan Thacker-Smith]
|
||||||
|
* Replace `assert_equal nil` with `assert_nil` (#895) [Dylan Thacker-Smith]
|
||||||
|
* Remove Spy Gem (#896) [Dylan Thacker-Smith]
|
||||||
|
* Add `collection_name` and `variable_name` reader to `For` block (#909)
|
||||||
|
* Symbols render as strings (#920) [Justin Li]
|
||||||
|
* Remove default value from Hash objects (#932) [Maxime Bedard]
|
||||||
|
* Remove one level of nesting (#944) [Dylan Thacker-Smith]
|
||||||
|
* Update Rubocop version (#952) [Justin Li]
|
||||||
|
* Add `at_least` and `at_most` filters (#954, #958) [Nithin Bekal]
|
||||||
|
* Add a regression test for a liquid-c trim mode bug (#972) [Dylan Thacker-Smith]
|
||||||
|
* Use https rather than git protocol to fetch liquid-c [Dylan Thacker-Smith]
|
||||||
|
* Add tests against Ruby 2.4 (#963) and 2.5 (#981)
|
||||||
|
* Replace RegExp literals with constants (#988) [Ashwin Maroli]
|
||||||
|
* Replace unnecessary `#each_with_index` with `#each` (#992) [Ashwin Maroli]
|
||||||
|
* Improve the unexpected end delimiter message for block tags. (#1003) [Dylan Thacker-Smith]
|
||||||
|
* Refactor and optimize rendering (#1005) [Christopher Aue]
|
||||||
|
* Add installation instruction (#1006) [Ben Gift]
|
||||||
|
* Remove Circle CI (#1010)
|
||||||
|
* Rename deprecated `BigDecimal.new` to `BigDecimal` (#1024) [Koichi ITO]
|
||||||
|
* Rename deprecated Rubocop name (#1027) [Justin Li]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Handle `join` filter on non String joiners (#857) [Richard Monette]
|
||||||
|
* Fix duplicate inclusion condition logic error of `Liquid::Strainer.add_filter` method (#861)
|
||||||
|
* Fix `escape`, `url_encode`, `url_decode` not handling non-string values (#898) [Thierry Joyal]
|
||||||
|
* Fix raise when variable is defined but nil when using `strict_variables` [Pascal Betz]
|
||||||
|
* Fix `sort` and `sort_natural` to handle arrays with nils (#930) [Eric Chan]
|
||||||
|
|
||||||
## 4.0.0 / 2016-12-14 / branch "4-0-stable"
|
## 4.0.0 / 2016-12-14 / branch "4-0-stable"
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
2
Rakefile
2
Rakefile
@@ -3,7 +3,7 @@ require 'rake/testtask'
|
|||||||
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
||||||
require "liquid/version"
|
require "liquid/version"
|
||||||
|
|
||||||
task default: [:rubocop, :test]
|
task default: [:test, :rubocop]
|
||||||
|
|
||||||
desc 'run test suite with default parser'
|
desc 'run test suite with default parser'
|
||||||
Rake::TestTask.new(:base_test) do |t|
|
Rake::TestTask.new(:base_test) do |t|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ module Liquid
|
|||||||
break
|
break
|
||||||
else # Other non-Block tags
|
else # Other non-Block tags
|
||||||
render_node_to_output(node, output, context)
|
render_node_to_output(node, output, context)
|
||||||
|
break if context.interrupt? # might have happened through an include
|
||||||
end
|
end
|
||||||
idx += 1
|
idx += 1
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ module Liquid
|
|||||||
'false'.freeze => false,
|
'false'.freeze => false,
|
||||||
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
|
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
|
||||||
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
|
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
|
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
|
||||||
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
|
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module Liquid
|
|||||||
def interpolate(name, vars)
|
def interpolate(name, vars)
|
||||||
name.gsub(/%\{(\w+)\}/) do
|
name.gsub(/%\{(\w+)\}/) do
|
||||||
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
||||||
"#{vars[$1.to_sym]}"
|
(vars[$1.to_sym]).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module Liquid
|
|||||||
')'.freeze => :close_round,
|
')'.freeze => :close_round,
|
||||||
'?'.freeze => :question,
|
'?'.freeze => :question,
|
||||||
'-'.freeze => :dash
|
'-'.freeze => :dash
|
||||||
}
|
}.freeze
|
||||||
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
|
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
|
||||||
SINGLE_STRING_LITERAL = /'[^\']*'/
|
SINGLE_STRING_LITERAL = /'[^\']*'/
|
||||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||||
|
|||||||
@@ -9,8 +9,14 @@ module Liquid
|
|||||||
'<'.freeze => '<'.freeze,
|
'<'.freeze => '<'.freeze,
|
||||||
'"'.freeze => '"'.freeze,
|
'"'.freeze => '"'.freeze,
|
||||||
"'".freeze => '''.freeze
|
"'".freeze => '''.freeze
|
||||||
}
|
}.freeze
|
||||||
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
||||||
|
STRIP_HTML_BLOCKS = Regexp.union(
|
||||||
|
/<script.*?<\/script>/m,
|
||||||
|
/<!--.*?-->/m,
|
||||||
|
/<style.*?<\/style>/m
|
||||||
|
)
|
||||||
|
STRIP_HTML_TAGS = /<.*?>/m
|
||||||
|
|
||||||
# Return the size of an array or of an string
|
# Return the size of an array or of an string
|
||||||
def size(input)
|
def size(input)
|
||||||
@@ -46,7 +52,12 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def url_decode(input)
|
def url_decode(input)
|
||||||
CGI.unescape(input.to_s) unless input.nil?
|
return if input.nil?
|
||||||
|
|
||||||
|
result = CGI.unescape(input.to_s)
|
||||||
|
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
|
||||||
|
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def slice(input, offset, length = nil)
|
def slice(input, offset, length = nil)
|
||||||
@@ -103,7 +114,9 @@ module Liquid
|
|||||||
|
|
||||||
def strip_html(input)
|
def strip_html(input)
|
||||||
empty = ''.freeze
|
empty = ''.freeze
|
||||||
input.to_s.gsub(/<script.*?<\/script>/m, empty).gsub(/<!--.*?-->/m, empty).gsub(/<style.*?<\/style>/m, empty).gsub(/<.*?>/m, empty)
|
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
||||||
|
result.gsub!(STRIP_HTML_TAGS, empty)
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove all newlines from the string
|
# Remove all newlines from the string
|
||||||
@@ -120,25 +133,18 @@ module Liquid
|
|||||||
# provide optional property with which to sort an array of hashes or drops
|
# provide optional property with which to sort an array of hashes or drops
|
||||||
def sort(input, property = nil)
|
def sort(input, property = nil)
|
||||||
ary = InputIterator.new(input)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
|
return [] if ary.empty?
|
||||||
|
|
||||||
if property.nil?
|
if property.nil?
|
||||||
ary.sort do |a, b|
|
ary.sort do |a, b|
|
||||||
if !a.nil? && !b.nil?
|
nil_safe_compare(a, b)
|
||||||
a <=> b
|
|
||||||
else
|
|
||||||
a.nil? ? 1 : -1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
elsif ary.empty? # The next two cases assume a non-empty array.
|
|
||||||
[]
|
|
||||||
elsif ary.all? { |el| el.respond_to?(:[]) }
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
||||||
ary.sort do |a, b|
|
begin
|
||||||
a = a[property]
|
ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
|
||||||
b = b[property]
|
rescue TypeError
|
||||||
if !a.nil? && !b.nil?
|
raise_property_error(property)
|
||||||
a <=> b
|
|
||||||
else
|
|
||||||
a.nil? ? 1 : -1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -148,25 +154,17 @@ module Liquid
|
|||||||
def sort_natural(input, property = nil)
|
def sort_natural(input, property = nil)
|
||||||
ary = InputIterator.new(input)
|
ary = InputIterator.new(input)
|
||||||
|
|
||||||
|
return [] if ary.empty?
|
||||||
|
|
||||||
if property.nil?
|
if property.nil?
|
||||||
ary.sort do |a, b|
|
ary.sort do |a, b|
|
||||||
if !a.nil? && !b.nil?
|
nil_safe_casecmp(a, b)
|
||||||
a.to_s.casecmp(b.to_s)
|
|
||||||
else
|
|
||||||
a.nil? ? 1 : -1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
elsif ary.empty? # The next two cases assume a non-empty array.
|
|
||||||
[]
|
|
||||||
elsif ary.all? { |el| el.respond_to?(:[]) }
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
||||||
ary.sort do |a, b|
|
begin
|
||||||
a = a[property]
|
ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
|
||||||
b = b[property]
|
rescue TypeError
|
||||||
if !a.nil? && !b.nil?
|
raise_property_error(property)
|
||||||
a.to_s.casecmp(b.to_s)
|
|
||||||
else
|
|
||||||
a.nil? ? 1 : -1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -179,9 +177,17 @@ module Liquid
|
|||||||
if ary.empty?
|
if ary.empty?
|
||||||
[]
|
[]
|
||||||
elsif ary.first.respond_to?(:[]) && target_value.nil?
|
elsif ary.first.respond_to?(:[]) && target_value.nil?
|
||||||
ary.where_present(property)
|
begin
|
||||||
|
ary.select { |item| item[property] }
|
||||||
|
rescue TypeError
|
||||||
|
raise_property_error(property)
|
||||||
|
end
|
||||||
elsif ary.first.respond_to?(:[])
|
elsif ary.first.respond_to?(:[])
|
||||||
ary.where(property, target_value)
|
begin
|
||||||
|
ary.select { |item| item[property] == target_value }
|
||||||
|
rescue TypeError
|
||||||
|
raise_property_error(property)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -195,7 +201,11 @@ module Liquid
|
|||||||
elsif ary.empty? # The next two cases assume a non-empty array.
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
||||||
[]
|
[]
|
||||||
elsif ary.first.respond_to?(:[])
|
elsif ary.first.respond_to?(:[])
|
||||||
ary.uniq{ |a| a[property] }
|
begin
|
||||||
|
ary.uniq { |a| a[property] }
|
||||||
|
rescue TypeError
|
||||||
|
raise_property_error(property)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -217,6 +227,8 @@ module Liquid
|
|||||||
r.is_a?(Proc) ? r.call : r
|
r.is_a?(Proc) ? r.call : r
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rescue TypeError
|
||||||
|
raise_property_error(property)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove nils within an array
|
# Remove nils within an array
|
||||||
@@ -229,7 +241,11 @@ module Liquid
|
|||||||
elsif ary.empty? # The next two cases assume a non-empty array.
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
||||||
[]
|
[]
|
||||||
elsif ary.first.respond_to?(:[])
|
elsif ary.first.respond_to?(:[])
|
||||||
ary.reject{ |a| a[property].nil? }
|
begin
|
||||||
|
ary.reject { |a| a[property].nil? }
|
||||||
|
rescue TypeError
|
||||||
|
raise_property_error(property)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -413,11 +429,31 @@ module Liquid
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def raise_property_error(property)
|
||||||
|
raise Liquid::ArgumentError.new("cannot select the property '#{property}'")
|
||||||
|
end
|
||||||
|
|
||||||
def apply_operation(input, operand, operation)
|
def apply_operation(input, operand, operation)
|
||||||
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
|
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
|
||||||
result.is_a?(BigDecimal) ? result.to_f : result
|
result.is_a?(BigDecimal) ? result.to_f : result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def nil_safe_compare(a, b)
|
||||||
|
if !a.nil? && !b.nil?
|
||||||
|
a <=> b
|
||||||
|
else
|
||||||
|
a.nil? ? 1 : -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def nil_safe_casecmp(a, b)
|
||||||
|
if !a.nil? && !b.nil?
|
||||||
|
a.to_s.casecmp(b.to_s)
|
||||||
|
else
|
||||||
|
a.nil? ? 1 : -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class InputIterator
|
class InputIterator
|
||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
@@ -463,24 +499,6 @@ module Liquid
|
|||||||
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
|
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def where(property, target_value)
|
|
||||||
select do |item|
|
|
||||||
item[property] == target_value
|
|
||||||
end
|
|
||||||
rescue TypeError
|
|
||||||
# Cannot index with the given property type (eg. indexing integers with strings
|
|
||||||
# which are only allowed to be indexed by other integers).
|
|
||||||
raise ArgumentError.new("cannot select the property `#{property}`")
|
|
||||||
end
|
|
||||||
|
|
||||||
def where_present(property)
|
|
||||||
select { |item| item[property] }
|
|
||||||
rescue TypeError
|
|
||||||
# Cannot index with the given property type (eg. indexing integers with strings
|
|
||||||
# which are only allowed to be indexed by other integers).
|
|
||||||
raise ArgumentError.new("cannot select the property `#{property}`")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module Liquid
|
|||||||
class If < Block
|
class If < Block
|
||||||
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
||||||
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
||||||
BOOLEAN_OPERATORS = %w(and or)
|
BOOLEAN_OPERATORS = %w(and or).freeze
|
||||||
|
|
||||||
attr_reader :blocks
|
attr_reader :blocks
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module Liquid
|
module Liquid
|
||||||
class VariableLookup
|
class VariableLookup
|
||||||
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
||||||
COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze]
|
COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze
|
||||||
|
|
||||||
attr_reader :name, :lookups
|
attr_reader :name, :lookups
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
module Liquid
|
module Liquid
|
||||||
VERSION = "4.0.1"
|
VERSION = "4.0.3".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
',
|
',
|
||||||
error_mode: :warn,
|
error_mode: :warn,
|
||||||
line_numbers: true
|
line_numbers: true
|
||||||
)
|
)
|
||||||
|
|
||||||
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
||||||
template.warnings.map(&:message)
|
template.warnings.map(&:message)
|
||||||
@@ -140,7 +140,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
',
|
',
|
||||||
error_mode: :strict,
|
error_mode: :strict,
|
||||||
line_numbers: true
|
line_numbers: true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
||||||
@@ -158,7 +158,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
bla
|
bla
|
||||||
',
|
',
|
||||||
line_numbers: true
|
line_numbers: true
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class ParsingQuirksTest < Minitest::Test
|
|||||||
# After the messed up quotes a filter without parameters (reverse) should work
|
# After the messed up quotes a filter without parameters (reverse) should work
|
||||||
# but one with parameters (remove) shouldn't be detected.
|
# but one with parameters (remove) shouldn't be detected.
|
||||||
assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
|
assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
|
||||||
assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
|
assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal '1', @filters.url_decode(1)
|
assert_equal '1', @filters.url_decode(1)
|
||||||
assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3))
|
assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3))
|
||||||
assert_nil @filters.url_decode(nil)
|
assert_nil @filters.url_decode(nil)
|
||||||
|
exception = assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.url_decode('%ff')
|
||||||
|
end
|
||||||
|
assert_equal 'Liquid error: invalid byte sequence in UTF-8', exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_truncatewords
|
def test_truncatewords
|
||||||
@@ -177,6 +181,9 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal 'test', @filters.strip_html("<div\nclass='multiline'>test</div>")
|
assert_equal 'test', @filters.strip_html("<div\nclass='multiline'>test</div>")
|
||||||
assert_equal 'test', @filters.strip_html("<!-- foo bar \n test -->test")
|
assert_equal 'test', @filters.strip_html("<!-- foo bar \n test -->test")
|
||||||
assert_equal '', @filters.strip_html(nil)
|
assert_equal '', @filters.strip_html(nil)
|
||||||
|
|
||||||
|
# Quirk of the existing implementation
|
||||||
|
assert_equal 'foo;', @filters.strip_html("<<<script </script>script>foo;</script>")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_join
|
def test_join
|
||||||
@@ -268,10 +275,34 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal [], @filters.sort([], "a")
|
assert_equal [], @filters.sort([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_sort_invalid_property
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.sort(foo, "bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_sort_natural_empty_array
|
def test_sort_natural_empty_array
|
||||||
assert_equal [], @filters.sort_natural([], "a")
|
assert_equal [], @filters.sort_natural([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_sort_natural_invalid_property
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.sort_natural(foo, "bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_legacy_sort_hash
|
def test_legacy_sort_hash
|
||||||
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
||||||
end
|
end
|
||||||
@@ -295,10 +326,34 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal [], @filters.uniq([], "a")
|
assert_equal [], @filters.uniq([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_uniq_invalid_property
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.uniq(foo, "bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_compact_empty_array
|
def test_compact_empty_array
|
||||||
assert_equal [], @filters.compact([], "a")
|
assert_equal [], @filters.compact([], "a")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_compact_invalid_property
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.compact(foo, "bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_reverse
|
def test_reverse
|
||||||
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
|
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
|
||||||
end
|
end
|
||||||
@@ -364,6 +419,29 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_map_returns_empty_on_2d_input_array
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.map(foo, "bar")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_map_returns_empty_with_no_property
|
||||||
|
foo = [
|
||||||
|
[1],
|
||||||
|
[2],
|
||||||
|
[3]
|
||||||
|
]
|
||||||
|
assert_raises Liquid::ArgumentError do
|
||||||
|
@filters.map(foo, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_sort_works_on_enumerables
|
def test_sort_works_on_enumerables
|
||||||
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
||||||
end
|
end
|
||||||
@@ -394,9 +472,9 @@ class StandardFiltersTest < Minitest::Test
|
|||||||
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
|
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
|
||||||
|
|
||||||
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
||||||
assert_equal "#{Date.today.year}", @filters.date('now', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
|
||||||
assert_equal "#{Date.today.year}", @filters.date('today', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
|
||||||
assert_equal "#{Date.today.year}", @filters.date('Today', '%Y')
|
assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
|
||||||
|
|
||||||
assert_nil @filters.date(nil, "%B")
|
assert_nil @filters.date(nil, "%B")
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ class TestFileSystem
|
|||||||
when 'assignments'
|
when 'assignments'
|
||||||
"{% assign foo = 'bar' %}"
|
"{% assign foo = 'bar' %}"
|
||||||
|
|
||||||
|
when 'break'
|
||||||
|
"{% break %}"
|
||||||
|
|
||||||
else
|
else
|
||||||
template_path
|
template_path
|
||||||
end
|
end
|
||||||
@@ -242,4 +245,9 @@ class IncludeTagTest < Minitest::Test
|
|||||||
|
|
||||||
assert_equal [], template.errors
|
assert_equal [], template.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_break_through_include
|
||||||
|
assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}"
|
||||||
|
assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}"
|
||||||
|
end
|
||||||
end # IncludeTagTest
|
end # IncludeTagTest
|
||||||
|
|||||||
0
test/test_helper.rb
Normal file → Executable file
0
test/test_helper.rb
Normal file → Executable file
@@ -24,9 +24,9 @@ class ConditionUnitTest < Minitest::Test
|
|||||||
assert_evaluates_true 1, '<=', 1
|
assert_evaluates_true 1, '<=', 1
|
||||||
# negative numbers
|
# negative numbers
|
||||||
assert_evaluates_true 1, '>', -1
|
assert_evaluates_true 1, '>', -1
|
||||||
assert_evaluates_true (-1), '<', 1
|
assert_evaluates_true -1, '<', 1
|
||||||
assert_evaluates_true 1.0, '>', -1.0
|
assert_evaluates_true 1.0, '>', -1.0
|
||||||
assert_evaluates_true (-1.0), '<', 1.0
|
assert_evaluates_true -1.0, '<', 1.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_operators_evalute_false
|
def test_default_operators_evalute_false
|
||||||
|
|||||||
Reference in New Issue
Block a user