diff --git a/lib/trmnl/liquid.rb b/lib/trmnl/liquid.rb index a92639d..42793aa 100644 --- a/lib/trmnl/liquid.rb +++ b/lib/trmnl/liquid.rb @@ -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 diff --git a/lib/trmnl/liquid/fallback.rb b/lib/trmnl/liquid/fallback.rb index dfe0953..ebd5d50 100644 --- a/lib/trmnl/liquid/fallback.rb +++ b/lib/trmnl/liquid/fallback.rb @@ -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 \ No newline at end of file +end diff --git a/lib/trmnl/liquid/file_system.rb b/lib/trmnl/liquid/file_system.rb index 1b0f652..472a46c 100644 --- a/lib/trmnl/liquid/file_system.rb +++ b/lib/trmnl/liquid/file_system.rb @@ -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 \ No newline at end of file +end diff --git a/lib/trmnl/liquid/filters.rb b/lib/trmnl/liquid/filters.rb index cc2157e..c89793d 100644 --- a/lib/trmnl/liquid/filters.rb +++ b/lib/trmnl/liquid/filters.rb @@ -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)) + + date.strftime strftime_exp.gsub("<>", 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 diff --git a/lib/trmnl/liquid/template_tag.rb b/lib/trmnl/liquid/template_tag.rb index d5f7ce2..b221a9a 100644 --- a/lib/trmnl/liquid/template_tag.rb +++ b/lib/trmnl/liquid/template_tag.rb @@ -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 \ No newline at end of file +end