Skip to content

Commit

Permalink
array filters should not crash on strings
Browse files Browse the repository at this point in the history
Official Shopidyf Liquid also can run array filters on strings,
considering them to be one element array.
  • Loading branch information
mikz committed Oct 5, 2018
1 parent 8783931 commit 74c185d
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 16 deletions.
45 changes: 31 additions & 14 deletions lib/liquid.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2777,33 +2777,52 @@ function FilterSet:find_filter( filter_name )
return self.filterset[filter_name]
end
end

local function is_iterator(o)
local mt = getmetatable(o)

return mt and mt.__ipairs
end

local function iterator(o)
if type(o) == 'table' or is_iterator(o) then
return o
else
return { o }
end
end

--=== array filter begin
local function join( a, b)
-- body
return Interpreter:safe_concat(a, b)
return Interpreter:safe_concat(iterator(a), b or ' ')
end
local function first( a )
-- body
return a[1]
return iterator(a)[1]
end
local function size( a )
-- body
return(#iterator(a))
end
local function last( a )
-- body
return a[#a]
return iterator(a)[size(a)]
end
local function concat( a, b)
-- body
local temp = {}
for i,v in ipairs(a) do
for i,v in ipairs(iterator(a)) do
table.insert(temp, v)
end
for i,v in ipairs(b) do
for i,v in ipairs(iterator(b)) do
table.insert(temp, v)
end
return temp
end
local function index( a, b)
-- body
return a[(b + 1)]
return iterator(a)[(b + 1)]
end
local function map( a, map_field)
-- body
Expand All @@ -2816,20 +2835,18 @@ end
local function reverse( a )
-- body
local temp = {}
local num = #a
local it = iterator(a)
local num = size(a)
for k = num, 1, -1 do
table.insert(temp, a[k])
table.insert(temp, it[k])
end
return temp
end
local function size( a )
-- body
return(#a)
end

local function sort( a, sort_field)
-- body
local t = {}
for i,v in ipairs(a) do
for i,v in ipairs(iterator(a)) do
table.insert(t, v)
end
if not sort_field then
Expand All @@ -2845,7 +2862,7 @@ local function uniq( a )
-- body
local t = {}
local result = {}
for i,v in ipairs(a) do
for i,v in ipairs(iterator(a)) do
local k = cjson.encode(v)
if not t[k] then
t[k] = true
Expand Down
172 changes: 170 additions & 2 deletions t/array_filters.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ plan tests => repeat_each() * (3 * blocks());

my $pwd = cwd();

our $HttpConfig = qq{
our $HttpConfig = qq|
lua_package_path "$pwd/lib/?.lua;;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
};
init_by_lua_block { Liquid = require 'liquid' }
|;


no_long_string();
Expand Down Expand Up @@ -264,3 +265,170 @@ GET /t
--- no_error_log
[error]
=== TEST 11: 'join' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- str | join: ' - ' -}}
]]):render(Liquid.InterpreterContext:new({ str = "string" })) )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 12: 'first' filter works strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- str | first -}}
]]):render(Liquid.InterpreterContext:new({ str = "string" })) )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 13: 'last' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- str | last -}}
]]):render( Liquid.InterpreterContext:new({ str = "string" })) )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 14: 'concat' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{%- assign a = "string" | concat:(1..3) -%}
{%- assign b = "string" | concat: "another" -%}
{%- for k in a %} {{k}} {%- endfor -%}
{%- for k in b %} {{k}} {%- endfor -%}
]]):render())
}
}
--- request
GET /t
--- response_body
string 1 2 3 string another
--- no_error_log
[error]
=== TEST 5: 'index' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- "string"| index: 0 -}}
]]):render() )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 16: 'reverse' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- "string" | reverse | join -}}
]]):render() )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 17: 'size' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- "string" | size -}}
]]):render() )
}
}
--- request
GET /t
--- response_body
1
--- no_error_log
[error]
=== TEST 18: 'sort' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- "string" | sort | join -}}
]]):render() )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]
=== TEST 19: 'uniq' filter works on strings
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
ngx.say( Liquid.Template:parse([[
{{- "string" | uniq | join -}}
]]):render() )
}
}
--- request
GET /t
--- response_body
string
--- no_error_log
[error]

0 comments on commit 74c185d

Please sign in to comment.