fmt 0.1.1 → 0.1.2
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 +4 -4
- data/README.md +86 -10
- data/lib/fmt/embed.rb +19 -0
- data/lib/fmt/filters.rb +10 -10
- data/lib/fmt/formatter.rb +12 -23
- data/lib/fmt/scanners/base_scanner.rb +41 -0
- data/lib/fmt/scanners/embed_scanner.rb +56 -0
- data/lib/fmt/scanners/filter_scanner.rb +31 -0
- data/lib/fmt/scanners/key_scanner.rb +15 -0
- data/lib/fmt/scanners.rb +3 -0
- data/lib/fmt/transformer.rb +33 -8
- data/lib/fmt/version.rb +1 -1
- data/lib/fmt.rb +6 -0
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4bafcbfda352b24f4203057c8ae8c8df4ddc109727fd610250d54c1db02ea2a
|
4
|
+
data.tar.gz: 1e672363e323f01757e1590441d8f836bba9b03936b4551189cd040a942936f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39a4f811f2a9ee86e82fd0e7ce557aa6f22971cd31bde8c5a717b47f74b35119c8d7616580dac5de18851329edd304a72549ecd8239c2104caea3f41d4a3da7e
|
7
|
+
data.tar.gz: 75fe78f4908b6b94eb7fe37ba0d76819562d7005405d72d3c14ccb93b55d465da95e890becd9794b53eb7c3d44970a6f14ba3d62d45c1eb78e1cf31810e4885f
|
data/README.md
CHANGED
@@ -1,6 +1,35 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/">
|
3
|
+
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-316-47d299.svg" />
|
4
|
+
</a>
|
5
|
+
<a href="https://github.com/testdouble/standard">
|
6
|
+
<img alt="Ruby Style" src="https://img.shields.io/badge/style-standard-168AFE?logo=ruby&logoColor=FE1616" />
|
7
|
+
</a>
|
8
|
+
<a href="https://github.com/sponsors/hopsoft">
|
9
|
+
<img alt="Sponsors" src="https://img.shields.io/github/sponsors/hopsoft?color=eb4aaa&logo=GitHub%20Sponsors" />
|
10
|
+
</a>
|
11
|
+
<a href="https://twitter.com/hopsoft">
|
12
|
+
<img alt="Twitter Follow" src="https://img.shields.io/twitter/url?label=%40hopsoft&style=social&url=https%3A%2F%2Ftwitter.com%2Fhopsoft">
|
13
|
+
</a>
|
14
|
+
</p>
|
15
|
+
|
1
16
|
# Fmt
|
2
17
|
|
3
|
-
|
18
|
+
#### A simple template engine based on native Ruby String formatting mechanics
|
19
|
+
|
20
|
+
<!-- Tocer[start]: Auto-generated, don't remove. -->
|
21
|
+
|
22
|
+
## Table of Contents
|
23
|
+
|
24
|
+
- [Why?](#why)
|
25
|
+
- [Setup](#setup)
|
26
|
+
- [Usage](#usage)
|
27
|
+
- [Formatting](#formatting)
|
28
|
+
- [Filters](#filters)
|
29
|
+
- [Embeds](#embeds)
|
30
|
+
- [Sponsors](#sponsors)
|
31
|
+
|
32
|
+
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
4
33
|
|
5
34
|
## Why?
|
6
35
|
|
@@ -35,7 +64,7 @@ Also, you can use Rainbow filters like `bold`, `cyan`, `underline`, et al. if yo
|
|
35
64
|
|
36
65
|
**You can even [register your own filters](#filters).**
|
37
66
|
|
38
|
-
###
|
67
|
+
### Formatting
|
39
68
|
|
40
69
|
Basic example:
|
41
70
|
|
@@ -44,7 +73,8 @@ require "rainbow"
|
|
44
73
|
require "fmt"
|
45
74
|
|
46
75
|
template = "Hello %{name}cyan|bold"
|
47
|
-
|
76
|
+
Fmt template, name: "World"
|
77
|
+
|
48
78
|
#=> "Hello \e[36m\e[1mWorld\e[0m"
|
49
79
|
```
|
50
80
|
|
@@ -57,7 +87,8 @@ require "rainbow"
|
|
57
87
|
require "fmt"
|
58
88
|
|
59
89
|
template = "Date: %{date}.10s|magenta"
|
60
|
-
|
90
|
+
Fmt template, date: Time.now
|
91
|
+
|
61
92
|
#=> "Date: \e[35m2024-07-26\e[0m"
|
62
93
|
```
|
63
94
|
|
@@ -77,7 +108,8 @@ template = <<~T
|
|
77
108
|
%{message}strip|green
|
78
109
|
T
|
79
110
|
|
80
|
-
|
111
|
+
Fmt template, date: Time.now, name: "Hopsoft", message: "This is neat!"
|
112
|
+
|
81
113
|
#=> "Date: \e[4m2024-07-26\e[0m\n\nGreetings, \e[1mHOPSOFT\e[0m\n\n\e[32mThis is neat!\e[0m\n"
|
82
114
|
```
|
83
115
|
|
@@ -92,16 +124,60 @@ The block accepts a string and should return a replacement string.
|
|
92
124
|
require "rainbow"
|
93
125
|
require "fmt"
|
94
126
|
|
95
|
-
Fmt.add_filter(:
|
127
|
+
Fmt.add_filter(:ljust) { |val| "".ljust 14, val.to_s }
|
96
128
|
|
97
129
|
template = <<~T
|
98
|
-
%{head}
|
130
|
+
%{head}ljust|faint
|
99
131
|
%{message}bold
|
100
|
-
%{tail}
|
132
|
+
%{tail}ljust|faint
|
101
133
|
T
|
102
134
|
|
103
|
-
|
104
|
-
|
135
|
+
Fmt template, head: "#", message: "Give it a try!", tail: "#"
|
136
|
+
|
137
|
+
#=> "\e[2m##############\e[0m\n\e[1mGive it a try!\e[0m\n\e[2m##############\e[0m\n"
|
105
138
|
```
|
106
139
|
|
107
140
|

|
141
|
+
|
142
|
+
### Embeds
|
143
|
+
|
144
|
+
Templates can be embedded or nested within other templates... as deep as needed!
|
145
|
+
Just wrap the embedded template in double curly braces: `{{EMBEDDED TEMPLATE HERE}}`
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
require "rainbow"
|
149
|
+
require "fmt"
|
150
|
+
|
151
|
+
template = "%{value}lime {{%{embed_value}red|bold|underline}}"
|
152
|
+
Fmt template, value: "Outer", embed_value: "Inner"
|
153
|
+
|
154
|
+
#=> "\e[38;5;46mOuter\e[0m \e[31m\e[1m\e[4mInner\e[0m"
|
155
|
+
```
|
156
|
+
|
157
|
+

|
158
|
+
|
159
|
+
```ruby
|
160
|
+
template = <<~T
|
161
|
+
|--%{value}yellow|bold|underline
|
162
|
+
| |--{{%{inner_value}green|bold|underline
|
163
|
+
| | |--{{%{deep_value}blue|bold|underline
|
164
|
+
| | | |-- We're in deep!}}}}
|
165
|
+
T
|
166
|
+
|
167
|
+
Fmt template, value: "Outer", inner_value: "Inner", deep_value: "Deep"
|
168
|
+
|
169
|
+
#=> "|--\e[33m\e[1m\e[4mOuter\e[0m\n| |--\e[32m\e[1m\e[4mInner\e[0m\n| | |--\e[34m\e[1m\e[4mDeep\e[0m\n| | | |-- We're in deep!\n"
|
170
|
+
```
|
171
|
+
|
172
|
+

|
173
|
+
|
174
|
+
## Sponsors
|
175
|
+
|
176
|
+
<p align="center">
|
177
|
+
<em>Proudly sponsored by</em>
|
178
|
+
</p>
|
179
|
+
<p align="center">
|
180
|
+
<a href="https://www.clickfunnels.com?utm_source=hopsoft&utm_medium=open-source&utm_campaign=fmt">
|
181
|
+
<img src="https://images.clickfunnel.com/uploads/digital_asset/file/176632/clickfunnels-dark-logo.svg" width="575" />
|
182
|
+
</a>
|
183
|
+
</p>
|
data/lib/fmt/embed.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fmt
|
4
|
+
class Embed
|
5
|
+
def initialize(string)
|
6
|
+
@string = string
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :string
|
10
|
+
|
11
|
+
def placeholder
|
12
|
+
"{{#{string}}}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def format(**locals)
|
16
|
+
Fmt(string, **locals)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/fmt/filters.rb
CHANGED
@@ -8,8 +8,6 @@ module Fmt
|
|
8
8
|
include Enumerable
|
9
9
|
include MonitorMixin
|
10
10
|
|
11
|
-
DELIMITER = "|"
|
12
|
-
|
13
11
|
NATIVE_FILTERS = %i[
|
14
12
|
capitalize
|
15
13
|
chomp
|
@@ -36,17 +34,19 @@ module Fmt
|
|
36
34
|
end
|
37
35
|
|
38
36
|
if defined? Rainbow
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
begin
|
38
|
+
Rainbow::Presenter.public_instance_methods(false).each do |name|
|
39
|
+
next unless Rainbow::Presenter.public_instance_method(name).arity == 0
|
40
|
+
add(name) { |str| Rainbow(str).public_send(name) }
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
43
|
+
Rainbow::X11ColorNames::NAMES.keys.each do |name|
|
44
|
+
add(name) { |str| Rainbow(str).public_send(name) }
|
45
|
+
end
|
46
|
+
rescue => error
|
47
|
+
puts "Error adding Rainbow filters! #{error.inspect}"
|
46
48
|
end
|
47
49
|
end
|
48
|
-
rescue
|
49
|
-
# noop
|
50
50
|
end
|
51
51
|
|
52
52
|
def each(&block)
|
data/lib/fmt/formatter.rb
CHANGED
@@ -2,17 +2,13 @@
|
|
2
2
|
|
3
3
|
require "singleton"
|
4
4
|
require_relative "filters"
|
5
|
+
require_relative "scanners"
|
5
6
|
require_relative "transformer"
|
6
7
|
|
7
8
|
module Fmt
|
8
9
|
class Formatter
|
9
10
|
include Singleton
|
10
11
|
|
11
|
-
OPEN = /%\{/
|
12
|
-
CLOSE = /\}/
|
13
|
-
KEY = /\w+(?=\})/
|
14
|
-
FILTERS = /[^\s]+(?=\s|$)/
|
15
|
-
|
16
12
|
attr_reader :filters
|
17
13
|
|
18
14
|
def format(string, **locals)
|
@@ -35,27 +31,20 @@ module Fmt
|
|
35
31
|
end
|
36
32
|
|
37
33
|
def next_transformer(string)
|
38
|
-
|
39
|
-
|
40
|
-
# 1. advance to the opening delimiter
|
41
|
-
scanner.skip_until(OPEN)
|
42
|
-
|
43
|
-
# 2. extract the key to be transformed
|
44
|
-
key = scanner.scan(KEY)
|
34
|
+
embed_scanner = Fmt::EmbedScanner.new(string)
|
35
|
+
embed_scanner.scan
|
45
36
|
|
46
|
-
|
47
|
-
|
37
|
+
key_scanner = Fmt::KeyScanner.new(string)
|
38
|
+
key = key_scanner.scan
|
39
|
+
return nil unless key
|
48
40
|
|
49
|
-
|
50
|
-
filter_string =
|
51
|
-
|
52
|
-
return nil if key.nil? || filter_string.nil?
|
53
|
-
|
54
|
-
mapped_filters = filter_string.split(Fmt::Filters::DELIMITER).map do |name|
|
55
|
-
filters.fetch name.to_sym, Fmt::Filter.new(name, name)
|
56
|
-
end
|
41
|
+
filter_scanner = Fmt::FilterScanner.new(key_scanner.rest, registered_filters: filters)
|
42
|
+
filter_string = filter_scanner.scan
|
57
43
|
|
58
|
-
Fmt::Transformer.new
|
44
|
+
Fmt::Transformer.new key.to_sym,
|
45
|
+
embeds: embed_scanner.embeds,
|
46
|
+
filters: filter_scanner.filters,
|
47
|
+
placeholder: "%{#{key}}#{filter_string}".strip
|
59
48
|
end
|
60
49
|
end
|
61
50
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
require "strscan"
|
5
|
+
|
6
|
+
module Fmt
|
7
|
+
class BaseScanner
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def initialize(string)
|
11
|
+
@string_scanner = StringScanner.new(string)
|
12
|
+
end
|
13
|
+
|
14
|
+
def_delegators :string_scanner, :string, :rest
|
15
|
+
attr_reader :value
|
16
|
+
|
17
|
+
def performed?
|
18
|
+
!!@performed
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
@performed = false
|
23
|
+
string_scanner.reset
|
24
|
+
end
|
25
|
+
|
26
|
+
def scan
|
27
|
+
return if performed?
|
28
|
+
@performed = true
|
29
|
+
perform
|
30
|
+
value
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
attr_reader :string_scanner
|
36
|
+
|
37
|
+
def perform
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_scanner"
|
4
|
+
require_relative "../embed"
|
5
|
+
|
6
|
+
module Fmt
|
7
|
+
class EmbedScanner < BaseScanner
|
8
|
+
def initialize(string, root: nil)
|
9
|
+
super(string)
|
10
|
+
@root ||= root || self
|
11
|
+
@embeds = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def embeds
|
15
|
+
root? ? @embeds : root.embeds
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :root
|
19
|
+
|
20
|
+
def root?
|
21
|
+
root == self
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def includes_embed?(string)
|
27
|
+
string.match?(/[{]{2}/)
|
28
|
+
end
|
29
|
+
|
30
|
+
def next_scanner(string)
|
31
|
+
Fmt::EmbedScanner.new string, root: root
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan_embeds(string)
|
35
|
+
return unless includes_embed?(string)
|
36
|
+
|
37
|
+
string = string[string.index(/[{]{2}/) + 2..]
|
38
|
+
scanner = next_scanner(string)
|
39
|
+
while (embed = scanner.scan)
|
40
|
+
embeds << Fmt::Embed.new(embed)
|
41
|
+
scanner = next_scanner(scanner.rest)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def perform?
|
46
|
+
!string.start_with?("}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def perform
|
50
|
+
return unless perform?
|
51
|
+
scan_embeds string # <------------------------------------ extract embeds
|
52
|
+
string_scanner.scan_until(/[{]{2}/) # <------------------- advance to start
|
53
|
+
@value = string_scanner.scan_until(/[^}]*(?=[}]{2})/) # <- extract value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_scanner"
|
4
|
+
|
5
|
+
module Fmt
|
6
|
+
class FilterScanner < BaseScanner
|
7
|
+
DELIMITER = "|"
|
8
|
+
|
9
|
+
def initialize(string, registered_filters:)
|
10
|
+
@registered_filters = registered_filters
|
11
|
+
@filters = []
|
12
|
+
super(string)
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :filter_string, :value
|
16
|
+
attr_reader :filters
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :registered_filters
|
21
|
+
|
22
|
+
def perform
|
23
|
+
@value = string_scanner.scan(/[^\s%]+/) # <- extract value
|
24
|
+
return unless string_scanner.matched?
|
25
|
+
|
26
|
+
@filters = value.split(DELIMITER)&.map do |name|
|
27
|
+
registered_filters.fetch name.to_sym, Fmt::Filter.new(name, name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_scanner"
|
4
|
+
|
5
|
+
module Fmt
|
6
|
+
class KeyScanner < BaseScanner
|
7
|
+
protected
|
8
|
+
|
9
|
+
def perform
|
10
|
+
string_scanner.skip_until(/%[{]/) # <------------------------------ advance to start
|
11
|
+
@value = string_scanner.scan(/\w+/) if string_scanner.matched? # <- extract value
|
12
|
+
string_scanner.scan(/[}]/) if string_scanner.matched? # <---------- advance to end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/fmt/scanners.rb
ADDED
data/lib/fmt/transformer.rb
CHANGED
@@ -2,37 +2,62 @@
|
|
2
2
|
|
3
3
|
module Fmt
|
4
4
|
class Transformer
|
5
|
-
def initialize(key,
|
5
|
+
def initialize(key, embeds:, filters:, placeholder:)
|
6
6
|
@key = key
|
7
|
+
@embeds = embeds
|
7
8
|
@filters = filters
|
8
9
|
@placeholder = placeholder
|
9
10
|
end
|
10
11
|
|
11
|
-
attr_reader :key, :filters, :placeholder, :proc_filters, :string_filters
|
12
|
+
attr_reader :key, :embeds, :filters, :placeholder, :proc_filters, :string_filters
|
12
13
|
|
13
14
|
def transform(string, **locals)
|
14
|
-
|
15
|
+
string = transform_embeds(string, **locals)
|
16
|
+
|
17
|
+
raise Fmt::Error, "Missing key! :#{key} <string=#{string.inspect} locals=#{locals.inspect}>" unless locals.key?(key)
|
15
18
|
|
16
|
-
raise Fmt::Error, "Missing key :#{key} in #{locals.inspect}" unless locals.key?(key)
|
17
19
|
replacement = locals[key]
|
18
20
|
|
19
21
|
filters.each do |filter|
|
20
22
|
if filter.string?
|
21
23
|
begin
|
22
|
-
replacement =
|
24
|
+
replacement = sprintf("%#{filter.value}", replacement)
|
23
25
|
rescue => error
|
24
|
-
|
26
|
+
message = <<~MSG
|
27
|
+
Invalid filter!
|
28
|
+
#{filter.inspect}
|
29
|
+
Verify it's either a valid native filter or is registered with Fmt.
|
30
|
+
Example: Fmt.add_filter(:#{filter.name}, &block)
|
31
|
+
#{error.message}
|
32
|
+
MSG
|
33
|
+
raise Fmt::Error, message
|
25
34
|
end
|
26
35
|
elsif filter.proc?
|
27
36
|
begin
|
28
37
|
replacement = filter.value.call(replacement)
|
29
38
|
rescue => error
|
30
|
-
|
39
|
+
message = <<~MSG
|
40
|
+
Error in filter!
|
41
|
+
#{filter.inspect}
|
42
|
+
#{error.message}
|
43
|
+
MSG
|
44
|
+
raise Fmt::Error, message
|
31
45
|
end
|
32
46
|
end
|
33
47
|
end
|
34
48
|
|
35
|
-
string.sub
|
49
|
+
result = string.sub(placeholder, replacement)
|
50
|
+
defined?(Rainbow) ? Rainbow(result) : result
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def transform_embeds(string, **locals)
|
56
|
+
while embeds.any?
|
57
|
+
embed = embeds.shift
|
58
|
+
string = string.sub(embed.placeholder, embed.format(**locals))
|
59
|
+
end
|
60
|
+
string
|
36
61
|
end
|
37
62
|
end
|
38
63
|
end
|
data/lib/fmt/version.rb
CHANGED
data/lib/fmt.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fmt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Hopkins (hopsoft)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: amazing_print
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: tocer
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: yard
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,9 +159,15 @@ extra_rdoc_files: []
|
|
145
159
|
files:
|
146
160
|
- README.md
|
147
161
|
- lib/fmt.rb
|
162
|
+
- lib/fmt/embed.rb
|
148
163
|
- lib/fmt/filter.rb
|
149
164
|
- lib/fmt/filters.rb
|
150
165
|
- lib/fmt/formatter.rb
|
166
|
+
- lib/fmt/scanners.rb
|
167
|
+
- lib/fmt/scanners/base_scanner.rb
|
168
|
+
- lib/fmt/scanners/embed_scanner.rb
|
169
|
+
- lib/fmt/scanners/filter_scanner.rb
|
170
|
+
- lib/fmt/scanners/key_scanner.rb
|
151
171
|
- lib/fmt/transformer.rb
|
152
172
|
- lib/fmt/version.rb
|
153
173
|
homepage: https://github.com/hopsoft/fmt
|
@@ -171,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
191
|
- !ruby/object:Gem::Version
|
172
192
|
version: '0'
|
173
193
|
requirements: []
|
174
|
-
rubygems_version: 3.5.
|
194
|
+
rubygems_version: 3.5.11
|
175
195
|
signing_key:
|
176
196
|
specification_version: 4
|
177
197
|
summary: A simple template engine based on native Ruby String formatting mechanics
|