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
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
# Additional mixin methods
|
|
22
|
+
|
|
23
|
+
# The Inform module
|
|
24
|
+
module Inform
|
|
25
|
+
# Some mixins provide exclusive Inform-ification for Ruby, withheld
|
|
26
|
+
# from mixins.rb because of said exclusivity
|
|
27
|
+
module SetHelpers
|
|
28
|
+
def in?(*others)
|
|
29
|
+
return false unless others.respond_to?(:include?)
|
|
30
|
+
others.flatten.include?(self)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def notin?(*others)
|
|
34
|
+
return false unless others.respond_to?(:include?)
|
|
35
|
+
!others.flatten.include?(self)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Stub helpers for NilClass instances
|
|
40
|
+
module NilClassSetHelpers
|
|
41
|
+
def in?(*)
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The Inform module
|
|
48
|
+
module Inform
|
|
49
|
+
# String helper methods mostly for use by Inform::ParseNoun
|
|
50
|
+
# rubocop: disable Metrics/AbcSize
|
|
51
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
52
|
+
# rubocop: disable Metrics/MethodLength
|
|
53
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
54
|
+
module Matchers
|
|
55
|
+
def matches?(obj, regexp = /^#{self}/i, delimeter = /[,\s]+/, str = self)
|
|
56
|
+
return false if str.nil? || (str.respond_to?(:empty?) && str.empty?)
|
|
57
|
+
return false unless obj.object?
|
|
58
|
+
k = obj.name
|
|
59
|
+
k = k.split(delimeter) if k.respond_to?(:split)
|
|
60
|
+
return str if k.respond_to?(:grep) && !k.grep(regexp).empty?
|
|
61
|
+
return str if k.respond_to?(:match?) && k.match?(regexp)
|
|
62
|
+
false
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
log.error e
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def matches_exactly?(obj, regexp = /^#{self}$/i, delimeter = /[,\s]+/, str = self)
|
|
69
|
+
return false if str.nil? || (str.respond_to?(:empty?) && str.empty?)
|
|
70
|
+
return false unless obj.object?
|
|
71
|
+
k = obj.name
|
|
72
|
+
return str if k.respond_to?(:match?) && k.match?(regexp)
|
|
73
|
+
k = k.split(delimeter) if k.respond_to?(:split)
|
|
74
|
+
return str if k.respond_to?(:grep) && !k.grep(regexp).empty?
|
|
75
|
+
return str if k.respond_to?(:match?) && k.match?(regexp)
|
|
76
|
+
false
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
log.error e
|
|
79
|
+
false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def matches_any_exactly?(obj, regexp = /^#{self}$/i, delimeter = /[,\s]+/, str = self)
|
|
83
|
+
return false if str.nil? || (str.respond_to?(:empty?) && str.empty?)
|
|
84
|
+
return false unless obj.object?
|
|
85
|
+
k = obj.name
|
|
86
|
+
k = k.split(delimeter) if k.respond_to?(:split)
|
|
87
|
+
return str if k.respond_to?(:grep) && !k.grep(regexp).empty?
|
|
88
|
+
false
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
log.error e
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def matches_last_exactly?(obj, regexp = /^#{self}$/i, delimeter = /[,\s]+/, str = self)
|
|
95
|
+
return false if str.nil? || (str.respond_to?(:empty?) && str.empty?)
|
|
96
|
+
return false unless obj.object?
|
|
97
|
+
k = obj.name
|
|
98
|
+
k = k.split(delimeter) if k.respond_to?(:split)
|
|
99
|
+
k = k.last if k.respond_to?(:last)
|
|
100
|
+
return str if k.respond_to?(:match?) && k.match?(regexp)
|
|
101
|
+
false
|
|
102
|
+
rescue StandardError => e
|
|
103
|
+
log.error e
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
# rubocop: enable Metrics/AbcSize
|
|
108
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
109
|
+
# rubocop: enable Metrics/MethodLength
|
|
110
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
111
|
+
# module Matchers
|
|
112
|
+
end
|
|
113
|
+
# module Inform
|
|
114
|
+
|
|
115
|
+
# The Object class to add some Inform helper methods
|
|
116
|
+
class Object
|
|
117
|
+
include Inform::SetHelpers
|
|
118
|
+
include Inform::Matchers
|
|
119
|
+
|
|
120
|
+
alias exhibits? kind_of?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The NilClass class to add some Inform helper methods
|
|
124
|
+
class NilClass
|
|
125
|
+
include Inform::NilClassSetHelpers
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# The Enumerable module to add some Inform helper methods
|
|
129
|
+
module Enumerable
|
|
130
|
+
include Inform::SetHelpers
|
|
131
|
+
|
|
132
|
+
def inform(o = '')
|
|
133
|
+
each { |x| x.inform(o) if x.respond_to?(:inform) }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The Inform module
|
|
138
|
+
module Inform
|
|
139
|
+
# The ObjectHelpers module functionality
|
|
140
|
+
module ObjectHelpers
|
|
141
|
+
def object?(obj = self)
|
|
142
|
+
obj.is_a?(Inform::Object) || obj.is_a?(Inform::System::Object)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def sysobj?(obj = self)
|
|
146
|
+
obj.is_a?(Inform::System::Object)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# The Inform module
|
|
152
|
+
module Inform
|
|
153
|
+
# The NilClassObjectHelpers module functionality
|
|
154
|
+
module NilClassObjectHelpers
|
|
155
|
+
def object?
|
|
156
|
+
false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def sysobj?
|
|
160
|
+
false
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def list_together
|
|
164
|
+
self
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Define some built-in Inform helper methods
|
|
170
|
+
class Object
|
|
171
|
+
include Inform::ObjectHelpers
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Define some built-in Inform helper methods
|
|
175
|
+
class NilClass
|
|
176
|
+
include Inform::NilClassObjectHelpers
|
|
177
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
# The Inform module
|
|
22
|
+
module Inform
|
|
23
|
+
# The History module
|
|
24
|
+
module History
|
|
25
|
+
DefaultHistoryLimit = 10
|
|
26
|
+
Histories = defined?(Java) ? java.util.concurrent.ConcurrentHashMap.new : {}
|
|
27
|
+
HistoryCommandPattern = %r{^(!|history)$}.freeze
|
|
28
|
+
|
|
29
|
+
def history
|
|
30
|
+
Histories[@player.identity] ||= []
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def history_limit
|
|
34
|
+
return DefaultHistoryLimit unless @player.respond_to?(:preferences)
|
|
35
|
+
@player.preferences.|(:history_limit, DefaultHistoryLimit).to_i
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def record_history(s)
|
|
39
|
+
return if s.nil? || s.empty? || HistoryCommandPattern.match?(s)
|
|
40
|
+
history.delete_if { |i| i == s }
|
|
41
|
+
history.push(s)
|
|
42
|
+
history.shift if history.length > history_limit
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright (c) 2004-2014 David Heinemeier Hansson
|
|
5
|
+
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
# a copy of this software and associated documentation files (the
|
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
# the following conditions:
|
|
13
|
+
|
|
14
|
+
# The above copyright notice and this permission notice shall be
|
|
15
|
+
# included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
24
|
+
|
|
25
|
+
# == License
|
|
26
|
+
|
|
27
|
+
# Active Support is released under the MIT license:
|
|
28
|
+
|
|
29
|
+
# * http://www.opensource.org/licenses/MIT
|
|
30
|
+
|
|
31
|
+
# The Inform module
|
|
32
|
+
module Inform
|
|
33
|
+
# The Inflector module
|
|
34
|
+
module Inflector
|
|
35
|
+
extend self # rubocop: disable Style/ModuleFunction
|
|
36
|
+
|
|
37
|
+
# The Inflections class
|
|
38
|
+
class Inflections
|
|
39
|
+
@instance = nil
|
|
40
|
+
|
|
41
|
+
def self.instance
|
|
42
|
+
@instance ||= new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
attr_reader :plurals, :singulars, :uncountables, :propers
|
|
46
|
+
|
|
47
|
+
def initialize
|
|
48
|
+
clear_fields
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def clear_fields(fields = %i[plurals singulars uncountables propers])
|
|
52
|
+
fields.each { |field| instance_variable_set(:"@#{field}", []) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def plural(rule, replacement)
|
|
56
|
+
@uncountables.delete(rule) if rule.is_a?(String)
|
|
57
|
+
@uncountables.delete(replacement)
|
|
58
|
+
@plurals.prepend([rule, replacement])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def singular(rule, replacement)
|
|
62
|
+
@uncountables.delete(rule) if rule.is_a?(String)
|
|
63
|
+
@uncountables.delete(replacement)
|
|
64
|
+
@singulars.prepend([rule, replacement])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def defective(noun)
|
|
68
|
+
@plurals.unshift([/^#{noun}$/i, noun])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# rubocop: disable Metrics/AbcSize
|
|
72
|
+
# rubocop: disable Metrics/MethodLength
|
|
73
|
+
def irregular(singular, plural)
|
|
74
|
+
@uncountables.delete(singular)
|
|
75
|
+
@uncountables.delete(plural)
|
|
76
|
+
|
|
77
|
+
s0 = singular[0]
|
|
78
|
+
srest = singular[1..]
|
|
79
|
+
|
|
80
|
+
p0 = plural[0]
|
|
81
|
+
prest = plural[1..]
|
|
82
|
+
|
|
83
|
+
if s0.upcase == p0.upcase
|
|
84
|
+
plural(/(#{s0})#{srest}$/i, '\1' + prest)
|
|
85
|
+
plural(/(#{p0})#{prest}$/i, '\1' + prest)
|
|
86
|
+
|
|
87
|
+
singular(/(#{s0})#{srest}$/i, '\1' + srest)
|
|
88
|
+
singular(/(#{p0})#{prest}$/i, '\1' + srest)
|
|
89
|
+
else
|
|
90
|
+
plural(/#{s0.upcase}(?i)#{srest}$/, p0.upcase + prest)
|
|
91
|
+
plural(/#{s0.downcase}(?i)#{srest}$/, p0.downcase + prest)
|
|
92
|
+
plural(/#{p0.upcase}(?i)#{prest}$/, p0.upcase + prest)
|
|
93
|
+
plural(/#{p0.downcase}(?i)#{prest}$/, p0.downcase + prest)
|
|
94
|
+
|
|
95
|
+
singular(/#{s0.upcase}(?i)#{srest}$/, s0.upcase + srest)
|
|
96
|
+
singular(/#{s0.downcase}(?i)#{srest}$/, s0.downcase + srest)
|
|
97
|
+
singular(/#{p0.upcase}(?i)#{prest}$/, s0.upcase + srest)
|
|
98
|
+
singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
# rubocop: enable Metrics/AbcSize
|
|
102
|
+
# rubocop: enable Metrics/MethodLength
|
|
103
|
+
|
|
104
|
+
def uncountable(*words)
|
|
105
|
+
(@uncountables << words).flatten!
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def proper(rule, replacement)
|
|
109
|
+
@propers.unshift([rule, replacement])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def clear(scope = :all)
|
|
113
|
+
case scope
|
|
114
|
+
when :all
|
|
115
|
+
clear_fields
|
|
116
|
+
else
|
|
117
|
+
clear_fields([scope])
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
# class Inflections
|
|
122
|
+
|
|
123
|
+
def inflections
|
|
124
|
+
return yield Inflections.instance if block_given?
|
|
125
|
+
Inflections.instance
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
# module Inflector
|
|
129
|
+
|
|
130
|
+
# rubocop: disable Metrics/BlockLength
|
|
131
|
+
Inflector.inflections do |inflect|
|
|
132
|
+
inflect.plural(/$/, 's')
|
|
133
|
+
inflect.plural(/s$/i, 's')
|
|
134
|
+
inflect.plural(/^(ax|test)is$/i, '\1es')
|
|
135
|
+
inflect.plural(/(octop|vir)us$/i, '\1i')
|
|
136
|
+
inflect.plural(/(octop|vir)i$/i, '\1i')
|
|
137
|
+
inflect.plural(/(alias|status)$/i, '\1es')
|
|
138
|
+
inflect.plural(/(bu)s$/i, '\1ses')
|
|
139
|
+
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
|
|
140
|
+
inflect.plural(/([ti])um$/i, '\1a')
|
|
141
|
+
inflect.plural(/([ti])a$/i, '\1a')
|
|
142
|
+
inflect.plural(/sis$/i, 'ses')
|
|
143
|
+
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
|
|
144
|
+
inflect.plural(/(hive)$/i, '\1s')
|
|
145
|
+
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
|
146
|
+
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
|
|
147
|
+
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
|
|
148
|
+
inflect.plural(/^(m|l)ouse$/i, '\1ice')
|
|
149
|
+
inflect.plural(/^(m|l)ice$/i, '\1ice')
|
|
150
|
+
inflect.plural(/^(ox)$/i, '\1en')
|
|
151
|
+
inflect.plural(/^(oxen)$/i, '\1')
|
|
152
|
+
inflect.plural(/(quiz)$/i, '\1zes')
|
|
153
|
+
|
|
154
|
+
inflect.singular(/s$/i, '')
|
|
155
|
+
inflect.singular(/(ss)$/i, '\1')
|
|
156
|
+
inflect.singular(/(n)ews$/i, '\1ews')
|
|
157
|
+
inflect.singular(/([ti])a$/i, '\1um')
|
|
158
|
+
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
|
|
159
|
+
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
|
|
160
|
+
inflect.singular(/([^f])ves$/i, '\1fe')
|
|
161
|
+
inflect.singular(/(hive)s$/i, '\1')
|
|
162
|
+
inflect.singular(/(tive)s$/i, '\1')
|
|
163
|
+
inflect.singular(/([lr])ves$/i, '\1f')
|
|
164
|
+
inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
|
|
165
|
+
inflect.singular(/(s)eries$/i, '\1eries')
|
|
166
|
+
inflect.singular(/(m)ovies$/i, '\1ovie')
|
|
167
|
+
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
|
|
168
|
+
inflect.singular(/^(m|l)ice$/i, '\1ouse')
|
|
169
|
+
inflect.singular(/(bus)(es)?$/i, '\1')
|
|
170
|
+
inflect.singular(/(o)es$/i, '\1')
|
|
171
|
+
inflect.singular(/(shoe)s$/i, '\1')
|
|
172
|
+
inflect.singular(/(cris|test)(is|es)$/i, '\1is')
|
|
173
|
+
inflect.singular(/^(a)x[ie]s$/i, '\1xis')
|
|
174
|
+
inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
|
|
175
|
+
inflect.singular(/(alias|status)(es)?$/i, '\1')
|
|
176
|
+
inflect.singular(/^(ox)en/i, '\1')
|
|
177
|
+
inflect.singular(/(vert|ind)ices$/i, '\1ex')
|
|
178
|
+
inflect.singular(/(matr)ices$/i, '\1ix')
|
|
179
|
+
inflect.singular(/(quiz)zes$/i, '\1')
|
|
180
|
+
inflect.singular(/(database)s$/i, '\1')
|
|
181
|
+
|
|
182
|
+
inflect.irregular('child', 'children')
|
|
183
|
+
inflect.irregular('man', 'men')
|
|
184
|
+
inflect.irregular('move', 'moves')
|
|
185
|
+
inflect.irregular('glove', 'gloves')
|
|
186
|
+
inflect.irregular('person', 'people')
|
|
187
|
+
inflect.irregular('sex', 'sexes')
|
|
188
|
+
inflect.irregular('zombie', 'zombies')
|
|
189
|
+
|
|
190
|
+
inflect.uncountable(%w[equipment information rice money species series fish sheep jeans police])
|
|
191
|
+
end
|
|
192
|
+
# rubocop: enable Metrics/BlockLength
|
|
193
|
+
# Inflector.inflections do |inflect|
|
|
194
|
+
end
|
|
195
|
+
# module Inform
|
data/lib/runtime/io.rb
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
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
|
+
# The Inform module
|
|
22
|
+
module Inform
|
|
23
|
+
# The IO module
|
|
24
|
+
module IO
|
|
25
|
+
def session
|
|
26
|
+
return unless defined?(Inform::IO::Session) && Inform::IO::Session.respond_to?(:of)
|
|
27
|
+
@session ||= Inform::IO::Session.of(self)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def noop; end
|
|
31
|
+
|
|
32
|
+
def connections
|
|
33
|
+
subscribed_connections = explicit_subscribers.select { |a| a.is_a? Connection }
|
|
34
|
+
if respond_to?(:inflib) && !inflib.nil? && subscribed_connections.empty?
|
|
35
|
+
subscribed_connections = inflib.explicit_subscribers.select { |a| a.is_a? Connection }
|
|
36
|
+
end
|
|
37
|
+
subscribed_connections
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def read
|
|
41
|
+
$stdin.gets(chomp: true)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def out(s)
|
|
45
|
+
if defined?(Curses)
|
|
46
|
+
Curses.addstr s
|
|
47
|
+
else
|
|
48
|
+
$stdout.write(s)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def inform(s = '')
|
|
53
|
+
s = invert_illeism(self, s) if respond_to?(:invert_illeism)
|
|
54
|
+
new_line
|
|
55
|
+
println s
|
|
56
|
+
new_line if s.is_a?(Array) && !s.empty?
|
|
57
|
+
prompt
|
|
58
|
+
flush_io
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
alias update inform
|
|
62
|
+
|
|
63
|
+
def flush_io
|
|
64
|
+
$stdout.flush
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def tidy_output(s, columns = 76)
|
|
68
|
+
s.gsub!(/^\n+/, "\n")
|
|
69
|
+
return s if s.length < columns || columns == 0
|
|
70
|
+
s.gsub(/(.{#{columns}}\S+)( +|$\n?)/, "\\1\n")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def new_line
|
|
74
|
+
out "\n"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def spaces(n)
|
|
78
|
+
out(' ' * n)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def print(s = '')
|
|
82
|
+
out(s.to_s)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def println(s = '', isolate: false)
|
|
86
|
+
_isolated = (isolate == true) # TODO: Implement
|
|
87
|
+
return print(s) if s.is_a?(Array)
|
|
88
|
+
out(s.to_s + "\n")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def output_stream(i, s); end
|
|
92
|
+
|
|
93
|
+
def reset_prompt
|
|
94
|
+
@prompt = nil
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def prompt(s = @prompt)
|
|
98
|
+
out(@prompt = s || "\n>")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ----------------------------------------------------------------------------
|
|
102
|
+
# Adapted from the C code for ls. :-)
|
|
103
|
+
# ----------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
ItemPaddingString = '%<item>s%<padding>s'.freeze
|
|
106
|
+
MinimumLineLength = 30
|
|
107
|
+
MinimumCellPadding = 8
|
|
108
|
+
MinimumColumnPadding = 2
|
|
109
|
+
|
|
110
|
+
# rubocop: disable Metrics/AbcSize
|
|
111
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
112
|
+
# rubocop: disable Metrics/MethodLength
|
|
113
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
114
|
+
def many_per_line(items)
|
|
115
|
+
max = 0
|
|
116
|
+
|
|
117
|
+
lines = []
|
|
118
|
+
prefs = @player.linkto :preferences
|
|
119
|
+
line_length = prefs ? prefs.word_wrap.to_i : MinimumLineLength
|
|
120
|
+
line_length = MinimumLineLength if line_length <= MinimumLineLength
|
|
121
|
+
buffer = ''
|
|
122
|
+
|
|
123
|
+
items.each do |item|
|
|
124
|
+
max = [item.length, max].max
|
|
125
|
+
end
|
|
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
|
|
141
|
+
|
|
142
|
+
m = []
|
|
143
|
+
loop do
|
|
144
|
+
m << []
|
|
145
|
+
for column in columns
|
|
146
|
+
m.last << column.shift
|
|
147
|
+
end
|
|
148
|
+
break if columns.last.empty?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
m.each do |row|
|
|
152
|
+
buffer = "\e[51m"
|
|
153
|
+
row.each do |item|
|
|
154
|
+
next unless item
|
|
155
|
+
n = [max - item.length, MinimumColumnPadding].max
|
|
156
|
+
padding = " " * n unless item == row.last
|
|
157
|
+
buffer += format(ItemPaddingString, item: item, padding: padding)
|
|
158
|
+
end
|
|
159
|
+
buffer += "\e[56m"
|
|
160
|
+
lines << buffer.strip
|
|
161
|
+
buffer = ''
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
lines
|
|
165
|
+
end
|
|
166
|
+
# rubocop: enable Metrics/AbcSize
|
|
167
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
168
|
+
# rubocop: enable Metrics/MethodLength
|
|
169
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
170
|
+
# def many_per_line
|
|
171
|
+
end
|
|
172
|
+
# module IO
|
|
173
|
+
end
|
|
174
|
+
# module Inform
|