trackler 2.0.3.0 → 2.0.3.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 +4 -4
- data/fixtures/common/exercises/no-metadata/description.md +1 -0
- data/lib/trackler/problem.rb +12 -0
- data/lib/trackler/problems.rb +8 -12
- data/lib/trackler/version.rb +1 -1
- data/tracks/bash/README.md +2 -0
- data/tracks/c/config.json +9 -2
- data/tracks/c/exercises/sieve/makefile +15 -0
- data/tracks/c/exercises/sieve/src/example.c +50 -0
- data/tracks/c/exercises/sieve/src/sieve.h +10 -0
- data/tracks/c/exercises/sieve/test/test_sieve.c +113 -0
- data/tracks/c/exercises/sieve/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/sieve/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/sieve/test/vendor/unity_internals.h +701 -0
- data/tracks/coffeescript/.travis.yml +1 -0
- data/tracks/coldfusion/.travis.yml +1 -0
- data/tracks/crystal/Makefile +18 -15
- data/tracks/crystal/README.md +5 -5
- data/tracks/crystal/config.json +6 -0
- data/tracks/crystal/exercises/acronym/src/acronym.cr +1 -0
- data/tracks/crystal/exercises/anagram/src/anagram.cr +1 -0
- data/tracks/crystal/exercises/atbash-cipher/src/atbash_cipher.cr +1 -0
- data/tracks/crystal/exercises/binary/src/binary.cr +1 -0
- data/tracks/crystal/exercises/bob/src/bob.cr +1 -0
- data/tracks/crystal/exercises/bracket-push/src/bracket_push.cr +1 -0
- data/tracks/crystal/exercises/difference-of-squares/spec/difference_of_squares_spec.cr +44 -0
- data/tracks/crystal/exercises/difference-of-squares/src/example.cr +15 -0
- data/tracks/crystal/exercises/forth/src/forth.cr +1 -0
- data/tracks/crystal/exercises/gigasecond/src/gigasecond.cr +1 -0
- data/tracks/crystal/exercises/hamming/src/hamming.cr +1 -0
- data/tracks/crystal/exercises/hello-world/src/hello_world.cr +1 -0
- data/tracks/crystal/exercises/largest-series-product/src/largest_series_product.cr +1 -0
- data/tracks/crystal/exercises/leap/src/leap.cr +1 -0
- data/tracks/crystal/exercises/pangram/src/pangram.cr +1 -0
- data/tracks/crystal/exercises/raindrops/src/raindrops.cr +1 -0
- data/tracks/crystal/exercises/react/src/react.cr +1 -0
- data/tracks/crystal/exercises/rna-transcription/src/rna_transcription.cr +1 -0
- data/tracks/crystal/exercises/roman-numerals/src/roman_numerals.cr +1 -0
- data/tracks/crystal/exercises/sieve/src/sieve.cr +1 -0
- data/tracks/crystal/src/generator/exercises/difference_of_squares.cr +39 -0
- data/tracks/go/exercises/allergies/allergies_test.go +2 -2
- data/tracks/go/exercises/anagram/anagram_test.go +3 -3
- data/tracks/go/exercises/grade-school/grade_school_test.go +3 -3
- data/tracks/go/exercises/secret-handshake/secret_handshake_test.go +1 -1
- data/tracks/java/config.json +13 -1
- data/tracks/java/exercises/binary-search-tree/build.gradle +18 -0
- data/tracks/java/exercises/binary-search-tree/src/example/java/BST.java +122 -0
- data/tracks/java/exercises/binary-search-tree/src/main/java/.keep +0 -0
- data/tracks/java/exercises/binary-search-tree/src/test/java/.keep +0 -0
- data/tracks/java/exercises/binary-search-tree/src/test/java/BSTTest.java +163 -0
- data/tracks/java/exercises/pythagorean-triplet/build.gradle +18 -0
- data/tracks/java/exercises/pythagorean-triplet/src/example/java/PythagoreanTriplet.java +117 -0
- data/tracks/java/exercises/pythagorean-triplet/src/main/java/PythagoreanTriplet.java +3 -0
- data/tracks/java/exercises/pythagorean-triplet/src/test/java/PythagoreanTripletTest.java +95 -0
- data/tracks/java/exercises/settings.gradle +2 -0
- data/tracks/julia/README.md +16 -0
- data/tracks/perl5/README.md +2 -0
- data/tracks/perl6/README.md +2 -1
- data/tracks/php/config.json +5 -0
- data/tracks/php/exercises/sieve/example.php +29 -0
- data/tracks/php/exercises/sieve/sieve_test.php +201 -0
- data/tracks/pony/.travis.yml +1 -0
- data/tracks/python/exercises/anagram/anagram_test.py +1 -0
- data/tracks/python/exercises/beer-song/beer_song_test.py +1 -0
- data/tracks/python/exercises/binary-search/binary_search_test.py +1 -0
- data/tracks/python/exercises/binary/binary_test.py +1 -0
- data/tracks/python/exercises/bob/bob_test.py +1 -0
- data/tracks/python/exercises/clock/clock_test.py +1 -0
- data/tracks/python/exercises/etl/etl_test.py +1 -0
- data/tracks/python/exercises/gigasecond/gigasecond_test.py +1 -0
- data/tracks/python/exercises/grains/grains_test.py +1 -0
- data/tracks/python/exercises/leap/leap_test.py +1 -0
- data/tracks/python/exercises/meetup/meetup_test.py +1 -0
- data/tracks/python/exercises/nucleotide-count/nucleotide_count_test.py +1 -0
- data/tracks/python/exercises/ocr-numbers/example.py +1 -0
- data/tracks/python/exercises/ocr-numbers/ocr_test.py +1 -0
- data/tracks/python/exercises/perfect-numbers/perfect_numbers_test.py +1 -0
- data/tracks/python/exercises/phone-number/phone_number_test.py +1 -0
- data/tracks/python/exercises/pig-latin/pig_latin_test.py +1 -0
- data/tracks/python/exercises/point-mutations/point_mutations_test.py +1 -0
- data/tracks/python/exercises/poker/poker_test.py +1 -0
- data/tracks/python/exercises/prime-factors/prime_factors_test.py +1 -0
- data/tracks/python/exercises/pythagorean-triplet/example.py +2 -3
- data/tracks/python/exercises/rail-fence-cipher/rail_fence_cipher_test.py +1 -0
- data/tracks/python/exercises/raindrops/raindrops_test.py +1 -0
- data/tracks/python/exercises/rectangles/rectangles_count_test.py +1 -0
- data/tracks/python/exercises/robot-simulator/robot_simulator_test.py +1 -0
- data/tracks/python/exercises/roman-numerals/roman_numerals_test.py +1 -0
- data/tracks/python/exercises/run-length-encoding/run_length_test.py +1 -0
- data/tracks/python/exercises/say/say_test.py +1 -0
- data/tracks/python/exercises/scrabble-score/scrabble_score_test.py +1 -0
- data/tracks/python/exercises/sieve/sieve_test.py +1 -0
- data/tracks/python/exercises/space-age/space_age_test.py +1 -0
- data/tracks/python/exercises/triangle/triangle_test.py +1 -0
- data/tracks/python/exercises/word-count/word_count_test.py +1 -0
- data/tracks/python/requirements-travis.txt +1 -1
- data/tracks/ruby/docs/24pullrequests.md +21 -0
- data/tracks/ruby/exercises/bowling/.version +1 -1
- data/tracks/ruby/exercises/bowling/bowling_test.rb +44 -15
- data/tracks/ruby/exercises/bowling/example.rb +10 -5
- data/tracks/ruby/exercises/bowling/example.tt +4 -2
- data/tracks/ruby/lib/bowling_cases.rb +1 -1
- data/tracks/scala/exercises/bank-account/HINTS.md +11 -0
- data/tracks/scala/exercises/bank-account/example.scala +2 -4
- data/tracks/scala/exercises/bank-account/src/main/scala/BankAccount.scala +13 -0
- data/tracks/scala/exercises/bank-account/src/test/scala/BankAccountTest.scala +5 -5
- data/tracks/scala/exercises/hamming/HINTS.md +57 -0
- data/tracks/scala/exercises/hello-world/HINTS.md +8 -0
- data/tracks/scala/exercises/nucleotide-count/HINTS.md +61 -0
- metadata +48 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## 24 Pull Requests for Exercism - Ruby Edition!
|
|
2
|
+
|
|
3
|
+
We are welcoming contributors to the project.
|
|
4
|
+
|
|
5
|
+
Look for the following labels in our issue list:
|
|
6
|
+
|
|
7
|
+
* first-timers only
|
|
8
|
+
* good first patch
|
|
9
|
+
* bug
|
|
10
|
+
* enhancement
|
|
11
|
+
|
|
12
|
+
Or notice something to contribute? Documentation not quite up to par?
|
|
13
|
+
Something missing? Submitting and reviewing exercises on Exercism and
|
|
14
|
+
notice something you don't like? Create a pull request!
|
|
15
|
+
|
|
16
|
+
Or notice something to contribute? Documentation not quite up to par?
|
|
17
|
+
Something missing? Create a pull request!
|
|
18
|
+
|
|
19
|
+
Check out the [Getting Involved in a Track](https://github.com/exercism/exercism.io/blob/master/docs/getting-involved-in-a-track.md) documentation, and some [ideas for things we are looking for](http://exercism.io/languages/ruby/todo) for exercises that are needed to be implemented.
|
|
20
|
+
|
|
21
|
+
We are available to answer questions in the [](https://gitter.im/exercism/xruby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3
|
|
@@ -3,8 +3,8 @@ gem 'minitest', '>= 5.0.0'
|
|
|
3
3
|
require 'minitest/autorun'
|
|
4
4
|
require_relative 'bowling'
|
|
5
5
|
|
|
6
|
-
# Test data version:
|
|
7
|
-
#
|
|
6
|
+
# Test data version: c59c2c4
|
|
7
|
+
#
|
|
8
8
|
class BowlingTest < Minitest::Test
|
|
9
9
|
def setup
|
|
10
10
|
@game = Game.new
|
|
@@ -50,7 +50,7 @@ class BowlingTest < Minitest::Test
|
|
|
50
50
|
assert_equal 17, @game.score
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def test_a_strike_earns_ten_points_in_a_frame_with_a_single_roll
|
|
54
54
|
skip
|
|
55
55
|
roll([10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
56
56
|
assert_equal 10, @game.score
|
|
@@ -100,7 +100,7 @@ class BowlingTest < Minitest::Test
|
|
|
100
100
|
|
|
101
101
|
def test_rolls_can_not_score_negative_points
|
|
102
102
|
skip
|
|
103
|
-
assert_raises
|
|
103
|
+
assert_raises Game::BowlingError do
|
|
104
104
|
roll([-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
105
105
|
@game.score
|
|
106
106
|
end
|
|
@@ -108,7 +108,7 @@ class BowlingTest < Minitest::Test
|
|
|
108
108
|
|
|
109
109
|
def test_a_roll_can_not_score_more_than_10_points
|
|
110
110
|
skip
|
|
111
|
-
assert_raises
|
|
111
|
+
assert_raises Game::BowlingError do
|
|
112
112
|
roll([11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
113
113
|
@game.score
|
|
114
114
|
end
|
|
@@ -116,23 +116,53 @@ class BowlingTest < Minitest::Test
|
|
|
116
116
|
|
|
117
117
|
def test_two_rolls_in_a_frame_can_not_score_more_than_10_points
|
|
118
118
|
skip
|
|
119
|
-
assert_raises
|
|
119
|
+
assert_raises Game::BowlingError do
|
|
120
120
|
roll([5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
121
121
|
@game.score
|
|
122
122
|
end
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
def test_bonus_roll_after_a_strike_in_the_last_frame_can_not_score_more_than_10_points
|
|
126
|
+
skip
|
|
127
|
+
assert_raises Game::BowlingError do
|
|
128
|
+
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11])
|
|
129
|
+
@game.score
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
125
133
|
def test_two_bonus_rolls_after_a_strike_in_the_last_frame_can_not_score_more_than_10_points
|
|
126
134
|
skip
|
|
127
|
-
assert_raises
|
|
135
|
+
assert_raises Game::BowlingError do
|
|
128
136
|
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6])
|
|
129
137
|
@game.score
|
|
130
138
|
end
|
|
131
139
|
end
|
|
132
140
|
|
|
141
|
+
def test_two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike
|
|
142
|
+
skip
|
|
143
|
+
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6])
|
|
144
|
+
assert_equal 26, @game.score
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_the_second_bonus_rolls_after_a_strike_in_the_last_frame_can_not_be_a_strike_if_the_first_one_is_not_a_strike
|
|
148
|
+
skip
|
|
149
|
+
assert_raises Game::BowlingError do
|
|
150
|
+
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10])
|
|
151
|
+
@game.score
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def test_second_bonus_roll_after_a_strike_in_the_last_frame_can_not_score_than_10_points
|
|
156
|
+
skip
|
|
157
|
+
assert_raises Game::BowlingError do
|
|
158
|
+
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 11])
|
|
159
|
+
@game.score
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
133
163
|
def test_an_unstarted_game_can_not_be_scored
|
|
134
164
|
skip
|
|
135
|
-
assert_raises
|
|
165
|
+
assert_raises Game::BowlingError do
|
|
136
166
|
roll([])
|
|
137
167
|
@game.score
|
|
138
168
|
end
|
|
@@ -140,7 +170,7 @@ class BowlingTest < Minitest::Test
|
|
|
140
170
|
|
|
141
171
|
def test_an_incomplete_game_can_not_be_scored
|
|
142
172
|
skip
|
|
143
|
-
assert_raises
|
|
173
|
+
assert_raises Game::BowlingError do
|
|
144
174
|
roll([0, 0])
|
|
145
175
|
@game.score
|
|
146
176
|
end
|
|
@@ -148,7 +178,7 @@ class BowlingTest < Minitest::Test
|
|
|
148
178
|
|
|
149
179
|
def test_a_game_with_more_than_ten_frames_can_not_be_scored
|
|
150
180
|
skip
|
|
151
|
-
assert_raises
|
|
181
|
+
assert_raises Game::BowlingError do
|
|
152
182
|
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
153
183
|
@game.score
|
|
154
184
|
end
|
|
@@ -156,7 +186,7 @@ class BowlingTest < Minitest::Test
|
|
|
156
186
|
|
|
157
187
|
def test_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
|
|
158
188
|
skip
|
|
159
|
-
assert_raises
|
|
189
|
+
assert_raises Game::BowlingError do
|
|
160
190
|
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10])
|
|
161
191
|
@game.score
|
|
162
192
|
end
|
|
@@ -164,7 +194,7 @@ class BowlingTest < Minitest::Test
|
|
|
164
194
|
|
|
165
195
|
def test_both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
|
|
166
196
|
skip
|
|
167
|
-
assert_raises
|
|
197
|
+
assert_raises Game::BowlingError do
|
|
168
198
|
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10])
|
|
169
199
|
@game.score
|
|
170
200
|
end
|
|
@@ -172,7 +202,7 @@ class BowlingTest < Minitest::Test
|
|
|
172
202
|
|
|
173
203
|
def test_bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
|
|
174
204
|
skip
|
|
175
|
-
assert_raises
|
|
205
|
+
assert_raises Game::BowlingError do
|
|
176
206
|
roll([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3])
|
|
177
207
|
@game.score
|
|
178
208
|
end
|
|
@@ -194,9 +224,8 @@ class BowlingTest < Minitest::Test
|
|
|
194
224
|
#
|
|
195
225
|
# If you are curious, read more about constants on RubyDoc:
|
|
196
226
|
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html
|
|
197
|
-
|
|
198
227
|
def test_bookkeeping
|
|
199
228
|
skip
|
|
200
|
-
assert_equal
|
|
229
|
+
assert_equal 3, BookKeeping::VERSION
|
|
201
230
|
end
|
|
202
231
|
end
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
module BookKeeping
|
|
2
|
-
VERSION =
|
|
2
|
+
VERSION = 3
|
|
3
3
|
end
|
|
4
4
|
|
|
5
5
|
class Game
|
|
6
6
|
PINS = { MIN: 0, MAX: 10 }.freeze
|
|
7
7
|
at_exit { public :roll, :score }
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
class BowlingError < StandardError; end
|
|
11
|
+
class RollError < BowlingError; end
|
|
12
|
+
class GameError < BowlingError; end
|
|
13
|
+
|
|
9
14
|
private
|
|
10
15
|
|
|
11
16
|
def initialize
|
|
@@ -20,9 +25,9 @@ class Game
|
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def validate(pins)
|
|
23
|
-
raise
|
|
24
|
-
raise
|
|
25
|
-
raise
|
|
28
|
+
raise RollError, 'Invalid number of pins' unless (PINS[:MIN]..PINS[:MAX]).cover?(pins)
|
|
29
|
+
raise RollError, 'Too many pins in frame' unless valid_frame?(pins)
|
|
30
|
+
raise GameError, 'Game is over, no rolls allowed' if game_complete?
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def valid_frame?(pins)
|
|
@@ -33,7 +38,7 @@ class Game
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def score
|
|
36
|
-
raise
|
|
41
|
+
raise GameError, 'Score unavailable until end of the game' unless game_complete?
|
|
37
42
|
@score_card.values.map.with_index(1) do |f, i|
|
|
38
43
|
score_frame(f, i)
|
|
39
44
|
end.reduce(:+)
|
|
@@ -3,8 +3,8 @@ gem 'minitest', '>= 5.0.0'
|
|
|
3
3
|
require 'minitest/autorun'
|
|
4
4
|
require_relative 'bowling'
|
|
5
5
|
|
|
6
|
-
# Test data version:
|
|
7
|
-
#
|
|
6
|
+
# Test data version: <%= sha1 %>
|
|
7
|
+
#
|
|
8
8
|
class BowlingTest < Minitest::Test
|
|
9
9
|
def setup
|
|
10
10
|
@game = Game.new
|
|
@@ -13,11 +13,13 @@ class BowlingTest < Minitest::Test
|
|
|
13
13
|
def roll(rolls)
|
|
14
14
|
rolls.each { |pins| @game.roll(pins) }
|
|
15
15
|
end
|
|
16
|
+
|
|
16
17
|
<% test_cases.each do |test_case| %>
|
|
17
18
|
def <%= test_case.test_name %>
|
|
18
19
|
<%= test_case.skipped %>
|
|
19
20
|
<%= test_case.work_load %>
|
|
20
21
|
end
|
|
22
|
+
|
|
21
23
|
<% end %>
|
|
22
24
|
<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
|
|
23
25
|
def test_bookkeeping
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Hints
|
|
2
|
+
|
|
3
|
+
This exercise is testing mutable state that can be accessed saftely from multiple threads. Scala provides a variety of ways to protect
|
|
4
|
+
mutable state. For developers familiar with Java concurrency, Scala can utilize the Java concurrency support such as the Java synchronized block.
|
|
5
|
+
|
|
6
|
+
### Common Pitfalls
|
|
7
|
+
|
|
8
|
+
In Scala there are two ways to achieve mutable state: Use a "var" or a mutable object.
|
|
9
|
+
Two common mistakes here are:
|
|
10
|
+
- Do not use a "var" that is also a mutable object. One is enough, but not both together.
|
|
11
|
+
- Don't expose the "var" or mutable object to the outside world. So make them "private" and change the mutable object into immutable before you return it as a value.
|
|
@@ -3,12 +3,12 @@ import org.scalatest.{Matchers, FunSuite}
|
|
|
3
3
|
|
|
4
4
|
class BankAccountTest extends FunSuite with Matchers with Conductors with IntegrationPatience {
|
|
5
5
|
test("open account") {
|
|
6
|
-
|
|
6
|
+
Bank.openAccount().getBalance should be (Some(0))
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
test("incrementing and checking balance") {
|
|
10
10
|
pending
|
|
11
|
-
val acct =
|
|
11
|
+
val acct = Bank.openAccount()
|
|
12
12
|
acct.getBalance should be (Some(0))
|
|
13
13
|
acct.incrementBalance(10) should be (Some(10))
|
|
14
14
|
acct.getBalance should be (Some(10))
|
|
@@ -18,7 +18,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
18
18
|
|
|
19
19
|
test("closed account should hold no balance") {
|
|
20
20
|
pending
|
|
21
|
-
val acct =
|
|
21
|
+
val acct = Bank.openAccount()
|
|
22
22
|
acct.closeAccount()
|
|
23
23
|
acct.incrementBalance(10)
|
|
24
24
|
acct.incrementBalance(10)
|
|
@@ -30,7 +30,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
30
30
|
val conductor = new Conductor
|
|
31
31
|
import conductor._
|
|
32
32
|
|
|
33
|
-
val acct =
|
|
33
|
+
val acct = Bank.openAccount()
|
|
34
34
|
|
|
35
35
|
thread("t1") {
|
|
36
36
|
acct.incrementBalance(10)
|
|
@@ -54,7 +54,7 @@ class BankAccountTest extends FunSuite with Matchers with Conductors with Integr
|
|
|
54
54
|
val conductor = new Conductor
|
|
55
55
|
import conductor._
|
|
56
56
|
|
|
57
|
-
val acct =
|
|
57
|
+
val acct = Bank.openAccount()
|
|
58
58
|
|
|
59
59
|
thread("t1") {
|
|
60
60
|
for (a <- 1 to 10)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## Hints
|
|
2
|
+
`Option` is used to indicate a computation that may possibly have no useful result
|
|
3
|
+
(for example due to an error or invalid input).
|
|
4
|
+
If you are unfamiliar with `Option` you may read [this tutorial](http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html).
|
|
5
|
+
`Option` is a so-called [Monad](https://en.wikipedia.org/wiki/Monad_(functional_programming)) which covers a "computational aspect", in this case possible absence of a value.
|
|
6
|
+
Proper use of Monads can result in very concise yet elegant
|
|
7
|
+
and readable code. Improper use can easily result in the contrary.
|
|
8
|
+
Watch [this video](https://www.youtube.com/watch?v=Mw_Jnn_Y5iA) to learn more.
|
|
9
|
+
#### Common pitfalls that you should avoid
|
|
10
|
+
There are a few rules of thumbs for `Option`:
|
|
11
|
+
1. If you don't need it don't use it. Instead of
|
|
12
|
+
```scala
|
|
13
|
+
def add1(x: Int): Option[Int] = Some(x + 1)
|
|
14
|
+
```
|
|
15
|
+
better have
|
|
16
|
+
```scala
|
|
17
|
+
def add1(x: Int): Int = x + 1
|
|
18
|
+
```
|
|
19
|
+
(there is `Option.map` to apply such simple functions,
|
|
20
|
+
so you don't have to clutter them with `Option`).
|
|
21
|
+
2. Don't "unwrap" if you don't really need to.
|
|
22
|
+
Often there are built-in functions for your purpose. Indicators of premature
|
|
23
|
+
unwrapping are `isDefined/isEmpty` or pattern matching. Instead of
|
|
24
|
+
```scala
|
|
25
|
+
val x: Option[Int] = ...
|
|
26
|
+
|
|
27
|
+
if (x.isDefined) x.get + 1 else 0
|
|
28
|
+
// or
|
|
29
|
+
x match {
|
|
30
|
+
case Some(n) => n + 1
|
|
31
|
+
case None => 0
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
better have
|
|
35
|
+
```scala
|
|
36
|
+
x map (_ + 1) getOrElse 0
|
|
37
|
+
```
|
|
38
|
+
3. Monads can be used inside a for-comprehension FTW.
|
|
39
|
+
This is advisable when you want to "compose" several `Option` instances. Instead of
|
|
40
|
+
```scala
|
|
41
|
+
val xo: Option[Int] = ...
|
|
42
|
+
val yo: Option[Int] = ...
|
|
43
|
+
val zo: Option[Int] = ...
|
|
44
|
+
|
|
45
|
+
xo.flatMap(x =>
|
|
46
|
+
yo.flatMap(y =>
|
|
47
|
+
zo.map(z =>
|
|
48
|
+
x + y + z)))
|
|
49
|
+
```
|
|
50
|
+
better have
|
|
51
|
+
```scala
|
|
52
|
+
for {
|
|
53
|
+
x <- xo
|
|
54
|
+
y <- yo
|
|
55
|
+
z <- zo
|
|
56
|
+
} yield x + y + z
|
|
57
|
+
```
|