Skip to content

Commit dcf3a4a

Browse files
authored
Merge pull request #7 from 3scale/filter-iterator
array filters should not crash on strings
2 parents ce79ebf + 74c185d commit dcf3a4a

2 files changed

Lines changed: 201 additions & 16 deletions

File tree

lib/liquid.lua

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,33 +2777,52 @@ function FilterSet:find_filter( filter_name )
27772777
return self.filterset[filter_name]
27782778
end
27792779
end
2780+
2781+
local function is_iterator(o)
2782+
local mt = getmetatable(o)
2783+
2784+
return mt and mt.__ipairs
2785+
end
2786+
2787+
local function iterator(o)
2788+
if type(o) == 'table' or is_iterator(o) then
2789+
return o
2790+
else
2791+
return { o }
2792+
end
2793+
end
2794+
27802795
--=== array filter begin
27812796
local function join( a, b)
27822797
-- body
2783-
return Interpreter:safe_concat(a, b)
2798+
return Interpreter:safe_concat(iterator(a), b or ' ')
27842799
end
27852800
local function first( a )
27862801
-- body
2787-
return a[1]
2802+
return iterator(a)[1]
2803+
end
2804+
local function size( a )
2805+
-- body
2806+
return(#iterator(a))
27882807
end
27892808
local function last( a )
27902809
-- body
2791-
return a[#a]
2810+
return iterator(a)[size(a)]
27922811
end
27932812
local function concat( a, b)
27942813
-- body
27952814
local temp = {}
2796-
for i,v in ipairs(a) do
2815+
for i,v in ipairs(iterator(a)) do
27972816
table.insert(temp, v)
27982817
end
2799-
for i,v in ipairs(b) do
2818+
for i,v in ipairs(iterator(b)) do
28002819
table.insert(temp, v)
28012820
end
28022821
return temp
28032822
end
28042823
local function index( a, b)
28052824
-- body
2806-
return a[(b + 1)]
2825+
return iterator(a)[(b + 1)]
28072826
end
28082827
local function map( a, map_field)
28092828
-- body
@@ -2816,20 +2835,18 @@ end
28162835
local function reverse( a )
28172836
-- body
28182837
local temp = {}
2819-
local num = #a
2838+
local it = iterator(a)
2839+
local num = size(a)
28202840
for k = num, 1, -1 do
2821-
table.insert(temp, a[k])
2841+
table.insert(temp, it[k])
28222842
end
28232843
return temp
28242844
end
2825-
local function size( a )
2826-
-- body
2827-
return(#a)
2828-
end
2845+
28292846
local function sort( a, sort_field)
28302847
-- body
28312848
local t = {}
2832-
for i,v in ipairs(a) do
2849+
for i,v in ipairs(iterator(a)) do
28332850
table.insert(t, v)
28342851
end
28352852
if not sort_field then
@@ -2845,7 +2862,7 @@ local function uniq( a )
28452862
-- body
28462863
local t = {}
28472864
local result = {}
2848-
for i,v in ipairs(a) do
2865+
for i,v in ipairs(iterator(a)) do
28492866
local k = cjson.encode(v)
28502867
if not t[k] then
28512868
t[k] = true

t/array_filters.t

Lines changed: 170 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ plan tests => repeat_each() * (3 * blocks());
77

88
my $pwd = cwd();
99

10-
our $HttpConfig = qq{
10+
our $HttpConfig = qq|
1111
lua_package_path "$pwd/lib/?.lua;;;";
1212
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
13-
};
13+
init_by_lua_block { Liquid = require 'liquid' }
14+
|;
1415

1516

1617
no_long_string();
@@ -264,3 +265,170 @@ GET /t
264265
--- no_error_log
265266
[error]
266267
268+
269+
270+
=== TEST 11: 'join' filter works on strings
271+
--- http_config eval: $::HttpConfig
272+
--- config
273+
location /t {
274+
content_by_lua_block {
275+
ngx.say( Liquid.Template:parse([[
276+
{{- str | join: ' - ' -}}
277+
]]):render(Liquid.InterpreterContext:new({ str = "string" })) )
278+
}
279+
}
280+
--- request
281+
GET /t
282+
--- response_body
283+
string
284+
--- no_error_log
285+
[error]
286+
287+
=== TEST 12: 'first' filter works strings
288+
--- http_config eval: $::HttpConfig
289+
--- config
290+
location /t {
291+
content_by_lua_block {
292+
ngx.say( Liquid.Template:parse([[
293+
{{- str | first -}}
294+
]]):render(Liquid.InterpreterContext:new({ str = "string" })) )
295+
}
296+
}
297+
--- request
298+
GET /t
299+
--- response_body
300+
string
301+
--- no_error_log
302+
[error]
303+
304+
305+
306+
=== TEST 13: 'last' filter works on strings
307+
--- http_config eval: $::HttpConfig
308+
--- config
309+
location /t {
310+
content_by_lua_block {
311+
ngx.say( Liquid.Template:parse([[
312+
{{- str | last -}}
313+
]]):render( Liquid.InterpreterContext:new({ str = "string" })) )
314+
}
315+
}
316+
--- request
317+
GET /t
318+
--- response_body
319+
string
320+
--- no_error_log
321+
[error]
322+
323+
=== TEST 14: 'concat' filter works on strings
324+
--- http_config eval: $::HttpConfig
325+
--- config
326+
location /t {
327+
content_by_lua_block {
328+
ngx.say( Liquid.Template:parse([[
329+
{%- assign a = "string" | concat:(1..3) -%}
330+
{%- assign b = "string" | concat: "another" -%}
331+
{%- for k in a %} {{k}} {%- endfor -%}
332+
{%- for k in b %} {{k}} {%- endfor -%}
333+
]]):render())
334+
}
335+
}
336+
--- request
337+
GET /t
338+
--- response_body
339+
string 1 2 3 string another
340+
--- no_error_log
341+
[error]
342+
343+
=== TEST 5: 'index' filter works on strings
344+
--- http_config eval: $::HttpConfig
345+
--- config
346+
location /t {
347+
content_by_lua_block {
348+
ngx.say( Liquid.Template:parse([[
349+
{{- "string"| index: 0 -}}
350+
]]):render() )
351+
}
352+
}
353+
--- request
354+
GET /t
355+
--- response_body
356+
string
357+
--- no_error_log
358+
[error]
359+
360+
361+
=== TEST 16: 'reverse' filter works on strings
362+
--- http_config eval: $::HttpConfig
363+
--- config
364+
location /t {
365+
content_by_lua_block {
366+
ngx.say( Liquid.Template:parse([[
367+
{{- "string" | reverse | join -}}
368+
]]):render() )
369+
}
370+
}
371+
--- request
372+
GET /t
373+
--- response_body
374+
string
375+
--- no_error_log
376+
[error]
377+
378+
379+
380+
=== TEST 17: 'size' filter works on strings
381+
--- http_config eval: $::HttpConfig
382+
--- config
383+
location /t {
384+
content_by_lua_block {
385+
ngx.say( Liquid.Template:parse([[
386+
{{- "string" | size -}}
387+
]]):render() )
388+
}
389+
}
390+
--- request
391+
GET /t
392+
--- response_body
393+
1
394+
--- no_error_log
395+
[error]
396+
397+
398+
399+
=== TEST 18: 'sort' filter works on strings
400+
--- http_config eval: $::HttpConfig
401+
--- config
402+
location /t {
403+
content_by_lua_block {
404+
ngx.say( Liquid.Template:parse([[
405+
{{- "string" | sort | join -}}
406+
]]):render() )
407+
}
408+
}
409+
--- request
410+
GET /t
411+
--- response_body
412+
string
413+
414+
--- no_error_log
415+
[error]
416+
417+
418+
419+
=== TEST 19: 'uniq' filter works on strings
420+
--- http_config eval: $::HttpConfig
421+
--- config
422+
location /t {
423+
content_by_lua_block {
424+
ngx.say( Liquid.Template:parse([[
425+
{{- "string" | uniq | join -}}
426+
]]):render() )
427+
}
428+
}
429+
--- request
430+
GET /t
431+
--- response_body
432+
string
433+
--- no_error_log
434+
[error]

0 commit comments

Comments
 (0)