bunto 3.0.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +124 -76
  3. data/README.markdown +49 -12
  4. data/{bin → exe}/bunto +18 -14
  5. data/lib/bunto.rb +83 -78
  6. data/lib/bunto/cleaner.rb +10 -8
  7. data/lib/bunto/collection.rb +33 -17
  8. data/lib/bunto/command.rb +19 -13
  9. data/lib/bunto/commands/build.rb +22 -14
  10. data/lib/bunto/commands/clean.rb +9 -8
  11. data/lib/bunto/commands/doctor.rb +10 -8
  12. data/lib/bunto/commands/help.rb +4 -3
  13. data/lib/bunto/commands/new.rb +30 -21
  14. data/lib/bunto/commands/new_theme.rb +36 -0
  15. data/lib/bunto/commands/serve.rb +26 -20
  16. data/lib/bunto/commands/serve/servlet.rb +4 -5
  17. data/lib/bunto/configuration.rb +187 -125
  18. data/lib/bunto/converters/markdown.rb +19 -9
  19. data/lib/bunto/converters/markdown/kramdown_parser.rb +12 -5
  20. data/lib/bunto/converters/markdown/rdiscount_parser.rb +4 -4
  21. data/lib/bunto/converters/markdown/redcarpet_parser.rb +90 -84
  22. data/lib/bunto/convertible.rb +38 -25
  23. data/lib/bunto/deprecator.rb +11 -6
  24. data/lib/bunto/desktop.ini +2 -0
  25. data/lib/bunto/document.rb +53 -51
  26. data/lib/bunto/drops/bunto_drop.rb +12 -0
  27. data/lib/bunto/drops/document_drop.rb +40 -5
  28. data/lib/bunto/drops/drop.rb +49 -10
  29. data/lib/bunto/drops/excerpt_drop.rb +15 -0
  30. data/lib/bunto/drops/site_drop.rb +4 -2
  31. data/lib/bunto/drops/url_drop.rb +4 -4
  32. data/lib/bunto/entry_filter.rb +64 -19
  33. data/lib/bunto/errors.rb +6 -3
  34. data/lib/bunto/excerpt.rb +4 -6
  35. data/lib/bunto/external.rb +4 -4
  36. data/lib/bunto/filters.rb +72 -39
  37. data/lib/bunto/frontmatter_defaults.rb +45 -38
  38. data/lib/bunto/hooks.rb +21 -21
  39. data/lib/bunto/layout.rb +4 -8
  40. data/lib/bunto/liquid_renderer.rb +14 -3
  41. data/lib/bunto/liquid_renderer/file.rb +5 -1
  42. data/lib/bunto/liquid_renderer/table.rb +11 -11
  43. data/lib/bunto/log_adapter.rb +2 -2
  44. data/lib/bunto/page.rb +10 -10
  45. data/lib/bunto/plugin.rb +5 -5
  46. data/lib/bunto/plugin_manager.rb +12 -8
  47. data/lib/bunto/publisher.rb +1 -1
  48. data/lib/bunto/reader.rb +11 -7
  49. data/lib/bunto/readers/data_reader.rb +9 -9
  50. data/lib/bunto/readers/layout_reader.rb +7 -7
  51. data/lib/bunto/readers/page_reader.rb +3 -1
  52. data/lib/bunto/readers/post_reader.rb +9 -10
  53. data/lib/bunto/readers/static_file_reader.rb +3 -1
  54. data/lib/bunto/regenerator.rb +50 -28
  55. data/lib/bunto/related_posts.rb +1 -1
  56. data/lib/bunto/renderer.rb +33 -23
  57. data/lib/bunto/site.rb +94 -51
  58. data/lib/bunto/static_file.rb +33 -26
  59. data/lib/bunto/stevenson.rb +6 -5
  60. data/lib/bunto/tags/highlight.rb +50 -35
  61. data/lib/bunto/tags/include.rb +42 -31
  62. data/lib/bunto/tags/link.rb +11 -4
  63. data/lib/bunto/tags/post_url.rb +8 -7
  64. data/lib/bunto/theme.rb +10 -8
  65. data/lib/bunto/theme_builder.rb +117 -0
  66. data/lib/bunto/url.rb +21 -14
  67. data/lib/bunto/utils.rb +57 -28
  68. data/lib/bunto/utils/ansi.rb +9 -9
  69. data/lib/bunto/utils/platforms.rb +2 -2
  70. data/lib/bunto/version.rb +1 -1
  71. data/lib/site_template/_config.yml +3 -1
  72. data/lib/site_template/_posts/0000-00-00-welcome-to-bunto.markdown.erb +3 -3
  73. data/lib/site_template/about.md +3 -3
  74. data/lib/site_template/css/main.scss +3 -17
  75. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
  76. data/lib/theme_template/Gemfile +2 -0
  77. data/lib/theme_template/LICENSE.txt.erb +21 -0
  78. data/lib/theme_template/README.md.erb +48 -0
  79. data/lib/theme_template/_layouts/default.html +1 -0
  80. data/lib/theme_template/_layouts/page.html +5 -0
  81. data/lib/theme_template/_layouts/post.html +5 -0
  82. data/lib/theme_template/example/_config.yml.erb +1 -0
  83. data/lib/theme_template/example/_post.md +12 -0
  84. data/lib/theme_template/example/index.html +14 -0
  85. data/lib/theme_template/example/style.scss +7 -0
  86. data/lib/theme_template/gitignore.erb +4 -0
  87. data/lib/theme_template/theme.gemspec.erb +18 -0
  88. metadata +40 -19
  89. data/lib/site_template/_includes/footer.html +0 -38
  90. data/lib/site_template/_includes/head.html +0 -12
  91. data/lib/site_template/_includes/header.html +0 -27
  92. data/lib/site_template/_includes/icon-github.html +0 -1
  93. data/lib/site_template/_includes/icon-github.svg +0 -1
  94. data/lib/site_template/_includes/icon-twitter.html +0 -1
  95. data/lib/site_template/_includes/icon-twitter.svg +0 -1
  96. data/lib/site_template/_layouts/default.html +0 -20
  97. data/lib/site_template/_layouts/page.html +0 -14
  98. data/lib/site_template/_layouts/post.html +0 -15
  99. data/lib/site_template/_sass/_base.scss +0 -200
  100. data/lib/site_template/_sass/_layout.scss +0 -242
  101. data/lib/site_template/_sass/_syntax-highlighting.scss +0 -71
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+
3
+ module Bunto
4
+ module Drops
5
+ class ExcerptDrop < DocumentDrop
6
+ def layout
7
+ @obj.doc.data["layout"]
8
+ end
9
+
10
+ def excerpt
11
+ nil
12
+ end
13
+ end
14
+ end
15
+ end
@@ -24,11 +24,13 @@ module Bunto
24
24
  end
25
25
 
26
26
  def html_pages
27
- @site_html_pages ||= @obj.pages.select { |page| page.html? || page.url.end_with?("/") }
27
+ @site_html_pages ||= @obj.pages.select do |page|
28
+ page.html? || page.url.end_with?("/")
29
+ end
28
30
  end
29
31
 
30
32
  def collections
31
- @site_collections ||= @obj.collections.values.map(&:to_liquid)
33
+ @site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid)
32
34
  end
33
35
 
34
36
  private
@@ -19,20 +19,20 @@ module Bunto
19
19
  end
20
20
 
21
21
  def title
22
- Utils.slugify(@obj.data['slug'], :mode => "pretty", :cased => true) ||
22
+ Utils.slugify(@obj.data["slug"], :mode => "pretty", :cased => true) ||
23
23
  Utils.slugify(@obj.basename_without_ext, :mode => "pretty", :cased => true)
24
24
  end
25
25
 
26
26
  def slug
27
- Utils.slugify(@obj.data['slug']) || Utils.slugify(@obj.basename_without_ext)
27
+ Utils.slugify(@obj.data["slug"]) || Utils.slugify(@obj.basename_without_ext)
28
28
  end
29
29
 
30
30
  def categories
31
31
  category_set = Set.new
32
- Array(@obj.data['categories']).each do |category|
32
+ Array(@obj.data["categories"]).each do |category|
33
33
  category_set << category.to_s.downcase
34
34
  end
35
- category_set.to_a.join('/')
35
+ category_set.to_a.join("/")
36
36
  end
37
37
 
38
38
  def year
@@ -1,12 +1,15 @@
1
1
  module Bunto
2
2
  class EntryFilter
3
- SPECIAL_LEADING_CHARACTERS = ['.', '_', '#', '~'].freeze
4
-
5
3
  attr_reader :site
4
+ SPECIAL_LEADING_CHARACTERS = [
5
+ ".", "_", "#", "~"
6
+ ].freeze
6
7
 
7
8
  def initialize(site, base_directory = nil)
8
9
  @site = site
9
- @base_directory = derive_base_directory(@site, base_directory.to_s.dup)
10
+ @base_directory = derive_base_directory(
11
+ @site, base_directory.to_s.dup
12
+ )
10
13
  end
11
14
 
12
15
  def base_directory
@@ -14,14 +17,14 @@ module Bunto
14
17
  end
15
18
 
16
19
  def derive_base_directory(site, base_dir)
17
- if base_dir.start_with?(site.source)
18
- base_dir[site.source] = ""
19
- end
20
+ base_dir[site.source] = "" if base_dir.start_with?(site.source)
20
21
  base_dir
21
22
  end
22
23
 
23
24
  def relative_to_source(entry)
24
- File.join(base_directory, entry)
25
+ File.join(
26
+ base_directory, entry
27
+ )
25
28
  end
26
29
 
27
30
  def filter(entries)
@@ -33,7 +36,8 @@ module Bunto
33
36
  end
34
37
 
35
38
  def included?(entry)
36
- glob_include?(site.include, entry)
39
+ glob_include?(site.include,
40
+ entry)
37
41
  end
38
42
 
39
43
  def special?(entry)
@@ -42,34 +46,75 @@ module Bunto
42
46
  end
43
47
 
44
48
  def backup?(entry)
45
- entry[-1..-1] == '~'
49
+ entry[-1..-1] == "~"
46
50
  end
47
51
 
48
52
  def excluded?(entry)
49
53
  excluded = glob_include?(site.exclude, relative_to_source(entry))
50
- Bunto.logger.debug "EntryFilter:", "excluded #{relative_to_source(entry)}" if excluded
54
+ if excluded
55
+ Bunto.logger.debug(
56
+ "EntryFilter:",
57
+ "excluded #{relative_to_source(entry)}"
58
+ )
59
+ end
51
60
  excluded
52
61
  end
53
62
 
63
+ # --
64
+ # Check if a file is a symlink.
65
+ # NOTE: This can be converted to allowing even in safe,
66
+ # since we use Pathutil#in_path? now.
67
+ # --
54
68
  def symlink?(entry)
55
69
  site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry)
56
70
  end
57
71
 
72
+ # --
73
+ # NOTE: Pathutil#in_path? gets the realpath.
74
+ # @param [<Anything>] entry the entry you want to validate.
75
+ # Check if a path is outside of our given root.
76
+ # --
58
77
  def symlink_outside_site_source?(entry)
59
- ! File.realpath(entry).start_with?(File.realpath(@site.source))
60
- end
61
-
62
- def ensure_leading_slash(path)
63
- path[0..0] == "/" ? path : "/#{path}"
78
+ !Pathutil.new(entry).in_path?(
79
+ site.in_source_dir
80
+ )
64
81
  end
65
82
 
83
+ # --
84
+ # Check if an entry matches a specific pattern and return true,false.
66
85
  # Returns true if path matches against any glob pattern.
67
- # Look for more detail about glob pattern in method File::fnmatch.
86
+ # --
68
87
  def glob_include?(enum, e)
69
- entry = ensure_leading_slash(e)
88
+ entry = Pathutil.new(site.in_source_dir).join(e)
70
89
  enum.any? do |exp|
71
- item = ensure_leading_slash(exp)
72
- File.fnmatch?(item, entry) || entry.start_with?(item)
90
+ # Users who send a Regexp knows what they want to
91
+ # exclude, so let them send a Regexp to exclude files,
92
+ # we will not bother caring if it works or not, it's
93
+ # on them at this point.
94
+
95
+ if exp.is_a?(Regexp)
96
+ entry =~ exp
97
+
98
+ else
99
+ item = Pathutil.new(site.in_source_dir).join(exp)
100
+
101
+ # If it's a directory they want to exclude, AKA
102
+ # ends with a "/" then we will go on to check and
103
+ # see if the entry falls within that path and
104
+ # exclude it if that's the case.
105
+
106
+ if e.end_with?("/")
107
+ entry.in_path?(
108
+ item
109
+ )
110
+
111
+ else
112
+ File.fnmatch?(item, entry) ||
113
+ entry.to_path.start_with?(
114
+ item
115
+ )
116
+ end
117
+ end
73
118
  end
74
119
  end
75
120
  end
@@ -2,13 +2,16 @@ module Bunto
2
2
  module Errors
3
3
  FatalException = Class.new(::RuntimeError)
4
4
 
5
+ InvalidThemeName = Class.new(FatalException)
6
+
5
7
  DropMutationException = Class.new(FatalException)
6
8
  InvalidPermalinkError = Class.new(FatalException)
7
9
  InvalidYAMLFrontMatterError = Class.new(FatalException)
8
10
  MissingDependencyException = Class.new(FatalException)
9
11
 
10
- InvalidDateError = Class.new(FatalException)
11
- InvalidPostNameError = Class.new(FatalException)
12
- PostURLError = Class.new(FatalException)
12
+ InvalidDateError = Class.new(FatalException)
13
+ InvalidPostNameError = Class.new(FatalException)
14
+ PostURLError = Class.new(FatalException)
15
+ InvalidURLError = Class.new(FatalException)
13
16
  end
14
17
  end
@@ -7,7 +7,8 @@ module Bunto
7
7
  attr_writer :output
8
8
 
9
9
  def_delegators :@doc, :site, :name, :ext, :relative_path, :extname,
10
- :render_with_liquid?, :collection, :related_posts
10
+ :render_with_liquid?, :collection, :related_posts,
11
+ :url, :next_doc, :previous_doc
11
12
 
12
13
  # Initialize this Excerpt instance.
13
14
  #
@@ -59,10 +60,7 @@ module Bunto
59
60
  end
60
61
 
61
62
  def to_liquid
62
- doc.data['excerpt'] = nil
63
- @to_liquid ||= doc.to_liquid
64
- doc.data['excerpt'] = self
65
- @to_liquid
63
+ Bunto::Drops::ExcerptDrop.new(self)
66
64
  end
67
65
 
68
66
  # Returns the shorthand String identifier of this doc.
@@ -120,7 +118,7 @@ module Bunto
120
118
  if tail.empty?
121
119
  head
122
120
  else
123
- "" << head << "\n\n" << tail.scan(/^\[[^\]]+\]:.+$/).join("\n")
121
+ "" << head << "\n\n" << tail.scan(%r!^\[[^\]]+\]:.+$!).join("\n")
124
122
  end
125
123
  end
126
124
  end
@@ -17,13 +17,13 @@ module Bunto
17
17
  #
18
18
  # names - a string gem name or array of gem names
19
19
  #
20
- def require_if_present(names, &block)
20
+ def require_if_present(names)
21
21
  Array(names).each do |name|
22
22
  begin
23
23
  require name
24
24
  rescue LoadError
25
25
  Bunto.logger.debug "Couldn't load #{name}. Skipping."
26
- block.call(name) if block
26
+ yield(name) if block_given?
27
27
  false
28
28
  end
29
29
  end
@@ -39,7 +39,7 @@ module Bunto
39
39
  def require_with_graceful_fail(names)
40
40
  Array(names).each do |name|
41
41
  begin
42
- Bunto.logger.debug "Requiring:", "#{name}"
42
+ Bunto.logger.debug "Requiring:", name.to_s
43
43
  require name
44
44
  rescue LoadError => e
45
45
  Bunto.logger.error "Dependency Error:", <<-MSG
@@ -50,7 +50,7 @@ The full error message from Ruby is: '#{e.message}'
50
50
 
51
51
  If you run into trouble, you can find helpful resources at http://bunto.github.io/help/!
52
52
  MSG
53
- raise Bunto::Errors::MissingDependencyException.new(name)
53
+ raise Bunto::Errors::MissingDependencyException, name
54
54
  end
55
55
  end
56
56
  end
@@ -1,7 +1,7 @@
1
- require 'uri'
2
- require 'json'
3
- require 'date'
4
- require 'liquid'
1
+ require "uri"
2
+ require "json"
3
+ require "date"
4
+ require "liquid"
5
5
 
6
6
  module Bunto
7
7
  module Filters
@@ -13,7 +13,7 @@ module Bunto
13
13
  def markdownify(input)
14
14
  site = @context.registers[:site]
15
15
  converter = site.find_converter_instance(Bunto::Converters::Markdown)
16
- converter.convert(input)
16
+ converter.convert(input.to_s)
17
17
  end
18
18
 
19
19
  # Convert quotes into smart quotes.
@@ -24,7 +24,7 @@ module Bunto
24
24
  def smartify(input)
25
25
  site = @context.registers[:site]
26
26
  converter = site.find_converter_instance(Bunto::Converters::SmartyPants)
27
- converter.convert(input)
27
+ converter.convert(input.to_s)
28
28
  end
29
29
 
30
30
  # Convert a Sass string into CSS output.
@@ -56,7 +56,7 @@ module Bunto
56
56
  #
57
57
  # Returns the given filename or title as a lowercase URL String.
58
58
  # See Utils.slugify for more detail.
59
- def slugify(input, mode=nil)
59
+ def slugify(input, mode = nil)
60
60
  Utils.slugify(input, :mode => mode)
61
61
  end
62
62
 
@@ -118,7 +118,7 @@ module Bunto
118
118
  #
119
119
  # Returns the escaped String.
120
120
  def xml_escape(input)
121
- input.to_s.encode(:xml => :attr).gsub(/\A"|"\Z/, "")
121
+ input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "")
122
122
  end
123
123
 
124
124
  # CGI escape a string for use in a URL. Replaces any special characters
@@ -133,7 +133,7 @@ module Bunto
133
133
  #
134
134
  # Returns the escaped String.
135
135
  def cgi_escape(input)
136
- CGI::escape(input)
136
+ CGI.escape(input)
137
137
  end
138
138
 
139
139
  # URI escape a string.
@@ -150,6 +150,15 @@ module Bunto
150
150
  URI.escape(input)
151
151
  end
152
152
 
153
+ # Replace any whitespace in the input string with a single space
154
+ #
155
+ # input - The String on which to operate.
156
+ #
157
+ # Returns the formatted String
158
+ def normalize_whitespace(input)
159
+ input.to_s.gsub(%r!\s+!, " ").strip
160
+ end
161
+
153
162
  # Count the number of words in the input string.
154
163
  #
155
164
  # input - The String on which to operate.
@@ -180,7 +189,7 @@ module Bunto
180
189
  when 2
181
190
  "#{array[0]} #{connector} #{array[1]}"
182
191
  else
183
- "#{array[0...-1].join(', ')}, #{connector} #{array[-1]}"
192
+ "#{array[0...-1].join(", ")}, #{connector} #{array[-1]}"
184
193
  end
185
194
  end
186
195
 
@@ -203,11 +212,14 @@ module Bunto
203
212
  # "items" => [...] } # all the items where `property` == "larry"
204
213
  def group_by(input, property)
205
214
  if groupable?(input)
206
- input.group_by do |item|
207
- item_property(item, property).to_s
208
- end.inject([]) do |memo, i|
209
- memo << { "name" => i.first, "items" => i.last, "size" => i.last.size }
210
- end
215
+ input.group_by { |item| item_property(item, property).to_s }
216
+ .each_with_object([]) do |item, array|
217
+ array << {
218
+ "name" => item.first,
219
+ "items" => item.last,
220
+ "size" => item.last.size
221
+ }
222
+ end
211
223
  else
212
224
  input
213
225
  end
@@ -221,9 +233,11 @@ module Bunto
221
233
  #
222
234
  # Returns the filtered array of objects
223
235
  def where(input, property, value)
224
- return input unless input.is_a?(Enumerable)
236
+ return input unless input.respond_to?(:select)
225
237
  input = input.values if input.is_a?(Hash)
226
- input.select { |object| Array(item_property(object, property)).map(&:to_s).include?(value.to_s) }
238
+ input.select do |object|
239
+ Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
240
+ end || []
227
241
  end
228
242
 
229
243
  # Filters an array of objects against an expression
@@ -234,7 +248,7 @@ module Bunto
234
248
  #
235
249
  # Returns the filtered array of objects
236
250
  def where_exp(input, variable, expression)
237
- return input unless input.is_a?(Enumerable)
251
+ return input unless input.respond_to?(:select)
238
252
  input = input.values if input.is_a?(Hash) # FIXME
239
253
 
240
254
  condition = parse_condition(expression)
@@ -243,7 +257,18 @@ module Bunto
243
257
  @context[variable] = object
244
258
  condition.evaluate(@context)
245
259
  end
246
- end
260
+ end || []
261
+ end
262
+
263
+ # Convert the input into integer
264
+ #
265
+ # input - the object string
266
+ #
267
+ # Returns the integer value
268
+ def to_integer(input)
269
+ return 1 if input == true
270
+ return 0 if input == false
271
+ input.to_i
247
272
  end
248
273
 
249
274
  # Sort an array of objects
@@ -255,33 +280,21 @@ module Bunto
255
280
  # Returns the filtered array of objects
256
281
  def sort(input, property = nil, nils = "first")
257
282
  if input.nil?
258
- raise ArgumentError.new("Cannot sort a null object.")
283
+ raise ArgumentError, "Cannot sort a null object."
259
284
  end
260
285
  if property.nil?
261
286
  input.sort
262
287
  else
263
- case
264
- when nils == "first"
288
+ if nils == "first"
265
289
  order = - 1
266
- when nils == "last"
290
+ elsif nils == "last"
267
291
  order = + 1
268
292
  else
269
- raise ArgumentError.new("Invalid nils order: " \
270
- "'#{nils}' is not a valid nils order. It must be 'first' or 'last'.")
293
+ raise ArgumentError, "Invalid nils order: " \
294
+ "'#{nils}' is not a valid nils order. It must be 'first' or 'last'."
271
295
  end
272
296
 
273
- input.sort do |apple, orange|
274
- apple_property = item_property(apple, property)
275
- orange_property = item_property(orange, property)
276
-
277
- if !apple_property.nil? && orange_property.nil?
278
- - order
279
- elsif apple_property.nil? && !orange_property.nil?
280
- + order
281
- else
282
- apple_property <=> orange_property
283
- end
284
- end
297
+ sort_input(input, property, order)
285
298
  end
286
299
  end
287
300
 
@@ -332,6 +345,22 @@ module Bunto
332
345
  xml_escape(input.inspect)
333
346
  end
334
347
 
348
+ private
349
+ def sort_input(input, property, order)
350
+ input.sort do |apple, orange|
351
+ apple_property = item_property(apple, property)
352
+ orange_property = item_property(orange, property)
353
+
354
+ if !apple_property.nil? && orange_property.nil?
355
+ - order
356
+ elsif apple_property.nil? && !orange_property.nil?
357
+ + order
358
+ else
359
+ apple_property <=> orange_property
360
+ end
361
+ end
362
+ end
363
+
335
364
  private
336
365
  def time(input)
337
366
  case input
@@ -344,15 +373,17 @@ module Bunto
344
373
  when Numeric
345
374
  Time.at(input)
346
375
  else
347
- Bunto.logger.error "Invalid Date:", "'#{input}' is not a valid datetime."
348
- exit(1)
376
+ raise Errors::InvalidDateError,
377
+ "Invalid Date: '#{input.inspect}' is not a valid datetime."
349
378
  end.localtime
350
379
  end
351
380
 
381
+ private
352
382
  def groupable?(element)
353
383
  element.respond_to?(:group_by)
354
384
  end
355
385
 
386
+ private
356
387
  def item_property(item, property)
357
388
  if item.respond_to?(:to_liquid)
358
389
  item.to_liquid[property.to_s]
@@ -363,6 +394,7 @@ module Bunto
363
394
  end
364
395
  end
365
396
 
397
+ private
366
398
  def as_liquid(item)
367
399
  case item
368
400
  when Hash
@@ -386,6 +418,7 @@ module Bunto
386
418
  end
387
419
 
388
420
  # Parse a string to a Liquid Condition
421
+ private
389
422
  def parse_condition(exp)
390
423
  parser = Liquid::Parser.new(exp)
391
424
  left_expr = parser.expression