Class: Inform::Object

Inherits:
Sequel::Model show all
Includes:
Inform, Daemons, Events, Genealogical, IO, Linkable, Modular, Prototypical, Publisher, Taggable
Defined in:
lib/runtime/object.rb,
lib/runtime/world_tree.rb

Overview

The Inform::Object functionality

Direct Known Subclasses

ExtendedProperties

Constant Summary collapse

Visited =
defined?(Java) ? java.util.concurrent.ConcurrentHashMap.new : {}
COUNT_FAIL_MESSAGE =
'Failed to count children for %<obj>s: %<message>s'.freeze
ExportFileNameTemplate =
'%<self>s-%<id>s.%<ext>'.freeze
JsonOptions =
{
  include: i[tagged modularized]
}.freeze
XmlOptions =
{
  except: :id,
  include: {
    tagged: {
      except: :id
    },
    modularized: {
      except: :id
    }
  }
}.freeze
XmlFileNameTemplate =
'%<self>s-%<id>s.json'.freeze

Constants included from Daemons

Daemons::DaemonExecutionElapsedMessage, Daemons::DaemonScanElapsedMessage, Daemons::RecordNotFoundPattern

Constants included from Prototypical

Prototypical::AccessorMethodTemplate, Prototypical::LinkPattern, Prototypical::MISSING_PROPERTIES_MESSAGE, Prototypical::MethodBooleanOrBangPattern, Prototypical::MethodWriterPattern, Prototypical::MethodWriterTemplate, Prototypical::VariableTemplate, Prototypical::WriterMethodTemplate

Constants included from Subscribers

Subscribers::REGISTRY

Constants included from Events

Events::DEFAULT_ADD_EVENT_PARAMS, Events::REGISTRY, Events::THREADS_PER_PROCESSOR

Constants included from IO

IO::ItemPaddingString, IO::MinimumCellPadding, IO::MinimumColumnPadding, IO::MinimumLineLength

Constants included from Inform

Dictionary, INFORM_DIR_PATH, LIB_DIR_PATH, MethodDefinitionPattern, MethodTerminationPattern, NOUN, PLURAL, PREPOSITION, PROJECT_DIR_PATH, RUNTIME_DIR_PATH, SystemObjects, VERB, VERSION, VN_1610

Constants included from Color

Color::BackgroundColorCodes, Color::ColorCodes, Color::NearestColor, Color::StyleCodes

Constants included from Articles

Articles::LowercaseASpaceString, Articles::LowercaseSomeSpaceString, Articles::LowercaseTheSpaceString

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Daemons

#StartDaemon, #StartTimer, #StopDaemon, #StopTimer, #daemonic?, #daemonize, daemons, ensure_inform_library, execute, execute_daemon, execute_each_turn, #ghost, #heart, #init_heart, #occasionally, #on?, refresh_or_remove, #rescan, scan_objects, #schedules, #spawn, start, stop

Methods included from Genealogical

#>, #all?, #any?, #branch, #children, #collect, #concat, #count, #delete_if, #each, #each_with_object, #find, #find_all, #having, #in?, #include?, #map, #notin?, #reject, #select, #sibling, #siblings, #within?

Methods included from Modular

#apply_modules, #mod, #modules, #modules_semaphore, #nil_safe_modules, #reset_modules, #unmod

Methods included from Taggable

#nil_safe_tags, #tag, #tag_names, #tagged_with?, #tagged_with_all?, #tagged_with_any?, #tagged_with_none?, #untag

Methods included from TagHelpers

#attributes, #has, #has?, #hasany?, #hasnt, #hasnt?

Methods included from Linkable

#_set_object, #link, #linked?, #links, #linksfrom, #linkto, #unlink

Methods included from Prototypical

#&, #_assign, #_get, #_set, #accessor_and_writer, #context_event, #ensure_properties_attribute!, #instance_variables_map, #key_refers_to_link?, #method_missing, #prototype, #string?, #values, #|

Methods included from Publisher

#muted?, #publish, #publish_except, #publish_only, #publish_system_message, #subscribers

Methods included from Subscribers

#explicit_subscribers, #subscribe, #subscribers, #unsubscribe, #unsubscribe_all

Methods included from Events

#active?, active_objects, #add_event, available_processors, #contextualize, #delay, each, #elementally, #event, #events, #immediately, init_java_pool, init_java_pooled_executor, init_java_scheduled_executor, init_java_scheduler, init_pool, init_scheduled_executor, init_scheduler, #interrupt, object_events, pool, pooled_executor, possibilities, #register_callback, scheduled_executor, scheduler

Methods included from IO

#connections, #flush_io, #inform, #many_per_line, #new_line, #noop, #out, #output_stream, #prompt, #read, #reset_prompt, #session, #spaces, #tidy_output

Methods included from Inform

Grammar, #apply_instance_behavior!, attributes, #builder, #classification, #compass, #content, context, context_class, #context_proxy, #current_word, #deadflag, #deadflag=, #dict_par1, #dictionary, #disrobe, #drop, #emote, #ensure_behavior_module!, #extend_and_persist, #findobject, #getobject, #go, #initial, initialize_persistence_layer, #language_descriptors, #language_pronouns, #library_method?, #life?, #light_adjusted, load_grammar, load_grammar_by_path, #method_source, #nothing, #num_words, #number, #objectloop, #ofclass, #pause, prime_dictionary, #provides?, #quit, #randomly, #react_after?, #react_before?, #remaining_words, #resembles_method?, #run_daemons, #say, #score, #score=, #search, #special, #the_time, #the_time=, #things_score, #things_score=, #to_s, #topic, unload_grammars!, #visibility_ceiling=, #with, #workflags

Methods included from Plurals

#apply_inflections, #plural?, #pluralize, #singular?, #singularize

Methods included from Color

#background_color, #color, #nearest_color, #style, #un_background_color, #un_color, #un_style

Methods included from Articles

#A, #Cthatorthose, #Ctheyreorthats, #The, #a, #cthatorthose, #ctheyreorthats, #defart, #indefart, #isorare, #itorthem, #thatorthose, #the

Methods inherited from Sequel::Model

implicit_table_name

Methods included from InheritanceListener

included

Constructor Details

#initialize(*args, &block) ⇒ Object

rubocop: disable Metrics/MethodLength rubocop: disable Metrics/PerceivedComplexity



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/runtime/object.rb', line 92

def initialize(*args, &block)
  if args.empty?
    if block_given?
      super() { |obj| obj }
    else
      super()
    end
  elsif args.first.is_a?(String)
    short_name = args.first
    if block_given?
      super(name: short_name, short_name: short_name) { |obj| obj }
    else
      super(name: short_name, short_name: short_name)
    end
  elsif block_given?
    super { |obj| obj }
  else
    super(*args)
  end
  @tags_semaphore = Mutex.new
  @semaphore = Mutex.new
  self.with(&block) if block_given?
  self.save_changes
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Inform::Prototypical

Class Method Details

.fetch_or_create_by_name(name) ⇒ Object

rubocop: enable Metrics/MethodLength rubocop: enable Metrics/PerceivedComplexity



119
120
121
122
123
# File 'lib/runtime/object.rb', line 119

def self.fetch_or_create_by_name(name)
  db.transaction(savepoint: true) do
    for_update.where(name: name).first || create(name: name, short_name: name)
  end
end

Instance Method Details

#<<(o) ⇒ Object

TODO: Implement a unit test for this



269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/runtime/object.rb', line 269

def <<(o)
  return if o.nil?
  return if o == self
  if o.sysobj?
    o.parent = self
    sys_children << o
  else
    self.add_child o
    self.save_changes if self.respond_to?(:save_changes)
    self.refresh
  end
end

#<=>(other) ⇒ Object



180
181
182
# File 'lib/runtime/object.rb', line 180

def <=>(other)
  self.name <=> other.name
end

#==(other) ⇒ Object



184
185
186
# File 'lib/runtime/object.rb', line 184

def ==(other)
  other.respond_to?(:values) ? self.values[:id] == other.values[:id] : super
end

#_invoke(a, *args) ⇒ Object



200
201
202
203
# File 'lib/runtime/object.rb', line 200

def _invoke(a, *args)
  return unless inflib
  inflib._invoke(a, *args)
end

#after_clone(copy) ⇒ Object



357
358
359
# File 'lib/runtime/object.rb', line 357

def after_clone(copy)
  copy.untag :prized
end

#after_createObject



314
315
316
317
318
# File 'lib/runtime/object.rb', line 314

def after_create
  super
  index_words if self.respond_to?(:index_words)
  init
end

#after_destroyObject



326
327
328
# File 'lib/runtime/object.rb', line 326

def after_destroy
  super
end

#after_initializeObject



330
331
332
333
# File 'lib/runtime/object.rb', line 330

def after_initialize
  super
  apply_instance_behavior! if self.respond_to?(:apply_instance_behavior!)
end

#after_loadObject



341
342
343
344
# File 'lib/runtime/object.rb', line 341

def after_load
  super
  drain_deferred_with! if self.respond_to?(:drain_deferred_with!)
end

#after_refreshObject



335
336
337
338
339
# File 'lib/runtime/object.rb', line 335

def after_refresh
  super
  drain_deferred_with! if self.respond_to?(:drain_deferred_with!)
  apply_instance_behavior! if self.respond_to?(:apply_instance_behavior!)
end

#after_saveObject



346
347
348
349
# File 'lib/runtime/object.rb', line 346

def after_save
  super
  self.modified_at = Time.now
end

#before_clone(copy) ⇒ Object



355
# File 'lib/runtime/object.rb', line 355

def before_clone(copy); end

#before_createObject



309
310
311
312
# File 'lib/runtime/object.rb', line 309

def before_create
  self.created_at ||= Time.now
  super
end

#before_destroyObject



320
321
322
323
324
# File 'lib/runtime/object.rb', line 320

def before_destroy
  self.safe_refresh if self.respond_to?(:safe_refresh)
  self.children.each { |x| x.destroy unless x.has? :prized }
  super
end

#before_saveObject



351
352
353
# File 'lib/runtime/object.rb', line 351

def before_save
  super
end

#child(o = nil) ⇒ Object



297
298
299
# File 'lib/runtime/object.rb', line 297

def child(o = nil)
  o ? o.child : self.children.first
end

#classify_as(klass) ⇒ Object



247
248
249
250
251
252
253
254
# File 'lib/runtime/object.rb', line 247

def classify_as(klass)
  return if klass.nil?
  klass = find_class klass unless klass.is_a? Class
  self.object_type = klass.name
  self.safe_save
  self.safe_init
  Inform::Object[self.id]
end

#cloneObject

rubocop: disable Metrics/AbcSize rubocop: disable Metrics/MethodLength



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/runtime/object.rb', line 367

def clone
  return if Session.players.include?(self) # Don't clone players.
  data = self.values.dup
  data.delete :id
  data.delete :attributes
  data.delete :properties
  copy = self.class.new(data)
  before_clone(copy) if respond_to?(:before_clone)
  copy.properties = self.properties.dup
  copy.save
  copy.untag(*copy.tags)
  copy.tag(*self.tags)
  copy.mod(*self.modules)
  copy.link(:original, self)
  self.children.each { |x| copy << x.clone }
  after_clone(copy) if respond_to?(:after_clone)
  copy
end

#description(*args) ⇒ Object



148
149
150
151
152
153
# File 'lib/runtime/object.rb', line 148

def description(*args)
  return self[:description] if args.nil? || args.empty?
  self[:description] = args.length > 1 ? args.join(' ') : args.first
  self.save_changes if self.respond_to?(:save_changes)
  self[:description]
end

#empty?Boolean



290
291
292
293
294
295
# File 'lib/runtime/object.rb', line 290

def empty?
  self.class.where(parent_id: self.id).count.zero?
rescue StandardError => e
  log.warn format(COUNT_FAIL_MESSAGE, obj: self.identity, message: e.message)
  children_dataset.count.zero?
end

#encode_with(coder) ⇒ Object



435
436
437
438
439
# File 'lib/runtime/object.rb', line 435

def encode_with(coder)
  %w[id name short_name description properties links modularized tagged].each do |v|
    coder[v] = self.send(v) if self.respond_to? v
  end
end

#export_jsonObject



407
408
409
410
# File 'lib/runtime/object.rb', line 407

def export_json
  return unless respond_to? :to_json
  self.to_json(**JsonOptions).save(format(ExportFileNameTemplate, name: self.to_s, id: self.id, ext: :json))
end

#export_xmlObject



430
431
432
433
# File 'lib/runtime/object.rb', line 430

def export_xml
  return unless self.respond_to? :to_xml
  self.to_xml(**XmlOptions).save(format(ExportFileNameTemplate, name: self.to_s, id: self.id, ext: :xml))
end

#export_yamlObject



412
413
414
415
# File 'lib/runtime/object.rb', line 412

def export_yaml
  return unless self.respond_to? :to_yaml
  self.to_yaml.save(format(ExportFileNameTemplate, name: self.to_s, id: self.id, ext: :yml))
end

#inflibObject



205
206
207
208
# File 'lib/runtime/object.rb', line 205

def inflib
  return Inform::Runtime.libraries[self] if self.has?(:animate) || (defined?(Character) && self.is_a?(Character))
  @inflib
end

#inflib=(inflib) ⇒ Object

rubocop: disable Style/TrivialAccessors



211
212
213
# File 'lib/runtime/object.rb', line 211

def inflib=(inflib)
  @inflib = inflib
end

#initObject



361
362
363
# File 'lib/runtime/object.rb', line 361

def init
  # A designer should implement this in a subclass if necessary
end

#invoke(a, *args) ⇒ Object



195
196
197
198
# File 'lib/runtime/object.rb', line 195

def invoke(a, *args)
  return unless inflib
  inflib.invoke(a, *args)
end

#list_togetherObject



305
306
307
# File 'lib/runtime/object.rb', line 305

def list_together
  linkto :list_together
end

#locationObject



301
302
303
# File 'lib/runtime/object.rb', line 301

def location
  linkto(:location) || self.parent
end

#name(*args) ⇒ Object

rubocop: enable Metrics/AbcSize



140
141
142
143
144
145
146
# File 'lib/runtime/object.rb', line 140

def name(*args)
  return args.first.object_name if args.first.respond_to?(:object_name)
  return self[:name] if args.empty?
  self[:name] = args.length > 1 ? args.join(' ') : args.first
  self.save_changes if self.respond_to?(:save_changes)
  self[:name]
end

#name_wordsObject



159
160
161
# File 'lib/runtime/object.rb', line 159

def name_words
  self.values[:name].split(/[,\s]+/).join(', ')
end

#object_nameObject



155
156
157
# File 'lib/runtime/object.rb', line 155

def object_name
  self[:display_name] || self[:short_name] || self[:name]
end

#parse(s) ⇒ Object



188
189
190
191
192
193
# File 'lib/runtime/object.rb', line 188

def parse(s)
  return if inflib.nil?
  semaphore.synchronize do
    inflib.println(inflib.parse(s))
  end
end


220
221
222
# File 'lib/runtime/object.rb', line 220

def print(s, isolate: false)
  inflib&.print(s, isolate: isolate)
end

#println(s, isolate: false) ⇒ Object

rubocop: enable Style/TrivialAccessors



216
217
218
# File 'lib/runtime/object.rb', line 216

def println(s, isolate: false)
  inflib&.println(s, isolate: isolate)
end

#removeObject



282
283
284
285
286
# File 'lib/runtime/object.rb', line 282

def remove
  self.parent.remove_child(self.id) if self.parent&.children&.include?(self)
rescue StandardError => e
  log.error e
end

#routinesObject



176
177
178
# File 'lib/runtime/object.rb', line 176

def routines
  ((self.methods - Object.instance_methods) - Inform::Object.instance_methods).sort.uniq
end

#safe_initObject



241
242
243
244
245
# File 'lib/runtime/object.rb', line 241

def safe_init
  self.init if self.respond_to? :init
rescue Sequel::NoExistingObject => e
  log.warn "Object initialization failure: #{e.message}; ignoring"
end

#safe_refreshObject



229
230
231
232
233
# File 'lib/runtime/object.rb', line 229

def safe_refresh
  self.refresh
rescue Sequel::NoExistingObject => e
  log.warn "Object refresh failure: #{e.message}; ignoring"
end

#safe_saveObject



235
236
237
238
239
# File 'lib/runtime/object.rb', line 235

def safe_save
  self.save_changes if self.respond_to?(:save_changes)
rescue Sequel::NoExistingObject => e
  log.warn "Object save failure: #{e.message}; ignoring"
end

#semaphoreObject



163
164
165
# File 'lib/runtime/object.rb', line 163

def semaphore
  @semaphore ||= Mutex.new
end

#short_name(*args) ⇒ Object

rubocop: disable Metrics/AbcSize



126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/runtime/object.rb', line 126

def short_name(*args)
  return (self.short_name = args.first) unless args.empty?
  textual_name = self.values[:short_name]
  synonyms = self.values[:name]
  if textual_name.nil? || (textual_name.respond_to?(:empty?) && textual_name.empty?)
    self.values[:short_name] = synonyms
    self.save_changes if self.respond_to?(:save_changes)
    self.values[:short_name]
  else
    textual_name
  end
end

#sys_childrenObject



256
257
258
# File 'lib/runtime/object.rb', line 256

def sys_children
  SystemObjects[identity] ||= []
end

#sysclone(klass = Inform::System::Object) ⇒ Object

Create a clone of this object that is a non-persistent Inform::System::Object instead



390
391
392
393
394
395
396
397
398
399
400
# File 'lib/runtime/object.rb', line 390

def sysclone(klass = Inform::System::Object)
  copy = klass.new(self.short_name)
  copy.name = self.name
  # TODO: Support children cloning (maybe shallow only)
  copy.properties = self.properties.dup
  copy.properties[:source_id] = self.id
  copy.tags = self.nil_safe_tags
  # TODO: Support modules
  after_clone(copy) if respond_to?(:after_clone)
  copy
end

#tagsObject



172
173
174
# File 'lib/runtime/object.rb', line 172

def tags
  tags_semaphore.synchronize { tags_original }
end

#tags_originalObject



171
# File 'lib/runtime/object.rb', line 171

alias tags_original tags

#tags_semaphoreObject



167
168
169
# File 'lib/runtime/object.rb', line 167

def tags_semaphore
  @tags_semaphore ||= Mutex.new
end

#visitedObject



225
226
227
# File 'lib/runtime/object.rb', line 225

def visited
  Visited[self] ||= []
end