wordify_liquid 2.5.1

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.
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