fmt 0.1.1 → 0.1.3

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: 55fc16022e0fcb4b8815d6e7242106018e5786a9d610f38f8040cbb31cadb1a0
4
- data.tar.gz: 185f056e8450fb1facfe15c7c637e9b49d2a19a2270689b8e12953c664393e10
3
+ metadata.gz: 7aded878eeff57ab27f37b6e76bc34281d94000c95c5d0ae77dde2bee5ab5989
4
+ data.tar.gz: 0d6390579afbfa629f0e53a127c25b60c04548b831e8ec13b9ebd8ed0880a238
5
5
  SHA512:
6
- metadata.gz: 707ed8686b167ecba644d7a2358cf179670656cd9a7eb77f6d9408b7b8d5f07a9c204ca94fcd928e8630ca5633ce716c0fb600c4bca8d8e6992a1f682fcd76dc
7
- data.tar.gz: 4b350d2ce4dd9ceeca3b7640d392b806c9698607bae33db99f18a39248898dbeef10100040f2d78dfc66f95d78839a982cf9a1cb3391129c70347f68f043bf4d
6
+ metadata.gz: 1235f7508b608760ce2f984cdcb321c01ac2a1cd3d7d5b9d1b586b45614e3b79c38bf900264b569fa469c17e34d2b6e1999984715a9b51c8caa792ee7d080aa9
7
+ data.tar.gz: '012095a10cbeac34f3457bf18ebe9135513a774984139cd1c7c300cd00d774590eff1826f7af137adbb32acd77f2eb8bffa1d52b48c579422fe43a2e7c3769cf'
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-347-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
- Fmt is a simple template engine based on native Ruby String formatting mechanics.
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
 
@@ -9,7 +38,7 @@ I'm currenly using this to help build beautiful CLI applications with Ruby. Plus
9
38
  ## Setup
10
39
 
11
40
  ```
12
- bundle add rainbow # optional
41
+ bundle add rainbow # <- optional
13
42
  bundle add fmt
14
43
  ```
15
44
 
@@ -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
- ### Rendering
67
+ ### Formatting
39
68
 
40
69
  Basic example:
41
70
 
@@ -43,8 +72,11 @@ Basic example:
43
72
  require "rainbow"
44
73
  require "fmt"
45
74
 
75
+ Fmt.add_rainbow_filters
76
+
46
77
  template = "Hello %{name}cyan|bold"
47
- result = Fmt(template, name: "World")
78
+ Fmt template, name: "World"
79
+
48
80
  #=> "Hello \e[36m\e[1mWorld\e[0m"
49
81
  ```
50
82
 
@@ -56,8 +88,11 @@ Mix and match native formatting with Rainbow formatting:
56
88
  require "rainbow"
57
89
  require "fmt"
58
90
 
91
+ Fmt.add_rainbow_filters
92
+
59
93
  template = "Date: %{date}.10s|magenta"
60
- result = Fmt(template, date: Time.now)
94
+ Fmt template, date: Time.now
95
+
61
96
  #=> "Date: \e[35m2024-07-26\e[0m"
62
97
  ```
63
98
 
@@ -69,6 +104,8 @@ Multiline example:
69
104
  require "rainbow"
70
105
  require "fmt"
71
106
 
107
+ Fmt.add_rainbow_filters
108
+
72
109
  template = <<~T
73
110
  Date: %{date}.10s|underline
74
111
 
@@ -77,7 +114,8 @@ template = <<~T
77
114
  %{message}strip|green
78
115
  T
79
116
 
80
- result = Fmt(template, date: Time.now, name: "Hopsoft", message: "This is neat!")
117
+ Fmt template, date: Time.now, name: "Hopsoft", message: "This is neat!"
118
+
81
119
  #=> "Date: \e[4m2024-07-26\e[0m\n\nGreetings, \e[1mHOPSOFT\e[0m\n\n\e[32mThis is neat!\e[0m\n"
82
120
  ```
83
121
 
@@ -92,16 +130,63 @@ The block accepts a string and should return a replacement string.
92
130
  require "rainbow"
93
131
  require "fmt"
94
132
 
95
- Fmt.add_filter(:repeat20) { |str| str * 20 }
133
+ Fmt.add_rainbow_filters
134
+ Fmt.add_filter(:ljust) { |val| "".ljust 14, val.to_s }
96
135
 
97
136
  template = <<~T
98
- %{head}repeat20|faint
137
+ %{head}ljust|faint
99
138
  %{message}bold
100
- %{tail}repeat20|faint
139
+ %{tail}ljust|faint
101
140
  T
102
141
 
103
- result = Fmt(template, head: "#", message: "Give it a try!", tail: "#")
104
- #=> "\e[2m####################\e[0m\n\e[1mGive it a try!\e[0m\n\e[2m####################\e[0m\n"
142
+ Fmt template, head: "#", message: "Give it a try!", tail: "#"
143
+
144
+ #=> "\e[2m##############\e[0m\n\e[1mGive it a try!\e[0m\n\e[2m##############\e[0m\n"
105
145
  ```
106
146
 
107
147
  ![CleanShot 2024-07-26 at 01 46 26@2x](https://github.com/user-attachments/assets/bd1d67c6-1182-428b-be05-756f3d330f67)
148
+
149
+ ### Embeds
150
+
151
+ Templates can be embedded or nested within other templates... as deep as needed!
152
+ Just wrap the embedded template in double curly braces: `{{EMBEDDED TEMPLATE HERE}}`
153
+
154
+ ```ruby
155
+ require "rainbow"
156
+ require "fmt"
157
+
158
+ Fmt.add_rainbow_filters
159
+
160
+ template = "%{value}lime {{%{embed_value}red|bold|underline}}"
161
+ Fmt template, value: "Outer", embed_value: "Inner"
162
+
163
+ #=> "\e[38;5;46mOuter\e[0m \e[31m\e[1m\e[4mInner\e[0m"
164
+ ```
165
+
166
+ ![CleanShot 2024-07-29 at 02 42 19@2x](https://github.com/user-attachments/assets/f67dd215-b848-4a23-bd73-72822cb7d970)
167
+
168
+ ```ruby
169
+ template = <<~T
170
+ |--%{value}yellow|bold|underline
171
+ | |--{{%{inner_value}green|bold|underline
172
+ | | |--{{%{deep_value}blue|bold|underline
173
+ | | | |-- We're in deep!}}}}
174
+ T
175
+
176
+ Fmt template, value: "Outer", inner_value: "Inner", deep_value: "Deep"
177
+
178
+ #=> "|--\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"
179
+ ```
180
+
181
+ ![CleanShot 2024-07-29 at 02 45 27@2x](https://github.com/user-attachments/assets/1b933bf4-a62d-4913-b817-d6c69b0e7028)
182
+
183
+ ## Sponsors
184
+
185
+ <p align="center">
186
+ <em>Proudly sponsored by</em>
187
+ </p>
188
+ <p align="center">
189
+ <a href="https://www.clickfunnels.com?utm_source=hopsoft&utm_medium=open-source&utm_campaign=fmt">
190
+ <img src="https://images.clickfunnel.com/uploads/digital_asset/file/176632/clickfunnels-dark-logo.svg" width="575" />
191
+ </a>
192
+ </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
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+ require_relative "../filter"
5
+
6
+ module Fmt
7
+ class FilterGroup
8
+ include Enumerable
9
+ include MonitorMixin
10
+
11
+ def initialize
12
+ super
13
+ @data = {}
14
+ end
15
+
16
+ def [](name)
17
+ synchronize { data[name.to_sym] }
18
+ end
19
+
20
+ def add(name, filter_proc = nil, &block)
21
+ raise ArgumentError, "filter_proc and block are mutually exclusive" if filter_proc && block
22
+ raise ArgumentError, "filter_proc must be a Proc" unless block || filter_proc.is_a?(Proc)
23
+ synchronize do
24
+ data[name.to_sym] = Fmt::Filter.new(name.to_sym, filter_proc || block)
25
+ end
26
+ end
27
+
28
+ def each(&block)
29
+ synchronize { data.each(&block) }
30
+ end
31
+
32
+ def fetch(name, default = nil)
33
+ synchronize { data.fetch name.to_sym, default }
34
+ end
35
+
36
+ def key?(name)
37
+ synchronize { data.key? name.to_sym }
38
+ end
39
+
40
+ alias_method :added?, :key?
41
+ alias_method :include?, :key?
42
+
43
+ def merge!(other)
44
+ synchronize { data.merge! other.to_h }
45
+ self
46
+ end
47
+
48
+ def to_h
49
+ data.dup
50
+ end
51
+
52
+ protected
53
+
54
+ attr_reader :data
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "filter_group"
4
+
5
+ module Fmt
6
+ class RainbowFilterGroup < FilterGroup
7
+ def initialize
8
+ super
9
+
10
+ if defined? Rainbow
11
+ methods = Rainbow::Presenter.public_instance_methods(false).select do |method|
12
+ Rainbow::Presenter.public_instance_method(method).arity == 0
13
+ end
14
+
15
+ method_names = methods
16
+ .map { |m| m.name.to_sym }
17
+ .concat(Rainbow::X11ColorNames::NAMES.keys)
18
+
19
+ method_names.each do |name|
20
+ add(name) { |string| Rainbow(string).public_send name }
21
+ end
22
+ end
23
+ rescue => error
24
+ puts "Error adding Rainbow filters! #{error.inspect}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "filter_group"
4
+
5
+ module Fmt
6
+ class StringFilterGroup < FilterGroup
7
+ def initialize
8
+ super
9
+
10
+ # rubocop:disable Layout/ExtraSpacing AllowForAlignment
11
+ add :capitalize, ->(s) { s.capitalize }
12
+ add :chomp, ->(s) { s.chomp }
13
+ add :chop, ->(s) { s.chop }
14
+ add :downcase, ->(s) { s.downcase }
15
+ add :lstrip, ->(s) { s.lstrip }
16
+ add :reverse, ->(s) { s.reverse }
17
+ add :rstrip, ->(s) { s.rstrip }
18
+ add :shellescape, ->(s) { s.shellescape }
19
+ add :strip, ->(s) { s.strip }
20
+ add :succ, ->(s) { s.succ }
21
+ add :swapcase, ->(s) { s.swapcase }
22
+ add :undump, ->(s) { s.undump }
23
+ add :unicode_normalize, ->(s) { s.unicode_normalize }
24
+ add :upcase, ->(s) { s.upcase }
25
+ # rubocop:enable Layout/ExtraSpacing AllowForAlignment
26
+ end
27
+ end
28
+ end
data/lib/fmt/formatter.rb CHANGED
@@ -1,20 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "singleton"
4
- require_relative "filters"
4
+ require_relative "filter_groups/filter_group"
5
+ require_relative "filter_groups/rainbow_filter_group"
6
+ require_relative "filter_groups/string_filter_group"
7
+ require_relative "scanners"
5
8
  require_relative "transformer"
6
9
 
7
10
  module Fmt
8
11
  class Formatter
9
12
  include Singleton
10
13
 
11
- OPEN = /%\{/
12
- CLOSE = /\}/
13
- KEY = /\w+(?=\})/
14
- FILTERS = /[^\s]+(?=\s|$)/
15
-
16
14
  attr_reader :filters
17
15
 
16
+ def add_rainbow_filters
17
+ filters.merge! Fmt::RainbowFilterGroup.new.to_h
18
+ end
19
+
20
+ def add_filter(...)
21
+ filters.add(...)
22
+ end
23
+
18
24
  def format(string, **locals)
19
25
  result = string.to_s
20
26
  transformer = next_transformer(result)
@@ -31,31 +37,24 @@ module Fmt
31
37
 
32
38
  def initialize
33
39
  super
34
- @filters = Fmt::Filters.new
40
+ @filters = Fmt::FilterGroup.new.merge!(Fmt::StringFilterGroup.new)
35
41
  end
36
42
 
37
43
  def next_transformer(string)
38
- scanner = StringScanner.new(string)
44
+ embed_scanner = Fmt::EmbedScanner.new(string)
45
+ embed_scanner.scan
39
46
 
40
- # 1. advance to the opening delimiter
41
- scanner.skip_until(OPEN)
47
+ key_scanner = Fmt::KeyScanner.new(string)
48
+ key = key_scanner.scan
49
+ return nil unless key
42
50
 
43
- # 2. extract the key to be transformed
44
- key = scanner.scan(KEY)
45
-
46
- # 3. advance to the closing delimiter
47
- scanner.skip_until(CLOSE) if key
48
-
49
- # 4. scan for the filters
50
- filter_string = scanner.scan(FILTERS) if key
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
51
+ filter_scanner = Fmt::FilterScanner.new(key_scanner.rest, registered_filters: filters)
52
+ filter_string = filter_scanner.scan
57
53
 
58
- Fmt::Transformer.new(key.to_sym, *mapped_filters, placeholder: "%{#{key}}#{filter_string}".strip)
54
+ Fmt::Transformer.new key.to_sym,
55
+ embeds: embed_scanner.embeds,
56
+ filters: filter_scanner.filters,
57
+ placeholder: "%{#{key}}#{filter_string}".strip
59
58
  end
60
59
  end
61
60
  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
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(__dir__, "scanners", "*.rb")].each { |file| require file }
@@ -2,37 +2,56 @@
2
2
 
3
3
  module Fmt
4
4
  class Transformer
5
- def initialize(key, *filters, placeholder:)
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
- return string if filters.none?
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 = format("%#{filter.value}", replacement)
23
- rescue => error
24
- raise Fmt::Error, "Invalid filter! #{filter.inspect} Check the spelling and verify that it's registered `Fmt.add_filter(:#{filter.name}, &block)`; #{error.message}"
24
+ replacement = sprintf("%#{filter.value}", replacement)
25
+ rescue
26
+ raise Fmt::Error, <<~MSG
27
+ Invalid filter! #{filter.inspect}
28
+ Verify it has been properly registered. SEE: Fmt.add_filter(:#{filter.name}, &block)
29
+ MSG
25
30
  end
26
31
  elsif filter.proc?
27
32
  begin
28
33
  replacement = filter.value.call(replacement)
29
34
  rescue => error
30
- raise Fmt::Error, "Error in filter! #{filter.inspect} #{error.message}"
35
+ raise Fmt::Error, <<~MSG
36
+ Error in filter! #{filter.inspect}
37
+ #{error.message}
38
+ MSG
31
39
  end
32
40
  end
33
41
  end
34
42
 
35
- string.sub placeholder, replacement
43
+ result = string.sub(placeholder, replacement)
44
+ defined?(Rainbow) ? Rainbow(result) : result
45
+ end
46
+
47
+ private
48
+
49
+ def transform_embeds(string, **locals)
50
+ while embeds.any?
51
+ embed = embeds.shift
52
+ string = string.sub(embed.placeholder, embed.format(**locals))
53
+ end
54
+ string
36
55
  end
37
56
  end
38
57
  end
data/lib/fmt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fmt
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/fmt.rb CHANGED
@@ -11,8 +11,16 @@ module Fmt
11
11
  Formatter.instance
12
12
  end
13
13
 
14
+ def filters
15
+ formatter.filters
16
+ end
17
+
18
+ def add_rainbow_filters
19
+ formatter.add_rainbow_filters
20
+ end
21
+
14
22
  def add_filter(...)
15
- formatter.filters.add(...)
23
+ formatter.add_filter(...)
16
24
  end
17
25
  end
18
26
  end
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.1
4
+ version: 0.1.3
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-26 00:00:00.000000000 Z
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,17 @@ 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
- - lib/fmt/filters.rb
164
+ - lib/fmt/filter_groups/filter_group.rb
165
+ - lib/fmt/filter_groups/rainbow_filter_group.rb
166
+ - lib/fmt/filter_groups/string_filter_group.rb
150
167
  - lib/fmt/formatter.rb
168
+ - lib/fmt/scanners.rb
169
+ - lib/fmt/scanners/base_scanner.rb
170
+ - lib/fmt/scanners/embed_scanner.rb
171
+ - lib/fmt/scanners/filter_scanner.rb
172
+ - lib/fmt/scanners/key_scanner.rb
151
173
  - lib/fmt/transformer.rb
152
174
  - lib/fmt/version.rb
153
175
  homepage: https://github.com/hopsoft/fmt
@@ -171,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
193
  - !ruby/object:Gem::Version
172
194
  version: '0'
173
195
  requirements: []
174
- rubygems_version: 3.5.5
196
+ rubygems_version: 3.5.11
175
197
  signing_key:
176
198
  specification_version: 4
177
199
  summary: A simple template engine based on native Ruby String formatting mechanics
data/lib/fmt/filters.rb DELETED
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "monitor"
4
- require_relative "filter"
5
-
6
- module Fmt
7
- class Filters
8
- include Enumerable
9
- include MonitorMixin
10
-
11
- DELIMITER = "|"
12
-
13
- NATIVE_FILTERS = %i[
14
- capitalize
15
- chomp
16
- chop
17
- downcase
18
- lstrip
19
- reverse
20
- rstrip
21
- shellescape
22
- strip
23
- succ
24
- swapcase
25
- undump
26
- unicode_normalize
27
- upcase
28
- ]
29
-
30
- def initialize
31
- super
32
- @entries = {}
33
-
34
- NATIVE_FILTERS.each do |name|
35
- add(name) { |str| str.then(&:"#{name}") }
36
- end
37
-
38
- if defined? Rainbow
39
- Rainbow::Presenter.public_instance_methods(false).each do |name|
40
- next unless Rainbow::Presenter.public_instance_method(name).arity == 0
41
- add(name) { |str| Rainbow(str).public_send(name) }
42
- end
43
-
44
- Rainbow::X11ColorNames::NAMES.keys.each do |name|
45
- add(name) { |str| Rainbow(str).public_send(name) }
46
- end
47
- end
48
- rescue
49
- # noop
50
- end
51
-
52
- def each(&block)
53
- entries.each(&block)
54
- end
55
-
56
- def add(name, filter = nil, &block)
57
- raise ArgumentError, "filter and block are mutually exclusive" if filter && block
58
- raise ArgumentError, "filter must be a Proc" unless block || filter.is_a?(Proc)
59
- entries[name.to_sym] = Filter.new(name, filter || block)
60
- end
61
-
62
- alias_method :<<, :add
63
-
64
- def [](name)
65
- synchronize { entries[name.to_sym] }
66
- end
67
-
68
- def fetch(name, default = nil)
69
- synchronize { entries.fetch name.to_sym, default }
70
- end
71
-
72
- private
73
-
74
- attr_reader :entries
75
- end
76
- end