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
@@ -0,0 +1,74 @@
1
+ module Liquid
2
+ class TableRow < Block
3
+ Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
4
+
5
+ def initialize(tag_name, markup, tokens)
6
+ if markup =~ Syntax
7
+ @variable_name = $1
8
+ @collection_name = $2
9
+ @attributes = {}
10
+ markup.scan(TagAttributes) do |key, value|
11
+ @attributes[key] = value
12
+ end
13
+ else
14
+ raise SyntaxError.new("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3")
15
+ end
16
+
17
+ super
18
+ end
19
+
20
+ def render(context)
21
+ collection = context[@collection_name] or return ''
22
+
23
+ from = @attributes['offset'] ? context[@attributes['offset']].to_i : 0
24
+ to = @attributes['limit'] ? from + context[@attributes['limit']].to_i : nil
25
+
26
+ collection = Utils.slice_collection_using_each(collection, from, to)
27
+
28
+ length = collection.length
29
+
30
+ cols = context[@attributes['cols']].to_i
31
+
32
+ row = 1
33
+ col = 0
34
+
35
+ result = "<tr class=\"row1\">\n"
36
+ context.stack do
37
+
38
+ collection.each_with_index do |item, index|
39
+ context[@variable_name] = item
40
+ context['tablerowloop'] = {
41
+ 'length' => length,
42
+ 'index' => index + 1,
43
+ 'index0' => index,
44
+ 'col' => col + 1,
45
+ 'col0' => col,
46
+ 'index0' => index,
47
+ 'rindex' => length - index,
48
+ 'rindex0' => length - index - 1,
49
+ 'first' => (index == 0),
50
+ 'last' => (index == length - 1),
51
+ 'col_first' => (col == 0),
52
+ 'col_last' => (col == cols - 1)
53
+ }
54
+
55
+
56
+ col += 1
57
+
58
+ result << "<td class=\"col#{col}\">" << render_all(@nodelist, context) << '</td>'
59
+
60
+ if col == cols and not (index == length - 1)
61
+ col = 0
62
+ row += 1
63
+ result << "</tr>\n<tr class=\"row#{row}\">"
64
+ end
65
+
66
+ end
67
+ end
68
+ result << "</tr>\n"
69
+ result
70
+ end
71
+ end
72
+
73
+ Template.register_tag('tablerow', TableRow)
74
+ end
@@ -0,0 +1,17 @@
1
+ module Liquid
2
+
3
+ # An interrupt is any command that breaks processing of a block (ex: a for loop).
4
+ class Interrupt
5
+ attr_reader :message
6
+
7
+ def initialize(message=nil)
8
+ @message = message || "interrupt"
9
+ end
10
+ end
11
+
12
+ # Interrupt that is thrown whenever a {% break %} is called.
13
+ class BreakInterrupt < Interrupt; end
14
+
15
+ # Interrupt that is thrown whenever a {% continue %} is called.
16
+ class ContinueInterrupt < Interrupt; end
17
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright 2007 by Domizio Demichelis
2
+ # This library is free software. It may be used, redistributed and/or modified
3
+ # under the same terms as Ruby itself
4
+ #
5
+ # This extension is usesd in order to expose the object of the implementing class
6
+ # to liquid as it were a Drop. It also limits the liquid-callable methods of the instance
7
+ # to the allowed method passed with the liquid_methods call
8
+ # Example:
9
+ #
10
+ # class SomeClass
11
+ # liquid_methods :an_allowed_method
12
+ #
13
+ # def an_allowed_method
14
+ # 'this comes from an allowed method'
15
+ # end
16
+ # def unallowed_method
17
+ # 'this will never be an output'
18
+ # end
19
+ # end
20
+ #
21
+ # if you want to extend the drop to other methods you can defines more methods
22
+ # in the class <YourClass>::LiquidDropClass
23
+ #
24
+ # class SomeClass::LiquidDropClass
25
+ # def another_allowed_method
26
+ # 'and this from another allowed method'
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # usage:
32
+ # @something = SomeClass.new
33
+ #
34
+ # template:
35
+ # {{something.an_allowed_method}}{{something.unallowed_method}} {{something.another_allowed_method}}
36
+ #
37
+ # output:
38
+ # 'this comes from an allowed method and this from another allowed method'
39
+ #
40
+ # You can also chain associations, by adding the liquid_method call in the
41
+ # association models.
42
+ #
43
+ class Module
44
+
45
+ def liquid_methods(*allowed_methods)
46
+ drop_class = eval "class #{self.to_s}::LiquidDropClass < Liquid::Drop; self; end"
47
+ define_method :to_liquid do
48
+ drop_class.new(self)
49
+ end
50
+ drop_class.class_eval do
51
+ def initialize(object)
52
+ @object = object
53
+ end
54
+ allowed_methods.each do |sym|
55
+ define_method sym do
56
+ @object.send sym
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,245 @@
1
+ require 'cgi'
2
+
3
+ module Liquid
4
+
5
+ module StandardFilters
6
+
7
+ # Return the size of an array or of an string
8
+ def size(input)
9
+
10
+ input.respond_to?(:size) ? input.size : 0
11
+ end
12
+
13
+ # convert a input string to DOWNCASE
14
+ def downcase(input)
15
+ input.to_s.downcase
16
+ end
17
+
18
+ # convert a input string to UPCASE
19
+ def upcase(input)
20
+ input.to_s.upcase
21
+ end
22
+
23
+ # capitalize words in the input centence
24
+ def capitalize(input)
25
+ input.to_s.capitalize
26
+ end
27
+
28
+ def escape(input)
29
+ CGI.escapeHTML(input) rescue input
30
+ end
31
+
32
+ def escape_once(input)
33
+ ActionView::Helpers::TagHelper.escape_once(input)
34
+ rescue NameError
35
+ input
36
+ end
37
+
38
+ alias_method :h, :escape
39
+
40
+ # Truncate a string down to x characters
41
+ def truncate(input, length = 50, truncate_string = "...")
42
+ if input.nil? then return end
43
+ l = length.to_i - truncate_string.length
44
+ l = 0 if l < 0
45
+ input.length > length.to_i ? input[0...l] + truncate_string : input
46
+ end
47
+
48
+ def truncatewords(input, words = 15, truncate_string = " ...")
49
+ if input.nil? then return end
50
+ wordlist = input.to_s.split
51
+ l = words.to_i - 1
52
+ l = 0 if l < 0
53
+ wordlist.length > l ? wordlist[0..l].join(" ") + truncate_string : input
54
+ end
55
+
56
+ # Split input string into an array of substrings separated by given pattern.
57
+ #
58
+ # Example:
59
+ # <div class="summary">{{ post | split '//' | first }}</div>
60
+ #
61
+ def split(input, pattern)
62
+ input.split(pattern)
63
+ end
64
+
65
+ def strip_html(input)
66
+ input.to_s.gsub(/<script.*?<\/script>/, '').gsub(/<!--.*?-->/, '').gsub(/<.*?>/, '')
67
+ end
68
+
69
+ # Remove all newlines from the string
70
+ def strip_newlines(input)
71
+ input.to_s.gsub(/\n/, '')
72
+ end
73
+
74
+
75
+ # Join elements of the array with certain character between them
76
+ def join(input, glue = ' ')
77
+ [input].flatten.join(glue)
78
+ end
79
+
80
+ # Sort elements of the array
81
+ # provide optional property with which to sort an array of hashes or drops
82
+ def sort(input, property = nil)
83
+ ary = [input].flatten
84
+ if property.nil?
85
+ ary.sort
86
+ elsif ary.first.respond_to?('[]') and !ary.first[property].nil?
87
+ ary.sort {|a,b| a[property] <=> b[property] }
88
+ elsif ary.first.respond_to?(property)
89
+ ary.sort {|a,b| a.send(property) <=> b.send(property) }
90
+ end
91
+ end
92
+
93
+ # map/collect on a given property
94
+ def map(input, property)
95
+ ary = [input].flatten
96
+ if ary.first.respond_to?('[]') and !ary.first[property].nil?
97
+ ary.map {|e| e[property] }
98
+ elsif ary.first.respond_to?(property)
99
+ ary.map {|e| e.send(property) }
100
+ end
101
+ end
102
+
103
+ # Replace occurrences of a string with another
104
+ def replace(input, string, replacement = '')
105
+ input.to_s.gsub(string, replacement)
106
+ end
107
+
108
+ # Replace the first occurrences of a string with another
109
+ def replace_first(input, string, replacement = '')
110
+ input.to_s.sub(string, replacement)
111
+ end
112
+
113
+ # remove a substring
114
+ def remove(input, string)
115
+ input.to_s.gsub(string, '')
116
+ end
117
+
118
+ # remove the first occurrences of a substring
119
+ def remove_first(input, string)
120
+ input.to_s.sub(string, '')
121
+ end
122
+
123
+ # add one string to another
124
+ def append(input, string)
125
+ input.to_s + string.to_s
126
+ end
127
+
128
+ # prepend a string to another
129
+ def prepend(input, string)
130
+ string.to_s + input.to_s
131
+ end
132
+
133
+ # Add <br /> tags in front of all newlines in input string
134
+ def newline_to_br(input)
135
+ input.to_s.gsub(/\n/, "<br />\n")
136
+ end
137
+
138
+ # Reformat a date
139
+ #
140
+ # %a - The abbreviated weekday name (``Sun'')
141
+ # %A - The full weekday name (``Sunday'')
142
+ # %b - The abbreviated month name (``Jan'')
143
+ # %B - The full month name (``January'')
144
+ # %c - The preferred local date and time representation
145
+ # %d - Day of the month (01..31)
146
+ # %H - Hour of the day, 24-hour clock (00..23)
147
+ # %I - Hour of the day, 12-hour clock (01..12)
148
+ # %j - Day of the year (001..366)
149
+ # %m - Month of the year (01..12)
150
+ # %M - Minute of the hour (00..59)
151
+ # %p - Meridian indicator (``AM'' or ``PM'')
152
+ # %S - Second of the minute (00..60)
153
+ # %U - Week number of the current year,
154
+ # starting with the first Sunday as the first
155
+ # day of the first week (00..53)
156
+ # %W - Week number of the current year,
157
+ # starting with the first Monday as the first
158
+ # day of the first week (00..53)
159
+ # %w - Day of the week (Sunday is 0, 0..6)
160
+ # %x - Preferred representation for the date alone, no time
161
+ # %X - Preferred representation for the time alone, no date
162
+ # %y - Year without a century (00..99)
163
+ # %Y - Year with century
164
+ # %Z - Time zone name
165
+ # %% - Literal ``%'' character
166
+ def date(input, format)
167
+
168
+ if format.to_s.empty?
169
+ return input.to_s
170
+ end
171
+
172
+ if ((input.is_a?(String) && !/^\d+$/.match(input.to_s).nil?) || input.is_a?(Integer)) && input.to_i > 0
173
+ input = Time.at(input.to_i)
174
+ end
175
+
176
+ date = input.is_a?(String) ? Time.parse(input) : input
177
+
178
+ if date.respond_to?(:strftime)
179
+ date.strftime(format.to_s)
180
+ else
181
+ input
182
+ end
183
+ rescue => e
184
+ input
185
+ end
186
+
187
+ # Get the first element of the passed in array
188
+ #
189
+ # Example:
190
+ # {{ product.images | first | to_img }}
191
+ #
192
+ def first(array)
193
+ array.first if array.respond_to?(:first)
194
+ end
195
+
196
+ # Get the last element of the passed in array
197
+ #
198
+ # Example:
199
+ # {{ product.images | last | to_img }}
200
+ #
201
+ def last(array)
202
+ array.last if array.respond_to?(:last)
203
+ end
204
+
205
+ # addition
206
+ def plus(input, operand)
207
+ to_number(input) + to_number(operand)
208
+ end
209
+
210
+ # subtraction
211
+ def minus(input, operand)
212
+ to_number(input) - to_number(operand)
213
+ end
214
+
215
+ # multiplication
216
+ def times(input, operand)
217
+ to_number(input) * to_number(operand)
218
+ end
219
+
220
+ # division
221
+ def divided_by(input, operand)
222
+ to_number(input) / to_number(operand)
223
+ end
224
+
225
+ def modulo(input, operand)
226
+ to_number(input) % to_number(operand)
227
+ end
228
+
229
+ private
230
+
231
+ def to_number(obj)
232
+ case obj
233
+ when Numeric
234
+ obj
235
+ when String
236
+ (obj.strip =~ /^\d+\.\d+$/) ? obj.to_f : obj.to_i
237
+ else
238
+ 0
239
+ end
240
+ end
241
+
242
+ end
243
+
244
+ Template.register_filter(StandardFilters)
245
+ end
@@ -0,0 +1,53 @@
1
+ require 'set'
2
+
3
+ module Liquid
4
+
5
+ # Strainer is the parent class for the filters system.
6
+ # New filters are mixed into the strainer class which is then instantiated for each liquid template render run.
7
+ #
8
+ # The Strainer only allows method calls defined in filters given to it via Strainer.global_filter,
9
+ # Context#add_filters or Template.register_filter
10
+ class Strainer #:nodoc:
11
+ @@filters = {}
12
+ @@known_filters = Set.new
13
+ @@known_methods = Set.new
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def self.global_filter(filter)
20
+ raise ArgumentError, "Passed filter is not a module" unless filter.is_a?(Module)
21
+ add_known_filter(filter)
22
+ @@filters[filter.name] = filter
23
+ end
24
+
25
+ def self.add_known_filter(filter)
26
+ unless @@known_filters.include?(filter)
27
+ @@method_blacklist ||= Set.new(Strainer.instance_methods.map(&:to_s))
28
+ new_methods = filter.instance_methods.map(&:to_s)
29
+ new_methods.reject!{ |m| @@method_blacklist.include?(m) }
30
+ @@known_methods.merge(new_methods)
31
+ @@known_filters.add(filter)
32
+ end
33
+ end
34
+
35
+ def self.create(context)
36
+ strainer = Strainer.new(context)
37
+ @@filters.each { |k,m| strainer.extend(m) }
38
+ strainer
39
+ end
40
+
41
+ def invoke(method, *args)
42
+ if invokable?(method)
43
+ send(method, *args)
44
+ else
45
+ args.first
46
+ end
47
+ end
48
+
49
+ def invokable?(method)
50
+ @@known_methods.include?(method.to_s) && respond_to?(method)
51
+ end
52
+ end
53
+ end