inform-runtime 1.2.2 → 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.
- checksums.yaml +4 -4
- data/README.md +33 -41
- data/lib/story_teller/articles.rb +2 -1
- data/lib/story_teller/builtins.rb +63 -10
- data/lib/story_teller/color.rb +2 -1
- data/lib/story_teller/command.rb +4 -1
- data/lib/story_teller/context.rb +23 -27
- data/lib/story_teller/daemon.rb +2 -2
- data/lib/story_teller/engine.rb +80 -16
- data/lib/story_teller/events.rb +9 -2
- data/lib/story_teller/experimental/handler_dsl.rb +1 -16
- data/lib/story_teller/experimental/reverse_engineer_class.rb +1 -1
- data/lib/story_teller/grammar_parser.rb +60 -13
- data/lib/story_teller/helpers.rb +8 -18
- data/lib/story_teller/history.rb +2 -1
- data/lib/story_teller/inflector.rb +4 -2
- data/lib/story_teller/inform/ephemeral/link.rb +63 -31
- data/lib/story_teller/inform/ephemeral/module.rb +6 -5
- data/lib/story_teller/inform/ephemeral/object.rb +223 -236
- data/lib/story_teller/inform/ephemeral/tag.rb +27 -14
- data/lib/story_teller/io.rb +99 -49
- data/lib/story_teller/kernel.rb +13 -5
- data/lib/story_teller/library/bootstrap.rb +10 -27
- data/lib/story_teller/library/declarations.rb +1 -1
- data/lib/story_teller/library/directives.rb +1 -1
- data/lib/story_teller/library/loader.rb +4 -20
- data/lib/story_teller/library/location.rb +9 -3
- data/lib/story_teller/library.rb +1 -1
- data/lib/story_teller/logging.rb +165 -67
- data/lib/story_teller/mixins.rb +11 -4
- data/lib/story_teller/plurals.rb +2 -1
- data/lib/story_teller/privileges.rb +117 -0
- data/lib/story_teller/prototype.rb +158 -32
- data/lib/story_teller/publication.rb +2 -1
- data/lib/story_teller/session.rb +115 -25
- data/lib/story_teller/stdlib.rb +232 -2
- data/lib/story_teller/subscription.rb +2 -1
- data/lib/story_teller/tree.rb +2 -1
- data/lib/story_teller/version.rb +2 -2
- data/lib/story_teller/world_tree.rb +21 -23
- data/lib/story_teller.rb +18 -5
- metadata +7 -10
- data/lib/story_teller/core.rb +0 -38
- data/lib/story_teller/ephemeral_adapter.rb +0 -40
- data/lib/story_teller/inform/base.rb +0 -160
- data/lib/story_teller/model_adapter.rb +0 -132
data/lib/story_teller/io.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
# lib/story_teller/io.rb
|
|
1
2
|
# encoding: utf-8
|
|
2
3
|
# frozen_string_literal: false
|
|
3
4
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2026 but freely usable (see license)
|
|
5
6
|
#
|
|
6
7
|
# This file is part of the StoryTeller.
|
|
7
8
|
#
|
|
@@ -23,8 +24,10 @@ module StoryTeller
|
|
|
23
24
|
# The IO module
|
|
24
25
|
module IO
|
|
25
26
|
def session
|
|
26
|
-
return
|
|
27
|
-
|
|
27
|
+
return @session if defined?(@session) && !@session.nil?
|
|
28
|
+
return nil unless defined?(StoryTeller::IO::Session)
|
|
29
|
+
|
|
30
|
+
StoryTeller::IO::Session.of(self)
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
def noop; end
|
|
@@ -98,76 +101,123 @@ module StoryTeller
|
|
|
98
101
|
out(@prompt = s || "\n>")
|
|
99
102
|
end
|
|
100
103
|
|
|
104
|
+
def preference_value(key)
|
|
105
|
+
prefs = session.preferences
|
|
106
|
+
|
|
107
|
+
return prefs.public_send(key) if prefs.respond_to?(key)
|
|
108
|
+
return prefs[key] if prefs.respond_to?(:[]) && prefs.key?(key)
|
|
109
|
+
return prefs[key.to_s] if prefs.respond_to?(:[]) && prefs.key?(key.to_s)
|
|
110
|
+
|
|
111
|
+
nil
|
|
112
|
+
end
|
|
113
|
+
|
|
101
114
|
# ----------------------------------------------------------------------------
|
|
102
115
|
# Adapted from the C code for ls. :-)
|
|
103
116
|
# ----------------------------------------------------------------------------
|
|
104
117
|
|
|
105
118
|
ItemPaddingString = '%<item>s%<padding>s'.freeze
|
|
119
|
+
DefaultLineLength = 30
|
|
106
120
|
MinimumLineLength = 30
|
|
107
121
|
MinimumCellPadding = 8
|
|
108
122
|
MinimumColumnPadding = 2
|
|
109
123
|
|
|
124
|
+
def preferred_line_length
|
|
125
|
+
width = preference_value(:word_wrap).to_i
|
|
126
|
+
return width if width > MinimumLineLength
|
|
127
|
+
|
|
128
|
+
DefaultLineLength
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# def many_per_line(items)
|
|
132
|
+
# max = 0
|
|
133
|
+
|
|
134
|
+
# lines = []
|
|
135
|
+
# prefs = @player.linkto :preferences
|
|
136
|
+
# line_length = preferred_line_length
|
|
137
|
+
# buffer = ''
|
|
138
|
+
|
|
139
|
+
# items.each do |item|
|
|
140
|
+
# max = [item.length, max].max
|
|
141
|
+
# end
|
|
142
|
+
# max += MinimumColumnPadding
|
|
143
|
+
# width = (line_length - MinimumCellPadding) / max
|
|
144
|
+
# height = (items.length / width).ceil - 1
|
|
145
|
+
|
|
146
|
+
# return if width == 0
|
|
147
|
+
|
|
148
|
+
# columns = []
|
|
149
|
+
# i = 0
|
|
150
|
+
# loop do
|
|
151
|
+
# # Build a list of columns with nil padding
|
|
152
|
+
# column = items[i, height]
|
|
153
|
+
# columns << column + Array.new(height - column.length)
|
|
154
|
+
# i += height
|
|
155
|
+
# break if (i + height) >= (items.length + height)
|
|
156
|
+
# end
|
|
157
|
+
|
|
158
|
+
# m = []
|
|
159
|
+
# loop do
|
|
160
|
+
# m << []
|
|
161
|
+
# for column in columns
|
|
162
|
+
# m.last << column.shift
|
|
163
|
+
# end
|
|
164
|
+
# break if columns.last.empty?
|
|
165
|
+
# end
|
|
166
|
+
|
|
167
|
+
# m.each do |row|
|
|
168
|
+
# buffer = "\e[51m"
|
|
169
|
+
# row.each do |item|
|
|
170
|
+
# next unless item
|
|
171
|
+
# n = [max - item.length, MinimumColumnPadding].max
|
|
172
|
+
# padding = " " * n unless item == row.last
|
|
173
|
+
# buffer += format(ItemPaddingString, item: item, padding: padding)
|
|
174
|
+
# end
|
|
175
|
+
# buffer += "\e[56m"
|
|
176
|
+
# lines << buffer.strip
|
|
177
|
+
# buffer = ''
|
|
178
|
+
# end
|
|
179
|
+
|
|
180
|
+
# lines
|
|
181
|
+
# end
|
|
182
|
+
# # def many_per_line
|
|
183
|
+
|
|
110
184
|
# rubocop: disable Metrics/AbcSize
|
|
111
185
|
# rubocop: disable Metrics/CyclomaticComplexity
|
|
112
186
|
# rubocop: disable Metrics/MethodLength
|
|
113
|
-
# rubocop: disable Metrics/PerceivedComplexity
|
|
114
187
|
def many_per_line(items)
|
|
115
|
-
|
|
188
|
+
items = items.map(&:to_s)
|
|
189
|
+
return [] if items.empty?
|
|
116
190
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
line_length = MinimumLineLength if line_length <= MinimumLineLength
|
|
121
|
-
buffer = ''
|
|
191
|
+
line_length = preferred_line_length
|
|
192
|
+
max_item_length = items.map(&:length).max || 0
|
|
193
|
+
cell_width = max_item_length + MinimumColumnPadding
|
|
122
194
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
max += MinimumColumnPadding
|
|
127
|
-
width = (line_length - MinimumCellPadding) / max
|
|
128
|
-
height = (items.length / width).ceil - 1
|
|
129
|
-
|
|
130
|
-
return if width == 0
|
|
131
|
-
|
|
132
|
-
columns = []
|
|
133
|
-
i = 0
|
|
134
|
-
loop do
|
|
135
|
-
# Build a list of columns with nil padding
|
|
136
|
-
column = items[i, height]
|
|
137
|
-
columns << column + Array.new(height - column.length)
|
|
138
|
-
i += height
|
|
139
|
-
break if (i + height) >= (items.length + height)
|
|
140
|
-
end
|
|
195
|
+
column_count = (line_length - MinimumCellPadding) / cell_width
|
|
196
|
+
column_count = 1 if column_count < 1
|
|
197
|
+
column_count = items.length if column_count > items.length
|
|
141
198
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
end
|
|
148
|
-
break if columns.last.empty?
|
|
149
|
-
end
|
|
199
|
+
row_count = (items.length.to_f / column_count).ceil
|
|
200
|
+
rows = []
|
|
201
|
+
|
|
202
|
+
row_count.times do |row_index|
|
|
203
|
+
row = []
|
|
150
204
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
next
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
buffer += format(ItemPaddingString, item: item, padding: padding)
|
|
205
|
+
column_count.times do |column_index|
|
|
206
|
+
item_index = row_index + (column_index * row_count)
|
|
207
|
+
item = items[item_index]
|
|
208
|
+
next if item.nil?
|
|
209
|
+
|
|
210
|
+
row << item.ljust(cell_width)
|
|
158
211
|
end
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
buffer = ''
|
|
212
|
+
|
|
213
|
+
rows << row.join.rstrip
|
|
162
214
|
end
|
|
163
215
|
|
|
164
|
-
|
|
216
|
+
rows
|
|
165
217
|
end
|
|
166
218
|
# rubocop: enable Metrics/AbcSize
|
|
167
219
|
# rubocop: enable Metrics/CyclomaticComplexity
|
|
168
220
|
# rubocop: enable Metrics/MethodLength
|
|
169
|
-
# rubocop: enable Metrics/PerceivedComplexity
|
|
170
|
-
# def many_per_line
|
|
171
221
|
end
|
|
172
222
|
# module IO
|
|
173
223
|
end
|
data/lib/story_teller/kernel.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
# frozen_string_literal: false
|
|
4
4
|
|
|
5
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2026 but freely usable (see license)
|
|
6
6
|
#
|
|
7
7
|
# This file is part of StoryTeller.
|
|
8
8
|
#
|
|
@@ -176,17 +176,23 @@ module Kernel
|
|
|
176
176
|
|
|
177
177
|
raise MethodAlreadyDefined, :class_loader if respond_to?(:class_loader)
|
|
178
178
|
def class_loader
|
|
179
|
-
JRuby.runtime.jruby_class_loader
|
|
179
|
+
return JRuby.runtime.jruby_class_loader if defined?(JRuby)
|
|
180
|
+
|
|
181
|
+
raise NotImplementedError, "class_loader is only available on JRuby"
|
|
180
182
|
end
|
|
181
183
|
|
|
182
184
|
raise MethodAlreadyDefined, :load_service if respond_to?(:load_service)
|
|
183
185
|
def load_service
|
|
184
|
-
JRuby.runtime.load_service
|
|
186
|
+
return JRuby.runtime.load_service if defined?(JRuby)
|
|
187
|
+
|
|
188
|
+
raise NotImplementedError, "load_service is only available on JRuby"
|
|
185
189
|
end
|
|
186
190
|
|
|
187
191
|
raise MethodAlreadyDefined, :object_space if respond_to?(:object_space)
|
|
188
192
|
def object_space
|
|
189
|
-
JRuby.runtime.object_space
|
|
193
|
+
return JRuby.runtime.object_space if defined?(JRuby)
|
|
194
|
+
|
|
195
|
+
raise NotImplementedError, "object_space is only available on JRuby"
|
|
190
196
|
end
|
|
191
197
|
|
|
192
198
|
JavaPattern = %r{java}.freeze
|
|
@@ -205,6 +211,8 @@ module Kernel
|
|
|
205
211
|
raise MethodAlreadyDefined, :collect_garbage if respond_to?(:collect_garbage)
|
|
206
212
|
# rubocop: disable Metrics/AbcSize
|
|
207
213
|
def collect_garbage
|
|
214
|
+
return unless java?
|
|
215
|
+
|
|
208
216
|
java.lang.System.gc()
|
|
209
217
|
sleep 0.1
|
|
210
218
|
java.lang.System.runFinalization()
|
|
@@ -338,7 +346,7 @@ remove_method :original_rand
|
|
|
338
346
|
return 0 if obj.nil?
|
|
339
347
|
obj.refresh if obj.respond_to?(:refresh)
|
|
340
348
|
if defined? db
|
|
341
|
-
return db.run('SELECT count(id) from "object" where parent_id = ' + obj.id) unless
|
|
349
|
+
return db.run('SELECT count(id) from "object" where parent_id = ' + obj.id) unless ephemeral?
|
|
342
350
|
end
|
|
343
351
|
return obj.instance_variable_get(prop).length if obj.instance_variable_defined?(prop)
|
|
344
352
|
return unless obj.respond_to?(:children)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
# frozen_string_literal: false
|
|
4
4
|
|
|
5
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2026 but freely usable (see license)
|
|
6
6
|
#
|
|
7
7
|
# This file is part of the StoryTeller.
|
|
8
8
|
#
|
|
@@ -27,37 +27,20 @@ module StoryTeller
|
|
|
27
27
|
module Bootstrap
|
|
28
28
|
module_function
|
|
29
29
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
return
|
|
30
|
+
def manage_inform_library(player: nil)
|
|
31
|
+
existing = StoryTeller::Engine.libraries[player] unless player.nil?
|
|
32
|
+
return existing unless existing.nil?
|
|
33
33
|
|
|
34
|
-
|
|
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)
|
|
34
|
+
new_inform_library(player:)
|
|
38
35
|
end
|
|
39
36
|
|
|
40
|
-
def
|
|
41
|
-
inflib
|
|
42
|
-
|
|
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)
|
|
37
|
+
def new_inform_library(player: nil)
|
|
38
|
+
inflib = InformLibrary.new
|
|
39
|
+
bind_inform_library(inflib, player)
|
|
56
40
|
inflib.subscribe(inflib.selfobj)
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
ensure_player_location(inflib) if StoryTeller::Engine.persist_player_location?
|
|
42
|
+
inflib
|
|
59
43
|
end
|
|
60
|
-
# rubocop: enable Metrics/MethodLength
|
|
61
44
|
end
|
|
62
45
|
# module Bootstrap
|
|
63
46
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
# frozen_string_literal: false
|
|
4
4
|
|
|
5
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2026 but freely usable (see license)
|
|
6
6
|
#
|
|
7
7
|
# This file is part of the StoryTeller.
|
|
8
8
|
#
|
|
@@ -33,32 +33,18 @@ module StoryTeller
|
|
|
33
33
|
module_function
|
|
34
34
|
|
|
35
35
|
def augment_inform_library!
|
|
36
|
-
ensure_inform_object_model!
|
|
37
36
|
InformLibrary.extend(StoryTeller::Engine::Library)
|
|
38
37
|
InformLibrary.class_eval do
|
|
39
38
|
include Inform::Context unless include?(Inform::Context)
|
|
40
39
|
include Inform::StdLib unless include?(Inform::StdLib)
|
|
40
|
+
include Inform::Rules unless include?(Inform::Rules)
|
|
41
|
+
include Inform::History unless include?(Inform::History)
|
|
41
42
|
end
|
|
42
43
|
InformLibrary.prepend(StoryTeller::Library::Location)
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def load_library
|
|
46
47
|
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
48
|
end
|
|
63
49
|
|
|
64
50
|
# rubocop: disable Metrics/AbcSize
|
|
@@ -84,6 +70,7 @@ module StoryTeller
|
|
|
84
70
|
end
|
|
85
71
|
# rubocop: enable Metrics/AbcSize
|
|
86
72
|
# rubocop: enable Metrics/MethodLength
|
|
73
|
+
|
|
87
74
|
def load_grammar(module_name)
|
|
88
75
|
Inform::Grammar.load_by_name(module_name)
|
|
89
76
|
end
|
|
@@ -97,8 +84,5 @@ module StoryTeller
|
|
|
97
84
|
Inform::Grammar::Verbs.clear
|
|
98
85
|
end
|
|
99
86
|
end
|
|
100
|
-
# module Loader
|
|
101
87
|
end
|
|
102
|
-
# module Library
|
|
103
88
|
end
|
|
104
|
-
# module StoryTeller
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
# frozen_string_literal: false
|
|
4
4
|
|
|
5
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2026 but freely usable (see license)
|
|
6
6
|
#
|
|
7
7
|
# This file is part of the StoryTeller.
|
|
8
8
|
#
|
|
@@ -26,11 +26,17 @@ module StoryTeller
|
|
|
26
26
|
# module Location
|
|
27
27
|
module Location
|
|
28
28
|
def location
|
|
29
|
-
@
|
|
29
|
+
return @location unless StoryTeller::Engine.persist_player_location?
|
|
30
|
+
|
|
31
|
+
@player&.location || @location
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def location=(obj)
|
|
33
|
-
|
|
35
|
+
if StoryTeller::Engine.persist_player_location?
|
|
36
|
+
@player.location = obj
|
|
37
|
+
else
|
|
38
|
+
@location = obj
|
|
39
|
+
end
|
|
34
40
|
end
|
|
35
41
|
end
|
|
36
42
|
|
data/lib/story_teller/library.rb
CHANGED