sinclair 1.10.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/README.md +444 -324
  4. data/config/check_specs.yml +5 -5
  5. data/config/yardstick.yml +4 -0
  6. data/lib/sinclair/matchers/add_class_method.rb +0 -1
  7. data/lib/sinclair/method_builder/base.rb +32 -2
  8. data/lib/sinclair/method_builder/block_method_builder.rb +1 -12
  9. data/lib/sinclair/method_builder/call_method_builder.rb +10 -27
  10. data/lib/sinclair/method_builder/string_method_builder.rb +2 -29
  11. data/lib/sinclair/method_builder.rb +4 -20
  12. data/lib/sinclair/method_definition/block_definition.rb +2 -0
  13. data/lib/sinclair/method_definition/call_definition.rb +15 -18
  14. data/lib/sinclair/method_definition/parameter_builder.rb +89 -0
  15. data/lib/sinclair/method_definition/parameter_helper.rb +124 -0
  16. data/lib/sinclair/method_definition/string_definition.rb +26 -2
  17. data/lib/sinclair/method_definition.rb +42 -3
  18. data/lib/sinclair/method_definitions.rb +20 -22
  19. data/lib/sinclair/version.rb +1 -1
  20. data/lib/sinclair.rb +149 -62
  21. data/spec/integration/readme/sinclair/types_of_definition_spec.rb +61 -0
  22. data/spec/integration/yard/sinclair/add_class_method_spec.rb +51 -0
  23. data/spec/integration/yard/sinclair/add_method_spec.rb +60 -0
  24. data/spec/integration/yard/sinclair/eval_and_add_method_spec.rb +26 -0
  25. data/spec/integration/yard/sinclair_spec.rb +0 -83
  26. data/spec/lib/sinclair/method_builder/base_spec.rb +15 -0
  27. data/spec/lib/sinclair/method_builder/string_method_builder_spec.rb +24 -1
  28. data/spec/lib/sinclair/method_definition/call_definition_spec.rb +14 -17
  29. data/spec/lib/sinclair/method_definition/parameter_builder_spec.rb +81 -0
  30. data/spec/lib/sinclair/method_definition/string_definition_spec.rb +60 -29
  31. data/spec/lib/sinclair/method_definition_spec.rb +77 -2
  32. data/spec/lib/sinclair/method_definitions_spec.rb +15 -16
  33. data/spec/lib/sinclair_spec.rb +6 -160
  34. data/spec/support/models/dummy_builder.rb +5 -1
  35. data/spec/support/models/dummy_class_builder.rb +4 -0
  36. data/spec/support/models/person.rb +1 -1
  37. data/spec/support/shared_examples/sinclair.rb +118 -0
  38. metadata +11 -2
@@ -10,27 +10,24 @@ describe Sinclair::MethodDefinition::CallDefinition do
10
10
  let(:call_name) { :method_call }
11
11
  let(:attributes) { %i[key1 value2] }
12
12
 
13
- describe '#code_string' do
14
- let(:expected) { 'method_call :key1, :value2' }
15
-
16
- it 'returns the code string' do
17
- expect(definition.code_string)
18
- .to eq(expected)
13
+ describe '#code_block' do
14
+ let(:instance) { klass.new }
15
+ let(:klass) do
16
+ Class.new do
17
+ def method_call(*args)
18
+ args
19
+ end
20
+ end
19
21
  end
20
- end
21
22
 
22
- describe '#class_code_string' do
23
- let(:expected) do
24
- <<-RUBY
25
- class << self
26
- method_call :key1, :value2
27
- end
28
- RUBY
23
+ it do
24
+ expect(definition.code_block)
25
+ .to be_a(Proc)
29
26
  end
30
27
 
31
- it 'returns the code string' do
32
- expect(definition.class_code_string.gsub(/^ */, ''))
33
- .to eq(expected.gsub(/^ */, ''))
28
+ it 'returns a proc with the method call' do
29
+ expect(instance.instance_eval(&definition.code_block))
30
+ .to eq(attributes)
34
31
  end
35
32
  end
36
33
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::MethodDefinition::ParameterBuilder do
6
+ describe '.from' do
7
+ let(:parameters) { nil }
8
+ let(:named_parameters) { nil }
9
+
10
+ context 'when parameters and named_parameters are nil' do
11
+ it do
12
+ expect(described_class.from(parameters, named_parameters))
13
+ .to eq('')
14
+ end
15
+ end
16
+
17
+ context 'when parameters is empty' do
18
+ let(:parameters) { [] }
19
+
20
+ it do
21
+ expect(described_class.from(parameters, named_parameters))
22
+ .to eq('')
23
+ end
24
+ end
25
+
26
+ context 'when named_parameters is empty' do
27
+ let(:named_parameters) { [] }
28
+
29
+ it do
30
+ expect(described_class.from(parameters, named_parameters))
31
+ .to eq('')
32
+ end
33
+ end
34
+
35
+ context 'when parameters has no default values' do
36
+ let(:parameters) { %i[x y] }
37
+
38
+ it do
39
+ expect(described_class.from(parameters, named_parameters))
40
+ .to eq('(x, y)')
41
+ end
42
+ end
43
+
44
+ context 'when named_parameters has no default values' do
45
+ let(:named_parameters) { %i[x y] }
46
+
47
+ it do
48
+ expect(described_class.from(parameters, named_parameters))
49
+ .to eq('(x:, y:)')
50
+ end
51
+ end
52
+
53
+ context 'when parameters has only default values' do
54
+ let(:parameters) { [{ x: 1, y: 3 }] }
55
+
56
+ it do
57
+ expect(described_class.from(parameters, named_parameters))
58
+ .to eq('(x = 1, y = 3)')
59
+ end
60
+ end
61
+
62
+ context 'when named parameters has only default values' do
63
+ let(:named_parameters) { [{ x: 1, y: 3 }] }
64
+
65
+ it do
66
+ expect(described_class.from(parameters, named_parameters))
67
+ .to eq('(x: 1, y: 3)')
68
+ end
69
+ end
70
+
71
+ context 'when all options are present' do
72
+ let(:parameters) { [:x, { y: 2 }] }
73
+ let(:named_parameters) { [:a, { b: 3 }] }
74
+
75
+ it do
76
+ expect(described_class.from(parameters, named_parameters))
77
+ .to eq('(x, y = 2, a:, b: 3)')
78
+ end
79
+ end
80
+ end
81
+ end
@@ -11,59 +11,90 @@ describe Sinclair::MethodDefinition::StringDefinition do
11
11
  let(:code) { 'Random.rand' }
12
12
  let(:options) { {} }
13
13
 
14
- describe '#code_line' do
15
- let(:klass) { Class.new }
16
- let(:instance) { klass.new }
17
- let(:code_line) { definition.code_line }
18
-
19
- it 'returns the code' do
20
- expect(definition.code_line).to eq(code)
14
+ describe '#code_definition' do
15
+ let(:klass) { Class.new }
16
+ let(:instance) { klass.new }
17
+ let(:code_definition) { definition.code_definition }
18
+ let(:expected_code) do
19
+ <<-CODE
20
+ def #{method_name}
21
+ #{code}
22
+ end
23
+ CODE
21
24
  end
22
25
 
23
26
  it 'returns a code with no cache' do
24
- expect(instance.instance_eval(code_line))
25
- .not_to eq(instance.instance_eval(code_line))
27
+ expect(definition.code_definition.gsub(/^ */, ''))
28
+ .to eq(expected_code.gsub(/^ */, ''))
26
29
  end
27
30
 
28
- context 'when cache true is given' do
29
- let(:options) { { cached: true } }
31
+ context 'when parameters are given with defaults' do
32
+ let(:options) { { parameters: [:x, { y: 10 }] } }
33
+ let(:code) { 'x + y' }
34
+ let(:expected_code) do
35
+ <<-CODE
36
+ def #{method_name}(x, y = 10)
37
+ #{code}
38
+ end
39
+ CODE
40
+ end
30
41
 
31
42
  it 'returns the code with simple cache' do
32
- expect(definition.code_line)
33
- .to eq("@#{method_name} ||= #{code}")
43
+ expect(definition.code_definition.gsub(/^ */, ''))
44
+ .to eq(expected_code.gsub(/^ */, ''))
34
45
  end
46
+ end
35
47
 
36
- it 'returns a code with cache' do
37
- expect(instance.instance_eval(code_line))
38
- .to eq(instance.instance_eval(code_line))
48
+ context 'when parameters are given' do
49
+ let(:options) { { parameters: %i[x y] } }
50
+ let(:code) { 'x + y' }
51
+ let(:expected_code) do
52
+ <<-CODE
53
+ def #{method_name}(x, y)
54
+ #{code}
55
+ end
56
+ CODE
57
+ end
58
+
59
+ it 'returns the code with simple cache' do
60
+ expect(definition.code_definition.gsub(/^ */, ''))
61
+ .to eq(expected_code.gsub(/^ */, ''))
39
62
  end
63
+ end
40
64
 
41
- it 'returns a code that does not cache nil' do
42
- instance.instance_variable_set("@#{method_name}", nil)
65
+ context 'when cache true is given' do
66
+ let(:options) { { cached: true } }
67
+ let(:expected_code) do
68
+ <<-CODE
69
+ def #{method_name}
70
+ @#{method_name} ||= #{code}
71
+ end
72
+ CODE
73
+ end
43
74
 
44
- expect(instance.instance_eval(code_line)).not_to be_nil
75
+ it 'returns the code with simple cache' do
76
+ expect(definition.code_definition.gsub(/^ */, ''))
77
+ .to eq(expected_code.gsub(/^ */, ''))
45
78
  end
46
79
  end
47
80
 
48
81
  context 'when cache full is given' do
49
82
  let(:options) { { cached: :full } }
50
83
  let(:expected) do
51
- "defined?(@#{method_name}) ? @#{method_name} : (@#{method_name} = #{code})"
84
+ <<-CODE
85
+ def #{method_name}
86
+ defined?(@#{method_name}) ? @#{method_name} : (@#{method_name} = #{code})
87
+ end
88
+ CODE
52
89
  end
53
90
 
54
91
  it 'returns the code with full cache' do
55
- expect(definition.code_line).to eq(expected)
92
+ expect(definition.code_definition.gsub(/^ */, '')).to eq(expected.gsub(/^ */, ''))
56
93
  end
57
94
 
58
95
  it 'returns a code with cache' do
59
- expect(instance.instance_eval(code_line))
60
- .to eq(instance.instance_eval(code_line))
61
- end
62
-
63
- it 'returns a code that caches nil' do
64
- instance.instance_variable_set("@#{method_name}", nil)
65
-
66
- expect(instance.instance_eval(code_line)).to be_nil
96
+ expect(instance.instance_eval(code_definition))
97
+ .to eq(instance.instance_eval(code_definition))
67
98
  end
68
99
  end
69
100
  end
@@ -5,6 +5,58 @@ require 'spec_helper'
5
5
  describe Sinclair::MethodDefinition do
6
6
  let(:method_name) { :the_method }
7
7
 
8
+ describe '.build' do
9
+ subject(:definition) do
10
+ definition_class.new(method_name, **options)
11
+ end
12
+
13
+ let(:definition_class) { Class.new(described_class) }
14
+ let(:options) { {} }
15
+ let(:klass) { Class.new }
16
+ let(:type) { Sinclair::MethodBuilder::CLASS_METHOD }
17
+
18
+ context 'when the builder has not been defined' do
19
+ it do
20
+ expect { definition.build(klass, type) }
21
+ .to raise_error(NotImplementedError)
22
+ end
23
+ end
24
+
25
+ context 'when the builder has been defined' do
26
+ let(:definition_class) do
27
+ Class.new(described_class) do
28
+ attr_reader :name
29
+
30
+ def initialize(name)
31
+ @name = name
32
+ end
33
+
34
+ def code_definition
35
+ <<-CODE
36
+ def #{name}
37
+ 10
38
+ end
39
+ CODE
40
+ end
41
+ end
42
+ end
43
+
44
+ before do
45
+ definition_class.build_with(Sinclair::MethodBuilder::StringMethodBuilder)
46
+ end
47
+
48
+ it do
49
+ expect { definition.build(klass, type) }
50
+ .not_to raise_error
51
+ end
52
+
53
+ it 'builds the method using the builder' do
54
+ expect { definition.build(klass, type) }
55
+ .to add_class_method(method_name).to(klass)
56
+ end
57
+ end
58
+ end
59
+
8
60
  describe '.default_value' do
9
61
  subject(:klass) { Class.new(described_class) }
10
62
 
@@ -44,6 +96,8 @@ describe Sinclair::MethodDefinition do
44
96
  end
45
97
 
46
98
  describe '.for' do
99
+ let(:klass) { Class.new }
100
+
47
101
  context 'when there are no options nor block' do
48
102
  let(:type) { :call }
49
103
  let(:arguments) { %i[attr_reader some_attribute other_attribute] }
@@ -59,8 +113,29 @@ describe Sinclair::MethodDefinition do
59
113
  end
60
114
 
61
115
  it 'initializes it correctly' do
62
- expect(described_class.for(type, *arguments).code_string)
63
- .to eq('attr_reader :some_attribute, :other_attribute')
116
+ expect { klass.module_eval(&described_class.for(type, *arguments).code_block) }
117
+ .to add_method(:some_attribute).to(klass)
118
+ end
119
+ end
120
+
121
+ context 'when type is not given' do
122
+ let(:type) { nil }
123
+ let(:method_name) { :the_method }
124
+ let(:block) { proc { 10 } }
125
+
126
+ it do
127
+ expect(described_class.for(type, method_name, &block))
128
+ .to be_a(described_class)
129
+ end
130
+
131
+ it 'infers the definition from arguments' do
132
+ expect(described_class.for(type, method_name, &block))
133
+ .to be_a(described_class::BlockDefinition)
134
+ end
135
+
136
+ it 'initializes it correctly' do
137
+ expect(described_class.for(type, method_name, &block).name)
138
+ .to eq(method_name)
64
139
  end
65
140
  end
66
141
 
@@ -6,7 +6,8 @@ describe Sinclair::MethodDefinitions do
6
6
  subject(:definitions) { described_class.new }
7
7
 
8
8
  describe '#add' do
9
- let(:name) { :the_method }
9
+ let(:name) { :the_method }
10
+ let(:klass) { Class.new }
10
11
 
11
12
  context 'when passing block' do
12
13
  it 'returns the resulting array' do
@@ -41,31 +42,29 @@ describe Sinclair::MethodDefinitions do
41
42
  .to be_a(Sinclair::MethodDefinition::StringDefinition)
42
43
  end
43
44
  end
44
- end
45
45
 
46
- describe '#add_definition' do
47
46
  context 'when there are no options nor block' do
48
47
  let(:type) { :call }
49
48
  let(:arguments) { %i[attr_reader some_attribute other_attribute] }
50
49
 
51
50
  it do
52
- expect(definitions.add_definition(type, *arguments))
51
+ expect(definitions.add(*arguments, type: type))
53
52
  .to be_a(Array)
54
53
  end
55
54
 
56
55
  it 'creates a new definition' do
57
- expect(definitions.add_definition(type, *arguments).last)
56
+ expect(definitions.add(*arguments, type: type).last)
58
57
  .to be_a(Sinclair::MethodDefinition)
59
58
  end
60
59
 
61
60
  it 'creates a new definition of the chosen type' do
62
- expect(definitions.add_definition(type, *arguments).last)
61
+ expect(definitions.add(*arguments, type: type).last)
63
62
  .to be_a(Sinclair::MethodDefinition::CallDefinition)
64
63
  end
65
64
 
66
65
  it 'initializes it correctly' do
67
- expect(definitions.add_definition(type, *arguments).last.code_string)
68
- .to eq('attr_reader :some_attribute, :other_attribute')
66
+ expect { klass.module_eval(&definitions.add(*arguments, type: type).last.code_block) }
67
+ .to add_method(:some_attribute).to(klass)
69
68
  end
70
69
  end
71
70
 
@@ -75,22 +74,22 @@ describe Sinclair::MethodDefinitions do
75
74
  let(:block) { proc { 10 } }
76
75
 
77
76
  it do
78
- expect(definitions.add_definition(type, method_name, &block))
77
+ expect(definitions.add(type, method_name, &block))
79
78
  .to be_a(Array)
80
79
  end
81
80
 
82
81
  it 'creates a new definition' do
83
- expect(definitions.add_definition(type, method_name, &block).last)
82
+ expect(definitions.add(type, method_name, &block).last)
84
83
  .to be_a(Sinclair::MethodDefinition)
85
84
  end
86
85
 
87
86
  it 'creates a new definition of the chosen type' do
88
- expect(definitions.add_definition(type, method_name, &block).last)
87
+ expect(definitions.add(type, method_name, &block).last)
89
88
  .to be_a(Sinclair::MethodDefinition::BlockDefinition)
90
89
  end
91
90
 
92
91
  it 'initializes it correctly' do
93
- expect(definitions.add_definition(type, method_name, &block).last.name)
92
+ expect(definitions.add(method_name, type: type, &block).last.name)
94
93
  .to eq(method_name)
95
94
  end
96
95
  end
@@ -101,22 +100,22 @@ describe Sinclair::MethodDefinitions do
101
100
  let(:code) { '10' }
102
101
 
103
102
  it do
104
- expect(definitions.add_definition(type, method_name, code))
103
+ expect(definitions.add(method_name, code, type: type))
105
104
  .to be_a(Array)
106
105
  end
107
106
 
108
107
  it 'creates a new definition' do
109
- expect(definitions.add_definition(type, method_name, code).last)
108
+ expect(definitions.add(method_name, code, type: type).last)
110
109
  .to be_a(Sinclair::MethodDefinition)
111
110
  end
112
111
 
113
112
  it 'creates a new definition of the chosen type' do
114
- expect(definitions.add_definition(type, method_name, code).last)
113
+ expect(definitions.add(method_name, code, type: type).last)
115
114
  .to be_a(Sinclair::MethodDefinition::StringDefinition)
116
115
  end
117
116
 
118
117
  it 'initializes it correctly' do
119
- expect(definitions.add_definition(type, method_name, code).last.name)
118
+ expect(definitions.add(method_name, code, type: type).last.name)
120
119
  .to eq(method_name)
121
120
  end
122
121
  end
@@ -11,86 +11,15 @@ describe Sinclair do
11
11
  let(:builder_class) { described_class }
12
12
 
13
13
  describe '#add_method' do
14
- context 'when extending the class' do
15
- let(:builder_class) { described_class::DummyBuilder }
14
+ let(:object) { instance }
16
15
 
17
- before do
18
- builder.init
19
- builder.build
20
- end
21
-
22
- context 'when describing a method with block' do
23
- it 'creates a method with the block' do
24
- expect(instance.blocked).to eq(1)
25
- end
26
- end
27
-
28
- context 'when describing a method with string' do
29
- it 'creates a method using the string definition' do
30
- expect(instance.defined).to eq(1)
31
- expect(instance.defined).to eq(2)
32
- end
33
- end
34
-
35
- context 'when passing options' do
36
- let(:options) { { increment: 2 } }
37
-
38
- it 'parses the options' do
39
- expect(instance.defined).to eq(2)
40
- expect(instance.defined).to eq(4)
41
- end
42
- end
43
- end
44
-
45
- context 'when using the builder without extending' do
46
- context 'when declaring a method with a block' do
47
- before do
48
- builder.add_method(:blocked) { 1 }
49
- builder.add_method(:blocked) { 2 }
50
- builder.build
51
- end
52
-
53
- it 'respect the order of method addtion' do
54
- expect(instance.blocked).to eq(2)
55
- end
56
- end
57
-
58
- context 'when declaring a method string' do
59
- before do
60
- builder.add_method(:string, '1')
61
- builder.add_method(:string, '2')
62
- builder.build
63
- end
64
-
65
- it 'respect the order of method addtion' do
66
- expect(instance.string).to eq(2)
67
- end
68
- end
69
-
70
- context 'when declaring block and string' do
71
- before do
72
- builder.add_method(:value) { 1 }
73
- builder.add_method(:value, '2')
74
- builder.build
75
- end
76
-
77
- it 'respect the order of method addtion' do
78
- expect(instance.value).to eq(2)
79
- end
80
- end
16
+ it_behaves_like 'A sinclair builder', :instance
17
+ end
81
18
 
82
- context 'when declaring string and block' do
83
- before do
84
- builder.add_method(:value, '1')
85
- builder.add_method(:value) { 2 }
86
- builder.build
87
- end
19
+ describe '#add_class_method' do
20
+ let(:object) { dummy_class }
88
21
 
89
- it 'respect the order of method addtion' do
90
- expect(instance.value).to eq(2)
91
- end
92
- end
93
- end
22
+ it_behaves_like 'A sinclair builder', :class
94
23
  end
95
24
 
96
25
  describe '#eval_and_add_method' do
@@ -149,87 +78,4 @@ describe Sinclair do
149
78
  end
150
79
  end
151
80
  end
152
-
153
- describe '#add_class_method' do
154
- context 'when extending the class' do
155
- let(:builder_class) { described_class::DummyClassBuilder }
156
-
157
- before do
158
- builder.init
159
- builder.build
160
- end
161
-
162
- context 'when describing a method with block' do
163
- it 'creates a method with the block' do
164
- expect(dummy_class.blocked).to eq(1)
165
- end
166
- end
167
-
168
- context 'when describing a method with string' do
169
- it 'creates a method using the string definition' do
170
- expect(dummy_class.defined).to eq(1)
171
- expect(dummy_class.defined).to eq(2)
172
- end
173
- end
174
-
175
- context 'when passing options' do
176
- let(:options) { { increment: 2 } }
177
-
178
- it 'parses the options' do
179
- expect(dummy_class.defined).to eq(2)
180
- expect(dummy_class.defined).to eq(4)
181
- end
182
- end
183
- end
184
-
185
- context 'when using the builder without extending' do
186
- context 'when declaring a method with a block' do
187
- before do
188
- builder.add_class_method(:blocked) { 1 }
189
- builder.add_class_method(:blocked) { 2 }
190
- builder.build
191
- end
192
-
193
- it 'respect the order of method addtion' do
194
- expect(dummy_class.blocked).to eq(2)
195
- end
196
- end
197
-
198
- context 'when declaring a method string' do
199
- before do
200
- builder.add_class_method(:string, '1')
201
- builder.add_class_method(:string, '2')
202
- builder.build
203
- end
204
-
205
- it 'respect the order of method addtion' do
206
- expect(dummy_class.string).to eq(2)
207
- end
208
- end
209
-
210
- context 'when declaring block and string' do
211
- before do
212
- builder.add_class_method(:value) { 1 }
213
- builder.add_class_method(:value, '2')
214
- builder.build
215
- end
216
-
217
- it 'respect the order of method addtion' do
218
- expect(dummy_class.value).to eq(2)
219
- end
220
- end
221
-
222
- context 'when declaring string and block' do
223
- before do
224
- builder.add_class_method(:value, '1')
225
- builder.add_class_method(:value) { 2 }
226
- builder.build
227
- end
228
-
229
- it 'respect the order of method addtion' do
230
- expect(dummy_class.value).to eq(2)
231
- end
232
- end
233
- end
234
- end
235
81
  end
@@ -5,7 +5,11 @@ class Sinclair
5
5
  def init
6
6
  add_method(:blocked) { 1 }
7
7
  add_method(:defined, "@value = value + #{options_object&.increment || 1}")
8
- add_method(:value, '@value ||= 0')
8
+ add_method(:sum, 'x + y', parameters: %i[x y])
9
+ add_method(:value, cached: true) { 0 }
10
+ add_method(:type_block, type: :block) { 3 }
11
+ add_method(:type_string, '10', type: :string)
12
+ add_method(:attr_accessor, :some_attribute, type: :call)
9
13
  end
10
14
  end
11
15
  end
@@ -5,7 +5,11 @@ class Sinclair
5
5
  def init
6
6
  add_class_method(:blocked) { 1 }
7
7
  add_class_method(:defined, "@value = value + #{options_object&.increment || 1}")
8
+ add_class_method(:sum, 'x + y', parameters: %i[x y])
8
9
  add_class_method(:value, '@value ||= 0')
10
+ add_class_method(:type_block, type: :block) { 3 }
11
+ add_class_method(:type_string, '10', type: :string)
12
+ add_class_method(:attr_accessor, :some_attribute, type: :call)
9
13
  end
10
14
  end
11
15
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Person
4
- attr_reader :first_name, :last_name
4
+ attr_accessor :first_name, :last_name
5
5
 
6
6
  def initialize(first_name, last_name)
7
7
  @first_name = first_name