gamefic 0.2.0 → 0.6.0

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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gamefic/action.rb +87 -56
  3. data/lib/gamefic/ansi.rb +55 -0
  4. data/lib/gamefic/character.rb +130 -76
  5. data/lib/gamefic/command.rb +19 -0
  6. data/lib/gamefic/core_ext/array.rb +51 -40
  7. data/lib/gamefic/core_ext/string.rb +4 -0
  8. data/lib/gamefic/describable.rb +108 -46
  9. data/lib/gamefic/direction.rb +46 -0
  10. data/lib/gamefic/director/delegate.rb +91 -0
  11. data/lib/gamefic/director/order.rb +10 -0
  12. data/lib/gamefic/director/parser.rb +119 -0
  13. data/lib/gamefic/director.rb +16 -197
  14. data/lib/gamefic/engine/cgi.rb +221 -0
  15. data/lib/gamefic/engine/tty.rb +237 -0
  16. data/lib/gamefic/engine.rb +88 -67
  17. data/lib/gamefic/entity.rb +96 -69
  18. data/lib/gamefic/grammar/conjugator.rb +20 -0
  19. data/lib/gamefic/grammar/gender.rb +11 -0
  20. data/lib/gamefic/grammar/person.rb +10 -0
  21. data/lib/gamefic/grammar/plural.rb +13 -0
  22. data/lib/gamefic/grammar/pronouns.rb +60 -0
  23. data/lib/gamefic/grammar/tense.rb +6 -0
  24. data/lib/gamefic/grammar/verb_set.rb +43 -0
  25. data/lib/gamefic/grammar/verbs.rb +25 -0
  26. data/lib/gamefic/grammar/word_adapter.rb +36 -0
  27. data/lib/gamefic/grammar.rb +13 -0
  28. data/lib/gamefic/html.rb +53 -0
  29. data/lib/gamefic/keywords.rb +51 -33
  30. data/lib/gamefic/node.rb +65 -58
  31. data/lib/gamefic/plot/article_mount.rb +22 -0
  32. data/lib/gamefic/plot/command_mount.rb +88 -0
  33. data/lib/gamefic/plot/entity_mount.rb +45 -0
  34. data/lib/gamefic/plot/query_mount.rb +9 -0
  35. data/lib/gamefic/plot/scene_mount.rb +181 -0
  36. data/lib/gamefic/plot/you_mount.rb +22 -0
  37. data/lib/gamefic/plot.rb +296 -247
  38. data/lib/gamefic/query/ambiguous_children.rb +5 -0
  39. data/lib/gamefic/query/base.rb +265 -0
  40. data/lib/gamefic/query/children.rb +10 -0
  41. data/lib/gamefic/query/expression.rb +47 -0
  42. data/lib/gamefic/query/family.rb +10 -0
  43. data/lib/gamefic/query/many_children.rb +7 -0
  44. data/lib/gamefic/query/matches.rb +11 -0
  45. data/lib/gamefic/query/parent.rb +10 -0
  46. data/lib/gamefic/query/plural_children.rb +14 -0
  47. data/lib/gamefic/query/self.rb +10 -0
  48. data/lib/gamefic/query/siblings.rb +10 -0
  49. data/lib/gamefic/query/text.rb +43 -0
  50. data/lib/gamefic/query.rb +19 -203
  51. data/lib/gamefic/rule.rb +18 -0
  52. data/lib/gamefic/scene/active.rb +25 -0
  53. data/lib/gamefic/scene/concluded.rb +22 -0
  54. data/lib/gamefic/scene/multiplechoice.rb +74 -0
  55. data/lib/gamefic/scene/paused.rb +26 -0
  56. data/lib/gamefic/scene/yesorno.rb +43 -0
  57. data/lib/gamefic/scene.rb +125 -0
  58. data/lib/gamefic/script/base.rb +33 -0
  59. data/lib/gamefic/script/file.rb +14 -0
  60. data/lib/gamefic/script/text.rb +14 -0
  61. data/lib/gamefic/script.rb +9 -0
  62. data/lib/gamefic/serialized.rb +24 -0
  63. data/lib/gamefic/shell.rb +9 -247
  64. data/lib/gamefic/snapshots.rb +134 -0
  65. data/lib/gamefic/source/base.rb +12 -0
  66. data/lib/gamefic/source/file.rb +23 -0
  67. data/lib/gamefic/source/text.rb +16 -0
  68. data/lib/gamefic/source.rb +9 -0
  69. data/lib/gamefic/stage.rb +75 -0
  70. data/lib/gamefic/syntax.rb +106 -124
  71. data/lib/gamefic/tester.rb +20 -0
  72. data/lib/gamefic/version.rb +3 -0
  73. data/lib/gamefic.rb +18 -12
  74. metadata +102 -70
  75. data/lib/gamefic/base.rb +0 -10
  76. data/lib/gamefic/before.rb +0 -12
  77. data/lib/gamefic/import/basics/actions/close.rb +0 -16
  78. data/lib/gamefic/import/basics/actions/commands.rb +0 -3
  79. data/lib/gamefic/import/basics/actions/drop-in.rb +0 -17
  80. data/lib/gamefic/import/basics/actions/drop-on.rb +0 -16
  81. data/lib/gamefic/import/basics/actions/drop.rb +0 -30
  82. data/lib/gamefic/import/basics/actions/enter.rb +0 -16
  83. data/lib/gamefic/import/basics/actions/go.rb +0 -35
  84. data/lib/gamefic/import/basics/actions/inventory.rb +0 -8
  85. data/lib/gamefic/import/basics/actions/leave.rb +0 -29
  86. data/lib/gamefic/import/basics/actions/look-in-at.rb +0 -27
  87. data/lib/gamefic/import/basics/actions/look-under.rb +0 -3
  88. data/lib/gamefic/import/basics/actions/look.rb +0 -71
  89. data/lib/gamefic/import/basics/actions/nil.rb +0 -25
  90. data/lib/gamefic/import/basics/actions/open.rb +0 -23
  91. data/lib/gamefic/import/basics/actions/quit.rb +0 -3
  92. data/lib/gamefic/import/basics/actions/take.rb +0 -107
  93. data/lib/gamefic/import/basics/entities/container.rb +0 -8
  94. data/lib/gamefic/import/basics/entities/entity.rb +0 -11
  95. data/lib/gamefic/import/basics/entities/fixture.rb +0 -5
  96. data/lib/gamefic/import/basics/entities/item.rb +0 -5
  97. data/lib/gamefic/import/basics/entities/portal.rb +0 -40
  98. data/lib/gamefic/import/basics/entities/room.rb +0 -30
  99. data/lib/gamefic/import/basics/entities/scenery.rb +0 -5
  100. data/lib/gamefic/import/basics/entities/supporter.rb +0 -6
  101. data/lib/gamefic/import/basics/entities/thing.rb +0 -16
  102. data/lib/gamefic/import/basics/queries/reachable.rb +0 -38
  103. data/lib/gamefic/import/basics/queries/room.rb +0 -8
  104. data/lib/gamefic/import/basics/queries/visible.rb +0 -32
  105. data/lib/gamefic/import/basics/rules/has-enough-light.rb +0 -14
  106. data/lib/gamefic/import/basics.old/actions/container.rb +0 -112
  107. data/lib/gamefic/import/basics.old/actions/inventory.rb +0 -50
  108. data/lib/gamefic/import/basics.old/actions/look.rb +0 -53
  109. data/lib/gamefic/import/basics.old/actions/meta.rb +0 -6
  110. data/lib/gamefic/import/basics.old/actions/traversal.rb +0 -35
  111. data/lib/gamefic/import/basics.old/actions.rb +0 -1
  112. data/lib/gamefic/import/basics.old/entities/container.rb +0 -3
  113. data/lib/gamefic/import/basics.old/entities/fixture.rb +0 -3
  114. data/lib/gamefic/import/basics.old/entities/item.rb +0 -3
  115. data/lib/gamefic/import/basics.old/entities/portal.rb +0 -43
  116. data/lib/gamefic/import/basics.old/entities/room.rb +0 -27
  117. data/lib/gamefic/import/basics.old/entities/scenery.rb +0 -3
  118. data/lib/gamefic/import/basics.old/entities/supporter.rb +0 -3
  119. data/lib/gamefic/import/basics.old/entities.rb +0 -1
  120. data/lib/gamefic/import/basics.old/room_modes.rb +0 -48
  121. data/lib/gamefic/import/basics.rb +0 -6
  122. data/lib/gamefic/import/room_modes.rb +0 -48
  123. data/lib/gamefic/import/standard.rb +0 -1
  124. data/lib/gamefic/meta.rb +0 -12
  125. data/lib/gamefic/optionset.rb +0 -114
  126. data/lib/gamefic/requirement.rb +0 -14
  127. data/lib/gamefic/story.rb +0 -14
  128. data/lib/gamefic/thing.rb +0 -7
data/lib/gamefic/node.rb CHANGED
@@ -1,62 +1,69 @@
1
+ # Exception raised when setting a node's parent would cause
2
+ # a circular reference, e.g., A -> A or A -> B -> A
3
+ class CircularNodeReferenceError < Exception
4
+ end
5
+
1
6
  module Gamefic
2
7
 
3
- module Node
4
- def children
5
- if @children == nil
6
- @children = Array.new
7
- end
8
- @children.clone
9
- end
10
- def flatten
11
- array = Array.new
12
- children.each { |child|
13
- array = array + recurse_flatten(child)
14
- }
15
- return array
16
- end
17
- protected
18
- def add_child(node)
19
- children
20
- @children.push(node)
21
- end
22
- def rem_child(node)
23
- children
24
- @children.delete(node)
25
- end
26
- def concat_children(children)
27
- children
28
- @children.concat(children)
29
- end
30
- private
31
- def recurse_flatten(node)
32
- array = Array.new
33
- array.push(node)
34
- node.children.each { |child|
35
- array = array + recurse_flatten(child)
36
- }
37
- return array
38
- end
39
- end
40
-
41
- module Branch
42
- include Node
43
- def parent
44
- @parent
45
- end
46
- def parent=(node)
47
- if node == self
48
- raise "Entity cannot be its own parent"
49
- end
50
- if @parent != node
51
- if @parent != nil
52
- @parent.send(:rem_child, self)
53
- end
54
- @parent = node
55
- if @parent != nil
56
- @parent.send(:add_child, self)
57
- end
58
- end
59
- end
60
- end
8
+ module Node
9
+ # @return [Array]
10
+ def children
11
+ @children ||= []
12
+ @children.clone
13
+ end
14
+ def flatten
15
+ array = Array.new
16
+ children.each { |child|
17
+ array = array + recurse_flatten(child)
18
+ }
19
+ return array
20
+ end
21
+ def parent
22
+ @parent
23
+ end
24
+ def parent=(node)
25
+ return if node == @parent
26
+ if node == self
27
+ raise CircularNodeReferenceError.new("Node cannot be its own parent")
28
+ end
29
+ # Do not permit circular references
30
+ if node != nil and node.parent == self
31
+ node.parent = nil
32
+ end
33
+ if node != nil and flatten.include?(node)
34
+ raise CircularNodeReferenceError.new("Node cannot be a child of a descendant")
35
+ end
36
+ if @parent != node
37
+ if @parent != nil
38
+ @parent.send(:rem_child, self)
39
+ end
40
+ @parent = node
41
+ if @parent != nil
42
+ @parent.send(:add_child, self)
43
+ end
44
+ end
45
+ end
46
+ protected
47
+ def add_child(node)
48
+ children
49
+ @children.push(node)
50
+ end
51
+ def rem_child(node)
52
+ children
53
+ @children.delete(node)
54
+ end
55
+ def concat_children(children)
56
+ children.concat(children)
57
+ end
58
+ private
59
+ def recurse_flatten(node)
60
+ array = Array.new
61
+ array.push(node)
62
+ node.children.each { |child|
63
+ array = array + recurse_flatten(child)
64
+ }
65
+ return array
66
+ end
67
+ end
61
68
 
62
69
  end
@@ -0,0 +1,22 @@
1
+ module Gamefic
2
+ module ArticleMount
3
+ def a(entity)
4
+ entity.indefinitely
5
+ end
6
+ def an(entity)
7
+ entity.indefinitely
8
+ end
9
+ def the(entity)
10
+ entity.definitely
11
+ end
12
+ def A(entity)
13
+ entity.indefinitely.cap_first
14
+ end
15
+ def An(entity)
16
+ entity.indefinitely.cap_first
17
+ end
18
+ def The(entity)
19
+ entity.definitely.cap_first
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,88 @@
1
+ require 'gamefic/action'
2
+
3
+ module Gamefic
4
+
5
+ module Plot::CommandMount
6
+ # Create a Meta Action that responds to a command.
7
+ # Meta Actions are very similar to standard Actions, except the Plot
8
+ # understands them to be commands that operate above and/or outside of the
9
+ # actual game world. Examples of Meta Actions are commands that report the
10
+ # player's current score, save and restore saved games, or list the game's
11
+ # credits.
12
+ #
13
+ # @example A simple Meta Action
14
+ # meta :credits do |actor|
15
+ # actor.tell "This game was written by John Smith."
16
+ # end
17
+ #
18
+ # @param command [Symbol] An imperative verb for the command
19
+ # @param *queries [Array<Query::Base>] Queries to filter the command's tokens
20
+ # @yieldparam [Character]
21
+ def meta(command, *queries, &proc)
22
+ act = self.action(command, *queries, &proc)
23
+ act.meta = true
24
+ act
25
+ end
26
+ def action(command, *queries, &proc)
27
+ Action.new(self, command, *queries, &proc)
28
+ end
29
+ # Create an Action that responds to a command.
30
+ # An Action uses the command argument to identify the imperative verb that
31
+ # triggers the action.
32
+ # It can also accept queries to tokenize the remainder of the input and
33
+ # filter for particular entities or properties.
34
+ # The block argument contains the code to be executed when the input
35
+ # matches all of the Action's criteria (i.e., verb and queries).
36
+ #
37
+ # @example A simple Action.
38
+ # respond :salute do |actor|
39
+ # actor.tell "Hello, sir!"
40
+ # end
41
+ # # The command "salute" will respond "Hello, sir!"
42
+ #
43
+ # @example An Action that accepts a Character
44
+ # respond :salute, Use.visible(Character) do |actor, character|
45
+ # actor.tell "#{The character} returns your salute."
46
+ # end
47
+ #
48
+ # @param command [Symbol] An imperative verb for the command
49
+ # @param *queries [Array<Query::Base>] Queries to filter the command's tokens
50
+ # @yieldparam [Character]
51
+ def respond(command, *queries, &proc)
52
+ self.action(command, *queries, &proc)
53
+ end
54
+ # Create an alternate Syntax for an Action.
55
+ # The command and its translation can be parameterized.
56
+ #
57
+ # @example Create a synonym for the Inventory Action.
58
+ # interpret "catalogue", "inventory"
59
+ # # The command "catalogue" will be translated to "inventory"
60
+ #
61
+ # @example Create a parameterized synonym for the Look Action.
62
+ # interpret "scrutinize :entity", "look :entity"
63
+ # # The command "scrutinize chair" will be translated to "look chair"
64
+ #
65
+ # @param command [String] The format of the original command
66
+ # @param translation [String] The format of the translated command
67
+ # @return [Syntax] the Syntax object
68
+ def interpret command, translation
69
+ xlate command, translation
70
+ end
71
+ def syntax(*args)
72
+ xlate(*args)
73
+ end
74
+ def xlate(*args)
75
+ syn = Syntax.new(self, *args)
76
+ syn
77
+ end
78
+ def commandwords
79
+ words = Array.new
80
+ syntaxes.each { |s|
81
+ word = s.first_word
82
+ words.push(word) if !word.nil?
83
+ }
84
+ words.uniq
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,45 @@
1
+ module Gamefic
2
+
3
+ module Plot::EntityMount
4
+ # Make a new Entity with the provided properties.
5
+ #
6
+ # @example Create an Entity
7
+ # chair = make Entity, :name => 'red chair'
8
+ # chair.name #=> 'red chair'
9
+ #
10
+ # @param cls [Class] The Class of the Entity to be created.
11
+ # @param args [Hash] The entity's properties.
12
+ # @return The Entity instance.
13
+ def make(cls, args = {}, &block)
14
+ ent = cls.new(self, args, &block)
15
+ if ent.kind_of?(Entity) == false
16
+ raise "Invalid entity class"
17
+ end
18
+ ent
19
+ end
20
+ # Pick an entity based on its description.
21
+ # The description provided must match exactly one entity; otherwise
22
+ # an error is raised.
23
+ #
24
+ # @example Select the Entity that matches the description
25
+ # red_chair = make Entity, :name => 'red chair'
26
+ # blue_chair make Entity, :name => 'blue chair'
27
+ # pick "red chair" #=> red_chair
28
+ # pick "blue chair" #=> blue_chair
29
+ # pick "chair" #=> IndexError: description is ambiguous
30
+ #
31
+ # @param @description [String] The description of the entity
32
+ # @return [Entity] The entity that matches the description
33
+ def pick(description)
34
+ query = Gamefic::Query::Base.new
35
+ result = query.match(description, entities)
36
+ if result.objects.length == 0
37
+ raise IndexError.new("Unable to find entity from '#{description}'")
38
+ elsif result.objects.length > 1
39
+ raise IndexError.new("Ambiguous entities found from '#{description}'")
40
+ end
41
+ result.objects[0]
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,9 @@
1
+ module Gamefic
2
+ module Plot::QueryMount
3
+ end
4
+ module Query
5
+ def self.siblings *arguments
6
+ Siblings.new *arguments
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,181 @@
1
+ class NotConclusionError < Exception
2
+ end
3
+
4
+ module Gamefic
5
+
6
+ module Plot::SceneMount
7
+ # Get a Hash of SceneManager objects.
8
+ #
9
+ # @return [Hash<Symbol, SceneManager>]
10
+ def scene_managers
11
+ if @scene_managers.nil?
12
+ @scene_managers ||= {}
13
+ @scene_managers[:active] = ActiveSceneManager.new
14
+ @scene_managers[:concluded] = ConcludedSceneManager.new
15
+ end
16
+ @scene_managers
17
+ end
18
+
19
+ # Create a multiple-choice scene.
20
+ # The user will be required to make a valid choice to continue
21
+ #
22
+ # @yieldparam [Character]
23
+ # @yieldparam [MultipleChoiceSceneData]
24
+ def multiple_choice key, *args, &block
25
+ scene_managers[key] = MultipleChoiceSceneManager.new do |config|
26
+ config.start do |actor, data|
27
+ data.options = args
28
+ end
29
+ config.finish(&block)
30
+ end
31
+ end
32
+
33
+ # Create a yes-or-no scene.
34
+ # The user will be required to answer Yes or No to continue.
35
+ #
36
+ # @yieldparam [Character]
37
+ # @yieldparam [YesOrNoSceneData]
38
+ def yes_or_no key, prompt = nil, &block
39
+ manager = YesOrNoSceneManager.new do |config|
40
+ config.prompt = prompt
41
+ config.finish do |actor, data|
42
+ if data.answer.nil?
43
+ actor.tell "Please answer Yes or No."
44
+ else
45
+ data.next_cue ||= :active
46
+ block.call(actor, data)
47
+ end
48
+ end
49
+ end
50
+ scene_managers[key] = manager
51
+ end
52
+
53
+ # Create a scene with a prompt.
54
+ # This scene will use the provided block to process arbitrary input
55
+ # from the user.
56
+ #
57
+ # @param key [Symbol] A unique name for the scene.
58
+ # @param prompt [String] The prompt message to display to the user.
59
+ # @yieldparam [Character]
60
+ # @yieldparam [SceneData]
61
+ def prompt key, prompt, &block
62
+ scene_managers[key] = SceneManager.new do |config|
63
+ config.prompt = prompt
64
+ config.finish do |actor, data|
65
+ data.next_cue ||= :active
66
+ block.call actor, data
67
+ end
68
+ end
69
+ scene_managers[key].state = "Prompted"
70
+ end
71
+
72
+ # Create a scene that pauses the game.
73
+ # This scene will execute the specified block and wait for input
74
+ # from the user (e.g., pressing Enter) to continue.
75
+ #
76
+ # @param key [Symbol] A unique name for the scene.
77
+ # @yieldparam [Character]
78
+ # @yieldparam [SceneData]
79
+ def pause key, &block
80
+ manager = PausedSceneManager.new do |config|
81
+ config.start do |actor, data|
82
+ data.next_cue = :active
83
+ block.call actor, data
84
+ end
85
+ end
86
+ scene_managers[key] = manager
87
+ end
88
+
89
+ # Create a conclusion.
90
+ # The game will end after this scene is complete.
91
+ #
92
+ # @param key [Symbol] A unique name for the scene.
93
+ # @yieldparam [Character]
94
+ # @yieldparam [SceneData]
95
+ def conclusion key, &block
96
+ manager = ConcludedSceneManager.new do |config|
97
+ config.start(&block)
98
+ end
99
+ scene_managers[key] = manager
100
+ end
101
+
102
+ # Create a generic scene.
103
+ # After the scene is complete, it will automatically start the next cue.
104
+ #
105
+ # @param [Symbol] A unique name for the scene.
106
+ # @yieldparam [Character]
107
+ # @yieldparam [SceneData]
108
+ def scene key, &block
109
+ scene = SceneManager.new do |manager|
110
+ manager.start do |actor, data|
111
+ data.next_cue = :active
112
+ block.call(actor, data) if !block.nil?
113
+ cue actor, data.next_cue
114
+ actor.scene.start actor
115
+ end
116
+ # Since generic scenes always cue a new scene, there's no reason to
117
+ # define a finish block.
118
+ end
119
+ scene_managers[key] = scene
120
+ end
121
+
122
+ # Branch to a new scene based on a list of options.
123
+ # This is a specialized type of multiple-choice scene that determines
124
+ # which scene to cue based on a Hash of choices and scene keys.
125
+ #
126
+ # @example Select a scene
127
+ # branch :select_one_or_two, { "one" => :scene_one, "two" => :scene_two }
128
+ # scene :scene_one do |actor|
129
+ # actor.tell "You went to scene one"
130
+ # end
131
+ # scene :scene_two do |actor|
132
+ # actor.tell "You went to scene two"
133
+ # end
134
+ # introduction do |actor|
135
+ # cue actor, :select_one_or_two # The actor will be prompted to select "one" or "two" and get sent to the corresponding scene
136
+ # end
137
+ #
138
+ # @param key [Symbol] A unique name for the scene.
139
+ # @param options [Hash] A Hash of options and associated scene keys.
140
+ def branch key, options
141
+ multiple_choice key, *options.keys do |actor, data|
142
+ cue actor, options[data.selection]
143
+ end
144
+ end
145
+
146
+ # Cue a Character's next scene
147
+ #
148
+ # @param actor [Character] The character being cued
149
+ # @param key [Symbol] The name of the scene
150
+ def cue actor, key
151
+ if !actor.scene.nil? and actor.scene.state == "Concluded"
152
+ return
153
+ end
154
+ if key.nil?
155
+ raise "Cueing scene with nil key"
156
+ end
157
+ manager = scene_managers[key]
158
+ if manager.nil?
159
+ raise "No '#{key}' scene found"
160
+ else
161
+ actor.scene = manager.prepare key
162
+ end
163
+ @scene
164
+ end
165
+
166
+ # This is functionally identical to #cue, but it also raises an
167
+ # exception if the selected scene is not a Concluded state.
168
+ #
169
+ # @param actor [Character] The character being cued
170
+ # @param key [Symbol] The name of the scene
171
+ def conclude actor, key
172
+ key = :concluded if key.nil?
173
+ manager = scene_managers[key]
174
+ if manager.state != "Concluded"
175
+ raise NotConclusionError("Cued scene '#{key}' is not a conclusion")
176
+ end
177
+ cue actor, key
178
+ end
179
+ end
180
+
181
+ end
@@ -0,0 +1,22 @@
1
+ require 'gamefic'
2
+ require 'gamefic/grammar'
3
+
4
+ module Gamefic
5
+ module YouMount
6
+ class YouGrammarSet
7
+ include Grammar::Gender
8
+ include Grammar::Person
9
+ include Grammar::Plural
10
+ include Grammar::WordAdapter
11
+ end
12
+ # @return [YouGrammarSet]
13
+ def you
14
+ if @you.nil?
15
+ @you = YouGrammarSet.new
16
+ @you.person = 2
17
+ end
18
+ @you
19
+ end
20
+ end
21
+
22
+ end