wordify_liquid 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.md +75 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +44 -0
  4. data/lib/extras/liquid_view.rb +51 -0
  5. data/lib/liquid.rb +68 -0
  6. data/lib/liquid/block.rb +115 -0
  7. data/lib/liquid/condition.rb +120 -0
  8. data/lib/liquid/context.rb +259 -0
  9. data/lib/liquid/document.rb +17 -0
  10. data/lib/liquid/drop.rb +61 -0
  11. data/lib/liquid/errors.rb +11 -0
  12. data/lib/liquid/extensions.rb +62 -0
  13. data/lib/liquid/file_system.rb +62 -0
  14. data/lib/liquid/htmltags.rb +74 -0
  15. data/lib/liquid/interrupts.rb +17 -0
  16. data/lib/liquid/module_ex.rb +62 -0
  17. data/lib/liquid/standardfilters.rb +245 -0
  18. data/lib/liquid/strainer.rb +53 -0
  19. data/lib/liquid/tag.rb +26 -0
  20. data/lib/liquid/tags/assign.rb +33 -0
  21. data/lib/liquid/tags/break.rb +21 -0
  22. data/lib/liquid/tags/capture.rb +35 -0
  23. data/lib/liquid/tags/case.rb +79 -0
  24. data/lib/liquid/tags/comment.rb +9 -0
  25. data/lib/liquid/tags/continue.rb +21 -0
  26. data/lib/liquid/tags/cycle.rb +59 -0
  27. data/lib/liquid/tags/decrement.rb +39 -0
  28. data/lib/liquid/tags/for.rb +142 -0
  29. data/lib/liquid/tags/if.rb +79 -0
  30. data/lib/liquid/tags/ifchanged.rb +20 -0
  31. data/lib/liquid/tags/include.rb +65 -0
  32. data/lib/liquid/tags/increment.rb +35 -0
  33. data/lib/liquid/tags/raw.rb +21 -0
  34. data/lib/liquid/tags/unless.rb +33 -0
  35. data/lib/liquid/template.rb +150 -0
  36. data/lib/liquid/utils.rb +31 -0
  37. data/lib/liquid/variable.rb +57 -0
  38. data/lib/wordify_liquid.rb +1 -0
  39. data/test/liquid/assign_test.rb +21 -0
  40. data/test/liquid/block_test.rb +58 -0
  41. data/test/liquid/capture_test.rb +40 -0
  42. data/test/liquid/condition_test.rb +127 -0
  43. data/test/liquid/context_test.rb +478 -0
  44. data/test/liquid/drop_test.rb +169 -0
  45. data/test/liquid/error_handling_test.rb +81 -0
  46. data/test/liquid/file_system_test.rb +29 -0
  47. data/test/liquid/filter_test.rb +125 -0
  48. data/test/liquid/module_ex_test.rb +87 -0
  49. data/test/liquid/output_test.rb +116 -0
  50. data/test/liquid/parsing_quirks_test.rb +52 -0
  51. data/test/liquid/regexp_test.rb +44 -0
  52. data/test/liquid/security_test.rb +64 -0
  53. data/test/liquid/standard_filter_test.rb +195 -0
  54. data/test/liquid/strainer_test.rb +52 -0
  55. data/test/liquid/tags/break_tag_test.rb +16 -0
  56. data/test/liquid/tags/continue_tag_test.rb +16 -0
  57. data/test/liquid/tags/for_tag_test.rb +284 -0
  58. data/test/liquid/tags/html_tag_test.rb +63 -0
  59. data/test/liquid/tags/if_else_tag_test.rb +160 -0
  60. data/test/liquid/tags/include_tag_test.rb +139 -0
  61. data/test/liquid/tags/increment_tag_test.rb +24 -0
  62. data/test/liquid/tags/raw_tag_test.rb +15 -0
  63. data/test/liquid/tags/standard_tag_test.rb +295 -0
  64. data/test/liquid/tags/statements_test.rb +134 -0
  65. data/test/liquid/tags/unless_else_tag_test.rb +26 -0
  66. data/test/liquid/template_test.rb +74 -0
  67. data/test/liquid/variable_test.rb +180 -0
  68. data/test/test_helper.rb +29 -0
  69. metadata +145 -0
data/lib/liquid/tag.rb ADDED
@@ -0,0 +1,26 @@
1
+ module Liquid
2
+
3
+ class Tag
4
+
5
+ attr_accessor :nodelist
6
+
7
+ def initialize(tag_name, markup, tokens)
8
+ @tag_name = tag_name
9
+ @markup = markup
10
+ parse(tokens)
11
+ end
12
+
13
+ def parse(tokens)
14
+ end
15
+
16
+ def name
17
+ self.class.name.downcase
18
+ end
19
+
20
+ def render(context)
21
+ ''
22
+ end
23
+
24
+ end # Tag
25
+
26
+ end # Tag
@@ -0,0 +1,33 @@
1
+ module Liquid
2
+
3
+ # Assign sets a variable in your template.
4
+ #
5
+ # {% assign foo = 'monkey' %}
6
+ #
7
+ # You can then use the variable later in the page.
8
+ #
9
+ # {{ foo }}
10
+ #
11
+ class Assign < Tag
12
+ Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/o
13
+
14
+ def initialize(tag_name, markup, tokens)
15
+ if markup =~ Syntax
16
+ @to = $1
17
+ @from = Variable.new($2)
18
+ else
19
+ raise SyntaxError.new("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]")
20
+ end
21
+
22
+ super
23
+ end
24
+
25
+ def render(context)
26
+ context.scopes.last[@to] = @from.render(context)
27
+ ''
28
+ end
29
+
30
+ end
31
+
32
+ Template.register_tag('assign', Assign)
33
+ end
@@ -0,0 +1,21 @@
1
+ module Liquid
2
+
3
+ # Break tag to be used to break out of a for loop.
4
+ #
5
+ # == Basic Usage:
6
+ # {% for item in collection %}
7
+ # {% if item.condition %}
8
+ # {% break %}
9
+ # {% endif %}
10
+ # {% endfor %}
11
+ #
12
+ class Break < Tag
13
+
14
+ def interrupt
15
+ BreakInterrupt.new
16
+ end
17
+
18
+ end
19
+
20
+ Template.register_tag('break', Break)
21
+ end
@@ -0,0 +1,35 @@
1
+ module Liquid
2
+
3
+ # Capture stores the result of a block into a variable without rendering it inplace.
4
+ #
5
+ # {% capture heading %}
6
+ # Monkeys!
7
+ # {% endcapture %}
8
+ # ...
9
+ # <h1>{{ heading }}</h1>
10
+ #
11
+ # Capture is useful for saving content for use later in your template, such as
12
+ # in a sidebar or footer.
13
+ #
14
+ class Capture < Block
15
+ Syntax = /(\w+)/
16
+
17
+ def initialize(tag_name, markup, tokens)
18
+ if markup =~ Syntax
19
+ @to = $1
20
+ else
21
+ raise SyntaxError.new("Syntax Error in 'capture' - Valid syntax: capture [var]")
22
+ end
23
+
24
+ super
25
+ end
26
+
27
+ def render(context)
28
+ output = super
29
+ context.scopes.last[@to] = output
30
+ ''
31
+ end
32
+ end
33
+
34
+ Template.register_tag('capture', Capture)
35
+ end
@@ -0,0 +1,79 @@
1
+ module Liquid
2
+ class Case < Block
3
+ Syntax = /(#{QuotedFragment})/o
4
+ WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/o
5
+
6
+ def initialize(tag_name, markup, tokens)
7
+ @blocks = []
8
+
9
+ if markup =~ Syntax
10
+ @left = $1
11
+ else
12
+ raise SyntaxError.new("Syntax Error in tag 'case' - Valid syntax: case [condition]")
13
+ end
14
+
15
+ super
16
+ end
17
+
18
+ def unknown_tag(tag, markup, tokens)
19
+ @nodelist = []
20
+ case tag
21
+ when 'when'
22
+ record_when_condition(markup)
23
+ when 'else'
24
+ record_else_condition(markup)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def render(context)
31
+ context.stack do
32
+ execute_else_block = true
33
+
34
+ output = ''
35
+ @blocks.each do |block|
36
+ if block.else?
37
+ return render_all(block.attachment, context) if execute_else_block
38
+ elsif block.evaluate(context)
39
+ execute_else_block = false
40
+ output << render_all(block.attachment, context)
41
+ end
42
+ end
43
+ output
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def record_when_condition(markup)
50
+ while markup
51
+ # Create a new nodelist and assign it to the new block
52
+ if not markup =~ WhenSyntax
53
+ raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ")
54
+ end
55
+
56
+ markup = $2
57
+
58
+ block = Condition.new(@left, '==', $1)
59
+ block.attach(@nodelist)
60
+ @blocks.push(block)
61
+ end
62
+ end
63
+
64
+ def record_else_condition(markup)
65
+
66
+ if not markup.strip.empty?
67
+ raise SyntaxError.new("Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) ")
68
+ end
69
+
70
+ block = ElseCondition.new
71
+ block.attach(@nodelist)
72
+ @blocks << block
73
+ end
74
+
75
+
76
+ end
77
+
78
+ Template.register_tag('case', Case)
79
+ end
@@ -0,0 +1,9 @@
1
+ module Liquid
2
+ class Comment < Block
3
+ def render(context)
4
+ ''
5
+ end
6
+ end
7
+
8
+ Template.register_tag('comment', Comment)
9
+ end
@@ -0,0 +1,21 @@
1
+ module Liquid
2
+
3
+ # Continue tag to be used to break out of a for loop.
4
+ #
5
+ # == Basic Usage:
6
+ # {% for item in collection %}
7
+ # {% if item.condition %}
8
+ # {% continue %}
9
+ # {% endif %}
10
+ # {% endfor %}
11
+ #
12
+ class Continue < Tag
13
+
14
+ def interrupt
15
+ ContinueInterrupt.new
16
+ end
17
+
18
+ end
19
+
20
+ Template.register_tag('continue', Continue)
21
+ end
@@ -0,0 +1,59 @@
1
+ module Liquid
2
+
3
+ # Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
4
+ #
5
+ # {% for item in items %}
6
+ # <div class="{% cycle 'red', 'green', 'blue' %}"> {{ item }} </div>
7
+ # {% end %}
8
+ #
9
+ # <div class="red"> Item one </div>
10
+ # <div class="green"> Item two </div>
11
+ # <div class="blue"> Item three </div>
12
+ # <div class="red"> Item four </div>
13
+ # <div class="green"> Item five</div>
14
+ #
15
+ class Cycle < Tag
16
+ SimpleSyntax = /^#{QuotedFragment}+/o
17
+ NamedSyntax = /^(#{QuotedFragment})\s*\:\s*(.*)/o
18
+
19
+ def initialize(tag_name, markup, tokens)
20
+ case markup
21
+ when NamedSyntax
22
+ @variables = variables_from_string($2)
23
+ @name = $1
24
+ when SimpleSyntax
25
+ @variables = variables_from_string(markup)
26
+ @name = "'#{@variables.to_s}'"
27
+ else
28
+ raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
29
+ end
30
+ super
31
+ end
32
+
33
+ def render(context)
34
+ context.registers[:cycle] ||= Hash.new(0)
35
+
36
+ context.stack do
37
+ key = context[@name]
38
+ iteration = context.registers[:cycle][key]
39
+ result = context[@variables[iteration]]
40
+ iteration += 1
41
+ iteration = 0 if iteration >= @variables.size
42
+ context.registers[:cycle][key] = iteration
43
+ result
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def variables_from_string(markup)
50
+ markup.split(',').collect do |var|
51
+ var =~ /\s*(#{QuotedFragment})\s*/o
52
+ $1 ? $1 : nil
53
+ end.compact
54
+ end
55
+
56
+ end
57
+
58
+ Template.register_tag('cycle', Cycle)
59
+ end
@@ -0,0 +1,39 @@
1
+ module Liquid
2
+
3
+ # decrement is used in a place where one needs to insert a counter
4
+ # into a template, and needs the counter to survive across
5
+ # multiple instantiations of the template.
6
+ # NOTE: decrement is a pre-decrement, --i,
7
+ # while increment is post: i++.
8
+ #
9
+ # (To achieve the survival, the application must keep the context)
10
+ #
11
+ # if the variable does not exist, it is created with value 0.
12
+
13
+ # Hello: {% decrement variable %}
14
+ #
15
+ # gives you:
16
+ #
17
+ # Hello: -1
18
+ # Hello: -2
19
+ # Hello: -3
20
+ #
21
+ class Decrement < Tag
22
+ def initialize(tag_name, markup, tokens)
23
+ @variable = markup.strip
24
+
25
+ super
26
+ end
27
+
28
+ def render(context)
29
+ value = context.environments.first[@variable] ||= 0
30
+ value = value - 1
31
+ context.environments.first[@variable] = value
32
+ value.to_s
33
+ end
34
+
35
+ private
36
+ end
37
+
38
+ Template.register_tag('decrement', Decrement)
39
+ end
@@ -0,0 +1,142 @@
1
+ module Liquid
2
+
3
+ # "For" iterates over an array or collection.
4
+ # Several useful variables are available to you within the loop.
5
+ #
6
+ # == Basic usage:
7
+ # {% for item in collection %}
8
+ # {{ forloop.index }}: {{ item.name }}
9
+ # {% endfor %}
10
+ #
11
+ # == Advanced usage:
12
+ # {% for item in collection %}
13
+ # <div {% if forloop.first %}class="first"{% endif %}>
14
+ # Item {{ forloop.index }}: {{ item.name }}
15
+ # </div>
16
+ # {% else %}
17
+ # There is nothing in the collection.
18
+ # {% endfor %}
19
+ #
20
+ # You can also define a limit and offset much like SQL. Remember
21
+ # that offset starts at 0 for the first item.
22
+ #
23
+ # {% for item in collection limit:5 offset:10 %}
24
+ # {{ item.name }}
25
+ # {% end %}
26
+ #
27
+ # To reverse the for loop simply use {% for item in collection reversed %}
28
+ #
29
+ # == Available variables:
30
+ #
31
+ # forloop.name:: 'item-collection'
32
+ # forloop.length:: Length of the loop
33
+ # forloop.index:: The current item's position in the collection;
34
+ # forloop.index starts at 1.
35
+ # This is helpful for non-programmers who start believe
36
+ # the first item in an array is 1, not 0.
37
+ # forloop.index0:: The current item's position in the collection
38
+ # where the first item is 0
39
+ # forloop.rindex:: Number of items remaining in the loop
40
+ # (length - index) where 1 is the last item.
41
+ # forloop.rindex0:: Number of items remaining in the loop
42
+ # where 0 is the last item.
43
+ # forloop.first:: Returns true if the item is the first item.
44
+ # forloop.last:: Returns true if the item is the last item.
45
+ #
46
+ class For < Block
47
+ Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
48
+
49
+ def initialize(tag_name, markup, tokens)
50
+ if markup =~ Syntax
51
+ @variable_name = $1
52
+ @collection_name = $2
53
+ @name = "#{$1}-#{$2}"
54
+ @reversed = $3
55
+ @attributes = {}
56
+ markup.scan(TagAttributes) do |key, value|
57
+ @attributes[key] = value
58
+ end
59
+ else
60
+ raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]")
61
+ end
62
+
63
+ @nodelist = @for_block = []
64
+ super
65
+ end
66
+
67
+ def unknown_tag(tag, markup, tokens)
68
+ return super unless tag == 'else'
69
+ @nodelist = @else_block = []
70
+ end
71
+
72
+ def render(context)
73
+ context.registers[:for] ||= Hash.new(0)
74
+
75
+ collection = context[@collection_name]
76
+ collection = collection.to_a if collection.is_a?(Range)
77
+
78
+ # Maintains Ruby 1.8.7 String#each behaviour on 1.9
79
+ return render_else(context) unless iterable?(collection)
80
+
81
+ from = if @attributes['offset'] == 'continue'
82
+ context.registers[:for][@name].to_i
83
+ else
84
+ context[@attributes['offset']].to_i
85
+ end
86
+
87
+ limit = context[@attributes['limit']]
88
+ to = limit ? limit.to_i + from : nil
89
+
90
+
91
+ segment = Utils.slice_collection_using_each(collection, from, to)
92
+
93
+ return render_else(context) if segment.empty?
94
+
95
+ segment.reverse! if @reversed
96
+
97
+ result = ''
98
+
99
+ length = segment.length
100
+
101
+ # Store our progress through the collection for the continue flag
102
+ context.registers[:for][@name] = from + segment.length
103
+
104
+ context.stack do
105
+ segment.each_with_index do |item, index|
106
+ context[@variable_name] = item
107
+ context['forloop'] = {
108
+ 'name' => @name,
109
+ 'length' => length,
110
+ 'index' => index + 1,
111
+ 'index0' => index,
112
+ 'rindex' => length - index,
113
+ 'rindex0' => length - index - 1,
114
+ 'first' => (index == 0),
115
+ 'last' => (index == length - 1) }
116
+
117
+ result << render_all(@for_block, context)
118
+
119
+ # Handle any interrupts if they exist.
120
+ if context.has_interrupt?
121
+ interrupt = context.pop_interrupt
122
+ break if interrupt.is_a? BreakInterrupt
123
+ next if interrupt.is_a? ContinueInterrupt
124
+ end
125
+ end
126
+ end
127
+ result
128
+ end
129
+
130
+ private
131
+
132
+ def render_else(context)
133
+ return @else_block ? [render_all(@else_block, context)] : ''
134
+ end
135
+
136
+ def iterable?(collection)
137
+ collection.respond_to?(:each) || Utils.non_blank_string?(collection)
138
+ end
139
+ end
140
+
141
+ Template.register_tag('for', For)
142
+ end