eskimo 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/eskimo.rb +20 -4
  3. data/lib/eskimo/component.rb +2 -2
  4. data/lib/eskimo/components/did_you_mean.rb +34 -0
  5. data/lib/eskimo/components/either.rb +30 -0
  6. data/lib/eskimo/components/highlight.rb +31 -0
  7. data/lib/eskimo/components/highlight_column.rb +61 -0
  8. data/lib/eskimo/components/indent.rb +25 -0
  9. data/lib/eskimo/components/line_break.rb +18 -0
  10. data/lib/eskimo/components/soft_break.rb +16 -0
  11. data/lib/eskimo/components/squeeze.rb +43 -0
  12. data/lib/eskimo/components/strip.rb +15 -0
  13. data/lib/eskimo/components/strip_left.rb +15 -0
  14. data/lib/eskimo/components/strip_right.rb +15 -0
  15. data/lib/eskimo/components/style.rb +25 -0
  16. data/lib/eskimo/components/truncate.rb +31 -0
  17. data/lib/eskimo/components/truncate_rear.rb +25 -0
  18. data/lib/eskimo/components/wrap.rb +26 -0
  19. data/lib/eskimo/constants.rb +7 -0
  20. data/lib/eskimo/renderer.rb +15 -17
  21. data/lib/eskimo/version.rb +1 -1
  22. data/spec/component_spec.rb +13 -0
  23. data/spec/components/did_you_mean_spec.rb +21 -0
  24. data/spec/components/either_spec.rb +21 -0
  25. data/spec/components/highlight_column_spec.rb +63 -0
  26. data/spec/components/highlight_spec.rb +25 -0
  27. data/spec/components/indent_spec.rb +15 -0
  28. data/spec/components/line_break_spec.rb +17 -0
  29. data/spec/components/soft_break_spec.rb +17 -0
  30. data/spec/components/squeeze_spec.rb +61 -0
  31. data/spec/components/strip_left_spec.rb +15 -0
  32. data/spec/components/strip_right_spec.rb +15 -0
  33. data/spec/components/strip_spec.rb +15 -0
  34. data/spec/components/style_spec.rb +25 -0
  35. data/spec/components/truncate_rear_spec.rb +35 -0
  36. data/spec/components/truncate_spec.rb +35 -0
  37. data/spec/components/wrap_spec.rb +15 -0
  38. data/spec/spec_helper.rb +8 -0
  39. data/spec/support/component_suite.rb +15 -0
  40. metadata +52 -5
  41. data/lib/eskimo/components.rb +0 -114
  42. data/spec/components_spec.rb +0 -159
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5912c4b1987656f45fa2fc0beb17228f1cc967db41c084675774baf24167bb9f
4
- data.tar.gz: d8f3d3d02a29fabd13444207a972e3f92e0403d1ff5612d4fc40876e1dc349d6
3
+ metadata.gz: 7882c146ce7e288df43b38765be92f216137d746c1efb13cf76b1ac7e1ec13ad
4
+ data.tar.gz: 1e2bff1433d29f448a74bf39b54b083b6bc79869af86b00c293fefaa09493624
5
5
  SHA512:
6
- metadata.gz: fa006a58bbd5ad12d24e52a3401ed14d7ecc8a98cc5e494856dcba95666df4ff3be54eab24902e8167d687f7e6d8daca5e3d33da90ddf67efdce6cc2e87cab01
7
- data.tar.gz: 4c249f2b9b14cc4521b516ba78c0f1bbbbf7454600888a4eaab4ce55492f9e51447e48897be98d47c1d639b0a41fc70c2febbed6be955a0d978bcebcd2592f87
6
+ metadata.gz: 77d8528c5d5f839c7bbf8daf9bb049fe752c5077b34107e007bdba14b1192723760763750ea4061d2a4e60bf8573c11133ff3d174363d3eadb8f2fe1252eaa11
7
+ data.tar.gz: 8dfa377b6eb2e05e09eb8e5d70b2a747fc5b9073e5859055145bf66c413e3051239ea55ca9d386936ee5905e1382dd2938140c512aaf4360af9010fb16986a49
@@ -2,9 +2,25 @@ require 'pastel'
2
2
  require 'strings'
3
3
  require 'tty-screen'
4
4
 
5
- require_relative './eskimo/version'
5
+ require 'eskimo/version'
6
6
 
7
- require_relative './eskimo/component'
8
- require_relative './eskimo/renderer'
7
+ require 'eskimo/constants'
9
8
 
10
- require_relative './eskimo/components'
9
+ require 'eskimo/component'
10
+ require 'eskimo/renderer'
11
+
12
+ require 'eskimo/components/did_you_mean'
13
+ require 'eskimo/components/either'
14
+ require 'eskimo/components/highlight'
15
+ require 'eskimo/components/highlight_column'
16
+ require 'eskimo/components/indent'
17
+ require 'eskimo/components/line_break'
18
+ require 'eskimo/components/soft_break'
19
+ require 'eskimo/components/squeeze'
20
+ require 'eskimo/components/strip'
21
+ require 'eskimo/components/strip_left'
22
+ require 'eskimo/components/strip_right'
23
+ require 'eskimo/components/style'
24
+ require 'eskimo/components/truncate'
25
+ require 'eskimo/components/truncate_rear'
26
+ require 'eskimo/components/wrap'
@@ -20,8 +20,8 @@ module Eskimo
20
20
  # `render` prop provided by {Renderer#apply} with the tracked children
21
21
  # which converts them to a String and returns them.
22
22
  class Component
23
- def initialize(&children)
24
- @children = children
23
+ def initialize(*, **, &children_gen)
24
+ @children = children_gen
25
25
  end
26
26
 
27
27
  def render(render:, **)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Present the user with the closest possible correction, if any.
6
+ #
7
+ # DidYouMean.new(dictionary: [ 'abc', 'bca' ], item: 'abd')
8
+ # # => "hint: Did you mean? abc"
9
+ #
10
+ # DidYouMean.new(dictionary: [ 'abc', 'bca' ], item: 'asdfasdf')
11
+ # # => ""
12
+ #
13
+ # See https://github.com/yuki24/did_you_mean#using-the-didyoumeanspellchecker
14
+ class DidYouMean < Component
15
+ attr_reader :corrections, :separator
16
+
17
+ def initialize(dictionary:, item:, separator: " or ", &children)
18
+ @corrections = ::DidYouMean::SpellChecker.new(
19
+ dictionary: dictionary
20
+ ).correct(item)
21
+
22
+ @separator = separator
23
+
24
+ super
25
+ end
26
+
27
+ def render(**)
28
+ if corrections.any?
29
+ "Did you mean? #{corrections.join(separator)}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Render a fallback component in case the first one evaluates to an empty
6
+ # String.
7
+ #
8
+ # Either.new(->(**) { false }, "Fallback here")
9
+ # # => "Fallback here"
10
+ #
11
+ # Either.new(->(**) { "Hi!" }, "Fallback here")
12
+ # # => "Hi!"
13
+ #
14
+ class Either
15
+ attr_reader :children
16
+
17
+ def initialize(primary, fallback)
18
+ @children = [ primary, fallback ]
19
+ end
20
+
21
+ def render(render:, **)
22
+ for child in children do
23
+ rendered = render[child]
24
+
25
+ return rendered unless rendered.empty?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Highlight a substring with ASCII arrows.
6
+ #
7
+ # Highlight.new(pattern: /lol/) do
8
+ # "- include: lol://file.yml"
9
+ # end
10
+ # # => "- include: lol://file.yml"
11
+ # # ^^^
12
+ #
13
+ class Highlight < Component
14
+ attr_reader :pastel, :pattern, :style
15
+
16
+ def initialize(pattern:, style: [:red, :bold, :underline], &children)
17
+ @pastel = Pastel.new
18
+ @pattern = pattern
19
+ @style = style
20
+
21
+ super(&children)
22
+ end
23
+
24
+ def render(**)
25
+ super.sub(pattern) do |substring|
26
+ pastel.decorate(substring, *style)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,61 @@
1
+ module Eskimo
2
+ module Components
3
+ # Highlight a particular character of a string with an ASCII arrow.
4
+ #
5
+ # HighlightColumn.new(line: 0, column: 14) do
6
+ # "- include: lol://wut.yml"
7
+ # end
8
+ # => "- include: lol://wut.yml"
9
+ # " ^ "
10
+ # " here "
11
+ class HighlightColumn < Component
12
+ def initialize(
13
+ column:,
14
+ line:,
15
+ markers: ['^', 'here'],
16
+ style: [:bold, :red],
17
+ &children
18
+ )
19
+ pastel = Pastel.new
20
+
21
+ @colorize = ->(str) { pastel.decorate(str, *style) }
22
+ @column = column
23
+ @line = line
24
+ @marker_padding = ' ' * @column
25
+ @markers = markers
26
+
27
+ super
28
+ end
29
+
30
+ def render(**)
31
+ lines = super.lines
32
+ line = lines[@line]
33
+
34
+ unless line.nil? || line[@column].nil?
35
+ lines[@line] = transform_line!(line, @column, &@colorize)
36
+ end
37
+
38
+ lines.join
39
+ end
40
+
41
+ protected
42
+
43
+ def create_markers()
44
+ buf = ''
45
+
46
+ for marker in @markers do
47
+ buf << @marker_padding + @colorize[marker] + "\n"
48
+ end
49
+
50
+ buf
51
+ end
52
+
53
+ def transform_line!(line, column, &fn)
54
+ line[column] = fn[line[column]]
55
+ line << "\n" unless line.end_with?("\n")
56
+ line << create_markers
57
+ line
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Indent text from the left.
6
+ #
7
+ # Indent.new(width: 8) do
8
+ # [ "Hello", SoftBreak.new, "World!" ]
9
+ # end
10
+ # # => " Hello"
11
+ # # " World!"
12
+ class Indent < Component
13
+ attr_reader :width
14
+
15
+ def initialize(width: 4, &children)
16
+ @width = width
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ Strings.pad(super, [0,0,0,width])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Insert a paragraph-like line-break.
6
+ #
7
+ # [ "Hello", LineBreak.new, "World!" ]
8
+ # # => "Hello"
9
+ # # ""
10
+ # # ""
11
+ # # "World!"
12
+ class LineBreak
13
+ def render(**)
14
+ "\n \n"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Insert a soft line-break.
6
+ #
7
+ # [ "Hello", SoftBreak.new, "World!" ]
8
+ # # => "Hello"
9
+ # # "World!"
10
+ class SoftBreak
11
+ def render(**)
12
+ "\n"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Squeeze immediate consecutive soft breaks.
6
+ #
7
+ # Squeeze.new do
8
+ # [
9
+ # SoftBreak.new,
10
+ # ConditionalComponent.new,
11
+ #
12
+ # SoftBreak.new,
13
+ # false && SomeOtherComponent.new,
14
+ #
15
+ # SoftBreak.new,
16
+ # 'hello',
17
+ # ]
18
+ # end
19
+ # # => ""
20
+ # # "hello"
21
+ #
22
+ # The soft breaks for each conditional component will be preserved only
23
+ # if they do render some content.
24
+ class Squeeze
25
+ def initialize(children)
26
+ if !children.is_a?(Array) || block_given?
27
+ raise ArgumentError.new("Squeeze works only with an Array of components")
28
+ end
29
+
30
+ @children = children
31
+ end
32
+
33
+ def render(**props)
34
+ rendered = @children.map(&props[:render])
35
+
36
+ without_blanks = rendered.reject(&:empty?)
37
+ without_blanks.reject.with_index do |element, index|
38
+ element == "\n" && without_blanks[index+1] == "\n"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove surrounding whitespace.
6
+ #
7
+ # Strip.new { " hello world " }
8
+ # # => "hello world"
9
+ class Strip < Component
10
+ def render(**)
11
+ super.strip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove whitespace from the beginning.
6
+ #
7
+ # StripLeft.new { " hello world " }
8
+ # # => "hello world "
9
+ class StripLeft < Component
10
+ def render(**)
11
+ super.lstrip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Remove whitespace from the end.
6
+ #
7
+ # StripRight.new { " hello world " }
8
+ # # => " hello world"
9
+ class StripRight < Component
10
+ def render(**)
11
+ super.rstrip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Style text with colors and custom formatting.
6
+ #
7
+ # See [Pastel's documentation][pastel] for the accepted styles.
8
+ #
9
+ # [pastel]: https://github.com/piotrmurach/pastel
10
+ class Style < Component
11
+ attr_reader :pastel, :style
12
+
13
+ def initialize(*style, &children)
14
+ @style = style.flatten
15
+ @pastel = Pastel.new
16
+
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ pastel.decorate(super, *style)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eskimo
4
+ module Components
5
+ # Truncate text from the beginning if it exceeds a certain width.
6
+ #
7
+ # Truncate.new(width: 3) do
8
+ # "foo bar"
9
+ # end
10
+ # # => "... bar"
11
+ class Truncate < Component
12
+ attr_reader :maxlen
13
+
14
+ def initialize(reserve: 0, width: Constants::SCREEN_COLUMNS, &children)
15
+ @maxlen = [0, width - reserve].max
16
+
17
+ super
18
+ end
19
+
20
+ def render(**)
21
+ text = super
22
+
23
+ if text.length >= maxlen
24
+ '...' + text[text.length - maxlen - 1 .. -1]
25
+ else
26
+ text
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eskimo/components/truncate'
4
+
5
+ module Eskimo
6
+ module Components
7
+ # Truncate text from the rear if it exceeds a certain width.
8
+ #
9
+ # TruncateRear.new(width: 3) do
10
+ # "foo bar"
11
+ # end
12
+ # # => "foo..."
13
+ class TruncateRear < Truncate
14
+ def render(render:, **)
15
+ text = render[@children]
16
+
17
+ if text.length >= maxlen
18
+ text[0..maxlen - 1] + '...'
19
+ else
20
+ text
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end