fmt 0.1.2 → 0.3.0

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +170 -87
  3. data/lib/fmt/boot.rb +50 -0
  4. data/lib/fmt/lru_cache.rb +181 -0
  5. data/lib/fmt/mixins/matchable.rb +26 -0
  6. data/lib/fmt/models/arguments.rb +194 -0
  7. data/lib/fmt/models/embed.rb +48 -0
  8. data/lib/fmt/models/macro.rb +58 -0
  9. data/lib/fmt/models/model.rb +66 -0
  10. data/lib/fmt/models/pipeline.rb +47 -0
  11. data/lib/fmt/models/template.rb +55 -0
  12. data/lib/fmt/node.rb +128 -0
  13. data/lib/fmt/parsers/arguments_parser.rb +43 -0
  14. data/lib/fmt/parsers/embed_parser.rb +54 -0
  15. data/lib/fmt/parsers/macro_parser.rb +113 -0
  16. data/lib/fmt/parsers/parser.rb +56 -0
  17. data/lib/fmt/parsers/pipeline_parser.rb +41 -0
  18. data/lib/fmt/parsers/template_parser.rb +125 -0
  19. data/lib/fmt/refinements/kernel_refinement.rb +38 -0
  20. data/lib/fmt/registries/native_registry.rb +66 -0
  21. data/lib/fmt/registries/rainbow_registry.rb +36 -0
  22. data/lib/fmt/registries/registry.rb +127 -0
  23. data/lib/fmt/renderer.rb +132 -0
  24. data/lib/fmt/sigils.rb +23 -0
  25. data/lib/fmt/token.rb +126 -0
  26. data/lib/fmt/tokenizer.rb +96 -0
  27. data/lib/fmt/version.rb +3 -1
  28. data/lib/fmt.rb +51 -11
  29. data/sig/generated/fmt/boot.rbs +2 -0
  30. data/sig/generated/fmt/lru_cache.rbs +122 -0
  31. data/sig/generated/fmt/mixins/matchable.rbs +18 -0
  32. data/sig/generated/fmt/models/arguments.rbs +115 -0
  33. data/sig/generated/fmt/models/embed.rbs +34 -0
  34. data/sig/generated/fmt/models/macro.rbs +37 -0
  35. data/sig/generated/fmt/models/model.rbs +45 -0
  36. data/sig/generated/fmt/models/pipeline.rbs +31 -0
  37. data/sig/generated/fmt/models/template.rbs +33 -0
  38. data/sig/generated/fmt/node.rbs +64 -0
  39. data/sig/generated/fmt/parsers/arguments_parser.rbs +25 -0
  40. data/sig/generated/fmt/parsers/embed_parser.rbs +36 -0
  41. data/sig/generated/fmt/parsers/macro_parser.rbs +60 -0
  42. data/sig/generated/fmt/parsers/parser.rbs +44 -0
  43. data/sig/generated/fmt/parsers/pipeline_parser.rbs +25 -0
  44. data/sig/generated/fmt/parsers/template_parser.rbs +50 -0
  45. data/sig/generated/fmt/refinements/kernel_refinement.rbs +23 -0
  46. data/sig/generated/fmt/registries/native_registry.rbs +19 -0
  47. data/sig/generated/fmt/registries/rainbow_registry.rbs +11 -0
  48. data/sig/generated/fmt/registries/registry.rbs +69 -0
  49. data/sig/generated/fmt/renderer.rbs +70 -0
  50. data/sig/generated/fmt/sigils.rbs +30 -0
  51. data/sig/generated/fmt/token.rbs +77 -0
  52. data/sig/generated/fmt/tokenizer.rbs +51 -0
  53. data/sig/generated/fmt/version.rbs +5 -0
  54. data/sig/generated/fmt.rbs +41 -0
  55. metadata +126 -16
  56. data/lib/fmt/embed.rb +0 -19
  57. data/lib/fmt/filter.rb +0 -32
  58. data/lib/fmt/filters.rb +0 -76
  59. data/lib/fmt/formatter.rb +0 -50
  60. data/lib/fmt/scanners/base_scanner.rb +0 -41
  61. data/lib/fmt/scanners/embed_scanner.rb +0 -56
  62. data/lib/fmt/scanners/filter_scanner.rb +0 -31
  63. data/lib/fmt/scanners/key_scanner.rb +0 -15
  64. data/lib/fmt/scanners.rb +0 -3
  65. data/lib/fmt/transformer.rb +0 -63
data/lib/fmt/formatter.rb DELETED
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "singleton"
4
- require_relative "filters"
5
- require_relative "scanners"
6
- require_relative "transformer"
7
-
8
- module Fmt
9
- class Formatter
10
- include Singleton
11
-
12
- attr_reader :filters
13
-
14
- def format(string, **locals)
15
- result = string.to_s
16
- transformer = next_transformer(result)
17
-
18
- while transformer
19
- result = transformer.transform(result, **locals)
20
- transformer = next_transformer(result)
21
- end
22
-
23
- result
24
- end
25
-
26
- private
27
-
28
- def initialize
29
- super
30
- @filters = Fmt::Filters.new
31
- end
32
-
33
- def next_transformer(string)
34
- embed_scanner = Fmt::EmbedScanner.new(string)
35
- embed_scanner.scan
36
-
37
- key_scanner = Fmt::KeyScanner.new(string)
38
- key = key_scanner.scan
39
- return nil unless key
40
-
41
- filter_scanner = Fmt::FilterScanner.new(key_scanner.rest, registered_filters: filters)
42
- filter_string = filter_scanner.scan
43
-
44
- Fmt::Transformer.new key.to_sym,
45
- embeds: embed_scanner.embeds,
46
- filters: filter_scanner.filters,
47
- placeholder: "%{#{key}}#{filter_string}".strip
48
- end
49
- end
50
- end
@@ -1,41 +0,0 @@
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
@@ -1,56 +0,0 @@
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
@@ -1,31 +0,0 @@
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
@@ -1,15 +0,0 @@
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 DELETED
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Dir[File.join(__dir__, "scanners", "*.rb")].each { |file| require file }
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fmt
4
- class Transformer
5
- def initialize(key, embeds:, filters:, placeholder:)
6
- @key = key
7
- @embeds = embeds
8
- @filters = filters
9
- @placeholder = placeholder
10
- end
11
-
12
- attr_reader :key, :embeds, :filters, :placeholder, :proc_filters, :string_filters
13
-
14
- def transform(string, **locals)
15
- string = transform_embeds(string, **locals)
16
-
17
- raise Fmt::Error, "Missing key! :#{key} <string=#{string.inspect} locals=#{locals.inspect}>" unless locals.key?(key)
18
-
19
- replacement = locals[key]
20
-
21
- filters.each do |filter|
22
- if filter.string?
23
- begin
24
- replacement = sprintf("%#{filter.value}", replacement)
25
- rescue => error
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
34
- end
35
- elsif filter.proc?
36
- begin
37
- replacement = filter.value.call(replacement)
38
- rescue => error
39
- message = <<~MSG
40
- Error in filter!
41
- #{filter.inspect}
42
- #{error.message}
43
- MSG
44
- raise Fmt::Error, message
45
- end
46
- end
47
- end
48
-
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
61
- end
62
- end
63
- end