inform-runtime 1.2.3 → 1.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -41
  3. data/lib/story_teller/articles.rb +2 -1
  4. data/lib/story_teller/builtins.rb +63 -10
  5. data/lib/story_teller/color.rb +2 -1
  6. data/lib/story_teller/command.rb +2 -1
  7. data/lib/story_teller/context.rb +23 -27
  8. data/lib/story_teller/daemon.rb +2 -2
  9. data/lib/story_teller/engine.rb +45 -10
  10. data/lib/story_teller/events.rb +1 -1
  11. data/lib/story_teller/experimental/handler_dsl.rb +1 -16
  12. data/lib/story_teller/experimental/reverse_engineer_class.rb +1 -1
  13. data/lib/story_teller/grammar_parser.rb +60 -13
  14. data/lib/story_teller/helpers.rb +8 -4
  15. data/lib/story_teller/history.rb +1 -1
  16. data/lib/story_teller/inflector.rb +4 -2
  17. data/lib/story_teller/inform/ephemeral/link.rb +63 -31
  18. data/lib/story_teller/inform/ephemeral/module.rb +6 -5
  19. data/lib/story_teller/inform/ephemeral/object.rb +223 -236
  20. data/lib/story_teller/inform/ephemeral/tag.rb +27 -14
  21. data/lib/story_teller/io.rb +99 -49
  22. data/lib/story_teller/kernel.rb +2 -2
  23. data/lib/story_teller/library/bootstrap.rb +2 -2
  24. data/lib/story_teller/library/declarations.rb +1 -1
  25. data/lib/story_teller/library/directives.rb +1 -1
  26. data/lib/story_teller/library/loader.rb +3 -20
  27. data/lib/story_teller/library/location.rb +9 -3
  28. data/lib/story_teller/library.rb +1 -1
  29. data/lib/story_teller/logging.rb +1 -1
  30. data/lib/story_teller/mixins.rb +11 -4
  31. data/lib/story_teller/plurals.rb +2 -1
  32. data/lib/story_teller/privileges.rb +89 -6
  33. data/lib/story_teller/prototype.rb +150 -32
  34. data/lib/story_teller/publication.rb +2 -1
  35. data/lib/story_teller/session.rb +115 -25
  36. data/lib/story_teller/stdlib.rb +231 -1
  37. data/lib/story_teller/subscription.rb +2 -1
  38. data/lib/story_teller/tree.rb +2 -1
  39. data/lib/story_teller/version.rb +2 -2
  40. data/lib/story_teller/world_tree.rb +21 -23
  41. data/lib/story_teller.rb +18 -5
  42. metadata +6 -10
  43. data/lib/story_teller/core.rb +0 -39
  44. data/lib/story_teller/ephemeral_adapter.rb +0 -40
  45. data/lib/story_teller/inform/base.rb +0 -160
  46. data/lib/story_teller/model_adapter.rb +0 -132
@@ -2,7 +2,7 @@
2
2
  # encoding: utf-8
3
3
  # frozen_string_literal: false
4
4
 
5
- # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
+ # Copyright Nels Nelson 2008-2026 but freely usable (see license)
6
6
  #
7
7
  # This file is part of StoryTeller.
8
8
  #
@@ -34,7 +34,9 @@ module Inform
34
34
  end
35
35
 
36
36
  def values
37
- super || instance_variables_map
37
+ result = super
38
+ return result if result && result != __method__
39
+ raise NoMethodError, "undefined method `#{__method__}' for #{self}"
38
40
  rescue StandardError => e
39
41
  log.warn "Unexpected error invoking super(Inform::Prototypical#values): #{e.message}"
40
42
  instance_variables_map
@@ -126,25 +128,44 @@ module Inform
126
128
  MethodWriterPattern = %r{=$}.freeze
127
129
  LinkPattern = %r{.+_to$}.freeze
128
130
 
131
+ # rubocop: disable Style/MissingRespondToMissing
132
+ def method_missing(method, *args, &block)
133
+ stack = Thread.current[:prototypical_method_missing_stack] ||= []
134
+ frame = [object_id, method]
135
+
136
+ if stack.include?(frame)
137
+ raise NoMethodError, "Aborting Prototypical missing method " \
138
+ "resolution #{self.class}##{method} on #{inspect}"
139
+ end
140
+
141
+ stack << frame
142
+ attempt_resolution(method, *args, &block)
143
+ ensure
144
+ stack&.pop
145
+ end
146
+ # rubocop: enable Style/MissingRespondToMissing
147
+
129
148
  # rubocop: disable Metrics/AbcSize
130
149
  # rubocop: disable Metrics/CyclomaticComplexity
131
150
  # rubocop: disable Metrics/MethodLength
132
151
  # rubocop: disable Metrics/PerceivedComplexity
133
- # rubocop: disable Style/MissingRespondToMissing
134
- def method_missing(method, *args, &block)
135
- return super if method == :to_ary
152
+ def attempt_resolution(method, *args, &block)
153
+ raise NoMethodError, "undefined method `#{method}' for #{self}" if method == :to_ary
136
154
  m = method.to_s
137
- return super if MethodBooleanOrBangPattern.match?(m)
155
+ raise NoMethodError, "undefined method `#{method}' for #{self}" if MethodBooleanOrBangPattern.match?(m)
138
156
  mname = MethodWriterPattern.match?(m) ? m.chop : m
139
157
  property = mname.to_sym
140
158
  variable = format(VariableTemplate, property: property).to_sym
141
159
  event = context_event
142
160
 
161
+ library = respond_to?(:inflib, true) ? inflib : nil
162
+ object_properties = respond_to?(:properties, true) ? properties : nil
163
+
143
164
  if MethodWriterPattern.match?(m) || (LinkPattern.match?(m) && !args.empty?)
144
165
  if !event.nil? && StoryTeller::Engine.invocation_properties.include?(property)
145
166
  event.send(method, *args, &block)
146
- elsif inflib&.library_method?(method)
147
- inflib.send(method, *args, &block)
167
+ elsif library&.library_method?(method)
168
+ library.send(method, *args, &block)
148
169
  else
149
170
  self.prototype(method, *args, &block)
150
171
  end
@@ -152,13 +173,13 @@ module Inform
152
173
  result = event.send(method, *args, &block)
153
174
  log.debug("Value for event #{event}.#{method} is: #{result || 'nil'}") if defined? DEBUG
154
175
  result
155
- elsif inflib&.library_method?(method)
156
- inflib.send(method, *args, &block)
157
- elsif inflib.respond_to?(method) && StoryTeller::Engine.invocation_properties.include?(property)
158
- inflib.send(method, *args, &block)
159
- elsif inflib&.instance_variable_get(variable) || inflib&.instance_variables&.include?(variable)
160
- inflib.instance_variable_get(variable)
161
- elsif (properties.respond_to?(:key?) && properties.key?(property)) ||
176
+ elsif library&.library_method?(method)
177
+ library.send(method, *args, &block)
178
+ elsif library.respond_to?(method) && StoryTeller::Engine.invocation_properties.include?(property)
179
+ library.send(method, *args, &block)
180
+ elsif library&.instance_variable_get(variable) || library&.instance_variables&.include?(variable)
181
+ library.instance_variable_get(variable)
182
+ elsif property_defined?(object_properties, property) ||
162
183
  (respond_to?(:_key?) && _key?(property)) ||
163
184
  !args.empty?
164
185
  self.prototype(method, *args, &block)
@@ -170,14 +191,13 @@ module Inform
170
191
  # StoryTeller::Library.declarations.properties.key?(property)
171
192
  # self.prototype(method, *args, &block)
172
193
  else
173
- super
194
+ raise NoMethodError, "undefined method `#{method}' for #{self}"
174
195
  end
175
196
  end
176
197
  # rubocop: enable Metrics/AbcSize
177
198
  # rubocop: enable Metrics/CyclomaticComplexity
178
199
  # rubocop: enable Metrics/MethodLength
179
200
  # rubocop: enable Metrics/PerceivedComplexity
180
- # rubocop: enable Style/MissingRespondToMissing
181
201
 
182
202
  # TODO: Remove (2026-04-28)
183
203
  # def respond_to_missing?(method, include_all=false)
@@ -206,32 +226,81 @@ module Inform
206
226
  ).freeze
207
227
 
208
228
  # rubocop: disable Metrics/AbcSize
209
- # rubocop: disable Metrics/CyclomaticComplexity
210
229
  # rubocop: disable Metrics/MethodLength
211
230
  def prototype(key, *args, &block)
212
231
  ensure_properties_attribute!
213
232
  accessor, writer = accessor_and_writer(key)
233
+ link_result = nil
234
+
214
235
  if key_refers_to_link?(key)
215
236
  self.will_change_column(:properties) if self.respond_to?(:will_change_column)
216
- if args.empty? && self.properties.key?(key)
217
- return if (to_obj = get_constant(self.properties[key])).nil? || !to_obj.object?
218
- self.link(key, to_obj)
219
- self.properties.delete(key)
220
- self.save_changes if self.respond_to?(:save_changes)
221
- return to_obj
237
+
238
+ if args.empty?
239
+ link_result = resolve_link_property(key)
240
+ else
241
+ linked_object = object_for_link_value(args.first)
242
+ if linked_object.nil?
243
+ self.properties[key] = args.first
244
+ else
245
+ link_result = set_link_property(key, linked_object)
246
+ end
222
247
  end
223
- self.properties[key] = args.first
224
248
  end
249
+
225
250
  accessor = format(AccessorMethodTemplate, accessor: accessor)
226
251
  self.instance_eval(accessor, __FILE__, __LINE__)
227
252
  writer = format(WriterMethodTemplate, writer: writer)
228
253
  self.instance_eval(writer, __FILE__, __LINE__)
254
+
255
+ return link_result unless link_result.nil?
256
+
229
257
  self.send(key, *args, &block)
230
258
  end
231
259
  # rubocop: enable Metrics/AbcSize
232
- # rubocop: enable Metrics/CyclomaticComplexity
233
260
  # rubocop: enable Metrics/MethodLength
234
261
 
262
+ # rubocop: disable Metrics/CyclomaticComplexity
263
+ def resolve_link_property(key)
264
+ return nil unless key_refers_to_link?(key)
265
+
266
+ linked_object = self._get_object(key) if self.respond_to?(:_key?) &&
267
+ self._key?(key) &&
268
+ self.respond_to?(:_get_object)
269
+ return linked_object unless linked_object.nil?
270
+
271
+ property_key = property_key_for(key)
272
+ return nil if property_key.nil?
273
+
274
+ linked_object = object_for_link_value(self.properties[property_key])
275
+ return nil if linked_object.nil?
276
+
277
+ set_link_property(key, linked_object, property_key: property_key)
278
+ end
279
+ # rubocop: enable Metrics/CyclomaticComplexity
280
+
281
+ def object_for_link_value(value)
282
+ return value if value.respond_to?(:object?) && value.object?
283
+ return nil unless value.is_a?(Symbol) || value.is_a?(String)
284
+
285
+ object = constant_for_link_value(value)
286
+ return object if object.respond_to?(:object?) && object.object?
287
+
288
+ nil
289
+ end
290
+
291
+ def constant_for_link_value(value)
292
+ names = value.to_s.split('::').reject(&:empty?)
293
+ return nil if names.empty?
294
+
295
+ names.inject(::Object) do |scope, name|
296
+ return nil unless scope.const_defined?(name)
297
+
298
+ scope.const_get(name)
299
+ end
300
+ rescue NameError
301
+ nil
302
+ end
303
+
235
304
  MISSING_PROPERTIES_MESSAGE = 'Missing properties attribute for: ' \
236
305
  '%<identity>s'.freeze
237
306
 
@@ -240,14 +309,46 @@ module Inform
240
309
  raise StandardError, format(MISSING_PROPERTIES_MESSAGE, identity: self.identity)
241
310
  end
242
311
 
312
+ def property_defined?(object_properties, property)
313
+ return false unless object_properties.respond_to?(:key?)
314
+
315
+ object_properties.key?(property) || object_properties.key?(property.to_s)
316
+ end
317
+
243
318
  def key_refers_to_link?(key)
244
- StoryTeller::Library.declarations.properties.key?(key) && LinkPattern.match?(key.to_s)
319
+ return false unless LinkPattern.match?(key.to_s)
320
+
321
+ declared_property?(key)
322
+ end
323
+
324
+ def declared_property?(key)
325
+ return false unless defined?(StoryTeller::Library)
326
+ return false unless StoryTeller::Library.respond_to?(:declarations)
327
+
328
+ declarations = StoryTeller::Library.declarations
329
+ properties = declarations.properties if declarations.respond_to?(:properties)
330
+ return false unless properties.respond_to?(:key?)
331
+
332
+ properties.key?(key.to_sym) || properties.key?(key.to_s)
333
+ rescue StandardError
334
+ false
335
+ end
336
+
337
+ def property_key_for(key)
338
+ return key if self.properties.key?(key)
339
+
340
+ string_key = key.to_s
341
+ return string_key if self.properties.key?(string_key)
342
+
343
+ nil
245
344
  end
246
345
 
247
346
  def _get(key)
248
347
  result = nil
249
348
  result = self._get_object(key) if self.respond_to?(:_key?) && self._key?(key)
250
- result || self.properties.dup[key]
349
+ return result unless result.nil?
350
+
351
+ resolve_link_property(key) || self.properties.dup[property_key_for(key)]
251
352
  end
252
353
 
253
354
  # rubocop: disable Metrics/AbcSize
@@ -260,11 +361,13 @@ module Inform
260
361
  result = nil
261
362
  if values.first.object?
262
363
  result = self._set_object(key, values.first) if respond_to? :_set_object
364
+ elsif key_refers_to_link?(key) && (linked_object = object_for_link_value(values.first))
365
+ result = set_link_property(key, linked_object)
263
366
  elsif values.first.nil? && self.respond_to?(:_key?) && self._key?(key)
264
367
  result = self._unset_object(key) if self.respond_to?(:_unset_object)
265
368
  elsif values.first.nil?
266
369
  self.will_change_column(:properties) if self.respond_to?(:will_change_column)
267
- self.properties.delete(key)
370
+ self.properties.delete(property_key_for(key))
268
371
  self.save_changes if self.respond_to?(:save_changes)
269
372
  elsif values.length > 1
270
373
  self.will_change_column(:properties) if self.respond_to?(:will_change_column)
@@ -277,7 +380,7 @@ module Inform
277
380
  self.properties[key] = values.first
278
381
  self.save_changes if self.respond_to?(:save_changes)
279
382
  end
280
- result || self.properties.dup[key]
383
+ result || self.properties.dup[property_key_for(key)]
281
384
  end
282
385
  # rubocop: enable Metrics/AbcSize
283
386
  # rubocop: enable Metrics/CyclomaticComplexity
@@ -293,23 +396,38 @@ module Inform
293
396
  result = nil
294
397
  if value.object?
295
398
  result = self._set_object(key, value) if self.respond_to?(:_set_object)
399
+ elsif key_refers_to_link?(key) && (linked_object = object_for_link_value(value))
400
+ result = set_link_property(key, linked_object)
296
401
  elsif value.nil? && self.respond_to?(:_key?) && self._key?(key)
297
402
  result = self._unset_object(key) if self.respond_to?(:_unset_object)
298
403
  elsif value.nil? && self.properties.key?(key)
299
404
  self.will_change_column(:properties) if self.respond_to?(:will_change_column)
300
- self.properties.delete(key)
405
+ self.properties.delete(property_key_for(key))
301
406
  self.save_changes if self.respond_to?(:save_changes)
302
407
  else
303
408
  self.will_change_column(:properties) if self.respond_to?(:will_change_column)
304
409
  self.properties[key] = value
305
410
  self.save_changes if self.respond_to?(:save_changes)
306
411
  end
307
- result || self.properties.dup[key]
412
+ result || self.properties.dup[property_key_for(key)]
308
413
  end
309
414
  # rubocop: enable Metrics/AbcSize
310
415
  # rubocop: enable Metrics/CyclomaticComplexity
311
416
  # rubocop: enable Metrics/MethodLength
312
417
  # rubocop: enable Metrics/PerceivedComplexity
418
+
419
+ def set_link_property(key, object, property_key: property_key_for(key))
420
+ result = if self.respond_to?(:_set_object)
421
+ self._set_object(key, object)
422
+ elsif self.respond_to?(:link)
423
+ self.link(key, object)
424
+ object
425
+ end
426
+ self.properties.delete(property_key) unless property_key.nil?
427
+ self.will_change_column(:properties) if self.respond_to?(:will_change_column)
428
+ self.save_changes if self.respond_to?(:save_changes)
429
+ result || object
430
+ end
313
431
  end
314
432
  # module Prototypical
315
433
  end
@@ -1,7 +1,8 @@
1
+ # lib/story_teller/publication.rb
1
2
  # encoding: utf-8
2
3
  # frozen_string_literal: false
3
4
 
4
- # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
+ # Copyright Nels Nelson 2008-2026 but freely usable (see license)
5
6
  #
6
7
  # This file is part of the StoryTeller.
7
8
  #
@@ -1,7 +1,8 @@
1
+ # lib/story_teller/session.rb
1
2
  # encoding: utf-8
2
3
  # frozen_string_literal: false
3
4
 
4
- # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
+ # Copyright Nels Nelson 2008-2026 but freely usable (see license)
5
6
  #
6
7
  # This file is part of StoryTeller.
7
8
  #
@@ -22,6 +23,7 @@
22
23
  module SessionManagementMethods
23
24
  class Registry < Hash; end
24
25
  SessionsByChannel = Registry.new
26
+ SessionsByPlayer = Registry.new
25
27
 
26
28
  def add_promiscuous_states(*states)
27
29
  Promiscuous.merge states.flatten
@@ -31,12 +33,52 @@ module SessionManagementMethods
31
33
  SessionsByChannel
32
34
  end
33
35
 
36
+ def sessions_by_player
37
+ SessionsByPlayer
38
+ end
39
+
34
40
  def register(channel, session)
35
41
  sessions_by_channel[channel] = session
42
+ session.channel = channel if session.respond_to?(:channel=)
43
+ session
44
+ end
45
+
46
+ def register_player(player, session)
47
+ sessions_by_player[player] = session
48
+ session
36
49
  end
37
50
 
38
51
  def unregister(channel)
39
- sessions_by_channel.delete(channel)
52
+ session = sessions_by_channel.delete(channel)
53
+ sessions_by_player.delete_if { |_player, candidate| candidate.equal?(session) }
54
+ session
55
+ end
56
+
57
+ def release_player(player, session = nil)
58
+ return nil if player.nil?
59
+ return sessions_by_player.delete(player) if session.nil?
60
+ return sessions_by_player.delete(player) if sessions_by_player[player].equal?(session)
61
+
62
+ nil
63
+ end
64
+
65
+ def of(obj)
66
+ return nil if obj.nil?
67
+ return obj if obj.is_a?(self)
68
+
69
+ sessions_by_channel[obj] ||
70
+ sessions_by_player[obj] ||
71
+ session_for_method(obj, :player) ||
72
+ session_for_method(obj, :selfobj) ||
73
+ session_for_ivar(obj, :@player)
74
+ end
75
+
76
+ def players
77
+ sessions_by_player.keys
78
+ end
79
+
80
+ def channels
81
+ sessions_by_channel.keys
40
82
  end
41
83
 
42
84
  def [](channel)
@@ -52,7 +94,21 @@ module SessionManagementMethods
52
94
  end
53
95
 
54
96
  def get(channel)
55
- sessions_by_channel[channel] ||= Session.new(channel)
97
+ sessions_by_channel[channel] ||= new(channel)
98
+ end
99
+
100
+ private
101
+
102
+ def session_for_method(obj, method_name)
103
+ return nil unless obj.respond_to?(method_name)
104
+
105
+ sessions_by_player[obj.public_send(method_name)]
106
+ end
107
+
108
+ def session_for_ivar(obj, ivar_name)
109
+ return nil unless obj.instance_variable_defined?(ivar_name)
110
+
111
+ sessions_by_player[obj.instance_variable_get(ivar_name)]
56
112
  end
57
113
  end
58
114
  # module SessionManagementMethods
@@ -84,28 +140,43 @@ module SessionStateManagementMethods
84
140
  end
85
141
  end
86
142
 
87
- module Inform
143
+ # module StoryTeller
144
+ module StoryTeller
145
+ # module IO
88
146
  module IO
89
147
  # The Session class
90
148
  # TODO: Refactor method implementations into modules
149
+ # rubocop: disable Metrics/ClassLength
91
150
  class Session
92
- # These states accept any input, including no input
93
- Promiscuous = Set.new
94
151
  include SessionStateManagementMethods
95
152
 
96
153
  class << self
97
154
  include SessionManagementMethods
98
155
  end
99
- attr_accessor :channel, :state, :status
156
+ attr_accessor :channel, :machine, :player, :state, :status
100
157
  attr_reader :last_good_state, :last_activity, :previous, :inbound, :outbound, :settings
101
158
 
102
- def initialize(channel = nil)
103
- init_channel_session(channel) unless channel.nil?
104
- @status = nil
105
- @last_good_state = @state = default if respond_to? :default
159
+ # These states accept any input, including no input
160
+ Promiscuous = Set.new
161
+
162
+ # rubocop: disable Metrics/MethodLength
163
+ def initialize(channel = nil, machine: nil, player: nil, state: :playing, settings: {})
164
+ @channel = channel
165
+ @machine = machine
166
+ @player = nil
167
+ @state = state
168
+ @last_good_state = state
106
169
  @session_data = {}
107
- @settings = {}
170
+ @settings = settings
171
+ @status = nil
172
+ @last_activity = Time.now
173
+
174
+ self.class.register(channel, self) unless channel.nil?
175
+ control(player) unless player.nil?
108
176
  end
177
+ # rubocop: enable Metrics/MethodLength
178
+
179
+ alias preferences settings
109
180
 
110
181
  def init_channel_session(channel)
111
182
  Session[channel] = self
@@ -115,6 +186,13 @@ class Session
115
186
  @last_activity = Time.now
116
187
  end
117
188
 
189
+ def control(player)
190
+ self.class.release_player(@player, self)
191
+ @player = player
192
+ self.class.register_player(player, self) unless player.nil?
193
+ self
194
+ end
195
+
118
196
  def receive(message)
119
197
  return if message.nil? # It is okay if the message parameter is an empty string
120
198
  return disconnected if @channel.nil?
@@ -122,7 +200,7 @@ class Session
122
200
  process(sanitize(message))
123
201
  end
124
202
 
125
- def update(machine = self)
203
+ def update(machine = @machine)
126
204
  safely_progress(machine)
127
205
  after_update if self.respond_to?(:after_update)
128
206
  @last_good_state = @state unless @state == :confused
@@ -140,24 +218,27 @@ class Session
140
218
  self
141
219
  end
142
220
 
221
+ def expose_to(machine)
222
+ machine.instance_variable_set(:@buffer, @buffer)
223
+ machine.instance_variable_set(:@session, self)
224
+ end
225
+
143
226
  ExitCommandPattern = /^(exit|quit|q)$/i.freeze
144
227
 
145
228
  def exit_command?(message)
146
229
  !Promiscuous.include?(@state) && ExitCommandPattern.match?(message)
147
230
  end
148
231
 
149
- def process(message)
150
- return disconnect if exit_command?(message)
151
- @buffer = message
232
+ def process(message, machine = @machine)
233
+ raise ArgumentError, 'session machine is required' if machine.nil?
234
+
235
+ @machine = machine
236
+ @buffer = sanitize(message)
152
237
  @last_activity = Time.now
153
238
  @status = :active
154
- if valid_state?
155
- update
156
- else
157
- @inbound.publish @buffer
158
- end
159
239
 
160
- respond
240
+ expose_to(machine)
241
+ update(machine)
161
242
  end
162
243
 
163
244
  def respond
@@ -165,7 +246,7 @@ class Session
165
246
  end
166
247
 
167
248
  def safely_progress(machine = self)
168
- @state = machine.send(@state)
249
+ @state = machine.public_send(@state)
169
250
  raise 'Bad state machine implementation: nil state' if @state.nil?
170
251
  rescue StandardError => e
171
252
  log.error "Error updating state: #{e.message}", e
@@ -176,7 +257,7 @@ class Session
176
257
  def valid_state?(machine = self)
177
258
  case @state
178
259
  when String, Symbol
179
- machine.respond_to? @state
260
+ machine.respond_to?(@state)
180
261
  else
181
262
  false
182
263
  end
@@ -189,12 +270,21 @@ class Session
189
270
  prompt
190
271
  @last_good_state
191
272
  end
273
+
274
+ private
275
+
276
+ def prepare_machine(machine)
277
+ return if machine.equal?(self)
278
+
279
+ machine.instance_variable_set(:@buffer, @buffer)
280
+ end
192
281
  end
193
282
  # class Session
283
+ # rubocop: enable Metrics/ClassLength
194
284
 
195
285
  # The Connection class
196
286
  class Connection; end
197
287
  end
198
288
  # module IO
199
289
  end
200
- # module Inform
290
+ # module StoryTeller