tryruby 0.0.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 +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/bin/tryruby +21 -0
- data/lib/tryruby.rb +5 -0
- data/lib/tryruby/challenge.rb +28 -0
- data/lib/tryruby/challenge_builder.rb +32 -0
- data/lib/tryruby/colors.rb +43 -0
- data/lib/tryruby/commands.rb +18 -0
- data/lib/tryruby/default_levels.rb +858 -0
- data/lib/tryruby/level.rb +23 -0
- data/lib/tryruby/level_builder.rb +21 -0
- data/lib/tryruby/next_fix.rb +9 -0
- data/lib/tryruby/runner.rb +19 -0
- data/lib/tryruby/shell.rb +122 -0
- data/lib/tryruby/tutorial.rb +53 -0
- data/lib/tryruby/version.rb +4 -0
- data/spec/challenge_buider_spec.rb +39 -0
- data/spec/challenge_spec.rb +91 -0
- data/spec/colors_spec.rb +69 -0
- data/spec/commands_spec.rb +50 -0
- data/spec/level_builder_spec.rb +21 -0
- data/spec/level_spec.rb +30 -0
- data/spec/next_fix_spec.rb +22 -0
- data/spec/shell_spec.rb +205 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/tutorial_spec.rb +74 -0
- data/tryruby.gemspec +27 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2b4cc48e47a9d65df21ad93130190174011d3fdd
|
4
|
+
data.tar.gz: df7553c3ae34839e4102efd03c2af1acce62d92a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d5dbef89b29e262fe4afa77e16e44e43c84a2ad5725fba3bfdc1459ed1d803bfcf060a338e5dc2d851b2a0d9c40315bda9dc8d7db68b9395579c38482a481e08
|
7
|
+
data.tar.gz: 450ee857525876adfebf6fa40fcc5733194cf48a4ae1e372b8c27a1d54673bcf9e2f2312808a6281decb49602a415f1d60731073ce5741b8828c73ace5b12e6b
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Jakub Červenka
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Try Ruby!
|
2
|
+
|
3
|
+
[](https://travis-ci.org/cvut/tryruby)
|
4
|
+
|
5
|
+
A command line version of [tryruby.org](http://tryruby.org/) in case that the website goes down or is having troubles with too many simultaneous connections you can use this REPL shell to try ruby!
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
$ gem install tryruby
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
$ tryruby
|
14
|
+
|
15
|
+
## Contributing
|
16
|
+
|
17
|
+
1. Fork it ( https://github.com/cvut/tryruby/fork )
|
18
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
19
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
20
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
21
|
+
5. Create a new Pull Request
|
22
|
+
|
23
|
+
## TODO
|
24
|
+
|
25
|
+
* convert Why's drawings to ASCII art
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/tryruby
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
require_relative File.expand_path('../lib/tryruby/runner', File.dirname(__FILE__))
|
4
|
+
|
5
|
+
ARGV << 'Tryruby::DefaultLevels' unless ARGV.length > 0
|
6
|
+
tutorials = ARGV.map do |tutorial|
|
7
|
+
snake_case = tutorial.gsub(/::/, '/')
|
8
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
9
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
10
|
+
.tr('-', '_')
|
11
|
+
.downcase
|
12
|
+
begin
|
13
|
+
require snake_case
|
14
|
+
rescue LoadError
|
15
|
+
require_relative File.expand_path("../lib/#{snake_case}", File.dirname(__FILE__))
|
16
|
+
end
|
17
|
+
Object.const_get(tutorial).new
|
18
|
+
end
|
19
|
+
ARGV.clear
|
20
|
+
|
21
|
+
Tryruby::Runner.start(tutorials)
|
data/lib/tryruby.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'sourcify'
|
2
|
+
|
3
|
+
module Tryruby
|
4
|
+
# Single tutorial challenge
|
5
|
+
class Challenge
|
6
|
+
attr_reader :help, :display_setup
|
7
|
+
|
8
|
+
def initialize(help, test = nil, setup = nil, display_setup = false)
|
9
|
+
@help, @test, @setup, @display_setup = help, test, setup, display_setup
|
10
|
+
end
|
11
|
+
|
12
|
+
def test(repl, result, vars, output)
|
13
|
+
repl.instance_exec(result, vars, output, &@test) if @test
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup(repl, vars)
|
17
|
+
repl.instance_exec(vars, &@setup) if @setup
|
18
|
+
end
|
19
|
+
|
20
|
+
# Challenge setup as text
|
21
|
+
def setup_source
|
22
|
+
return '' unless @setup
|
23
|
+
vars_name = @setup.parameters[0][1]
|
24
|
+
source = @setup.to_source(strip_enclosure: true)
|
25
|
+
source.gsub(/#{vars_name}\[:([^\]]+)\]/, '\1')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'challenge'
|
2
|
+
require_relative 'colors'
|
3
|
+
|
4
|
+
module Tryruby
|
5
|
+
# Single challenge level builder
|
6
|
+
class ChallengeBuilder
|
7
|
+
include Colors
|
8
|
+
|
9
|
+
attr_writer :help, :test, :setup, :display_setup
|
10
|
+
alias_method :help, :help=
|
11
|
+
alias_method :display_setup, :display_setup=
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@help = ''
|
15
|
+
@test = nil
|
16
|
+
@setup = nil
|
17
|
+
@display_setup = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def test(&block)
|
21
|
+
self.test = block
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup(&block)
|
25
|
+
self.setup = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def challenge
|
29
|
+
Challenge.new(@help, @test, @setup, @display_setup)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'paint'
|
2
|
+
|
3
|
+
module Tryruby
|
4
|
+
# ANSI formatting shortcuts
|
5
|
+
module Colors
|
6
|
+
Paint::SHORTCUTS[:tryruby] = {
|
7
|
+
black: Paint.color(:black),
|
8
|
+
red: Paint.color(:red),
|
9
|
+
green: Paint.color(:green),
|
10
|
+
yellow: Paint.color(:yellow),
|
11
|
+
blue: Paint.color(:blue),
|
12
|
+
magenta: Paint.color(:magenta),
|
13
|
+
cyan: Paint.color(:cyan),
|
14
|
+
white: Paint.color(:white),
|
15
|
+
bg_black: Paint.color(nil, :black),
|
16
|
+
bg_red: Paint.color(nil, :red),
|
17
|
+
bg_green: Paint.color(nil, :green),
|
18
|
+
bg_yellow: Paint.color(nil, :yellow),
|
19
|
+
bg_blue: Paint.color(nil, :blue),
|
20
|
+
bg_magenta: Paint.color(nil, :magenta),
|
21
|
+
bg_cyan: Paint.color(nil, :cyan),
|
22
|
+
bg_white: Paint.color(nil, :white),
|
23
|
+
reset: Paint.color(:reset),
|
24
|
+
bold: Paint.color(:bold),
|
25
|
+
underline: Paint.color(:underline),
|
26
|
+
inverse: Paint.color(:inverse),
|
27
|
+
hide: Paint.color(:hide),
|
28
|
+
title: Paint.color(:bold, :underline),
|
29
|
+
result: Paint.color(:blue),
|
30
|
+
error: Paint.color(:red, :bold),
|
31
|
+
success: Paint.color(:green, :bold)
|
32
|
+
}
|
33
|
+
|
34
|
+
include Paint::Tryruby
|
35
|
+
|
36
|
+
def paint(*args)
|
37
|
+
Paint[*args]
|
38
|
+
end
|
39
|
+
|
40
|
+
module_function(*Paint::SHORTCUTS[:tryruby].keys)
|
41
|
+
module_function :paint
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,858 @@
|
|
1
|
+
require_relative 'tutorial'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Tryruby
|
5
|
+
# Levels and challenges form tryruby.org
|
6
|
+
class DefaultLevels < Tutorial
|
7
|
+
level do
|
8
|
+
challenge do
|
9
|
+
help <<-EOF
|
10
|
+
#{title 'Got 15 minutes? Give Ruby a shot right now!'}
|
11
|
+
|
12
|
+
Ruby is a programming language from Japan (available at ruby-lang.org) which is
|
13
|
+
revolutionizing the web. The beauty of Ruby is found in its balance between
|
14
|
+
simplicity and power.
|
15
|
+
|
16
|
+
Try out Ruby code in the prompt. In addition to Ruby's built-in methods, the
|
17
|
+
following commands are available:
|
18
|
+
|
19
|
+
* #{inverse 'help'} → Repeat last instructions.
|
20
|
+
* #{inverse 'next'} → Allows you to skip to the next section of a lesson.
|
21
|
+
* #{inverse 'back'} → Allows you to return to the previous section of a \
|
22
|
+
lesson.
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
|
26
|
+
challenge do
|
27
|
+
help <<-EOF
|
28
|
+
#{title 'Using the Prompt'}
|
29
|
+
|
30
|
+
The prompt below is a Ruby prompt.
|
31
|
+
|
32
|
+
Here you'll be able to type a line of Ruby code, hit #{inverse 'Enter'}, and \
|
33
|
+
watch it run!
|
34
|
+
|
35
|
+
For your first bit of Ruby, try typing some math, like: #{result '2 + 6'}
|
36
|
+
EOF
|
37
|
+
test { |result| result == 8 }
|
38
|
+
end
|
39
|
+
|
40
|
+
challenge do
|
41
|
+
help <<-EOF
|
42
|
+
Great! You did a little bit of math.
|
43
|
+
|
44
|
+
See how the answer was returned? Ruby uses a fat arrow for responses to your
|
45
|
+
entries.
|
46
|
+
|
47
|
+
Ruby recognizes numbers and mathematics operators. You could also try some other
|
48
|
+
math like:
|
49
|
+
|
50
|
+
* #{result '4 * 10'}
|
51
|
+
* #{result '5 - 12'}
|
52
|
+
* #{result '40 / 4'}
|
53
|
+
|
54
|
+
Even though we've placed a space between the numbers and the operators above,
|
55
|
+
it's not required. For now, stick with these basic operations; we'll try a few
|
56
|
+
others later.
|
57
|
+
|
58
|
+
When you're finished experimenting, type #{result 'next'} to move to the next \
|
59
|
+
lesson when
|
60
|
+
you're finished.
|
61
|
+
EOF
|
62
|
+
end
|
63
|
+
|
64
|
+
challenge do
|
65
|
+
help <<-EOF
|
66
|
+
#{title 'Say Your Name'}
|
67
|
+
|
68
|
+
Welp, we already know that computers are handy and fast for math.
|
69
|
+
|
70
|
+
But what about something really useful. Like, say, seeing the letters of your
|
71
|
+
name reversed!
|
72
|
+
|
73
|
+
To do that super-cool task, let's first get you familiar with text in Ruby. Type
|
74
|
+
your first name in quotes, like this: #{result '"Jimmy"'}
|
75
|
+
EOF
|
76
|
+
test { |res| res.is_a?(String) && res.length > 0 }
|
77
|
+
end
|
78
|
+
|
79
|
+
challenge do
|
80
|
+
help <<-EOF
|
81
|
+
#{title 'Say Your Name Reversed'}
|
82
|
+
|
83
|
+
Perfect, you've formed a #{inverse 'string'} from the letters of your name. \
|
84
|
+
A string is an
|
85
|
+
ordered set of characters that the computer can process.
|
86
|
+
|
87
|
+
Imagine the letters are on a string of laundry line and the quotes are
|
88
|
+
clothespins holding the ends. The quotes mark the beginning and the end of the
|
89
|
+
string, and are required.
|
90
|
+
|
91
|
+
Now, let's get to reversing your name.
|
92
|
+
|
93
|
+
Type: #{result '"Jimmy".reverse'}, using your own name where the string goes. \
|
94
|
+
(Don't forget
|
95
|
+
the dot!)
|
96
|
+
EOF
|
97
|
+
test { |res| res.is_a?(String) && res.length > 0 }
|
98
|
+
end
|
99
|
+
|
100
|
+
challenge do
|
101
|
+
help <<-EOF
|
102
|
+
#{title 'Counting the Letters'}
|
103
|
+
|
104
|
+
You have used the #{inverse 'reverse'} method on your name!
|
105
|
+
|
106
|
+
By enclosing your name in quotes, you made a string. Next, you used a dot to
|
107
|
+
access a hidden list of methods that belong to all strings. In this case, you
|
108
|
+
then called the #{inverse 'reverse'} method, which works on strings to flip \
|
109
|
+
the order of the
|
110
|
+
string’s characters. Cool, huh?
|
111
|
+
|
112
|
+
Now, let's use a different option which will show us how many letters are in
|
113
|
+
your name. Try typing #{result '"Jimmy".length'} using your name where the \
|
114
|
+
string goes.
|
115
|
+
EOF
|
116
|
+
test { |res| res.is_a?(Fixnum) && res > 0 }
|
117
|
+
end
|
118
|
+
|
119
|
+
challenge do
|
120
|
+
help <<-EOF
|
121
|
+
#{title 'On Repeat'}
|
122
|
+
|
123
|
+
Now, maybe you're wondering what any of this is actually good for. Have you ever
|
124
|
+
encountered a website that yelled at you for choosing a password that was too
|
125
|
+
short? Turns out, the #{inverse 'length'} property is often what that site \
|
126
|
+
uses to check for
|
127
|
+
a correct length.
|
128
|
+
|
129
|
+
Let's get crazy now, and multiply your name by 5. Follow the following format:
|
130
|
+
#{result '"Jimmy" * 5'}
|
131
|
+
EOF
|
132
|
+
test { |res| res.is_a?(String) && res.length > 0 }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
level do
|
137
|
+
challenge do
|
138
|
+
help <<-EOF
|
139
|
+
#{title 'Hey, Whoa, Level #2 Already'}
|
140
|
+
|
141
|
+
Let's look at what you've learned in the first minute.
|
142
|
+
|
143
|
+
* #{bold 'The prompt'}. Typing code into the prompt gives you an answer.
|
144
|
+
* #{bold 'Numbers and strings'} are Ruby's math and text objects.
|
145
|
+
* #{bold 'Methods'}. You've used English-language methods like \
|
146
|
+
#{inverse 'reverse'} and symbolic
|
147
|
+
methods like #{inverse '*'} (the multiplication method.) Methods are \
|
148
|
+
actions!
|
149
|
+
|
150
|
+
This is the essence of your learning. Taking simple things, toying with them and
|
151
|
+
turning them into new things! Feeling comfortable yet? I promise that we'll get
|
152
|
+
you there..
|
153
|
+
|
154
|
+
But now, let's do something a little uncomfortable. Try using that \
|
155
|
+
#{inverse 'reverse'}
|
156
|
+
method on a number: #{result '40.reverse'}
|
157
|
+
EOF
|
158
|
+
test { |res| res.is_a?(NoMethodError) }
|
159
|
+
end
|
160
|
+
|
161
|
+
challenge do
|
162
|
+
help <<-EOF
|
163
|
+
#{title 'Stop, You\'re Barking Mad!'}
|
164
|
+
|
165
|
+
You can't reverse the number #{inverse '40'}. I guess you can hold your \
|
166
|
+
monitor up to the
|
167
|
+
mirror, but reversing a number just doesn't make sense! Ruby has tossed you
|
168
|
+
a useful error message.
|
169
|
+
|
170
|
+
The message is telling you that there is no method #{inverse 'reverse'} for \
|
171
|
+
number values in
|
172
|
+
Ruby!
|
173
|
+
|
174
|
+
But, hmm...maybe if you can turn it into a string. Try this: \
|
175
|
+
#{result '40.to_s.reverse'}.
|
176
|
+
EOF
|
177
|
+
test { |res| res == '04' }
|
178
|
+
end
|
179
|
+
|
180
|
+
challenge do
|
181
|
+
help <<-EOF
|
182
|
+
#{title 'Boys are Different From Girls'}
|
183
|
+
|
184
|
+
...just like numbers are different from strings. While you can use methods on
|
185
|
+
any object in Ruby, some methods only work on certain types of values. A really
|
186
|
+
cool thing about Ruby is that you can always convert between different types
|
187
|
+
using Ruby's "to" methods.
|
188
|
+
|
189
|
+
* #{bold 'to_s'} converts values to strings.
|
190
|
+
* #{bold 'to_i'} converts values to integers (numbers.)
|
191
|
+
* #{bold 'to_a'} converts values to arrays.
|
192
|
+
|
193
|
+
What in the world are arrays, you might ask?! They are simply lists. Let's make
|
194
|
+
an empty one, by typing in a pair of brackets: #{result '[]'}.
|
195
|
+
EOF
|
196
|
+
test { |res| res == [] }
|
197
|
+
end
|
198
|
+
|
199
|
+
challenge do
|
200
|
+
help <<-EOF
|
201
|
+
#{title 'Standing in Line'}
|
202
|
+
|
203
|
+
Great, you built an empty array. Now let's see what else we can do with it.
|
204
|
+
|
205
|
+
First off, a good thing to know is that arrays store their information in a
|
206
|
+
#{bold 'sequence'}. Think of this like standing in line for popcorn. You are \
|
207
|
+
behind
|
208
|
+
someone and you wouldn't dream of pushing them aside, right? And that guy behind
|
209
|
+
you, you've got a close eye on him, too. First come, first serve.
|
210
|
+
|
211
|
+
Just like that line for popcorn, the order of an array's information will stay
|
212
|
+
consistent for you after you build it...well, at least until you modify it.
|
213
|
+
|
214
|
+
To try building an array with some stuff in it, here's a list of lottery numbers
|
215
|
+
for you: #{result '[12, 47, 35]'}. See those commas? They're important!
|
216
|
+
EOF
|
217
|
+
test { |res| res == [12, 47, 35] }
|
218
|
+
end
|
219
|
+
|
220
|
+
challenge do
|
221
|
+
help <<-EOF
|
222
|
+
#{title 'One Raises Its Hand'}
|
223
|
+
|
224
|
+
Sweet, you've got a short list of lottery numbers. Now, what if we wanted to
|
225
|
+
know which one is the highest in the array?
|
226
|
+
|
227
|
+
Try this: #{result '[12, 47, 35].max'}.
|
228
|
+
EOF
|
229
|
+
test { |res| res == 47 }
|
230
|
+
end
|
231
|
+
|
232
|
+
challenge do
|
233
|
+
help <<-EOF
|
234
|
+
#{title 'Tucking a List Away'}
|
235
|
+
|
236
|
+
Good, good. But it would be pretty annoying to have to retype that list every
|
237
|
+
time, right?
|
238
|
+
|
239
|
+
Let's fix that by using a Ruby #{bold 'variable'}, which helps us store \
|
240
|
+
important data.
|
241
|
+
Each variable has a unique name, so that it can be summoned up whenever we need
|
242
|
+
the info it contains.
|
243
|
+
|
244
|
+
Call your new variable #{inverse 'ticket'} and place your lottery numbers \
|
245
|
+
inside it, like so:
|
246
|
+
#{result 'ticket = [12, 47, 35]'}. That equal sign you see is what assigns \
|
247
|
+
your array to the
|
248
|
+
new variable.
|
249
|
+
EOF
|
250
|
+
test { |_, vars| vars[:ticket] == [12, 47, 35] }
|
251
|
+
end
|
252
|
+
|
253
|
+
challenge do
|
254
|
+
help <<-EOF
|
255
|
+
#{title 'Now Type Ticket'}
|
256
|
+
|
257
|
+
Sweet, now check this out. Type: #{result 'ticket'}
|
258
|
+
EOF
|
259
|
+
test { |res| res == [12, 47, 35] }
|
260
|
+
setup { |vars| vars[:ticket] = [12, 47, 35] }
|
261
|
+
end
|
262
|
+
|
263
|
+
challenge do
|
264
|
+
help <<-EOF
|
265
|
+
#{title 'Saved, Tucked Away'}
|
266
|
+
|
267
|
+
Fantastic! You've hung on to your lotto numbers, tucking them away inside a
|
268
|
+
#{bold 'variable'} called #{inverse 'ticket'}.
|
269
|
+
|
270
|
+
Now let's put your lotto numbers in order...sound good? Ruby has a great method
|
271
|
+
for that. Use: #{result 'ticket.sort!'}
|
272
|
+
|
273
|
+
You might notice that the method has an exclamation point at its end. This just
|
274
|
+
signals that we intend for Ruby to directly modify the same array that we've
|
275
|
+
built, rather than make a brand new copy that is sorted. You'll notice that if
|
276
|
+
you try calling #{inverse 'ticket'} again, it will be sorted permanently!
|
277
|
+
|
278
|
+
When you want to move on, just type #{result 'next'}
|
279
|
+
EOF
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
level do
|
284
|
+
poem = <<-EOF
|
285
|
+
My toast has flown from my hand
|
286
|
+
And my toast has gone to the moon.
|
287
|
+
But when I saw it on television,
|
288
|
+
Planting our flag on Halley's comet,
|
289
|
+
More still did I want to eat it.
|
290
|
+
EOF
|
291
|
+
challenge do
|
292
|
+
help <<-EOF
|
293
|
+
#{title 'Level #3 is Upon Us'}
|
294
|
+
|
295
|
+
You built a list. Then you sorted the list. And as you've seen, the \
|
296
|
+
#{inverse 'ticket'}
|
297
|
+
variable is now changed.
|
298
|
+
|
299
|
+
Now, let's look at how your second level went down:
|
300
|
+
|
301
|
+
* #{bold 'Errors'}. If you try to reverse a number or do anything fishy, \
|
302
|
+
Ruby will skip
|
303
|
+
the prompt and tell you to straighten up.
|
304
|
+
* #{bold 'Arrays'} are lists of stored information.
|
305
|
+
* #{bold 'Variables'} are a place to save stuff you might need again, as \
|
306
|
+
well as give
|
307
|
+
that stuff a name. You used the equals sign to do this, in a process called
|
308
|
+
assignment.
|
309
|
+
Like: #{inverse 'ticket = [14, 37, 18]'}.
|
310
|
+
|
311
|
+
In all, there are just five levels in this course. You are already two-fifths
|
312
|
+
of the way to the end! This is simple stuff, don't you think? More good stuff up
|
313
|
+
ahead.
|
314
|
+
|
315
|
+
Let's change directions for a moment. I've stuffed a bit of poetry for you in a
|
316
|
+
certain variable. Take a look, by typing #{result 'print poem'}
|
317
|
+
EOF
|
318
|
+
setup do |vars|
|
319
|
+
vars[:poem] = poem.dup
|
320
|
+
end
|
321
|
+
test do |_, _, output|
|
322
|
+
output == poem
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
challenge do
|
327
|
+
help <<-EOF
|
328
|
+
#{title 'Sadly, You Hate Toast Poetry'}
|
329
|
+
|
330
|
+
Look, it's okay. You don't have to like it. You may even want to hack it up.
|
331
|
+
Welp, be my guest.
|
332
|
+
|
333
|
+
Instead of toast, maybe go for a melon or something. Try this one:
|
334
|
+
#{result 'poem[\'toast\'] = \'honeydew\''}
|
335
|
+
EOF
|
336
|
+
setup do |vars|
|
337
|
+
vars[:poem] = poem.dup
|
338
|
+
end
|
339
|
+
test do |_, vars|
|
340
|
+
vars[:poem] == poem.sub('toast', 'honeydew')
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
challenge do
|
345
|
+
help <<-EOF
|
346
|
+
Now type #{result 'print poem'} once again to see the new poem.
|
347
|
+
|
348
|
+
See how you only changed the first toast? The joke's on you, bread hater.
|
349
|
+
|
350
|
+
When you want to move on, type #{result 'next'}
|
351
|
+
EOF
|
352
|
+
setup do |vars|
|
353
|
+
vars[:poem] = poem.sub('toast', 'honeydew')
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
challenge do
|
358
|
+
help <<-EOF
|
359
|
+
#{title 'Ready, Aim'}
|
360
|
+
|
361
|
+
The square brackets you just used are very common in Ruby. Remember, you typed:
|
362
|
+
#{inverse 'poem[\'toast\'] = \'honeydew\''}. That box that holds the word \
|
363
|
+
toast uses a square
|
364
|
+
bracket on each side. See 'em?
|
365
|
+
|
366
|
+
The two brackets are like a crosshairs used to line up precisely on a target.
|
367
|
+
These brackets mean, "I am looking for ____ somewhere in here." Ready ... aim
|
368
|
+
... #{bold 'data'}. Here, you were looking specifically for toast in order to \
|
369
|
+
swap it out
|
370
|
+
with a fruit.
|
371
|
+
|
372
|
+
Let's see if your new experience can help you produce the answer to this
|
373
|
+
question: what happens when we reverse this whole poem? #{result 'poem.reverse'}
|
374
|
+
EOF
|
375
|
+
setup do |vars|
|
376
|
+
vars[:poem] = poem.sub('toast', 'honeydew')
|
377
|
+
end
|
378
|
+
test do |result|
|
379
|
+
result == poem.sub('toast', 'honeydew').reverse
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
challenge do
|
384
|
+
help <<-EOF
|
385
|
+
#{title 'Too Much Reversal'}
|
386
|
+
|
387
|
+
Okay, I suppose that was expected. The whole poem's been turned backwards,
|
388
|
+
letter by letter. But say I really just wanted to reverse the lines only. In
|
389
|
+
other words, move the last line up to first and the first line down to last.
|
390
|
+
Backwards, yes, but not that backwards.
|
391
|
+
|
392
|
+
Ruby has a way. Try this: #{result 'poem.lines.to_a.reverse'}
|
393
|
+
EOF
|
394
|
+
setup do |vars|
|
395
|
+
vars[:poem] = poem.sub('toast', 'honeydew')
|
396
|
+
end
|
397
|
+
test do |result|
|
398
|
+
result == poem.sub('toast', 'honeydew').lines.to_a.reverse
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
challenge do
|
403
|
+
help <<-EOF
|
404
|
+
#{title 'Ringlets of Chained Methods'}
|
405
|
+
|
406
|
+
So...what actually happened there? You typed \
|
407
|
+
#{inverse 'poem.lines.to_a.reverse'} and
|
408
|
+
produced some Ruby magic.
|
409
|
+
|
410
|
+
First, you turned the #{inverse 'poem'} into a list using \
|
411
|
+
#{inverse 'lines.to_a'}. The #{inverse 'lines'} component
|
412
|
+
decided the way the string should be split up, and then one of our "to" methods,
|
413
|
+
#{inverse 'to_a'}, converted those splits into an Array. (to_array.)
|
414
|
+
|
415
|
+
Different methods, such as #{inverse 'bytes'} and #{inverse 'chars'} can be \
|
416
|
+
used in place of #{inverse 'lines'}. By
|
417
|
+
using #{inverse 'lines'} here, Ruby split the poem up according to each new \
|
418
|
+
line.
|
419
|
+
|
420
|
+
After that, you #{inverse 'reverse'}'d your Array. You had each line prepared \
|
421
|
+
in advance. And
|
422
|
+
then you reversed them. That's it!
|
423
|
+
|
424
|
+
And now, let's tack one more method on the end there, if you don't mind. Try:
|
425
|
+
#{result 'print poem.lines.to_a.reverse.join'}.
|
426
|
+
EOF
|
427
|
+
setup do |vars|
|
428
|
+
vars[:poem] = poem.sub('toast', 'honeydew')
|
429
|
+
end
|
430
|
+
test do |_, _, output|
|
431
|
+
output == poem.sub('toast', 'honeydew').lines.to_a.reverse.join
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
level do
|
437
|
+
challenge do
|
438
|
+
help <<-EOF
|
439
|
+
#{title 'Brace Yourselves! Level #4 is Here Now'}
|
440
|
+
|
441
|
+
Good show, my friend! The join method took that list of reversed lines and put
|
442
|
+
them together into a single string. (Sure, you could have also just used to_s.)
|
443
|
+
|
444
|
+
Time for a quick review.
|
445
|
+
|
446
|
+
* Exclamation Points. Methods may have exclamation points in their name, which
|
447
|
+
just means to impact the current data, rather than making a copy. No big
|
448
|
+
deal.
|
449
|
+
* Square Brackets. With these, you can target and find things. You can even
|
450
|
+
replace them if necessary.
|
451
|
+
* Chaining methods lets you get a lot more done in a single command. Break up
|
452
|
+
a poem, reverse it, reassemble it: poem.lines.to_a.reverse.join.
|
453
|
+
|
454
|
+
Guess what? Methods can also have question marks. Try: poem.include? "my hand"
|
455
|
+
to check it out.
|
456
|
+
|
457
|
+
At this point, you may want to tinker with the poem a bit more. A complete list
|
458
|
+
of all the String methods is here: http://ruby-doc.org/core/classes/String.html.
|
459
|
+
Go ahead and try a few (such as poem.downcase or poem.delete.)
|
460
|
+
|
461
|
+
And now on to something new. When you're ready to move on, type: books = {}
|
462
|
+
EOF
|
463
|
+
setup do |vars|
|
464
|
+
vars[:poem] = <<-EOF
|
465
|
+
My honeydew has flown from my hand
|
466
|
+
And my toast has gone to the moon.
|
467
|
+
But when I saw it on television,
|
468
|
+
Planting our flag on Halley's comet,
|
469
|
+
More still did I want to eat it.
|
470
|
+
EOF
|
471
|
+
end
|
472
|
+
test do |_, vars|
|
473
|
+
vars[:books] == {}
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
challenge do
|
478
|
+
help <<-EOF
|
479
|
+
A Wee Blank Book
|
480
|
+
|
481
|
+
You've made an empty hash, also known as: a dictionary. Hashes store related
|
482
|
+
information by giving reusable labels to pieces of our data.
|
483
|
+
|
484
|
+
We're going to stuff some miniature book reviews in this hash. Here's our rating
|
485
|
+
system:
|
486
|
+
|
487
|
+
* :splendid → a masterpiece.
|
488
|
+
* :quite_good → enjoyed, sure, yes.
|
489
|
+
* :mediocre → equal parts great and terrible.
|
490
|
+
* :quite_not_good → notably bad.
|
491
|
+
* :abysmal → steaming wreck.
|
492
|
+
|
493
|
+
To rate a book, put the title in square brackets and put the rating after the
|
494
|
+
equals.
|
495
|
+
|
496
|
+
For example: books["Gravity's Rainbow"] = :splendid
|
497
|
+
EOF
|
498
|
+
setup do |vars|
|
499
|
+
vars[:books] = {}
|
500
|
+
end
|
501
|
+
test do |_, vars|
|
502
|
+
vars[:books] == { 'Gravity\'s Rainbow' => :splendid }
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
challenge do
|
507
|
+
help <<-EOF
|
508
|
+
More Bite-Size Reviews
|
509
|
+
|
510
|
+
Keep going! Fill it up with some useful reviews. And if you want to see the
|
511
|
+
whole list, just type: books
|
512
|
+
|
513
|
+
Again, the available ratings are: :splendid, :quite_good, :mediocre,
|
514
|
+
:quite_not_good, and :abysmal.
|
515
|
+
|
516
|
+
Notice that these ratings are not strings. When you place a colon in front of
|
517
|
+
a simple word, you get a Ruby symbol. Symbols are much cheaper than strings (in
|
518
|
+
terms of computer memory.) If you need to use a word over and over in your
|
519
|
+
program itself, use a symbol. Rather than having thousands of copies of that
|
520
|
+
word in memory, the computer will store a symbol only once, and refer to it over
|
521
|
+
and over.
|
522
|
+
|
523
|
+
Once you've got three or four books in there, type: books.length. You should see
|
524
|
+
the right amount.
|
525
|
+
EOF
|
526
|
+
setup do |vars|
|
527
|
+
vars[:books] = { 'Gravity\'s Rainbow' => :splendid }
|
528
|
+
end
|
529
|
+
test do |result, vars|
|
530
|
+
vars[:books].length > 2 && result == vars[:books].length
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
challenge do
|
535
|
+
help <<-EOF
|
536
|
+
Wait, Did I Like Gravity's Rainbow?
|
537
|
+
|
538
|
+
See, the length method works on strings, list and hashes. One great thing about
|
539
|
+
Ruby is that method names are often reused, which means a lot less stuff for you
|
540
|
+
to remember.
|
541
|
+
|
542
|
+
If you'd like to look up one of your old reviews, just put the title of the book
|
543
|
+
in the square box again. Leave off the equal sign this time, though, since
|
544
|
+
you're not assigning any information. You're just researching!
|
545
|
+
|
546
|
+
Do it like this: books["Gravity's Rainbow"]
|
547
|
+
EOF
|
548
|
+
test do |result, vars|
|
549
|
+
result == vars[:books]["Gravity's Rainbow"]
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
challenge do
|
554
|
+
help <<-EOF
|
555
|
+
Hashes as Pairs
|
556
|
+
|
557
|
+
Keep in mind that hashes won't keep things in order. That's not their job. It'll
|
558
|
+
just pair up two things: a key and a value. In your reviews, the key is the
|
559
|
+
book's title and the value is the rating, in this case a symbol.
|
560
|
+
|
561
|
+
If you want to see a nice list of the book titles you've reviewed: books.keys
|
562
|
+
|
563
|
+
When you want to move on, type next
|
564
|
+
EOF
|
565
|
+
end
|
566
|
+
|
567
|
+
challenge do
|
568
|
+
help <<-EOF
|
569
|
+
Are You Harsh?
|
570
|
+
|
571
|
+
So are you giving out harsh, unfair reviews? Let's keep score with this hash:
|
572
|
+
ratings = Hash.new(0)
|
573
|
+
EOF
|
574
|
+
test do |_, vars|
|
575
|
+
vars[:ratings] == Hash.new(0)
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
challenge do
|
580
|
+
help <<-EOF
|
581
|
+
Are You Harsh?
|
582
|
+
|
583
|
+
That command was another way to build an empty hash. The zero you passed in will
|
584
|
+
set all of your initial rating counts to zero.
|
585
|
+
|
586
|
+
Okay, now let's count up your reviews. Stay with me on this one.
|
587
|
+
|
588
|
+
Type: books.values.each { |rate| ratings[rate] += 1 }
|
589
|
+
|
590
|
+
(That | in the code is called the pipe character. It's probably located right
|
591
|
+
above the Enter key on your keyboard.)
|
592
|
+
|
593
|
+
This code will turn all your unique values in books...into keys within the new
|
594
|
+
ratings hash. Crazy, right? Then, as it looks at each rating you originally gave
|
595
|
+
in books, it will increase the count value for that rating in ratings
|
596
|
+
|
597
|
+
After you've build your new hash of count values, type ratings again to see the
|
598
|
+
full tally. This new hash will show you a rating followed by the number of times
|
599
|
+
you've given that rating.
|
600
|
+
|
601
|
+
When you want to move on, type next
|
602
|
+
EOF
|
603
|
+
setup do |vars|
|
604
|
+
vars[:ratings] = Hash.new(0)
|
605
|
+
vars[:books] = {
|
606
|
+
'Gravity\'s Rainbow' => :splendid
|
607
|
+
} unless vars[:books].is_a?(Hash) && vars[:books].length > 0
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
challenge do
|
612
|
+
help <<-EOF
|
613
|
+
A Tally
|
614
|
+
|
615
|
+
One of the amazing new things we've just used is called a block. Basically,
|
616
|
+
a block is a chunk of Ruby code surrounded by curly braces. We'll take a closer
|
617
|
+
look at them later.
|
618
|
+
|
619
|
+
But for now, let's try another block:
|
620
|
+
|
621
|
+
5.times { print "Odelay!" }
|
622
|
+
|
623
|
+
When you want to move on, type next. You want the badge, don't you?
|
624
|
+
EOF
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
level do
|
629
|
+
comics = <<-EOF
|
630
|
+
Achewood: http://achewood.com/
|
631
|
+
Dinosaur Comics: http://qwantz.com/
|
632
|
+
Perry Bible Fellowship: http://cheston.com/pbf/archive.html
|
633
|
+
Get Your War On: http://mnftiu.cc/
|
634
|
+
EOF
|
635
|
+
new_comics = comics + 'Cat and Girl: http://catandgirl.com/'
|
636
|
+
|
637
|
+
challenge do
|
638
|
+
help <<-EOF
|
639
|
+
Now Arriving at Level #5
|
640
|
+
|
641
|
+
Blocks are always attached to methods. You saw this with the times method, which
|
642
|
+
took the block and ran its code over and over. (In this case: five times.)
|
643
|
+
|
644
|
+
This last lesson was a bit longer. You've probably used up three minutes
|
645
|
+
learning about:
|
646
|
+
|
647
|
+
* Hashes. The little 'dictionary' with the curly braces: {}.
|
648
|
+
* Symbols. Tiny, efficiently reusable code words with a colon: :splendid.
|
649
|
+
* Blocks. Chunks of code which can be tacked on to many of Ruby's methods.
|
650
|
+
Here's the code you used to build a scorecard:
|
651
|
+
books.values.each { |rate| ratings[rate] += 1 }.
|
652
|
+
|
653
|
+
On to the next thing, okay? On your computer, you probably have a lot of
|
654
|
+
different files. Some files have pictures in them, some have programs in them.
|
655
|
+
And files are often organized into folders, also called: directories.
|
656
|
+
|
657
|
+
I've prepared a few directories for you. Take a look, using the following
|
658
|
+
command: Dir.entries "/"
|
659
|
+
EOF
|
660
|
+
test do |result|
|
661
|
+
result == Dir.entries('/')
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
challenge do
|
666
|
+
help <<-EOF
|
667
|
+
The Private Collection of Dr. Dir
|
668
|
+
|
669
|
+
You've just listed out everything in the top directory, which is called the
|
670
|
+
root. It's indicated by the single slash in your string parameter. It contains
|
671
|
+
some programs, as well as other tutorials and such.
|
672
|
+
|
673
|
+
So, what exactly is that Dir.entries method? Well, it's just a method, like the
|
674
|
+
others you've seen. Dir has a collection of methods for checking out file
|
675
|
+
directories, and entries is being called on the Dir variable. The entries method
|
676
|
+
just lists everything in the directory you've indicated!
|
677
|
+
|
678
|
+
One other little thing we haven't really talked about quite yet: method
|
679
|
+
arguments. A few are highlighted below.
|
680
|
+
|
681
|
+
* Dir.entries "/" -- Anything listed after a method is considered an
|
682
|
+
'attachment'.
|
683
|
+
* print poem -- See, print is just an ordinary method, while the poem is what
|
684
|
+
got attached for printing.
|
685
|
+
* print "pre", "event", "ual", "ism" -- This bit has several arguments! Ruby
|
686
|
+
makes us use commas to distinguish between them.
|
687
|
+
|
688
|
+
Next up, we'll list just the text files in our directory using a bracket
|
689
|
+
notation. Remember how it searches?
|
690
|
+
|
691
|
+
Try: Dir["*.txt"]
|
692
|
+
EOF
|
693
|
+
setup do
|
694
|
+
File.write('comics.txt', comics)
|
695
|
+
end
|
696
|
+
test do |result|
|
697
|
+
result == Dir['*.txt']
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
challenge do
|
702
|
+
help <<-EOF
|
703
|
+
Come, Read Comics With Me
|
704
|
+
|
705
|
+
The Dir[] syntax is kind of like entries, but instead searches for files with
|
706
|
+
wildcard characters.
|
707
|
+
|
708
|
+
Here, we see those square brackets again! Notice how they still mean, "I am
|
709
|
+
looking for _____?"
|
710
|
+
|
711
|
+
Dir["*.txt"] says to Ruby: "I am looking for any files which end with .txt."
|
712
|
+
The asterisk indicates the "any file" part. Ruby then hands us every file that
|
713
|
+
matches our request.
|
714
|
+
|
715
|
+
Alright, let's crack open this comics file, then! We'll use a new method to do
|
716
|
+
it.
|
717
|
+
|
718
|
+
Here's the way: print File.read("comics.txt")
|
719
|
+
EOF
|
720
|
+
test do |_, _, output|
|
721
|
+
output == File.read('comics.txt')
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
challenge do
|
726
|
+
help <<-EOF
|
727
|
+
Mi Comicas, Tu Comicas
|
728
|
+
|
729
|
+
Alright, then! Now we can start to use files to store things. This is great
|
730
|
+
because normally when we exit Ruby, all our variables will be gone. Ruby, by
|
731
|
+
itself, forgets these things. But if we save things in files, we can read those
|
732
|
+
files in future Ruby escapades.
|
733
|
+
|
734
|
+
Hey, and guess what? The Home directory is yours now! I gave it to you! Am I
|
735
|
+
generous or what?!
|
736
|
+
|
737
|
+
First thing we'll do is make a copy of the comics file and put in new folder
|
738
|
+
called 'Home'.
|
739
|
+
|
740
|
+
To do that, you'll want to use a copying method called cp on a variable called
|
741
|
+
FileUtils.
|
742
|
+
|
743
|
+
Use FileUtils.cp('comics.txt', 'Home/comics.txt')
|
744
|
+
EOF
|
745
|
+
setup do
|
746
|
+
Dir.mkdir('Home') unless Dir.exist?('Home')
|
747
|
+
end
|
748
|
+
test do
|
749
|
+
File.exist?('Home/comics.txt') && \
|
750
|
+
File.read('Home/comics.txt') == comics
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
challenge do
|
755
|
+
help <<-EOF
|
756
|
+
Okay, you've got a copy, and it's located in the right directory. Check it out!
|
757
|
+
|
758
|
+
Use Dir["Home/*.txt"]
|
759
|
+
|
760
|
+
Type next to move to the next lesson when you're finished.
|
761
|
+
EOF
|
762
|
+
setup do
|
763
|
+
File.write('Home/comics.txt', comics)
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
challenge do
|
768
|
+
help <<-EOF
|
769
|
+
Your Own Turf
|
770
|
+
|
771
|
+
To add your own comic to the list, let's open the file in append mode,
|
772
|
+
which we indicate with the "a" parameter. This will allow us to put new stuff
|
773
|
+
at the end of the file.
|
774
|
+
|
775
|
+
Start by entering this code: File.open("Home/comics.txt", "a") do |f|
|
776
|
+
|
777
|
+
And Now For the Startling Conclusion
|
778
|
+
|
779
|
+
So your prompt has changed, see that? Your prompt is a double dot now.
|
780
|
+
|
781
|
+
In this tutorial, this prompt means that Ruby is expecting you to type a little
|
782
|
+
bit more. As you write further lines of Ruby code, the double-dots will continue
|
783
|
+
until the tutorial sees you are completely finished.
|
784
|
+
|
785
|
+
Alright, so here's more code. You've already typed the first line, so just enter
|
786
|
+
the second line.
|
787
|
+
|
788
|
+
File.open("Home/comics.txt", "a") do |f|
|
789
|
+
f << "Cat and Girl: http://catandgirl.com/"
|
790
|
+
end
|
791
|
+
|
792
|
+
Ruby Sits Still
|
793
|
+
|
794
|
+
The last line will add the Cat and Girl comic to the list, but Ruby's going to
|
795
|
+
wait until you're totally finished to take action.
|
796
|
+
|
797
|
+
This means we'll also need to wrap up the code block you've started. Turns out,
|
798
|
+
you actually opened a new block when you typed that do keyword.
|
799
|
+
|
800
|
+
So far the blocks we've seen have used curly braces, but this time we'll be
|
801
|
+
using do and end instead. A lot of Rubyists will use a do...end setup when the
|
802
|
+
block goes on for many lines.
|
803
|
+
|
804
|
+
Let's get that block finished now, with your very own end.
|
805
|
+
EOF
|
806
|
+
test do
|
807
|
+
File.exist?('Home/comics.txt') && \
|
808
|
+
File.read('Home/comics.txt') == new_comics
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
challenge do
|
813
|
+
help <<-EOF
|
814
|
+
Ruby Sits Still
|
815
|
+
|
816
|
+
Sweet! You've added that brand new comic to the end of the file. You can see for
|
817
|
+
yourself, using the read method you saw earlier:
|
818
|
+
print File.read("Home/comics.txt").
|
819
|
+
|
820
|
+
When you want to move on to the next lesson, type next.
|
821
|
+
EOF
|
822
|
+
setup do
|
823
|
+
File.write('Home/comics.txt', new_comics)
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
challenge do
|
828
|
+
help <<-EOF
|
829
|
+
The Clock Nailed To the File
|
830
|
+
|
831
|
+
I wonder, what time was it when you changed your file? We can check that out.
|
832
|
+
|
833
|
+
Type: File.mtime("Home/comics.txt").
|
834
|
+
EOF
|
835
|
+
test do |result|
|
836
|
+
result == File.mtime('Home/comics.txt')
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
challenge do
|
841
|
+
help <<-EOF
|
842
|
+
Just the Hour Hand
|
843
|
+
|
844
|
+
Excellent, there's the exact time, precisely when you added to the file.
|
845
|
+
The mtime method gives you a nice Ruby Time object.
|
846
|
+
|
847
|
+
If you want to check just what hour it was, hit the up arrow key to put your
|
848
|
+
previous entry in the console. Then modify the line to say:
|
849
|
+
File.mtime("Home/comics.txt").hour.
|
850
|
+
EOF
|
851
|
+
test do |result|
|
852
|
+
result == File.mtime('Home/comics.txt').hour
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
end
|
857
|
+
end
|
858
|
+
end
|