Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:00,000 --> 00:00:07,480
So blocks come in really handy when you need to control and resource.
2
00:00:07,480 --> 00:00:10,360
Maybe it's a network connection, maybe it's a file.
3
00:00:10,360 --> 00:00:15,900
Yeah, you need to connect and disconnect and open and close the resource and guarantee that
4
00:00:15,900 --> 00:00:18,800
everything is cleaned up properly at the end.
5
00:00:18,800 --> 00:00:23,640
For example, let's suppose we have a simple payment gateway class and imagine it talks
6
00:00:23,640 --> 00:00:25,680
to a remote web service.
7
00:00:25,680 --> 00:00:30,200
It needs to be initialized with a super secret username and password.
8
00:00:30,200 --> 00:00:35,080
We have a way to connect and disconnect from the remote service.
9
00:00:35,080 --> 00:00:40,760
We also have a way to submit transactions by specifying the type of transaction, maybe
10
00:00:40,760 --> 00:00:44,920
a sale or a refund and also send the amount.
11
00:00:44,920 --> 00:00:47,120
So here's the way we typically use it.
12
00:00:47,120 --> 00:00:49,600
We create a new gateway object.
13
00:00:49,600 --> 00:00:51,519
We connect to it.
14
00:00:51,520 --> 00:00:57,120
We send some transactions and then we have to remember to disconnect when we're done.
15
00:00:57,120 --> 00:00:58,520
So let's see that that works.
16
00:00:58,520 --> 00:00:59,920
All right, we run it.
17
00:00:59,920 --> 00:01:01,280
We connect it as Nicole.
18
00:01:01,280 --> 00:01:06,040
We submitted two sales and transactions and then we disconnect the due.
19
00:01:06,040 --> 00:01:09,760
Now code like this tends to sprout up in other areas of our app.
20
00:01:09,760 --> 00:01:13,960
For example, imagine somewhere else we handle refunds.
21
00:01:13,960 --> 00:01:17,120
So we basically have to do the same thing.
22
00:01:17,120 --> 00:01:19,040
So let's see that that works.
23
00:01:19,040 --> 00:01:23,560
Yep, we submitted your sale transactions and then we turned around, reconnected you,
24
00:01:23,560 --> 00:01:27,200
sent to refunds and disconnected at the end.
25
00:01:27,200 --> 00:01:29,120
Now obviously this is an ideal.
26
00:01:29,120 --> 00:01:33,720
We have the need to connect and disconnect around a whole series of transactions.
27
00:01:33,720 --> 00:01:38,920
Yeah, instead we could use a block and get some automatic resource management.
28
00:01:38,920 --> 00:01:43,840
So we're going to define a method that takes a block and then execute around the transactions
29
00:01:43,840 --> 00:01:44,840
in the block.
30
00:01:44,840 --> 00:01:46,800
So I'm going to define the method right up here.
31
00:01:46,800 --> 00:01:50,200
It's going to be called, let's start with a method outside the class.
32
00:01:50,200 --> 00:01:52,600
We're going to call it open gateway.
33
00:01:52,600 --> 00:01:55,000
It's going to need to take the user in the password.
34
00:01:55,000 --> 00:01:57,160
All right, what are we doing inside that method?
35
00:01:57,160 --> 00:02:02,000
Well, the very first thing we need to do is actually create a new payment gateway.
36
00:02:02,000 --> 00:02:07,360
And instead of using these hard-coded values, we'll use user and password here.
37
00:02:07,360 --> 00:02:09,759
So we'll just forward those onto the gateway.
38
00:02:09,759 --> 00:02:13,360
Then we need to do gateway connect.
39
00:02:13,360 --> 00:02:15,000
Then we want to yield to the block.
40
00:02:15,000 --> 00:02:16,000
Let it do the transactions.
41
00:02:16,000 --> 00:02:21,920
And then when we're done, we need to make sure that we actually disconnect from the gateway.
42
00:02:21,920 --> 00:02:26,400
Now the block itself is going to need the gateway object so we can run the transactions.
43
00:02:26,400 --> 00:02:31,840
So when we call yield, we're going to have to pass in that gateway object.
44
00:02:31,840 --> 00:02:34,200
Now down here, we're submitting the transactions.
45
00:02:34,200 --> 00:02:37,080
We'll call our open gateway method.
46
00:02:37,080 --> 00:02:38,080
We just wrote here.
47
00:02:38,080 --> 00:02:43,200
This will be Nicole and Secret.
48
00:02:43,200 --> 00:02:46,600
The block parameter is the gateway itself.
49
00:02:46,600 --> 00:02:50,079
Inside the block, we can then use that gateway object.
50
00:02:50,079 --> 00:02:55,519
And we don't have to worry about disconnecting it because when the block ends, the yield is returned.
51
00:02:55,519 --> 00:02:57,519
Remember, we're just going to disconnect right there.
52
00:02:57,519 --> 00:03:01,120
So we've got all this encapsulated in one nice little method.
53
00:03:01,120 --> 00:03:02,959
So we save this and run it.
54
00:03:02,959 --> 00:03:04,280
What we get the same output before.
55
00:03:04,280 --> 00:03:06,320
We saw we connected as Nicole.
56
00:03:06,320 --> 00:03:07,760
Then we submitted a sale transaction.
57
00:03:07,760 --> 00:03:09,959
Actually, two sale transactions.
58
00:03:09,960 --> 00:03:13,400
And the block disconnected us at the very end.
59
00:03:13,400 --> 00:03:18,760
So we've got some automatic resource management going on inside of this method, executing
60
00:03:18,760 --> 00:03:21,280
around this block.
61
00:03:21,280 --> 00:03:24,800
So now that we've got it working, let's make a little design improvement here.
62
00:03:24,800 --> 00:03:28,480
Well let's say we want to move this method inside of our payment gateway class.
63
00:03:28,480 --> 00:03:32,280
We're just going to move, we're inside of the class right here.
64
00:03:32,280 --> 00:03:33,480
Right?
65
00:03:33,480 --> 00:03:35,440
And right now it's an instance method.
66
00:03:35,440 --> 00:03:39,840
We would have to have a payment gateway object in order to call this method.
67
00:03:39,840 --> 00:03:42,960
We're not going to have a payment gateway object because we don't create one until the
68
00:03:42,960 --> 00:03:44,280
method is actually run.
69
00:03:44,280 --> 00:03:48,400
So we're going to change this to be a class method by using self dot.
70
00:03:48,400 --> 00:03:50,960
And then we're going to change the name of the method because it's pretty clear if
71
00:03:50,960 --> 00:03:54,720
it's a class method on the payment gateway that we don't need to call it open gateway.
72
00:03:54,720 --> 00:03:58,040
We would just call it open because we know what we're opening there.
73
00:03:58,040 --> 00:04:01,520
One small refinement here is if you're inside of a class method and you want to get
74
00:04:01,520 --> 00:04:06,760
to hold the class, weld the self variable points to the payment gateway class here.
75
00:04:06,760 --> 00:04:11,079
So we can change payment gateway class to just self right there.
76
00:04:11,079 --> 00:04:17,560
Now to call that method down here instead of using open gateway, we call payment gateway.
77
00:04:17,560 --> 00:04:18,880
That's the name of the class.
78
00:04:18,880 --> 00:04:20,719
It defines a method called open.
79
00:04:20,719 --> 00:04:22,599
It's a class level method.
80
00:04:22,599 --> 00:04:23,599
Just like that.
81
00:04:23,599 --> 00:04:24,599
And that should run as well.
82
00:04:24,599 --> 00:04:27,880
I'm going to go ahead and change this one for doing refunds.
83
00:04:27,880 --> 00:04:29,760
So we look like this.
84
00:04:29,760 --> 00:04:32,719
Payment gateway.
85
00:04:32,720 --> 00:04:38,120
We need to take the block parameter which is a gateway like that.
86
00:04:38,120 --> 00:04:39,120
We don't need to connect.
87
00:04:39,120 --> 00:04:41,040
That's already handled in the open method.
88
00:04:41,040 --> 00:04:44,240
We're going to submit our transactions and we don't need to disconnect because that's
89
00:04:44,240 --> 00:04:46,240
automatically handled for us.
90
00:04:46,240 --> 00:04:47,240
Save those off.
91
00:04:47,240 --> 00:04:49,680
And we get the same result we got before.
92
00:04:49,680 --> 00:04:53,240
We submit our self transactions and our refund transactions.
93
00:04:53,240 --> 00:04:58,200
But the really nice thing is this code is a lot more compact and expressive.
94
00:04:58,200 --> 00:05:02,200
We don't have to worry about connecting and disconnecting in the right order.
95
00:05:02,200 --> 00:05:06,000
The method called open handles all that for us.
96
00:05:06,000 --> 00:05:11,880
So what if we want to create a connected gateway but not using associated block?
97
00:05:11,880 --> 00:05:14,200
Like let's say we want to do a special scenario.
98
00:05:14,200 --> 00:05:16,640
We want to void a transaction.
99
00:05:16,640 --> 00:05:19,200
We would still need to open the gateway.
100
00:05:19,200 --> 00:05:21,520
Okay, well let's take this open method here.
101
00:05:21,520 --> 00:05:25,159
I'm just going to copy that so it's a bit easier.
102
00:05:25,159 --> 00:05:27,440
And we'd like to just assign it to a variable.
103
00:05:27,440 --> 00:05:30,640
We'd have the open method return to us a gateway object.
104
00:05:30,640 --> 00:05:32,719
But then we're going to manage it from here.
105
00:05:32,719 --> 00:05:36,039
So we would then use gateway and we would submit.
106
00:05:36,039 --> 00:05:39,960
You said it was a void transaction, maybe for $15.
107
00:05:39,960 --> 00:05:44,039
And then because we don't have a block here, we're going to go ahead and disconnect it.
108
00:05:44,039 --> 00:05:48,719
So we're responsible for disconnecting it because we're not passing an associated block
109
00:05:48,719 --> 00:05:49,960
to that open method.
110
00:05:49,960 --> 00:05:50,960
But that's okay.
111
00:05:50,960 --> 00:05:53,960
We want to take some more fine grain control when we do this.
112
00:05:53,960 --> 00:05:58,120
So if we try to run this, well we get this local jump error.
113
00:05:58,120 --> 00:06:02,840
We saw a little bit earlier in the course because we haven't associated a block and we're
114
00:06:02,840 --> 00:06:05,840
calling yield up here, we get this error.
115
00:06:05,840 --> 00:06:06,840
Now it's up to you.
116
00:06:06,840 --> 00:06:11,520
It's a design decision whether you want to require a block or you want somebody to be
117
00:06:11,520 --> 00:06:13,640
able to pass a block or not pass a block.
118
00:06:13,640 --> 00:06:15,960
In our case, we want to support both scenarios.
119
00:06:15,960 --> 00:06:16,960
All right.
120
00:06:16,960 --> 00:06:22,200
And you might think the way to handle this would be to call if block is given just as we
121
00:06:22,200 --> 00:06:24,760
have done before in other scenarios.
122
00:06:24,760 --> 00:06:29,039
But that's not going to work in this scenario because let's look at what happens.
123
00:06:29,039 --> 00:06:33,760
When we call the open method right here without a block, so it's going to create a new
124
00:06:33,760 --> 00:06:36,880
gateway object, it's then going to connect to it.
125
00:06:36,880 --> 00:06:40,520
It's then going to get the this line is going to say, well, a block wasn't given, so
126
00:06:40,520 --> 00:06:42,280
I'm not going to yield to the block.
127
00:06:42,280 --> 00:06:44,960
But it is going to try to disconnect the block.
128
00:06:44,960 --> 00:06:49,920
So what's going to happen here is we're not going to get an object back because no object
129
00:06:49,920 --> 00:06:51,640
was ever passed back to us.
130
00:06:51,640 --> 00:06:55,919
The method tries to do everything for us inside of that method.
131
00:06:55,919 --> 00:06:57,360
So what do we want to do instead?
132
00:06:57,360 --> 00:07:02,000
Well, we need to get back a gateway object that's connected has been disconnected and we can
133
00:07:02,000 --> 00:07:03,520
do whatever we want with it.
134
00:07:03,520 --> 00:07:05,039
So here's a little trick.
135
00:07:05,039 --> 00:07:10,400
Right here after we've connected, we're going to return that gateway object.
136
00:07:10,400 --> 00:07:13,520
We're only going to return the object if a block hasn't been given.
137
00:07:13,520 --> 00:07:17,080
So unless block is given, return the object.
138
00:07:17,080 --> 00:07:22,359
Otherwise, go ahead and yield to it. We don't need the if block given right there.
139
00:07:22,359 --> 00:07:26,440
So if a block isn't supplied, just go ahead and return the gateway and these lines of code
140
00:07:26,440 --> 00:07:27,599
won't be run.
141
00:07:27,599 --> 00:07:31,200
If a block is supplied, do the normal thing, yield to it and disconnect when you're
142
00:07:31,200 --> 00:07:32,200
all done.
143
00:07:32,200 --> 00:07:35,440
So if we save this, now we can use it in multiple scenarios.
144
00:07:35,440 --> 00:07:40,039
We see that we can submit our void transaction, our sales, and our refunds.
145
00:07:40,039 --> 00:07:43,560
We can call the open method with or without a block.
146
00:07:43,560 --> 00:07:47,000
So using block given gives the method two different behaviors.
147
00:07:47,000 --> 00:07:50,640
When it's called with a block, it executes the block and disconnects.
148
00:07:50,640 --> 00:07:54,960
When it's called without a block, it simply returns the gateway object.
149
00:07:54,960 --> 00:08:00,120
Again, it's a design decision whether you want to allow your methods to take blocks or
150
00:08:00,120 --> 00:08:02,480
optionally not take blocks.
151
00:08:02,480 --> 00:08:09,400
But wait, what happens if our block encounters an exception while it's issuing refunds?
152
00:08:09,400 --> 00:08:11,040
Well, we know how to handle that.
153
00:08:11,040 --> 00:08:12,640
We do.
154
00:08:12,640 --> 00:08:16,000
So let's simulate a problem here inside of this refund block.
155
00:08:16,000 --> 00:08:17,680
We're going to raise an exception.
156
00:08:17,680 --> 00:08:20,960
This time, I'm just going to say, oh, problem, exclamation point.
157
00:08:20,960 --> 00:08:21,960
Right?
158
00:08:21,960 --> 00:08:24,520
If we run that, well, our exception is not handled.
159
00:08:24,520 --> 00:08:26,039
We don't want to rescue you clause or anything.
160
00:08:26,039 --> 00:08:28,000
So it propagates all the way up to the top.
161
00:08:28,000 --> 00:08:31,080
But let's look at what happened in the printouts here.
162
00:08:31,080 --> 00:08:37,559
We submitted a refund for $5 and $20, but notice after the refund, our connection wasn't
163
00:08:37,559 --> 00:08:38,559
disconnected.
164
00:08:38,559 --> 00:08:41,319
We don't see a disconnect after this line right here.
165
00:08:41,320 --> 00:08:44,640
Now, and that's because we raised an exception inside of the block.
166
00:08:44,640 --> 00:08:49,720
If we go look inside of our open method, it's not handling exceptions at all.
167
00:08:49,720 --> 00:08:54,640
So when we yield to the block, the exception is going to stop the program from executing
168
00:08:54,640 --> 00:08:55,880
right at this point.
169
00:08:55,880 --> 00:08:59,600
So we're never going to get to this line of code which disconnects the gateway.
170
00:08:59,600 --> 00:09:04,560
So we need to guarantee or ensure that the gateway is disconnected even if the block raises
171
00:09:04,560 --> 00:09:05,560
an exception.
172
00:09:05,560 --> 00:09:09,320
And we know how to do that using our old friend the insure clause.
173
00:09:09,320 --> 00:09:14,480
So we're just going to take that chunk of code and put it inside of it and sure like that.
174
00:09:14,480 --> 00:09:20,360
So if an exception is raised here, we know that that line of code will always be executed.
175
00:09:20,360 --> 00:09:25,920
If we run it now, notice we get the line after the refunds disconnected in a call.
176
00:09:25,920 --> 00:09:28,360
So the disconnect happened.
177
00:09:28,360 --> 00:09:30,200
But there's a small problem here.
178
00:09:30,200 --> 00:09:33,960
Imagine up in this code where we're creating a new gateway with new.
179
00:09:33,960 --> 00:09:37,560
Imagine somewhere in that code, it raised an exception.
180
00:09:37,560 --> 00:09:41,839
Well if it raises an exception up here in this line of code, ensure we'll still be called,
181
00:09:41,839 --> 00:09:44,400
it will try to disconnect the gateway.
182
00:09:44,400 --> 00:09:48,400
But if it raises an exception up here, then it will never be connected in the first place
183
00:09:48,400 --> 00:09:53,439
and we'll try to disconnect a gateway that hasn't been connected in the first place.
184
00:09:53,439 --> 00:09:58,520
So we need to be a little bit more selective about which lines of code the insure clause
185
00:09:58,520 --> 00:10:00,000
applies to.
186
00:10:00,000 --> 00:10:02,280
And we can do that using begin.
187
00:10:02,280 --> 00:10:05,959
We only want to ensure to be applied to this line of code when we're yielding to the
188
00:10:05,959 --> 00:10:06,959
block.
189
00:10:06,960 --> 00:10:10,320
So we can say begin.
190
00:10:10,320 --> 00:10:11,560
All right.
191
00:10:11,560 --> 00:10:17,960
That's yielding to the block and we want to ensure that that happens after that block is run.
192
00:10:17,960 --> 00:10:23,920
So we've got a begin, some statement, and then ensure only gets applied to that section
193
00:10:23,920 --> 00:10:24,920
of code.
194
00:10:24,920 --> 00:10:30,320
And we know by this point our gateway is already connected so we're good to go.
195
00:10:30,320 --> 00:10:32,360
Now as things stand, there's no rescue clause.
196
00:10:32,360 --> 00:10:36,040
So any exception is still going to get propagated all the way to the top.
197
00:10:36,040 --> 00:10:42,640
And we could optionally add a rescue clause here as we did before rescue exception,
198
00:10:42,640 --> 00:10:45,800
e, and we could print out the message associated with that.
199
00:10:45,800 --> 00:10:50,439
And again, this rescue clause only applies to that line of code.
200
00:10:50,439 --> 00:10:55,640
So the takeaway here is we've got resource management and exception handling encapsulated
201
00:10:55,640 --> 00:10:59,000
in this one spot in this one open method.
202
00:10:59,000 --> 00:11:04,880
And that makes it really easy to add or remove stuff being executed around.
203
00:11:04,880 --> 00:11:07,960
This is a really common pattern for managing resources.
204
00:11:07,960 --> 00:11:12,200
So let's look at one more example of this that's built into Ruby.
205
00:11:12,200 --> 00:11:16,960
Yeah, you'll often want to open up a file, do something with its contents, and then ensure
206
00:11:16,960 --> 00:11:19,880
that the file is closed when you're all done with the file.
207
00:11:19,880 --> 00:11:22,280
And Ruby's got you covered.
208
00:11:22,280 --> 00:11:25,280
Okay, and Ruby, you can write and read a file like this.
209
00:11:25,280 --> 00:11:30,400
You can call the open method on the file class, pass in a file name, and a mode.
210
00:11:30,400 --> 00:11:32,320
In this case, we're writing to the file.
211
00:11:32,320 --> 00:11:36,520
We get back an open file object, in this case, it's in the variable F.
212
00:11:36,520 --> 00:11:40,840
And then we can just use puts on that F object that print out some strings to that file,
213
00:11:40,840 --> 00:11:43,280
and at the end, we need to make sure to close it.
214
00:11:43,280 --> 00:11:46,400
When you turn around and want to read the file, you open the file with the file name,
215
00:11:46,400 --> 00:11:50,840
and the mode is now set to R, which is reading, you get back an open file object again.
216
00:11:50,840 --> 00:11:52,280
We can iterate through the file.
217
00:11:52,280 --> 00:11:56,880
This is an example of each on a file object, gives you each line, which is pretty cool.
218
00:11:56,880 --> 00:11:59,440
And then you've got to remember to close the file when you're done.
219
00:11:59,440 --> 00:12:03,040
So if we run this, it wrote to a file, and then it read it back in again,
220
00:12:03,040 --> 00:12:07,000
and it just prints out, hello, and goodbye, which are the contents of that file.
221
00:12:07,000 --> 00:12:10,720
So this works, but it has the same problem that we ran into with the gateway.
222
00:12:10,720 --> 00:12:14,040
We have to remember to close the file when we're done.
223
00:12:14,040 --> 00:12:18,720
But conveniently, the open method is designed to optionally take a block,
224
00:12:18,720 --> 00:12:22,400
and using it with a block makes it a lot less prone to error.
225
00:12:22,400 --> 00:12:26,240
So the way to do that is instead of getting back a file object like that,
226
00:12:26,240 --> 00:12:30,680
we can associate a block with the open method, and we're going to get a block parameter.
227
00:12:30,680 --> 00:12:32,880
It's going to be the file object itself.
228
00:12:32,880 --> 00:12:37,360
Then inside of the block, we can use that F object, print out our strings,
229
00:12:37,360 --> 00:12:41,840
and we don't have to remember to close it, because that's going to be handled by the open method for us.
230
00:12:41,840 --> 00:12:43,240
So we just end the block.
231
00:12:43,240 --> 00:12:48,240
In the same way when we're reading, we can give it a block parameter, and a block there,
232
00:12:48,240 --> 00:12:52,240
inside of the block will read those things, and we don't have to close it at the end.
233
00:12:52,240 --> 00:12:56,800
So the responsibility for closing an open file has shifted from you, the coder,
234
00:12:56,800 --> 00:13:00,080
to the file objects themselves, which is really nice.
235
00:13:00,080 --> 00:13:05,440
So just for fun, how might we implement a file that open in its simplest form?
236
00:13:05,440 --> 00:13:09,520
Well, let's go ahead and change the occurrences of open here to my open.
237
00:13:09,520 --> 00:13:12,480
We're going to write our own version of this.
238
00:13:12,480 --> 00:13:18,480
We know these are defined inside of the file class, so let's go ahead and reopen Ruby's file class.
239
00:13:18,480 --> 00:13:22,400
The method is a class method we're calling on the class is going to be self-dot,
240
00:13:22,400 --> 00:13:24,880
and this can be called my open.
241
00:13:24,880 --> 00:13:26,320
All right, it takes some parameters.
242
00:13:26,320 --> 00:13:30,800
The first parameter is the file name, and the second parameter is the mode.
243
00:13:30,800 --> 00:13:33,440
All right, what's the first thing we need to do inside of here?
244
00:13:33,440 --> 00:13:36,080
Well, we need to create a new file that's open.
245
00:13:36,080 --> 00:13:41,680
Why we do that is we call file.new, pass in the file name, or just go ahead and
246
00:13:41,680 --> 00:13:43,360
delegate that down to that method.
247
00:13:43,360 --> 00:13:48,240
File.new actually opens the file and returns a new file handle or file object.
248
00:13:48,240 --> 00:13:52,320
Oh, and as a small little refinement here, you can use self because inside of the
249
00:13:52,320 --> 00:13:56,640
class method, self is going to refer to the file class itself in this case.
250
00:13:57,760 --> 00:14:02,560
Last thing we need to do, we know, is to close the file in between those two things.
251
00:14:02,560 --> 00:14:06,640
We need to yield to the block and give the block the file as a block parameter.
252
00:14:07,520 --> 00:14:13,840
Okay, that's a pretty good start, but what happens if a block isn't given to this my open method?
253
00:14:13,840 --> 00:14:18,400
Well, what we want to do there is just simply return the file objects.
254
00:14:18,400 --> 00:14:22,080
Say, return the file unless a block is given.
255
00:14:23,760 --> 00:14:29,520
That way we can use file.open or file.myopen, just as we did when we started out by getting back a
256
00:14:29,520 --> 00:14:33,440
file object, doing what we want with it, and then taking care of closing it ourselves.
257
00:14:34,160 --> 00:14:36,400
Of course, we also need to handle exceptions.
258
00:14:37,040 --> 00:14:41,840
In particular, we need to make sure that the file is always closed, whether the block
259
00:14:41,840 --> 00:14:45,120
raises it and exception or not, and we learned how to do that earlier.
260
00:14:45,120 --> 00:14:48,160
We want to scope it to just this line of code so we're going to say begin.
261
00:14:49,840 --> 00:14:55,840
Yield to the block and then ensure that the file object is closed at the very end there.
262
00:14:56,480 --> 00:15:00,000
Now, in this particular case, there's no rescue clause, so any exceptions are going to
263
00:15:00,000 --> 00:15:04,640
get propagated to the code that calls open, which is in a better position to handle it anyway.
264
00:15:05,200 --> 00:15:08,880
All right, if we save that, but we run it, we get the same result.
265
00:15:08,880 --> 00:15:14,560
So we basically re-implemented the open method using the techniques we've learned throughout this course.
266
00:15:15,120 --> 00:15:15,760
Pretty cool.
267
00:15:16,480 --> 00:15:20,400
So these examples pull together a lot of things we learned throughout this course.
268
00:15:20,720 --> 00:15:24,800
Yeah, and hopefully you recognize some recurring patterns in all these examples.
269
00:15:24,800 --> 00:15:43,359
And in the exercise that follows, you'll find some more examples to practice resource management with blocks.
25490
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.