Module: Liquid2

Defined in:
lib/liquid2.rb,
lib/liquid2/tag.rb,
lib/liquid2/node.rb,
lib/liquid2/errors.rb,
lib/liquid2/filter.rb,
lib/liquid2/loader.rb,
lib/liquid2/parser.rb,
lib/liquid2/context.rb,
lib/liquid2/scanner.rb,
lib/liquid2/version.rb,
lib/liquid2/template.rb,
lib/liquid2/undefined.rb,
lib/liquid2/expression.rb,
lib/liquid2/environment.rb,
lib/liquid2/utils/cache.rb,
lib/liquid2/filters/date.rb,
lib/liquid2/filters/json.rb,
lib/liquid2/filters/math.rb,
lib/liquid2/filters/size.rb,
lib/liquid2/filters/sort.rb,
lib/liquid2/nodes/output.rb,
lib/liquid2/filters/array.rb,
lib/liquid2/filters/slice.rb,
lib/liquid2/nodes/comment.rb,
lib/liquid2/nodes/tags/if.rb,
lib/liquid2/filters/string.rb,
lib/liquid2/loaders/mixins.rb,
lib/liquid2/nodes/tags/doc.rb,
lib/liquid2/nodes/tags/for.rb,
lib/liquid2/nodes/tags/raw.rb,
lib/liquid2/utils/unescape.rb,
lib/liquid2/filters/default.rb,
lib/liquid2/nodes/tags/case.rb,
lib/liquid2/nodes/tags/echo.rb,
lib/liquid2/nodes/tags/with.rb,
lib/liquid2/static_analysis.rb,
lib/liquid2/expressions/loop.rb,
lib/liquid2/expressions/path.rb,
lib/liquid2/nodes/tags/cycle.rb,
lib/liquid2/nodes/tags/macro.rb,
lib/liquid2/utils/chain_hash.rb,
lib/liquid2/expressions/array.rb,
lib/liquid2/expressions/blank.rb,
lib/liquid2/expressions/range.rb,
lib/liquid2/nodes/tags/assign.rb,
lib/liquid2/nodes/tags/liquid.rb,
lib/liquid2/nodes/tags/render.rb,
lib/liquid2/nodes/tags/unless.rb,
lib/liquid2/expressions/lambda.rb,
lib/liquid2/expressions/object.rb,
lib/liquid2/nodes/tags/capture.rb,
lib/liquid2/nodes/tags/extends.rb,
lib/liquid2/nodes/tags/include.rb,
lib/liquid2/expressions/boolean.rb,
lib/liquid2/expressions/logical.rb,
lib/liquid2/nodes/tags/tablerow.rb,
lib/liquid2/expressions/filtered.rb,
lib/liquid2/nodes/tags/decrement.rb,
lib/liquid2/nodes/tags/increment.rb,
lib/liquid2/expressions/arguments.rb,
lib/liquid2/expressions/arithmetic.rb,
lib/liquid2/expressions/identifier.rb,
lib/liquid2/expressions/relational.rb,
lib/liquid2/nodes/tags/block_comment.rb,
lib/liquid2/nodes/tags/inline_comment.rb,
lib/liquid2/loaders/file_system_loader.rb,
lib/liquid2/expressions/template_string.rb

Overview

:nodoc:

Defined Under Namespace

Modules: CachingLoaderMixin, Filters, StaticAnalysis Classes: ArithmeticExpression, ArrayLiteral, ArraySpread, AssignTag, Blank, Block, BlockComment, BlockDrop, BlockTag, BooleanExpression, BreakTag, BuiltIn, CachingFileSystemLoader, CallTag, CaptureTag, CaseTag, Comment, ComparisonExpression, ConditionalBlock, Contains, ContinueTag, CycleTag, DecrementTag, DisabledTagError, Divide, DocTag, EchoTag, Empty, Environment, Eq, Expression, ExtendsTag, FileSystemLoader, Filter, FilteredExpression, ForLoop, ForTag, Ge, GroupedExpression, Gt, HashLoader, Identifier, IfTag, In, IncludeTag, IncrementTag, InlineComment, KeywordArgument, LRUCache, Lambda, Le, LiquidArgumentError, LiquidError, LiquidFilterNotFoundError, LiquidResourceLimitError, LiquidSyntaxError, LiquidTag, LiquidTemplateNotFoundError, LiquidTypeError, LogicalAnd, LogicalNot, LogicalOr, LoopExpression, Lt, MacroTag, Minus, Modulo, MultiEqualBlock, Ne, Negative, Node, ObjectLiteral, ObjectLiteralItem, Output, Parameter, Parser, Partial, Path, Plus, Positive, Pow, RangeExpression, RawTag, ReadOnlyChainHash, RenderContext, RenderTag, RequiredBlockError, Scanner, StrictDefaultUndefined, StrictUndefined, TableRow, TableRowTag, Tag, Template, TemplateInheritanceError, TemplateLoader, TemplateSource, TemplateString, TernaryExpression, ThreadSafeLRUCache, Times, Undefined, UndefinedError, UnlessTag, WithTag

Constant Summary collapse

DEFAULT_ENVIRONMENT =
Environment.new
VERSION =
"0.5.0"
DISABLED_TAGS =
Set["include"]

Class Method Summary collapse

Class Method Details

.code_point_to_string(code_point, token) ⇒ Object

Raises:



114
115
116
117
118
# File 'lib/liquid2/utils/unescape.rb', line 114

def self.code_point_to_string(code_point, token)
  raise LiquidSyntaxError.new("invalid character", token) if code_point <= 8

  code_point.chr(Encoding::UTF_8)
end

.contains?(left, right) ⇒ Boolean



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/liquid2/expressions/relational.rb', line 108

def self.contains?(left, right)
  return false unless left.respond_to?(:include?)

  if left.is_a?(String)
    right.nil? || Liquid2.undefined?(right) ? false : left.include?(Liquid2.to_s(right))
  else
    left.include?(right)
  end
rescue ::ArgumentError => e
  raise Liquid2::LiquidArgumentError, e.message
end

.decode_hex_char(value, index, token) ⇒ Object

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/liquid2/utils/unescape.rb', line 58

def self.decode_hex_char(value, index, token)
  length = value.length

  raise LiquidSyntaxError.new("incomplete escape sequence", token) if index + 4 >= length

  index += 1 # move past 'u'
  code_point = parse_hex_digits(value[index, 4] || raise, token)

  raise LiquidSyntaxError.new("unexpected low surrogate", token) if low_surrogate?(code_point)

  return [code_point, index + 3] unless high_surrogate?(code_point)

  unless index + 9 < length && value[index + 4] == "\\" && value[index + 5] == "u"
    raise LiquidSyntaxError.new("incomplete escape sequence", token)
  end

  low_surrogate = parse_hex_digits(value[index + 6, 10] || raise, token)

  unless low_surrogate?(low_surrogate)
    raise LiquidSyntaxError.new("unexpected low surrogate",
                                token)
  end

  code_point = 0x10000 + (
    ((code_point & 0x03FF) << 10) | (low_surrogate & 0x03FF)
  )

  [code_point, index + 9]
end

.eq?(left, right) ⇒ Boolean

Test left and right for Liquid equality.



94
95
96
97
98
99
# File 'lib/liquid2/expressions/relational.rb', line 94

def self.eq?(left, right)
  left, right = right, left if right.is_a?(Empty) || right.is_a?(Blank)
  left == right
rescue ::ArgumentError => e
  raise Liquid2::LiquidArgumentError, e.message
end

.high_surrogate?(code_point) ⇒ Boolean



106
107
108
# File 'lib/liquid2/utils/unescape.rb', line 106

def self.high_surrogate?(code_point)
  code_point.between?(0xD800, 0xDBFF)
end

.low_surrogate?(code_point) ⇒ Boolean



110
111
112
# File 'lib/liquid2/utils/unescape.rb', line 110

def self.low_surrogate?(code_point)
  code_point.between?(0xDC00, 0xDFFF)
end

.lt?(left, right) ⇒ Boolean

Return ‘true` if left is considered less than right.



102
103
104
105
106
# File 'lib/liquid2/expressions/relational.rb', line 102

def self.lt?(left, right)
  left < right
rescue ::ArgumentError => e
  raise Liquid2::LiquidArgumentError, e.message
end

.parse(source, globals: nil) ⇒ Template

Parse source text as a template using the default Liquid environment.



25
26
27
# File 'lib/liquid2.rb', line 25

def self.parse(source, globals: nil)
  DEFAULT_ENVIRONMENT.parse(source, globals: globals)
end

.parse_hex_digits(digits, token) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/liquid2/utils/unescape.rb', line 88

def self.parse_hex_digits(digits, token)
  code_point = 0
  digits.each_byte do |b|
    code_point <<= 4
    case b
    when 48..57
      code_point |= b - 48
    when 65..70
      code_point |= b - 65 + 10
    when 97..102
      code_point |= b - 97 + 10
    else
      raise LiquidSyntaxError.new("invalid escape sequence", token)
    end
  end
  code_point
end

.render(source, data = nil) ⇒ String

Parse and render template source with data as template variables and the default Liquid environment.



34
35
36
# File 'lib/liquid2.rb', line 34

def self.render(source, data = nil)
  DEFAULT_ENVIRONMENT.render(source, data)
end

.to_liquid_int(obj, default: 0) ⇒ Object Also known as: to_i



65
66
67
68
69
# File 'lib/liquid2.rb', line 65

def self.to_liquid_int(obj, default: 0)
  Float(obj).to_i
rescue ArgumentError, TypeError
  default
end

.to_liquid_string(obj) ⇒ Object Also known as: to_s

Stringify an object. Use this anywhere a string is expected, like in a filter.



39
40
41
42
43
44
45
46
# File 'lib/liquid2.rb', line 39

def self.to_liquid_string(obj)
  case obj
  when Hash, Array
    JSON.generate(obj)
  else
    obj.to_s
  end
end

.to_output_string(obj) ⇒ Object Also known as: to_output_s

Stringify an object for output. Use this when writing directly to an output buffer.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/liquid2.rb', line 49

def self.to_output_string(obj)
  case obj
  when Array
    # Concatenate string representations of array elements.
    obj.map do |item|
      Liquid2.to_s(item)
    end.join
  when BigDecimal
    # TODO: test capture
    # TODO: are there any scenarios where we need to cast to_f before output?
    obj.to_f.to_s
  else
    Liquid2.to_s(obj)
  end
end

.truthy?(context, obj) ⇒ bool

Return ‘true` if obj is Liquid truthy.



75
76
77
78
79
80
# File 'lib/liquid2.rb', line 75

def self.truthy?(context, obj)
  return false if context.env.falsy_undefined && undefined?(obj)

  obj = obj.to_liquid(context) if obj.respond_to?(:to_liquid)
  !!obj
end

.undefined?(obj) ⇒ Boolean

Return ‘true` if obj is undefined.



83
84
85
# File 'lib/liquid2.rb', line 83

def self.undefined?(obj)
  obj.is_a?(Undefined)
end

.unescape_string(value, quote, token) ⇒ String

Replace escape sequences with their equivalent Unicode code point. This is a bit like Ruby’s String#undump, but assumes surrounding quotes have been removed and follows JSON escaping semantics.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/liquid2/utils/unescape.rb', line 11

def self.unescape_string(value, quote, token)
  unescaped = String.new(encoding: "UTF-8")
  index = 0
  length = value.length

  while index < length
    ch = value[index] || raise
    if ch == "\\"
      index += 1
      case value[index]
      when quote
        unescaped << quote
      when "\\"
        unescaped << "\\"
      when "/"
        unescaped << "/"
      when "b"
        unescaped << "\x08"
      when "f"
        unescaped << "\x0C"
      when "n"
        unescaped << "\n"
      when "r"
        unescaped << "\r"
      when "t"
        unescaped << "\t"
      when "u"
        code_point, index = Liquid2.decode_hex_char(value, index, token)
        unescaped << Liquid2.code_point_to_string(code_point, token)
      when "$"
        unescaped << "$"
      else
        raise LiquidSyntaxError.new("unknown escape sequence", token)
      end
    else
      # raise LiquidSyntaxError.new("invalid character #{ch.inspect}", token) if ch.ord <= 0x1F

      unescaped << ch
    end

    index += 1

  end

  unescaped
end