liquid 2.0.0 → 2.1.0

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.
@@ -1,17 +1,17 @@
1
1
  module Liquid
2
- class Document < Block
2
+ class Document < Block
3
3
  # we don't need markup to open this block
4
4
  def initialize(tokens)
5
5
  parse(tokens)
6
- end
7
-
8
- # There isn't a real delimter
6
+ end
7
+
8
+ # There isn't a real delimter
9
9
  def block_delimiter
10
10
  []
11
11
  end
12
-
12
+
13
13
  # Document blocks don't need to be terminated since they are not actually opened
14
14
  def assert_missing_delimitation!
15
- end
15
+ end
16
16
  end
17
- end
17
+ end
data/lib/liquid/drop.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  module Liquid
2
-
2
+
3
3
  # A drop in liquid is a class which allows you to to export DOM like things to liquid
4
- # Methods of drops are callable.
5
- # The main use for liquid drops is the implement lazy loaded objects.
6
- # If you would like to make data available to the web designers which you don't want loaded unless needed then
4
+ # Methods of drops are callable.
5
+ # The main use for liquid drops is the implement lazy loaded objects.
6
+ # If you would like to make data available to the web designers which you don't want loaded unless needed then
7
7
  # a drop is a great way to do that
8
8
  #
9
9
  # Example:
@@ -13,38 +13,39 @@ module Liquid
13
13
  # Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
14
14
  # end
15
15
  # end
16
- #
16
+ #
17
17
  # tmpl = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {%endfor%} ' )
18
- # tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query.
18
+ # tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query.
19
19
  #
20
- # Your drop can either implement the methods sans any parameters or implement the before_method(name) method which is a
20
+ # Your drop can either implement the methods sans any parameters or implement the before_method(name) method which is a
21
21
  # catch all
22
22
  class Drop
23
23
  attr_writer :context
24
24
 
25
- # Catch all for the method
25
+ # Catch all for the method
26
26
  def before_method(method)
27
27
  nil
28
28
  end
29
-
29
+
30
30
  # called by liquid to invoke a drop
31
- def invoke_drop(method)
32
- if self.class.public_instance_methods.include?(method.to_s)
33
- send(method.to_sym)
34
- else
31
+ def invoke_drop(method)
32
+ # for backward compatibility with Ruby 1.8
33
+ methods = self.class.public_instance_methods.map { |m| m.to_s }
34
+ if methods.include?(method.to_s)
35
+ send(method.to_sym)
36
+ else
35
37
  before_method(method)
36
38
  end
37
39
  end
38
-
40
+
39
41
  def has_key?(name)
40
42
  true
41
43
  end
42
-
44
+
43
45
  def to_liquid
44
46
  self
45
47
  end
46
48
 
47
49
  alias :[] :invoke_drop
48
50
  end
49
-
50
51
  end
@@ -1,7 +1,7 @@
1
1
  module Liquid
2
- class TableRow < Block
3
- Syntax = /(\w+)\s+in\s+(#{VariableSignature}+)/
4
-
2
+ class TableRow < Block
3
+ Syntax = /(\w+)\s+in\s+(#{VariableSignature}+)/
4
+
5
5
  def initialize(tag_name, markup, tokens)
6
6
  if markup =~ Syntax
7
7
  @variable_name = $1
@@ -13,62 +13,62 @@ module Liquid
13
13
  else
14
14
  raise SyntaxError.new("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3")
15
15
  end
16
-
17
- super
16
+
17
+ super
18
18
  end
19
-
20
- def render(context)
19
+
20
+ def render(context)
21
21
  collection = context[@collection_name] or return ''
22
-
22
+
23
23
  if @attributes['limit'] or @attributes['offset']
24
24
  limit = context[@attributes['limit']] || -1
25
25
  offset = context[@attributes['offset']] || 0
26
26
  collection = collection[offset.to_i..(limit.to_i + offset.to_i - 1)]
27
27
  end
28
-
28
+
29
29
  length = collection.length
30
-
30
+
31
31
  cols = context[@attributes['cols']].to_i
32
32
 
33
33
  row = 1
34
34
  col = 0
35
35
 
36
36
  result = ["<tr class=\"row1\">\n"]
37
- context.stack do
37
+ context.stack do
38
38
 
39
39
  collection.each_with_index do |item, index|
40
40
  context[@variable_name] = item
41
41
  context['tablerowloop'] = {
42
42
  'length' => length,
43
- 'index' => index + 1,
44
- 'index0' => index,
45
- 'col' => col + 1,
46
- 'col0' => col,
47
- 'index0' => index,
43
+ 'index' => index + 1,
44
+ 'index0' => index,
45
+ 'col' => col + 1,
46
+ 'col0' => col,
47
+ 'index0' => index,
48
48
  'rindex' => length - index,
49
49
  'rindex0' => length - index -1,
50
50
  'first' => (index == 0),
51
51
  'last' => (index == length - 1),
52
52
  'col_first' => (col == 0),
53
53
  'col_last' => (col == cols - 1)
54
- }
55
-
56
-
54
+ }
55
+
56
+
57
57
  col += 1
58
-
58
+
59
59
  result << ["<td class=\"col#{col}\">"] + render_all(@nodelist, context) + ['</td>']
60
60
 
61
- if col == cols and not (index == length - 1)
61
+ if col == cols and not (index == length - 1)
62
62
  col = 0
63
63
  row += 1
64
- result << ["</tr>\n<tr class=\"row#{row}\">"]
64
+ result << ["</tr>\n<tr class=\"row#{row}\">"]
65
65
  end
66
-
66
+
67
67
  end
68
68
  end
69
69
  result + ["</tr>\n"]
70
- end
70
+ end
71
71
  end
72
-
73
- Template.register_tag('tablerow', TableRow)
74
- end
72
+
73
+ Template.register_tag('tablerow', TableRow)
74
+ end
@@ -18,7 +18,7 @@
18
18
  # end
19
19
  # end
20
20
  #
21
- # if you want to extend the drop to other methods you can defines more methods
21
+ # if you want to extend the drop to other methods you can defines more methods
22
22
  # in the class <YourClass>::LiquidDropClass
23
23
  #
24
24
  # class SomeClass::LiquidDropClass
@@ -37,11 +37,11 @@
37
37
  # output:
38
38
  # 'this comes from an allowed method and this from another allowed method'
39
39
  #
40
- # You can also chain associations, by adding the liquid_method call in the
40
+ # You can also chain associations, by adding the liquid_method call in the
41
41
  # association models.
42
42
  #
43
43
  class Module
44
-
44
+
45
45
  def liquid_methods(*allowed_methods)
46
46
  drop_class = eval "class #{self.to_s}::LiquidDropClass < Liquid::Drop; self; end"
47
47
  define_method :to_liquid do
@@ -58,5 +58,5 @@ class Module
58
58
  end
59
59
  end
60
60
  end
61
-
61
+
62
62
  end
@@ -48,7 +48,7 @@ module Liquid
48
48
  end
49
49
 
50
50
  def strip_html(input)
51
- input.to_s.gsub(/<.*?>/, '')
51
+ input.to_s.gsub(/<script.*?<\/script>/, '').gsub(/<.*?>/, '')
52
52
  end
53
53
 
54
54
  # Remove all newlines from the string
@@ -185,22 +185,35 @@ module Liquid
185
185
 
186
186
  # addition
187
187
  def plus(input, operand)
188
- input + operand if input.respond_to?('+')
188
+ to_number(input) + to_number(operand)
189
189
  end
190
190
 
191
191
  # subtraction
192
192
  def minus(input, operand)
193
- input - operand if input.respond_to?('-')
193
+ to_number(input) - to_number(operand)
194
194
  end
195
195
 
196
196
  # multiplication
197
197
  def times(input, operand)
198
- input * operand if input.respond_to?('*')
198
+ to_number(input) * to_number(operand)
199
199
  end
200
200
 
201
201
  # division
202
202
  def divided_by(input, operand)
203
- input / operand if input.respond_to?('/')
203
+ to_number(input) / to_number(operand)
204
+ end
205
+
206
+ private
207
+
208
+ def to_number(obj)
209
+ case obj
210
+ when Numeric
211
+ obj
212
+ when String
213
+ (obj.strip =~ /^\d+\.\d+$/) ? obj.to_f : obj.to_i
214
+ else
215
+ 0
216
+ end
204
217
  end
205
218
 
206
219
  end
@@ -1,52 +1,51 @@
1
1
  require 'set'
2
2
 
3
3
  module Liquid
4
-
5
-
4
+
6
5
  parent_object = if defined? BlankObject
7
6
  BlankObject
8
7
  else
9
8
  Object
10
9
  end
11
10
 
12
- # Strainer is the parent class for the filters system.
13
- # New filters are mixed into the strainer class which is then instanciated for each liquid template render run.
11
+ # Strainer is the parent class for the filters system.
12
+ # New filters are mixed into the strainer class which is then instanciated for each liquid template render run.
14
13
  #
15
- # One of the strainer's responsibilities is to keep malicious method calls out
14
+ # One of the strainer's responsibilities is to keep malicious method calls out
16
15
  class Strainer < parent_object #:nodoc:
17
- INTERNAL_METHOD = /^__/
18
- @@required_methods = Set.new([:__send__, :__id__, :respond_to?, :extend, :methods, :class])
19
-
16
+ INTERNAL_METHOD = /^__/
17
+ @@required_methods = Set.new([:__id__, :__send__, :respond_to?, :extend, :methods, :class, :object_id])
18
+
20
19
  @@filters = {}
21
-
20
+
22
21
  def initialize(context)
23
22
  @context = context
24
23
  end
25
-
24
+
26
25
  def self.global_filter(filter)
27
26
  raise ArgumentError, "Passed filter is not a module" unless filter.is_a?(Module)
28
27
  @@filters[filter.name] = filter
29
28
  end
30
-
29
+
31
30
  def self.create(context)
32
31
  strainer = Strainer.new(context)
33
32
  @@filters.each { |k,m| strainer.extend(m) }
34
33
  strainer
35
34
  end
36
-
35
+
37
36
  def respond_to?(method, include_private = false)
38
37
  method_name = method.to_s
39
38
  return false if method_name =~ INTERNAL_METHOD
40
39
  return false if @@required_methods.include?(method_name)
41
40
  super
42
41
  end
43
-
44
- # remove all standard methods from the bucket so circumvent security
45
- # problems
46
- instance_methods.each do |m|
47
- unless @@required_methods.include?(m.to_sym)
42
+
43
+ # remove all standard methods from the bucket so circumvent security
44
+ # problems
45
+ instance_methods.each do |m|
46
+ unless @@required_methods.include?(m.to_sym)
48
47
  undef_method m
49
48
  end
50
- end
49
+ end
51
50
  end
52
51
  end
data/lib/liquid/tag.rb CHANGED
@@ -1,26 +1,26 @@
1
1
  module Liquid
2
-
2
+
3
3
  class Tag
4
4
  attr_accessor :nodelist
5
-
5
+
6
6
  def initialize(tag_name, markup, tokens)
7
7
  @tag_name = tag_name
8
8
  @markup = markup
9
9
  parse(tokens)
10
10
  end
11
-
11
+
12
12
  def parse(tokens)
13
13
  end
14
-
14
+
15
15
  def name
16
16
  self.class.name.downcase
17
17
  end
18
-
18
+
19
19
  def render(context)
20
20
  ''
21
- end
21
+ end
22
22
  end
23
-
23
+
24
24
 
25
25
  end
26
-
26
+
@@ -9,7 +9,7 @@ module Liquid
9
9
  # {{ monkey }}
10
10
  #
11
11
  class Assign < Tag
12
- Syntax = /(#{VariableSignature}+)\s*=\s*(#{Expression}+)/
12
+ Syntax = /(#{VariableSignature}+)\s*=\s*(#{QuotedFragment}+)/
13
13
 
14
14
  def initialize(tag_name, markup, tokens)
15
15
  if markup =~ Syntax
@@ -1,5 +1,5 @@
1
1
  module Liquid
2
-
2
+
3
3
  # Capture stores the result of a block into a variable without rendering it inplace.
4
4
  #
5
5
  # {% capture heading %}
@@ -8,28 +8,28 @@ module Liquid
8
8
  # ...
9
9
  # <h1>{{ monkeys }}</h1>
10
10
  #
11
- # Capture is useful for saving content for use later in your template, such as
11
+ # Capture is useful for saving content for use later in your template, such as
12
12
  # in a sidebar or footer.
13
13
  #
14
14
  class Capture < Block
15
15
  Syntax = /(\w+)/
16
16
 
17
- def initialize(tag_name, markup, tokens)
17
+ def initialize(tag_name, markup, tokens)
18
18
  if markup =~ Syntax
19
19
  @to = $1
20
20
  else
21
21
  raise SyntaxError.new("Syntax Error in 'capture' - Valid syntax: capture [var]")
22
22
  end
23
-
24
- super
23
+
24
+ super
25
25
  end
26
26
 
27
27
  def render(context)
28
28
  output = super
29
- context[@to] = output.to_s
29
+ context[@to] = output.join
30
30
  ''
31
31
  end
32
- end
33
-
32
+ end
33
+
34
34
  Template.register_tag('capture', Capture)
35
- end
35
+ end
@@ -1,7 +1,7 @@
1
1
  module Liquid
2
2
  class Case < Block
3
- Syntax = /(#{Expression})/
4
- WhenSyntax = /(#{Expression})(?:(?:\s+or\s+|\s*\,\s*)(#{Expression}.*))?/
3
+ Syntax = /(#{QuotedFragment})/
4
+ WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/
5
5
 
6
6
  def initialize(tag_name, markup, tokens)
7
7
  @blocks = []
@@ -13,8 +13,8 @@ module Liquid
13
13
  # <div class="green"> Item five</div>
14
14
  #
15
15
  class Cycle < Tag
16
- SimpleSyntax = /^#{Expression}/
17
- NamedSyntax = /^(#{Expression})\s*\:\s*(.*)/
16
+ SimpleSyntax = /^#{QuotedFragment}+/
17
+ NamedSyntax = /^(#{QuotedFragment})\s*\:\s*(.*)/
18
18
 
19
19
  def initialize(tag_name, markup, tokens)
20
20
  case markup
@@ -48,7 +48,7 @@ module Liquid
48
48
 
49
49
  def variables_from_string(markup)
50
50
  markup.split(',').collect do |var|
51
- var =~ /\s*(#{Expression})\s*/
51
+ var =~ /\s*(#{QuotedFragment})\s*/
52
52
  $1 ? $1 : nil
53
53
  end.compact
54
54
  end