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.
- data/CHANGELOG +10 -6
- data/Rakefile +27 -12
- data/lib/extras/liquid_view.rb +27 -16
- data/lib/liquid.rb +3 -3
- data/lib/liquid/block.rb +30 -26
- data/lib/liquid/condition.rb +31 -34
- data/lib/liquid/context.rb +47 -25
- data/lib/liquid/document.rb +7 -7
- data/lib/liquid/drop.rb +17 -16
- data/lib/liquid/htmltags.rb +27 -27
- data/lib/liquid/module_ex.rb +4 -4
- data/lib/liquid/standardfilters.rb +18 -5
- data/lib/liquid/strainer.rb +17 -18
- data/lib/liquid/tag.rb +8 -8
- data/lib/liquid/tags/assign.rb +1 -1
- data/lib/liquid/tags/capture.rb +9 -9
- data/lib/liquid/tags/case.rb +2 -2
- data/lib/liquid/tags/cycle.rb +3 -3
- data/lib/liquid/tags/for.rb +1 -1
- data/lib/liquid/tags/if.rb +3 -2
- data/lib/liquid/tags/include.rb +2 -1
- data/lib/liquid/template.rb +57 -54
- data/lib/liquid/variable.rb +7 -8
- metadata +25 -21
- data/init.rb +0 -8
- data/test/test_helper.rb +0 -20
data/lib/liquid/tags/for.rb
CHANGED
@@ -42,7 +42,7 @@ module Liquid
|
|
42
42
|
# forloop.last:: Returns true if the item is the last item.
|
43
43
|
#
|
44
44
|
class For < Block
|
45
|
-
Syntax = /(\w+)\s+in\s+(#{
|
45
|
+
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/
|
46
46
|
|
47
47
|
def initialize(tag_name, markup, tokens)
|
48
48
|
if markup =~ Syntax
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -13,7 +13,8 @@ module Liquid
|
|
13
13
|
#
|
14
14
|
class If < Block
|
15
15
|
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
|
16
|
-
Syntax = /(#{
|
16
|
+
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/
|
17
|
+
ExpressionsAndOperators = /(?:and|or|(?:\s*(?!\b(?:and|or)\b)(?:#{QuotedFragment}|\S+)\s*)+)/
|
17
18
|
|
18
19
|
def initialize(tag_name, markup, tokens)
|
19
20
|
|
@@ -50,7 +51,7 @@ module Liquid
|
|
50
51
|
ElseCondition.new
|
51
52
|
else
|
52
53
|
|
53
|
-
expressions = markup.
|
54
|
+
expressions = markup.scan(ExpressionsAndOperators).reverse
|
54
55
|
raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax
|
55
56
|
|
56
57
|
condition = Condition.new($1, $2, $3)
|
data/lib/liquid/tags/include.rb
CHANGED
@@ -24,7 +24,8 @@ module Liquid
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def render(context)
|
27
|
-
|
27
|
+
file_system = context.registers[:file_system] || Liquid::Template.file_system
|
28
|
+
source = file_system.read_template_file(context[@template_name])
|
28
29
|
partial = Liquid::Template.parse(source)
|
29
30
|
|
30
31
|
variable = context[@variable_name || @template_name[1..-2]]
|
data/lib/liquid/template.rb
CHANGED
@@ -1,120 +1,123 @@
|
|
1
1
|
module Liquid
|
2
2
|
|
3
|
-
# Templates are central to liquid.
|
4
|
-
# Interpretating templates is a two step process. First you compile the
|
5
|
-
# source code you got. During compile time some extensive error checking is performed.
|
6
|
-
# your code should expect to get some SyntaxErrors.
|
3
|
+
# Templates are central to liquid.
|
4
|
+
# Interpretating templates is a two step process. First you compile the
|
5
|
+
# source code you got. During compile time some extensive error checking is performed.
|
6
|
+
# your code should expect to get some SyntaxErrors.
|
7
7
|
#
|
8
|
-
# After you have a compiled template you can then <tt>render</tt> it.
|
9
|
-
# You can use a compiled template over and over again and keep it cached.
|
8
|
+
# After you have a compiled template you can then <tt>render</tt> it.
|
9
|
+
# You can use a compiled template over and over again and keep it cached.
|
10
|
+
#
|
11
|
+
# Example:
|
10
12
|
#
|
11
|
-
# Example:
|
12
|
-
#
|
13
13
|
# template = Liquid::Template.parse(source)
|
14
14
|
# template.render('user_name' => 'bob')
|
15
15
|
#
|
16
16
|
class Template
|
17
17
|
attr_accessor :root
|
18
18
|
@@file_system = BlankFileSystem.new
|
19
|
-
|
20
|
-
class <<self
|
19
|
+
|
20
|
+
class << self
|
21
21
|
def file_system
|
22
22
|
@@file_system
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def file_system=(obj)
|
26
26
|
@@file_system = obj
|
27
27
|
end
|
28
|
-
|
29
|
-
def register_tag(name, klass)
|
28
|
+
|
29
|
+
def register_tag(name, klass)
|
30
30
|
tags[name.to_s] = klass
|
31
|
-
end
|
32
|
-
|
31
|
+
end
|
32
|
+
|
33
33
|
def tags
|
34
34
|
@tags ||= {}
|
35
35
|
end
|
36
|
-
|
37
|
-
# Pass a module with filter methods which should be available
|
36
|
+
|
37
|
+
# Pass a module with filter methods which should be available
|
38
38
|
# to all liquid views. Good for registering the standard library
|
39
|
-
def register_filter(mod)
|
39
|
+
def register_filter(mod)
|
40
40
|
Strainer.global_filter(mod)
|
41
|
-
end
|
42
|
-
|
41
|
+
end
|
42
|
+
|
43
43
|
# creates a new <tt>Template</tt> object from liquid source code
|
44
44
|
def parse(source)
|
45
45
|
template = Template.new
|
46
46
|
template.parse(source)
|
47
47
|
template
|
48
|
-
end
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
# creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
|
52
52
|
def initialize
|
53
53
|
end
|
54
|
-
|
55
|
-
# Parse source code.
|
56
|
-
# Returns self for easy chaining
|
54
|
+
|
55
|
+
# Parse source code.
|
56
|
+
# Returns self for easy chaining
|
57
57
|
def parse(source)
|
58
58
|
@root = Document.new(tokenize(source))
|
59
59
|
self
|
60
60
|
end
|
61
|
-
|
62
|
-
def registers
|
61
|
+
|
62
|
+
def registers
|
63
63
|
@registers ||= {}
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
def assigns
|
67
67
|
@assigns ||= {}
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
|
+
def instance_assigns
|
71
|
+
@instance_assigns ||= {}
|
72
|
+
end
|
73
|
+
|
70
74
|
def errors
|
71
75
|
@errors ||= []
|
72
76
|
end
|
73
|
-
|
77
|
+
|
74
78
|
# Render takes a hash with local variables.
|
75
79
|
#
|
76
|
-
# if you use the same filters over and over again consider registering them globally
|
80
|
+
# if you use the same filters over and over again consider registering them globally
|
77
81
|
# with <tt>Template.register_filter</tt>
|
78
|
-
#
|
82
|
+
#
|
79
83
|
# Following options can be passed:
|
80
|
-
#
|
84
|
+
#
|
81
85
|
# * <tt>filters</tt> : array with local filters
|
82
|
-
# * <tt>registers</tt> : hash with register variables. Those can be accessed from
|
83
|
-
# filters and tags and might be useful to integrate liquid more with its host application
|
86
|
+
# * <tt>registers</tt> : hash with register variables. Those can be accessed from
|
87
|
+
# filters and tags and might be useful to integrate liquid more with its host application
|
84
88
|
#
|
85
89
|
def render(*args)
|
86
|
-
return '' if @root.nil?
|
87
|
-
|
90
|
+
return '' if @root.nil?
|
91
|
+
|
88
92
|
context = case args.first
|
89
93
|
when Liquid::Context
|
90
94
|
args.shift
|
91
95
|
when Hash
|
92
|
-
|
93
|
-
Context.new(assigns, registers, @rethrow_errors)
|
96
|
+
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors)
|
94
97
|
when nil
|
95
|
-
Context.new(assigns, registers, @rethrow_errors)
|
98
|
+
Context.new(assigns, instance_assigns, registers, @rethrow_errors)
|
96
99
|
else
|
97
100
|
raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
|
98
101
|
end
|
99
|
-
|
102
|
+
|
100
103
|
case args.last
|
101
104
|
when Hash
|
102
105
|
options = args.pop
|
103
|
-
|
106
|
+
|
104
107
|
if options[:registers].is_a?(Hash)
|
105
|
-
self.registers.merge!(options[:registers])
|
108
|
+
self.registers.merge!(options[:registers])
|
106
109
|
end
|
107
110
|
|
108
111
|
if options[:filters]
|
109
112
|
context.add_filters(options[:filters])
|
110
|
-
end
|
111
|
-
|
113
|
+
end
|
114
|
+
|
112
115
|
when Module
|
113
|
-
context.add_filters(args.pop)
|
116
|
+
context.add_filters(args.pop)
|
114
117
|
when Array
|
115
|
-
context.add_filters(args.pop)
|
118
|
+
context.add_filters(args.pop)
|
116
119
|
end
|
117
|
-
|
120
|
+
|
118
121
|
begin
|
119
122
|
# render the nodelist.
|
120
123
|
# for performance reasons we get a array back here. join will make a string out of it
|
@@ -123,24 +126,24 @@ module Liquid
|
|
123
126
|
@errors = context.errors
|
124
127
|
end
|
125
128
|
end
|
126
|
-
|
129
|
+
|
127
130
|
def render!(*args)
|
128
131
|
@rethrow_errors = true; render(*args)
|
129
132
|
end
|
130
|
-
|
133
|
+
|
131
134
|
private
|
132
|
-
|
135
|
+
|
133
136
|
# Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
|
134
137
|
def tokenize(source)
|
135
|
-
source = source.source if source.respond_to?(:source)
|
138
|
+
source = source.source if source.respond_to?(:source)
|
136
139
|
return [] if source.to_s.empty?
|
137
140
|
tokens = source.split(TemplateParser)
|
138
141
|
|
139
142
|
# removes the rogue empty element at the beginning of the array
|
140
|
-
tokens.shift if tokens[0] and tokens[0].empty?
|
143
|
+
tokens.shift if tokens[0] and tokens[0].empty?
|
141
144
|
|
142
145
|
tokens
|
143
146
|
end
|
144
|
-
|
145
|
-
end
|
147
|
+
|
148
|
+
end
|
146
149
|
end
|
data/lib/liquid/variable.rb
CHANGED
@@ -11,17 +11,18 @@ module Liquid
|
|
11
11
|
# {{ user | link }}
|
12
12
|
#
|
13
13
|
class Variable
|
14
|
+
FilterParser = /(?:#{FilterSeparator}|(?:\s*(?!(?:#{FilterSeparator}))(?:#{QuotedFragment}|\S+)\s*)+)/
|
14
15
|
attr_accessor :filters, :name
|
15
16
|
|
16
17
|
def initialize(markup)
|
17
18
|
@markup = markup
|
18
19
|
@name = nil
|
19
20
|
@filters = []
|
20
|
-
if match = markup.match(/\s*(#{QuotedFragment})/)
|
21
|
+
if match = markup.match(/\s*(#{QuotedFragment})(.*)/)
|
21
22
|
@name = match[1]
|
22
|
-
if
|
23
|
-
filters = Regexp.last_match(1).
|
24
|
-
filters.each do |f|
|
23
|
+
if match[2].match(/#{FilterSeparator}\s*(.*)/)
|
24
|
+
filters = Regexp.last_match(1).scan(FilterParser)
|
25
|
+
filters.each do |f|
|
25
26
|
if matches = f.match(/\s*(\w+)/)
|
26
27
|
filtername = matches[1]
|
27
28
|
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*(#{QuotedFragment})/).flatten
|
@@ -34,8 +35,7 @@ module Liquid
|
|
34
35
|
|
35
36
|
def render(context)
|
36
37
|
return '' if @name.nil?
|
37
|
-
|
38
|
-
@filters.inject(output) do |output, filter|
|
38
|
+
@filters.inject(context[@name]) do |output, filter|
|
39
39
|
filterargs = filter[1].to_a.collect do |a|
|
40
40
|
context[a]
|
41
41
|
end
|
@@ -45,7 +45,6 @@ module Liquid
|
|
45
45
|
raise FilterNotFound, "Error - filter '#{filter[0]}' in '#{@markup.strip}' could not be found."
|
46
46
|
end
|
47
47
|
end
|
48
|
-
output
|
49
48
|
end
|
50
49
|
end
|
51
|
-
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liquid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 11
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 2.1.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Tobias Luetke
|
@@ -9,20 +15,11 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2009-
|
18
|
+
date: 2009-04-13 00:00:00 -04:00
|
13
19
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
type: :development
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.8.2
|
24
|
-
version:
|
25
|
-
description: A secure non evaling end user template engine with aesthetic markup.
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A secure, non-evaling end user template engine with aesthetic markup.
|
26
23
|
email: tobi@leetsoft.com
|
27
24
|
executables: []
|
28
25
|
|
@@ -39,7 +36,6 @@ files:
|
|
39
36
|
- Manifest.txt
|
40
37
|
- README.txt
|
41
38
|
- Rakefile
|
42
|
-
- init.rb
|
43
39
|
- lib/extras/liquid_view.rb
|
44
40
|
- lib/liquid.rb
|
45
41
|
- lib/liquid/block.rb
|
@@ -69,6 +65,8 @@ files:
|
|
69
65
|
- lib/liquid/variable.rb
|
70
66
|
has_rdoc: true
|
71
67
|
homepage: http://www.liquidmarkup.org
|
68
|
+
licenses: []
|
69
|
+
|
72
70
|
post_install_message:
|
73
71
|
rdoc_options:
|
74
72
|
- --main
|
@@ -76,23 +74,29 @@ rdoc_options:
|
|
76
74
|
require_paths:
|
77
75
|
- lib
|
78
76
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
79
78
|
requirements:
|
80
79
|
- - ">="
|
81
80
|
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
82
84
|
version: "0"
|
83
|
-
version:
|
84
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
85
87
|
requirements:
|
86
88
|
- - ">="
|
87
89
|
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
88
93
|
version: "0"
|
89
|
-
version:
|
90
94
|
requirements: []
|
91
95
|
|
92
96
|
rubyforge_project: liquid
|
93
|
-
rubygems_version: 1.3.
|
97
|
+
rubygems_version: 1.3.7
|
94
98
|
signing_key:
|
95
99
|
specification_version: 2
|
96
|
-
summary: A secure non
|
97
|
-
test_files:
|
98
|
-
|
100
|
+
summary: A secure, non-evaling end user template engine with aesthetic markup.
|
101
|
+
test_files: []
|
102
|
+
|
data/init.rb
DELETED
data/test/test_helper.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra')
|
3
|
-
|
4
|
-
require 'test/unit'
|
5
|
-
require 'test/unit/assertions'
|
6
|
-
require 'caller'
|
7
|
-
require 'breakpoint'
|
8
|
-
require File.dirname(__FILE__) + '/../lib/liquid'
|
9
|
-
|
10
|
-
|
11
|
-
module Test
|
12
|
-
module Unit
|
13
|
-
module Assertions
|
14
|
-
include Liquid
|
15
|
-
def assert_template_result(expected, template, assigns={}, message=nil)
|
16
|
-
assert_equal expected, Template.parse(template).render(assigns)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|