liquid 2.6.1 → 4.0.3

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 (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