liquid 2.6.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +194 -29
  3. data/{MIT-LICENSE → LICENSE} +0 -0
  4. data/README.md +60 -2
  5. data/lib/liquid.rb +25 -14
  6. data/lib/liquid/block.rb +47 -96
  7. data/lib/liquid/block_body.rb +143 -0
  8. data/lib/liquid/condition.rb +70 -39
  9. data/lib/liquid/context.rb +116 -157
  10. data/lib/liquid/document.rb +19 -9
  11. data/lib/liquid/drop.rb +31 -14
  12. data/lib/liquid/errors.rb +54 -10
  13. data/lib/liquid/expression.rb +49 -0
  14. data/lib/liquid/extensions.rb +19 -7
  15. data/lib/liquid/file_system.rb +25 -14
  16. data/lib/liquid/forloop_drop.rb +42 -0
  17. data/lib/liquid/i18n.rb +39 -0
  18. data/lib/liquid/interrupts.rb +2 -3
  19. data/lib/liquid/lexer.rb +55 -0
  20. data/lib/liquid/locales/en.yml +26 -0
  21. data/lib/liquid/parse_context.rb +38 -0
  22. data/lib/liquid/parse_tree_visitor.rb +42 -0
  23. data/lib/liquid/parser.rb +90 -0
  24. data/lib/liquid/parser_switching.rb +31 -0
  25. data/lib/liquid/profiler.rb +158 -0
  26. data/lib/liquid/profiler/hooks.rb +23 -0
  27. data/lib/liquid/range_lookup.rb +37 -0
  28. data/lib/liquid/resource_limits.rb +23 -0
  29. data/lib/liquid/standardfilters.rb +311 -77
  30. data/lib/liquid/strainer.rb +39 -26
  31. data/lib/liquid/tablerowloop_drop.rb +62 -0
  32. data/lib/liquid/tag.rb +28 -11
  33. data/lib/liquid/tags/assign.rb +34 -10
  34. data/lib/liquid/tags/break.rb +1 -4
  35. data/lib/liquid/tags/capture.rb +11 -9
  36. data/lib/liquid/tags/case.rb +37 -22
  37. data/lib/liquid/tags/comment.rb +10 -3
  38. data/lib/liquid/tags/continue.rb +1 -4
  39. data/lib/liquid/tags/cycle.rb +20 -14
  40. data/lib/liquid/tags/decrement.rb +4 -8
  41. data/lib/liquid/tags/for.rb +121 -60
  42. data/lib/liquid/tags/if.rb +73 -30
  43. data/lib/liquid/tags/ifchanged.rb +3 -5
  44. data/lib/liquid/tags/include.rb +77 -46
  45. data/lib/liquid/tags/increment.rb +4 -8
  46. data/lib/liquid/tags/raw.rb +35 -10
  47. data/lib/liquid/tags/table_row.rb +62 -0
  48. data/lib/liquid/tags/unless.rb +6 -9
  49. data/lib/liquid/template.rb +130 -32
  50. data/lib/liquid/tokenizer.rb +31 -0
  51. data/lib/liquid/truffle.rb +5 -0
  52. data/lib/liquid/utils.rb +57 -4
  53. data/lib/liquid/variable.rb +121 -30
  54. data/lib/liquid/variable_lookup.rb +88 -0
  55. data/lib/liquid/version.rb +2 -1
  56. data/test/fixtures/en_locale.yml +9 -0
  57. data/test/integration/assign_test.rb +48 -0
  58. data/test/integration/blank_test.rb +106 -0
  59. data/test/integration/block_test.rb +12 -0
  60. data/test/{liquid → integration}/capture_test.rb +13 -3
  61. data/test/integration/context_test.rb +32 -0
  62. data/test/integration/document_test.rb +19 -0
  63. data/test/integration/drop_test.rb +273 -0
  64. data/test/integration/error_handling_test.rb +260 -0
  65. data/test/integration/filter_test.rb +178 -0
  66. data/test/integration/hash_ordering_test.rb +23 -0
  67. data/test/integration/output_test.rb +123 -0
  68. data/test/integration/parse_tree_visitor_test.rb +247 -0
  69. data/test/integration/parsing_quirks_test.rb +122 -0
  70. data/test/integration/render_profiling_test.rb +154 -0
  71. data/test/integration/security_test.rb +80 -0
  72. data/test/integration/standard_filter_test.rb +776 -0
  73. data/test/{liquid → integration}/tags/break_tag_test.rb +2 -3
  74. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -2
  75. data/test/integration/tags/for_tag_test.rb +410 -0
  76. data/test/integration/tags/if_else_tag_test.rb +188 -0
  77. data/test/integration/tags/include_tag_test.rb +253 -0
  78. data/test/integration/tags/increment_tag_test.rb +23 -0
  79. data/test/{liquid → integration}/tags/raw_tag_test.rb +9 -2
  80. data/test/integration/tags/standard_tag_test.rb +296 -0
  81. data/test/integration/tags/statements_test.rb +111 -0
  82. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +25 -24
  83. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  84. data/test/integration/template_test.rb +332 -0
  85. data/test/integration/trim_mode_test.rb +529 -0
  86. data/test/integration/variable_test.rb +96 -0
  87. data/test/test_helper.rb +106 -19
  88. data/test/truffle/truffle_test.rb +9 -0
  89. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +9 -9
  90. data/test/unit/condition_unit_test.rb +166 -0
  91. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +85 -74
  92. data/test/unit/file_system_unit_test.rb +35 -0
  93. data/test/unit/i18n_unit_test.rb +37 -0
  94. data/test/unit/lexer_unit_test.rb +51 -0
  95. data/test/unit/parser_unit_test.rb +82 -0
  96. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +4 -4
  97. data/test/unit/strainer_unit_test.rb +164 -0
  98. data/test/unit/tag_unit_test.rb +21 -0
  99. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  100. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  101. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  102. data/test/unit/template_unit_test.rb +78 -0
  103. data/test/unit/tokenizer_unit_test.rb +55 -0
  104. data/test/unit/variable_unit_test.rb +162 -0
  105. metadata +157 -77
  106. data/lib/extras/liquid_view.rb +0 -51
  107. data/lib/liquid/htmltags.rb +0 -74
  108. data/lib/liquid/module_ex.rb +0 -62
  109. data/test/liquid/assign_test.rb +0 -21
  110. data/test/liquid/condition_test.rb +0 -127
  111. data/test/liquid/drop_test.rb +0 -180
  112. data/test/liquid/error_handling_test.rb +0 -81
  113. data/test/liquid/file_system_test.rb +0 -29
  114. data/test/liquid/filter_test.rb +0 -125
  115. data/test/liquid/hash_ordering_test.rb +0 -25
  116. data/test/liquid/module_ex_test.rb +0 -87
  117. data/test/liquid/output_test.rb +0 -116
  118. data/test/liquid/parsing_quirks_test.rb +0 -52
  119. data/test/liquid/security_test.rb +0 -64
  120. data/test/liquid/standard_filter_test.rb +0 -251
  121. data/test/liquid/strainer_test.rb +0 -52
  122. data/test/liquid/tags/for_tag_test.rb +0 -297
  123. data/test/liquid/tags/if_else_tag_test.rb +0 -166
  124. data/test/liquid/tags/include_tag_test.rb +0 -166
  125. data/test/liquid/tags/increment_tag_test.rb +0 -24
  126. data/test/liquid/tags/standard_tag_test.rb +0 -295
  127. data/test/liquid/tags/statements_test.rb +0 -134
  128. data/test/liquid/tags/unless_else_tag_test.rb +0 -26
  129. data/test/liquid/template_test.rb +0 -146
  130. data/test/liquid/variable_test.rb +0 -186
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b0e31111a331f2a07fcb229b706bbb9b5e719b29
4
- data.tar.gz: f1c6fbf31aec9e38ba89d022efe99fd5046f8794
2
+ SHA256:
3
+ metadata.gz: e41c3a6ffee8037dec34a186cf023e2ccb09ac4f94d0c9a812ea02fd50559bf7
4
+ data.tar.gz: ff088908363f5a54e5833c64d32b441fb679503340b5f7511de99eb257fd4289
5
5
  SHA512:
6
- metadata.gz: a05f58776ef9c97c252192f092b5d7a4b945afa7d67d95668af0a019952dce717b1346a7bb8967d22e3272c9fc458cadf377a35aef9a10de5309df16190b12a1
7
- data.tar.gz: 80ca90e27ae95d04efbee61dadd4ca3316e3593dab28a68350fb1d595813d38b27b52aecadd05394ad8973a392431fe7246b0fb3751dba6f40ad54bf982e1b67
6
+ metadata.gz: 6b726a02e92f8d9fac005e07034aeee32dd2eae3a2b342fb4e9e648dc79da4c086de92e1e1a24bf52054a4a2b0a74af17f89fdd6c3cbbb2982e4b5b5971a23c2
7
+ data.tar.gz: e875f98a0b30f914ec1703781bfb443e737ea11675829c3e98fca96524dfe30a72fb9adf59c7855f85eda8014c2e6a9850d911b22cb96a63d2eac52e91273a42
data/History.md CHANGED
@@ -1,43 +1,208 @@
1
- # Liquid Version History
2
-
3
- IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
4
- The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
5
-
6
- ## 2.6.1 / 2014-01-10 / branch "2-6-stable"
1
+ # Liquid Change Log
2
+
3
+ ## 4.0.3 / 2019-03-12
4
+
5
+ ### Fixed
6
+ * Fix break and continue tags inside included templates in loops (#1072) [Justin Li]
7
+
8
+ ## 4.0.2 / 2019-03-08
9
+
10
+ ### Changed
11
+ * Add `where` filter (#1026) [Samuel Doiron]
12
+ * Add `ParseTreeVisitor` to iterate the Liquid AST (#1025) [Stephen Paul Weber]
13
+ * Improve `strip_html` performance (#1032) [printercu]
14
+
15
+ ### Fixed
16
+ * Add error checking for invalid combinations of inputs to sort, sort_natural, where, uniq, map, compact filters (#1059) [Garland Zhang]
17
+ * Validate the character encoding in url_decode (#1070) [Clayton Smith]
18
+
19
+ ## 4.0.1 / 2018-10-09
20
+
21
+ ### Changed
22
+ * Add benchmark group in Gemfile (#855) [Jerry Liu]
23
+ * Allow benchmarks to benchmark render by itself (#851) [Jerry Liu]
24
+ * Avoid calling `line_number` on String node when rescuing a render error. (#860) [Dylan Thacker-Smith]
25
+ * Avoid duck typing to detect whether to call render on a node. [Dylan Thacker-Smith]
26
+ * Clarify spelling of `reversed` on `for` block tag (#843) [Mark Crossfield]
27
+ * Replace recursion with loop to avoid potential stack overflow from malicious input (#891, #892) [Dylan Thacker-Smith]
28
+ * Limit block tag nesting to 100 (#894) [Dylan Thacker-Smith]
29
+ * Replace `assert_equal nil` with `assert_nil` (#895) [Dylan Thacker-Smith]
30
+ * Remove Spy Gem (#896) [Dylan Thacker-Smith]
31
+ * Add `collection_name` and `variable_name` reader to `For` block (#909)
32
+ * Symbols render as strings (#920) [Justin Li]
33
+ * Remove default value from Hash objects (#932) [Maxime Bedard]
34
+ * Remove one level of nesting (#944) [Dylan Thacker-Smith]
35
+ * Update Rubocop version (#952) [Justin Li]
36
+ * Add `at_least` and `at_most` filters (#954, #958) [Nithin Bekal]
37
+ * Add a regression test for a liquid-c trim mode bug (#972) [Dylan Thacker-Smith]
38
+ * Use https rather than git protocol to fetch liquid-c [Dylan Thacker-Smith]
39
+ * Add tests against Ruby 2.4 (#963) and 2.5 (#981)
40
+ * Replace RegExp literals with constants (#988) [Ashwin Maroli]
41
+ * Replace unnecessary `#each_with_index` with `#each` (#992) [Ashwin Maroli]
42
+ * Improve the unexpected end delimiter message for block tags. (#1003) [Dylan Thacker-Smith]
43
+ * Refactor and optimize rendering (#1005) [Christopher Aue]
44
+ * Add installation instruction (#1006) [Ben Gift]
45
+ * Remove Circle CI (#1010)
46
+ * Rename deprecated `BigDecimal.new` to `BigDecimal` (#1024) [Koichi ITO]
47
+ * Rename deprecated Rubocop name (#1027) [Justin Li]
48
+
49
+ ### Fixed
50
+ * Handle `join` filter on non String joiners (#857) [Richard Monette]
51
+ * Fix duplicate inclusion condition logic error of `Liquid::Strainer.add_filter` method (#861)
52
+ * Fix `escape`, `url_encode`, `url_decode` not handling non-string values (#898) [Thierry Joyal]
53
+ * Fix raise when variable is defined but nil when using `strict_variables` [Pascal Betz]
54
+ * Fix `sort` and `sort_natural` to handle arrays with nils (#930) [Eric Chan]
55
+
56
+ ## 4.0.0 / 2016-12-14 / branch "4-0-stable"
57
+
58
+ ### Changed
59
+ * Render an opaque internal error by default for non-Liquid::Error (#835) [Dylan Thacker-Smith]
60
+ * Ruby 2.0 support dropped (#832) [Dylan Thacker-Smith]
61
+ * Add to_number Drop method to allow custom drops to work with number filters (#731)
62
+ * Add strict_variables and strict_filters options to detect undefined references (#691)
63
+ * Improve loop performance (#681) [Florian Weingarten]
64
+ * Rename Drop method `before_method` to `liquid_method_missing` (#661) [Thierry Joyal]
65
+ * Add url_decode filter to invert url_encode (#645) [Larry Archer]
66
+ * Add global_filter to apply a filter to all output (#610) [Loren Hale]
67
+ * Add compact filter (#600) [Carson Reinke]
68
+ * Rename deprecated "has_key?" and "has_interrupt?" methods (#593) [Florian Weingarten]
69
+ * Include template name with line numbers in render errors (574) [Dylan Thacker-Smith]
70
+ * Add sort_natural filter (#554) [Martin Hanzel]
71
+ * Add forloop.parentloop as a reference to the parent loop (#520) [Justin Li]
72
+ * Block parsing moved to BlockBody class (#458) [Dylan Thacker-Smith]
73
+ * Add concat filter to concatenate arrays (#429) [Diogo Beato]
74
+ * Ruby 1.9 support dropped (#491) [Justin Li]
75
+ * Liquid::Template.file_system's read_template_file method is no longer passed the context. (#441) [James Reid-Smith]
76
+ * Remove `liquid_methods` (See https://github.com/Shopify/liquid/pull/568 for replacement)
77
+ * Liquid::Template.register_filter raises when the module overrides registered public methods as private or protected (#705) [Gaurav Chande]
78
+
79
+ ### Fixed
80
+
81
+ * Fix variable names being detected as an operator when starting with contains (#788) [Michael Angell]
82
+ * Fix include tag used with strict_variables (#828) [QuickPay]
83
+ * Fix map filter when value is a Proc (#672) [Guillaume Malette]
84
+ * Fix truncate filter when value is not a string (#672) [Guillaume Malette]
85
+ * Fix behaviour of escape filter when input is nil (#665) [Tanel Jakobsoo]
86
+ * Fix sort filter behaviour with empty array input (#652) [Marcel Cary]
87
+ * Fix test failure under certain timezones (#631) [Dylan Thacker-Smith]
88
+ * Fix bug in uniq filter (#595) [Florian Weingarten]
89
+ * Fix bug when "blank" and "empty" are used as variable names (#592) [Florian Weingarten]
90
+ * Fix condition parse order in strict mode (#569) [Justin Li]
91
+ * Fix naming of the "context variable" when dynamically including a template (#559) [Justin Li]
92
+ * Gracefully accept empty strings in the date filter (#555) [Loren Hale]
93
+ * Fix capturing into variables with a hyphen in the name (#505) [Florian Weingarten]
94
+ * Fix case sensitivity regression in date standard filter (#499) [Kelley Reynolds]
95
+ * Disallow filters with no variable in strict mode (#475) [Justin Li]
96
+ * Disallow variable names in the strict parser that are not valid in the lax parser (#463) [Justin Li]
97
+ * Fix BlockBody#warnings taking exponential time to compute (#486) [Justin Li]
98
+
99
+ ## 3.0.5 / 2015-07-23 / branch "3-0-stable"
100
+
101
+ * Fix test failure under certain timezones [Dylan Thacker-Smith]
102
+
103
+ ## 3.0.4 / 2015-07-17
104
+
105
+ * Fix chained access to multi-dimensional hashes [Florian Weingarten]
106
+
107
+ ## 3.0.3 / 2015-05-28
108
+
109
+ * Fix condition parse order in strict mode (#569) [Justin Li]
110
+
111
+ ## 3.0.2 / 2015-04-24
112
+
113
+ * Expose VariableLookup private members (#551) [Justin Li]
114
+ * Documentation fixes
115
+
116
+ ## 3.0.1 / 2015-01-23
117
+
118
+ * Remove duplicate `index0` key in TableRow tag (#502) [Alfred Xing]
119
+
120
+ ## 3.0.0 / 2014-11-12
121
+
122
+ * Removed Block#end_tag. Instead, override parse with `super` followed by your code. See #446 [Dylan Thacker-Smith]
123
+ * Fixed condition with wrong data types (#423) [Bogdan Gusiev]
124
+ * Add url_encode to standard filters (#421) [Derrick Reimer]
125
+ * Add uniq to standard filters [Florian Weingarten]
126
+ * Add exception_handler feature (#397) and #254 [Bogdan Gusiev, Florian Weingarten]
127
+ * Optimize variable parsing to avoid repeated regex evaluation during template rendering #383 [Jason Hiltz-Laforge]
128
+ * Optimize checking for block interrupts to reduce object allocation #380 [Jason Hiltz-Laforge]
129
+ * Properly set context rethrow_errors on render! #349 [Thierry Joyal]
130
+ * Fix broken rendering of variables which are equal to false (#345) [Florian Weingarten]
131
+ * Remove ActionView template handler [Dylan Thacker-Smith]
132
+ * Freeze lots of string literals for new Ruby 2.1 optimization (#297) [Florian Weingarten]
133
+ * Allow newlines in tags and variables (#324) [Dylan Thacker-Smith]
134
+ * Tag#parse is called after initialize, which now takes options instead of tokens as the 3rd argument. See #321 [Dylan Thacker-Smith]
135
+ * Raise `Liquid::ArgumentError` instead of `::ArgumentError` when filter has wrong number of arguments #309 [Bogdan Gusiev]
136
+ * Add a to_s default for liquid drops (#306) [Adam Doeler]
137
+ * Add strip, lstrip, and rstrip to standard filters [Florian Weingarten]
138
+ * Make if, for & case tags return complete and consistent nodelists (#250) [Nick Jones]
139
+ * Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith]
140
+ * Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl]
141
+ * Fix resource counting bug with respond_to?(:length) (#263) [Florian Weingarten]
142
+ * Allow specifying custom patterns for template filenames (#284) [Andrei Gladkyi]
143
+ * Allow drops to optimize loading a slice of elements (#282) [Tom Burns]
144
+ * Support for passing variables to snippets in subdirs (#271) [Joost Hietbrink]
145
+ * Add a class cache to avoid runtime extend calls (#249) [James Tucker]
146
+ * Remove some legacy Ruby 1.8 compatibility code (#276) [Florian Weingarten]
147
+ * Add default filter to standard filters (#267) [Derrick Reimer]
148
+ * Add optional strict parsing and warn parsing (#235) [Tristan Hume]
149
+ * Add I18n syntax error translation (#241) [Simon Hørup Eskildsen, Sirupsen]
150
+ * Make sort filter work on enumerable drops (#239) [Florian Weingarten]
151
+ * Fix clashing method names in enumerable drops (#238) [Florian Weingarten]
152
+ * Make map filter work on enumerable drops (#233) [Florian Weingarten]
153
+ * Improved whitespace stripping for blank blocks, related to #216 [Florian Weingarten]
154
+
155
+ ## 2.6.3 / 2015-07-23 / branch "2-6-stable"
156
+
157
+ * Fix test failure under certain timezones [Dylan Thacker-Smith]
158
+
159
+ ## 2.6.2 / 2015-01-23
160
+
161
+ * Remove duplicate hash key [Parker Moore]
162
+
163
+ ## 2.6.1 / 2014-01-10
7
164
 
8
165
  Security fix, cherry-picked from master (4e14a65):
9
- * Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
10
- * Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
166
+ * Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl]
167
+ * Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith]
11
168
 
12
169
  ## 2.6.0 / 2013-11-25
13
170
 
14
- * ...
171
+ IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
172
+ The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
173
+
15
174
  * Bugfix for #106: fix example servlet [gnowoel]
16
- * Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss, joliss]
17
- * Bugfix for #114: strip_html filter supports style tags [James Allardice, jamesallardice]
18
- * Bugfix for #117: 'now' support for date filter in Ruby 1.9 [Notre Dame Webgroup, ndwebgroup]
19
- * Bugfix for #166: truncate filter on UTF-8 strings with Ruby 1.8 [Florian Weingarten, fw42]
20
- * Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
21
- * Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
22
- * Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
23
- * Bugfix for #174, "can't convert Fixnum into String" for "replace" [wǒ_is神仙, jsw0528]
24
- * Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
25
- * Resource limits [Florian Weingarten, fw42]
26
- * Add reverse filter [Jay Strybis, unreal]
175
+ * Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss]
176
+ * Bugfix for #114: strip_html filter supports style tags [James Allardice]
177
+ * Bugfix for #117: 'now' support for date filter in Ruby 1.9 [Notre Dame Webgroup]
178
+ * Bugfix for #166: truncate filter on UTF-8 strings with Ruby 1.8 [Florian Weingarten]
179
+ * Bugfix for #204: 'raw' parsing bug [Florian Weingarten]
180
+ * Bugfix for #150: 'for' parsing bug [Peter Schröder]
181
+ * Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder]
182
+ * Bugfix for #174, "can't convert Fixnum into String" for "replace" [jsw0528]
183
+ * Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep]
184
+ * Resource limits [Florian Weingarten]
185
+ * Add reverse filter [Jay Strybis]
27
186
  * Add utf-8 support
28
- * Use array instead of Hash to keep the registered filters [Tasos Stathopoulos, astathopoulos]
29
- * Cache tokenized partial templates [Tom Burns, boourns]
30
- * Avoid warnings in Ruby 1.9.3 [Marcus Stollsteimer, stomar]
31
- * Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
32
- * Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
187
+ * Use array instead of Hash to keep the registered filters [Tasos Stathopoulos]
188
+ * Cache tokenized partial templates [Tom Burns]
189
+ * Avoid warnings in Ruby 1.9.3 [Marcus Stollsteimer]
190
+ * Better documentation for 'include' tag (closes #163) [Peter Schröder]
191
+ * Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves]
192
+
193
+ ## 2.5.5 / 2014-01-10 / branch "2-5-stable"
194
+
195
+ Security fix, cherry-picked from master (4e14a65):
196
+ * Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl]
197
+ * Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith]
33
198
 
34
- ## 2.5.4 / 2013-11-11 / branch "2.5-stable"
199
+ ## 2.5.4 / 2013-11-11
35
200
 
36
- * Fix "can't convert Fixnum into String" for "replace", see #173, [wǒ_is神仙, jsw0528]
201
+ * Fix "can't convert Fixnum into String" for "replace" (#173), [jsw0528]
37
202
 
38
203
  ## 2.5.3 / 2013-10-09
39
204
 
40
- * #232, #234, #237: Fix map filter bugs [Florian Weingarten, fw42]
205
+ * #232, #234, #237: Fix map filter bugs [Florian Weingarten]
41
206
 
42
207
  ## 2.5.2 / 2013-09-03 / deleted
43
208
 
@@ -45,7 +210,7 @@ Yanked from rubygems, as it contained too many changes that broke compatibility.
45
210
 
46
211
  ## 2.5.1 / 2013-07-24
47
212
 
48
- * #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten, fw42]
213
+ * #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten]
49
214
 
50
215
  ## 2.5.0 / 2013-03-06
51
216
 
File without changes
data/README.md CHANGED
@@ -1,9 +1,12 @@
1
+ [![Build Status](https://api.travis-ci.org/Shopify/liquid.svg?branch=master)](http://travis-ci.org/Shopify/liquid)
2
+ [![Inline docs](http://inch-ci.org/github/Shopify/liquid.svg?branch=master)](http://inch-ci.org/github/Shopify/liquid)
3
+
1
4
  # Liquid template engine
2
5
 
3
6
  * [Contributing guidelines](CONTRIBUTING.md)
4
7
  * [Version history](History.md)
5
8
  * [Liquid documentation from Shopify](http://docs.shopify.com/themes/liquid-basics)
6
- * [Liquid Wiki from Shopify](http://wiki.shopify.com/Liquid)
9
+ * [Liquid Wiki at GitHub](https://github.com/Shopify/liquid/wiki)
7
10
  * [Website](http://liquidmarkup.org/)
8
11
 
9
12
  ## Introduction
@@ -39,6 +42,8 @@ Liquid is a template engine which was written with very specific requirements:
39
42
 
40
43
  ## How to use Liquid
41
44
 
45
+ Install Liquid by adding `gem 'liquid'` to your gemfile.
46
+
42
47
  Liquid supports a very simple API based around the Liquid::Template class.
43
48
  For standard use you can just pass it the content of a file and call render with a parameters hash.
44
49
 
@@ -47,4 +52,57 @@ For standard use you can just pass it the content of a file and call render with
47
52
  @template.render('name' => 'tobi') # => "hi tobi"
48
53
  ```
49
54
 
50
- [![Build Status](https://secure.travis-ci.org/Shopify/liquid.png)](http://travis-ci.org/Shopify/liquid)
55
+ ### Error Modes
56
+
57
+ Setting the error mode of Liquid lets you specify how strictly you want your templates to be interpreted.
58
+ Normally the parser is very lax and will accept almost anything without error. Unfortunately this can make
59
+ it very hard to debug and can lead to unexpected behaviour.
60
+
61
+ Liquid also comes with a stricter parser that can be used when editing templates to give better error messages
62
+ when templates are invalid. You can enable this new parser like this:
63
+
64
+ ```ruby
65
+ Liquid::Template.error_mode = :strict # Raises a SyntaxError when invalid syntax is used
66
+ Liquid::Template.error_mode = :warn # Adds errors to template.errors but continues as normal
67
+ Liquid::Template.error_mode = :lax # The default mode, accepts almost anything.
68
+ ```
69
+
70
+ If you want to set the error mode only on specific templates you can pass `:error_mode` as an option to `parse`:
71
+ ```ruby
72
+ Liquid::Template.parse(source, :error_mode => :strict)
73
+ ```
74
+ This is useful for doing things like enabling strict mode only in the theme editor.
75
+
76
+ It is recommended that you enable `:strict` or `:warn` mode on new apps to stop invalid templates from being created.
77
+ It is also recommended that you use it in the template editors of existing apps to give editors better error messages.
78
+
79
+ ### Undefined variables and filters
80
+
81
+ By default, the renderer doesn't raise or in any other way notify you if some variables or filters are missing, i.e. not passed to the `render` method.
82
+ You can improve this situation by passing `strict_variables: true` and/or `strict_filters: true` options to the `render` method.
83
+ When one of these options is set to true, all errors about undefined variables and undefined filters will be stored in `errors` array of a `Liquid::Template` instance.
84
+ Here are some examples:
85
+
86
+ ```ruby
87
+ template = Liquid::Template.parse("{{x}} {{y}} {{z.a}} {{z.b}}")
88
+ template.render({ 'x' => 1, 'z' => { 'a' => 2 } }, { strict_variables: true })
89
+ #=> '1 2 ' # when a variable is undefined, it's rendered as nil
90
+ template.errors
91
+ #=> [#<Liquid::UndefinedVariable: Liquid error: undefined variable y>, #<Liquid::UndefinedVariable: Liquid error: undefined variable b>]
92
+ ```
93
+
94
+ ```ruby
95
+ template = Liquid::Template.parse("{{x | filter1 | upcase}}")
96
+ template.render({ 'x' => 'foo' }, { strict_filters: true })
97
+ #=> '' # when at least one filter in the filter chain is undefined, a whole expression is rendered as nil
98
+ template.errors
99
+ #=> [#<Liquid::UndefinedFilter: Liquid error: undefined filter filter1>]
100
+ ```
101
+
102
+ If you want to raise on a first exception instead of pushing all of them in `errors`, you can use `render!` method:
103
+
104
+ ```ruby
105
+ template = Liquid::Template.parse("{{x}} {{y}}")
106
+ template.render!({ 'x' => 1}, { strict_variables: true })
107
+ #=> Liquid::UndefinedVariable: Liquid error: undefined variable y
108
+ ```
@@ -21,9 +21,10 @@
21
21
 
22
22
  module Liquid
23
23
  FilterSeparator = /\|/
24
- ArgumentSeparator = ','
25
- FilterArgumentSeparator = ':'
26
- VariableAttributeSeparator = '.'
24
+ ArgumentSeparator = ','.freeze
25
+ FilterArgumentSeparator = ':'.freeze
26
+ VariableAttributeSeparator = '.'.freeze
27
+ WhitespaceControl = '-'.freeze
27
28
  TagStart = /\{\%/
28
29
  TagEnd = /\%\}/
29
30
  VariableSignature = /\(?[\w\-\.\[\]]\)?/
@@ -33,37 +34,47 @@ module Liquid
33
34
  VariableIncompleteEnd = /\}\}?/
34
35
  QuotedString = /"[^"]*"|'[^']*'/
35
36
  QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
36
- StrictQuotedFragment = /"[^"]+"|'[^']+'|[^\s|:,]+/
37
- FirstFilterArgument = /#{FilterArgumentSeparator}(?:#{StrictQuotedFragment})/o
38
- OtherFilterArgument = /#{ArgumentSeparator}(?:#{StrictQuotedFragment})/o
39
- SpacelessFilter = /^(?:'[^']+'|"[^"]+"|[^'"])*#{FilterSeparator}(?:#{StrictQuotedFragment})(?:#{FirstFilterArgument}(?:#{OtherFilterArgument})*)?/o
40
- Expression = /(?:#{QuotedFragment}(?:#{SpacelessFilter})*)/o
41
37
  TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
42
- AnyStartingTag = /\{\{|\{\%/
43
- PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/o
44
- TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/o
38
+ AnyStartingTag = /#{TagStart}|#{VariableStart}/o
39
+ PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
40
+ TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
45
41
  VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
42
+
43
+ singleton_class.send(:attr_accessor, :cache_classes)
44
+ self.cache_classes = true
46
45
  end
47
46
 
48
47
  require "liquid/version"
48
+ require 'liquid/parse_tree_visitor'
49
+ require 'liquid/lexer'
50
+ require 'liquid/parser'
51
+ require 'liquid/i18n'
49
52
  require 'liquid/drop'
53
+ require 'liquid/tablerowloop_drop'
54
+ require 'liquid/forloop_drop'
50
55
  require 'liquid/extensions'
51
56
  require 'liquid/errors'
52
57
  require 'liquid/interrupts'
53
58
  require 'liquid/strainer'
59
+ require 'liquid/expression'
54
60
  require 'liquid/context'
61
+ require 'liquid/parser_switching'
55
62
  require 'liquid/tag'
56
63
  require 'liquid/block'
64
+ require 'liquid/block_body'
57
65
  require 'liquid/document'
58
66
  require 'liquid/variable'
67
+ require 'liquid/variable_lookup'
68
+ require 'liquid/range_lookup'
59
69
  require 'liquid/file_system'
70
+ require 'liquid/resource_limits'
60
71
  require 'liquid/template'
61
- require 'liquid/htmltags'
62
72
  require 'liquid/standardfilters'
63
73
  require 'liquid/condition'
64
- require 'liquid/module_ex'
65
74
  require 'liquid/utils'
75
+ require 'liquid/tokenizer'
76
+ require 'liquid/parse_context'
66
77
 
67
78
  # Load all the tags of the standard library
68
79
  #
69
- Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
80
+ Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f }
@@ -1,126 +1,77 @@
1
1
  module Liquid
2
-
3
2
  class Block < Tag
4
- IsTag = /^#{TagStart}/o
5
- IsVariable = /^#{VariableStart}/o
6
- FullToken = /^#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}$/o
7
- ContentOfVariable = /^#{VariableStart}(.*)#{VariableEnd}$/o
8
-
9
- def parse(tokens)
10
- @nodelist ||= []
11
- @nodelist.clear
12
-
13
- while token = tokens.shift
3
+ MAX_DEPTH = 100
14
4
 
15
- case token
16
- when IsTag
17
- if token =~ FullToken
18
-
19
- # if we found the proper block delimiter just end parsing here and let the outer block
20
- # proceed
21
- if block_delimiter == $1
22
- end_tag
23
- return
24
- end
5
+ def initialize(tag_name, markup, options)
6
+ super
7
+ @blank = true
8
+ end
25
9
 
26
- # fetch the tag from registered blocks
27
- if tag = Template.tags[$1]
28
- @nodelist << tag.new($1, $2, tokens)
29
- else
30
- # this tag is not registered with the system
31
- # pass it to the current block for special handling or error reporting
32
- unknown_tag($1, $2, tokens)
33
- end
34
- else
35
- raise SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{TagEnd.inspect} "
36
- end
37
- when IsVariable
38
- @nodelist << create_variable(token)
39
- when ''
40
- # pass
41
- else
42
- @nodelist << token
43
- end
10
+ def parse(tokens)
11
+ @body = BlockBody.new
12
+ while parse_body(@body, tokens)
44
13
  end
14
+ end
45
15
 
46
- # Make sure that it's ok to end parsing in the current block.
47
- # Effectively this method will throw an exception unless the current block is
48
- # of type Document
49
- assert_missing_delimitation!
16
+ def render(context)
17
+ @body.render(context)
50
18
  end
51
19
 
52
- def end_tag
20
+ def blank?
21
+ @blank
53
22
  end
54
23
 
55
- def unknown_tag(tag, params, tokens)
56
- case tag
57
- when 'else'
58
- raise SyntaxError, "#{block_name} tag does not expect else tag"
59
- when 'end'
60
- raise SyntaxError, "'end' is not a valid delimiter for #{block_name} tags. use #{block_delimiter}"
61
- else
62
- raise SyntaxError, "Unknown tag '#{tag}'"
63
- end
24
+ def nodelist
25
+ @body.nodelist
64
26
  end
65
27
 
66
- def block_delimiter
67
- "end#{block_name}"
28
+ def unknown_tag(tag, _params, _tokens)
29
+ if tag == 'else'.freeze
30
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_else".freeze,
31
+ block_name: block_name))
32
+ elsif tag.start_with?('end'.freeze)
33
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.invalid_delimiter".freeze,
34
+ tag: tag,
35
+ block_name: block_name,
36
+ block_delimiter: block_delimiter))
37
+ else
38
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag))
39
+ end
68
40
  end
69
41
 
70
42
  def block_name
71
43
  @tag_name
72
44
  end
73
45
 
74
- def create_variable(token)
75
- token.scan(ContentOfVariable) do |content|
76
- return Variable.new(content.first)
77
- end
78
- raise SyntaxError.new("Variable '#{token}' was not properly terminated with regexp: #{VariableEnd.inspect} ")
79
- end
80
-
81
- def render(context)
82
- render_all(@nodelist, context)
46
+ def block_delimiter
47
+ @block_delimiter ||= "end#{block_name}"
83
48
  end
84
49
 
85
50
  protected
86
51
 
87
- def assert_missing_delimitation!
88
- raise SyntaxError.new("#{block_name} tag was never closed")
89
- end
90
-
91
- def render_all(list, context)
92
- output = []
93
- context.resource_limits[:render_length_current] = 0
94
- context.resource_limits[:render_score_current] += list.length
95
-
96
- list.each do |token|
97
- # Break out if we have any unhanded interrupts.
98
- break if context.has_interrupt?
99
-
100
- begin
101
- # If we get an Interrupt that means the block must stop processing. An
102
- # Interrupt is any command that stops block execution such as {% break %}
103
- # or {% continue %}
104
- if token.is_a? Continue or token.is_a? Break
105
- context.push_interrupt(token.interrupt)
106
- break
52
+ def parse_body(body, tokens)
53
+ if parse_context.depth >= MAX_DEPTH
54
+ raise StackLevelError, "Nesting too deep".freeze
55
+ end
56
+ parse_context.depth += 1
57
+ begin
58
+ body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|
59
+ @blank &&= body.blank?
60
+
61
+ return false if end_tag_name == block_delimiter
62
+ unless end_tag_name
63
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
107
64
  end
108
65
 
109
- token_output = (token.respond_to?(:render) ? token.render(context) : token)
110
- context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
111
- if context.resource_limits_reached?
112
- context.resource_limits[:reached] = true
113
- raise MemoryError.new("Memory limits exceeded")
114
- end
115
- output << token_output
116
- rescue MemoryError => e
117
- raise e
118
- rescue ::StandardError => e
119
- output << (context.handle_error(e))
66
+ # this tag is not registered with the system
67
+ # pass it to the current block for special handling or error reporting
68
+ unknown_tag(end_tag_name, end_tag_params, tokens)
120
69
  end
70
+ ensure
71
+ parse_context.depth -= 1
121
72
  end
122
73
 
123
- output.join
74
+ true
124
75
  end
125
76
  end
126
77
  end