mirror of
https://github.com/usetrmnl/trmnl-liquid.git
synced 2026-04-29 13:43:18 -07:00
Fixed auto correctable RuboCop issues
Ran RuboCop auto correct to clean all this up which reduced a ton of issues. ~19 offenses remain which require manual intervention to fix. Milestone: patch
This commit is contained in:
+14
-14
@@ -1,34 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'liquid'
|
||||
|
||||
require 'trmnl/liquid/filters'
|
||||
require 'trmnl/liquid/file_system'
|
||||
require 'trmnl/liquid/template_tag'
|
||||
require "liquid"
|
||||
require "trmnl/liquid/file_system"
|
||||
require "trmnl/liquid/filters"
|
||||
require "trmnl/liquid/template_tag"
|
||||
|
||||
# optional
|
||||
begin
|
||||
require 'trmnl/i18n'
|
||||
require "trmnl/i18n"
|
||||
rescue LoadError
|
||||
nil
|
||||
end
|
||||
|
||||
if defined?(::TRMNL::I18n)
|
||||
::TRMNL::I18n.load_locales
|
||||
end
|
||||
TRMNL::I18n.load_locales if defined?(TRMNL::I18n)
|
||||
|
||||
if Gem.loaded_specs['rails-i18n']
|
||||
::I18n.load_path += Pathname.new(Gem.loaded_specs['rails-i18n'].full_gem_path).join('rails', 'locale').glob('*.yml')
|
||||
if Gem.loaded_specs["rails-i18n"]
|
||||
I18n.load_path += Pathname.new(Gem.loaded_specs["rails-i18n"].full_gem_path).join(
|
||||
"rails",
|
||||
"locale"
|
||||
).glob("*.yml")
|
||||
end
|
||||
|
||||
module TRMNL
|
||||
module Liquid
|
||||
def self.build_environment(*args)
|
||||
::Liquid::Environment.build(*args) do |env|
|
||||
env.register_filter(TRMNL::Liquid::Filters)
|
||||
env.register_tag('template', TRMNL::Liquid::TemplateTag)
|
||||
env.register_filter TRMNL::Liquid::Filters
|
||||
env.register_tag "template", TRMNL::Liquid::TemplateTag
|
||||
env.file_system = TRMNL::Liquid::FileSystem.new
|
||||
yield(env) if block_given?
|
||||
yield env if block_given?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module TRMNL
|
||||
module Liquid
|
||||
# library-native formatting functions that don't rely on ActionView helpers
|
||||
module Fallback
|
||||
extend self
|
||||
module_function
|
||||
|
||||
def number_with_delimiter(number, delimiter, separator)
|
||||
def number_with_delimiter number, delimiter, separator
|
||||
str = number.to_s
|
||||
|
||||
# return early if it's not a simple numeric-like string
|
||||
return str unless str.match?(/\A-?\d+(\.\d+)?\z/)
|
||||
|
||||
integer, fractional = str.split('.')
|
||||
negative = integer.start_with?('-')
|
||||
integer, fractional = str.split "."
|
||||
negative = integer.start_with? "-"
|
||||
integer = integer[1..] if negative
|
||||
|
||||
integer_with_delimiters = integer.reverse.scan(/\d{1,3}/).join(delimiter).reverse
|
||||
@@ -24,38 +26,37 @@ module TRMNL
|
||||
end
|
||||
end
|
||||
|
||||
def number_to_currency(number, unit, delimiter, separator, precision)
|
||||
result = number_with_delimiter(number, delimiter, separator)
|
||||
dollars, cents = result.split(separator)
|
||||
def number_to_currency number, unit, delimiter, separator, precision
|
||||
result = number_with_delimiter number, delimiter, separator
|
||||
dollars, cents = result.split separator
|
||||
|
||||
if precision <= 0
|
||||
"#{unit}#{dollars}"
|
||||
else
|
||||
cents = cents.to_s[0..(precision - 1)].ljust(precision, '0')
|
||||
cents = cents.to_s[0..(precision - 1)].ljust precision, "0"
|
||||
"#{unit}#{dollars}#{separator}#{cents}"
|
||||
end
|
||||
end
|
||||
|
||||
def ordinalize(number)
|
||||
suffix =
|
||||
if (11..13).include?(number % 100)
|
||||
'th'
|
||||
else
|
||||
case number % 10
|
||||
when 1 then 'st'
|
||||
when 2 then 'nd'
|
||||
when 3 then 'rd'
|
||||
else 'th'
|
||||
end
|
||||
end
|
||||
def ordinalize number
|
||||
suffix = if (11..13).include? number % 100
|
||||
"th"
|
||||
else
|
||||
case number % 10
|
||||
when 1 then "st"
|
||||
when 2 then "nd"
|
||||
when 3 then "rd"
|
||||
else "th"
|
||||
end
|
||||
end
|
||||
|
||||
"#{number}#{suffix}"
|
||||
end
|
||||
|
||||
def pluralize(count, singular, plural)
|
||||
def pluralize count, singular, plural
|
||||
plural ||= "#{singular}s"
|
||||
count == 1 ? "1 #{singular}" : "#{count} #{plural}"
|
||||
count == 1 ? "1 #{singular}" : "#{count} #{plural}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module TRMNL
|
||||
module Liquid
|
||||
# This in-memory "file system" is the backing storage for custom templates defined {% template [name] %} tags.
|
||||
# This in-memory "file system" is the backing storage for custom templates
|
||||
# defined {% template [name] %} tags.
|
||||
class FileSystem < ::Liquid::BlankFileSystem
|
||||
def initialize
|
||||
super
|
||||
@templates = {}
|
||||
end
|
||||
|
||||
# called by Markup::LiquidTemplateTag to save users' custom shared templates via our custom {% template %} tag
|
||||
def register(name, body)
|
||||
# called by Markup::LiquidTemplateTag to save users' custom shared templates via our
|
||||
# custom {% template %} tag
|
||||
def register name, body
|
||||
@templates[name] = body
|
||||
end
|
||||
|
||||
# called by ::Liquid::Template for {% render 'foo' %} when rendering screen markup
|
||||
def read_template_file(name)
|
||||
@templates[name] || raise(::Liquid::FileSystemError, "Template not found: #{name}")
|
||||
def read_template_file name
|
||||
@templates[name] || fail(::Liquid::FileSystemError, "Template not found: #{name}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+100
-99
@@ -1,11 +1,13 @@
|
||||
require 'date'
|
||||
require 'json'
|
||||
require 'redcarpet'
|
||||
require 'tzinfo'
|
||||
require 'rqrcode'
|
||||
require 'securerandom'
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'fallback'
|
||||
require "date"
|
||||
require "json"
|
||||
require "redcarpet"
|
||||
require "rqrcode"
|
||||
require "securerandom"
|
||||
require "tzinfo"
|
||||
|
||||
require_relative "fallback"
|
||||
|
||||
# optional
|
||||
%w[
|
||||
@@ -13,195 +15,196 @@ require_relative 'fallback'
|
||||
action_view
|
||||
active_support/core_ext/integer/inflections
|
||||
].each do |lib|
|
||||
begin
|
||||
require lib
|
||||
rescue LoadError
|
||||
nil
|
||||
end
|
||||
require lib
|
||||
rescue LoadError
|
||||
nil
|
||||
end
|
||||
|
||||
module TRMNL
|
||||
module Liquid
|
||||
module Filters
|
||||
def append_random(var)
|
||||
"#{var}#{SecureRandom.hex(2)}"
|
||||
def append_random var
|
||||
"#{var}#{SecureRandom.hex 2}"
|
||||
end
|
||||
|
||||
def days_ago(num, tz = 'Etc/UTC')
|
||||
tzinfo = TZInfo::Timezone.get(tz)
|
||||
def days_ago num, tz = "Etc/UTC"
|
||||
tzinfo = TZInfo::Timezone.get tz
|
||||
tzinfo.now.to_date - num.to_i
|
||||
end
|
||||
|
||||
def group_by(collection, key)
|
||||
def group_by collection, key
|
||||
collection.group_by { |obj| obj[key] }
|
||||
end
|
||||
|
||||
def find_by(collection, key, value, fallback = nil)
|
||||
def find_by collection, key, value, fallback = nil
|
||||
collection.find { |obj| obj[key] == value } || fallback
|
||||
end
|
||||
|
||||
def markdown_to_html(markdown)
|
||||
markdown ||= ''
|
||||
renderer = Redcarpet::Render::HTML.new(_render_options = {})
|
||||
service = Redcarpet::Markdown.new(renderer, _extensions = {})
|
||||
service.render(markdown)
|
||||
def markdown_to_html markdown
|
||||
markdown ||= ""
|
||||
renderer = Redcarpet::Render::HTML.new _render_options = {}
|
||||
service = Redcarpet::Markdown.new renderer, _extensions = {}
|
||||
service.render markdown
|
||||
end
|
||||
|
||||
def number_with_delimiter(number, delimiter = ',', separator = '.')
|
||||
if helpers.respond_to?(:number_with_delimiter)
|
||||
helpers.number_with_delimiter(number, delimiter: delimiter, separator: separator)
|
||||
def number_with_delimiter number, delimiter = ",", separator = "."
|
||||
if helpers.respond_to? :number_with_delimiter
|
||||
helpers.number_with_delimiter number, delimiter: delimiter, separator: separator
|
||||
else
|
||||
Fallback.number_with_delimiter(number, delimiter, separator)
|
||||
Fallback.number_with_delimiter number, delimiter, separator
|
||||
end
|
||||
end
|
||||
|
||||
def number_to_currency(number, unit_or_locale = '$', delimiter = ',', separator = '.', precision = 2)
|
||||
if helpers.respond_to?(:number_to_currency)
|
||||
cur_switcher = with_i18n(:unit) do |i18n|
|
||||
def number_to_currency number,
|
||||
unit_or_locale = "$",
|
||||
delimiter = ",",
|
||||
separator = ".",
|
||||
precision = 2
|
||||
if helpers.respond_to? :number_to_currency
|
||||
cur_switcher = with_i18n :unit do |i18n|
|
||||
i18n.available_locales.include?(unit_or_locale.to_sym) ? :locale : :unit
|
||||
end
|
||||
opts = { delimiter:, separator:, precision: }.merge(cur_switcher => unit_or_locale)
|
||||
opts = {delimiter:, separator:, precision:}.merge cur_switcher => unit_or_locale
|
||||
helpers.number_to_currency(number, **opts)
|
||||
else
|
||||
Fallback.number_to_currency(number, unit_or_locale, delimiter, separator, precision)
|
||||
Fallback.number_to_currency number, unit_or_locale, delimiter, separator, precision
|
||||
end
|
||||
end
|
||||
|
||||
def l_word(word, locale)
|
||||
with_i18n("custom_plugins.#{word}") do |i18n|
|
||||
i18n.t("custom_plugins.#{word}", locale: locale)
|
||||
def l_word word, locale
|
||||
with_i18n "custom_plugins.#{word}" do |i18n|
|
||||
i18n.t "custom_plugins.#{word}", locale: locale
|
||||
end
|
||||
end
|
||||
|
||||
def l_date(date, format, locale = 'en')
|
||||
with_i18n(date.to_s) do |i18n|
|
||||
format = format.to_sym unless format.include?('%')
|
||||
i18n.l(to_datetime(date), format: format, locale: locale)
|
||||
def l_date date, format, locale = "en"
|
||||
with_i18n date.to_s do |i18n|
|
||||
format = format.to_sym unless format.include? "%"
|
||||
i18n.l to_datetime(date), format: format, locale: locale
|
||||
end
|
||||
end
|
||||
|
||||
def map_to_i(collection)
|
||||
def map_to_i collection
|
||||
collection.map(&:to_i)
|
||||
end
|
||||
|
||||
def pluralize(singular, count, opts = {})
|
||||
plural = opts['plural']
|
||||
locale = opts['locale'] || with_i18n(nil) { |i18n| i18n.locale } || 'en'
|
||||
def pluralize singular, count, opts = {}
|
||||
plural = opts["plural"]
|
||||
locale = opts["locale"] || with_i18n(nil) { |i18n| i18n.locale } || "en"
|
||||
|
||||
if helpers.respond_to?(:pluralize)
|
||||
helpers.pluralize(count, singular, plural: plural, locale: locale)
|
||||
if helpers.respond_to? :pluralize
|
||||
helpers.pluralize count, singular, plural: plural, locale: locale
|
||||
else
|
||||
Fallback.pluralize(count, singular, plural)
|
||||
Fallback.pluralize count, singular, plural
|
||||
end
|
||||
end
|
||||
|
||||
def json(obj)
|
||||
JSON.generate(obj)
|
||||
def json obj
|
||||
JSON.generate obj
|
||||
end
|
||||
|
||||
def parse_json(obj)
|
||||
JSON.parse(obj)
|
||||
def parse_json obj
|
||||
JSON.parse obj
|
||||
end
|
||||
|
||||
def sample(array) = array.sample
|
||||
|
||||
# source: https://github.com/jekyll/jekyll/blob/40ac06ed3e95325a07868dd2ac419e409af823b6/lib/jekyll/filters.rb#L209
|
||||
def where_exp(input, variable, expression)
|
||||
return input unless input.respond_to?(:select)
|
||||
def where_exp input, variable, expression
|
||||
return input unless input.respond_to? :select
|
||||
|
||||
input = input.values if input.is_a?(Hash)
|
||||
input = input.values if input.is_a? Hash
|
||||
|
||||
condition = parse_condition(expression)
|
||||
condition = parse_condition expression
|
||||
@context.stack do
|
||||
input.select do |object|
|
||||
@context[variable] = object
|
||||
condition.evaluate(@context)
|
||||
condition.evaluate @context
|
||||
end
|
||||
end || []
|
||||
end
|
||||
|
||||
def ordinalize(date_str, strftime_exp)
|
||||
date = Date.parse(date_str)
|
||||
|
||||
ordinal_day = if date.day.respond_to?(:ordinalize)
|
||||
def ordinalize date_str, strftime_exp
|
||||
date = Date.parse date_str
|
||||
|
||||
ordinal_day = if date.day.respond_to? :ordinalize
|
||||
date.day.ordinalize
|
||||
else
|
||||
Fallback.ordinalize(date.day)
|
||||
Fallback.ordinalize date.day
|
||||
end
|
||||
|
||||
date.strftime(strftime_exp.gsub('<<ordinal_day>>', ordinal_day))
|
||||
|
||||
date.strftime strftime_exp.gsub("<<ordinal_day>>", ordinal_day)
|
||||
end
|
||||
|
||||
def qr_code(data, size = 11, level = '')
|
||||
level.downcase!
|
||||
level = 'h' unless %w[l m q h].include?(level)
|
||||
def qr_code data, size = 11, level = ""
|
||||
level = "h" unless %w[l m q h].include? level.downcase
|
||||
|
||||
qrcode = RQRCode::QRCode.new(data, level:)
|
||||
qrcode.as_svg(
|
||||
color: '000',
|
||||
fill: 'fff',
|
||||
shape_rendering: 'crispEdges',
|
||||
color: "000",
|
||||
fill: "fff",
|
||||
shape_rendering: "crispEdges",
|
||||
module_size: size,
|
||||
standalone: true,
|
||||
use_path: true,
|
||||
svg_attributes: {
|
||||
class: 'qr-code'
|
||||
class: "qr-code"
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_i18n(fallback, &block)
|
||||
def with_i18n fallback
|
||||
if defined?(::I18n)
|
||||
block.call(::I18n)
|
||||
yield ::I18n
|
||||
else
|
||||
fallback
|
||||
end
|
||||
end
|
||||
|
||||
def to_datetime(obj)
|
||||
def to_datetime obj
|
||||
case obj
|
||||
when DateTime
|
||||
obj
|
||||
when Date
|
||||
obj.to_datetime
|
||||
when Time
|
||||
DateTime.parse(obj.iso8601)
|
||||
else
|
||||
DateTime.parse(obj.to_s)
|
||||
when DateTime
|
||||
obj
|
||||
when Date
|
||||
obj.to_datetime
|
||||
when Time
|
||||
DateTime.parse(obj.iso8601)
|
||||
else
|
||||
DateTime.parse obj.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def parse_condition(exp)
|
||||
parser = ::Liquid::Parser.new(exp)
|
||||
condition = parse_binary_comparison(parser)
|
||||
def parse_condition exp
|
||||
parser = ::Liquid::Parser.new exp
|
||||
condition = parse_binary_comparison parser
|
||||
|
||||
parser.consume(:end_of_string)
|
||||
parser.consume :end_of_string
|
||||
condition
|
||||
end
|
||||
|
||||
def parse_binary_comparison(parser)
|
||||
condition = parse_comparison(parser)
|
||||
def parse_binary_comparison parser
|
||||
condition = parse_comparison parser
|
||||
first_condition = condition
|
||||
while (binary_operator = parser.id?('and') || parser.id?('or'))
|
||||
child_condition = parse_comparison(parser)
|
||||
condition.send(binary_operator, child_condition)
|
||||
while (binary_operator = parser.id?("and") || parser.id?("or"))
|
||||
child_condition = parse_comparison parser
|
||||
condition.send binary_operator, child_condition
|
||||
condition = child_condition
|
||||
end
|
||||
first_condition
|
||||
end
|
||||
|
||||
def parse_comparison(parser)
|
||||
left_operand = ::Liquid::Expression.parse(parser.expression)
|
||||
operator = parser.consume?(:comparison)
|
||||
def parse_comparison parser
|
||||
left_operand = ::Liquid::Expression.parse parser.expression
|
||||
operator = parser.consume? :comparison
|
||||
|
||||
# No comparison-operator detected. Initialize a Liquid::Condition using only left operand
|
||||
return ::Liquid::Condition.new(left_operand) unless operator
|
||||
return ::Liquid::Condition.new left_operand unless operator
|
||||
|
||||
# Parse what remained after extracting the left operand and the `:comparison` operator
|
||||
# and initialize a Liquid::Condition object using the operands and the comparison-operator
|
||||
::Liquid::Condition.new(left_operand, operator, ::Liquid::Expression.parse(parser.expression))
|
||||
::Liquid::Condition.new left_operand, operator, ::Liquid::Expression.parse(parser.expression)
|
||||
end
|
||||
|
||||
class Helpers
|
||||
@@ -209,11 +212,9 @@ module TRMNL
|
||||
::ActionView::Helpers::TextHelper
|
||||
::ActionView::Helpers::NumberHelper
|
||||
].each do |name|
|
||||
begin
|
||||
include Object.const_get(name)
|
||||
rescue NameError
|
||||
next
|
||||
end
|
||||
include Object.const_get(name)
|
||||
rescue NameError
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module TRMNL
|
||||
module Liquid
|
||||
# The {% template [name] %} tag block is used in conjunction with InlineTemplatesFileSystem to allow users to define
|
||||
# custom templates within the context of the current Liquid template. Generally speaking, they will define their own
|
||||
# templates in the "shared" markup content, which is prepended to the individual screen templates before rendering.
|
||||
# The {% template [name] %} tag block is used in conjunction with InlineTemplatesFileSystem to
|
||||
# allow users to define custom templates within the context of the current Liquid template.
|
||||
# Generally speaking, they will define their own templates in the "shared" markup content,
|
||||
# which is prepended to the individual screen templates before rendering.
|
||||
class TemplateTag < ::Liquid::Block
|
||||
NAME_REGEX = %r{\A[a-zA-Z0-9_/]+\z}
|
||||
NAME_REGEX = %r(\A[a-zA-Z0-9_/]+\z)
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
def initialize tag_name, markup, options
|
||||
super
|
||||
@name = markup.strip
|
||||
end
|
||||
|
||||
def parse(tokens)
|
||||
@body = ""
|
||||
def parse tokens
|
||||
@body = +""
|
||||
while (token = tokens.shift)
|
||||
break if token.strip == "{% endtemplate %}"
|
||||
|
||||
@@ -20,14 +23,14 @@ module TRMNL
|
||||
end
|
||||
end
|
||||
|
||||
def render(context)
|
||||
unless @name =~ NAME_REGEX
|
||||
def render context
|
||||
unless NAME_REGEX.match? @name
|
||||
return "Liquid error: invalid template name #{@name.inspect} - template names must contain only letters, numbers, underscores, and slashes"
|
||||
end
|
||||
|
||||
context.registers[:file_system].register(@name, @body.strip)
|
||||
''
|
||||
context.registers[:file_system].register @name, @body.strip
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user