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.
- checksums.yaml +4 -4
- data/README.md +10 -12
- data/Rakefile +26 -16
- data/lib/{runtime → story_teller}/articles.rb +14 -10
- data/lib/{runtime → story_teller}/builtins.rb +50 -22
- data/lib/{runtime → story_teller}/color.rb +8 -8
- data/lib/{runtime → story_teller}/command.rb +26 -28
- data/lib/{runtime → story_teller}/context.rb +23 -24
- data/lib/story_teller/core.rb +38 -0
- data/lib/{runtime → story_teller}/daemon.rb +35 -36
- data/lib/story_teller/engine.rb +151 -0
- data/lib/story_teller/ephemeral_adapter.rb +42 -0
- data/lib/{runtime → story_teller}/events.rb +8 -9
- data/lib/{runtime → story_teller}/experimental/handler_dsl.rb +7 -18
- data/lib/story_teller/experimental/reverse_engineer_class.rb +37 -0
- data/lib/{runtime → story_teller}/grammar_parser.rb +24 -40
- data/lib/{runtime → story_teller}/helpers.rb +21 -7
- data/lib/{runtime → story_teller}/history.rb +5 -5
- data/lib/{runtime → story_teller}/inflector.rb +4 -5
- data/lib/story_teller/inform/base.rb +160 -0
- data/lib/{runtime → story_teller/inform/ephemeral}/link.rb +27 -45
- data/lib/{runtime → story_teller/inform/ephemeral}/module.rb +17 -58
- data/lib/story_teller/inform/ephemeral/object.rb +329 -0
- data/lib/{runtime → story_teller/inform/ephemeral}/tag.rb +54 -81
- data/lib/story_teller/inform/models.rb +25 -0
- data/lib/{runtime → story_teller}/io.rb +10 -10
- data/lib/{runtime → story_teller}/kernel.rb +21 -31
- data/lib/story_teller/library/bootstrap.rb +66 -0
- data/lib/story_teller/library/declarations.rb +53 -0
- data/lib/story_teller/library/directives.rb +91 -0
- data/lib/story_teller/library/loader.rb +104 -0
- data/lib/story_teller/library/location.rb +73 -0
- data/lib/{runtime → story_teller}/library.rb +27 -12
- data/lib/{runtime → story_teller}/logging.rb +47 -24
- data/lib/{runtime → story_teller}/mixins.rb +6 -6
- data/lib/story_teller/model_adapter.rb +132 -0
- data/lib/{runtime → story_teller}/plurals.rb +11 -11
- data/lib/{runtime → story_teller}/prototype.rb +11 -10
- data/lib/{runtime → story_teller}/publication.rb +9 -9
- data/lib/{runtime → story_teller}/session.rb +6 -8
- data/lib/{runtime → story_teller}/stdlib.rb +13 -11
- data/lib/{runtime → story_teller}/subscription.rb +8 -8
- data/lib/{runtime → story_teller}/tree.rb +6 -6
- data/lib/{runtime → story_teller}/version.rb +16 -6
- data/lib/story_teller/world_tree.rb +54 -0
- data/lib/story_teller.rb +26 -0
- metadata +59 -99
- data/config/database.yml +0 -37
- data/exe/inform.rb +0 -6
- data/game/config.yml +0 -5
- data/game/example.inf +0 -76
- data/game/example.rb +0 -90
- data/game/forms/example_form.rb +0 -2
- data/game/grammar/game_grammar.inf.rb +0 -11
- data/game/languages/english.rb +0 -2
- data/game/models/example_model.rb +0 -2
- data/game/modules/example_module.rb +0 -9
- data/game/rules/example_state.rb +0 -2
- data/game/scripts/example_script.rb +0 -2
- data/game/topics/example_topic.rb +0 -2
- data/game/verbs/game_verbs.rb +0 -15
- data/game/verbs/metaverbs.rb +0 -2028
- data/lib/runtime/config.rb +0 -48
- data/lib/runtime/database.rb +0 -500
- data/lib/runtime/game.rb +0 -74
- data/lib/runtime/game_loader.rb +0 -132
- data/lib/runtime/library_loader.rb +0 -135
- data/lib/runtime/object.rb +0 -761
- data/lib/runtime/options.rb +0 -104
- data/lib/runtime/persistence.rb +0 -292
- data/lib/runtime/runtime.rb +0 -321
- data/lib/runtime/world_tree.rb +0 -69
- data/lib/runtime.rb +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c3f645b1ace31cbe26dc29da531a3d40392d107bcc22d0445f3354382774605
|
|
4
|
+
data.tar.gz: 3f88a923448fae1599fcf6f19b2ba5a143dfdcb807f495009ab4b80f9bb4fe07
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d35daf14d931f42c4a2ddec69e36c001cbcac7a7b305cca83b07d10f0a19f3c6fb7aa01625104365c3576ab3cf6168454e3babc57e097278b2a44b1b9523dfc0
|
|
7
|
+
data.tar.gz: 4a2e28628ca4b4bb609c5393cf07937d3efd9fd9555562e913fef541629e0eb09e1113ff4ebc6e70bcbeff5dcfff24f96cc5510a87fb18530ad6daa488613afd
|
data/README.md
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# StoryTeller
|
|
2
2
|
|
|
3
3
|
[](license-gpl)
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
**
|
|
8
|
-
|
|
9
|
-
[Inform 6 Ruby Port].
|
|
7
|
+
**StoryTeller** is a runtime layer for use by software programs used to
|
|
8
|
+
play interactive-fiction games which are built for the [Inform 6 Ruby Port].
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
like frotz.
|
|
10
|
+
StoryTeller is intended to simply provide the barest minimum facilities
|
|
11
|
+
required by the Inform 6 Library Ruby Port software to function in the
|
|
12
|
+
context of a game play specified by a game directory or file. It does not
|
|
13
|
+
attempt to replicate a byte code interpreter runtime like frotz.
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
## Install mise-en-place
|
|
@@ -100,7 +98,7 @@ Here is a bird's-eye view of the project layout.
|
|
|
100
98
|
|
|
101
99
|
```sh
|
|
102
100
|
# date && tree -A -I "game|logs|vendor|tmp|Gemfile.lock"
|
|
103
|
-
|
|
101
|
+
Sat Dec 13 22:05:24 CST 2025
|
|
104
102
|
.
|
|
105
103
|
├── config
|
|
106
104
|
│ └── database.yml
|
|
@@ -108,7 +106,6 @@ Tue Oct 14 19:01:27 CDT 2025
|
|
|
108
106
|
├── exe
|
|
109
107
|
│ └── inform.rb
|
|
110
108
|
├── Gemfile
|
|
111
|
-
├── inform-runtime-1.0.3.gem
|
|
112
109
|
├── inform-runtime.gemspec
|
|
113
110
|
├── lib
|
|
114
111
|
│ ├── runtime
|
|
@@ -145,6 +142,7 @@ Tue Oct 14 19:01:27 CDT 2025
|
|
|
145
142
|
│ │ ├── publication.rb
|
|
146
143
|
│ │ ├── runtime.rb
|
|
147
144
|
│ │ ├── session.rb
|
|
145
|
+
│ │ ├── snapshots.rb
|
|
148
146
|
│ │ ├── stdlib.rb
|
|
149
147
|
│ │ ├── subscription.rb
|
|
150
148
|
│ │ ├── tag.rb
|
|
@@ -178,7 +176,7 @@ Tue Oct 14 19:01:27 CDT 2025
|
|
|
178
176
|
|
|
179
177
|
Thanks!
|
|
180
178
|
|
|
181
|
-
[Inform 6 Ruby Port]: https://gitlab.com/nelsnelson/
|
|
179
|
+
[Inform 6 Ruby Port]: https://gitlab.com/nelsnelson/inform6lib-ruby
|
|
182
180
|
[license-gpl]: https://gitlab.com/nelsnelson/inform6/blob/master/LICENSE
|
|
183
181
|
[mise]: https://mise.jdx.dev/
|
|
184
182
|
[PostgreSQL]: https://postgresql.org/download
|
data/Rakefile
CHANGED
|
@@ -4,23 +4,43 @@
|
|
|
4
4
|
# -*- mode: ruby -*-
|
|
5
5
|
# vi: set ft=ruby :
|
|
6
6
|
|
|
7
|
+
require 'fileutils'
|
|
7
8
|
require 'rake'
|
|
8
9
|
require 'rake/clean'
|
|
10
|
+
require 'shellwords'
|
|
9
11
|
|
|
10
|
-
unless defined?(
|
|
11
|
-
# Ensure
|
|
12
|
-
module
|
|
13
|
-
PROJECT = File.basename(__dir__)
|
|
12
|
+
unless defined?(StoryTeller::PROJECT)
|
|
13
|
+
# Ensure Story::Teller module constants
|
|
14
|
+
module StoryTeller
|
|
15
|
+
PROJECT = File.basename(File.expand_path(__dir__))
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
load "#{
|
|
19
|
+
load "#{StoryTeller::PROJECT}.gemspec"
|
|
18
20
|
|
|
19
21
|
CLEAN.add File.join('tmp', '**', '*'), 'tmp'
|
|
20
22
|
CLOBBER.add '*.gem', 'pkg'
|
|
21
23
|
|
|
22
24
|
task default: %i[package]
|
|
23
25
|
|
|
26
|
+
desc 'Archive the current codebase snapshot'
|
|
27
|
+
task :archive do
|
|
28
|
+
repo_path = '.'
|
|
29
|
+
archive = File.expand_path(File.join('..', "#{StoryTeller::PROJECT}.zip"), Dir.pwd)
|
|
30
|
+
|
|
31
|
+
diff_clean = system('git', '-C', repo_path, 'diff-index', '--quiet', 'HEAD', '--')
|
|
32
|
+
untracked = `git -C #{repo_path.shellescape} ls-files --others --exclude-standard`
|
|
33
|
+
|
|
34
|
+
unless diff_clean && untracked.empty?
|
|
35
|
+
warn 'Please resolve uncommitted or untracked changes in working tree.'
|
|
36
|
+
exit 1
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
FileUtils.rm_f(archive)
|
|
40
|
+
|
|
41
|
+
system('git', '-C', repo_path, 'archive', '-o', archive, '--format=zip', 'HEAD') or abort
|
|
42
|
+
end
|
|
43
|
+
|
|
24
44
|
desc 'Run the rubocop linter'
|
|
25
45
|
task :lint do
|
|
26
46
|
system('bundle', 'exec', 'rubocop') or abort
|
|
@@ -32,15 +52,6 @@ task :test do
|
|
|
32
52
|
end
|
|
33
53
|
task test: :lint
|
|
34
54
|
|
|
35
|
-
desc 'Explode the gem'
|
|
36
|
-
task :explode do
|
|
37
|
-
puts "Installing gem into the ./tmp directory..."
|
|
38
|
-
gems = Dir['*.gem']
|
|
39
|
-
raise 'No .gem files found; to build, run: bundle exec rake' if gems.empty?
|
|
40
|
-
system('gem', 'install', '--no-document', '--install-dir=tmp', *gems) or abort
|
|
41
|
-
end
|
|
42
|
-
task explode: :clean
|
|
43
|
-
|
|
44
55
|
desc 'Package the gem'
|
|
45
56
|
task :package do
|
|
46
57
|
system('gem', 'build') or abort
|
|
@@ -52,7 +63,6 @@ task :verify do
|
|
|
52
63
|
system('bundle', 'exec', 'rspec', 'spec/verify_gem_spec.rb') or abort
|
|
53
64
|
system('bundle', 'exec', 'rake', 'clean')
|
|
54
65
|
end
|
|
55
|
-
task verify: :explode
|
|
56
66
|
|
|
57
67
|
desc 'Publish the gem'
|
|
58
68
|
task :publish do
|
|
@@ -61,5 +71,5 @@ end
|
|
|
61
71
|
task publish: :verify
|
|
62
72
|
|
|
63
73
|
def latest_gem
|
|
64
|
-
Dir["#{
|
|
74
|
+
Dir["#{StoryTeller::PROJECT}*.gem"].max_by { |p| File.mtime(p) }
|
|
65
75
|
end
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: false
|
|
3
3
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
4
|
+
# Copyright Nels Nelson 2008-2025 but freely usable (see license)
|
|
5
5
|
#
|
|
6
|
-
# This file is part of the
|
|
6
|
+
# This file is part of the StoryTeller.
|
|
7
7
|
#
|
|
8
|
-
# The
|
|
8
|
+
# The 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
|
|
13
|
+
# The 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
|
|
19
|
+
# along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
|
|
20
20
|
|
|
21
|
-
# The
|
|
22
|
-
module
|
|
21
|
+
# The StoryTeller module
|
|
22
|
+
module StoryTeller
|
|
23
23
|
# The Articles module
|
|
24
|
-
# Support standard
|
|
24
|
+
# Support standard StoryTeller methods for dynamically applying appropriate
|
|
25
25
|
# articles to nouns.
|
|
26
26
|
module Articles
|
|
27
27
|
LowercaseTheSpaceString = 'the '.freeze
|
|
@@ -97,10 +97,14 @@ module Inform
|
|
|
97
97
|
def ctheyreorthats(obj); CTheyreorThats(obj); end
|
|
98
98
|
end
|
|
99
99
|
# module Articles
|
|
100
|
+
end
|
|
101
|
+
# module StoryTeller
|
|
100
102
|
|
|
103
|
+
# module Inform
|
|
104
|
+
module Inform
|
|
101
105
|
# Re-open the Inform::Parser module
|
|
102
106
|
module Parser
|
|
103
|
-
include
|
|
107
|
+
include StoryTeller::Articles
|
|
104
108
|
|
|
105
109
|
VowelsOrHiPattern = %r{^([aeiou]|hi).+}.freeze
|
|
106
110
|
|
|
@@ -132,7 +136,7 @@ module Inform
|
|
|
132
136
|
# module Parser
|
|
133
137
|
|
|
134
138
|
module Verbs
|
|
135
|
-
include
|
|
139
|
+
include StoryTeller::Articles
|
|
136
140
|
end
|
|
137
141
|
end
|
|
138
142
|
# module Inform
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
+
# lib/story_teller/builtins.rb
|
|
1
2
|
# encoding: utf-8
|
|
2
3
|
# frozen_string_literal: false
|
|
3
4
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2025 but freely usable (see license)
|
|
5
6
|
#
|
|
6
|
-
# This file is part of the
|
|
7
|
+
# This file is part of the StoryTeller.
|
|
7
8
|
#
|
|
8
|
-
# The
|
|
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
|
|
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
|
|
20
|
-
|
|
21
|
-
require 'set'
|
|
20
|
+
# along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
|
|
22
21
|
|
|
23
22
|
require 'method_source' # Require the method_source gem
|
|
24
23
|
|
|
@@ -26,12 +25,14 @@ require_relative 'articles'
|
|
|
26
25
|
require_relative 'color'
|
|
27
26
|
require_relative 'plurals'
|
|
28
27
|
|
|
29
|
-
# These are built-ins which may be used throughout the
|
|
28
|
+
# These are built-ins which may be used throughout the StoryTeller namespace.
|
|
30
29
|
# TODO: Consider moving these into a module included in the Kernel module.
|
|
31
|
-
module
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
include
|
|
30
|
+
module StoryTeller
|
|
31
|
+
# module Builtins
|
|
32
|
+
module Builtins
|
|
33
|
+
include StoryTeller::Articles
|
|
34
|
+
include StoryTeller::Color
|
|
35
|
+
include StoryTeller::Plurals
|
|
35
36
|
|
|
36
37
|
alias random rand
|
|
37
38
|
|
|
@@ -164,22 +165,25 @@ module Inform
|
|
|
164
165
|
|
|
165
166
|
def objectloop(*_args, &block)
|
|
166
167
|
if self.is_a?(InformLibrary)
|
|
167
|
-
|
|
168
|
+
object_class = StoryTeller::ModelAdapter.object_class
|
|
169
|
+
object_class&.all&.each { |o| block.call(o) }
|
|
168
170
|
elsif self.respond_to?(:descendants)
|
|
169
171
|
self.descendants.each { |o| block.call(o) }
|
|
170
172
|
end
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
def getobject(id)
|
|
174
|
-
|
|
176
|
+
object_class = StoryTeller::ModelAdapter.object_class!
|
|
177
|
+
o = object_class[id]
|
|
175
178
|
o.refresh
|
|
176
179
|
rescue StandardError
|
|
177
180
|
raise NoSuchObject
|
|
178
181
|
end
|
|
179
182
|
|
|
180
183
|
def findobject(*args, &block)
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
object_class = StoryTeller::ModelAdapter.object_class!
|
|
185
|
+
return object_class.dataset.order(:name, :id).grep(:name, *args).to_a if args.first.is_a?(Regexp)
|
|
186
|
+
object_class.dataset.grep(&block).to_a
|
|
183
187
|
end
|
|
184
188
|
|
|
185
189
|
def deadflag; @deadflag; end
|
|
@@ -234,13 +238,15 @@ module Inform
|
|
|
234
238
|
def language_pronouns
|
|
235
239
|
# TODO: Cleanup upon disconnect
|
|
236
240
|
key = self.respond_to?(:inflib) ? self.inflib : self.identity
|
|
237
|
-
LanguagePronouns[key] ||= Marshal.load(
|
|
241
|
+
Inform::English::LanguagePronouns[key] ||= Marshal.load(
|
|
242
|
+
Marshal.dump(Inform::English::LanguagePronouns[:default]))
|
|
238
243
|
end
|
|
239
244
|
|
|
240
245
|
def language_descriptors
|
|
241
246
|
# TODO: Cleanup upon disconnect
|
|
242
247
|
key = self.respond_to?(:inflib) ? self.inflib : self.identity
|
|
243
|
-
LanguageDescriptors[key] ||= Marshal.load(
|
|
248
|
+
Inform::English::LanguageDescriptors[key] ||= Marshal.load(
|
|
249
|
+
Marshal.dump(Inform::English::LanguageDescriptors[:default]))
|
|
244
250
|
end
|
|
245
251
|
|
|
246
252
|
def light_adjusted(obj = @player)
|
|
@@ -275,11 +281,31 @@ module Inform
|
|
|
275
281
|
invoke :Disrobe, obj
|
|
276
282
|
end
|
|
277
283
|
|
|
278
|
-
def
|
|
279
|
-
|
|
284
|
+
def __read
|
|
285
|
+
StoryTeller::Runtime.instance.read
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def __quit
|
|
289
|
+
StoryTeller::Runtime.instance.quit_game
|
|
280
290
|
publish :disconnect
|
|
281
291
|
end
|
|
282
292
|
|
|
293
|
+
def __verify(*args)
|
|
294
|
+
StoryTeller::Runtime.instance.verify_game(*args)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def __restart(*args)
|
|
298
|
+
StoryTeller::Runtime.instance.restart_game(*args)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def __save(*args)
|
|
302
|
+
StoryTeller::Runtime.instance.save_game(*args)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def __restore(*args)
|
|
306
|
+
StoryTeller::Runtime.instance.restore_game(*args)
|
|
307
|
+
end
|
|
308
|
+
|
|
283
309
|
# ----------------------------------------------------------------------------
|
|
284
310
|
# (From the Inform Designer's Manual)
|
|
285
311
|
# §26 Describing objects and rooms
|
|
@@ -319,7 +345,7 @@ module Inform
|
|
|
319
345
|
end
|
|
320
346
|
|
|
321
347
|
def library_method?(method)
|
|
322
|
-
|
|
348
|
+
StoryTeller::Library.methods_index.include?(method) && respond_to?(method)
|
|
323
349
|
end
|
|
324
350
|
|
|
325
351
|
VERB = 1
|
|
@@ -356,4 +382,6 @@ module Inform
|
|
|
356
382
|
# rubocop: enable Metrics/CyclomaticComplexity
|
|
357
383
|
# rubocop: enable Metrics/PerceivedComplexity
|
|
358
384
|
end
|
|
359
|
-
# module
|
|
385
|
+
# module Builtins
|
|
386
|
+
end
|
|
387
|
+
# module StoryTeller
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: false
|
|
3
3
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
4
|
+
# Copyright Nels Nelson 2008-2025 but freely usable (see license)
|
|
5
5
|
#
|
|
6
|
-
# This file is part of the
|
|
6
|
+
# This file is part of the StoryTeller.
|
|
7
7
|
#
|
|
8
|
-
# The
|
|
8
|
+
# The 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
|
|
13
|
+
# The 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
|
|
19
|
+
# along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
|
|
20
20
|
|
|
21
|
-
# The
|
|
22
|
-
module
|
|
21
|
+
# The StoryTeller module
|
|
22
|
+
module StoryTeller
|
|
23
23
|
# The Color module
|
|
24
24
|
module Color
|
|
25
25
|
StyleCodes = {
|
|
@@ -142,4 +142,4 @@ module Inform
|
|
|
142
142
|
end
|
|
143
143
|
# module Color
|
|
144
144
|
end
|
|
145
|
-
# module
|
|
145
|
+
# module StoryTeller
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: false
|
|
3
3
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
4
|
+
# Copyright Nels Nelson 2008-2025 but freely usable (see license)
|
|
5
5
|
#
|
|
6
|
-
# This file is part of the
|
|
6
|
+
# This file is part of the StoryTeller.
|
|
7
7
|
#
|
|
8
|
-
# The
|
|
8
|
+
# The 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
|
|
13
|
+
# The 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
|
|
19
|
+
# along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
|
|
20
20
|
|
|
21
21
|
# Re-open the Proc class to define #to_lambda
|
|
22
22
|
class Proc
|
|
@@ -44,8 +44,8 @@ class Proc
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# The
|
|
48
|
-
module
|
|
47
|
+
# The StoryTeller module
|
|
48
|
+
module StoryTeller
|
|
49
49
|
# The CommandCauseRecordNotFoundError class
|
|
50
50
|
class CommandCauseRecordNotFoundError < StandardError; end
|
|
51
51
|
|
|
@@ -103,7 +103,7 @@ module PublicCommandMethods
|
|
|
103
103
|
def now(params = {}, &block)
|
|
104
104
|
# TODO: Determine if :cause should be overwritten
|
|
105
105
|
# by any :cause params given by the params Hash
|
|
106
|
-
|
|
106
|
+
StoryTeller::Command.new({ cause: cause, antecedent: self }.merge(params), &block)
|
|
107
107
|
end
|
|
108
108
|
alias add_event now
|
|
109
109
|
alias event now
|
|
@@ -114,12 +114,12 @@ module PublicCommandMethods
|
|
|
114
114
|
|
|
115
115
|
# Shortcut for using delays
|
|
116
116
|
def delay(delay, &block)
|
|
117
|
-
|
|
117
|
+
StoryTeller::Command.new({ cause: cause, antecedent: self, delay: delay }, &block)
|
|
118
118
|
end
|
|
119
119
|
alias after_delay delay
|
|
120
120
|
|
|
121
121
|
def finally(&block)
|
|
122
|
-
|
|
122
|
+
StoryTeller::Command.new({ cause: cause, antecedent: self, terminus: true }, &block)
|
|
123
123
|
end
|
|
124
124
|
alias on_cancel finally
|
|
125
125
|
alias when_completed finally
|
|
@@ -169,7 +169,7 @@ module PublicCommandMethods
|
|
|
169
169
|
rescue StandardError => e
|
|
170
170
|
if RecordNotFoundErrorPattern.match?(e.message)
|
|
171
171
|
message = e.message + ' for cause of event ' + self.to_s
|
|
172
|
-
raise
|
|
172
|
+
raise StoryTeller::CommandCauseRecordNotFoundError, message
|
|
173
173
|
end
|
|
174
174
|
log.warn "Unexpected error refreshing event cause object: #{e.message}"
|
|
175
175
|
end
|
|
@@ -225,10 +225,10 @@ module PrivateCommandMethods
|
|
|
225
225
|
def schedule(event, delay = 0)
|
|
226
226
|
raise "The event parameter may not be nil" if event.nil?
|
|
227
227
|
delay = event.time_delay.to_f * 1000 if event.time_delay > 0
|
|
228
|
-
event.future =
|
|
229
|
-
Futures.addCallback(to_java_future(event.future), event,
|
|
228
|
+
event.future = StoryTeller::Commands::Scheduler.schedule(event, delay, TimeUnit::MILLISECONDS)
|
|
229
|
+
Futures.addCallback(to_java_future(event.future), event, StoryTeller::Commands::Scheduler)
|
|
230
230
|
event.cause.events << event
|
|
231
|
-
|
|
231
|
+
StoryTeller::Commands::ActiveObjects << event.cause unless StoryTeller::Commands::ActiveObjects.include?(event.cause)
|
|
232
232
|
event.future
|
|
233
233
|
end
|
|
234
234
|
# rubocop: enable Metrics/AbcSize
|
|
@@ -254,7 +254,7 @@ module PrivateCommandMethods
|
|
|
254
254
|
else
|
|
255
255
|
log.error "Command activity type is unknown: #{event.activity} (#{event.activity.class})"
|
|
256
256
|
end
|
|
257
|
-
rescue
|
|
257
|
+
rescue StoryTeller::CommandCauseRecordNotFoundError => e
|
|
258
258
|
log.error "Error refreshing cause object: #{e.message}"
|
|
259
259
|
rescue LocalJumpError => e
|
|
260
260
|
# It is a shame that this happens. It used to not happen, so long
|
|
@@ -290,10 +290,10 @@ module PrivateCommandMethods
|
|
|
290
290
|
se = Thread.current[:event]
|
|
291
291
|
Thread.current[:event] = event
|
|
292
292
|
log.debug "Queueing #{event}"
|
|
293
|
-
event.future =
|
|
294
|
-
Futures.addCallback(to_java_future(event.future), event,
|
|
293
|
+
event.future = StoryTeller::Commands.pool.java_send(:submit, [java.lang.Runnable], event)
|
|
294
|
+
Futures.addCallback(to_java_future(event.future), event, StoryTeller::Commands.pool)
|
|
295
295
|
event.cause.events << event
|
|
296
|
-
|
|
296
|
+
StoryTeller::Commands.active_objects << event.cause unless StoryTeller::Commands.active_objects.include?(event.cause)
|
|
297
297
|
event.future.get
|
|
298
298
|
event.future
|
|
299
299
|
rescue SystemExit => e
|
|
@@ -315,7 +315,7 @@ module PrivateCommandMethods
|
|
|
315
315
|
def deactivate(obj)
|
|
316
316
|
raise "The obj parameter may not be nil" if obj.nil?
|
|
317
317
|
obj.events.remove self
|
|
318
|
-
|
|
318
|
+
StoryTeller::Commands::ActiveObjects.remove obj if obj.events.empty?
|
|
319
319
|
end
|
|
320
320
|
|
|
321
321
|
def cancelled
|
|
@@ -391,13 +391,13 @@ module CommandInitializationMethods
|
|
|
391
391
|
def generate_identity
|
|
392
392
|
s = format(CommandCauseIdentityTemplate, identity: @cause.identity, name: @cause.name)
|
|
393
393
|
if !callstack.empty?
|
|
394
|
-
trace = @callstack.first.gsub(
|
|
394
|
+
trace = @callstack.first.gsub(StoryTeller::Engine.project_dir_path, '')
|
|
395
395
|
location, line_number, method_name = CallerPattern.match(trace)&.captures
|
|
396
396
|
s << format(CommandSourceFullTemplate,
|
|
397
397
|
method_name: method_name, source_location: location, source_line_number: line_number)
|
|
398
398
|
elsif @activity.respond_to?(:source_location) || @activity.is_a?(Proc)
|
|
399
399
|
activity_source_location_enumerator = @activity.source_location.each
|
|
400
|
-
source_location = activity_source_location_enumerator.next.gsub(
|
|
400
|
+
source_location = activity_source_location_enumerator.next.gsub(StoryTeller::Engine.project_dir_path, '')
|
|
401
401
|
source_line_number = activity_source_location_enumerator.next
|
|
402
402
|
s << format(CommandSourceTemplate, source_location: source_location, source_line_number: source_line_number)
|
|
403
403
|
elsif name != @activity.to_s
|
|
@@ -428,9 +428,9 @@ module CommandInitializationMethods
|
|
|
428
428
|
end
|
|
429
429
|
# module CommandInitializationMethods
|
|
430
430
|
|
|
431
|
-
# The
|
|
432
|
-
module
|
|
433
|
-
# The
|
|
431
|
+
# The StoryTeller module
|
|
432
|
+
module StoryTeller
|
|
433
|
+
# The StoryTeller::Command class
|
|
434
434
|
class Command
|
|
435
435
|
attr_accessor :future
|
|
436
436
|
attr_reader :time, :name, :args, :type, :context, :semaphore, :identity
|
|
@@ -453,7 +453,7 @@ module Inform
|
|
|
453
453
|
|
|
454
454
|
def contextualize(from)
|
|
455
455
|
# log.info "Initializing context for command #{self} from #{from} (#{from.class})"
|
|
456
|
-
|
|
456
|
+
StoryTeller::Context.get.members.each do |attribute|
|
|
457
457
|
value = get_value(from, attribute)
|
|
458
458
|
warn_when_nilling_noun(from, attribute, value)
|
|
459
459
|
setter_method = format('%<attribute>s=', attribute: attribute).to_sym
|
|
@@ -461,10 +461,8 @@ module Inform
|
|
|
461
461
|
end
|
|
462
462
|
end
|
|
463
463
|
|
|
464
|
-
private
|
|
465
|
-
|
|
466
464
|
include CommandInitializationMethods
|
|
467
465
|
end
|
|
468
466
|
# class Command
|
|
469
467
|
end
|
|
470
|
-
# module
|
|
468
|
+
# module StoryTeller
|
|
@@ -1,45 +1,48 @@
|
|
|
1
|
+
# lib/story_teller/context.rb
|
|
1
2
|
# encoding: utf-8
|
|
2
3
|
# frozen_string_literal: false
|
|
3
4
|
|
|
4
|
-
# Copyright Nels Nelson 2008-
|
|
5
|
+
# Copyright Nels Nelson 2008-2025 but freely usable (see license)
|
|
5
6
|
#
|
|
6
|
-
# This file is part of the
|
|
7
|
+
# This file is part of the StoryTeller.
|
|
7
8
|
#
|
|
8
|
-
# The
|
|
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
|
|
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
|
|
20
|
+
# along with the StoryTeller. If not, see <http://www.gnu.org/licenses/>.
|
|
20
21
|
|
|
21
|
-
# The
|
|
22
|
-
module
|
|
22
|
+
# The StoryTeller module
|
|
23
|
+
module StoryTeller
|
|
23
24
|
def self.context_class
|
|
24
|
-
Inform::Context.definition || Inform::Context.set(
|
|
25
|
+
Inform::Context.definition || Inform::Context.set(StoryTeller::Engine.invocation_context)
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def self.context
|
|
28
29
|
context_class.new
|
|
29
30
|
end
|
|
31
|
+
end
|
|
30
32
|
|
|
33
|
+
# The Inform module
|
|
34
|
+
module Inform
|
|
31
35
|
# Define Context module
|
|
32
36
|
module Context
|
|
33
|
-
|
|
37
|
+
module_function
|
|
38
|
+
|
|
39
|
+
@definition = nil
|
|
40
|
+
|
|
34
41
|
def definition
|
|
35
|
-
|
|
42
|
+
@definition
|
|
36
43
|
end
|
|
37
|
-
module_function :definition
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
Inform::Context.definition
|
|
41
|
-
end
|
|
42
|
-
module_function :get
|
|
45
|
+
alias get definition
|
|
43
46
|
|
|
44
47
|
AttributeFieldReferenceTemplate = '@%<attribute>s'.freeze
|
|
45
48
|
|
|
@@ -47,31 +50,27 @@ module Inform
|
|
|
47
50
|
return from.send(attribute) if from.respond_to?(attribute)
|
|
48
51
|
from.instance_variable_get(format(AttributeFieldReferenceTemplate, attribute: attribute).to_sym)
|
|
49
52
|
end
|
|
50
|
-
module_function :get_value
|
|
51
53
|
|
|
52
54
|
AttributeSetterMethodTemplate = '%<attribute>s='.freeze
|
|
53
55
|
|
|
54
56
|
def setter_method(attribute)
|
|
55
57
|
format(AttributeSetterMethodTemplate, attribute: attribute).to_sym
|
|
56
58
|
end
|
|
57
|
-
module_function :setter_method
|
|
58
59
|
|
|
59
60
|
def each_attribute(obj)
|
|
60
|
-
|
|
61
|
+
@definition&.members&.each do |attribute|
|
|
61
62
|
yield(attribute, get_value(obj, attribute))
|
|
62
63
|
end
|
|
63
64
|
end
|
|
64
|
-
module_function :each_attribute
|
|
65
65
|
|
|
66
66
|
def set(definition)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
@definition = definition
|
|
68
|
+
@definition&.members&.each do |attribute|
|
|
69
|
+
StoryTeller::Command.send(:attr_accessor, attribute) unless StoryTeller::Command.respond_to? attribute
|
|
70
70
|
Inform::Event.send(:attr_accessor, attribute) unless Inform::Event.respond_to? attribute
|
|
71
71
|
end
|
|
72
|
-
definition
|
|
72
|
+
@definition
|
|
73
73
|
end
|
|
74
|
-
module_function :set
|
|
75
74
|
end
|
|
76
75
|
# module Context
|
|
77
76
|
end
|