gamefic 3.3.0 → 3.5.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/CHANGELOG.md +20 -0
- data/README.md +1 -1
- data/lib/gamefic/action.rb +4 -4
- data/lib/gamefic/active/epic.rb +1 -0
- data/lib/gamefic/active.rb +4 -0
- data/lib/gamefic/callback.rb +16 -0
- data/lib/gamefic/chapter.rb +71 -0
- data/lib/gamefic/command.rb +40 -1
- data/lib/gamefic/dispatcher.rb +5 -31
- data/lib/gamefic/entity.rb +26 -0
- data/lib/gamefic/narrative.rb +30 -8
- data/lib/gamefic/plot.rb +28 -1
- data/lib/gamefic/proxy.rb +46 -0
- data/lib/gamefic/query/base.rb +28 -12
- data/lib/gamefic/query/general.rb +3 -12
- data/lib/gamefic/query/result.rb +4 -1
- data/lib/gamefic/query/scoped.rb +1 -18
- data/lib/gamefic/query/text.rb +13 -12
- data/lib/gamefic/response.rb +66 -38
- data/lib/gamefic/rulebook/calls.rb +0 -4
- data/lib/gamefic/rulebook/events.rb +10 -24
- data/lib/gamefic/rulebook/hooks.rb +10 -10
- data/lib/gamefic/rulebook.rb +8 -22
- data/lib/gamefic/scanner/base.rb +44 -0
- data/lib/gamefic/scanner/fuzzy.rb +17 -0
- data/lib/gamefic/scanner/fuzzy_nesting.rb +14 -0
- data/lib/gamefic/scanner/nesting.rb +39 -0
- data/lib/gamefic/scanner/result.rb +50 -0
- data/lib/gamefic/scanner/strict.rb +31 -0
- data/lib/gamefic/scanner.rb +33 -111
- data/lib/gamefic/scope/descendants.rb +16 -0
- data/lib/gamefic/scope/family.rb +31 -8
- data/lib/gamefic/scope.rb +1 -0
- data/lib/gamefic/scriptable/actions.rb +8 -27
- data/lib/gamefic/scriptable/entities.rb +4 -1
- data/lib/gamefic/scriptable/events.rb +13 -7
- data/lib/gamefic/scriptable/plot_proxies.rb +16 -0
- data/lib/gamefic/scriptable/proxies.rb +31 -0
- data/lib/gamefic/scriptable/queries.rb +15 -7
- data/lib/gamefic/scriptable/scenes.rb +10 -4
- data/lib/gamefic/scriptable.rb +73 -42
- data/lib/gamefic/stage.rb +2 -2
- data/lib/gamefic/subplot.rb +31 -7
- data/lib/gamefic/version.rb +1 -1
- data/lib/gamefic.rb +3 -1
- metadata +14 -4
- data/lib/gamefic/composer.rb +0 -70
- data/lib/gamefic/scriptable/proxy.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79309729d2296ceec16e10d3380fba331512f15ca2d303788c1fbcc83c077457
|
4
|
+
data.tar.gz: f4ce7d947730da4e833d895ae3085c4027d80cf89306b3aeff03d1a2a6ecd2aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01c7c68bdc217447d90bda4c2bdd362e318c644dc3486999f6125d6c124193e0b33782a250272a2455ea98e2f531551f3819611c4139b191d3dccaa61d9e03d8
|
7
|
+
data.tar.gz: '06101965d9a47188f2b5b22e87f4f7b4bbeefd5f102d2405e1457c8a389a732e782cd4eedccec2176f2b237ad3783b1ab0058ce2721e451caa29e4e8a6d52cdc'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## 3.5.0
|
2
|
+
- Configurable scanners
|
3
|
+
- Refactored scanners and queries
|
4
|
+
- Allow assignment to nil instance variables in stage
|
5
|
+
- Lazy proxies
|
6
|
+
- Remove buggy index proxies
|
7
|
+
- Chapter inherits Narrative
|
8
|
+
- Plot attribute proxy for chapters and subplots
|
9
|
+
- Entity#leave
|
10
|
+
- Descendants query
|
11
|
+
- Persistent subplots
|
12
|
+
- Entity#broadcast
|
13
|
+
- Ascendants in family query
|
14
|
+
|
15
|
+
## 3.4.0 - September 10, 2024
|
16
|
+
- Chapters
|
17
|
+
- Subplots and chapters do not repeat plot scripts
|
18
|
+
- Scriptable.no_scripts is deprecated
|
19
|
+
- Refactoring/removing unused methods
|
20
|
+
|
1
21
|
## 3.3.0 - September 1, 2024
|
2
22
|
- Node#take
|
3
23
|
- Node#include?
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
16
16
|
|
17
17
|
## Contributing
|
18
18
|
|
19
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/castwide/gamefic
|
19
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/castwide/gamefic.
|
20
20
|
|
21
21
|
## License
|
22
22
|
|
data/lib/gamefic/action.rb
CHANGED
@@ -16,12 +16,12 @@ module Gamefic
|
|
16
16
|
# @param [Array<Symbol>]
|
17
17
|
attr_reader :verbs
|
18
18
|
|
19
|
-
# @param [
|
20
|
-
attr_reader :
|
19
|
+
# @param [Callback]
|
20
|
+
attr_reader :callback
|
21
21
|
|
22
|
-
def initialize
|
22
|
+
def initialize verbs, callback
|
23
23
|
@verbs = verbs
|
24
|
-
@
|
24
|
+
@callback = callback
|
25
25
|
end
|
26
26
|
|
27
27
|
def match?(input)
|
data/lib/gamefic/active/epic.rb
CHANGED
data/lib/gamefic/active.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
class Callback
|
5
|
+
# @param narrative [Narrative]
|
6
|
+
# @param code [Proc]
|
7
|
+
def initialize narrative, code
|
8
|
+
@narrative = narrative
|
9
|
+
@code = code
|
10
|
+
end
|
11
|
+
|
12
|
+
def run *args
|
13
|
+
Stage.run @narrative, *args, &@code
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
# Chapters are plot extensions that manage their own namespaces. Authors can
|
5
|
+
# use them to encapsulate related content in a separate object instead of
|
6
|
+
# adding the required instance variables, methods, and attributes to the
|
7
|
+
# plot.
|
8
|
+
#
|
9
|
+
# Chapters are similar to subplots with three important exceptions:
|
10
|
+
# * Chapters normally persist for the duration of a plot.
|
11
|
+
# * Players do not need to be introduced to a chapter.
|
12
|
+
# * Chapters share their plot's entities, players, and rulebook.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# class MyChapter < Gamefic::Chapter
|
16
|
+
# def thing
|
17
|
+
# @thing ||= make Gamefic::Entity, name: 'chapter thing'
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# class MyPlot < Gamefic::Plot
|
22
|
+
# append MyChapter
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# plot = MyPlot.new
|
26
|
+
# plot.entities #=> [<#Gamefic::Entity a chapter thing>]
|
27
|
+
# plot.thing # raises NoMethodError
|
28
|
+
# plot.chapters.first.thing #=> <#Gamefic::Entity a chapter thing>
|
29
|
+
#
|
30
|
+
class Chapter < Narrative
|
31
|
+
extend Scriptable::PlotProxies
|
32
|
+
|
33
|
+
# @return [Plot]
|
34
|
+
attr_reader :plot
|
35
|
+
|
36
|
+
# @param plot [Plot]
|
37
|
+
def initialize(plot)
|
38
|
+
@plot = plot
|
39
|
+
# The plot is responsible for hydrating chapters
|
40
|
+
super(hydrate: false)
|
41
|
+
end
|
42
|
+
|
43
|
+
def script
|
44
|
+
included_blocks.select(&:script?).each { |blk| Stage.run self, &blk.code }
|
45
|
+
end
|
46
|
+
|
47
|
+
def included_blocks
|
48
|
+
self.class.included_blocks - plot.included_blocks
|
49
|
+
end
|
50
|
+
|
51
|
+
def rulebook
|
52
|
+
plot.rulebook
|
53
|
+
end
|
54
|
+
|
55
|
+
def entity_vault
|
56
|
+
plot.entity_vault
|
57
|
+
end
|
58
|
+
|
59
|
+
def player_vault
|
60
|
+
plot.player_vault
|
61
|
+
end
|
62
|
+
|
63
|
+
def subplots
|
64
|
+
plot.subplots
|
65
|
+
end
|
66
|
+
|
67
|
+
def branch(...)
|
68
|
+
plot.branch(...)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/gamefic/command.rb
CHANGED
@@ -10,11 +10,50 @@ module Gamefic
|
|
10
10
|
# @return [Array<Array<Entity>, Entity, String>]
|
11
11
|
attr_reader :arguments
|
12
12
|
|
13
|
+
# @return [Integer]
|
14
|
+
attr_reader :strictness
|
15
|
+
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :precision
|
18
|
+
|
13
19
|
# @param verb [Symbol]
|
14
20
|
# @param arguments [Array<Array<Entity>, Entity, String>]
|
15
|
-
|
21
|
+
# @param strictness [Integer]
|
22
|
+
# @param precision [Integer]
|
23
|
+
#
|
24
|
+
# @todo Consider making strictness and precision required or providing
|
25
|
+
# another generator
|
26
|
+
def initialize verb, arguments, strictness = 0, precision = 0
|
16
27
|
@verb = verb
|
17
28
|
@arguments = arguments
|
29
|
+
@strictness = strictness
|
30
|
+
@precision = precision
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Compose a command from input.
|
35
|
+
#
|
36
|
+
# @param actor [Actor]
|
37
|
+
# @param input [String]
|
38
|
+
# @return [Command]
|
39
|
+
def compose actor, input
|
40
|
+
expressions = Syntax.tokenize(input, actor.epic.syntaxes)
|
41
|
+
expressions.flat_map { |expression| expression_to_commands(actor, expression) }
|
42
|
+
.first || Command.new(nil, [])
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# @param actor [Actor]
|
48
|
+
# @param expression [Expression]
|
49
|
+
# @return [Array<Command>]
|
50
|
+
def expression_to_commands actor, expression
|
51
|
+
actor.epic
|
52
|
+
.responses_for(expression.verb)
|
53
|
+
.map { |response| response.to_command(actor, expression) }
|
54
|
+
.compact
|
55
|
+
.sort_by.with_index { |result, idx| [-result.precision, -result.strictness, idx] }
|
56
|
+
end
|
18
57
|
end
|
19
58
|
end
|
20
59
|
end
|
data/lib/gamefic/dispatcher.rb
CHANGED
@@ -10,7 +10,6 @@ module Gamefic
|
|
10
10
|
@actor = actor
|
11
11
|
@command = command
|
12
12
|
@executed = false
|
13
|
-
@finalized = false
|
14
13
|
end
|
15
14
|
|
16
15
|
# Run the dispatcher.
|
@@ -23,11 +22,11 @@ module Gamefic
|
|
23
22
|
action = next_action
|
24
23
|
return unless action
|
25
24
|
|
26
|
-
|
25
|
+
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_before_actions action }
|
27
26
|
return if action.cancelled?
|
28
27
|
|
29
28
|
action.execute
|
30
|
-
|
29
|
+
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_after_actions action }
|
31
30
|
action
|
32
31
|
end
|
33
32
|
|
@@ -46,9 +45,9 @@ module Gamefic
|
|
46
45
|
# @param input [String]
|
47
46
|
# @return [Dispatcher]
|
48
47
|
def self.dispatch actor, input
|
49
|
-
expressions = Syntax.tokenize(input, actor.epic.syntaxes)
|
50
|
-
|
51
|
-
new(actor,
|
48
|
+
# expressions = Syntax.tokenize(input, actor.epic.syntaxes)
|
49
|
+
# new(actor, Command.compose(actor, expressions))
|
50
|
+
new(actor, Command.compose(actor, input))
|
52
51
|
end
|
53
52
|
|
54
53
|
# @param actor [Active]
|
@@ -82,31 +81,6 @@ module Gamefic
|
|
82
81
|
|
83
82
|
return Action.new(actor, @command.arguments, response) if response.accept?(actor, @command)
|
84
83
|
end
|
85
|
-
finalize
|
86
|
-
end
|
87
|
-
|
88
|
-
# @return [void]
|
89
|
-
def run_before_action_hooks action
|
90
|
-
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_before_actions action }
|
91
|
-
end
|
92
|
-
|
93
|
-
# @return [void]
|
94
|
-
def run_after_action_hooks action
|
95
|
-
actor.epic.rulebooks.flat_map { |rlbk| rlbk.run_after_actions action }
|
96
|
-
end
|
97
|
-
|
98
|
-
# If the dispatcher proceeds through all possible responses, it can fall
|
99
|
-
# back to a nil response as a catchall for commands that could not be
|
100
|
-
# completed.
|
101
|
-
#
|
102
|
-
# @return [Action, nil]
|
103
|
-
def finalize
|
104
|
-
return nil if @finalized
|
105
|
-
|
106
|
-
@finalized = true
|
107
|
-
@command = Command.new(nil, ["#{command.verb} #{command.arguments.join(' ').strip}"])
|
108
|
-
@responses = actor.epic.responses_for(nil)
|
109
|
-
next_action
|
110
84
|
end
|
111
85
|
end
|
112
86
|
end
|
data/lib/gamefic/entity.rb
CHANGED
@@ -55,6 +55,32 @@ module Gamefic
|
|
55
55
|
"#<#{self.class} #{name}>"
|
56
56
|
end
|
57
57
|
|
58
|
+
# Move this entity to its parent entity.
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# room = Gamefic::Entity.new(name: 'room')
|
62
|
+
# person = Gamefic::Entity.new(name: 'person', parent: room)
|
63
|
+
# thing = Gamefic::Entity.new(name: 'thing', parent: person)
|
64
|
+
#
|
65
|
+
# thing.parent #=> person
|
66
|
+
# thing.leave
|
67
|
+
# thing.parent #=> room
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
def leave
|
71
|
+
self.parent = parent&.parent
|
72
|
+
end
|
73
|
+
|
74
|
+
# Tell a message to all of this entity's accessible descendants.
|
75
|
+
#
|
76
|
+
# @param message [String]
|
77
|
+
# @return [void]
|
78
|
+
def broadcast message
|
79
|
+
Query::Scoped.new(Scope::Descendants).select(self)
|
80
|
+
.that_are(Active, proc(&:acting?))
|
81
|
+
.each { |actor| actor.tell message }
|
82
|
+
end
|
83
|
+
|
58
84
|
class << self
|
59
85
|
# Set or update the default attributes for new instances.
|
60
86
|
#
|
data/lib/gamefic/narrative.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
|
3
5
|
module Gamefic
|
4
6
|
# A base class for building and managing the resources that compose a story.
|
5
7
|
# The Plot and Subplot classes inherit from Narrative and provide additional
|
@@ -12,19 +14,40 @@ module Gamefic
|
|
12
14
|
include Scriptable::Actions
|
13
15
|
include Scriptable::Entities
|
14
16
|
include Scriptable::Events
|
15
|
-
include Scriptable::
|
17
|
+
include Scriptable::Proxies
|
16
18
|
include Scriptable::Queries
|
17
19
|
include Scriptable::Scenes
|
18
20
|
|
19
21
|
attr_reader :rulebook
|
20
22
|
|
21
|
-
def initialize
|
22
|
-
|
23
|
+
def initialize(hydrate: true)
|
24
|
+
return unless hydrate
|
25
|
+
|
26
|
+
seed
|
27
|
+
script
|
28
|
+
post_script
|
29
|
+
end
|
30
|
+
|
31
|
+
def seed
|
32
|
+
included_blocks.select(&:seed?).each { |blk| Stage.run self, &blk.code }
|
33
|
+
end
|
34
|
+
|
35
|
+
def script
|
36
|
+
@rulebook = Rulebook.new
|
37
|
+
included_blocks.select(&:script?).each { |blk| Stage.run self, &blk.code }
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Array<Module>]
|
41
|
+
def included_blocks
|
42
|
+
self.class.included_blocks
|
43
|
+
end
|
44
|
+
|
45
|
+
def post_script
|
23
46
|
entity_vault.lock
|
24
|
-
|
25
|
-
hydrate
|
47
|
+
rulebook.freeze
|
26
48
|
end
|
27
49
|
|
50
|
+
# @return [Array<Symbol>]
|
28
51
|
def scenes
|
29
52
|
rulebook.scenes.names
|
30
53
|
end
|
@@ -91,9 +114,8 @@ module Gamefic
|
|
91
114
|
end
|
92
115
|
|
93
116
|
def hydrate
|
94
|
-
|
95
|
-
|
96
|
-
@rulebook.freeze
|
117
|
+
script
|
118
|
+
post_script
|
97
119
|
end
|
98
120
|
|
99
121
|
def self.inherited klass
|
data/lib/gamefic/plot.rb
CHANGED
@@ -5,12 +5,31 @@ module Gamefic
|
|
5
5
|
# methods for creating entities, actions, scenes, and hooks.
|
6
6
|
#
|
7
7
|
class Plot < Narrative
|
8
|
+
def seed
|
9
|
+
super
|
10
|
+
chapters.each(&:seed)
|
11
|
+
end
|
12
|
+
|
13
|
+
def script
|
14
|
+
super
|
15
|
+
chapters.each(&:script)
|
16
|
+
rulebook.scenes.with_defaults self
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_script
|
20
|
+
super
|
21
|
+
chapters.freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
def chapters
|
25
|
+
@chapters ||= self.class.appended_chapters.map { |klass| klass.new(self) }
|
26
|
+
end
|
27
|
+
|
8
28
|
def ready
|
9
29
|
super
|
10
30
|
subplots.each(&:ready)
|
11
31
|
players.each(&:start_take)
|
12
32
|
subplots.each(&:conclude) if concluding?
|
13
|
-
|
14
33
|
players.select(&:concluding?).each { |plyr| rulebook.run_player_conclude_blocks plyr }
|
15
34
|
subplots.delete_if(&:concluding?)
|
16
35
|
end
|
@@ -76,6 +95,14 @@ module Gamefic
|
|
76
95
|
subplots.each(&:hydrate)
|
77
96
|
end
|
78
97
|
|
98
|
+
def self.append chapter
|
99
|
+
appended_chapters.add chapter
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.appended_chapters
|
103
|
+
@appended_chapters ||= Set.new
|
104
|
+
end
|
105
|
+
|
79
106
|
def self.restore data
|
80
107
|
Snapshot.restore data
|
81
108
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
class Proxy
|
5
|
+
# @return [Symbol]
|
6
|
+
attr_reader :type
|
7
|
+
|
8
|
+
# @return [Symbol, Array<Symbol>, String, Integer]
|
9
|
+
attr_reader :key
|
10
|
+
|
11
|
+
# @param type [Symbol]
|
12
|
+
# @param key [Symbol, String]
|
13
|
+
def initialize type, key
|
14
|
+
@type = type
|
15
|
+
@key = key
|
16
|
+
validate_type
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch narrative
|
20
|
+
send(type, narrative) ||
|
21
|
+
raise(ArgumentError, "Unable to fetch entity from proxy agent symbol `#{key}`")
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def attr narrative
|
27
|
+
Stage.run(narrative, [key].flatten) { |keys| keys.inject(self) { |obj, key| obj.send key } }
|
28
|
+
rescue NoMethodError
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def ivar narrative
|
33
|
+
narrative.instance_variable_get key
|
34
|
+
end
|
35
|
+
|
36
|
+
def pick narrative
|
37
|
+
narrative.pick! key
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_type
|
41
|
+
return if [:attr, :ivar, :pick].include?(type)
|
42
|
+
|
43
|
+
raise ArgumentError, "Invalid proxy type `#{type}` (must be :attr, :ivar, or :pick)"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/gamefic/query/base.rb
CHANGED
@@ -13,6 +13,8 @@ module Gamefic
|
|
13
13
|
# @return [Boolean]
|
14
14
|
attr_reader :ambiguous
|
15
15
|
|
16
|
+
attr_accessor :narrative
|
17
|
+
|
16
18
|
# @raise [ArgumentError] if any of the arguments are nil
|
17
19
|
#
|
18
20
|
# @param arguments [Array<Object>]
|
@@ -26,12 +28,6 @@ module Gamefic
|
|
26
28
|
|
27
29
|
# Get a query result for a given subject and token.
|
28
30
|
#
|
29
|
-
# @note This method is retained as a convenience for authors. Narratives
|
30
|
-
# should use Composer to build commands, as it provides more precise
|
31
|
-
# matching of tokens to valid response arguments. Authors can use
|
32
|
-
# #query to find entities that match a token regardless of whether the
|
33
|
-
# result matches an available response.
|
34
|
-
#
|
35
31
|
# @example
|
36
32
|
# respond :reds do |actor|
|
37
33
|
# reds = available(ambiguous: true).query(actor, 'red').match
|
@@ -41,19 +37,28 @@ module Gamefic
|
|
41
37
|
# @param subject [Gamefic::Entity]
|
42
38
|
# @param token [String]
|
43
39
|
# @return [Result]
|
44
|
-
def query(
|
45
|
-
|
40
|
+
def query(subject, token)
|
41
|
+
scan = Scanner.scan(select(subject), token)
|
42
|
+
ambiguous? ? ambiguous_result(scan) : unambiguous_result(scan)
|
46
43
|
end
|
44
|
+
alias filter query
|
47
45
|
|
48
46
|
# Get an array of entities that match the query from the context of the
|
49
47
|
# subject.
|
50
48
|
#
|
49
|
+
# Subclasses should override this method.
|
50
|
+
#
|
51
51
|
# @param subject [Entity]
|
52
52
|
# @return [Array<Entity>]
|
53
53
|
def select _subject
|
54
|
-
|
54
|
+
[]
|
55
55
|
end
|
56
56
|
|
57
|
+
# True if the object is selectable by the subject.
|
58
|
+
#
|
59
|
+
# @param subject [Entity]
|
60
|
+
# @param object [Array<Entity>, Entity]
|
61
|
+
# @return [Boolean]
|
57
62
|
def accept?(subject, object)
|
58
63
|
available = select(subject)
|
59
64
|
if ambiguous?
|
@@ -75,9 +80,9 @@ module Gamefic
|
|
75
80
|
private
|
76
81
|
|
77
82
|
def calculate_precision
|
78
|
-
|
83
|
+
unproxied_arguments.sum(@ambiguous ? -1000 : 0) do |arg|
|
79
84
|
case arg
|
80
|
-
when Entity,
|
85
|
+
when Entity, Proxy
|
81
86
|
1000
|
82
87
|
when Class, Module
|
83
88
|
class_depth(arg) * 100
|
@@ -107,7 +112,18 @@ module Gamefic
|
|
107
112
|
def unambiguous_result scan
|
108
113
|
return Result.new(nil, scan.token) unless scan.matched.one?
|
109
114
|
|
110
|
-
Result.new(scan.matched.first, scan.remainder)
|
115
|
+
Result.new(scan.matched.first, scan.remainder, scan.strictness)
|
116
|
+
end
|
117
|
+
|
118
|
+
def unproxied_arguments
|
119
|
+
@unproxied_arguments ||= arguments.map do |arg|
|
120
|
+
case arg
|
121
|
+
when Proxy
|
122
|
+
arg.fetch(narrative)
|
123
|
+
else
|
124
|
+
arg
|
125
|
+
end
|
126
|
+
end
|
111
127
|
end
|
112
128
|
end
|
113
129
|
end
|
@@ -20,16 +20,7 @@ module Gamefic
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def select subject
|
23
|
-
available_entities(subject).that_are(
|
24
|
-
end
|
25
|
-
|
26
|
-
def query subject, token
|
27
|
-
filtered = available_entities(subject).that_are(*@arguments)
|
28
|
-
return Result.new(token, nil) if filtered.include?(token)
|
29
|
-
|
30
|
-
scan = Scanner.scan(filtered, token)
|
31
|
-
|
32
|
-
ambiguous? ? ambiguous_result(scan) : unambiguous_result(scan)
|
23
|
+
available_entities(subject).that_are(*unproxied_arguments)
|
33
24
|
end
|
34
25
|
|
35
26
|
private
|
@@ -37,9 +28,9 @@ module Gamefic
|
|
37
28
|
def available_entities(subject)
|
38
29
|
if @entities.is_a?(Proc)
|
39
30
|
if @entities.arity.zero?
|
40
|
-
|
31
|
+
Stage.run narrative, &@entities
|
41
32
|
else
|
42
|
-
|
33
|
+
Stage.run narrative, subject, &@entities
|
43
34
|
end
|
44
35
|
else
|
45
36
|
@entities
|
data/lib/gamefic/query/result.rb
CHANGED
@@ -11,9 +11,12 @@ module Gamefic
|
|
11
11
|
# @return [String]
|
12
12
|
attr_reader :remainder
|
13
13
|
|
14
|
-
|
14
|
+
attr_reader :strictness
|
15
|
+
|
16
|
+
def initialize match, remainder, strictness = 0
|
15
17
|
@match = match
|
16
18
|
@remainder = remainder
|
19
|
+
@strictness = strictness
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
data/lib/gamefic/query/scoped.rb
CHANGED
@@ -17,29 +17,12 @@ module Gamefic
|
|
17
17
|
|
18
18
|
def select(subject)
|
19
19
|
@scope.matches(subject)
|
20
|
-
.that_are(
|
21
|
-
end
|
22
|
-
|
23
|
-
# @return [Result]
|
24
|
-
def query(subject, token)
|
25
|
-
available = @scope.matches(subject)
|
26
|
-
.that_are(*@arguments)
|
27
|
-
return Result.new(token, nil) if available.include?(token)
|
28
|
-
|
29
|
-
scan = Scanner.scan(available, token)
|
30
|
-
|
31
|
-
return ambiguous_result(scan) if ambiguous?
|
32
|
-
|
33
|
-
unambiguous_result(scan)
|
20
|
+
.that_are(*unproxied_arguments)
|
34
21
|
end
|
35
22
|
|
36
23
|
def precision
|
37
24
|
@precision ||= @scope.precision + calculate_precision
|
38
25
|
end
|
39
|
-
|
40
|
-
def ambiguous?
|
41
|
-
@ambiguous
|
42
|
-
end
|
43
26
|
end
|
44
27
|
end
|
45
28
|
end
|