liquid 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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