ruby_drills 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +6 -0
  6. data/CREDITS.txt +0 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +202 -0
  9. data/NOTICE.txt +11 -0
  10. data/README.md +118 -0
  11. data/Rakefile +6 -0
  12. data/bin/ruby_drills +13 -0
  13. data/lib/ruby_drills/array/all_drill.rb +28 -0
  14. data/lib/ruby_drills/array/all_names_drill.rb +30 -0
  15. data/lib/ruby_drills/array/array_drills.rb +18 -0
  16. data/lib/ruby_drills/array/chunk_drill.rb +34 -0
  17. data/lib/ruby_drills/array/drop_while_drill.rb +27 -0
  18. data/lib/ruby_drills/array/partition_drill.rb +27 -0
  19. data/lib/ruby_drills/array/reduce_drill.rb +24 -0
  20. data/lib/ruby_drills/array/take_while_drill.rb +26 -0
  21. data/lib/ruby_drills/array/zip_drill.rb +28 -0
  22. data/lib/ruby_drills/chomper.rb +23 -0
  23. data/lib/ruby_drills/cli.rb +76 -0
  24. data/lib/ruby_drills/commands.rb +106 -0
  25. data/lib/ruby_drills/config.rb +19 -0
  26. data/lib/ruby_drills/data/gambler.ascii +65 -0
  27. data/lib/ruby_drills/drill.rb +66 -0
  28. data/lib/ruby_drills/drills.rb +52 -0
  29. data/lib/ruby_drills/hash/hash_drills.rb +17 -0
  30. data/lib/ruby_drills/sessions/collector_client.rb +39 -0
  31. data/lib/ruby_drills/sessions/local.rb +45 -0
  32. data/lib/ruby_drills/sessions/timestamp.rb +9 -0
  33. data/lib/ruby_drills/string/string_drills.rb +16 -0
  34. data/lib/ruby_drills/version.rb +3 -0
  35. data/lib/ruby_drills/welcome/welcome_drills.rb +13 -0
  36. data/lib/starter.rb +68 -0
  37. data/ruby_drills.gemspec +29 -0
  38. data/spec/commands_spec.rb +24 -0
  39. data/spec/ruby_drills_spec.rb +7 -0
  40. data/spec/sessions/timestamp_spec.rb +10 -0
  41. data/spec/spec_helper.rb +2 -0
  42. metadata +194 -0
@@ -0,0 +1,76 @@
1
+ module RubyDrills
2
+
3
+ # Manage the processing of command line options
4
+ class CLI
5
+
6
+ class << self
7
+
8
+ # @return [Proc] The Proc defining the valid command line options.
9
+ attr_accessor :options
10
+
11
+ # @return [Array] The Procs that process the parsed options.
12
+ attr_accessor :option_processors
13
+
14
+ # @return [Array<String>] The input array of strings to process
15
+ # as CLI options.
16
+ attr_accessor :input_args
17
+
18
+ # Add another set of CLI options (a Slop block)
19
+ def add_options(&block)
20
+ if options
21
+ old_options = options
22
+ self.options = proc do
23
+ instance_exec(&old_options)
24
+ instance_exec(&block)
25
+ end
26
+ else
27
+ self.options = block
28
+ end
29
+ self
30
+ end
31
+
32
+ # Add a block responsible for processing parsed options.
33
+ def process_options(&block)
34
+ self.option_processors ||= []
35
+ option_processors << block
36
+ self
37
+ end
38
+
39
+ # Clear `options` and `option_processors`
40
+ def reset
41
+ self.options = nil
42
+ self.option_processors = nil
43
+ end
44
+
45
+ def parse_options(args=ARGV.dup)
46
+ unless options
47
+ raise NoOptionsError, "No command line options defined! Use RubyDrills::CLI.add_options to add command line options."
48
+ end
49
+
50
+ self.input_args = args
51
+
52
+ opts = Slop.parse!(args, :help => true, :multiple_switches => false, &options)
53
+
54
+ # Option processors are optional.
55
+ if option_processors
56
+ option_processors.each { |processor| processor.call(opts) }
57
+ end
58
+
59
+ self
60
+ end
61
+
62
+ end
63
+
64
+ reset
65
+ end
66
+ end
67
+
68
+ RubyDrills::CLI.add_options do
69
+ on :v, :version, "Display the version" do
70
+ puts "RubyDrills version #{RubyDrills::VERSION} on Ruby #{RUBY_VERSION}"
71
+ exit
72
+ end
73
+ end.process_options do |opts|
74
+ exit if opts.help?
75
+ Starter.new
76
+ end
@@ -0,0 +1,106 @@
1
+ module Commands
2
+ GAMBLER = File.read(File.join(File.dirname(__FILE__), 'data/gambler.ascii'))
3
+
4
+ # Each command returns a response indicating whether or not the drill is complete.
5
+ def continue
6
+ puts "\nPress any key to continue:"
7
+ Chomper.get_char
8
+ system('clear');
9
+ true
10
+ end
11
+
12
+ def fail(input, message=nil)
13
+ puts "\n\tnot yet...".yellow
14
+ RubyDrills::Config::SESSIONS.attempt(self.class.name, input, reference, 'fail')
15
+ puts message.yellow unless message.nil?
16
+ false
17
+ end
18
+
19
+ def win(input)
20
+ puts "\n\t!!! WIN !!!\n".green
21
+ RubyDrills::Config::SESSIONS.attempt(self.class.name, input, reference, 'pass')
22
+ if (reference != input.strip)
23
+ puts "How does your answer compare to the reference solution?"
24
+ puts reference
25
+ end
26
+ true
27
+ end
28
+
29
+ def skip
30
+ puts "\n\tskipping...for now...".yellow
31
+ true
32
+ end
33
+
34
+ def review
35
+ puts "\n\t#{reference}".green
36
+ puts "\n\ttry this one again soon...".yellow
37
+ true
38
+ end
39
+
40
+ def fold
41
+ puts GAMBLER
42
+ puts "\nYou got to know when to hold 'em, know when to fold 'em...\n".yellow
43
+ true
44
+ end
45
+
46
+ def hint
47
+ puts hints.rotate!.last
48
+ false
49
+ end
50
+
51
+ def back
52
+ puts "\tYou're already at the first drill".yellow if !previous
53
+ previous
54
+ end
55
+
56
+ def clear
57
+ system('clear')
58
+ false
59
+ end
60
+
61
+ def help
62
+ puts %{
63
+ For each drill, type in some Ruby.
64
+ Answer correctly and you'll get a 'WIN' on the board.
65
+ Otherwise, you'll see 'not yet'.
66
+
67
+ These commands are also available to you:
68
+
69
+ help:\tthis screen
70
+ show:\tshow the problem description
71
+ hint:\tget unstuck
72
+ back:\tback to the previous drill
73
+ skip:\ton to the next drill
74
+ review:\tsee the answer
75
+ clear:\tclear the screen
76
+ menu:\tback to the main menu
77
+ exit:\tend your session}
78
+ false
79
+ end
80
+
81
+ def welcome
82
+ puts %{
83
+ Welcome to Ruby Drills!
84
+
85
+ Drills are a way to engage in deliberate practice to master a language.
86
+ Challenges in Ruby Drills focus on a specific method.
87
+ Answers typically consist of a single line.
88
+ Your objective is to complete the drill with ease and joy,
89
+ without consulting any external documentation.
90
+
91
+ -----------------------------------------------------------------------
92
+ }
93
+ end
94
+
95
+ def quit
96
+ system('clear')
97
+ puts %{
98
+ Mastery...the mysterious process during which what is at first difficult
99
+ becomes progressively easier and more pleasurable through practice.
100
+
101
+ --- George Leonard}
102
+ puts
103
+ exit
104
+ end
105
+
106
+ end
@@ -0,0 +1,19 @@
1
+ module RubyDrills
2
+ class Config
3
+
4
+ SESSIONS = Sessions::CollectorClient.new
5
+
6
+ def self.pry_config
7
+ Pry.config.pager = false
8
+
9
+ Pry.config.prompt = [
10
+ proc { |target_self, nest_level, pry|
11
+ "#{":#{nest_level}" unless nest_level.zero?}>> "
12
+ },
13
+ proc { |target_self, nest_level, pry|
14
+ "#{":#{nest_level}" unless nest_level.zero?}* "
15
+ }
16
+ ]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,65 @@
1
+ 7I,.:=,===~~,~~:~~:,~=~~:,:~~~,~::.....,..,,,,,~77:?+777I=I777?:+I?????????+,,~~
2
+ III++?,~~:~~:~=::~~.~~~~~.:~~~:,............,?7?:,:,,777I=I77I?+~,..,~::~~~~~,~~
3
+ III=?I::~~:~::~::~~.:~~~~.:~~~................,,.,,,,,,=?+?I7I???+I,~~~:~~~~:,~~
4
+ I??..:~~~~:~~,~::~:,,~~:~.:~~..................,......,.?+?77??+++?,:~~:~~~~:,~~
5
+ I??II,+=:~::~,:~:::,.~~:~.:~....................,,..,,...++I7I?++??,::~,~~::,,~~
6
+ I???=.++,,~:~:,:,~,:.~~:~.,:...................,,,,,:::,.==II?+=?I+.::~:~~~~,,~~
7
+ ????~,.,~.~::~::~~::.,~::.:.....................,~=,~+,.,,~II++=??+.::::~~::.,::
8
+ ??????~++:,~~:~:~~::,,:::......................,.,~,,::,,.=II===?=?,::::~:::.,:~
9
+ ??????..:,~,~,::::::,.~~~,................,.....,,,,,,:,.,=II===?+=,::::::::.:~~
10
+ ???I???+,?:.~::::~~:,.:~:.......................,,..,...,.=II++=?+~,::~::~::.:~~
11
+ ???????+:?:,,:::::~::.,::......................,..,,..,:..+?I+=~=+=,::~~:~:,.::~
12
+ ??I????....?.:~,::::,..~.................,,..,:.,......,..?=I=~~:+:,::~::::,.:~~
13
+ ????I.....,:,,:::::::,.:...,....,...,,,,,.,......,..,.....?=I==~:+,,::~::::..:~~
14
+ ++I..............,:~::..,,..........,,,:,,:,,:,.,..,,,,...?~+~~~,+,,::~~~::..:::
15
+ ??....................:=:..,,,....,...,,::,~::,,,,.,,,,,:.?~+~~~,~.,:,:~:::.,::~
16
+ ??:........................,==,.......,:,,,:::::,,,,,:,,,,I,=::~,~.,:::~::,.,:::
17
+ ???............................,==:...,,,,,,,,.,,:,,,::,,,I,=::,,:.,::~~::,.,::~
18
+ +?+?................................:+==,,..........,::,:~I.~,,,.:.:::~:::,.,:::
19
+ +++++,.....................................~++=,:,...,~:,??.:,,,.,.::~~~::,.::~:
20
+ +++?++?....,.....................................:==+=~~~??.,,,,.:.::~:~::,,::~,
21
+ +?????+?,..,,,,:~~+++::.,:,,,,,...................................,=I?=::,..::~.
22
+ ???????=...,,,.::~~:,:::~~,:~~==~...~?+:................................~?..::~.
23
+ ?+???+=,.....,,:.,..~:::==+===,,,=?:~++??????:.............................=:::,
24
+ ++???+,...........,~:::~=+++++++??+=+=+???==~,,..............................:,,
25
+ ++??+~.......,,...:.~~,~=+?+?+??????==+??+++=,.+?+=~,~.......................:,:
26
+ +?++=:.......=,..::I=:,~=++???????+=+=+++=+++??~~.=:~=:.~:::................::,:
27
+ ++++~........,..:=+++::~=++??++++++====++++?+I?+??+++~~:~:~~,..............~::,:
28
+ ???+,...........:++II,:~=++++?????==~~=++????+???????+~=+~~+,+.......,~::.,~:,,:
29
+ +++~............~??I=,:~==+++?????===+?I????????????++~+:.~=+:.....::~~:,.:~:,::
30
+ ++:.........:..,~+I??::~~==+?????=~:~+++++??I??????+++=+.:..~~..:::,:~~:,,~~:::,
31
+ +~..............,??I?::~~==+?????+=,,.:,,~=??I????+++=I?,...,:..::=~,:~:,~~::::~
32
+ =,..............~+???::~==+??=::,,::=:~~:,+++??+?+++II+?:,=:,..~~~~~:.....,:::~~
33
+ ...............,,????::~=+++,~.:,::::,::~::+?+?+++++??++:~=+.:++=~=~::,..,,..,~~
34
+ .................+?I?~:~=++,=,::,~::==:==~::+?+++++???I=:==:....,+~,,::~~~~:,:~:
35
+ ................:=+?+~:~=+===~++=+I?.,,==~=:+++++++?II?::=......~,,..:::~:=~~=~:
36
+ ................,????+?==+,==+=+++=+==~~,,~+?+?+++I???~~~?.....==,,=,:,,,::::~~=
37
+ ..........,.....,~==+?:,,::==+===~=~=+++++:~+++++?I?II,,.......,,,,~:,.=~,:,:::~
38
+ ......,.....,....,~:::=~,:,=+=++++=++++=++=~++++??????..........,,,,:.,+~:,,=::~
39
+ ...,...............:~,,~~:+=,?:==++++=+?+++:+++??+I?I+......,......,:.:,::,.,=::
40
+ ....,.......,....?,::.~===,~=~~=??==?I?+~+?=,..~??+?~..................:,:.:,,::
41
+ ............,..,.II,.~,~::==?~~+?+I++?I?+~+??==~+??+.......................:,.::
42
+ ...........,..,,.III...=,,,,=????+?=I7?IIII+?==?+=~...........................:~
43
+ ...,.,.....,.,.,=I7II...,,:,+:?=++?I+=+???+I????II,...........................,:
44
+ .,,........,,...IIIII7....,~:,+=?I?.,+~+?===,~IIII.............................:
45
+ ...,.,..........I=~.II=,,,,,::~::?:+=,=,=~+=IIIIII,............................,
46
+ ,,..,.,...,:.....7I..II::,,,,:,,,,,,:~~:++=?II?III=............................,
47
+ ,....,...,.,,,..,,,77777I====~:~~~~~==+++=+7III7II7.............................
48
+ ..,:,,,...:,,.,,,:I77777777I7==7==++++++=~+7I7I?77:,............................
49
+ ,,..,...::..?77777777777777777777?+=++=~~+II7I7,,.,.............................
50
+ ..,~..,,.77II77777777II77777777777777~~=:IIII,.,............................,...
51
+ ,,.,:,,,:I77777777III77777777777777777?,I7I+.,..............................,...
52
+ ,.,.,,....777II777I777777777I77777777I7III?=...................................,
53
+ :,........77I7I77I7777777777777777777777II?I,...................................
54
+ ,,,,,.....+777I777777777777777777777777777??..............................,.....
55
+ ,:,,,......77IIII77I77777777I77777777777777I..................,.................
56
+ ..,,.,.....?777777II77I7I7777777777777777I7I,...................................
57
+ ,,,.,.......77I++???????????I777777777777777,,,...........................,,.,.,
58
+ ,,..::..:+???I???I??IIIIIII7II777777777777777.,..........,...............,..,,.,
59
+ .,:,,=?I??IIIIII?I??I????????7777777777777777I.............................,.,,.
60
+ .,,,=IIIIIIII???=~,,77I777777I7777777I7III7777,...........................,...,,
61
+ :...+IIIIII?????I???IIIIIIII??III777II77I77I,,,........................,.......,
62
+ ...:??IIIIIIIIIII?IIIIIIIIIIIIII7II7I7I777II..............................,..,,,
63
+ ...:?IIIIIIIIIIII?+I??????+????I77I77777?III.,......................,.......,,,,
64
+ ,.,:?IIIIIIII?I?+++?IIIII??IIIIII7I77IIIII??...,.......................,..,,,,:,
65
+ ..:~?IIIIIIIIII7IIIIIIIIIIIIIII7777IIIIII+++.,,,,,....................,,,,,,,,,,
@@ -0,0 +1,66 @@
1
+ class Drill
2
+ include Commands
3
+ attr_accessor :next, :previous, :hints
4
+
5
+ def initialize
6
+ setup
7
+ @context = Pry.binding_for(self)
8
+ end
9
+
10
+ def drills
11
+ # Composite pattern: Allow for drill.start to work in the REPL or in tests.
12
+ [self]
13
+ end
14
+
15
+ def expected
16
+ eval(reference)
17
+ end
18
+
19
+ def done?(input)
20
+ case input.to_sym
21
+ when :menu
22
+ RubyDrills::Config::SESSIONS.command(self.class.name, input)
23
+ clear
24
+ true
25
+ when :exit
26
+ RubyDrills::Config::SESSIONS.command(self.class.name, input)
27
+ quit
28
+ when :show
29
+ RubyDrills::Config::SESSIONS.command(self.class.name, input)
30
+ show
31
+ when lambda {|s| Commands.instance_methods.include?(s) }
32
+ RubyDrills::Config::SESSIONS.command(self.class.name, input)
33
+ self.send(input)
34
+ else
35
+ check_answer(input)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def check_answer(input)
42
+ begin
43
+ Pry.run_command input, :context => @context, :output => answer = StringIO.new
44
+ Pry.run_command reference, :context => @context, :output => exp = StringIO.new
45
+
46
+ puts answer.string
47
+
48
+ return fail(input) if answer.string != exp.string
49
+ return false if !comparable_answer?(input)
50
+ win(input)
51
+ rescue SyntaxError => ex
52
+ puts "SyntaxError"
53
+ fail(input)
54
+ rescue StandardError => ex
55
+ puts "#{ex.inspect}"
56
+ fail(input)
57
+ end
58
+ end
59
+
60
+ def comparable_answer?(input)
61
+ valid?(input).tap do |pass|
62
+ fail(input, "\tyou have the right answer, but try a different method.") if !pass
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,52 @@
1
+ class Drills
2
+ include Commands
3
+
4
+ def start
5
+ drill = linked_drills[0]
6
+ while drill do
7
+ drill.show
8
+
9
+ begin
10
+ input = Readline.readline("\n>> ", true)
11
+ end while (!drill.done?(input))
12
+
13
+ case input
14
+ when 'back'
15
+ drill = drill.previous
16
+ clear
17
+ when 'menu'
18
+ break
19
+ else
20
+ drill = drill.next
21
+ continue
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+ # Creates a linked list from the array of drills
28
+ def linked_drills
29
+ ordered_drills.tap do |linked|
30
+ for i in 0..linked.size-1
31
+ linked[i].previous = linked[i-1] unless (i == 0)
32
+ linked[i].next = linked[i+1] unless (i == linked.size-1)
33
+ end
34
+ end
35
+ end
36
+
37
+ # deliver drills in random order
38
+ def ordered_drills
39
+ drills.shuffle
40
+ end
41
+
42
+ # Determines the list of drills in this directory
43
+ def drills
44
+ mod = self.class.name.gsub(/Drills/, '').downcase
45
+ Dir["#{File.dirname(__FILE__)}/#{mod}/*drill.rb"].map do |f|
46
+ require f
47
+ name = File.basename(f, '.rb')
48
+ clazz = name.split('_').map(&:capitalize).join
49
+ Module.const_get(clazz).new
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ class HashDrills < Drills
2
+
3
+ def banner
4
+ %{
5
+ Ruby Drills: Hash
6
+
7
+ A Hash is a dictionary-like collection of unique keys and their values.
8
+ Also called associative arrays, they are similar to Arrays, but where an
9
+ Array uses integers as its index, a Hash allows you to use any object type.
10
+
11
+ COMING SOON
12
+
13
+ ------------------------------------------------------------------
14
+ }
15
+ end
16
+
17
+ end
@@ -0,0 +1,39 @@
1
+ require 'securerandom'
2
+ require 'httparty'
3
+
4
+ module Sessions
5
+ class CollectorClient
6
+ include HTTParty
7
+ base_uri 'https://drill-collector.herokuapp.com'
8
+ # base_uri 'http://localhost:9091'
9
+ # debug_output $stderr
10
+
11
+ attr_reader :session_id
12
+
13
+ def initialize
14
+ @session_id = SecureRandom.urlsafe_base64
15
+ end
16
+
17
+ def command(name, input)
18
+ store({context: name, input: input, type: 'command'})
19
+ end
20
+
21
+ def attempt(name, input, reference, result)
22
+ store({context: name, input: input, reference: reference, result: result, type: 'attempt'})
23
+ end
24
+
25
+ private
26
+
27
+ def store(entry)
28
+ Thread.new do
29
+ begin
30
+ data = entry.merge(timestamp: Sessions::Timestamp.collector, session_id: @session_id)
31
+ self.class.post('/record', {:body => data})
32
+ rescue => e
33
+ # silent scream for now...
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ require 'fileutils'
2
+ require 'pstore'
3
+
4
+ module Sessions
5
+ class Local
6
+ include FileUtils
7
+
8
+ DIR = '/usr/local/var/ruby_drills'
9
+
10
+ def initialize
11
+ ensure_directory_exists
12
+ @db = PStore.new(File.join(DIR, 'progress.pstore'))
13
+ end
14
+
15
+ def command(name, input)
16
+ store({context: name, input: input, type: 'command'})
17
+ end
18
+
19
+ def attempt(name, input, reference, result)
20
+ store({context: name, input: input, reference: reference, result: result, type: 'attempt'})
21
+ end
22
+
23
+ def stats
24
+ @db.transaction(true) do
25
+ @db.roots.each do |key|
26
+ puts @db[key].inspect
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def ensure_directory_exists
34
+ FileUtils.mkdir_p(DIR) if !File.exists?(DIR)
35
+ end
36
+
37
+ def store(entry)
38
+ @db.transaction do
39
+ t = Sessions::Timestamp.collector
40
+ @db[t] = entry.merge({ time: t })
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ module Sessions
2
+ class Timestamp
3
+
4
+ def self.collector(t = Time.now)
5
+ t.strftime("%b %-d, %Y %-l:%M:%S %p %Z")
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ class StringDrills < Drills
2
+
3
+ def banner
4
+ %{
5
+ Ruby Drills: String
6
+
7
+ A String object holds and manipulates an arbitrary sequence of bytes,
8
+ typically representing characters.
9
+
10
+ COMING SOON
11
+
12
+ ------------------------------------------------------------------
13
+ }
14
+ end
15
+
16
+ end
@@ -0,0 +1,3 @@
1
+ module RubyDrills
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,13 @@
1
+ class WelcomeDrills
2
+ include Commands
3
+
4
+ def banner
5
+ welcome
6
+ end
7
+
8
+ def start
9
+ help
10
+ continue
11
+ end
12
+
13
+ end
data/lib/starter.rb ADDED
@@ -0,0 +1,68 @@
1
+ require 'slop'
2
+ require 'pry'
3
+ require 'colorize'
4
+ require 'readline'
5
+
6
+ require 'ruby_drills/version'
7
+ require 'ruby_drills/cli'
8
+ require 'ruby_drills/commands'
9
+ require 'ruby_drills/drill'
10
+ require 'ruby_drills/drills'
11
+ require 'ruby_drills/chomper'
12
+ require 'ruby_drills/sessions/collector_client'
13
+ require 'ruby_drills/sessions/timestamp'
14
+ require 'ruby_drills/config'
15
+
16
+ class Starter
17
+ include Commands
18
+
19
+ def initialize
20
+ RubyDrills::Config.pry_config
21
+ clear
22
+ welcome
23
+ menu(drills)
24
+ clear
25
+ quit
26
+ end
27
+
28
+ def menu(options)
29
+ choice = nil
30
+ valid_choices = valid_number_to_drill_associations(options)
31
+
32
+ while (choice != 'q')
33
+ if valid_choices.include?(choice)
34
+ clear
35
+ run_drill(options[choice.to_i])
36
+ elsif (choice == 's')
37
+ RubyDrills::Config::SESSIONS.stats
38
+ end
39
+
40
+ puts "\nWhat would you like to learn next?\n\n"
41
+ options.each_with_index {|opt, i| puts "\t#{i}: #{opt.capitalize}"}
42
+ puts "\n\ts: see your stats"
43
+ puts "\tq: quit"
44
+
45
+ choice = Readline.readline("\n>> ", true)
46
+ end
47
+ end
48
+
49
+ def drills
50
+ %w[welcome array string hash]
51
+ end
52
+
53
+ private
54
+
55
+ def valid_number_to_drill_associations(options)
56
+ (0...options.size).to_a.map {|x| x.to_s}
57
+ end
58
+
59
+ def run_drill(d)
60
+ require "ruby_drills/#{d}/#{d}_drills"
61
+ clazz = Module.const_get("#{d.capitalize}Drills")
62
+ drill = clazz.new
63
+ puts drill.banner
64
+ continue
65
+ drill.start
66
+ end
67
+
68
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruby_drills/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "ruby_drills"
8
+ gem.version = RubyDrills::VERSION
9
+
10
+ gem.authors = ["Bobby Norton"]
11
+ gem.email = ["bobby@testedminds.com"]
12
+ gem.description = "A deliberate practice tool for the core Ruby API's."
13
+ gem.summary = gem.description
14
+ gem.homepage = "http://rubydrills.com"
15
+ gem.license = "Apache 2.0"
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib"]
21
+
22
+ gem.add_dependency("pry", "0.9.12.1")
23
+ gem.add_dependency("colorize", "0.5.8")
24
+ gem.add_dependency("httparty", "0.11.0")
25
+
26
+ gem.add_development_dependency("rake", "10.0.4")
27
+ gem.add_development_dependency("rspec", "~> 2.14.0.rc1")
28
+ gem.add_development_dependency("wrong", "0.7.0")
29
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands do
4
+ describe "#hint" do
5
+ it "returns hints in order" do
6
+ wrapper = Class.new do
7
+ include Commands
8
+ attr_accessor :hints
9
+ def setup
10
+ @hints = %w[first second third]
11
+ end
12
+ end.new
13
+ wrapper.setup
14
+ expect(wrapper).to receive(:puts).with("first").ordered
15
+ expect(wrapper).to receive(:puts).with("second").ordered
16
+ expect(wrapper).to receive(:puts).with("third").ordered
17
+ expect(wrapper).to receive(:puts).with("first").ordered
18
+ wrapper.hint
19
+ wrapper.hint
20
+ wrapper.hint
21
+ wrapper.hint
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe "RubyDrills" do
4
+ it "should have a version number" do
5
+ assert { RubyDrills::VERSION }
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sessions::Timestamp do
4
+
5
+ specify "collector format" do
6
+ t = Time.parse("2011-10-17 22:38:00 +0600")
7
+ Sessions::Timestamp.collector(t).should == "Oct 17, 2011 11:38:00 AM CDT"
8
+ end
9
+
10
+ end
@@ -0,0 +1,2 @@
1
+ require 'starter'
2
+ require 'wrong/adapters/rspec'