inform-runtime 1.0.4 → 1.2.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -12
  3. data/Rakefile +26 -16
  4. data/lib/{runtime → story_teller}/articles.rb +14 -10
  5. data/lib/{runtime → story_teller}/builtins.rb +50 -22
  6. data/lib/{runtime → story_teller}/color.rb +8 -8
  7. data/lib/{runtime → story_teller}/command.rb +26 -28
  8. data/lib/{runtime → story_teller}/context.rb +23 -24
  9. data/lib/story_teller/core.rb +38 -0
  10. data/lib/{runtime → story_teller}/daemon.rb +35 -36
  11. data/lib/story_teller/engine.rb +151 -0
  12. data/lib/story_teller/ephemeral_adapter.rb +42 -0
  13. data/lib/{runtime → story_teller}/events.rb +8 -9
  14. data/lib/{runtime → story_teller}/experimental/handler_dsl.rb +7 -18
  15. data/lib/story_teller/experimental/reverse_engineer_class.rb +37 -0
  16. data/lib/{runtime → story_teller}/grammar_parser.rb +24 -40
  17. data/lib/{runtime → story_teller}/helpers.rb +21 -7
  18. data/lib/{runtime → story_teller}/history.rb +5 -5
  19. data/lib/{runtime → story_teller}/inflector.rb +4 -5
  20. data/lib/story_teller/inform/base.rb +160 -0
  21. data/lib/{runtime → story_teller/inform/ephemeral}/link.rb +27 -45
  22. data/lib/{runtime → story_teller/inform/ephemeral}/module.rb +17 -58
  23. data/lib/story_teller/inform/ephemeral/object.rb +329 -0
  24. data/lib/{runtime → story_teller/inform/ephemeral}/tag.rb +54 -81
  25. data/lib/story_teller/inform/models.rb +25 -0
  26. data/lib/{runtime → story_teller}/io.rb +10 -10
  27. data/lib/{runtime → story_teller}/kernel.rb +21 -31
  28. data/lib/story_teller/library/bootstrap.rb +66 -0
  29. data/lib/story_teller/library/declarations.rb +53 -0
  30. data/lib/story_teller/library/directives.rb +91 -0
  31. data/lib/story_teller/library/loader.rb +104 -0
  32. data/lib/story_teller/library/location.rb +73 -0
  33. data/lib/{runtime → story_teller}/library.rb +27 -12
  34. data/lib/{runtime → story_teller}/logging.rb +47 -24
  35. data/lib/{runtime → story_teller}/mixins.rb +6 -6
  36. data/lib/story_teller/model_adapter.rb +132 -0
  37. data/lib/{runtime → story_teller}/plurals.rb +11 -11
  38. data/lib/{runtime → story_teller}/prototype.rb +11 -10
  39. data/lib/{runtime → story_teller}/publication.rb +9 -9
  40. data/lib/{runtime → story_teller}/session.rb +6 -8
  41. data/lib/{runtime → story_teller}/stdlib.rb +13 -11
  42. data/lib/{runtime → story_teller}/subscription.rb +8 -8
  43. data/lib/{runtime → story_teller}/tree.rb +6 -6
  44. data/lib/{runtime → story_teller}/version.rb +16 -6
  45. data/lib/story_teller/world_tree.rb +54 -0
  46. data/lib/story_teller.rb +26 -0
  47. metadata +59 -99
  48. data/config/database.yml +0 -37
  49. data/exe/inform.rb +0 -6
  50. data/game/config.yml +0 -5
  51. data/game/example.inf +0 -76
  52. data/game/example.rb +0 -90
  53. data/game/forms/example_form.rb +0 -2
  54. data/game/grammar/game_grammar.inf.rb +0 -11
  55. data/game/languages/english.rb +0 -2
  56. data/game/models/example_model.rb +0 -2
  57. data/game/modules/example_module.rb +0 -9
  58. data/game/rules/example_state.rb +0 -2
  59. data/game/scripts/example_script.rb +0 -2
  60. data/game/topics/example_topic.rb +0 -2
  61. data/game/verbs/game_verbs.rb +0 -15
  62. data/game/verbs/metaverbs.rb +0 -2028
  63. data/lib/runtime/config.rb +0 -48
  64. data/lib/runtime/database.rb +0 -500
  65. data/lib/runtime/game.rb +0 -74
  66. data/lib/runtime/game_loader.rb +0 -132
  67. data/lib/runtime/library_loader.rb +0 -135
  68. data/lib/runtime/object.rb +0 -761
  69. data/lib/runtime/options.rb +0 -104
  70. data/lib/runtime/persistence.rb +0 -292
  71. data/lib/runtime/runtime.rb +0 -321
  72. data/lib/runtime/world_tree.rb +0 -69
  73. data/lib/runtime.rb +0 -35
@@ -0,0 +1,66 @@
1
+ # lib/story_teller/library/bootstrap.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: false
4
+
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
6
+ #
7
+ # This file is part of the StoryTeller.
8
+ #
9
+ # The StoryTeller is free software: you can redistribute it and/or
10
+ # modify it under the terms of the GNU General Public License as published
11
+ # by the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # The StoryTeller is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # The StoryTeller module
23
+ module StoryTeller
24
+ # The StoryTeller::Library module
25
+ module Library
26
+ # The StoryTeller::Library::Bootstrap module
27
+ module Bootstrap
28
+ module_function
29
+
30
+ def ensure_location(inflib)
31
+ return if inflib.nil?
32
+ return if inflib.location
33
+
34
+ player_obj = inflib.player
35
+ location = player_obj&.location
36
+ location ||= player_obj&.spawn_point if player_obj.respond_to?(:spawn_point)
37
+ inflib.instance_variable_set(:@location, location)
38
+ end
39
+
40
+ def set_selfobj(inflib, player)
41
+ inflib.selfobj = player unless player.nil?
42
+ end
43
+
44
+ # rubocop: disable Metrics/MethodLength
45
+ def manage_inform_library(player: nil, key: StoryTeller::Engine, &block)
46
+ inflib = StoryTeller::Engine.libraries[key]
47
+ unless inflib.nil? || player.nil?
48
+ set_selfobj(inflib, player)
49
+ return inflib
50
+ end
51
+
52
+ inflib = block_given? ? block.call : InformLibrary.new
53
+ return nil if inflib.nil?
54
+
55
+ set_selfobj(inflib, player)
56
+ inflib.subscribe(inflib.selfobj)
57
+ ensure_location(inflib)
58
+ StoryTeller::Engine.libraries[key] = inflib
59
+ end
60
+ # rubocop: enable Metrics/MethodLength
61
+ end
62
+ # module Bootstrap
63
+ end
64
+ # module Library
65
+ end
66
+ # module StoryTeller
@@ -0,0 +1,53 @@
1
+ # story/library/declarations.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: false
4
+
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
6
+ #
7
+ # This file is part of the StoryTeller.
8
+ #
9
+ # The StoryTeller is free software: you can redistribute it and/or
10
+ # modify it under the terms of the GNU General Public License as published
11
+ # by the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # The StoryTeller is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # The StoryTeller module
23
+ module StoryTeller
24
+ # The StoryTeller::Library module
25
+ module Library
26
+ # The StoryTeller::Library::Declarations class
27
+ class Declarations
28
+ attr_reader :properties, :attributes, :globals
29
+
30
+ def initialize
31
+ reset!
32
+ end
33
+
34
+ def reset!
35
+ @properties = Hash.new { |hash, key| hash[key] = [] }
36
+ @attributes = Set.new
37
+ @globals = []
38
+ end
39
+
40
+ def add_attribute(attribute)
41
+ @attributes << attribute
42
+ end
43
+
44
+ def add_property(property, value)
45
+ @properties[property] << value
46
+ end
47
+
48
+ def add_global(symbol)
49
+ @globals << symbol
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,91 @@
1
+ # story/library/directives.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: false
4
+
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
6
+ #
7
+ # This file is part of the StoryTeller.
8
+ #
9
+ # The StoryTeller is free software: you can redistribute it and/or
10
+ # modify it under the terms of the GNU General Public License as published
11
+ # by the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # The StoryTeller is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # The StoryTeller module
23
+ module StoryTeller
24
+ # The StoryTeller::Library module
25
+ module Library
26
+ # The StoryTeller::Library::Directives module
27
+ module Directives
28
+ InclusionGrammarGuessTemplate = '%<inclusion>s.h.inf.rb'.freeze
29
+ InclusionGuessesTemplate = '%<inclusion>s.h'.freeze
30
+ PropertyModifiers = %i[additive].freeze
31
+
32
+ module_function
33
+
34
+ def Link(link)
35
+ # TODO: Implement
36
+ # Not a high priority, because in the original Inform6 links were
37
+ # effectively just pointers to objects loaded in memory, and so
38
+ # were ephemeral in nature.
39
+ end
40
+
41
+ def Include(inclusion)
42
+ # warn "StoryTeller::Engine.Include(#{inclusion}) from #{caller_locations(1, 5).map { |l|
43
+ # "#{l.path}:#{l.lineno}"
44
+ # }.join(' | ')}"
45
+ inclusion = StoryTeller::Engine.language_name if /^language__$/.match(inclusion)
46
+ grammar_guess = format(InclusionGrammarGuessTemplate, inclusion: inclusion)
47
+ guess = File.expand_path(
48
+ File.join(
49
+ StoryTeller::Library.inform_gem_lib_path,
50
+ StoryTeller::Engine.inform_code_prefix,
51
+ grammar_guess))
52
+ return StoryTeller::Library::Loader.load_grammar_by_path(guess) if File.exist?(guess)
53
+ StoryTeller::Library::Loader.require_first_existing(
54
+ format(InclusionGuessesTemplate, inclusion: inclusion).split)
55
+ end
56
+
57
+ def Attribute(attribute)
58
+ StoryTeller::Library.declarations.add_attribute(attribute)
59
+ end
60
+
61
+ def Property(*args)
62
+ if PropertyModifiers.include?(modifier_or_property = args.shift)
63
+ StoryTeller::Library.declarations.add_property(args.shift, args.shift)
64
+ else
65
+ StoryTeller::Library.declarations.add_property(modifier_or_property, args.shift)
66
+ end
67
+ end
68
+
69
+ def Default(property, value)
70
+ Constant(property, value)
71
+ end
72
+
73
+ def Constant(constant, value, target = ::Object)
74
+ return if constant.nil?
75
+ silence_warnings do
76
+ target.instance_eval { const_set(constant.to_sym, value) }
77
+ end
78
+ rescue StandardError => e
79
+ log.error "Unexpected error resetting constant #{constant}", e
80
+ nil
81
+ end
82
+
83
+ def import_global(symbol)
84
+ StoryTeller::Library.declarations.add_global(symbol)
85
+ end
86
+ end
87
+ # module Directives
88
+ end
89
+ # module Library
90
+ end
91
+ # module StoryTeller
@@ -0,0 +1,104 @@
1
+ # lib/story_teller/library/loader.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: false
4
+
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
6
+ #
7
+ # This file is part of the StoryTeller.
8
+ #
9
+ # The StoryTeller is free software: you can redistribute it and/or
10
+ # modify it under the terms of the GNU General Public License as published
11
+ # by the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # The StoryTeller is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # The StoryTeller module
23
+ module StoryTeller
24
+ # The StoryTeller::Library module
25
+ module Library
26
+ GEM_NAME = 'inform6lib'.freeze
27
+ GEM_PATH = Gem.loaded_specs[GEM_NAME]&.full_gem_path or raise "The #{GEM_NAME} gem is required"
28
+
29
+ class LibraryLoadError < StandardError; end
30
+
31
+ # The Library::Loader module provides methods for loading Library files.
32
+ module Loader
33
+ module_function
34
+
35
+ def augment_inform_library!
36
+ ensure_inform_object_model!
37
+ InformLibrary.extend(StoryTeller::Engine::Library)
38
+ InformLibrary.class_eval do
39
+ include Inform::Context unless include?(Inform::Context)
40
+ include Inform::StdLib unless include?(Inform::StdLib)
41
+ end
42
+ InformLibrary.prepend(StoryTeller::Library::Location)
43
+ end
44
+
45
+ def load_library
46
+ augment_inform_library!
47
+ StoryTeller::Library::Bootstrap.manage_inform_library
48
+ end
49
+
50
+ def inform_object_model?
51
+ object_class = StoryTeller::ModelAdapter.object_class
52
+ return false if object_class.nil?
53
+
54
+ object_class.method_defined?(:<<) &&
55
+ object_class.method_defined?(:with)
56
+ end
57
+
58
+ def ensure_inform_object_model!
59
+ return if inform_object_model?
60
+
61
+ StoryTeller::EphemeralAdapter.register!
62
+ end
63
+
64
+ # rubocop: disable Metrics/AbcSize
65
+ # rubocop: disable Metrics/MethodLength
66
+ def require_first_existing(guesses)
67
+ guessed_file_path = File.join(StoryTeller::Engine.inform_code_prefix, guesses.shift)
68
+ guessed_local_file_path = File.expand_path(guessed_file_path)
69
+ if File.exist?(guessed_local_file_path)
70
+ log.debug "Loading local library file: #{guessed_local_file_path}"
71
+ require_relative guessed_local_file_path
72
+ else
73
+ log.debug "Loading library: #{guessed_file_path}"
74
+ require guessed_file_path
75
+ end
76
+ rescue StandardError => e
77
+ log.error e.message
78
+ e.backtrace.each { |t| log.warn t }
79
+ raise e
80
+ rescue LoadError => e
81
+ log.warn e.message
82
+ e.backtrace.each { |t| log.warn t }
83
+ retry unless guesses.empty?
84
+ end
85
+ # rubocop: enable Metrics/AbcSize
86
+ # rubocop: enable Metrics/MethodLength
87
+ def load_grammar(module_name)
88
+ Inform::Grammar.load_by_name(module_name)
89
+ end
90
+
91
+ def load_grammar_by_path(module_path)
92
+ Inform::Grammar.load_by_path(module_path)
93
+ end
94
+
95
+ def unload_grammars!
96
+ log.debug "Unloading all grammars"
97
+ Inform::Grammar::Verbs.clear
98
+ end
99
+ end
100
+ # module Loader
101
+ end
102
+ # module Library
103
+ end
104
+ # module StoryTeller
@@ -0,0 +1,73 @@
1
+ # lib/story_teller/library/location.rb
2
+ # encoding: utf-8
3
+ # frozen_string_literal: false
4
+
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
6
+ #
7
+ # This file is part of the StoryTeller.
8
+ #
9
+ # The StoryTeller is free software: you can redistribute it and/or
10
+ # modify it under the terms of the GNU General Public License as published
11
+ # by the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # The StoryTeller is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # module StoryTeller
23
+ module StoryTeller
24
+ # module Library
25
+ module Library
26
+ # module Location
27
+ module Location
28
+ def location
29
+ @player&.location
30
+ end
31
+
32
+ def location=(obj)
33
+ @player.location = obj
34
+ end
35
+ end
36
+
37
+ # module LocationInstaller
38
+ module LocationInstaller
39
+ module_function
40
+
41
+ def install!
42
+ return false unless defined?(InformLibrary)
43
+ return false if InformLibrary < StoryTeller::Library::Location
44
+
45
+ InformLibrary.prepend(StoryTeller::Library::Location)
46
+ true
47
+ end
48
+ end
49
+
50
+ # module LocationTracePoint
51
+ module LocationTracePoint
52
+ module_function
53
+
54
+ def install_or_defer!
55
+ return true if StoryTeller::Library::LocationInstaller.install!
56
+ return false if defined?(@trace_point) && @trace_point&.enabled?
57
+
58
+ @trace_point = TracePoint.new(:class) do |_tp|
59
+ next unless defined?(InformLibrary)
60
+ next unless StoryTeller::Library::LocationInstaller.install!
61
+
62
+ @trace_point.disable
63
+ @trace_point = nil
64
+ end
65
+
66
+ @trace_point.enable
67
+ false
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ StoryTeller::Library::LocationTracePoint.install_or_defer!
@@ -1,31 +1,46 @@
1
+ # lib/story_teller/library.rb
1
2
  # encoding: utf-8
2
3
  # frozen_string_literal: false
3
4
 
4
- # Copyright Nels Nelson 2008-2023 but freely usable (see license)
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
6
  #
6
- # This file is part of the Inform Runtime.
7
+ # This file is part of the StoryTeller.
7
8
  #
8
- # The Inform Runtime is free software: you can redistribute it and/or
9
+ # The StoryTeller is free software: you can redistribute it and/or
9
10
  # modify it under the terms of the GNU General Public License as published
10
11
  # by the Free Software Foundation, either version 3 of the License, or
11
12
  # (at your option) any later version.
12
13
  #
13
- # The Inform Runtime is distributed in the hope that it will be useful,
14
+ # The StoryTeller is distributed in the hope that it will be useful,
14
15
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
16
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
17
  # GNU General Public License for more details.
17
18
  #
18
19
  # You should have received a copy of the GNU General Public License
19
- # along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
20
+ # along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
20
21
 
21
- require_relative 'library_loader'
22
+ require_relative 'library/bootstrap'
23
+ require_relative 'library/declarations'
24
+ require_relative 'library/directives'
25
+ require_relative 'library/loader'
26
+ require_relative 'library/location'
22
27
 
23
- # The Inform module
24
- module Inform
28
+ # The StoryTeller module
29
+ module StoryTeller
25
30
  # The Library module
26
31
  module Library
27
32
  @methods_index = []
28
33
 
34
+ def inform_gem_lib_path
35
+ @inform_gem_lib_path ||= File.expand_path(File.join(StoryTeller::Library::GEM_PATH, 'lib'))
36
+ end
37
+ module_function :inform_gem_lib_path
38
+
39
+ def declarations
40
+ @declarations ||= Declarations.new
41
+ end
42
+ module_function :declarations
43
+
29
44
  def methods_index
30
45
  return @methods_index unless @methods_index.empty?
31
46
  load_library_methods
@@ -39,9 +54,9 @@ module Inform
39
54
  # rubocop: disable Metrics/MethodLength
40
55
  def load_library_methods
41
56
  library_methods = Set.new
42
- library_methods.merge(StdLib.instance_methods(false))
43
- library_methods.merge(Inform::IO.instance_methods(false))
44
- library_methods.merge(Inform.instance_methods(false))
57
+ library_methods.merge(Inform::StdLib.instance_methods(false))
58
+ library_methods.merge(StoryTeller::IO.instance_methods(false))
59
+ library_methods.merge(StoryTeller.instance_methods(false))
45
60
  library_methods.merge(InformLibrary.instance_methods(false))
46
61
  Inform.included_modules.each do |mod|
47
62
  library_methods.merge(mod.instance_methods(false))
@@ -50,7 +65,7 @@ module Inform
50
65
  library_methods.merge(mod.instance_methods(false))
51
66
  end
52
67
  @methods_index.concat(library_methods.to_a).sort
53
- log.debug "Loaded library methods: #{@methods_index}"
68
+ log.trace "Loaded library methods: #{@methods_index}"
54
69
  end
55
70
  # rubocop: enable Metrics/AbcSize
56
71
  # rubocop: enable Metrics/MethodLength
@@ -1,22 +1,23 @@
1
+ # lib/story_teller/logging.rb
1
2
  # encoding: utf-8
2
3
  # frozen_string_literal: false
3
4
 
4
- # Copyright Nels Nelson 2008-2023 but freely usable (see license)
5
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
6
  #
6
- # This file is part of the Inform Runtime.
7
+ # This file is part of StoryTeller.
7
8
  #
8
- # The Inform Runtime is free software: you can redistribute it and/or
9
+ # StoryTeller is free software: you can redistribute it and/or
9
10
  # modify it under the terms of the GNU General Public License as published
10
11
  # by the Free Software Foundation, either version 3 of the License, or
11
12
  # (at your option) any later version.
12
13
  #
13
- # The Inform Runtime is distributed in the hope that it will be useful,
14
+ # StoryTeller is distributed in the hope that it will be useful,
14
15
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
16
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
17
  # GNU General Public License for more details.
17
18
  #
18
19
  # You should have received a copy of the GNU General Public License
19
- # along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
20
+ # along with StoryTeller. If not, see <http://www.gnu.org/licenses/>.
20
21
 
21
22
  require 'fileutils'
22
23
  require 'logger'
@@ -82,15 +83,26 @@ end
82
83
  # implicit backtrace printing
83
84
  # TODO: Figure out if this is actually useful.
84
85
  class Logger
86
+ TRACE = DEBUG - 1 unless const_defined?(:TRACE)
87
+
85
88
  include LoggerHelpers
86
89
 
87
90
  alias original_error error
91
+
88
92
  def error(error_or_message, error = nil)
89
93
  warn error_or_message
90
94
  return extract_backtrace(error_or_message) if error.nil?
91
95
  original_error(generate_message(error_or_message, error))
92
96
  extract_backtrace(original_error(error))
93
97
  end
98
+
99
+ def trace(progname = nil, &block)
100
+ add(TRACE, nil, progname, &block)
101
+ end
102
+
103
+ def trace?
104
+ @level <= TRACE
105
+ end
94
106
  end
95
107
 
96
108
  # The Logging module
@@ -100,6 +112,18 @@ module Logging
100
112
  java_import Java::org.apache.logging.log4j.LogManager
101
113
  end
102
114
 
115
+ RubyLogLevels = {
116
+ all: -Float::INFINITY,
117
+ trace: Logger::TRACE,
118
+ debug: Logger::DEBUG,
119
+ info: Logger::INFO,
120
+ warn: Logger::WARN,
121
+ error: Logger::ERROR,
122
+ fatal: Logger::FATAL,
123
+ unknown: Logger::UNKNOWN,
124
+ off: Logger::UNKNOWN + 1
125
+ }.freeze
126
+
103
127
  def init_logger(level = :info, logger_name = nil)
104
128
  return init_java_logger(level, logger_name, caller[2]) if defined?(Java)
105
129
  init_ruby_logger(level, logger_name, caller[2])
@@ -118,7 +142,7 @@ module Logging
118
142
  logger_name = get_formatted_logger_name(logger_name)
119
143
  logger_name = source_location.split(ForwardSlashPattern).last if logger_name.empty?
120
144
  log = Logger.new($stdout, progname: logger_name)
121
- log.level = level.to_s unless level.nil?
145
+ log.level = normalize_ruby_log_level(level) unless level.nil?
122
146
  log.formatter = method(:ruby_log_formatter)
123
147
  log
124
148
  end
@@ -131,6 +155,14 @@ module Logging
131
155
  log
132
156
  end
133
157
 
158
+ def normalize_ruby_log_level(level)
159
+ return level if level.is_a?(Integer)
160
+
161
+ RubyLogLevels.fetch(level.to_sym) do
162
+ raise ArgumentError, "Unknown Ruby log level: #{level.inspect}"
163
+ end
164
+ end
165
+
134
166
  def get_formatted_logger_name(logger_name = nil)
135
167
  return logger_name.to_s[/\w+$/] unless logger_name.nil?
136
168
  return name[/\w+$/] if is_a?(Class) || is_a?(Module)
@@ -162,7 +194,10 @@ module Logging
162
194
  # rubocop: enable Metrics/CyclomaticComplexity
163
195
 
164
196
  def log_level=(level)
165
- Logging.config[:level] = symbolize_numeric_log_level(level)
197
+ raise "Parameter level may not be nil" if level.nil?
198
+ normalized_level = symbolize_numeric_log_level(level)
199
+
200
+ Logging.config[:level] = normalized_level
166
201
  end
167
202
  module_function :log_level=
168
203
 
@@ -178,20 +213,8 @@ module Logging
178
213
  end
179
214
  # module Logging
180
215
 
181
- # The Module class
182
- class Module
183
- # Universally include Logging
184
- include ::Logging
185
- end
186
-
187
- # The Class class
188
- class Class
189
- # Universally include Logging
190
- include ::Logging
191
- end
192
-
193
- # The Object class
194
- class Object
195
- # Universally include Logging
196
- include ::Logging
197
- end
216
+ # Make logging universally available
217
+ # Yeah, yeah, I know this is a "bad idea". Too bad.
218
+ # Logging should be a universal runtime facility, period.
219
+ # The fact that it isn't is an absurdity to me.
220
+ Object.include(Logging)
@@ -1,22 +1,22 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: false
3
3
 
4
- # Copyright Nels Nelson 2008-2023 but freely usable (see license)
4
+ # Copyright Nels Nelson 2008-2025 but freely usable (see license)
5
5
  #
6
- # This file is part of the Inform Runtime.
6
+ # This file is part of StoryTeller.
7
7
  #
8
- # The Inform Runtime is free software: you can redistribute it and/or
8
+ # StoryTeller is free software: you can redistribute it and/or
9
9
  # modify it under the terms of the GNU General Public License as published
10
10
  # by the Free Software Foundation, either version 3 of the License, or
11
11
  # (at your option) any later version.
12
12
  #
13
- # The Inform Runtime is distributed in the hope that it will be useful,
13
+ # StoryTeller is distributed in the hope that it will be useful,
14
14
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
15
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
16
  # GNU General Public License for more details.
17
17
  #
18
18
  # You should have received a copy of the GNU General Public License
19
- # along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
19
+ # along with StoryTeller. If not, see <http://www.gnu.org/licenses/>.
20
20
 
21
21
 
22
22
  JoinedTemplate = '%<str>s%<other>s'.freeze
@@ -501,7 +501,7 @@ class Array
501
501
  def to_s(separator = CommaSpaceString)
502
502
  # This will make it possible to print Lists nicely, but not screw up
503
503
  # the behavior of the List.
504
- map(&:to_s).join(separator)
504
+ self.join(separator)
505
505
  end
506
506
 
507
507
  alias random sample