dev-ui 0.1.0 → 0.1.1

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
  SHA1:
3
- metadata.gz: '0088aa409f65b6130d130f404bb71662a06a6f3d'
4
- data.tar.gz: a1a7e7da5c2b8534882f67b22953d4fe886f4d4b
3
+ metadata.gz: cb7feeed4cd2083e294dd368521e85d4240cb954
4
+ data.tar.gz: d87bb0bab774010578bfaed70966e87e8a0222b6
5
5
  SHA512:
6
- metadata.gz: d8dc9c83e8145df6ba606ad805b9c2fd1444c372ad00cbd34e534878ba1a3f0180d00488371cac76706f22bd4d8335e1dc51a3b144fc00e08496ecd07eac471e
7
- data.tar.gz: b89f0a81a0840ed0ffde9b9f118ae4d9552b0ac4fde6505158a63ecd2bddcb4fdc8a1a74db78ffd9a7a0a27acc970cc68321905a1cfa89135299d1ad2883e2f0
6
+ metadata.gz: b371ef8177c5d3626d75c940d56b3afa40924a70fbdc0bb941b3f33c1e5253eb41118a023c6c3a72e92bd15df2bacc65dc361874cc9f4dd08162d402c9215100
7
+ data.tar.gz: 0dfc477dd137c74de7a99336478c7c120c3cd394c5e259e2b758a6777a7d1fe1eae0ab859c0728c9a224d80bd0f28601e5c2088488bf4ba4025c32dc0b42005f
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
1
  # NOTE: These are development-only dependencies
2
2
  source "https://rubygems.org"
3
3
 
4
+ gemspec
5
+
4
6
  group :development, :test do
5
7
  gem 'rubocop'
6
8
  gem 'byebug'
data/Gemfile.lock CHANGED
@@ -1,3 +1,8 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dev-ui (0.1.0)
5
+
1
6
  GEM
2
7
  remote: https://rubygems.org/
3
8
  specs:
@@ -21,7 +26,7 @@ GEM
21
26
  powerpack (0.1.1)
22
27
  rainbow (2.2.2)
23
28
  rake
24
- rake (12.0.0)
29
+ rake (10.5.0)
25
30
  rubocop (0.49.1)
26
31
  parallel (~> 1.10)
27
32
  parser (>= 2.3.3.1, < 3.0)
@@ -36,12 +41,15 @@ PLATFORMS
36
41
  ruby
37
42
 
38
43
  DEPENDENCIES
44
+ bundler (~> 1.15)
39
45
  byebug
46
+ dev-ui!
40
47
  method_source
41
48
  minitest (>= 5.0.0)
42
49
  minitest-reporters
43
50
  mocha
51
+ rake (~> 10.0)
44
52
  rubocop
45
53
 
46
54
  BUNDLED WITH
47
- 1.15.0
55
+ 1.16.0
data/README.md CHANGED
@@ -1,3 +1,125 @@
1
+ Dev UI
2
+ ---
3
+
4
+ Dev UI is a small framework who's only responsibility is to print pretty to the terminal
5
+
6
+ - [Master Documentation](http://www.rubydoc.info/github/Shopify/dev-ui/master/Dev/UI)
7
+ - [Documentation of the Rubygems version](http://www.rubydoc.info/gems/dev-ui/)
8
+ - [Rubygems](https://rubygems.org/gems/dev-ui)
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ gem install dev-ui
14
+ ```
15
+
16
+ or add the following to your Gemfile:
17
+
18
+ ```ruby
19
+ gem 'dev-ui'
20
+ ```
21
+
22
+ In your code, simply add a `require 'dev/ui'`. Most options assume `Dev::UI::StdoutRouter.enable` has been called.
23
+
24
+ ## Features
25
+
26
+ This may not be an exhaustive list. Please check our [documentation](http://www.rubydoc.info/github/Shopify/dev-ui/master/Dev/UI) for more information.
27
+
28
+ ---
29
+
30
+ ### Nested framing
31
+ To handle content flow (see example below)
32
+
33
+ ```ruby
34
+ Dev::UI::StdoutRouter.enable
35
+ Dev::UI::Frame.open('Frame 1') do
36
+ Dev::UI::Frame.open('Frame 2') { puts "inside frame 2" }
37
+ puts "inside frame 1"
38
+ end
39
+ ```
40
+
41
+ ![Nested Framing](https://user-images.githubusercontent.com/3074765/33799861-cb5dcb5c-dd01-11e7-977e-6fad38cee08c.png)
42
+
43
+ ---
44
+
45
+ ### Interactive Prompts
46
+ Prompt user with options and ask them to choose. Can answer using arrow keys, numbers, or vim bindings (or y/n for yes/no questions)
47
+
48
+ ```ruby
49
+ Dev::UI.ask('What language/framework do you use?', options: %w(rails go ruby python))
50
+ Dev::UI::InteractivePrompt.call(%w(rails go ruby python))
51
+ ```
52
+
53
+ ![Interactive Prompt](https://user-images.githubusercontent.com/3074765/33797984-0ebb5e64-dcdf-11e7-9e7e-7204f279cece.gif)
54
+
55
+ ---
56
+
57
+ ### Free form text prompts
58
+
59
+ ```ruby
60
+ Dev::UI.ask('Is Dev UI Awesome?', default: 'It is great!')
61
+ ```
62
+
63
+ ![Free form text prompt](https://user-images.githubusercontent.com/3074765/33799822-47f23302-dd01-11e7-82f3-9072a5a5f611.png)
64
+
65
+ ---
66
+
67
+ ### Spinner groups
68
+ Handle many multi-threaded processes while suppressing output unless there is an issue. Can update title to show state.
69
+
70
+ ```ruby
71
+ spin_group = Dev::UI::SpinGroup.new
72
+ spin_group.add('Title') { |spinner| sleep 3.0 }
73
+ spin_group.add('Title 2') { |spinner| sleep 3.0; spinner.update_title('New Title'); sleep 3.0 }
74
+ spin_group.wait
75
+ ```
76
+
77
+ ![Spinner Group](https://user-images.githubusercontent.com/3074765/33798295-d94fd822-dce3-11e7-819b-43e5502d490e.gif)
78
+
79
+ ---
80
+
81
+ ### Text Color formatting
82
+ e.g. `{{red:Red}} {{green:Green}}`
83
+
84
+ ```ruby
85
+ puts Dev::UI.fmt "{{red:Red}} {{green:Green}}"
86
+ ```
87
+
88
+ ![Text Format](https://user-images.githubusercontent.com/3074765/33799827-6d0721a2-dd01-11e7-9ab5-c3d455264afe.png)
89
+
90
+ ---
91
+
92
+ ### Symbol/Glyph Formatting
93
+ e.g. `{{*}}` => a yellow ⭑
94
+
95
+ ```ruby
96
+ puts Dev::UI.fmt "{{*}} {{x}} {{?}} {{v}}"
97
+ ```
98
+
99
+ ![Symbol Formatting](https://user-images.githubusercontent.com/3074765/33799847-9ec03fd0-dd01-11e7-93f7-5f5cc540e61e.png)
100
+
101
+ ---
102
+
103
+ ### Progress Bar
104
+
105
+ Show progress of a process or operation.
106
+
107
+ ```ruby
108
+ Dev::UI::Progress.progress do |bar|
109
+ 100.times do
110
+ bar.tick
111
+ end
112
+ end
113
+ ```
114
+
115
+ ![Progress Bar](https://user-images.githubusercontent.com/3074765/33799794-cc4c940e-dd00-11e7-9bdc-90f77ec9167c.gif)
116
+
117
+ ---
118
+
119
+ ## Example Usage
120
+
121
+ The following code makes use of nested-framing, multi-threaded spinners, formatted text, and more.
122
+
1
123
  ```ruby
2
124
  require 'dev/ui'
3
125
 
@@ -7,16 +129,24 @@ Dev::UI::Frame.open('{{*}} {{bold:a}}', color: :green) do
7
129
  Dev::UI::Frame.open('{{i}} b', color: :magenta) do
8
130
  Dev::UI::Frame.open('{{?}} c', color: :cyan) do
9
131
  sg = Dev::UI::SpinGroup.new
10
- sg.add('wow') { sleep(2.5) }
132
+ sg.add('wow') do |spinner|
133
+ sleep(2.5)
134
+ spinner.update_title('second round!')
135
+ sleep (1.0)
136
+ end
11
137
  sg.add('such spin') { sleep(1.6) }
12
138
  sg.add('many glyph') { sleep(2.0) }
13
139
  sg.wait
14
140
  end
15
141
  end
16
142
  Dev::UI::Frame.divider('{{v}} lol')
17
- puts 'words'
143
+ puts Dev::UI.fmt '{{info:words}} {{red:oh no!}} {{green:success!}}'
18
144
  sg = Dev::UI::SpinGroup.new
19
145
  sg.add('more spins') { sleep(0.5) ; raise 'oh no' }
20
146
  sg.wait
21
147
  end
22
148
  ```
149
+
150
+ Output:
151
+
152
+ ![Example Output](https://user-images.githubusercontent.com/3074765/33797758-7a54c7cc-dcdb-11e7-918e-a47c9689f068.gif)
data/dev.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  up:
2
- - homebrew:
3
2
  - ruby: 2.3.3
4
3
  - bundler
5
4
 
data/lib/dev/ui.rb CHANGED
@@ -12,16 +12,27 @@ module Dev
12
12
  autoload :Formatter, 'dev/ui/formatter'
13
13
  autoload :Spinner, 'dev/ui/spinner'
14
14
 
15
-
16
- # TODO: this, better
15
+ # Convenience accessor to +Dev::UI::Spinner::SpinGroup+
17
16
  SpinGroup = Spinner::SpinGroup
18
17
 
19
- # TODO: test
18
+ # Glyph resolution using +Dev::UI::Glyph.lookup+
19
+ # Look at the method signature for +Glyph.lookup+ for more details
20
+ #
21
+ # ==== Attributes
22
+ #
23
+ # * +handle+ - handle of the glyph to resolve
24
+ #
20
25
  def self.glyph(handle)
21
26
  Dev::UI::Glyph.lookup(handle)
22
27
  end
23
28
 
24
- # TODO: test
29
+ # Color resolution using +Dev::UI::Color.lookup+
30
+ # Will lookup using +Color.lookup+ if a symbol, otherwise we assume it is a valid color and return it
31
+ #
32
+ # ==== Attributes
33
+ #
34
+ # * +input+ - color to resolve
35
+ #
25
36
  def self.resolve_color(input)
26
37
  case input
27
38
  when Symbol
@@ -31,35 +42,96 @@ module Dev
31
42
  end
32
43
  end
33
44
 
45
+ # Conviencence Method for +Dev::UI::Prompt.confirm+
46
+ #
47
+ # ==== Attributes
48
+ #
49
+ # * +question+ - question to confirm
50
+ #
34
51
  def self.confirm(question)
35
52
  Dev::UI::Prompt.confirm(question)
36
53
  end
37
54
 
55
+ # Conviencence Method for +Dev::UI::Prompt.ask+
56
+ #
57
+ # ==== Attributes
58
+ #
59
+ # * +question+ - question to ask
60
+ # * +kwargs+ - arugments for +Prompt.ask+
61
+ #
38
62
  def self.ask(question, **kwargs)
39
63
  Dev::UI::Prompt.ask(question, **kwargs)
40
64
  end
41
65
 
66
+ # Conviencence Method to resolve text using +Dev::UI::Formatter.format+
67
+ # Check +Dev::UI::Formatter::SGR_MAP+ for available formatting options
68
+ #
69
+ # ==== Attributes
70
+ #
71
+ # * +input+ - input to format
72
+ #
42
73
  def self.resolve_text(input)
43
74
  return input if input.nil?
44
75
  Dev::UI::Formatter.new(input).format
45
76
  end
46
77
 
78
+ # Conviencence Method to format text using +Dev::UI::Formatter.format+
79
+ # Check +Dev::UI::Formatter::SGR_MAP+ for available formatting options
80
+ #
81
+ # https://user-images.githubusercontent.com/3074765/33799827-6d0721a2-dd01-11e7-9ab5-c3d455264afe.png
82
+ # https://user-images.githubusercontent.com/3074765/33799847-9ec03fd0-dd01-11e7-93f7-5f5cc540e61e.png
83
+ #
84
+ # ==== Attributes
85
+ #
86
+ # * +input+ - input to format
87
+ #
88
+ # ==== Options
89
+ #
90
+ # * +enable_color+ - should color be used? default to true
91
+ #
47
92
  def self.fmt(input, enable_color: true)
48
93
  Dev::UI::Formatter.new(input).format(enable_color: enable_color)
49
94
  end
50
95
 
96
+ # Conviencence Method for +Dev::UI::Frame.open+
97
+ #
98
+ # ==== Attributes
99
+ #
100
+ # * +args+ - arguments for +Frame.open+
101
+ # * +block+ - block for +Frame.open+
102
+ #
51
103
  def self.frame(*args, &block)
52
104
  Dev::UI::Frame.open(*args, &block)
53
105
  end
54
106
 
107
+ # Conviencence Method for +Dev::UI::Spinner.spin+
108
+ #
109
+ # ==== Attributes
110
+ #
111
+ # * +args+ - arguments for +Spinner.open+
112
+ # * +block+ - block for +Spinner.open+
113
+ #
55
114
  def self.spinner(*args, &block)
56
115
  Dev::UI::Spinner.spin(*args, &block)
57
116
  end
58
117
 
118
+ # Conviencence Method to override frame color using +Dev::UI::Frame.with_frame_color+
119
+ #
120
+ # ==== Attributes
121
+ #
122
+ # * +color+ - color to override to
123
+ # * +block+ - block for +Frame.with_frame_color_override+
124
+ #
59
125
  def self.with_frame_color(color, &block)
60
126
  Dev::UI::Frame.with_frame_color_override(color, &block)
61
127
  end
62
128
 
129
+ # Duplicate output to a file path
130
+ #
131
+ # ==== Attributes
132
+ #
133
+ # * +path+ - path to duplicate output to
134
+ #
63
135
  def self.log_output_to(path)
64
136
  if Dev::UI::StdoutRouter.duplicate_output_to
65
137
  raise "multiple logs not allowed"
@@ -73,6 +145,12 @@ module Dev
73
145
  end
74
146
  end
75
147
 
148
+ # Disable all framing within a block
149
+ #
150
+ # ==== Attributes
151
+ #
152
+ # * +block+ - block in which to disable frames
153
+ #
76
154
  def self.raw
77
155
  prev = Thread.current[:no_devui_frame_inset]
78
156
  Thread.current[:no_devui_frame_inset] = true
data/lib/dev/ui/ansi.rb CHANGED
@@ -7,9 +7,9 @@ module Dev
7
7
 
8
8
  # ANSI escape sequences (like \x1b[31m) have zero width.
9
9
  # when calculating the padding width, we must exclude them.
10
- # This also implements a *reaaaallly* shitty version of utf8 character
11
- # width calculation like we could get for real from something like
12
- # utf8proc.
10
+ # This also implements a basic version of utf8 character width calculation like
11
+ # we could get for real from something like utf8proc.
12
+ #
13
13
  def self.printing_width(str)
14
14
  zwj = false
15
15
  strip_codes(str).codepoints.reduce(0) do |acc, cp|
@@ -27,10 +27,23 @@ module Dev
27
27
  end
28
28
  end
29
29
 
30
+ # Strips ANSI codes from a str
31
+ #
32
+ # ==== Attributes
33
+ #
34
+ # - +str+ - The string from which to strip codes
35
+ #
30
36
  def self.strip_codes(str)
31
37
  str.gsub(/\x1b\[[\d;]+[A-z]|\r/, '')
32
38
  end
33
39
 
40
+ # Returns an ANSI control sequence
41
+ #
42
+ # ==== Attributes
43
+ #
44
+ # - +args+ - Argument to pass to the ANSI control sequence
45
+ # - +cmd+ - ANSI control sequence Command
46
+ #
34
47
  def self.control(args, cmd)
35
48
  ESC + "[" + args + cmd
36
49
  end
@@ -42,50 +55,98 @@ module Dev
42
55
 
43
56
  # Cursor Movement
44
57
 
58
+ # Move the cursor up n lines
59
+ #
60
+ # ==== Attributes
61
+ #
62
+ # * +n+ - number of lines by which to move the cursor up
63
+ #
45
64
  def self.cursor_up(n = 1)
46
65
  return '' if n.zero?
47
66
  control(n.to_s, 'A')
48
67
  end
49
68
 
69
+ # Move the cursor down n lines
70
+ #
71
+ # ==== Attributes
72
+ #
73
+ # * +n+ - number of lines by which to move the cursor down
74
+ #
50
75
  def self.cursor_down(n = 1)
51
76
  return '' if n.zero?
52
77
  control(n.to_s, 'B')
53
78
  end
54
79
 
80
+ # Move the cursor forward n columns
81
+ #
82
+ # ==== Attributes
83
+ #
84
+ # * +n+ - number of columns by which to move the cursor forward
85
+ #
55
86
  def self.cursor_forward(n = 1)
56
87
  return '' if n.zero?
57
88
  control(n.to_s, 'C')
58
89
  end
59
90
 
91
+ # Move the cursor back n columns
92
+ #
93
+ # ==== Attributes
94
+ #
95
+ # * +n+ - number of columns by which to move the cursor back
96
+ #
60
97
  def self.cursor_back(n = 1)
61
98
  return '' if n.zero?
62
99
  control(n.to_s, 'D')
63
100
  end
64
101
 
102
+ # Move the cursor to a specific column
103
+ #
104
+ # ==== Attributes
105
+ #
106
+ # * +n+ - The column to move to
107
+ #
65
108
  def self.cursor_horizontal_absolute(n = 1)
66
109
  control(n.to_s, 'G')
67
110
  end
68
111
 
69
- # Cursor Visibility
70
-
112
+ # Show the cursor
113
+ #
71
114
  def self.show_cursor
72
115
  control('', "?25h")
73
116
  end
74
117
 
118
+ # Hide the cursor
119
+ #
75
120
  def self.hide_cursor
76
121
  control('', "?25l")
77
122
  end
78
123
 
79
- # Line Handling
124
+ # Save the cursor position
125
+ #
126
+ def self.cursor_save
127
+ control('', 's')
128
+ end
129
+
130
+ # Restore the saved cursor position
131
+ #
132
+ def self.cursor_restore
133
+ control('', 'u')
134
+ end
80
135
 
136
+ # Move to the next line
137
+ #
81
138
  def self.next_line
82
139
  cursor_down + control('1', 'G')
83
140
  end
84
141
 
142
+ # Move to the previous line
143
+ #
85
144
  def self.previous_line
86
145
  cursor_up + control('1', 'G')
87
146
  end
88
147
 
148
+ # Move to the end of the line
149
+ #
89
150
  def self.end_of_line
90
151
  control("\033[", 'C')
91
152
  end