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

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