liquid 3.0.6 → 4.0.0.rc1

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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +89 -58
  3. data/{MIT-LICENSE → LICENSE} +0 -0
  4. data/lib/liquid.rb +7 -6
  5. data/lib/liquid/block.rb +31 -124
  6. data/lib/liquid/block_body.rb +54 -57
  7. data/lib/liquid/condition.rb +23 -22
  8. data/lib/liquid/context.rb +50 -42
  9. data/lib/liquid/document.rb +19 -9
  10. data/lib/liquid/drop.rb +12 -13
  11. data/lib/liquid/errors.rb +16 -17
  12. data/lib/liquid/expression.rb +15 -3
  13. data/lib/liquid/extensions.rb +7 -7
  14. data/lib/liquid/file_system.rb +3 -3
  15. data/lib/liquid/forloop_drop.rb +42 -0
  16. data/lib/liquid/i18n.rb +5 -5
  17. data/lib/liquid/interrupts.rb +1 -2
  18. data/lib/liquid/lexer.rb +6 -4
  19. data/lib/liquid/locales/en.yml +3 -1
  20. data/lib/liquid/parse_context.rb +37 -0
  21. data/lib/liquid/parser_switching.rb +4 -4
  22. data/lib/liquid/profiler.rb +18 -19
  23. data/lib/liquid/profiler/hooks.rb +7 -7
  24. data/lib/liquid/range_lookup.rb +16 -1
  25. data/lib/liquid/resource_limits.rb +23 -0
  26. data/lib/liquid/standardfilters.rb +101 -56
  27. data/lib/liquid/strainer.rb +4 -5
  28. data/lib/liquid/tablerowloop_drop.rb +62 -0
  29. data/lib/liquid/tag.rb +9 -8
  30. data/lib/liquid/tags/assign.rb +5 -4
  31. data/lib/liquid/tags/break.rb +0 -3
  32. data/lib/liquid/tags/capture.rb +1 -1
  33. data/lib/liquid/tags/case.rb +19 -12
  34. data/lib/liquid/tags/comment.rb +2 -2
  35. data/lib/liquid/tags/cycle.rb +6 -6
  36. data/lib/liquid/tags/decrement.rb +1 -4
  37. data/lib/liquid/tags/for.rb +93 -75
  38. data/lib/liquid/tags/if.rb +49 -44
  39. data/lib/liquid/tags/ifchanged.rb +0 -2
  40. data/lib/liquid/tags/include.rb +60 -52
  41. data/lib/liquid/tags/raw.rb +26 -4
  42. data/lib/liquid/tags/table_row.rb +12 -30
  43. data/lib/liquid/tags/unless.rb +3 -4
  44. data/lib/liquid/template.rb +23 -50
  45. data/lib/liquid/tokenizer.rb +31 -0
  46. data/lib/liquid/utils.rb +48 -8
  47. data/lib/liquid/variable.rb +46 -45
  48. data/lib/liquid/variable_lookup.rb +3 -3
  49. data/lib/liquid/version.rb +1 -1
  50. data/test/integration/assign_test.rb +8 -8
  51. data/test/integration/blank_test.rb +14 -14
  52. data/test/integration/context_test.rb +2 -2
  53. data/test/integration/document_test.rb +19 -0
  54. data/test/integration/drop_test.rb +42 -40
  55. data/test/integration/error_handling_test.rb +64 -45
  56. data/test/integration/filter_test.rb +60 -20
  57. data/test/integration/output_test.rb +26 -27
  58. data/test/integration/parsing_quirks_test.rb +15 -13
  59. data/test/integration/render_profiling_test.rb +20 -20
  60. data/test/integration/security_test.rb +5 -7
  61. data/test/integration/standard_filter_test.rb +119 -37
  62. data/test/integration/tags/break_tag_test.rb +1 -2
  63. data/test/integration/tags/continue_tag_test.rb +0 -1
  64. data/test/integration/tags/for_tag_test.rb +133 -98
  65. data/test/integration/tags/if_else_tag_test.rb +75 -77
  66. data/test/integration/tags/include_tag_test.rb +23 -30
  67. data/test/integration/tags/increment_tag_test.rb +10 -11
  68. data/test/integration/tags/raw_tag_test.rb +7 -1
  69. data/test/integration/tags/standard_tag_test.rb +121 -122
  70. data/test/integration/tags/statements_test.rb +3 -5
  71. data/test/integration/tags/table_row_test.rb +20 -19
  72. data/test/integration/tags/unless_else_tag_test.rb +6 -6
  73. data/test/integration/template_test.rb +91 -45
  74. data/test/integration/variable_test.rb +23 -13
  75. data/test/test_helper.rb +33 -5
  76. data/test/unit/block_unit_test.rb +6 -5
  77. data/test/unit/condition_unit_test.rb +82 -77
  78. data/test/unit/context_unit_test.rb +48 -57
  79. data/test/unit/file_system_unit_test.rb +3 -3
  80. data/test/unit/i18n_unit_test.rb +2 -2
  81. data/test/unit/lexer_unit_test.rb +11 -8
  82. data/test/unit/parser_unit_test.rb +2 -2
  83. data/test/unit/regexp_unit_test.rb +1 -1
  84. data/test/unit/strainer_unit_test.rb +13 -2
  85. data/test/unit/tag_unit_test.rb +7 -2
  86. data/test/unit/tags/case_tag_unit_test.rb +1 -1
  87. data/test/unit/tags/for_tag_unit_test.rb +2 -2
  88. data/test/unit/tags/if_tag_unit_test.rb +1 -1
  89. data/test/unit/template_unit_test.rb +6 -5
  90. data/test/unit/tokenizer_unit_test.rb +24 -7
  91. data/test/unit/variable_unit_test.rb +60 -43
  92. metadata +44 -41
  93. data/lib/liquid/module_ex.rb +0 -62
  94. data/lib/liquid/token.rb +0 -18
  95. data/test/unit/module_ex_unit_test.rb +0 -87
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # Break tag to be used to break out of a for loop.
4
3
  #
5
4
  # == Basic Usage:
@@ -10,11 +9,9 @@ module Liquid
10
9
  # {% endfor %}
11
10
  #
12
11
  class Break < Tag
13
-
14
12
  def interrupt
15
13
  BreakInterrupt.new
16
14
  end
17
-
18
15
  end
19
16
 
20
17
  Template.register_tag('break'.freeze, Break)
@@ -25,7 +25,7 @@ module Liquid
25
25
  def render(context)
26
26
  output = super
27
27
  context.scopes.last[@to] = output
28
- context.increment_used_resources(:assign_score_current, output)
28
+ context.resource_limits.assign_score += output.length
29
29
  ''.freeze
30
30
  end
31
31
 
@@ -8,18 +8,24 @@ module Liquid
8
8
  @blocks = []
9
9
 
10
10
  if markup =~ Syntax
11
- @left = $1
11
+ @left = Expression.parse($1)
12
12
  else
13
13
  raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
14
14
  end
15
15
  end
16
16
 
17
+ def parse(tokens)
18
+ body = BlockBody.new
19
+ while parse_body(body, tokens)
20
+ body = @blocks.last.attachment
21
+ end
22
+ end
23
+
17
24
  def nodelist
18
- @blocks.flat_map(&:attachment)
25
+ @blocks.map(&:attachment)
19
26
  end
20
27
 
21
28
  def unknown_tag(tag, markup, tokens)
22
- @nodelist = []
23
29
  case tag
24
30
  when 'when'.freeze
25
31
  record_when_condition(markup)
@@ -37,10 +43,10 @@ module Liquid
37
43
  output = ''
38
44
  @blocks.each do |block|
39
45
  if block.else?
40
- return render_all(block.attachment, context) if execute_else_block
46
+ return block.attachment.render(context) if execute_else_block
41
47
  elsif block.evaluate(context)
42
48
  execute_else_block = false
43
- output << render_all(block.attachment, context)
49
+ output << block.attachment.render(context)
44
50
  end
45
51
  end
46
52
  output
@@ -50,27 +56,28 @@ module Liquid
50
56
  private
51
57
 
52
58
  def record_when_condition(markup)
59
+ body = BlockBody.new
60
+
53
61
  while markup
54
- # Create a new nodelist and assign it to the new block
55
- if not markup =~ WhenSyntax
62
+ unless markup =~ WhenSyntax
56
63
  raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze))
57
64
  end
58
65
 
59
66
  markup = $2
60
67
 
61
- block = Condition.new(@left, '=='.freeze, $1)
62
- block.attach(@nodelist)
63
- @blocks.push(block)
68
+ block = Condition.new(@left, '=='.freeze, Expression.parse($1))
69
+ block.attach(body)
70
+ @blocks << block
64
71
  end
65
72
  end
66
73
 
67
74
  def record_else_condition(markup)
68
- if not markup.strip.empty?
75
+ unless markup.strip.empty?
69
76
  raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_else".freeze))
70
77
  end
71
78
 
72
79
  block = ElseCondition.new
73
- block.attach(@nodelist)
80
+ block.attach(BlockBody.new)
74
81
  @blocks << block
75
82
  end
76
83
  end
@@ -1,10 +1,10 @@
1
1
  module Liquid
2
2
  class Comment < Block
3
- def render(context)
3
+ def render(_context)
4
4
  ''.freeze
5
5
  end
6
6
 
7
- def unknown_tag(tag, markup, tokens)
7
+ def unknown_tag(_tag, _markup, _tokens)
8
8
  end
9
9
 
10
10
  def blank?
@@ -20,10 +20,10 @@ module Liquid
20
20
  case markup
21
21
  when NamedSyntax
22
22
  @variables = variables_from_string($2)
23
- @name = $1
23
+ @name = Expression.parse($1)
24
24
  when SimpleSyntax
25
25
  @variables = variables_from_string(markup)
26
- @name = "'#{@variables.to_s}'"
26
+ @name = @variables.to_s
27
27
  else
28
28
  raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
29
29
  end
@@ -33,11 +33,11 @@ module Liquid
33
33
  context.registers[:cycle] ||= Hash.new(0)
34
34
 
35
35
  context.stack do
36
- key = context[@name]
36
+ key = context.evaluate(@name)
37
37
  iteration = context.registers[:cycle][key]
38
- result = context[@variables[iteration]]
38
+ result = context.evaluate(@variables[iteration])
39
39
  iteration += 1
40
- iteration = 0 if iteration >= @variables.size
40
+ iteration = 0 if iteration >= @variables.size
41
41
  context.registers[:cycle][key] = iteration
42
42
  result
43
43
  end
@@ -48,7 +48,7 @@ module Liquid
48
48
  def variables_from_string(markup)
49
49
  markup.split(',').collect do |var|
50
50
  var =~ /\s*(#{QuotedFragment})\s*/o
51
- $1 ? $1 : nil
51
+ $1 ? Expression.parse($1) : nil
52
52
  end.compact
53
53
  end
54
54
  end
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # decrement is used in a place where one needs to insert a counter
4
3
  # into a template, and needs the counter to survive across
5
4
  # multiple instantiations of the template.
@@ -26,12 +25,10 @@ module Liquid
26
25
 
27
26
  def render(context)
28
27
  value = context.environments.first[@variable] ||= 0
29
- value = value - 1
28
+ value -= 1
30
29
  context.environments.first[@variable] = value
31
30
  value.to_s
32
31
  end
33
-
34
- private
35
32
  end
36
33
 
37
34
  Template.register_tag('decrement'.freeze, Decrement)
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # "For" iterates over an array or collection.
4
3
  # Several useful variables are available to you within the loop.
5
4
  #
@@ -42,6 +41,7 @@ module Liquid
42
41
  # where 0 is the last item.
43
42
  # forloop.first:: Returns true if the item is the first item.
44
43
  # forloop.last:: Returns true if the item is the last item.
44
+ # forloop.parentloop:: Provides access to the parent loop, if present.
45
45
  #
46
46
  class For < Block
47
47
  Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
@@ -49,78 +49,31 @@ module Liquid
49
49
  def initialize(tag_name, markup, options)
50
50
  super
51
51
  parse_with_selected_parser(markup)
52
- @nodelist = @for_block = []
52
+ @for_block = BlockBody.new
53
+ end
54
+
55
+ def parse(tokens)
56
+ return unless parse_body(@for_block, tokens)
57
+ parse_body(@else_block, tokens)
53
58
  end
54
59
 
55
60
  def nodelist
56
- if @else_block
57
- @for_block + @else_block
58
- else
59
- @for_block
60
- end
61
+ @else_block ? [@for_block, @else_block] : [@for_block]
61
62
  end
62
63
 
63
64
  def unknown_tag(tag, markup, tokens)
64
65
  return super unless tag == 'else'.freeze
65
- @nodelist = @else_block = []
66
+ @else_block = BlockBody.new
66
67
  end
67
68
 
68
69
  def render(context)
69
- context.registers[:for] ||= Hash.new(0)
70
-
71
- collection = context[@collection_name]
72
- collection = collection.to_a if collection.is_a?(Range)
73
-
74
- # Maintains Ruby 1.8.7 String#each behaviour on 1.9
75
- return render_else(context) unless iterable?(collection)
70
+ segment = collection_segment(context)
76
71
 
77
- from = if @attributes['offset'.freeze] == 'continue'.freeze
78
- context.registers[:for][@name].to_i
72
+ if segment.empty?
73
+ render_else(context)
79
74
  else
80
- context[@attributes['offset'.freeze]].to_i
75
+ render_segment(context, segment)
81
76
  end
82
-
83
- limit = context[@attributes['limit'.freeze]]
84
- to = limit ? limit.to_i + from : nil
85
-
86
- segment = Utils.slice_collection(collection, from, to)
87
-
88
- return render_else(context) if segment.empty?
89
-
90
- segment.reverse! if @reversed
91
-
92
- result = ''
93
-
94
- length = segment.length
95
-
96
- # Store our progress through the collection for the continue flag
97
- context.registers[:for][@name] = from + segment.length
98
-
99
- context.stack do
100
- segment.each_with_index do |item, index|
101
- context[@variable_name] = item
102
- context['forloop'.freeze] = {
103
- 'name'.freeze => @name,
104
- 'length'.freeze => length,
105
- 'index'.freeze => index + 1,
106
- 'index0'.freeze => index,
107
- 'rindex'.freeze => length - index,
108
- 'rindex0'.freeze => length - index - 1,
109
- 'first'.freeze => (index == 0),
110
- 'last'.freeze => (index == length - 1)
111
- }
112
-
113
- result << render_all(@for_block, context)
114
-
115
- # Handle any interrupts if they exist.
116
- if context.has_interrupt?
117
- interrupt = context.pop_interrupt
118
- break if interrupt.is_a? BreakInterrupt
119
- next if interrupt.is_a? ContinueInterrupt
120
- end
121
- end
122
- end
123
- result
124
77
  end
125
78
 
126
79
  protected
@@ -128,12 +81,12 @@ module Liquid
128
81
  def lax_parse(markup)
129
82
  if markup =~ Syntax
130
83
  @variable_name = $1
131
- @collection_name = $2
132
- @name = "#{$1}-#{$2}"
133
- @reversed = $3
134
- @attributes = {}
84
+ collection_name = $2
85
+ @reversed = !!$3
86
+ @name = "#{@variable_name}-#{collection_name}"
87
+ @collection_name = Expression.parse(collection_name)
135
88
  markup.scan(TagAttributes) do |key, value|
136
- @attributes[key] = value
89
+ set_attribute(key, value)
137
90
  end
138
91
  else
139
92
  raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
@@ -143,31 +96,96 @@ module Liquid
143
96
  def strict_parse(markup)
144
97
  p = Parser.new(markup)
145
98
  @variable_name = p.consume(:id)
146
- raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
147
- @collection_name = p.expression
148
- @name = "#{@variable_name}-#{@collection_name}"
99
+ raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
100
+ collection_name = p.expression
101
+ @name = "#{@variable_name}-#{collection_name}"
102
+ @collection_name = Expression.parse(collection_name)
149
103
  @reversed = p.id?('reversed'.freeze)
150
104
 
151
- @attributes = {}
152
105
  while p.look(:id) && p.look(:colon, 1)
153
106
  unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
154
107
  raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
155
108
  end
156
109
  p.consume
157
- val = p.expression
158
- @attributes[attribute] = val
110
+ set_attribute(attribute, p.expression)
159
111
  end
160
112
  p.consume(:end_of_string)
161
113
  end
162
114
 
163
115
  private
164
116
 
165
- def render_else(context)
166
- return @else_block ? [render_all(@else_block, context)] : ''.freeze
117
+ def collection_segment(context)
118
+ offsets = context.registers[:for] ||= Hash.new(0)
119
+
120
+ from = if @from == :continue
121
+ offsets[@name].to_i
122
+ else
123
+ context.evaluate(@from).to_i
124
+ end
125
+
126
+ collection = context.evaluate(@collection_name)
127
+ collection = collection.to_a if collection.is_a?(Range)
128
+
129
+ limit = context.evaluate(@limit)
130
+ to = limit ? limit.to_i + from : nil
131
+
132
+ segment = Utils.slice_collection(collection, from, to)
133
+ segment.reverse! if @reversed
134
+
135
+ offsets[@name] = from + segment.length
136
+
137
+ segment
167
138
  end
168
139
 
169
- def iterable?(collection)
170
- collection.respond_to?(:each) || Utils.non_blank_string?(collection)
140
+ def render_segment(context, segment)
141
+ for_stack = context.registers[:for_stack] ||= []
142
+ length = segment.length
143
+
144
+ result = ''
145
+
146
+ context.stack do
147
+ loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1])
148
+
149
+ for_stack.push(loop_vars)
150
+
151
+ begin
152
+ context['forloop'.freeze] = loop_vars
153
+
154
+ segment.each_with_index do |item, index|
155
+ context[@variable_name] = item
156
+ result << @for_block.render(context)
157
+ loop_vars.send(:increment!)
158
+
159
+ # Handle any interrupts if they exist.
160
+ if context.interrupt?
161
+ interrupt = context.pop_interrupt
162
+ break if interrupt.is_a? BreakInterrupt
163
+ next if interrupt.is_a? ContinueInterrupt
164
+ end
165
+ end
166
+ ensure
167
+ for_stack.pop
168
+ end
169
+ end
170
+
171
+ result
172
+ end
173
+
174
+ def set_attribute(key, expr)
175
+ case key
176
+ when 'offset'.freeze
177
+ @from = if expr == 'continue'.freeze
178
+ :continue
179
+ else
180
+ Expression.parse(expr)
181
+ end
182
+ when 'limit'.freeze
183
+ @limit = Expression.parse(expr)
184
+ end
185
+ end
186
+
187
+ def render_else(context)
188
+ @else_block ? @else_block.render(context) : ''.freeze
171
189
  end
172
190
  end
173
191
 
@@ -20,8 +20,13 @@ module Liquid
20
20
  push_block('if'.freeze, markup)
21
21
  end
22
22
 
23
+ def parse(tokens)
24
+ while parse_body(@blocks.last.attachment, tokens)
25
+ end
26
+ end
27
+
23
28
  def nodelist
24
- @blocks.flat_map(&:attachment)
29
+ @blocks.map(&:attachment)
25
30
  end
26
31
 
27
32
  def unknown_tag(tag, markup, tokens)
@@ -36,7 +41,7 @@ module Liquid
36
41
  context.stack do
37
42
  @blocks.each do |block|
38
43
  if block.evaluate(context)
39
- return render_all(block.attachment, context)
44
+ return block.attachment.render(context)
40
45
  end
41
46
  end
42
47
  ''.freeze
@@ -45,61 +50,61 @@ module Liquid
45
50
 
46
51
  private
47
52
 
48
- def push_block(tag, markup)
49
- block = if tag == 'else'.freeze
50
- ElseCondition.new
51
- else
52
- parse_with_selected_parser(markup)
53
- end
54
-
55
- @blocks.push(block)
56
- @nodelist = block.attach(Array.new)
53
+ def push_block(tag, markup)
54
+ block = if tag == 'else'.freeze
55
+ ElseCondition.new
56
+ else
57
+ parse_with_selected_parser(markup)
57
58
  end
58
59
 
59
- def lax_parse(markup)
60
- expressions = markup.scan(ExpressionsAndOperators)
61
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
60
+ @blocks.push(block)
61
+ block.attach(BlockBody.new)
62
+ end
62
63
 
63
- condition = Condition.new($1, $2, $3)
64
+ def lax_parse(markup)
65
+ expressions = markup.scan(ExpressionsAndOperators)
66
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
64
67
 
65
- while not expressions.empty?
66
- operator = expressions.pop.to_s.strip
68
+ condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
67
69
 
68
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
70
+ until expressions.empty?
71
+ operator = expressions.pop.to_s.strip
69
72
 
70
- new_condition = Condition.new($1, $2, $3)
71
- raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
72
- new_condition.send(operator, condition)
73
- condition = new_condition
74
- end
73
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
75
74
 
76
- condition
75
+ new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
76
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
77
+ new_condition.send(operator, condition)
78
+ condition = new_condition
77
79
  end
78
80
 
79
- def strict_parse(markup)
80
- p = Parser.new(markup)
81
- condition = parse_binary_comparison(p)
82
- p.consume(:end_of_string)
83
- condition
84
- end
81
+ condition
82
+ end
85
83
 
86
- def parse_binary_comparison(p)
87
- condition = parse_comparison(p)
88
- if op = (p.id?('and'.freeze) || p.id?('or'.freeze))
89
- condition.send(op, parse_binary_comparison(p))
90
- end
91
- condition
84
+ def strict_parse(markup)
85
+ p = Parser.new(markup)
86
+ condition = parse_binary_comparison(p)
87
+ p.consume(:end_of_string)
88
+ condition
89
+ end
90
+
91
+ def parse_binary_comparison(p)
92
+ condition = parse_comparison(p)
93
+ if op = (p.id?('and'.freeze) || p.id?('or'.freeze))
94
+ condition.send(op, parse_binary_comparison(p))
92
95
  end
96
+ condition
97
+ end
93
98
 
94
- def parse_comparison(p)
95
- a = p.expression
96
- if op = p.consume?(:comparison)
97
- b = p.expression
98
- Condition.new(a, op, b)
99
- else
100
- Condition.new(a)
101
- end
99
+ def parse_comparison(p)
100
+ a = Expression.parse(p.expression)
101
+ if op = p.consume?(:comparison)
102
+ b = Expression.parse(p.expression)
103
+ Condition.new(a, op, b)
104
+ else
105
+ Condition.new(a)
102
106
  end
107
+ end
103
108
  end
104
109
 
105
110
  Template.register_tag('if'.freeze, If)