need_for_type 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/README.md +48 -0
- data/assets/easy/1.txt +1 -0
- data/assets/hard/1.txt +1 -0
- data/assets/medium/1.txt +1 -0
- data/bin/need_for_type +17 -0
- data/lib/need_for_type.rb +5 -0
- data/lib/need_for_type/display_window.rb +81 -0
- data/lib/need_for_type/file_manager.rb +31 -0
- data/lib/need_for_type/states.rb +9 -0
- data/lib/need_for_type/states/game.rb +113 -0
- data/lib/need_for_type/states/menu.rb +31 -0
- data/lib/need_for_type/states/score.rb +27 -0
- data/lib/need_for_type/states/state.rb +9 -0
- data/lib/need_for_type/typer.rb +23 -0
- data/lib/need_for_type/version.rb +3 -0
- data/lib/need_for_type/window.rb +62 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c9d15376668b2067a3279a2f17c32f62e209cc6c
|
4
|
+
data.tar.gz: b9c778b6ced2d63ae6f7f233a494ac274630e644
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6f8cb2a5d6424054fcb74bbc0635b05c0616ae803dac320ee10313e222237350f5d7ed5602b09fabe04bf7a3dca0f9305ee2b796d772cfef3f13a8a21c103ce1
|
7
|
+
data.tar.gz: 9a4e563fcf77a6ca9ab0bb28956e8350413f95674a2bdf21d506c5273102bd2076d7a47e4c918b3b9b6236d8404ea634fbd5c5cabe713ce8b90d6ca88be9647a
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# need-for-type
|
2
|
+
|
3
|
+
need-for-type is a terminal type racer inpired by [Nitro Type](https://www.nitrotype.com/).
|
4
|
+
|
5
|
+
![screenshot](https://raw.githubusercontent.com/jbernardo95/need-for-type/master/assets/screenshot.png)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Run the following command:
|
10
|
+
|
11
|
+
```shell
|
12
|
+
$ gem install 'need_for_type'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
On a new terminal window run the following command:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
$ need_for_type
|
21
|
+
```
|
22
|
+
|
23
|
+
## Development
|
24
|
+
|
25
|
+
After checking out the repo, run `./bin/setup` to install dependencies.
|
26
|
+
|
27
|
+
You can run `./bin/console` for an interactive prompt that will allow you to experiment.
|
28
|
+
|
29
|
+
To install the development version of the gem onto your local machine, run `bundle exec rake install`.
|
30
|
+
|
31
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jbernardo95/need-for-type. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
37
|
+
|
38
|
+
|
39
|
+
## Credits
|
40
|
+
|
41
|
+
Sample texts included in this library come from the following sources:
|
42
|
+
|
43
|
+
- http://www.lipsum.com/
|
44
|
+
- https://medium.com/@kristicoulter
|
45
|
+
|
46
|
+
## License
|
47
|
+
|
48
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/assets/easy/1.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
There is. But it's broken. I mingle empty-handed for 15 minutes, fending off well-meaning offers to get me something from the bar. After the fifth, I realize I'm going to cry if one more person offers me alcohol. I leave and cry anyway. Later I order vanilla ice cream from room service to cheer myself up.
|
data/assets/hard/1.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam suscipit porttitor arcu, eget hendrerit est iaculis a. Aliquam faucibus libero et accumsan accumsan. Duis id tellus eu tellus finibus eleifend. Sed quis elit nec metus condimentum ultricies vitae in est. Proin sit amet scelerisque odio. Aenean luctus lorem non ante hendrerit luctus. Pellentesque et tellus id lectus ornare mattis. Aenean ac dolor vitae metus iaculis mollis eu vel arcu. Donec aliquet turpis diam, sit amet finibus enim vulputate mattis. Quisque laoreet feugiat nisi eget tempus. Duis varius dapibus nulla. Etiam at elit sapien. Pellentesque dui odio, ornare id nisl elementum, consectetur hendrerit turpis. Quisque convallis sapien orci. Mauris non enim sollicitudin, fringilla justo quis, congue massa. Etiam cursus, tellus interdum mattis lacinia, urna magna luctus mauris, at egestas ante tortor a urna.
|
data/assets/medium/1.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
That second summer, I meet my friend Mindy outside San Diego, where her adopted son is days from being born. Mindy’s dark alleys were different from mine, but she walked them all the same and walked herself out of them, too. Sometimes, talking about the recent past, we blink at each other like people struggling to readjust to sunlight after a long, bad movie. More and more it’s the new that gets our attention: my new job, her newish and happy marriage, the book I’m writing and the classes she’s taking. The things we are making happen, step by step.
|
data/bin/need_for_type
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'curses'
|
4
|
+
require 'need_for_type'
|
5
|
+
require 'need_for_type/typer'
|
6
|
+
require 'need_for_type/window'
|
7
|
+
|
8
|
+
Curses.init_screen
|
9
|
+
Curses.noecho
|
10
|
+
NeedForType::Window.init_colors
|
11
|
+
|
12
|
+
begin
|
13
|
+
typer = NeedForType::Typer.new
|
14
|
+
typer.play
|
15
|
+
ensure
|
16
|
+
Curses.close_screen
|
17
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'curses'
|
2
|
+
require 'need_for_type/window'
|
3
|
+
|
4
|
+
module NeedForType
|
5
|
+
class DisplayWindow < Window
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super(Curses.lines, Curses.cols, 0, 0)
|
9
|
+
Curses.curs_set(CURSOR_INVISIBLE)
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_menu(selected_option)
|
13
|
+
self.render do
|
14
|
+
self.setpos(2, 4)
|
15
|
+
self.render_text("Need For Type", GREEN, NORMAL)
|
16
|
+
|
17
|
+
self.setpos(4, 4)
|
18
|
+
mode = standout_mode(0, selected_option)
|
19
|
+
self.render_text("1. Easy", WHITE, mode)
|
20
|
+
|
21
|
+
self.setpos(5, 4)
|
22
|
+
mode = standout_mode(1, selected_option)
|
23
|
+
self.render_text("2. Medium", WHITE, mode)
|
24
|
+
|
25
|
+
self.setpos(6, 4)
|
26
|
+
mode = standout_mode(2, selected_option)
|
27
|
+
self.render_text("3. Hard", WHITE, mode)
|
28
|
+
|
29
|
+
self.setpos(8, 4)
|
30
|
+
mode = standout_mode(3, selected_option)
|
31
|
+
self.render_text("Exit", WHITE, mode)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def standout_mode(option, selected_option)
|
36
|
+
selected_option == option ? STANDOUT : NORMAL
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_game_text(text, chars_completed, failed = false)
|
40
|
+
current_color = failed ? RED : YELLOW
|
41
|
+
completed = text[0, chars_completed - 1]
|
42
|
+
tail = text[chars_completed + 1, text.length]
|
43
|
+
|
44
|
+
self.render do
|
45
|
+
self.setpos(2,4)
|
46
|
+
self.render_multiple_text(GREEN, NORMAL) { completed.each { |c| self.addstr(c) } }
|
47
|
+
self.render_text(c, color, NORMAL)
|
48
|
+
self.render_multiple_text(WHITE, NORMAL) { tail.each { |c| self.addstr(c) } }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_game_text(text, chars_completed, failed = false)
|
53
|
+
self.render do
|
54
|
+
self.setpos(2, 4)
|
55
|
+
text.each_with_index do |c, i|
|
56
|
+
if i < chars_completed
|
57
|
+
self.render_text(c, GREEN, NORMAL)
|
58
|
+
elsif i == chars_completed
|
59
|
+
color = failed ? RED : YELLOW
|
60
|
+
self.render_text(c, color, NORMAL)
|
61
|
+
else
|
62
|
+
self.render_text(c, WHITE, NORMAL)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_score(time, wpm, accuracy)
|
69
|
+
self.render do
|
70
|
+
self.setpos(2, 4)
|
71
|
+
self.render_text("Time: #{time.round(2)} sec", GREEN, NORMAL)
|
72
|
+
|
73
|
+
self.setpos(3, 4)
|
74
|
+
self.render_text("WPM: #{wpm.round}", GREEN, NORMAL)
|
75
|
+
|
76
|
+
self.setpos(4, 4)
|
77
|
+
self.render_text("Accuracy: #{accuracy.round(2)} %", GREEN, NORMAL)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module NeedForType
|
2
|
+
class FileManager
|
3
|
+
attr_accessor :content
|
4
|
+
|
5
|
+
def initialize(difficulty)
|
6
|
+
@path = "#{NeedForType::GEM_ROOT}/assets/#{difficulty_to_s(difficulty)}/"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Reads random file from difficulty folder
|
10
|
+
def get_random_text
|
11
|
+
directory = Dir[@path]
|
12
|
+
random_file = rand(1..directory.count)
|
13
|
+
|
14
|
+
# TODO: apply markov's chain's to the text
|
15
|
+
@content = File.read("#{@path}/#{random_file}.txt").strip
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def difficulty_to_s(difficulty)
|
21
|
+
case difficulty
|
22
|
+
when 0
|
23
|
+
'easy'
|
24
|
+
when 1
|
25
|
+
'medium'
|
26
|
+
when 2
|
27
|
+
'hard'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
require 'need_for_type/states'
|
4
|
+
require 'need_for_type/file_manager'
|
5
|
+
|
6
|
+
module NeedForType::States
|
7
|
+
class Game < State
|
8
|
+
|
9
|
+
def initialize(display_window, difficulty)
|
10
|
+
super(display_window)
|
11
|
+
|
12
|
+
@difficulty = difficulty
|
13
|
+
@state = :init_game
|
14
|
+
@text = ''
|
15
|
+
end
|
16
|
+
|
17
|
+
# Takes action according to the current @state
|
18
|
+
def update
|
19
|
+
case @state
|
20
|
+
when :init_game
|
21
|
+
handle_init_game
|
22
|
+
when :in_game_get_input
|
23
|
+
handle_in_game_get_input
|
24
|
+
when :in_game_valid_input
|
25
|
+
handle_in_game_valid_input
|
26
|
+
when :in_game_invalid_input
|
27
|
+
handle_in_game_invalid_input
|
28
|
+
when :end_game
|
29
|
+
handle_end_game
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def handle_init_game
|
36
|
+
@chars_completed = 0
|
37
|
+
@word = ''
|
38
|
+
|
39
|
+
@total_taps = 0
|
40
|
+
@correct_taps = 0
|
41
|
+
|
42
|
+
file_manager = NeedForType::FileManager.new(@difficulty)
|
43
|
+
@text = file_manager.get_random_text
|
44
|
+
@split_text = @text.split('')
|
45
|
+
@display_window.render_game_text(@split_text, @chars_completed)
|
46
|
+
|
47
|
+
@start_time = Time.now
|
48
|
+
|
49
|
+
@state = :in_game_get_input
|
50
|
+
|
51
|
+
return self
|
52
|
+
end
|
53
|
+
|
54
|
+
# Gets input from user and compares it
|
55
|
+
def handle_in_game_get_input
|
56
|
+
input = @display_window.get_input
|
57
|
+
@total_taps += 1
|
58
|
+
|
59
|
+
if input == @text[@chars_completed]
|
60
|
+
@state = :in_game_valid_input
|
61
|
+
else
|
62
|
+
@state = :in_game_invalid_input
|
63
|
+
end
|
64
|
+
|
65
|
+
return self
|
66
|
+
end
|
67
|
+
|
68
|
+
# User input is correct
|
69
|
+
def handle_in_game_valid_input
|
70
|
+
@chars_completed += 1
|
71
|
+
@correct_taps += 1
|
72
|
+
|
73
|
+
if @chars_completed == @text.size
|
74
|
+
@state = :end_game
|
75
|
+
return self
|
76
|
+
end
|
77
|
+
|
78
|
+
if @text[@chars_completed] == ' '
|
79
|
+
@word = ''
|
80
|
+
else
|
81
|
+
@word += @text[@chars_completed]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Render
|
85
|
+
@display_window.render_game_text(@split_text, @chars_completed)
|
86
|
+
|
87
|
+
@state = :in_game_get_input
|
88
|
+
|
89
|
+
return self
|
90
|
+
end
|
91
|
+
|
92
|
+
# User input is wrong
|
93
|
+
def handle_in_game_invalid_input
|
94
|
+
Curses.beep
|
95
|
+
|
96
|
+
@display_window.render_game_text(@split_text, @chars_completed, true)
|
97
|
+
|
98
|
+
@state = :in_game_get_input
|
99
|
+
|
100
|
+
return self
|
101
|
+
end
|
102
|
+
|
103
|
+
def handle_end_game
|
104
|
+
@end_time = Time.now
|
105
|
+
|
106
|
+
total_time = @end_time - @start_time
|
107
|
+
wpm = (@text.split.size * 60) / total_time
|
108
|
+
accuracy = (@correct_taps.to_f / @total_taps.to_f) * 100
|
109
|
+
|
110
|
+
return NeedForType::States::Score.new(@display_window, total_time, wpm, accuracy)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
require 'need_for_type/states'
|
4
|
+
|
5
|
+
module NeedForType::States
|
6
|
+
class Menu < State
|
7
|
+
|
8
|
+
def initialize(display_window)
|
9
|
+
super(display_window)
|
10
|
+
|
11
|
+
@option = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
@display_window.render_menu(@option)
|
16
|
+
|
17
|
+
input = @display_window.get_input
|
18
|
+
|
19
|
+
if input == Curses::Key::UP
|
20
|
+
@option = (@option - 1) % 4
|
21
|
+
elsif input == Curses::Key::DOWN
|
22
|
+
@option = (@option + 1) % 4
|
23
|
+
elsif input == Curses::Key::ENTER || input == 10
|
24
|
+
exit if @option == 3
|
25
|
+
return NeedForType::States::Game.new(@display_window, @option)
|
26
|
+
end
|
27
|
+
|
28
|
+
return self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
require 'need_for_type/states'
|
4
|
+
|
5
|
+
module NeedForType::States
|
6
|
+
class Score < State
|
7
|
+
|
8
|
+
def initialize(display_window, time, wpm, accuracy)
|
9
|
+
super(display_window)
|
10
|
+
@time = time
|
11
|
+
@wpm = wpm
|
12
|
+
@accuracy = accuracy
|
13
|
+
end
|
14
|
+
|
15
|
+
def update
|
16
|
+
@display_window.render_score(@time, @wpm, @accuracy)
|
17
|
+
|
18
|
+
input = @display_window.get_input
|
19
|
+
|
20
|
+
if input == Curses::Key::ENTER || input == 10
|
21
|
+
return NeedForType::States::Menu.new(@display_window)
|
22
|
+
end
|
23
|
+
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
require 'need_for_type/display_window'
|
4
|
+
|
5
|
+
require 'need_for_type/states'
|
6
|
+
|
7
|
+
module NeedForType
|
8
|
+
class Typer
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
display_window = NeedForType::DisplayWindow.new
|
12
|
+
|
13
|
+
@state = NeedForType::States::Menu.new(display_window)
|
14
|
+
end
|
15
|
+
|
16
|
+
def play
|
17
|
+
while true
|
18
|
+
@state = @state.update
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
module NeedForType
|
4
|
+
class Window < Curses::Window
|
5
|
+
# Cursor visibility
|
6
|
+
CURSOR_VISIBLE = 1
|
7
|
+
CURSOR_INVISIBLE = 0
|
8
|
+
|
9
|
+
# Colors
|
10
|
+
WHITE = 1
|
11
|
+
GREEN = 2
|
12
|
+
YELLOW = 3
|
13
|
+
RED = 4
|
14
|
+
|
15
|
+
# Modes
|
16
|
+
NORMAL = Curses::A_NORMAL
|
17
|
+
STANDOUT = Curses::A_STANDOUT
|
18
|
+
|
19
|
+
def initialize(lines, cols, top, left)
|
20
|
+
super(lines, cols, top, left)
|
21
|
+
|
22
|
+
self.box('|', '-')
|
23
|
+
self.keypad = true
|
24
|
+
self.refresh
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.init_colors
|
28
|
+
Curses.start_color
|
29
|
+
Curses.init_pair(WHITE, Curses::COLOR_WHITE, Curses::COLOR_BLACK)
|
30
|
+
Curses.init_pair(GREEN, Curses::COLOR_GREEN, Curses::COLOR_BLACK)
|
31
|
+
Curses.init_pair(YELLOW, Curses::COLOR_YELLOW, Curses::COLOR_BLACK)
|
32
|
+
Curses.init_pair(RED, Curses::COLOR_RED, Curses::COLOR_BLACK)
|
33
|
+
end
|
34
|
+
|
35
|
+
def render(color = WHITE, mode = NORMAL)
|
36
|
+
self.attrset(Curses.color_pair(color) | mode)
|
37
|
+
|
38
|
+
self.clear
|
39
|
+
self.box('|', '-')
|
40
|
+
|
41
|
+
yield if block_given?
|
42
|
+
|
43
|
+
self.refresh
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_text(text, color = WHITE, mode = NORMAL)
|
47
|
+
self.attron(Curses.color_pair(color) | mode)
|
48
|
+
self.addstr(text)
|
49
|
+
self.attroff(Curses.color_pair(color) | mode)
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_multiple_text(color = WHITE, mode = NORMAL)
|
53
|
+
self.attron(Curses.color_pair(color) | mode)
|
54
|
+
yield
|
55
|
+
self.attroff(Curses.color_pair(color) | mode)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_input
|
59
|
+
self.getch
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: need_for_type
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- tiagonbotelho
|
8
|
+
- jbernardo95
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-08-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.10'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.10'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10.0'
|
42
|
+
description: need-for-type is a terminal type racer inpired by Nitro Type
|
43
|
+
email:
|
44
|
+
- tiagonbotelho@gmail.com
|
45
|
+
- jbamaro95@gmail.com
|
46
|
+
executables:
|
47
|
+
- need_for_type
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- Gemfile
|
52
|
+
- README.md
|
53
|
+
- assets/easy/1.txt
|
54
|
+
- assets/hard/1.txt
|
55
|
+
- assets/medium/1.txt
|
56
|
+
- bin/need_for_type
|
57
|
+
- lib/need_for_type.rb
|
58
|
+
- lib/need_for_type/display_window.rb
|
59
|
+
- lib/need_for_type/file_manager.rb
|
60
|
+
- lib/need_for_type/states.rb
|
61
|
+
- lib/need_for_type/states/game.rb
|
62
|
+
- lib/need_for_type/states/menu.rb
|
63
|
+
- lib/need_for_type/states/score.rb
|
64
|
+
- lib/need_for_type/states/state.rb
|
65
|
+
- lib/need_for_type/typer.rb
|
66
|
+
- lib/need_for_type/version.rb
|
67
|
+
- lib/need_for_type/window.rb
|
68
|
+
homepage: https://github.com/jbernardo95/need-for-type
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.6.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: A terminal typeracer
|
92
|
+
test_files: []
|