gamefic 3.6.0 → 4.0.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/.rubocop.yml +0 -3
- data/CHANGELOG.md +19 -0
- data/Rakefile +1 -0
- data/gamefic.gemspec +1 -1
- data/lib/gamefic/action.rb +68 -54
- data/lib/gamefic/active/cue.rb +84 -6
- data/lib/gamefic/active/messaging.rb +8 -0
- data/lib/gamefic/active/narratives.rb +101 -0
- data/lib/gamefic/active.rb +80 -92
- data/lib/gamefic/binding.rb +44 -0
- data/lib/gamefic/chapter.rb +30 -46
- data/lib/gamefic/command.rb +22 -40
- data/lib/gamefic/core_ext/array.rb +7 -7
- data/lib/gamefic/core_ext/string.rb +2 -2
- data/lib/gamefic/describable.rb +13 -0
- data/lib/gamefic/dispatcher.rb +35 -55
- data/lib/gamefic/entity.rb +6 -5
- data/lib/gamefic/expression.rb +1 -11
- data/lib/gamefic/logging.rb +3 -10
- data/lib/gamefic/match.rb +23 -0
- data/lib/gamefic/messenger.rb +1 -1
- data/lib/gamefic/narrative.rb +38 -74
- data/lib/gamefic/narrator.rb +77 -0
- data/lib/gamefic/node.rb +40 -8
- data/lib/gamefic/order.rb +53 -0
- data/lib/gamefic/plot.rb +41 -59
- data/lib/gamefic/props/default.rb +5 -17
- data/lib/gamefic/props/multiple_choice.rb +5 -2
- data/lib/gamefic/props/multiple_partial.rb +16 -0
- data/lib/gamefic/props/output.rb +7 -5
- data/lib/gamefic/props/yes_or_no.rb +2 -2
- data/lib/gamefic/props.rb +1 -0
- data/lib/gamefic/proxy/attr.rb +11 -0
- data/lib/gamefic/proxy/base.rb +3 -15
- data/lib/gamefic/proxy/config.rb +2 -2
- data/lib/gamefic/proxy/pick.rb +3 -3
- data/lib/gamefic/proxy/pick_ex.rb +11 -0
- data/lib/gamefic/proxy.rb +3 -71
- data/lib/gamefic/query/ascendants.rb +16 -0
- data/lib/gamefic/query/base.rb +47 -73
- data/lib/gamefic/query/children.rb +15 -0
- data/lib/gamefic/query/descendants.rb +17 -0
- data/lib/gamefic/query/extended.rb +20 -0
- data/lib/gamefic/query/family.rb +27 -0
- data/lib/gamefic/query/global.rb +22 -0
- data/lib/gamefic/query/integer.rb +32 -0
- data/lib/gamefic/query/myself.rb +13 -0
- data/lib/gamefic/query/parent.rb +13 -0
- data/lib/gamefic/query/result.rb +1 -1
- data/lib/gamefic/query/siblings.rb +12 -0
- data/lib/gamefic/query/subqueries.rb +17 -0
- data/lib/gamefic/query/text.rb +8 -9
- data/lib/gamefic/query.rb +11 -3
- data/lib/gamefic/request.rb +60 -0
- data/lib/gamefic/response.rb +46 -72
- data/lib/gamefic/scanner/nesting.rb +6 -6
- data/lib/gamefic/scanner/result.rb +3 -0
- data/lib/gamefic/scanner/strict.rb +14 -4
- data/lib/gamefic/scanner.rb +11 -6
- data/lib/gamefic/scene/active_choice.rb +75 -0
- data/lib/gamefic/scene/activity.rb +7 -3
- data/lib/gamefic/scene/base.rb +123 -0
- data/lib/gamefic/scene/conclusion.rb +4 -1
- data/lib/gamefic/scene/multiple_choice.rb +14 -11
- data/lib/gamefic/scene/pause.rb +5 -1
- data/lib/gamefic/scene/yes_or_no.rb +9 -0
- data/lib/gamefic/scene.rb +2 -1
- data/lib/gamefic/scriptable/hooks.rb +161 -0
- data/lib/gamefic/scriptable/queries.rb +38 -29
- data/lib/gamefic/scriptable/responses.rb +70 -0
- data/lib/gamefic/scriptable/scenes.rb +88 -115
- data/lib/gamefic/scriptable/seeds.rb +69 -0
- data/lib/gamefic/scriptable/syntaxes.rb +29 -0
- data/lib/gamefic/scriptable.rb +14 -199
- data/lib/gamefic/{scriptable → scripting}/entities.rb +22 -22
- data/lib/gamefic/scripting/hooks.rb +45 -0
- data/lib/gamefic/{scriptable → scripting}/proxies.rb +5 -3
- data/lib/gamefic/scripting/responses.rb +21 -0
- data/lib/gamefic/scripting/scenes.rb +57 -0
- data/lib/gamefic/scripting/seeds.rb +10 -0
- data/lib/gamefic/scripting/syntaxes.rb +13 -0
- data/lib/gamefic/scripting.rb +43 -0
- data/lib/gamefic/subplot.rb +11 -22
- data/lib/gamefic/syntax.rb +39 -24
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +6 -7
- metadata +38 -41
- data/lib/gamefic/active/epic.rb +0 -74
- data/lib/gamefic/active/take.rb +0 -67
- data/lib/gamefic/block.rb +0 -28
- data/lib/gamefic/callback.rb +0 -16
- data/lib/gamefic/proxy/plot_pick.rb +0 -11
- data/lib/gamefic/query/abstract.rb +0 -12
- data/lib/gamefic/query/general.rb +0 -41
- data/lib/gamefic/query/scoped.rb +0 -27
- data/lib/gamefic/rulebook/calls.rb +0 -86
- data/lib/gamefic/rulebook/events.rb +0 -65
- data/lib/gamefic/rulebook/hooks.rb +0 -57
- data/lib/gamefic/rulebook/scenes.rb +0 -68
- data/lib/gamefic/rulebook.rb +0 -125
- data/lib/gamefic/scene/default.rb +0 -88
- data/lib/gamefic/scope/base.rb +0 -44
- data/lib/gamefic/scope/children.rb +0 -16
- data/lib/gamefic/scope/descendants.rb +0 -16
- data/lib/gamefic/scope/family.rb +0 -43
- data/lib/gamefic/scope/myself.rb +0 -13
- data/lib/gamefic/scope/parent.rb +0 -13
- data/lib/gamefic/scope/siblings.rb +0 -14
- data/lib/gamefic/scope.rb +0 -9
- data/lib/gamefic/scriptable/actions.rb +0 -137
- data/lib/gamefic/scriptable/events.rb +0 -71
- data/lib/gamefic/scriptable/plot_proxies.rb +0 -29
- data/lib/gamefic/snapshot.rb +0 -44
- data/lib/gamefic/stage.rb +0 -51
- data/lib/gamefic/syntax/template.rb +0 -67
- data/lib/gamefic/vault.rb +0 -52
data/lib/gamefic/props/output.rb
CHANGED
|
@@ -59,13 +59,13 @@ module Gamefic
|
|
|
59
59
|
# @return [String, nil]
|
|
60
60
|
|
|
61
61
|
# @param key [Symbol]
|
|
62
|
-
def []
|
|
62
|
+
def [](key)
|
|
63
63
|
raw_data[key]
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
# @param key [Symbol]
|
|
67
67
|
# @param value [Object]
|
|
68
|
-
def []=
|
|
68
|
+
def []=(key, value)
|
|
69
69
|
raw_data[key] = value
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -74,15 +74,15 @@ module Gamefic
|
|
|
74
74
|
raw_data.dup
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def to_json
|
|
77
|
+
def to_json(_ = nil)
|
|
78
78
|
raw_data.to_json
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
def merge!
|
|
81
|
+
def merge!(data)
|
|
82
82
|
data.each { |key, val| self[key] = val }
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def replace
|
|
85
|
+
def replace(data)
|
|
86
86
|
raw_data.replace data
|
|
87
87
|
end
|
|
88
88
|
|
|
@@ -102,6 +102,8 @@ module Gamefic
|
|
|
102
102
|
def respond_to_missing?(method, _with_private = false)
|
|
103
103
|
READER_METHODS.include?(method) || WRITER_METHODS.include?(method)
|
|
104
104
|
end
|
|
105
|
+
|
|
106
|
+
EMPTY = new.freeze
|
|
105
107
|
end
|
|
106
108
|
end
|
|
107
109
|
end
|
|
@@ -4,7 +4,7 @@ module Gamefic
|
|
|
4
4
|
module Props
|
|
5
5
|
# A MultipleChoice variant that only allows Yes or No.
|
|
6
6
|
#
|
|
7
|
-
class YesOrNo <
|
|
7
|
+
class YesOrNo < MultiplePartial
|
|
8
8
|
def yes?
|
|
9
9
|
selection == 'Yes'
|
|
10
10
|
end
|
|
@@ -14,7 +14,7 @@ module Gamefic
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def options
|
|
17
|
-
@options ||= %w[Yes No]
|
|
17
|
+
@options ||= %w[Yes No]
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
end
|
data/lib/gamefic/props.rb
CHANGED
data/lib/gamefic/proxy/base.rb
CHANGED
|
@@ -1,27 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Gamefic
|
|
4
|
-
|
|
4
|
+
module Proxy
|
|
5
5
|
class Base
|
|
6
6
|
attr_reader :args
|
|
7
7
|
|
|
8
|
-
def initialize *args
|
|
8
|
+
def initialize *args
|
|
9
9
|
@args = args
|
|
10
|
-
@raise = raise
|
|
11
10
|
end
|
|
12
11
|
|
|
13
|
-
def
|
|
14
|
-
@raise
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def fetch narrative
|
|
18
|
-
result = select(narrative)
|
|
19
|
-
return result if result
|
|
20
|
-
raise "#{self.class} failed for #{args.inspect}" if raise?
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def select narrative
|
|
24
|
-
end
|
|
12
|
+
def fetch(narrative); end
|
|
25
13
|
end
|
|
26
14
|
end
|
|
27
15
|
end
|
data/lib/gamefic/proxy/config.rb
CHANGED
data/lib/gamefic/proxy/pick.rb
CHANGED
data/lib/gamefic/proxy.rb
CHANGED
|
@@ -1,79 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Gamefic
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
class Proxy
|
|
4
|
+
module Proxy
|
|
7
5
|
require 'gamefic/proxy/base'
|
|
6
|
+
require 'gamefic/proxy/attr'
|
|
8
7
|
require 'gamefic/proxy/config'
|
|
9
8
|
require 'gamefic/proxy/pick'
|
|
10
|
-
require 'gamefic/proxy/
|
|
11
|
-
|
|
12
|
-
TYPES = %i[attr ivar pick pick! plot_pick plot_pick! config].freeze
|
|
13
|
-
|
|
14
|
-
# @return [Symbol]
|
|
15
|
-
attr_reader :type
|
|
16
|
-
|
|
17
|
-
# @return [Symbol, Array<Symbol>, String, Integer]
|
|
18
|
-
attr_reader :key
|
|
19
|
-
|
|
20
|
-
# @param type [Symbol]
|
|
21
|
-
# @param key [Symbol, String, Array]
|
|
22
|
-
def initialize type, key
|
|
23
|
-
Gamefic.logger.debug "Using deprecated #{type} proxy"
|
|
24
|
-
@type = type
|
|
25
|
-
validate_type
|
|
26
|
-
@key = type == :config ? [key].compact : key
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def fetch narrative
|
|
30
|
-
send(type, narrative) ||
|
|
31
|
-
raise(ArgumentError, "Unable to fetch entity from proxy agent symbol `#{key}`")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def [](key)
|
|
35
|
-
raise ArgumentError, 'Invalid []' unless type == :config
|
|
36
|
-
|
|
37
|
-
@key.push key
|
|
38
|
-
self
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def attr narrative
|
|
44
|
-
Stage.run(narrative, [key].flatten) { |keys| keys.inject(self) { |obj, key| obj.send key } }
|
|
45
|
-
rescue NoMethodError
|
|
46
|
-
nil
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def ivar narrative
|
|
50
|
-
narrative.instance_variable_get key
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def pick narrative
|
|
54
|
-
narrative.pick *key
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def pick! narrative
|
|
58
|
-
narrative.pick! *key
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def plot_pick narrative
|
|
62
|
-
narrative.plot.pick *key
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def plot_pick! narrative
|
|
66
|
-
narrative.plot.pick! *key
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def config narrative
|
|
70
|
-
key.inject(narrative.config) { |hash, key| hash[key] }
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def validate_type
|
|
74
|
-
return if TYPES.include?(type)
|
|
75
|
-
|
|
76
|
-
raise ArgumentError, "Invalid proxy type `#{type}` (must be #{TYPES.join_or})"
|
|
77
|
-
end
|
|
9
|
+
require 'gamefic/proxy/pick_ex'
|
|
78
10
|
end
|
|
79
11
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# Query the subject's parent and accessible grandparents.
|
|
6
|
+
#
|
|
7
|
+
class Ascendants < Base
|
|
8
|
+
include Subqueries
|
|
9
|
+
|
|
10
|
+
def span(subject)
|
|
11
|
+
[subject.parent].tap { |result| result.push result.last.parent while result.last&.parent&.accessible&.include?(result.last) }
|
|
12
|
+
.compact
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/gamefic/query/base.rb
CHANGED
|
@@ -3,61 +3,46 @@
|
|
|
3
3
|
module Gamefic
|
|
4
4
|
module Query
|
|
5
5
|
# A base class for entity-based queries that can be applied to responses.
|
|
6
|
-
# Each query
|
|
7
|
-
#
|
|
6
|
+
# Each query matches a command token to an object that can be passed into
|
|
7
|
+
# a response callback.
|
|
8
|
+
#
|
|
9
|
+
# Most queries return entities, but there are also queries for plain text
|
|
10
|
+
# and integers.
|
|
8
11
|
#
|
|
9
12
|
class Base
|
|
10
13
|
# @return [Array<Object>]
|
|
11
14
|
attr_reader :arguments
|
|
12
15
|
|
|
13
|
-
# @return [Boolean]
|
|
14
|
-
attr_reader :ambiguous
|
|
15
|
-
|
|
16
|
-
attr_accessor :narrative
|
|
17
|
-
|
|
18
16
|
# @raise [ArgumentError] if any of the arguments are nil
|
|
19
17
|
#
|
|
20
18
|
# @param arguments [Array<Object>]
|
|
21
|
-
# @param ambiguous [Boolean]
|
|
22
19
|
# @param name [String]
|
|
23
|
-
def initialize *arguments,
|
|
20
|
+
def initialize *arguments, name: self.class.to_s
|
|
24
21
|
raise ArgumentError, "nil argument in query" if arguments.any?(&:nil?)
|
|
25
22
|
|
|
26
23
|
@arguments = arguments
|
|
27
|
-
@ambiguous = ambiguous
|
|
28
24
|
@name = name
|
|
29
25
|
end
|
|
30
26
|
|
|
31
27
|
# Get a query result for a given subject and token.
|
|
32
28
|
#
|
|
33
|
-
# @example
|
|
34
|
-
# respond :reds do |actor|
|
|
35
|
-
# reds = available(ambiguous: true).query(actor, 'red').match
|
|
36
|
-
# actor.tell "The red things you can see here are #{reds.join_and}."
|
|
37
|
-
# end
|
|
38
|
-
#
|
|
39
29
|
# @param subject [Gamefic::Entity]
|
|
40
30
|
# @param token [String]
|
|
41
31
|
# @return [Result]
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
unambiguous_result(first_pass.filter(*normalized_arguments))
|
|
48
|
-
else
|
|
49
|
-
unambiguous_result(first_pass)
|
|
50
|
-
end
|
|
32
|
+
def filter(subject, token)
|
|
33
|
+
scan = Scanner.scan(select(subject), token)
|
|
34
|
+
return Result.new(nil, scan.token) unless scan.matched.one?
|
|
35
|
+
|
|
36
|
+
Result.new(scan.matched.first, scan.remainder, scan.strictness)
|
|
51
37
|
end
|
|
52
|
-
alias filter query
|
|
53
38
|
|
|
54
39
|
# Get an array of entities that match the arguments from the context of
|
|
55
40
|
# the subject.
|
|
56
41
|
#
|
|
57
42
|
# @param subject [Entity]
|
|
58
43
|
# @return [Array<Entity>]
|
|
59
|
-
def select
|
|
60
|
-
span(subject).that_are(*
|
|
44
|
+
def select(subject)
|
|
45
|
+
span(subject).that_are(*arguments)
|
|
61
46
|
end
|
|
62
47
|
|
|
63
48
|
# Get an array of entities that are candidates for selection from the
|
|
@@ -68,47 +53,65 @@ module Gamefic
|
|
|
68
53
|
#
|
|
69
54
|
# @param subject [Entity]
|
|
70
55
|
# @return [Array<Entity>]
|
|
71
|
-
def span
|
|
56
|
+
def span(_subject)
|
|
72
57
|
[]
|
|
73
58
|
end
|
|
74
59
|
|
|
75
60
|
# True if the object is selectable by the subject.
|
|
76
61
|
#
|
|
77
62
|
# @param subject [Entity]
|
|
78
|
-
# @param object [
|
|
63
|
+
# @param object [Entity]
|
|
79
64
|
# @return [Boolean]
|
|
80
65
|
def accept?(subject, object)
|
|
81
|
-
|
|
82
|
-
if ambiguous?
|
|
83
|
-
object & available == object
|
|
84
|
-
else
|
|
85
|
-
available.include?(object)
|
|
86
|
-
end
|
|
66
|
+
select(subject).include?(object)
|
|
87
67
|
end
|
|
88
68
|
|
|
69
|
+
# The query's precision. The higher the number, the more specific the
|
|
70
|
+
# query is.
|
|
71
|
+
#
|
|
72
|
+
# In general terms, a query's precision is highest if its arguments
|
|
73
|
+
# select for a specific instance of an entity instead of a class of
|
|
74
|
+
# entity.
|
|
75
|
+
#
|
|
76
|
+
# When a command gets parsed, the resulting list of available actions
|
|
77
|
+
# gets sorted in descending order of their responses' overall precision,
|
|
78
|
+
# so the action with the highest precision gets attempted first.
|
|
79
|
+
#
|
|
89
80
|
# @return [Integer]
|
|
90
81
|
def precision
|
|
91
82
|
@precision ||= calculate_precision
|
|
92
83
|
end
|
|
93
84
|
|
|
94
|
-
def ambiguous?
|
|
95
|
-
@ambiguous
|
|
96
|
-
end
|
|
97
|
-
|
|
98
85
|
def name
|
|
99
86
|
@name || self.class.to_s
|
|
100
87
|
end
|
|
101
88
|
|
|
102
89
|
def inspect
|
|
103
|
-
"
|
|
90
|
+
"#{name}(#{arguments.map(&:inspect).join(', ')})"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def bind(narrative)
|
|
94
|
+
clone.tap do |query|
|
|
95
|
+
query.instance_exec do
|
|
96
|
+
@arguments = narrative.unproxy(@arguments)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.plain
|
|
102
|
+
@plain ||= new
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.span(subject)
|
|
106
|
+
plain.span(subject)
|
|
104
107
|
end
|
|
105
108
|
|
|
106
109
|
private
|
|
107
110
|
|
|
108
111
|
def calculate_precision
|
|
109
|
-
|
|
112
|
+
arguments.sum(0) do |arg|
|
|
110
113
|
case arg
|
|
111
|
-
when Entity, Proxy
|
|
114
|
+
when Entity, Proxy::Base
|
|
112
115
|
1000
|
|
113
116
|
when Class, Module
|
|
114
117
|
class_depth(arg) * 100
|
|
@@ -118,7 +121,7 @@ module Gamefic
|
|
|
118
121
|
end
|
|
119
122
|
end
|
|
120
123
|
|
|
121
|
-
def class_depth
|
|
124
|
+
def class_depth(klass)
|
|
122
125
|
return 1 unless klass.is_a?(Class)
|
|
123
126
|
|
|
124
127
|
depth = 1
|
|
@@ -126,35 +129,6 @@ module Gamefic
|
|
|
126
129
|
depth += 1 while (sup = sup.superclass)
|
|
127
130
|
depth
|
|
128
131
|
end
|
|
129
|
-
|
|
130
|
-
# @param scan [Scanner::Result]
|
|
131
|
-
def ambiguous_result scan
|
|
132
|
-
return Result.new(nil, scan.token) if scan.matched.empty?
|
|
133
|
-
|
|
134
|
-
Result.new(scan.matched, scan.remainder)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# @param scan [Scanner::Result]
|
|
138
|
-
def unambiguous_result scan
|
|
139
|
-
return Result.new(nil, scan.token) unless scan.matched.one?
|
|
140
|
-
|
|
141
|
-
Result.new(scan.matched.first, scan.remainder, scan.strictness)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def normalized_arguments
|
|
145
|
-
@normalized_arguments ||= arguments.map do |arg|
|
|
146
|
-
case arg
|
|
147
|
-
when Proxy, Proxy::Base
|
|
148
|
-
arg.fetch(narrative)
|
|
149
|
-
when String
|
|
150
|
-
proc do |entity|
|
|
151
|
-
arg.keywords.all? { |word| entity.keywords.include?(word) }
|
|
152
|
-
end
|
|
153
|
-
else
|
|
154
|
-
arg
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
132
|
end
|
|
159
133
|
end
|
|
160
134
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# Query the subject's children and accessible grandchildren.
|
|
6
|
+
#
|
|
7
|
+
class Descendants < Base
|
|
8
|
+
include Subqueries
|
|
9
|
+
|
|
10
|
+
def span(subject)
|
|
11
|
+
subject.children.flat_map do |child|
|
|
12
|
+
[child] + subquery_accessible(child)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# Query the subject's siblings and their descendants. Unlike `Family`, the
|
|
6
|
+
# subject's descendants are excluded from results.
|
|
7
|
+
#
|
|
8
|
+
# Descendants need to be `accessible` to be included in the query.
|
|
9
|
+
#
|
|
10
|
+
class Extended < Base
|
|
11
|
+
include Subqueries
|
|
12
|
+
|
|
13
|
+
def span(subject)
|
|
14
|
+
Siblings.span(subject).flat_map do |child|
|
|
15
|
+
[child] + subquery_accessible(child)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# Query the subject's ascendants, descendants, siblings, and siblings'
|
|
6
|
+
# descendants.
|
|
7
|
+
#
|
|
8
|
+
# Entities other than the subject's parent and immediate children need to
|
|
9
|
+
# be `accessible` to be included in the query.
|
|
10
|
+
#
|
|
11
|
+
class Family < Base
|
|
12
|
+
include Subqueries
|
|
13
|
+
|
|
14
|
+
def span(subject)
|
|
15
|
+
Ascendants.span(subject) + Descendants.span(subject) + match_sibling_branches(subject)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def match_sibling_branches(subject)
|
|
21
|
+
Siblings.span(subject).flat_map do |child|
|
|
22
|
+
[child] + subquery_accessible(child)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# Query all the entities in the subject's epic.
|
|
6
|
+
#
|
|
7
|
+
# If the subject is not an actor, this query will always return an empty
|
|
8
|
+
# result.
|
|
9
|
+
#
|
|
10
|
+
class Global < Base
|
|
11
|
+
def span(subject)
|
|
12
|
+
return [] unless subject.is_a?(Active)
|
|
13
|
+
|
|
14
|
+
subject.narratives.entities
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def precision
|
|
18
|
+
@precision ||= super - 2000
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gamefic
|
|
4
|
+
module Query
|
|
5
|
+
# A special query that handles integers instead of entities.
|
|
6
|
+
#
|
|
7
|
+
class Integer < Base
|
|
8
|
+
# @param name [String, nil]
|
|
9
|
+
def initialize(name: self.class.name)
|
|
10
|
+
super(name: name)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def filter(_subject, token)
|
|
14
|
+
return Result.new(token, '') if token.is_a?(::Integer)
|
|
15
|
+
|
|
16
|
+
words = token.keywords
|
|
17
|
+
number = words.shift
|
|
18
|
+
return Result.new(nil, token) unless number =~ /\d+/
|
|
19
|
+
|
|
20
|
+
Result.new(number.to_i, words.join(' '))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def precision
|
|
24
|
+
-10_000
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def accept?(_subject, token)
|
|
28
|
+
token.is_a?(::Integer)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/gamefic/query/result.rb
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Gamefic
|
|
2
|
+
module Query
|
|
3
|
+
module Subqueries
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
# Return an array of the entity's accessible descendants.
|
|
7
|
+
#
|
|
8
|
+
# @param entity [Entity]
|
|
9
|
+
# @return [Array<Entity>]
|
|
10
|
+
def subquery_accessible(entity)
|
|
11
|
+
entity.accessible.flat_map do |child|
|
|
12
|
+
[child] + subquery_accessible(child)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|