Skip to content

Commit 573ca32

Browse files
committed
Merge pull request #8 from daigaku-ruby/add-chapter-strings
Add chapter strings
2 parents bdb03dc + c2a9492 commit 573ca32

9 files changed

Lines changed: 269 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# e.g.
2+
firstname = 'Peter'
3+
lastname = 'Pan'
4+
fullname = "#{lastname}, #{firstname}"
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
require 'rspec'
2+
require 'rspec/expectations'
3+
require 'code_breaker'
4+
5+
RSpec::Matchers.define :run_string_interpolation do |expected|
6+
match do |actual|
7+
interpolation = interpolation_part_of(actual)
8+
return false if interpolation.nil?
9+
interpolation[:lvasgn][1][:dstr] == expected
10+
end
11+
12+
failure_message do |actual|
13+
actual_line = actual.split("\n").select do |line|
14+
line =~ /fullname\s?=.+/
15+
end
16+
17+
parsed_line = CodeBreaker.parse(actual_line.join)
18+
interpolation = parsed_line[:lvasgn].last
19+
20+
unless interpolation.is_a?(Hash) && interpolation[:dstr]
21+
return "You didn't do any string interpolation."
22+
end
23+
24+
[['solution::code']]
25+
26+
%Q{Your interpolated fullname shoud be "#{lastname}, #{firstname}"
27+
------- but is "#{fullname}".}
28+
end
29+
30+
def interpolation_part_of(actual)
31+
parsed = CodeBreaker.parse(actual)
32+
33+
interpolation = parsed.select do |part|
34+
next unless part.is_a?(Hash)
35+
next unless part.has_key?(:lvasgn)
36+
next unless part[:lvasgn][0] == :fullname
37+
next unless part[:lvasgn][1].is_a?(Hash)
38+
39+
part[:lvasgn][1].has_key?(:dstr)
40+
end
41+
42+
interpolation.first
43+
end
44+
end
45+
46+
describe "Your code" do
47+
[['solution::code']]
48+
49+
VARIABLES = [:firstname, :lastname, :fullname].freeze
50+
51+
VARIABLES.each do |name|
52+
it "defines a variable with name \"#{name}\"" do
53+
expect(local_variables.include?(name)).to be true
54+
end
55+
56+
if name != :fullname && local_variables.include?(name)
57+
it "assigns a String to the variable \"#{name}\"" do
58+
expect(eval(name.to_s)).to be_a String
59+
end
60+
end
61+
end
62+
63+
if (local_variables & VARIABLES).sort == VARIABLES.sort
64+
it "creates an interpolated String" do
65+
statement = [[{ lvar: :lastname }], String, [{ lvar: :firstname }]]
66+
code_lines = %q{ [['solution::code']] }
67+
68+
expect(code_lines).to run_string_interpolation(statement)
69+
end
70+
end
71+
end

3_Strings/1_Interpolation/task.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Interpolation
2+
3+
---
4+
5+
*You will learn:*
6+
- how to create interpolated Strings
7+
8+
---
9+
10+
You already learned that you can define a String with either single quotes or
11+
double quotes. The resulting String is the same, but if you use the double quotes
12+
for creating a String you can interpolate variables within this string.
13+
14+
The interpolated statement has to be wrapped in *#{}* – a hash followed by curly brackets.
15+
Let's look at an example:
16+
17+
` amount = 5`
18+
` message = "I learned` *#{amount}* `units today."`
19+
20+
The variable `message` now has the value *"I learned 5 units today."*.
21+
If you would use single quotes then the String would not evaluate the *#{}* part:
22+
23+
` message = 'I learned #{amount} units today.'`
24+
25+
The variable `message` has the value *"I learned #{amount} values today."*
26+
the value of `amount` will not be interpolated into the String.
27+
28+
A common pattern is:
29+
30+
\* You should use single quotes `''` for Strings that are not interpolated
31+
\* You should only use double quotes `""` for Strings that should be interpolated
32+
33+
---
34+
35+
Define a variable `firstname` and `lastname` with your firstname and lastname as values.
36+
Then create a variable `fullname` and assign an interpolated String by using
37+
the `lastname` and `firstname` variables.
38+
39+
The resulting String should look like *"YourLastname, YourFirstname"*.
40+
41+
---
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# e.g.
2+
('Ruby' << 32) + 'r' + 'o' * 5 + 'cks' << 33
3+
4+
# or
5+
'Ruby'.concat(32) + 'r' + 'o' * 5 + 'cks'.concat(33)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
require 'rspec'
2+
require 'rspec/expectations'
3+
4+
RSpec::Matchers.define :use_multiplication_of_strings do
5+
match { |actual| actual =~ /['"]o['"]\s?\*\s?\d+/ }
6+
7+
failure_message do |actual|
8+
%Q{Your code doesn't use the * method to add the "o"s}
9+
end
10+
end
11+
12+
RSpec::Matchers.define :concat_the_ordinal_number do |expected|
13+
match { |actual| actual =~ /(<<[\(\s]?#{expected}\)?|\.concat[\(\s]#{expected}\(?)/ }
14+
15+
failure_message do |actual|
16+
%Q{Your code doesn't add "#{expected.chr}" by using the ordinal number}
17+
end
18+
end
19+
20+
def code_line
21+
%q{[['solution::code']]}
22+
end
23+
24+
def code
25+
@code ||= eval(code_line)
26+
end
27+
28+
describe 'Your code' do
29+
it 'creates a String' do
30+
expect(code).to be_a String
31+
end
32+
33+
it 'adds whitespace by using the ordinal number' do
34+
expect(code_line).to concat_the_ordinal_number 32
35+
end
36+
37+
it 'uses the * method to create the "ooooo"' do
38+
expect(code_line).to use_multiplication_of_strings
39+
end
40+
41+
it 'adds an exclamation mark by using the ordinal number' do
42+
expect(code_line).to concat_the_ordinal_number 33
43+
end
44+
45+
46+
if code.is_a?(String)
47+
it 'forms the String "Ruby rooooocks!"' do
48+
expect(code.strip).to eq 'Ruby rooooocks!'
49+
end
50+
end
51+
end
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Concatenating Strings
2+
3+
---
4+
5+
*You will learn:*
6+
- how to concatenate Strings
7+
- how to append a String to another String
8+
- about the ordinal number representation of Strings
9+
10+
---
11+
12+
If you look into Ruby's documentation for the the *String* class you will find several
13+
methods to concatenate Strings: *(ruby-doc core: String)*.
14+
15+
Adding a String to another String is an often used operation when working with Strings.
16+
In Ruby there are two possibilities to combine Strings:
17+
18+
`1) You can connect two Strings and create a third String out of them`
19+
`2) You can directly modify an existing String`
20+
21+
Let's have a closer look into both the options:
22+
23+
## Combining Strings into a new String
24+
25+
A String comes with 2 methods to do this, namely `+` and `\*`.
26+
You might think "Wait, these are Number operations!". Right, but the *String* class
27+
does also define them.
28+
29+
The `+` method just adds a second String to the end of the first one:
30+
31+
` 'white' + 'space'` *# => "whitespace"*
32+
33+
If you want to have whitespace between these words you have explicitly add it to
34+
the end of the first or the beginning of the second String.
35+
36+
The `\*` method takes an Integer *n* and runs the `+`-concatenation *n* times:
37+
38+
` 'la' \* 3` *# => "lalala"* (here n = 3)
39+
40+
If your first String was stored in a variable, then a concatenation with the `+` and `\*`
41+
methods doesn't change the value of this variable:
42+
43+
` name = 'Ada'`
44+
` fullname = name + ' Lovelace'` *# => "Ada Lovelace"
45+
` puts fullname` *# => "Ada Lovelace"
46+
` puts name` *# => "Ada"
47+
48+
The variable `name` still has the value *"Ada"*, `fullname` holds the concatenated String.
49+
50+
## Directly modifying a String
51+
52+
There are two methods for directly adding a String to another String: `<<` and `concat`.
53+
54+
The `<<` method works like `+` with the difference however that it adds the second String
55+
to the first one. Let's take the example from above again:
56+
57+
` name = 'Ada'`
58+
` name << ' Lovelace'` *# => "Ada Lovelace"
59+
` puts name` *# => "Ada Lovelace"
60+
61+
The value of *name* is now the concatenation.
62+
63+
The method `concat` works the same but just has a more recognizable name:
64+
65+
` name = 'William'`
66+
` name.concat(' King')` *# => "William King"
67+
` puts name` *# => "William King"
68+
69+
Both `<<` and `concat` also take an integer number as parameter.
70+
Hm, how can we add an Integer value to a String? The answer is that each one-character
71+
String has an Integer representation (ordinal number). You can check which ordinal number
72+
a character has by using the `ord` method:
73+
74+
` 'A'.ord` *# => 65*
75+
` '?'.ord` *# => 63*
76+
77+
This means if you write
78+
79+
` 'Pardon'.concat(63)` *# => "Pardon?"*
80+
81+
then the *63* is first converted to its String representation and then added to the first String.
82+
83+
If you want to add a number – as it is – to a String, you have to convert it to a String before.
84+
You can use the `to_s` method to achive this:
85+
86+
` 'User' << 1.to_s` *# => "User1"*
87+
88+
Now that we learned about all these methods, let's concatenate some Strings!
89+
90+
---
91+
92+
Create the String *"Ruby rooooocks!"* by using the methods `+`, `\*` and `<<` or `concat`!
93+
94+
Create the whitespace and the exclamation mark by concatenating ordinal numbers to the String.
95+
Use the `\*` method to add the multiple *ooooo*s to the String.
96+
97+
---
File renamed without changes.

0 commit comments

Comments
 (0)