mustermann 1.0.2.rc1 → 1.0.2.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +799 -230
  3. data/{mustermann/bench → bench}/capturing.rb +0 -0
  4. data/{mustermann/bench → bench}/regexp.rb +0 -0
  5. data/{mustermann/bench → bench}/simple_vs_sinatra.rb +0 -0
  6. data/{mustermann/bench → bench}/template_vs_addressable.rb +0 -0
  7. data/{mustermann/lib → lib}/mustermann.rb +0 -0
  8. data/{mustermann/lib → lib}/mustermann/ast/boundaries.rb +0 -0
  9. data/{mustermann/lib → lib}/mustermann/ast/compiler.rb +0 -0
  10. data/{mustermann/lib → lib}/mustermann/ast/expander.rb +0 -0
  11. data/{mustermann/lib → lib}/mustermann/ast/node.rb +0 -0
  12. data/{mustermann/lib → lib}/mustermann/ast/param_scanner.rb +0 -0
  13. data/{mustermann/lib → lib}/mustermann/ast/parser.rb +0 -0
  14. data/{mustermann/lib → lib}/mustermann/ast/pattern.rb +0 -0
  15. data/{mustermann/lib → lib}/mustermann/ast/template_generator.rb +0 -0
  16. data/{mustermann/lib → lib}/mustermann/ast/transformer.rb +0 -0
  17. data/{mustermann/lib → lib}/mustermann/ast/translator.rb +0 -0
  18. data/{mustermann/lib → lib}/mustermann/ast/validation.rb +0 -0
  19. data/{mustermann/lib → lib}/mustermann/caster.rb +0 -0
  20. data/{mustermann/lib → lib}/mustermann/composite.rb +0 -0
  21. data/{mustermann/lib → lib}/mustermann/concat.rb +0 -0
  22. data/{mustermann/lib → lib}/mustermann/equality_map.rb +0 -0
  23. data/{mustermann/lib → lib}/mustermann/error.rb +0 -0
  24. data/{mustermann/lib → lib}/mustermann/expander.rb +0 -0
  25. data/{mustermann/lib → lib}/mustermann/extension.rb +0 -0
  26. data/{mustermann/lib → lib}/mustermann/identity.rb +0 -0
  27. data/{mustermann/lib → lib}/mustermann/mapper.rb +0 -0
  28. data/{mustermann/lib → lib}/mustermann/pattern.rb +0 -0
  29. data/{mustermann/lib → lib}/mustermann/pattern_cache.rb +0 -0
  30. data/{mustermann/lib → lib}/mustermann/regexp.rb +0 -0
  31. data/{mustermann/lib → lib}/mustermann/regexp_based.rb +0 -0
  32. data/{mustermann/lib → lib}/mustermann/regular.rb +0 -0
  33. data/{mustermann/lib → lib}/mustermann/simple_match.rb +0 -0
  34. data/{mustermann/lib → lib}/mustermann/sinatra.rb +0 -0
  35. data/{mustermann/lib → lib}/mustermann/sinatra/parser.rb +0 -0
  36. data/{mustermann/lib → lib}/mustermann/sinatra/safe_renderer.rb +0 -0
  37. data/{mustermann/lib → lib}/mustermann/sinatra/try_convert.rb +0 -0
  38. data/{mustermann/lib → lib}/mustermann/to_pattern.rb +0 -0
  39. data/{mustermann/lib → lib}/mustermann/version.rb +1 -1
  40. data/{mustermann/mustermann.gemspec → mustermann.gemspec} +0 -0
  41. data/{mustermann/spec → spec}/ast_spec.rb +0 -0
  42. data/{mustermann/spec → spec}/composite_spec.rb +0 -0
  43. data/{mustermann/spec → spec}/concat_spec.rb +0 -0
  44. data/{mustermann/spec → spec}/equality_map_spec.rb +0 -0
  45. data/{mustermann/spec → spec}/expander_spec.rb +0 -0
  46. data/{mustermann/spec → spec}/extension_spec.rb +0 -0
  47. data/{mustermann/spec → spec}/identity_spec.rb +0 -0
  48. data/{mustermann/spec → spec}/mapper_spec.rb +0 -0
  49. data/{mustermann/spec → spec}/mustermann_spec.rb +0 -0
  50. data/{mustermann/spec → spec}/pattern_spec.rb +0 -0
  51. data/{mustermann/spec → spec}/regexp_based_spec.rb +0 -0
  52. data/{mustermann/spec → spec}/regular_spec.rb +0 -0
  53. data/{mustermann/spec → spec}/simple_match_spec.rb +0 -0
  54. data/{mustermann/spec → spec}/sinatra_spec.rb +0 -0
  55. data/{mustermann/spec → spec}/to_pattern_spec.rb +0 -0
  56. metadata +71 -126
  57. data/.gitignore +0 -18
  58. data/.rspec +0 -5
  59. data/.travis.yml +0 -25
  60. data/.yardopts +0 -3
  61. data/Gemfile +0 -7
  62. data/Rakefile +0 -27
  63. data/mustermann-contrib/LICENSE +0 -23
  64. data/mustermann-contrib/README.md +0 -1155
  65. data/mustermann-contrib/examples/highlighting.rb +0 -35
  66. data/mustermann-contrib/highlighting.png +0 -0
  67. data/mustermann-contrib/irb.png +0 -0
  68. data/mustermann-contrib/lib/mustermann/cake.rb +0 -19
  69. data/mustermann-contrib/lib/mustermann/express.rb +0 -38
  70. data/mustermann-contrib/lib/mustermann/file_utils.rb +0 -218
  71. data/mustermann-contrib/lib/mustermann/file_utils/glob_pattern.rb +0 -40
  72. data/mustermann-contrib/lib/mustermann/fileutils.rb +0 -1
  73. data/mustermann-contrib/lib/mustermann/flask.rb +0 -199
  74. data/mustermann-contrib/lib/mustermann/pyramid.rb +0 -29
  75. data/mustermann-contrib/lib/mustermann/rails.rb +0 -47
  76. data/mustermann-contrib/lib/mustermann/shell.rb +0 -57
  77. data/mustermann-contrib/lib/mustermann/simple.rb +0 -51
  78. data/mustermann-contrib/lib/mustermann/string_scanner.rb +0 -314
  79. data/mustermann-contrib/lib/mustermann/strscan.rb +0 -1
  80. data/mustermann-contrib/lib/mustermann/template.rb +0 -63
  81. data/mustermann-contrib/lib/mustermann/uri_template.rb +0 -1
  82. data/mustermann-contrib/lib/mustermann/versions.rb +0 -47
  83. data/mustermann-contrib/lib/mustermann/visualizer.rb +0 -39
  84. data/mustermann-contrib/lib/mustermann/visualizer/highlight.rb +0 -138
  85. data/mustermann-contrib/lib/mustermann/visualizer/highlighter.rb +0 -38
  86. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ad_hoc.rb +0 -95
  87. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ast.rb +0 -103
  88. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/composite.rb +0 -46
  89. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/dummy.rb +0 -19
  90. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/regular.rb +0 -105
  91. data/mustermann-contrib/lib/mustermann/visualizer/pattern_extension.rb +0 -69
  92. data/mustermann-contrib/lib/mustermann/visualizer/renderer/ansi.rb +0 -24
  93. data/mustermann-contrib/lib/mustermann/visualizer/renderer/generic.rb +0 -47
  94. data/mustermann-contrib/lib/mustermann/visualizer/renderer/hansi_template.rb +0 -35
  95. data/mustermann-contrib/lib/mustermann/visualizer/renderer/html.rb +0 -51
  96. data/mustermann-contrib/lib/mustermann/visualizer/renderer/sexp.rb +0 -38
  97. data/mustermann-contrib/lib/mustermann/visualizer/tree.rb +0 -64
  98. data/mustermann-contrib/lib/mustermann/visualizer/tree_renderer.rb +0 -79
  99. data/mustermann-contrib/mustermann-contrib.gemspec +0 -19
  100. data/mustermann-contrib/spec/cake_spec.rb +0 -91
  101. data/mustermann-contrib/spec/express_spec.rb +0 -210
  102. data/mustermann-contrib/spec/file_utils_spec.rb +0 -120
  103. data/mustermann-contrib/spec/flask_spec.rb +0 -362
  104. data/mustermann-contrib/spec/flask_subclass_spec.rb +0 -369
  105. data/mustermann-contrib/spec/pattern_extension_spec.rb +0 -50
  106. data/mustermann-contrib/spec/pyramid_spec.rb +0 -102
  107. data/mustermann-contrib/spec/rails_spec.rb +0 -648
  108. data/mustermann-contrib/spec/shell_spec.rb +0 -148
  109. data/mustermann-contrib/spec/simple_spec.rb +0 -269
  110. data/mustermann-contrib/spec/string_scanner_spec.rb +0 -272
  111. data/mustermann-contrib/spec/template_spec.rb +0 -842
  112. data/mustermann-contrib/spec/visualizer_spec.rb +0 -199
  113. data/mustermann-contrib/theme.png +0 -0
  114. data/mustermann-contrib/tree.png +0 -0
  115. data/mustermann/LICENSE +0 -23
  116. data/mustermann/README.md +0 -853
  117. data/support/lib/support.rb +0 -7
  118. data/support/lib/support/coverage.rb +0 -23
  119. data/support/lib/support/env.rb +0 -19
  120. data/support/lib/support/expand_matcher.rb +0 -28
  121. data/support/lib/support/generate_template_matcher.rb +0 -27
  122. data/support/lib/support/match_matcher.rb +0 -39
  123. data/support/lib/support/pattern.rb +0 -42
  124. data/support/lib/support/projects.rb +0 -20
  125. data/support/lib/support/scan_matcher.rb +0 -63
  126. data/support/support.gemspec +0 -27
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mustermann
3
- module Visualizer
4
- # @!visibility private
5
- module Highlighter
6
- # @!visibility private
7
- module Composite
8
- extend self
9
-
10
- # @!visibility private
11
- def highlight?(pattern)
12
- pattern.is_a? Mustermann::Composite
13
- end
14
-
15
- # @!visibility private
16
- def highlight(pattern, renderer)
17
- operator = " #{pattern.operator} "
18
- patterns = pattern.patterns.map { |p| highlight_nested(p, renderer) }.join(quote(renderer, operator))
19
- renderer.pre(:composite) + patterns + renderer.post(:composite)
20
- end
21
-
22
- # @!visibility private
23
- def highlight_nested(pattern, renderer)
24
- highlighter = Highlighter.highlighter_for(pattern)
25
- if highlighter.respond_to? :nested_highlight
26
- highlighter.nested_highlight(pattern, renderer)
27
- else
28
- type = quote(renderer, pattern.class.name[/[^:]+$/].downcase + ":", :type)
29
- quote = quote(renderer, ?")
30
- type + quote + highlighter.highlight(pattern, renderer) + quote
31
- end
32
- end
33
-
34
- # @!visibility private
35
- def nested_highlight(pattern, renderer)
36
- quote(renderer, ?() + highlight(pattern, renderer) + quote(renderer, ?))
37
- end
38
-
39
- # @!visibility private
40
- def quote(renderer, string, type = :quote)
41
- renderer.pre(type) + renderer.escape(string, string) + renderer.post(type)
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mustermann
3
- module Visualizer
4
- # @!visibility private
5
- module Highlighter
6
- # Provides highlighting for patterns that don't have a highlighter.
7
- # @!visibility private
8
- module Dummy
9
- # @!visibility private
10
- def self.highlight(pattern, renderer)
11
- output = String.new
12
- output << renderer.pre(:root) << renderer.pre(:unknown)
13
- output << renderer.escape(pattern.to_s)
14
- output << renderer.post(:unknown) << renderer.post(:root)
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'strscan'
3
-
4
- module Mustermann
5
- module Visualizer
6
- # @!visibility private
7
- module Highlighter
8
- # Provides highlighting for {Mustermann::Regular}
9
- # @!visibility private
10
- class Regular
11
- # @!visibility private
12
- SPECIAL_ESCAPE = ['w', 'W', 'd', 'D', 'h', 'H', 's', 'S', 'G', 'b', 'B']
13
- private_constant(:SPECIAL_ESCAPE)
14
-
15
- # @!visibility private
16
- def self.highlight?(pattern)
17
- pattern.class.name == "Mustermann::Regular"
18
- end
19
-
20
- # @!visibility private
21
- def self.highlight(pattern, renderer)
22
- new(renderer).highlight(pattern)
23
- end
24
-
25
- # @!visibility private
26
- attr_reader :renderer, :output, :scanner
27
-
28
- # @!visibility private
29
- def initialize(renderer)
30
- @renderer = renderer
31
- @output = String.new
32
- end
33
-
34
- # @!visibility private
35
- def highlight(pattern)
36
- output << renderer.pre(:root)
37
- @scanner = ::StringScanner.new(pattern.to_s)
38
- scan
39
- output << renderer.post(:root)
40
- end
41
-
42
- # @!visibility private
43
- def scan(stop = nil)
44
- until scanner.eos?
45
- case char = scanner.getch
46
- when stop then return char
47
- when ?/ then element(:separator, char)
48
- when Regexp.escape(char) then element(:char, char)
49
- when ?\\ then escaped(scanner.getch)
50
- when ?( then potential_capture
51
- when ?[ then char_class
52
- when ?^, ?$ then element(:illegal, char)
53
- when ?{ then element(:special, "\{#{scanner.scan(/[^\}]*\}/)}")
54
- else element(:special, char)
55
- end
56
- end
57
- end
58
-
59
- # @!visibility private
60
- def char_class
61
- if result = scanner.scan(/\[:\w+:\]\]/)
62
- element(:special, "[#{result}")
63
- else
64
- element(:special, ?[)
65
- element(:special, ?^) if scanner.scan(/\^/)
66
- end
67
- end
68
-
69
- # @!visibility private
70
- def potential_capture
71
- if scanner.scan(/\?<(\w+)>/)
72
- element(:capture, "(?<") do
73
- element(:name, scanner[1])
74
- output << ">" << scan(?))
75
- end
76
- elsif scanner.scan(/\?(?:(?:-\w+)?:|>|<=|<!|!|=)/)
77
- element(:special, "(#{scanner[0]}")
78
- else
79
- element(:capture, "(") { output << scan(?)) }
80
- end
81
- end
82
-
83
- # @!visibility private
84
- def escaped(char)
85
- case char
86
- when *SPECIAL_ESCAPE then element(:special, "\\#{char}")
87
- when 'A', 'Z', 'z' then element(:illegal, "\\#{char}")
88
- when 'g' then element(:special, "\\#{char}#{scanner.scan(/<\w*>/)}")
89
- when 'p', 'u' then element(:special, "\\#{char}#{scanner.scan(/\{[^\}]*\}/)}")
90
- when ?/ then element(:separator, char)
91
- else element(:escaped, ?\\) { element(:escaped_char, char) }
92
- end
93
- end
94
-
95
- # @!visibility private
96
- def element(type, content = nil)
97
- output << renderer.pre(type)
98
- output << renderer.escape(content) if content
99
- yield if block_given?
100
- output << renderer.post(type)
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mustermann
3
- module Visualizer
4
- # Mixin that will be added to {Mustermann::Pattern}.
5
- module PatternExtension
6
- prepend_features Composite
7
- prepend_features Pattern
8
-
9
- # @example
10
- # puts Mustermann.new("/:page").to_ansi
11
- #
12
- # @return [String] ANSI colorized version of the pattern.
13
- def to_ansi(inspect: nil, **theme)
14
- Visualizer.highlight(self, **theme).to_ansi(inspect: inspect)
15
- end
16
-
17
- # @example
18
- # puts Mustermann.new("/:page").to_html
19
- #
20
- # @return [String] HTML version of the pattern.
21
- def to_html(inspect: nil, tag: :span, class_prefix: "mustermann_", css: :inline, **theme)
22
- Visualizer.highlight(self, **theme).to_html(inspect: inspect, tag: tag, class_prefix: class_prefix, css: css)
23
- end
24
-
25
- # @example
26
- # puts Mustermann.new("/:page").to_tree
27
- #
28
- # @return [String] tree version of the pattern.
29
- def to_tree
30
- Visualizer.tree(self).to_s
31
- end
32
-
33
- # If invoked directly by puts: ANSI colorized version of the pattern.
34
- # If invoked by anything else: String version of the pattern.
35
- #
36
- # @example
37
- # require 'mustermann/visualizer'
38
- # pattern = Mustermann.new('/:page')
39
- # puts pattern # will have color
40
- # puts pattern.to_s # will not have color
41
- #
42
- # @return [String] non-colorized or colorized version of the pattern
43
- def to_s
44
- caller_locations.first.label == 'puts' ? to_ansi : super
45
- end
46
-
47
- # If invoked directly by IRB, same as {#color_inspect}, otherwise same as {Mustermann::Pattern#inspect}.
48
- def inspect
49
- caller_locations.first.base_label == '<module:IRB>' ? color_inspect : super
50
- end
51
-
52
- # @return [String] ANSI colorized version of {Mustermann::Pattern#inspect}
53
- def color_inspect(base_color = nil, **theme)
54
- base_color ||= Highlight::DEFAULT_THEME[:base01]
55
- template = is_a?(Composite) ? "*#<%p:(*%s*)>*" : "*#<%p:*%s*>*"
56
- Hansi.render(template, self.class, to_ansi(inspect: true, **theme), "*" => base_color)
57
- end
58
-
59
- # If invoked directly by IRB, same as {#color_inspect}, otherwise same as Object#pretty_print.
60
- def pretty_print(q)
61
- if q.class.name.to_s[/[^:]+$/] == "ColorPrinter"
62
- q.text(color_inspect, inspect.length)
63
- else
64
- super
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mustermann
3
- module Visualizer
4
- # @!visibility private
5
- module Renderer
6
- # Generates ANSI colored strings.
7
- # @!visibility private
8
- class ANSI
9
- # @!visibility private
10
- def initialize(target, mode: Hansi.mode, **options)
11
- @target = target
12
- @mode = mode
13
- @options = options
14
- end
15
-
16
- # @!visibility private
17
- def render
18
- template = @target.to_hansi_template(**@options)
19
- Hansi.render(template, tags: true, theme: @target.theme, mode: @mode)
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
- module Mustermann
3
- module Visualizer
4
- # @!visibility private
5
- module Renderer
6
- # Logic shared by most renderers.
7
- class Generic
8
- # @!visibility private
9
- def initialize(target, inspect: nil, add_qoutes: true)
10
- @target = target
11
- @inspect = inspect
12
- @add_qoutes = !target.pattern.is_a?(Mustermann::Composite)
13
- end
14
-
15
- # @!visibility private
16
- def render
17
- quote = "#{pre(:quote)}#{escape_string(?")}#{post(:quote)}" if @inspect and @add_qoutes
18
- pre(:pattern).to_s + preamble.to_s + quote.to_s + @target.render(self) + quote.to_s + post(:pattern).to_s
19
- end
20
-
21
- # @!visibility private
22
- def preamble
23
- end
24
-
25
- # @!visibility private
26
- def escape(value, inspect_value = value.to_s.inspect[1..-2])
27
- escape_string(@inspect ? inspect_value : value.to_s)
28
- end
29
-
30
- # @!visibility private
31
- def escape_string(string)
32
- string
33
- end
34
-
35
- # @!visibility private
36
- def pre(type)
37
- ""
38
- end
39
-
40
- # @!visibility private
41
- def post(type)
42
- ""
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'mustermann/visualizer/renderer/generic'
3
-
4
- module Mustermann
5
- module Visualizer
6
- # @!visibility private
7
- module Renderer
8
- # Generates Hansi template string.
9
- # @see Mustermann::Visualizer::Renderer::ANSI
10
- # @!visibility private
11
- class HansiTemplate < Generic
12
- # @!visibility private
13
- def initialize(*)
14
- @hansi = Hansi::StringRenderer.new(tags: true)
15
- super
16
- end
17
-
18
- # @!visibility private
19
- def escape_string(string)
20
- @hansi.escape(string)
21
- end
22
-
23
- # @!visibility private
24
- def pre(type)
25
- "<#{type}>"
26
- end
27
-
28
- # @!visibility private
29
- def post(type)
30
- "</#{type}>"
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'mustermann/visualizer/renderer/generic'
3
- require 'cgi'
4
-
5
- module Mustermann
6
- module Visualizer
7
- # @!visibility private
8
- module Renderer
9
- # Generates HTML output.
10
- # @!visibility private
11
- class HTML < Generic
12
- # @!visibility private
13
- def initialize(target, tag: :span, class_prefix: "mustermann_", css: :inline, **options)
14
- raise ArgumentError, 'css option %p not supported, should be true, false or inline' if css != true and css != false and css != :inline
15
- super(target, **options)
16
- @css, @tag, @class_prefix = css, tag, class_prefix
17
- end
18
-
19
- # @!visibility private
20
- def preamble
21
- "<style type=\"text/css\">\n%s</style>" % stylesheet if @css == true
22
- end
23
-
24
- # @!visibility private
25
- def stylesheet
26
- @target.theme.to_css { |name| ".#{@class_prefix}pattern .#{@class_prefix}#{name}" }
27
- end
28
-
29
- # @!visibility private
30
- def escape_string(string)
31
- CGI.escape_html(string)
32
- end
33
-
34
- # @!visibility private
35
- def pre(type)
36
- if @css == :inline
37
- return "" unless rule = @target.theme[type]
38
- "<#{@tag} style=\"#{rule.to_css_rule}\">"
39
- else
40
- "<#{@tag} class=\"#{@class_prefix}#{type}\">"
41
- end
42
- end
43
-
44
- # @!visibility private
45
- def post(type)
46
- "</#{@tag}>"
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'mustermann/visualizer/renderer/generic'
3
-
4
- module Mustermann
5
- module Visualizer
6
- # @!visibility private
7
- module Renderer
8
- # Generates a s-expression like string.
9
- # @!visibility private
10
- class Sexp < Generic
11
- # @!visibility private
12
- def render
13
- @inspect = false
14
- super.gsub(/ ?\)( \))*/) { |s| s.gsub(' ', '') }.strip
15
- end
16
-
17
-
18
- # @!visibility private
19
- def pre(type)
20
- "(#{type} " if type != :pattern
21
- end
22
-
23
- # @!visibility private
24
- def escape_string(input)
25
- inspect = input.inspect
26
- input = inspect if inspect != "\"#{input}\""
27
- input = inspect if input =~ /[\s\"\'\(\)]/
28
- input + " "
29
- end
30
-
31
- # @!visibility private
32
- def post(type)
33
- ") " if type != :pattern
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'hansi'
3
-
4
- module Mustermann
5
- module Visualizer
6
- # Represents a (sub)tree and at the same time a node in the tree.
7
- class Tree
8
- # @!visibility private
9
- attr_reader :line, :children, :prefix_color, :before, :after
10
-
11
- # @!visibility private
12
- def initialize(line, *children, prefix_color: :default, before: "", after: "")
13
- @line = line
14
- @children = children
15
- @prefix_color = prefix_color
16
- @before = before
17
- @after = after
18
- end
19
-
20
- # used for positioning {#after}
21
- # @!visibility private
22
- def line_widths(offset = 0)
23
- child_widths = children.flat_map { |c| c.line_widths(offset + 2) }
24
- width = length(line + before) + offset
25
- [width, *child_widths]
26
- end
27
-
28
- # Renders the tree.
29
- # @return [String] rendered version of the tree
30
- def to_s
31
- render("", "", line_widths.max)
32
- end
33
-
34
- # Renders tree, including nesting.
35
- # @!visibility private
36
- def render(first_prefix, prefix, width)
37
- output = before + Hansi.render(prefix_color, first_prefix) + line
38
- output = ljust(output, width) + " " + after + "\n"
39
- children[0..-2].each { |child| output += child.render(prefix + "├ ", prefix + "│ ", width) }
40
- output += children.last.render(prefix + "└ ", prefix + " ", width) if children.last
41
- output
42
- end
43
-
44
- # @!visibility private
45
- def length(string)
46
- deansi(string).length
47
- end
48
-
49
- # @!visibility private
50
- def deansi(string)
51
- string.gsub(/\e\[[^m]+m/, '')
52
- end
53
-
54
- # @!visibility private
55
- def ljust(string, width)
56
- missing = width - length(string)
57
- append = missing > 0 ? " " * missing : ""
58
- string + append
59
- end
60
-
61
- private :ljust, :deansi, :length
62
- end
63
- end
64
- end