gamefic 3.3.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|