liquidoc 0.12.0.pre.rc5 → 0.12.0.pre.rc6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40a1c127ce84efe07e6762641c2cc16d8248770cf8c8b2e65f5e1ae299ac5fa4
4
- data.tar.gz: 35436583f8eb40766990bc1740ef60541160c7d2c4f67b1c71277e1f6f653d68
3
+ metadata.gz: 8d01d4d6d0f2b4c6fb1c6cd9bbfff037d33db88674076835dfaa343df194d940
4
+ data.tar.gz: f3b7943d004fce1442644844bfb99ab7e94a54574ba4d6b4a4644ba1f14e14f4
5
5
  SHA512:
6
- metadata.gz: 0ad1a76573b551921a54b4595a79621fbbef203f4506882ac30baa3fc71fb40a8a735981340e1f7c70755fb9f660a1aca71ebe4a04fcff56325fc7adbd62c0ee
7
- data.tar.gz: 60072de6a7cd07e61dcbf73c43d88d6d816c0509400247c0ba2326a0f4d6eb80c4ad9084563ac34cfad71b4bbf9a0eab2433af7f28aa4ba8fd7afca5fe67dd2f
6
+ metadata.gz: 80e1b66595ecdf7b91b99759e355cb2053769c4ffa5f61d7380894dafa3e64009b8266299d8b8f84dbace1382423c28a7f617e8d1f2bb269c1d4084c7cf1d6dc
7
+ data.tar.gz: 5b90303b75f33fc389c8328a268b53168bc7e2f5afd4dbb1b8c339db468eaed73e0a8c7eda8900addb6d2429dffd1916596926d7bd2d6b353922982b18c1b523
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Filters
5
+ module DateFilters
6
+ # Format a date in short format e.g. "27 Jan 2011".
7
+ # Ordinal format is also supported, in both the UK
8
+ # (e.g. "27th Jan 2011") and US ("e.g. Jan 27th, 2011") formats.
9
+ # UK format is the default.
10
+ #
11
+ # date - the Time to format.
12
+ # type - if "ordinal" the returned String will be in ordinal format
13
+ # style - if "US" the returned String will be in US format.
14
+ # Otherwise it will be in UK format.
15
+ #
16
+ # Returns the formatting String.
17
+ def date_to_string(date, type = nil, style = nil)
18
+ stringify_date(date, "%b", type, style)
19
+ end
20
+
21
+ # Format a date in long format e.g. "27 January 2011".
22
+ # Ordinal format is also supported, in both the UK
23
+ # (e.g. "27th January 2011") and US ("e.g. January 27th, 2011") formats.
24
+ # UK format is the default.
25
+ #
26
+ # date - the Time to format.
27
+ # type - if "ordinal" the returned String will be in ordinal format
28
+ # style - if "US" the returned String will be in US format.
29
+ # Otherwise it will be in UK format.
30
+ #
31
+ # Returns the formatted String.
32
+ def date_to_long_string(date, type = nil, style = nil)
33
+ stringify_date(date, "%B", type, style)
34
+ end
35
+
36
+ # Format a date for use in XML.
37
+ #
38
+ # date - The Time to format.
39
+ #
40
+ # Examples
41
+ #
42
+ # date_to_xmlschema(Time.now)
43
+ # # => "2011-04-24T20:34:46+08:00"
44
+ #
45
+ # Returns the formatted String.
46
+ def date_to_xmlschema(date)
47
+ return date if date.to_s.empty?
48
+ time(date).xmlschema
49
+ end
50
+
51
+ # Format a date according to RFC-822
52
+ #
53
+ # date - The Time to format.
54
+ #
55
+ # Examples
56
+ #
57
+ # date_to_rfc822(Time.now)
58
+ # # => "Sun, 24 Apr 2011 12:34:46 +0000"
59
+ #
60
+ # Returns the formatted String.
61
+ def date_to_rfc822(date)
62
+ return date if date.to_s.empty?
63
+ time(date).rfc822
64
+ end
65
+
66
+ private
67
+ # month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B")
68
+ # type: nil (default) or "ordinal"
69
+ # style: nil (default) or "US"
70
+ #
71
+ # Returns a stringified date or the empty input.
72
+ def stringify_date(date, month_type, type = nil, style = nil)
73
+ return date if date.to_s.empty?
74
+ time = time(date)
75
+ if type == "ordinal"
76
+ day = time.day
77
+ ordinal_day = "#{day}#{ordinal(day)}"
78
+ return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US"
79
+ return time.strftime("#{ordinal_day} #{month_type} %Y")
80
+ end
81
+ time.strftime("%d #{month_type} %Y")
82
+ end
83
+
84
+ private
85
+ def ordinal(number)
86
+ return "th" if (11..13).cover?(number)
87
+
88
+ case number % 10
89
+ when 1 then "st"
90
+ when 2 then "nd"
91
+ when 3 then "rd"
92
+ else "th"
93
+ end
94
+ end
95
+
96
+ private
97
+ def time(input)
98
+ date = Liquid::Utils.to_date(input)
99
+ unless date.respond_to?(:to_time)
100
+ raise Errors::InvalidDateError,
101
+ "Invalid Date: '#{input.inspect}' is not a valid datetime."
102
+ end
103
+ date.to_time.dup.localtime
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Filters
5
+ module GroupingFilters
6
+ # Group an array of items by a property
7
+ #
8
+ # input - the inputted Enumerable
9
+ # property - the property
10
+ #
11
+ # Returns an array of Hashes, each looking something like this:
12
+ # {"name" => "larry"
13
+ # "items" => [...] } # all the items where `property` == "larry"
14
+ def group_by(input, property)
15
+ if groupable?(input)
16
+ groups = input.group_by { |item| item_property(item, property).to_s }
17
+ grouped_array(groups)
18
+ else
19
+ input
20
+ end
21
+ end
22
+
23
+ # Group an array of items by an expression
24
+ #
25
+ # input - the object array
26
+ # variable - the variable to assign each item to in the expression
27
+ # expression -a Liquid comparison expression passed in as a string
28
+ #
29
+ # Returns the filtered array of objects
30
+ def group_by_exp(input, variable, expression)
31
+ return input unless groupable?(input)
32
+
33
+ parsed_expr = parse_expression(expression)
34
+ @context.stack do
35
+ groups = input.group_by do |item|
36
+ @context[variable] = item
37
+ parsed_expr.render(@context)
38
+ end
39
+ grouped_array(groups)
40
+ end
41
+ end
42
+
43
+ private
44
+ def parse_expression(str)
45
+ Liquid::Variable.new(str, Liquid::ParseContext.new)
46
+ end
47
+
48
+ private
49
+ def groupable?(element)
50
+ element.respond_to?(:group_by)
51
+ end
52
+
53
+ private
54
+ def grouped_array(groups)
55
+ groups.each_with_object([]) do |item, array|
56
+ array << {
57
+ "name" => item.first,
58
+ "items" => item.last,
59
+ "size" => item.last.size,
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,488 @@
1
+ # These Liquid Filters are from the Jekyll project.
2
+ # They were copied here from Jekyll 4.0.0.pre.alpha1 source
3
+ # Modifications mostly consist of removals
4
+ # Would prefer keeping this in sync by using only select filters from a jekyll
5
+ # dependency gem, but I was unable to implement at this time. See
6
+ # ‘Forked’ at commit:
7
+ # https://github.com/jekyll/jekyll/tree/551014eb05f0c3eed3c8196b6d1e04e7ae433679
8
+
9
+ module Jekyll
10
+ module GroupingFilters
11
+ # Group an array of items by a property
12
+ #
13
+ # input - the inputted Enumerable
14
+ # property - the property
15
+ #
16
+ # Returns an array of Hashes, each looking something like this:
17
+ # {"name" => "larry"
18
+ # "items" => [...] } # all the items where `property` == "larry"
19
+ def group_by(input, property)
20
+ if groupable?(input)
21
+ groups = input.group_by { |item| item_property(item, property).to_s }
22
+ grouped_array(groups)
23
+ else
24
+ input
25
+ end
26
+ end
27
+
28
+ # Group an array of items by an expression
29
+ #
30
+ # input - the object array
31
+ # variable - the variable to assign each item to in the expression
32
+ # expression -a Liquid comparison expression passed in as a string
33
+ #
34
+ # Returns the filtered array of objects
35
+ def group_by_exp(input, variable, expression)
36
+ return input unless groupable?(input)
37
+
38
+ parsed_expr = parse_expression(expression)
39
+ @context.stack do
40
+ groups = input.group_by do |item|
41
+ @context[variable] = item
42
+ parsed_expr.render(@context)
43
+ end
44
+ grouped_array(groups)
45
+ end
46
+ end
47
+
48
+ private
49
+ def parse_expression(str)
50
+ Liquid::Variable.new(str, Liquid::ParseContext.new)
51
+ end
52
+
53
+ private
54
+ def groupable?(element)
55
+ element.respond_to?(:group_by)
56
+ end
57
+
58
+ private
59
+ def grouped_array(groups)
60
+ groups.each_with_object([]) do |item, array|
61
+ array << {
62
+ "name" => item.first,
63
+ "items" => item.last,
64
+ "size" => item.last.size,
65
+ }
66
+ end
67
+ end
68
+ end
69
+
70
+ module DateFilters
71
+ # Format a date in short format e.g. "27 Jan 2011".
72
+ # Ordinal format is also supported, in both the UK
73
+ # (e.g. "27th Jan 2011") and US ("e.g. Jan 27th, 2011") formats.
74
+ # UK format is the default.
75
+ #
76
+ # date - the Time to format.
77
+ # type - if "ordinal" the returned String will be in ordinal format
78
+ # style - if "US" the returned String will be in US format.
79
+ # Otherwise it will be in UK format.
80
+ #
81
+ # Returns the formatting String.
82
+ def date_to_string(date, type = nil, style = nil)
83
+ stringify_date(date, "%b", type, style)
84
+ end
85
+
86
+ # Format a date in long format e.g. "27 January 2011".
87
+ # Ordinal format is also supported, in both the UK
88
+ # (e.g. "27th January 2011") and US ("e.g. January 27th, 2011") formats.
89
+ # UK format is the default.
90
+ #
91
+ # date - the Time to format.
92
+ # type - if "ordinal" the returned String will be in ordinal format
93
+ # style - if "US" the returned String will be in US format.
94
+ # Otherwise it will be in UK format.
95
+ #
96
+ # Returns the formatted String.
97
+ def date_to_long_string(date, type = nil, style = nil)
98
+ stringify_date(date, "%B", type, style)
99
+ end
100
+
101
+ # Format a date for use in XML.
102
+ #
103
+ # date - The Time to format.
104
+ #
105
+ # Examples
106
+ #
107
+ # date_to_xmlschema(Time.now)
108
+ # # => "2011-04-24T20:34:46+08:00"
109
+ #
110
+ # Returns the formatted String.
111
+ def date_to_xmlschema(date)
112
+ return date if date.to_s.empty?
113
+ time(date).xmlschema
114
+ end
115
+
116
+ # Format a date according to RFC-822
117
+ #
118
+ # date - The Time to format.
119
+ #
120
+ # Examples
121
+ #
122
+ # date_to_rfc822(Time.now)
123
+ # # => "Sun, 24 Apr 2011 12:34:46 +0000"
124
+ #
125
+ # Returns the formatted String.
126
+ def date_to_rfc822(date)
127
+ return date if date.to_s.empty?
128
+ time(date).rfc822
129
+ end
130
+
131
+ private
132
+ # month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B")
133
+ # type: nil (default) or "ordinal"
134
+ # style: nil (default) or "US"
135
+ #
136
+ # Returns a stringified date or the empty input.
137
+ def stringify_date(date, month_type, type = nil, style = nil)
138
+ return date if date.to_s.empty?
139
+ time = time(date)
140
+ if type == "ordinal"
141
+ day = time.day
142
+ ordinal_day = "#{day}#{ordinal(day)}"
143
+ return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US"
144
+ return time.strftime("#{ordinal_day} #{month_type} %Y")
145
+ end
146
+ time.strftime("%d #{month_type} %Y")
147
+ end
148
+
149
+ private
150
+ def ordinal(number)
151
+ return "th" if (11..13).cover?(number)
152
+
153
+ case number % 10
154
+ when 1 then "st"
155
+ when 2 then "nd"
156
+ when 3 then "rd"
157
+ else "th"
158
+ end
159
+ end
160
+
161
+ private
162
+ def time(input)
163
+ date = Liquid::Utils.to_date(input)
164
+ unless date.respond_to?(:to_time)
165
+ raise "Invalid Date: '#{input.inspect}' is not a valid datetime."
166
+ end
167
+ date.to_time.dup.localtime
168
+ end
169
+ end
170
+
171
+ module Filters
172
+
173
+ # XML escape a string for use. Replaces any special characters with
174
+ # appropriate HTML entity replacements.
175
+ #
176
+ # input - The String to escape.
177
+ #
178
+ # Examples
179
+ #
180
+ # xml_escape('foo "bar" <baz>')
181
+ # # => "foo &quot;bar&quot; &lt;baz&gt;"
182
+ #
183
+ # Returns the escaped String.
184
+ def xml_escape(input)
185
+ input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "")
186
+ end
187
+
188
+ # CGI escape a string for use in a URL. Replaces any special characters
189
+ # with appropriate %XX replacements.
190
+ #
191
+ # input - The String to escape.
192
+ #
193
+ # Examples
194
+ #
195
+ # cgi_escape('foo,bar;baz?')
196
+ # # => "foo%2Cbar%3Bbaz%3F"
197
+ #
198
+ # Returns the escaped String.
199
+ def cgi_escape(input)
200
+ CGI.escape(input)
201
+ end
202
+
203
+ # URI escape a string.
204
+ #
205
+ # input - The String to escape.
206
+ #
207
+ # Examples
208
+ #
209
+ # uri_escape('foo, bar \\baz?')
210
+ # # => "foo,%20bar%20%5Cbaz?"
211
+ #
212
+ # Returns the escaped String.
213
+ def uri_escape(input)
214
+ Addressable::URI.normalize_component(input)
215
+ end
216
+
217
+ # Replace any whitespace in the input string with a single space
218
+ #
219
+ # input - The String on which to operate.
220
+ #
221
+ # Returns the formatted String
222
+ def normalize_whitespace(input)
223
+ input.to_s.gsub(%r!\s+!, " ").strip
224
+ end
225
+
226
+ # Count the number of words in the input string.
227
+ #
228
+ # input - The String on which to operate.
229
+ #
230
+ # Returns the Integer word count.
231
+ def number_of_words(input)
232
+ input.split.length
233
+ end
234
+
235
+ # Join an array of things into a string by separating with commas and the
236
+ # word "and" for the last one.
237
+ #
238
+ # Based on but differs from array_to_sentence_string, not available to LiquiDoc
239
+ #
240
+ # array - The Array of Strings to join.
241
+ # connector - Word used to connect the last 2 items in the array
242
+ #
243
+ # Examples
244
+ #
245
+ # array_to_serial(["apples", "oranges", "grapes"])
246
+ # # => "apples, oranges, and grapes"
247
+ # array_to_serial(["apples", "oranges", "grapes"], "")
248
+ # # => "apples, oranges, grapes"
249
+ # Improved behavior::
250
+ # array_to_serial(["apples", "oranges"], "")
251
+ # # => "apples, oranges"
252
+ #
253
+ # Returns the formatted String.
254
+ def array_to_serial(array, connector="and", serializer=", ")
255
+ con = "#{connector} " unless connector.empty?
256
+ case array.length
257
+ when 0
258
+ out = ""
259
+ when 1
260
+ out = array[0].to_s
261
+ when 2
262
+ ser = serializer if connector.empty?
263
+ out = "#{array[0]}#{ser} #{con}#{array[1]}"
264
+ else
265
+ out = "#{array[0...-1].join(serializer)}#{serializer}#{con}#{array[-1]}"
266
+ end
267
+ out
268
+ end
269
+
270
+ # Convert the input into json string
271
+ #
272
+ # input - The Array or Hash to be converted
273
+ #
274
+ # Returns the converted json string
275
+ def jsonify(input)
276
+ as_liquid(input).to_json
277
+ end
278
+
279
+ # Filter an array of objects
280
+ #
281
+ # input - the object array
282
+ # property - property within each object to filter by
283
+ # value - desired value
284
+ #
285
+ # Returns the filtered array of objects
286
+ def where(input, property, value)
287
+ return input if property.nil? || value.nil?
288
+ return input unless input.respond_to?(:select)
289
+ input = input.values if input.is_a?(Hash)
290
+ input_id = input.hash
291
+
292
+ # implement a hash based on method parameters to cache the end-result
293
+ # for given parameters.
294
+ @where_filter_cache ||= {}
295
+ @where_filter_cache[input_id] ||= {}
296
+ @where_filter_cache[input_id][property] ||= {}
297
+
298
+ # stash or retrive results to return
299
+ @where_filter_cache[input_id][property][value] ||= begin
300
+ input.select do |object|
301
+ Array(item_property(object, property)).map!(&:to_s).include?(value.to_s)
302
+ end || []
303
+ end
304
+ end
305
+
306
+ # Filters an array of objects against an expression
307
+ #
308
+ # input - the object array
309
+ # variable - the variable to assign each item to in the expression
310
+ # expression - a Liquid comparison expression passed in as a string
311
+ #
312
+ # Returns the filtered array of objects
313
+ def where_exp(input, variable, expression)
314
+ return input unless input.respond_to?(:select)
315
+ input = input.values if input.is_a?(Hash) # FIXME
316
+
317
+ condition = parse_condition(expression)
318
+ @context.stack do
319
+ input.select do |object|
320
+ @context[variable] = object
321
+ condition.evaluate(@context)
322
+ end
323
+ end || []
324
+ end
325
+
326
+ # Convert the input into integer
327
+ #
328
+ # input - the object string
329
+ #
330
+ # Returns the integer value
331
+ def to_integer(input)
332
+ return 1 if input == true
333
+ return 0 if input == false
334
+ input.to_i
335
+ end
336
+
337
+ # Sort an array of objects
338
+ #
339
+ # input - the object array
340
+ # property - property within each object to filter by
341
+ # nils ('first' | 'last') - nils appear before or after non-nil values
342
+ #
343
+ # Returns the filtered array of objects
344
+ def sort(input, property = nil, nils = "first")
345
+ if input.nil?
346
+ raise ArgumentError, "Cannot sort a null object."
347
+ end
348
+ if property.nil?
349
+ input.sort
350
+ else
351
+ if nils == "first"
352
+ order = - 1
353
+ elsif nils == "last"
354
+ order = + 1
355
+ else
356
+ raise ArgumentError, "Invalid nils order: " \
357
+ "'#{nils}' is not a valid nils order. It must be 'first' or 'last'."
358
+ end
359
+
360
+ sort_input(input, property, order)
361
+ end
362
+ end
363
+
364
+ def pop(array, num=1)
365
+ return array unless array.is_a?(Array)
366
+ num = Liquid::Utils.to_integer(num)
367
+ new_ary = array.dup
368
+ new_ary.pop(num)
369
+ end
370
+
371
+ def push(array, add)
372
+ return array unless array.is_a?(Array)
373
+ new_ary = array.dup
374
+ new_ary.push(add)
375
+ end
376
+
377
+ def shift(array, num=1)
378
+ return array unless array.is_a?(Array)
379
+ num = Liquid::Utils.to_integer(num)
380
+ new_ary = array.dup
381
+ new_ary.shift(num)
382
+ end
383
+
384
+ def unshift(array, add)
385
+ return array unless array.is_a?(Array)
386
+ new_ary = array.dup
387
+ new_ary.unshift(add)
388
+ end
389
+
390
+ def sample(array, num=1)
391
+ return array unless array.respond_to?(:sample)
392
+ num = Liquid::Utils.to_integer(num)
393
+ array.sample(num)
394
+ end
395
+
396
+ # Convert an object into its String representation for debugging
397
+ #
398
+ # input - The Object to be converted
399
+ #
400
+ # Returns a String representation of the object.
401
+ def inspect(input)
402
+ xml_escape(input.inspect)
403
+ end
404
+
405
+ private
406
+
407
+ # Sort the input Enumerable by the given property.
408
+ # If the property doesn't exist, return the sort order respective of
409
+ # which item doesn't have the property.
410
+ # We also utilize the Schwartzian transform to make this more efficient.
411
+ def sort_input(input, property, order)
412
+ input.map { |item| [item_property(item, property), item] }
413
+ .sort! do |apple_info, orange_info|
414
+ apple_property = apple_info.first
415
+ orange_property = orange_info.first
416
+
417
+ if !apple_property.nil? && orange_property.nil?
418
+ - order
419
+ elsif apple_property.nil? && !orange_property.nil?
420
+ + order
421
+ else
422
+ apple_property <=> orange_property
423
+ end
424
+ end
425
+ .map!(&:last)
426
+ end
427
+
428
+ private
429
+ def item_property(item, property)
430
+ if item.respond_to?(:to_liquid)
431
+ property.to_s.split(".").reduce(item.to_liquid) do |subvalue, attribute|
432
+ subvalue[attribute]
433
+ end
434
+ elsif item.respond_to?(:data)
435
+ item.data[property.to_s]
436
+ else
437
+ item[property.to_s]
438
+ end
439
+ end
440
+
441
+ private
442
+ def as_liquid(item)
443
+ case item
444
+ when Hash
445
+ pairs = item.map { |k, v| as_liquid([k, v]) }
446
+ Hash[pairs]
447
+ when Array
448
+ item.map { |i| as_liquid(i) }
449
+ else
450
+ if item.respond_to?(:to_liquid)
451
+ liquidated = item.to_liquid
452
+ # prevent infinite recursion for simple types (which return `self`)
453
+ if liquidated == item
454
+ item
455
+ else
456
+ as_liquid(liquidated)
457
+ end
458
+ else
459
+ item
460
+ end
461
+ end
462
+ end
463
+
464
+ # Parse a string to a Liquid Condition
465
+ private
466
+ def parse_condition(exp)
467
+ parser = Liquid::Parser.new(exp)
468
+ left_expr = parser.expression
469
+ operator = parser.consume?(:comparison)
470
+ condition =
471
+ if operator
472
+ Liquid::Condition.new(Liquid::Expression.parse(left_expr),
473
+ operator,
474
+ Liquid::Expression.parse(parser.expression))
475
+ else
476
+ Liquid::Condition.new(Liquid::Expression.parse(left_expr))
477
+ end
478
+ parser.consume(:end_of_string)
479
+
480
+ condition
481
+ end
482
+
483
+ end
484
+ end
485
+
486
+ Liquid::Template.register_filter(Jekyll::GroupingFilters)
487
+ Liquid::Template.register_filter(Jekyll::DateFilters)
488
+ Liquid::Template.register_filter(Jekyll::Filters)