inform-runtime 1.0.4
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 +7 -0
- data/LICENSE +623 -0
- data/README.md +185 -0
- data/Rakefile +65 -0
- data/config/database.yml +37 -0
- data/exe/inform.rb +6 -0
- data/game/config.yml +5 -0
- data/game/example.inf +76 -0
- data/game/example.rb +90 -0
- data/game/forms/example_form.rb +2 -0
- data/game/grammar/game_grammar.inf.rb +11 -0
- data/game/languages/english.rb +2 -0
- data/game/models/example_model.rb +2 -0
- data/game/modules/example_module.rb +9 -0
- data/game/rules/example_state.rb +2 -0
- data/game/scripts/example_script.rb +2 -0
- data/game/topics/example_topic.rb +2 -0
- data/game/verbs/game_verbs.rb +15 -0
- data/game/verbs/metaverbs.rb +2028 -0
- data/lib/runtime/articles.rb +138 -0
- data/lib/runtime/builtins.rb +359 -0
- data/lib/runtime/color.rb +145 -0
- data/lib/runtime/command.rb +470 -0
- data/lib/runtime/config.rb +48 -0
- data/lib/runtime/context.rb +78 -0
- data/lib/runtime/daemon.rb +266 -0
- data/lib/runtime/database.rb +500 -0
- data/lib/runtime/events.rb +771 -0
- data/lib/runtime/experimental/handler_dsl.rb +175 -0
- data/lib/runtime/game.rb +74 -0
- data/lib/runtime/game_loader.rb +132 -0
- data/lib/runtime/grammar_parser.rb +553 -0
- data/lib/runtime/helpers.rb +177 -0
- data/lib/runtime/history.rb +45 -0
- data/lib/runtime/inflector.rb +195 -0
- data/lib/runtime/io.rb +174 -0
- data/lib/runtime/kernel.rb +450 -0
- data/lib/runtime/library.rb +59 -0
- data/lib/runtime/library_loader.rb +135 -0
- data/lib/runtime/link.rb +158 -0
- data/lib/runtime/logging.rb +197 -0
- data/lib/runtime/mixins.rb +570 -0
- data/lib/runtime/module.rb +202 -0
- data/lib/runtime/object.rb +761 -0
- data/lib/runtime/options.rb +104 -0
- data/lib/runtime/persistence.rb +292 -0
- data/lib/runtime/plurals.rb +60 -0
- data/lib/runtime/prototype.rb +307 -0
- data/lib/runtime/publication.rb +92 -0
- data/lib/runtime/runtime.rb +321 -0
- data/lib/runtime/session.rb +202 -0
- data/lib/runtime/stdlib.rb +604 -0
- data/lib/runtime/subscription.rb +47 -0
- data/lib/runtime/tag.rb +287 -0
- data/lib/runtime/tree.rb +204 -0
- data/lib/runtime/version.rb +24 -0
- data/lib/runtime/world_tree.rb +69 -0
- data/lib/runtime.rb +35 -0
- metadata +199 -0
data/lib/runtime/link.rb
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
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/>.
|
|
20
|
+
|
|
21
|
+
# Link
|
|
22
|
+
|
|
23
|
+
if defined?(Sequel::Migration)
|
|
24
|
+
# The LinkSetup class
|
|
25
|
+
class LinkSetup < Sequel::Migration
|
|
26
|
+
# rubocop: disable Metrics/MethodLength
|
|
27
|
+
def up
|
|
28
|
+
# return if table_exists? :link
|
|
29
|
+
log.debug "#up"
|
|
30
|
+
create_table? :link do
|
|
31
|
+
primary_key :id
|
|
32
|
+
foreign_key :from_id, :object, on_delete: :cascade
|
|
33
|
+
foreign_key :to_id, :object, on_delete: :cascade
|
|
34
|
+
index :name
|
|
35
|
+
index :created_at
|
|
36
|
+
|
|
37
|
+
String :name
|
|
38
|
+
DateTime :created_at
|
|
39
|
+
DateTime :modified_at
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
# rubocop: enable Metrics/MethodLength
|
|
43
|
+
|
|
44
|
+
def down
|
|
45
|
+
drop_table :link if table_exists? :link
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
# class LinkSetup
|
|
49
|
+
end
|
|
50
|
+
# defined?(Sequel::Migration)
|
|
51
|
+
|
|
52
|
+
# The Inform module
|
|
53
|
+
module Inform
|
|
54
|
+
# The Inform::Link class
|
|
55
|
+
class Link < Sequel::Model
|
|
56
|
+
set_primary_key :id
|
|
57
|
+
def_column_accessor :created_at, :modified_at
|
|
58
|
+
def_column_accessor :name
|
|
59
|
+
many_to_one :from, class: Inform::Object, key: :from_id
|
|
60
|
+
many_to_one :to, class: Inform::Object, key: :to_id
|
|
61
|
+
|
|
62
|
+
LinkTemplate = '%<link_name>s -> %<to_name>s [%<to_identity>s]'.freeze
|
|
63
|
+
LinkMethods = %w[from_id to_id].freeze
|
|
64
|
+
MethodWriterTemplate = '%<method_name>s='.freeze
|
|
65
|
+
|
|
66
|
+
def before_create
|
|
67
|
+
self.created_at ||= Time.now
|
|
68
|
+
super
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def after_save
|
|
72
|
+
super
|
|
73
|
+
self.modified_at = Time.now.utc
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def to_s
|
|
77
|
+
format(LinkTemplate, link_name: name, to_name: to.name, to_identity: to.identity)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def <=>(other)
|
|
81
|
+
self.name <=> other.name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def init_with(coder)
|
|
85
|
+
LinkMethods.each do |method_name|
|
|
86
|
+
method_symbol = format(MethodWriterTemplate, method_name: method_name).to_sym
|
|
87
|
+
self.send(method_symbol, coder[method_name]) if self.respond_to? method_symbol
|
|
88
|
+
end
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The Inform module
|
|
95
|
+
module Inform
|
|
96
|
+
# The Linkable module
|
|
97
|
+
module Linkable
|
|
98
|
+
def links
|
|
99
|
+
super
|
|
100
|
+
rescue StandardError => _e
|
|
101
|
+
Array::Empty
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# rubocop: disable Metrics/AbcSize
|
|
105
|
+
# rubocop: disable Metrics/MethodLength
|
|
106
|
+
def link(link_name, obj = nil)
|
|
107
|
+
link = Inform::Link.first(name: link_name.to_s, from_id: self.id)
|
|
108
|
+
link&.to&.refresh
|
|
109
|
+
return link if obj.nil?
|
|
110
|
+
if link.nil?
|
|
111
|
+
clauses = { name: link_name.to_s, from_id: self.id, to_id: obj.id }
|
|
112
|
+
link = Inform::Link.find_or_create(**clauses) do |l|
|
|
113
|
+
l.from = self
|
|
114
|
+
l.to = obj
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
link.to = obj
|
|
118
|
+
link.save
|
|
119
|
+
end
|
|
120
|
+
link
|
|
121
|
+
end
|
|
122
|
+
# rubocop: enable Metrics/AbcSize
|
|
123
|
+
# rubocop: enable Metrics/MethodLength
|
|
124
|
+
|
|
125
|
+
def linked?(link_name)
|
|
126
|
+
Inform::Link.filter(name: link_name.to_s, from_id: self.id).count > 0
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def unlink(link_name)
|
|
130
|
+
Inform::Link.first(name: link_name.to_s, from_id: self.id).destroy&.to
|
|
131
|
+
rescue Sequel::NoExistingObject => e
|
|
132
|
+
log.warn 'Error: ' + e.message
|
|
133
|
+
log.warn 'No such link: ' + link_name
|
|
134
|
+
nil
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def linkto(link_name)
|
|
138
|
+
Inform::Link.first(name: link_name.to_s, from_id: self.id)&.to&.refresh
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def linksfrom(link_name = nil)
|
|
142
|
+
if link_name.nil?
|
|
143
|
+
Inform::Link.filter(to_id: self.id).map(&:from)
|
|
144
|
+
else
|
|
145
|
+
Inform::Link.filter(name: link_name.to_s, to_id: self.id).map(&:from)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
alias _key? linked?
|
|
150
|
+
alias _get_object linkto
|
|
151
|
+
def _set_object(link_name, obj = nil)
|
|
152
|
+
link(link_name, obj).to
|
|
153
|
+
end
|
|
154
|
+
alias _unset_object unlink
|
|
155
|
+
end
|
|
156
|
+
# module Linkable
|
|
157
|
+
end
|
|
158
|
+
# module Inform
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
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/>.
|
|
20
|
+
|
|
21
|
+
require 'fileutils'
|
|
22
|
+
require 'logger'
|
|
23
|
+
|
|
24
|
+
if defined?(Java)
|
|
25
|
+
require 'apache-log4j-2'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The Logging module
|
|
29
|
+
module Logging
|
|
30
|
+
# rubocop: disable Metrics/MethodLength
|
|
31
|
+
def config
|
|
32
|
+
@config ||= begin
|
|
33
|
+
support_dir_path = File.expand_path(__dir__)
|
|
34
|
+
lib_dir_path = File.expand_path(File.dirname(support_dir_path))
|
|
35
|
+
project_dir_path = File.expand_path(File.dirname(lib_dir_path))
|
|
36
|
+
app_name = File.basename(project_dir_path)
|
|
37
|
+
logs_dir_path = File.expand_path(File.join(project_dir_path, 'logs'))
|
|
38
|
+
FileUtils.mkdir_p(logs_dir_path)
|
|
39
|
+
log_file = File.expand_path(File.join(logs_dir_path, "#{app_name}.log"))
|
|
40
|
+
{
|
|
41
|
+
level: :info,
|
|
42
|
+
name: app_name,
|
|
43
|
+
lib_dir_path: lib_dir_path,
|
|
44
|
+
project_dir_path: project_dir_path,
|
|
45
|
+
logs_dir_path: logs_dir_path,
|
|
46
|
+
log_file: log_file,
|
|
47
|
+
rolling_log_file_name_template: "#{app_name}-%d{yyyy-MM-dd}.log.gz",
|
|
48
|
+
logging_timestamp_format: '%Y-%m-%d %H:%M:%S',
|
|
49
|
+
logging_pattern_template: {
|
|
50
|
+
java: '%d{ABSOLUTE} %-5p [%c{1}] %m%n',
|
|
51
|
+
ruby: "%<timestamp>s %-5<severity>s [%<progname>s] %<msg>s\n"
|
|
52
|
+
},
|
|
53
|
+
schedule: '0 0 0 * * ?',
|
|
54
|
+
size: '100M'
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
module_function :config
|
|
59
|
+
# rubocop: enable Metrics/MethodLength
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Namespace for methods to help with implicit backtrace printing
|
|
63
|
+
module LoggerHelpers
|
|
64
|
+
def generate_message(error_or_message, error)
|
|
65
|
+
error_message = "#{error_or_message}: #{error.class.name}"
|
|
66
|
+
error_message << ": #{error.message}" if error.respond_to?(:message)
|
|
67
|
+
error_message
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def extract_backtrace(error, default_result = nil)
|
|
71
|
+
if error.respond_to?(:backtrace)
|
|
72
|
+
error.backtrace.each { |trace| original_error(trace) unless trace.nil? }
|
|
73
|
+
elsif error.respond_to?(:getStackTrace)
|
|
74
|
+
error.getStackTrace().each { |trace| original_error(trace) unless trace.nil? }
|
|
75
|
+
else
|
|
76
|
+
default_result
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Monkey-patch the built-in Ruby Logger class to support
|
|
82
|
+
# implicit backtrace printing
|
|
83
|
+
# TODO: Figure out if this is actually useful.
|
|
84
|
+
class Logger
|
|
85
|
+
include LoggerHelpers
|
|
86
|
+
|
|
87
|
+
alias original_error error
|
|
88
|
+
def error(error_or_message, error = nil)
|
|
89
|
+
warn error_or_message
|
|
90
|
+
return extract_backtrace(error_or_message) if error.nil?
|
|
91
|
+
original_error(generate_message(error_or_message, error))
|
|
92
|
+
extract_backtrace(original_error(error))
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# The Logging module
|
|
97
|
+
module Logging
|
|
98
|
+
if defined?(Java)
|
|
99
|
+
java_import Java::org.apache.logging.log4j.Level
|
|
100
|
+
java_import Java::org.apache.logging.log4j.LogManager
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def init_logger(level = :info, logger_name = nil)
|
|
104
|
+
return init_java_logger(level, logger_name, caller[2]) if defined?(Java)
|
|
105
|
+
init_ruby_logger(level, logger_name, caller[2])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def ruby_log_formatter(severity, datetime, progname, message)
|
|
109
|
+
format(
|
|
110
|
+
Logging.config[:logging_pattern_template][:ruby],
|
|
111
|
+
timestamp: datetime.strftime(Logging.config[:logging_timestamp_format]),
|
|
112
|
+
progname: progname, severity: severity, msg: message)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
ForwardSlashPattern = %r{/}.freeze
|
|
116
|
+
|
|
117
|
+
def init_ruby_logger(level = nil, logger_name = nil, source_location = nil)
|
|
118
|
+
logger_name = get_formatted_logger_name(logger_name)
|
|
119
|
+
logger_name = source_location.split(ForwardSlashPattern).last if logger_name.empty?
|
|
120
|
+
log = Logger.new($stdout, progname: logger_name)
|
|
121
|
+
log.level = level.to_s unless level.nil?
|
|
122
|
+
log.formatter = method(:ruby_log_formatter)
|
|
123
|
+
log
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def init_java_logger(level = nil, logger_name = nil, source_location = nil)
|
|
127
|
+
logger_name = get_formatted_logger_name(logger_name)
|
|
128
|
+
logger_name = source_location.split(ForwardSlashPattern).last if logger_name.empty?
|
|
129
|
+
log = LogManager.getLogger(logger_name)
|
|
130
|
+
log.level = Level.to_level(level.to_s.upcase) unless level.nil?
|
|
131
|
+
log
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def get_formatted_logger_name(logger_name = nil)
|
|
135
|
+
return logger_name.to_s[/\w+$/] unless logger_name.nil?
|
|
136
|
+
return name[/\w+$/] if is_a?(Class) || is_a?(Module)
|
|
137
|
+
self.class.name[/\w+$/]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
141
|
+
# OFF: 0
|
|
142
|
+
# FATAL: 100
|
|
143
|
+
# ERROR: 200
|
|
144
|
+
# WARN: 300
|
|
145
|
+
# INFO: 400
|
|
146
|
+
# DEBUG: 500
|
|
147
|
+
# TRACE: 600
|
|
148
|
+
# ALL: 2147483647
|
|
149
|
+
# See: https://logging.apache.org/log4j/2.x/log4j-api/apidocs/org/apache/logging/log4j/Level.html
|
|
150
|
+
def symbolize_numeric_log_level(level)
|
|
151
|
+
case level
|
|
152
|
+
when 5..Float::INFINITY then :off
|
|
153
|
+
when 4 then :fatal
|
|
154
|
+
when 3 then :error
|
|
155
|
+
when 2 then :warn
|
|
156
|
+
when 1 then :info
|
|
157
|
+
when 0 then :debug
|
|
158
|
+
when -1 then :trace
|
|
159
|
+
when -Float::INFINITY..-2 then :all
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
163
|
+
|
|
164
|
+
def log_level=(level)
|
|
165
|
+
Logging.config[:level] = symbolize_numeric_log_level(level)
|
|
166
|
+
end
|
|
167
|
+
module_function :log_level=
|
|
168
|
+
|
|
169
|
+
def log_level
|
|
170
|
+
Logging.config[:level]
|
|
171
|
+
end
|
|
172
|
+
module_function :log_level
|
|
173
|
+
|
|
174
|
+
def log(level = Logging.log_level, log_name = Logging.config[:app_name])
|
|
175
|
+
@log ||= init_logger(level, log_name)
|
|
176
|
+
end
|
|
177
|
+
alias logger log
|
|
178
|
+
end
|
|
179
|
+
# module Logging
|
|
180
|
+
|
|
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
|