trmnl-liquid 0.2.1 → 0.4.0

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: b5e5f00cdb88f5f81b745ea1394c369a3dc00d45589d934f5eece892b129016f
4
- data.tar.gz: 78364324ec935698b118aa5681834abd3aa0a2e7ea6ba2ce764b13ddcbe08a12
3
+ metadata.gz: f21152bc330bde8f49978e8a4680e4e1ef79e19c8dd63e657ada328567c85e1c
4
+ data.tar.gz: 58fc02a7aa0dbbb0e2fcf66d08019e59a76a63cb18f8bacf63e462df4d50f39b
5
5
  SHA512:
6
- metadata.gz: 3b425d1b5e6f12cd5a2cae92c8c3f7e5337755bce55a376f5c6f93310dcd79d5017f90a2cbfd7c1de112bbca7da07a1fad94367f2c21848fa752f2be5ae0df23
7
- data.tar.gz: 984f0474d0314d0940cce7eb40d2ec968b156deac79231c630914bab33bdc92f6f6b50667b786efa66c767c68e0ce97bc57ebd5abf144f3d64601fa93abb0ee7
6
+ metadata.gz: bca98684b5fa6857652231dfbf9ce04cdb49d42feeb0025c3f2862f7eb589d92d1bb42d0142728e12c103fbac42d519a65d87e1cdf4a6b03f6855a9128807745
7
+ data.tar.gz: 0eaad3ce40e20868d4560eacdd1810b1dc19ee8d9676907e87a588141e23949ab80c9bb7fd9daab07da7fea2b69e002311f6e9c83ec33e9880ddb3e6ea63ac06
@@ -0,0 +1,61 @@
1
+ module TRMNL
2
+ module Liquid
3
+ # library-native formatting functions that don't rely on ActionView helpers
4
+ module Fallback
5
+ extend self
6
+
7
+ def number_with_delimiter(number, delimiter, separator)
8
+ str = number.to_s
9
+
10
+ # return early if it's not a simple numeric-like string
11
+ return str unless str.match?(/\A-?\d+(\.\d+)?\z/)
12
+
13
+ integer, fractional = str.split('.')
14
+ negative = integer.start_with?('-')
15
+ integer = integer[1..] if negative
16
+
17
+ integer_with_delimiters = integer.reverse.scan(/\d{1,3}/).join(delimiter).reverse
18
+ integer_with_delimiters = "-#{integer_with_delimiters}" if negative
19
+
20
+ if fractional
21
+ integer_with_delimiters + separator + fractional
22
+ else
23
+ integer_with_delimiters
24
+ end
25
+ end
26
+
27
+ def number_to_currency(number, unit, delimiter, separator, precision)
28
+ result = number_with_delimiter(number, delimiter, separator)
29
+ dollars, cents = result.split(separator)
30
+
31
+ if precision <= 0
32
+ "#{unit}#{dollars}"
33
+ else
34
+ cents = cents.to_s[0..(precision - 1)].ljust(precision, '0')
35
+ "#{unit}#{dollars}#{separator}#{cents}"
36
+ end
37
+ end
38
+
39
+ def ordinalize(number)
40
+ suffix =
41
+ if (11..13).include?(number % 100)
42
+ 'th'
43
+ else
44
+ case number % 10
45
+ when 1 then 'st'
46
+ when 2 then 'nd'
47
+ when 3 then 'rd'
48
+ else 'th'
49
+ end
50
+ end
51
+
52
+ "#{number}#{suffix}"
53
+ end
54
+
55
+ def pluralize(count, singular, plural)
56
+ plural ||= "#{singular}s"
57
+ count == 1 ? "1 #{singular}" : "#{count} #{plural}"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,12 +1,23 @@
1
- require 'action_view'
2
1
  require 'date'
2
+ require 'json'
3
3
  require 'redcarpet'
4
4
  require 'tzinfo'
5
-
6
- begin
7
- require 'i18n'
8
- rescue LoadError
9
- nil
5
+ require 'rqrcode'
6
+ require 'securerandom'
7
+
8
+ require_relative 'fallback'
9
+
10
+ # optional
11
+ %w[
12
+ i18n
13
+ action_view
14
+ active_support/core_ext/integer/inflections
15
+ ].each do |lib|
16
+ begin
17
+ require lib
18
+ rescue LoadError
19
+ nil
20
+ end
10
21
  end
11
22
 
12
23
  module TRMNL
@@ -36,16 +47,24 @@ module TRMNL
36
47
  service.render(markdown)
37
48
  end
38
49
 
39
- def number_with_delimiter(number, delimiter = ',', separator = ',')
40
- helpers.number_with_delimiter(number, delimiter: delimiter, separator: separator)
50
+ def number_with_delimiter(number, delimiter = ',', separator = '.')
51
+ if helpers.respond_to?(:number_with_delimiter)
52
+ helpers.number_with_delimiter(number, delimiter: delimiter, separator: separator)
53
+ else
54
+ Fallback.number_with_delimiter(number, delimiter, separator)
55
+ end
41
56
  end
42
57
 
43
- def number_to_currency(number, unit_or_locale = '$', delimiter = ',', separator = '.')
44
- cur_switcher = with_i18n(:unit) do |i18n|
45
- i18n.available_locales.include?(unit_or_locale.to_sym) ? :locale : :unit
58
+ def number_to_currency(number, unit_or_locale = '$', delimiter = ',', separator = '.', precision = 2)
59
+ if helpers.respond_to?(:number_to_currency)
60
+ cur_switcher = with_i18n(:unit) do |i18n|
61
+ i18n.available_locales.include?(unit_or_locale.to_sym) ? :locale : :unit
62
+ end
63
+ opts = { delimiter:, separator:, precision: }.merge(cur_switcher => unit_or_locale)
64
+ helpers.number_to_currency(number, **opts)
65
+ else
66
+ Fallback.number_to_currency(number, unit_or_locale, delimiter, separator, precision)
46
67
  end
47
- opts = { delimiter:, separator: }.merge(cur_switcher => unit_or_locale)
48
- helpers.number_to_currency(number, **opts)
49
68
  end
50
69
 
51
70
  def l_word(word, locale)
@@ -61,8 +80,19 @@ module TRMNL
61
80
  end
62
81
  end
63
82
 
64
- def pluralize(singular, count)
65
- helpers.pluralize(count, singular)
83
+ def map_to_i(collection)
84
+ collection.map(&:to_i)
85
+ end
86
+
87
+ def pluralize(singular, count, opts = {})
88
+ plural = opts['plural']
89
+ locale = opts['locale'] || with_i18n(nil) { |i18n| i18n.locale } || 'en'
90
+
91
+ if helpers.respond_to?(:pluralize)
92
+ helpers.pluralize(count, singular, plural: plural, locale: locale)
93
+ else
94
+ Fallback.pluralize(count, singular, plural)
95
+ end
66
96
  end
67
97
 
68
98
  def json(obj)
@@ -75,6 +105,51 @@ module TRMNL
75
105
 
76
106
  def sample(array) = array.sample
77
107
 
108
+ # source: https://github.com/jekyll/jekyll/blob/40ac06ed3e95325a07868dd2ac419e409af823b6/lib/jekyll/filters.rb#L209
109
+ def where_exp(input, variable, expression)
110
+ return input unless input.respond_to?(:select)
111
+
112
+ input = input.values if input.is_a?(Hash)
113
+
114
+ condition = parse_condition(expression)
115
+ @context.stack do
116
+ input.select do |object|
117
+ @context[variable] = object
118
+ condition.evaluate(@context)
119
+ end
120
+ end || []
121
+ end
122
+
123
+ def ordinalize(date_str, strftime_exp)
124
+ date = Date.parse(date_str)
125
+
126
+ ordinal_day = if date.day.respond_to?(:ordinalize)
127
+ date.day.ordinalize
128
+ else
129
+ Fallback.ordinalize(date.day)
130
+ end
131
+
132
+ date.strftime(strftime_exp.gsub('<<ordinal_day>>', ordinal_day))
133
+ end
134
+
135
+ def qr_code(data, size = 11, level = '')
136
+ level.downcase!
137
+ level = 'h' unless %w[l m q h].include?(level)
138
+
139
+ qrcode = RQRCode::QRCode.new(data, level:)
140
+ qrcode.as_svg(
141
+ color: '000',
142
+ fill: 'fff',
143
+ shape_rendering: 'crispEdges',
144
+ module_size: size,
145
+ standalone: true,
146
+ use_path: true,
147
+ svg_attributes: {
148
+ class: 'qr-code'
149
+ }
150
+ )
151
+ end
152
+
78
153
  private
79
154
 
80
155
  def with_i18n(fallback, &block)
@@ -98,15 +173,53 @@ module TRMNL
98
173
  end
99
174
  end
100
175
 
101
- def helpers
102
- @helpers ||= begin
103
- mod = Module.new do
104
- include ::ActionView::Helpers::NumberHelper
105
- include ::ActionView::Helpers::TextHelper
176
+ def parse_condition(exp)
177
+ parser = ::Liquid::Parser.new(exp)
178
+ condition = parse_binary_comparison(parser)
179
+
180
+ parser.consume(:end_of_string)
181
+ condition
182
+ end
183
+
184
+ def parse_binary_comparison(parser)
185
+ condition = parse_comparison(parser)
186
+ first_condition = condition
187
+ while (binary_operator = parser.id?('and') || parser.id?('or'))
188
+ child_condition = parse_comparison(parser)
189
+ condition.send(binary_operator, child_condition)
190
+ condition = child_condition
191
+ end
192
+ first_condition
193
+ end
194
+
195
+ def parse_comparison(parser)
196
+ left_operand = ::Liquid::Expression.parse(parser.expression)
197
+ operator = parser.consume?(:comparison)
198
+
199
+ # No comparison-operator detected. Initialize a Liquid::Condition using only left operand
200
+ return ::Liquid::Condition.new(left_operand) unless operator
201
+
202
+ # Parse what remained after extracting the left operand and the `:comparison` operator
203
+ # and initialize a Liquid::Condition object using the operands and the comparison-operator
204
+ ::Liquid::Condition.new(left_operand, operator, ::Liquid::Expression.parse(parser.expression))
205
+ end
206
+
207
+ class Helpers
208
+ %w[
209
+ ::ActionView::Helpers::TextHelper
210
+ ::ActionView::Helpers::NumberHelper
211
+ ].each do |name|
212
+ begin
213
+ include Object.const_get(name)
214
+ rescue NameError
215
+ next
106
216
  end
107
- Object.new.extend(mod)
108
217
  end
109
218
  end
219
+
220
+ def helpers
221
+ @helpers ||= Helpers.new
222
+ end
110
223
  end
111
224
  end
112
225
  end
@@ -1,7 +1,6 @@
1
-
2
1
  # frozen_string_literal: true
3
2
  module TRMNL
4
3
  module Liquid
5
- VERSION = "0.2.1"
4
+ VERSION = "0.4.0"
6
5
  end
7
6
  end
data/lib/trmnl/liquid.rb CHANGED
@@ -7,6 +7,7 @@ require 'trmnl/liquid/file_system'
7
7
  require 'trmnl/liquid/template_tag'
8
8
  require 'trmnl/liquid/version'
9
9
 
10
+ # optional
10
11
  begin
11
12
  require 'trmnl/i18n'
12
13
  rescue LoadError
data/trmnl-liquid.gemspec CHANGED
@@ -27,7 +27,10 @@ Gem::Specification.new do |spec|
27
27
  spec.files = Dir["*.gemspec", "lib/**/*"]
28
28
  spec.require_paths = ["lib"]
29
29
 
30
- spec.add_dependency "actionview", "~> 8.0"
30
+ spec.add_dependency "base64"
31
31
  spec.add_dependency "liquid", "~> 5.6"
32
32
  spec.add_dependency "redcarpet", "~> 3.6"
33
+ spec.add_dependency "rqrcode", "~> 3.0"
34
+ spec.add_dependency "securerandom", ">= 0.3"
35
+ spec.add_dependency "tzinfo"
33
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trmnl-liquid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TRMNL
@@ -10,19 +10,19 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: actionview
13
+ name: base64
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '8.0'
18
+ version: '0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '8.0'
25
+ version: '0'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: liquid
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +51,48 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '3.6'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rqrcode
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: securerandom
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0.3'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0.3'
82
+ - !ruby/object:Gem::Dependency
83
+ name: tzinfo
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
54
96
  email:
55
97
  - engineering@usetrmnl.com
56
98
  executables: []
@@ -58,6 +100,7 @@ extensions: []
58
100
  extra_rdoc_files: []
59
101
  files:
60
102
  - lib/trmnl/liquid.rb
103
+ - lib/trmnl/liquid/fallback.rb
61
104
  - lib/trmnl/liquid/file_system.rb
62
105
  - lib/trmnl/liquid/filters.rb
63
106
  - lib/trmnl/liquid/template_tag.rb