liquid 1.9.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/Manifest.txt +0 -31
  2. data/Rakefile +1 -1
  3. data/lib/extras/liquid_view.rb +15 -2
  4. data/lib/liquid.rb +15 -15
  5. data/lib/liquid/block.rb +1 -2
  6. data/lib/liquid/context.rb +89 -99
  7. data/lib/liquid/drop.rb +6 -4
  8. data/lib/liquid/errors.rb +1 -0
  9. data/lib/liquid/standardfilters.rb +56 -11
  10. data/lib/liquid/strainer.rb +1 -1
  11. data/lib/liquid/tags/assign.rb +1 -1
  12. data/lib/liquid/tags/case.rb +2 -2
  13. data/lib/liquid/tags/cycle.rb +3 -4
  14. data/lib/liquid/tags/for.rb +53 -35
  15. data/lib/liquid/tags/if.rb +3 -3
  16. data/lib/liquid/template.rb +8 -7
  17. data/lib/liquid/variable.rb +10 -11
  18. metadata +5 -35
  19. data/example/server/example_servlet.rb +0 -37
  20. data/example/server/liquid_servlet.rb +0 -28
  21. data/example/server/server.rb +0 -12
  22. data/example/server/templates/index.liquid +0 -6
  23. data/example/server/templates/products.liquid +0 -45
  24. data/test/block_test.rb +0 -58
  25. data/test/condition_test.rb +0 -109
  26. data/test/context_test.rb +0 -418
  27. data/test/drop_test.rb +0 -141
  28. data/test/error_handling_test.rb +0 -78
  29. data/test/extra/breakpoint.rb +0 -547
  30. data/test/extra/caller.rb +0 -80
  31. data/test/file_system_test.rb +0 -30
  32. data/test/filter_test.rb +0 -98
  33. data/test/helper.rb +0 -20
  34. data/test/html_tag_test.rb +0 -31
  35. data/test/if_else_test.rb +0 -127
  36. data/test/include_tag_test.rb +0 -114
  37. data/test/module_ex_test.rb +0 -89
  38. data/test/output_test.rb +0 -121
  39. data/test/parsing_quirks_test.rb +0 -29
  40. data/test/regexp_test.rb +0 -40
  41. data/test/security_test.rb +0 -41
  42. data/test/standard_filter_test.rb +0 -126
  43. data/test/standard_tag_test.rb +0 -383
  44. data/test/statements_test.rb +0 -137
  45. data/test/strainer_test.rb +0 -16
  46. data/test/template_test.rb +0 -26
  47. data/test/unless_else_test.rb +0 -27
  48. data/test/variable_test.rb +0 -135
@@ -28,10 +28,12 @@ module Liquid
28
28
  end
29
29
 
30
30
  # called by liquid to invoke a drop
31
- def invoke_drop(method)
32
- result = before_method(method)
33
- result ||= send(method.to_sym) if self.class.public_instance_methods.include?(method.to_s)
34
- result
31
+ def invoke_drop(method)
32
+ if self.class.public_instance_methods.include?(method.to_s)
33
+ send(method.to_sym)
34
+ else
35
+ before_method(method)
36
+ end
35
37
  end
36
38
 
37
39
  def has_key?(name)
@@ -7,4 +7,5 @@ module Liquid
7
7
  class FileSystemError < Error; end
8
8
  class StandardError < Error; end
9
9
  class SyntaxError < Error; end
10
+ class StackLevelError < Error; end
10
11
  end
@@ -63,9 +63,27 @@ module Liquid
63
63
  end
64
64
 
65
65
  # Sort elements of the array
66
- def sort(input)
67
- [input].flatten.sort
66
+ # provide optional property with which to sort an array of hashes or drops
67
+ def sort(input, property = nil)
68
+ ary = [input].flatten
69
+ if property.nil?
70
+ ary.sort
71
+ elsif ary.first.respond_to?('[]') and !ary.first[property].nil?
72
+ ary.sort {|a,b| a[property] <=> b[property] }
73
+ elsif ary.first.respond_to?(property)
74
+ ary.sort {|a,b| a.send(property) <=> b.send(property) }
75
+ end
68
76
  end
77
+
78
+ # map/collect on a given property
79
+ def map(input, property)
80
+ ary = [input].flatten
81
+ if ary.first.respond_to?('[]') and !ary.first[property].nil?
82
+ ary.map {|e| e[property] }
83
+ elsif ary.first.respond_to?(property)
84
+ ary.map {|e| e.send(property) }
85
+ end
86
+ end
69
87
 
70
88
  # Replace occurrences of a string with another
71
89
  def replace(input, string, replacement = '')
@@ -85,7 +103,17 @@ module Liquid
85
103
  # remove the first occurrences of a substring
86
104
  def remove_first(input, string)
87
105
  input.to_s.sub(string, '')
88
- end
106
+ end
107
+
108
+ # add one string to another
109
+ def append(input, string)
110
+ input.to_s + string.to_s
111
+ end
112
+
113
+ # prepend a string to another
114
+ def prepend(input, string)
115
+ string.to_s + input.to_s
116
+ end
89
117
 
90
118
  # Add <br /> tags in front of all newlines in input string
91
119
  def newline_to_br(input)
@@ -126,16 +154,13 @@ module Liquid
126
154
  return input.to_s
127
155
  end
128
156
 
129
- date = case input
130
- when String
131
- Time.parse(input)
132
- when Date, Time, DateTime
133
- input
157
+ date = input.is_a?(String) ? Time.parse(input) : input
158
+
159
+ if date.respond_to?(:strftime)
160
+ date.strftime(format.to_s)
134
161
  else
135
- return input
162
+ input
136
163
  end
137
-
138
- date.strftime(format.to_s)
139
164
  rescue => e
140
165
  input
141
166
  end
@@ -158,6 +183,26 @@ module Liquid
158
183
  array.last if array.respond_to?(:last)
159
184
  end
160
185
 
186
+ # addition
187
+ def plus(input, operand)
188
+ input + operand if input.respond_to?('+')
189
+ end
190
+
191
+ # subtraction
192
+ def minus(input, operand)
193
+ input - operand if input.respond_to?('-')
194
+ end
195
+
196
+ # multiplication
197
+ def times(input, operand)
198
+ input * operand if input.respond_to?('*')
199
+ end
200
+
201
+ # division
202
+ def divided_by(input, operand)
203
+ input / operand if input.respond_to?('/')
204
+ end
205
+
161
206
  end
162
207
 
163
208
  Template.register_filter(StandardFilters)
@@ -34,7 +34,7 @@ module Liquid
34
34
  strainer
35
35
  end
36
36
 
37
- def respond_to?(method)
37
+ def respond_to?(method, include_private = false)
38
38
  method_name = method.to_s
39
39
  return false if method_name =~ INTERNAL_METHOD
40
40
  return false if @@required_methods.include?(method_name)
@@ -9,7 +9,7 @@ module Liquid
9
9
  # {{ monkey }}
10
10
  #
11
11
  class Assign < Tag
12
- Syntax = /(#{VariableSignature}+)\s*=\s*(#{QuotedFragment}+)/
12
+ Syntax = /(#{VariableSignature}+)\s*=\s*(#{Expression}+)/
13
13
 
14
14
  def initialize(tag_name, markup, tokens)
15
15
  if markup =~ Syntax
@@ -1,7 +1,7 @@
1
1
  module Liquid
2
2
  class Case < Block
3
- Syntax = /(#{QuotedFragment})/
4
- WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/
3
+ Syntax = /(#{Expression})/
4
+ WhenSyntax = /(#{Expression})(?:(?:\s+or\s+|\s*\,\s*)(#{Expression}.*))?/
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 = /#{QuotedFragment}/
17
- NamedSyntax = /(#{QuotedFragment})\s*\:\s*(.*)/
16
+ SimpleSyntax = /^#{Expression}/
17
+ NamedSyntax = /^(#{Expression})\s*\:\s*(.*)/
18
18
 
19
19
  def initialize(tag_name, markup, tokens)
20
20
  case markup
@@ -27,7 +27,6 @@ module Liquid
27
27
  else
28
28
  raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
29
29
  end
30
-
31
30
  super
32
31
  end
33
32
 
@@ -49,7 +48,7 @@ module Liquid
49
48
 
50
49
  def variables_from_string(markup)
51
50
  markup.split(',').collect do |var|
52
- var =~ /\s*(#{QuotedFragment})\s*/
51
+ var =~ /\s*(#{Expression})\s*/
53
52
  $1 ? $1 : nil
54
53
  end.compact
55
54
  end
@@ -20,7 +20,9 @@ module Liquid
20
20
  #
21
21
  # {% for item in collection limit:5 offset:10 %}
22
22
  # {{ item.name }}
23
- # {% end %}
23
+ # {% end %}
24
+ #
25
+ # To reverse the for loop simply use {% for item in collection reversed %}
24
26
  #
25
27
  # == Available variables:
26
28
  #
@@ -40,13 +42,14 @@ module Liquid
40
42
  # forloop.last:: Returns true if the item is the last item.
41
43
  #
42
44
  class For < Block
43
- Syntax = /(\w+)\s+in\s+(#{VariableSignature}+)/
45
+ Syntax = /(\w+)\s+in\s+(#{Expression}+)\s*(reversed)?/
44
46
 
45
47
  def initialize(tag_name, markup, tokens)
46
48
  if markup =~ Syntax
47
49
  @variable_name = $1
48
50
  @collection_name = $2
49
- @name = "#{$1}-#{$2}"
51
+ @name = "#{$1}-#{$2}"
52
+ @reversed = $3
50
53
  @attributes = {}
51
54
  markup.scan(TagAttributes) do |key, value|
52
55
  @attributes[key] = value
@@ -64,35 +67,33 @@ module Liquid
64
67
  collection = context[@collection_name]
65
68
  collection = collection.to_a if collection.is_a?(Range)
66
69
 
67
- return '' if collection.nil? or collection.empty?
68
-
69
- range = (0..collection.length)
70
-
71
- if @attributes['limit'] or @attributes['offset']
72
- offset = 0
73
- if @attributes['offset'] == 'continue'
74
- offset = context.registers[:for][@name]
75
- else
76
- offset = context[@attributes['offset']] || 0
77
- end
78
- limit = context[@attributes['limit']]
79
-
80
- range_end = limit ? offset + limit : collection.length
81
- range = (offset..range_end-1)
82
-
83
- # Save the range end in the registers so that future calls to
84
- # offset:continue have something to pick up
85
- context.registers[:for][@name] = range_end
70
+ return '' unless collection.respond_to?(:each)
71
+
72
+ from = if @attributes['offset'] == 'continue'
73
+ context.registers[:for][@name].to_i
74
+ else
75
+ context[@attributes['offset']].to_i
86
76
  end
87
-
88
- result = []
89
- segment = collection[range]
90
- return '' if segment.nil?
77
+
78
+ limit = context[@attributes['limit']]
79
+ to = limit ? limit.to_i + from : nil
80
+
81
+
82
+ segment = slice_collection_using_each(collection, from, to)
83
+
84
+ return '' if segment.empty?
85
+
86
+ segment.reverse! if @reversed
91
87
 
88
+ result = []
89
+
90
+ length = segment.length
91
+
92
+ # Store our progress through the collection for the continue flag
93
+ context.registers[:for][@name] = from + segment.length
94
+
92
95
  context.stack do
93
- length = segment.length
94
-
95
- segment.each_with_index do |item, index|
96
+ segment.each_with_index do |item, index|
96
97
  context[@variable_name] = item
97
98
  context['forloop'] = {
98
99
  'name' => @name,
@@ -103,15 +104,32 @@ module Liquid
103
104
  'rindex0' => length - index -1,
104
105
  'first' => (index == 0),
105
106
  'last' => (index == length - 1) }
106
-
107
+
107
108
  result << render_all(@nodelist, context)
108
109
  end
109
110
  end
110
-
111
- # Store position of last element we rendered. This allows us to do
112
-
113
- result
114
- end
111
+ result
112
+ end
113
+
114
+ def slice_collection_using_each(collection, from, to)
115
+ segments = []
116
+ index = 0
117
+ yielded = 0
118
+ collection.each do |item|
119
+
120
+ if to && to <= index
121
+ break
122
+ end
123
+
124
+ if from <= index
125
+ segments << item
126
+ end
127
+
128
+ index += 1
129
+ end
130
+
131
+ segments
132
+ end
115
133
  end
116
134
 
117
135
  Template.register_tag('for', For)
@@ -13,7 +13,7 @@ module Liquid
13
13
  #
14
14
  class If < Block
15
15
  SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
16
- Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/
16
+ Syntax = /(#{Expression})\s*([=!<>a-z_]+)?\s*(#{Expression})?/
17
17
 
18
18
  def initialize(tag_name, markup, tokens)
19
19
 
@@ -51,14 +51,14 @@ module Liquid
51
51
  else
52
52
 
53
53
  expressions = markup.split(/\b(and|or)\b/).reverse
54
- raise SyntaxHelp unless expressions.shift =~ Syntax
54
+ raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax
55
55
 
56
56
  condition = Condition.new($1, $2, $3)
57
57
 
58
58
  while not expressions.empty?
59
59
  operator = expressions.shift
60
60
 
61
- raise SyntaxHelp unless expressions.shift.to_s =~ Syntax
61
+ raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
62
62
 
63
63
  new_condition = Condition.new($1, $2, $3)
64
64
  new_condition.send(operator.to_sym, condition)
@@ -83,7 +83,7 @@ module Liquid
83
83
  # filters and tags and might be useful to integrate liquid more with its host application
84
84
  #
85
85
  def render(*args)
86
- return '' if @root.nil?
86
+ return '' if @root.nil?
87
87
 
88
88
  context = case args.first
89
89
  when Liquid::Context
@@ -107,17 +107,17 @@ module Liquid
107
107
 
108
108
  if options[:filters]
109
109
  context.add_filters(options[:filters])
110
- end
110
+ end
111
+
111
112
  when Module
112
113
  context.add_filters(args.pop)
113
114
  when Array
114
115
  context.add_filters(args.pop)
115
116
  end
116
-
117
-
118
- # render the nodelist.
119
- # for performance reasons we get a array back here. to_s will make a string out of it
117
+
120
118
  begin
119
+ # render the nodelist.
120
+ # for performance reasons we get a array back here. join will make a string out of it
121
121
  @root.render(context).join
122
122
  ensure
123
123
  @errors = context.errors
@@ -131,7 +131,8 @@ module Liquid
131
131
  private
132
132
 
133
133
  # Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
134
- def tokenize(source)
134
+ def tokenize(source)
135
+ source = source.source if source.respond_to?(:source)
135
136
  return [] if source.to_s.empty?
136
137
  tokens = source.split(TemplateParser)
137
138
 
@@ -1,5 +1,5 @@
1
1
  module Liquid
2
-
2
+
3
3
  # Holds variables. Variables are only loaded "just in time"
4
4
  # and are not evaluated as part of the render stage
5
5
  #
@@ -10,30 +10,29 @@ module Liquid
10
10
  #
11
11
  # {{ user | link }}
12
12
  #
13
- class Variable
13
+ class Variable
14
14
  attr_accessor :filters, :name
15
-
15
+
16
16
  def initialize(markup)
17
- @markup = markup
17
+ @markup = markup
18
18
  @name = nil
19
19
  @filters = []
20
20
  if match = markup.match(/\s*(#{QuotedFragment})/)
21
21
  @name = match[1]
22
- if markup.match(/#{FilterSperator}\s*(.*)/)
23
- filters = Regexp.last_match(1).split(/#{FilterSperator}/)
24
-
22
+ if markup.match(/#{FilterSeparator}\s*(.*)/)
23
+ filters = Regexp.last_match(1).split(/#{FilterSeparator}/)
25
24
  filters.each do |f|
26
25
  if matches = f.match(/\s*(\w+)/)
27
26
  filtername = matches[1]
28
- filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*(#{QuotedFragment})/).flatten
27
+ filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*(#{QuotedFragment})/).flatten
29
28
  @filters << [filtername.to_sym, filterargs]
30
29
  end
31
30
  end
32
31
  end
33
32
  end
34
- end
33
+ end
35
34
 
36
- def render(context)
35
+ def render(context)
37
36
  return '' if @name.nil?
38
37
  output = context[@name]
39
38
  @filters.inject(output) do |output, filter|
@@ -45,7 +44,7 @@ module Liquid
45
44
  rescue FilterNotFound
46
45
  raise FilterNotFound, "Error - filter '#{filter[0]}' in '#{@markup.strip}' could not be found."
47
46
  end
48
- end
47
+ end
49
48
  output
50
49
  end
51
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liquid
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
@@ -9,17 +9,18 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-04 00:00:00 -04:00
12
+ date: 2009-03-10 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hoe
17
+ type: :development
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
20
21
  - - ">="
21
22
  - !ruby/object:Gem::Version
22
- version: 1.5.1
23
+ version: 1.8.2
23
24
  version:
24
25
  description: A secure non evaling end user template engine with aesthetic markup.
25
26
  email: tobi@leetsoft.com
@@ -38,11 +39,6 @@ files:
38
39
  - Manifest.txt
39
40
  - README.txt
40
41
  - Rakefile
41
- - example/server/example_servlet.rb
42
- - example/server/liquid_servlet.rb
43
- - example/server/server.rb
44
- - example/server/templates/index.liquid
45
- - example/server/templates/products.liquid
46
42
  - init.rb
47
43
  - lib/extras/liquid_view.rb
48
44
  - lib/liquid.rb
@@ -71,32 +67,6 @@ files:
71
67
  - lib/liquid/tags/unless.rb
72
68
  - lib/liquid/template.rb
73
69
  - lib/liquid/variable.rb
74
- - test/block_test.rb
75
- - test/condition_test.rb
76
- - test/context_test.rb
77
- - test/drop_test.rb
78
- - test/error_handling_test.rb
79
- - test/extra/breakpoint.rb
80
- - test/extra/caller.rb
81
- - test/file_system_test.rb
82
- - test/filter_test.rb
83
- - test/helper.rb
84
- - test/html_tag_test.rb
85
- - test/if_else_test.rb
86
- - test/include_tag_test.rb
87
- - test/module_ex_test.rb
88
- - test/output_test.rb
89
- - test/parsing_quirks_test.rb
90
- - test/regexp_test.rb
91
- - test/security_test.rb
92
- - test/standard_filter_test.rb
93
- - test/standard_tag_test.rb
94
- - test/statements_test.rb
95
- - test/strainer_test.rb
96
- - test/template_test.rb
97
- - test/test_helper.rb
98
- - test/unless_else_test.rb
99
- - test/variable_test.rb
100
70
  has_rdoc: true
101
71
  homepage: http://www.liquidmarkup.org
102
72
  post_install_message:
@@ -120,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
90
  requirements: []
121
91
 
122
92
  rubyforge_project: liquid
123
- rubygems_version: 1.1.0
93
+ rubygems_version: 1.3.1
124
94
  signing_key:
125
95
  specification_version: 2
126
96
  summary: A secure non evaling end user template engine with aesthetic markup.