fmt 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![CleanShot 2024-07-26 at 01 46 26@2x](https://github.com/user-attachments/assets/bd1d67c6-1182-428b-be05-756f3d330f67)
|
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
|
+
![CleanShot 2024-07-29 at 02 42 19@2x](https://github.com/user-attachments/assets/f67dd215-b848-4a23-bd73-72822cb7d970)
|
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
|
+
![CleanShot 2024-07-29 at 02 45 27@2x](https://github.com/user-attachments/assets/1b933bf4-a62d-4913-b817-d6c69b0e7028)
|
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
|