gamefic 2.0.2 → 2.2.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.
@@ -7,17 +7,20 @@ module Gamefic
7
7
  #
8
8
  class Element
9
9
  include Gamefic::Describable
10
- # include Gamefic::Index
11
10
  include Gamefic::Serialize
12
11
 
13
- # @todo It would be nice if this initialization wasn't necessary.
14
12
  def initialize(args = {})
15
- # super self.class.default_attributes.merge(args)
16
- self.class.default_attributes.merge(args).each_pair do |k, v|
17
- public_send "#{k}=", v
18
- end
19
- post_initialize
20
- yield self if block_given?
13
+ klass = self.class
14
+ defaults = {}
15
+ while klass <= Element
16
+ defaults = klass.default_attributes.merge(defaults)
17
+ klass = klass.superclass
18
+ end
19
+ defaults.merge(args).each_pair do |k, v|
20
+ public_send "#{k}=", v
21
+ end
22
+ post_initialize
23
+ yield self if block_given?
21
24
  end
22
25
 
23
26
  def post_initialize
@@ -38,10 +41,6 @@ module Gamefic
38
41
  def default_attributes
39
42
  @default_attributes ||= {}
40
43
  end
41
-
42
- def inherited subclass
43
- subclass.set_default default_attributes
44
- end
45
44
  end
46
45
  end
47
46
  end
@@ -13,10 +13,10 @@ module Gamefic
13
13
 
14
14
  # Set the Entity's parent.
15
15
  #
16
- # @param node [Gamefic::Entity] The new parent.
16
+ # @param node [Gamefic::Entity, nil] The new parent.
17
17
  def parent=(node)
18
- if node != nil and node.kind_of?(Entity) == false
19
- raise "Entity's parent must be an Entity"
18
+ if node && node.is_a?(Entity) == false
19
+ raise ArgumentError, "Entity's parent must be an Entity"
20
20
  end
21
21
  super
22
22
  end
data/lib/gamefic/plot.rb CHANGED
@@ -27,7 +27,6 @@ module Gamefic
27
27
 
28
28
  exclude_from_serial [:@static]
29
29
 
30
- # @param structure [Gamefic::Structure]
31
30
  # @param metadata [Hash]
32
31
  def initialize metadata: {}
33
32
  @metadata = metadata
@@ -35,11 +34,6 @@ module Gamefic
35
34
  @static = [self] + scene_classes + entities
36
35
  end
37
36
 
38
- def player_class cls = nil
39
- @player_class = cls unless cls.nil?
40
- @player_class ||= Gamefic::Actor
41
- end
42
-
43
37
  # Get an Array of the Plot's current Syntaxes.
44
38
  #
45
39
  # @return [Array<Syntax>]
@@ -80,7 +74,6 @@ module Gamefic
80
74
  entities.each { |e| e.flush }
81
75
  call_before_player_update
82
76
  players.each do |p|
83
- p.performed nil
84
77
  next unless p.scene
85
78
  p.last_input = p.queue.last
86
79
  p.last_prompt = p.scene.prompt
@@ -93,8 +86,8 @@ module Gamefic
93
86
  end
94
87
  call_player_update
95
88
  call_update
96
- subplots.each { |s| s.update unless s.concluded? }
97
- subplots.delete_if { |s| s.concluded? }
89
+ subplots.delete_if(&:concluded?)
90
+ subplots.each(&:update)
98
91
  end
99
92
 
100
93
  # Send a message to a group of entities.
@@ -55,13 +55,18 @@ module Gamefic
55
55
  result.include?(object)
56
56
  end
57
57
 
58
+ # A ranking of how precise the query's arguments are.
59
+ #
60
+ # Query precision is a factor in calculating Action#rank.
61
+ #
62
+ # @return [Integer]
58
63
  def precision
59
64
  if @precision.nil?
60
65
  @precision = 1
61
66
  arguments.each { |a|
62
- if a.kind_of?(Class)
67
+ if a.is_a?(Class)
63
68
  @precision += 100
64
- elsif a.kind_of?(Gamefic::Entity)
69
+ elsif a.is_a?(Gamefic::Entity)
65
70
  @precision += 1000
66
71
  end
67
72
  }
@@ -69,10 +74,7 @@ module Gamefic
69
74
  end
70
75
  @precision
71
76
  end
72
-
73
- def rank
74
- precision
75
- end
77
+ alias rank precision
76
78
 
77
79
  def signature
78
80
  "#{self.class.to_s.split('::').last.downcase}(#{simplify_arguments.join(', ')})"
@@ -83,18 +85,18 @@ module Gamefic
83
85
  # @return [Boolean]
84
86
  def accept?(entity)
85
87
  result = true
86
- arguments.each { |a|
87
- if a.kind_of?(Symbol)
88
- result = (entity.send(a) != false)
89
- elsif a.kind_of?(Regexp)
90
- result = (!entity.to_s.match(a).nil?)
91
- elsif a.is_a?(Module) or a.is_a?(Class)
92
- result = (entity.is_a?(a))
88
+ arguments.each do |a|
89
+ result = if a.is_a?(Symbol)
90
+ (entity.send(a) != false)
91
+ elsif a.is_a?(Regexp)
92
+ !entity.to_s.match(a).nil?
93
+ elsif a.is_a?(Module) || a.is_a?(Class)
94
+ entity.is_a?(a)
93
95
  else
94
- result = (entity == a)
96
+ (entity == a)
95
97
  end
96
98
  break if result == false
97
- }
99
+ end
98
100
  result
99
101
  end
100
102
 
@@ -109,10 +111,10 @@ module Gamefic
109
111
  return [] if entity.nil?
110
112
  result = []
111
113
  if entity.accessible?
112
- entity.children.each { |c|
114
+ entity.children.each do |c|
113
115
  result.push c
114
116
  result.concat subquery_accessible(c)
115
- }
117
+ end
116
118
  end
117
119
  result
118
120
  end
@@ -121,7 +123,7 @@ module Gamefic
121
123
 
122
124
  def simplify_arguments
123
125
  arguments.map do |a|
124
- if a.kind_of?(Class) or a.kind_of?(Object)
126
+ if a.is_a?(Class) || a.is_a?(Object)
125
127
  a.to_s.split('::').last.downcase
126
128
  else
127
129
  a.to_s.downcase
@@ -136,13 +138,12 @@ module Gamefic
136
138
  def denest(objects, token)
137
139
  parts = token.split(NEST_REGEXP)
138
140
  current = parts.pop
139
- last_result = objects.select{ |e| e.specified?(current) }
140
- last_result = objects.select{ |e| e.specified?(current, fuzzy: true) } if last_result.empty?
141
- result = last_result
142
- while parts.length > 0
141
+ last_result = objects.select { |e| e.specified?(current) }
142
+ last_result = objects.select { |e| e.specified?(current, fuzzy: true) } if last_result.empty?
143
+ until parts.empty?
143
144
  current = "#{parts.last} #{current}"
144
- result = last_result.select{ |e| e.specified?(current) }
145
- result = last_result.select{ |e| e.specified?(current, fuzzy: true) } if result.empty?
145
+ result = last_result.select { |e| e.specified?(current) }
146
+ result = last_result.select { |e| e.specified?(current, fuzzy: true) } if result.empty?
146
147
  break if result.empty?
147
148
  parts.pop
148
149
  last_result = result
@@ -5,9 +5,9 @@ module Gamefic
5
5
  result = []
6
6
  children = super
7
7
  result.concat children
8
- children.each { |c|
8
+ children.each do |c|
9
9
  result.concat subquery_accessible(c)
10
- }
10
+ end
11
11
  result
12
12
  end
13
13
  end
@@ -1,5 +1,7 @@
1
1
  module Gamefic
2
2
  module Query
3
+ # Query to retrieve the subject's siblings and all accessible descendants.
4
+ #
3
5
  class Family < Base
4
6
  def context_from(subject)
5
7
  result = []
@@ -2,14 +2,15 @@ module Gamefic
2
2
  module Query
3
3
  class Text < Base
4
4
  def initialize *arguments
5
- arguments.each { |a|
6
- if (a.kind_of?(Symbol) or a.kind_of?(String)) and !a.to_s.end_with?('?')
5
+ arguments.each do |a|
6
+ if (a.kind_of?(Symbol) || a.kind_of?(String)) && !a.to_s.end_with?('?')
7
7
  raise ArgumentError.new("Text query arguments can only be boolean method names (:method?) or regular expressions")
8
8
  end
9
- }
9
+ end
10
10
  super
11
11
  end
12
- def resolve(subject, token, continued: false)
12
+
13
+ def resolve _subject, token, continued: false
13
14
  return Matches.new([], '', token) unless accept?(token)
14
15
  parts = token.split(Keywords::SPLIT_REGEXP)
15
16
  cursor = []
@@ -22,20 +23,18 @@ module Gamefic
22
23
  }
23
24
  if continued
24
25
  Matches.new([matches.join(' ')], matches.join(' '), parts[i..-1].join(' '))
26
+ elsif matches.length == parts.length
27
+ Matches.new([matches.join(' ')], matches.join(' '), '')
25
28
  else
26
- if matches.length == parts.length
27
- Matches.new([matches.join(' ')], matches.join(' '), '')
28
- else
29
- Matches.new([], '', parts.join(' '))
30
- end
29
+ Matches.new([], '', parts.join(' '))
31
30
  end
32
31
  end
33
32
 
34
- def include?(subject, token)
33
+ def include? _subject, token
35
34
  accept?(token)
36
35
  end
37
36
 
38
- def accept?(entity)
37
+ def accept? entity
39
38
  return false unless entity.kind_of?(String) and !entity.empty?
40
39
  super
41
40
  end
@@ -0,0 +1,17 @@
1
+ module Gamefic
2
+ module Query
3
+ # Query to retrieve all of the subject's ancestors, siblings, and descendants.
4
+ #
5
+ class Tree < Family
6
+ def context_from(subject)
7
+ result = super
8
+ parent = subject.parent
9
+ until parent.nil?
10
+ result.unshift parent
11
+ parent = parent.parent
12
+ end
13
+ result
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/gamefic/query.rb CHANGED
@@ -5,6 +5,7 @@ module Gamefic
5
5
  autoload :Descendants, 'gamefic/query/descendants'
6
6
  autoload :External, 'gamefic/query/external'
7
7
  autoload :Family, 'gamefic/query/family'
8
+ autoload :Tree, 'gamefic/query/tree'
8
9
  autoload :Itself, 'gamefic/query/itself'
9
10
  autoload :Matches, 'gamefic/query/matches'
10
11
  autoload :Parent, 'gamefic/query/parent'
@@ -10,9 +10,7 @@ module Gamefic
10
10
 
11
11
  def finish
12
12
  super
13
- o = nil
14
- o = actor.perform input.strip unless input.to_s.strip.empty?
15
- actor.performed o
13
+ actor.perform input.strip unless input.to_s.strip.empty?
16
14
  end
17
15
 
18
16
  class << self
@@ -1,6 +1,8 @@
1
1
  module Gamefic
2
- # The Base Scene is not intended for instantiation. Other Scene classes
3
- # should inherit from it.
2
+ # An abstract class for building different types of scenes. It can be
3
+ # extended either through concrete subclasses or by creating anonymous
4
+ # subclasses through a scene helper method like
5
+ # `Gamefic::World::Scenes#custom`.
4
6
  #
5
7
  class Scene::Base
6
8
  include Gamefic::Serialize
@@ -1,7 +1,7 @@
1
1
  module Gamefic
2
2
  # A Conclusion ends the Plot (or the character's participation in it).
3
3
  #
4
- class Scene::Conclusion < Scene::Custom
4
+ class Scene::Conclusion < Scene::Base
5
5
  def type
6
6
  @type ||= 'Conclusion'
7
7
  end
@@ -6,7 +6,7 @@ module Gamefic
6
6
  # The finish block's input parameter receives a MultipleChoice::Input object
7
7
  # instead of a String.
8
8
  #
9
- class Scene::MultipleChoice < Scene::Custom
9
+ class Scene::MultipleChoice < Scene::Base
10
10
  # The zero-based index of the selected option.
11
11
  #
12
12
  # @return [Integer]
@@ -14,7 +14,7 @@ module Gamefic
14
14
 
15
15
  # The one-based index of the selected option.
16
16
  #
17
- # @return [Number]
17
+ # @return [Integer]
18
18
  attr_reader :number
19
19
 
20
20
  # The full text of the selected option.
@@ -33,7 +33,6 @@ module Gamefic
33
33
  get_choice
34
34
  if selection.nil?
35
35
  actor.tell invalid_message
36
- tell_options
37
36
  else
38
37
  super
39
38
  end
@@ -77,14 +76,5 @@ module Gamefic
77
76
  }
78
77
  end
79
78
  end
80
-
81
- def tell_options
82
- list = '<ol class="multiple_choice">'
83
- options.each { |o|
84
- list += "<li><a href=\"#\" rel=\"gamefic\" data-command=\"#{o}\">#{o}</a></li>"
85
- }
86
- list += "</ol>"
87
- actor.tell list
88
- end
89
79
  end
90
80
  end
@@ -1,7 +1,7 @@
1
1
  module Gamefic
2
2
  # Pause for user input.
3
3
  #
4
- class Scene::Pause < Scene::Custom
4
+ class Scene::Pause < Scene::Base
5
5
  def post_initialize
6
6
  self.type = 'Pause'
7
7
  self.prompt = 'Press enter to continue...'
@@ -4,7 +4,7 @@ module Gamefic
4
4
  # block. After the scene is finished, the :active scene will be cued if no
5
5
  # other scene has been prepared or cued.
6
6
  #
7
- class Scene::YesOrNo < Scene::Custom
7
+ class Scene::YesOrNo < Scene::Base
8
8
  attr_writer :invalid_message
9
9
 
10
10
  def post_initialize
data/lib/gamefic/scene.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module Gamefic
2
2
  module Scene
3
3
  autoload :Base, 'gamefic/scene/base'
4
- autoload :Custom, 'gamefic/scene/custom'
5
4
  autoload :Activity, 'gamefic/scene/activity'
6
5
  autoload :Pause, 'gamefic/scene/pause'
7
6
  autoload :Conclusion, 'gamefic/scene/conclusion'
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Gamefic
2
4
  module Serialize
3
5
  def to_serial(index = [])
@@ -30,13 +32,6 @@ module Gamefic
30
32
  end
31
33
  end
32
34
 
33
- def self.instances
34
- GC.start
35
- result = []
36
- ObjectSpace.each_object(Gamefic::Serialize) { |obj| result.push obj }
37
- result
38
- end
39
-
40
35
  # @param string [String]
41
36
  # @return [Object]
42
37
  def self.string_to_constant string
@@ -69,7 +64,7 @@ class Object
69
64
  end
70
65
 
71
66
  def from_serial(index = [])
72
- if self.is_a?(Hash) && (self['class'] || self['instance'])
67
+ if self.is_a?(Hash)
73
68
  if self['instance']
74
69
  elematch = self['instance'].match(/^#<ELE_([\d]+)>$/)
75
70
  object = index[elematch[1].to_i]
@@ -83,6 +78,8 @@ class Object
83
78
  return object
84
79
  elsif self['class'] == 'Class'
85
80
  return Gamefic::Serialize.string_to_constant(self['name'])
81
+ elsif self['class'] == 'Set'
82
+ return Set.new(self['data'].map { |el| el.from_serial(index) })
86
83
  else
87
84
  elematch = self['class'].match(/^#<ELE_([\d]+)>$/)
88
85
  if elematch
@@ -106,25 +103,8 @@ class Object
106
103
  return index.index(match[1].to_i) if match
107
104
  match = self.match(/#<SYM:([a-z0-9_\?\!]+)>/i)
108
105
  return match[1].to_sym if match
109
- # return nil if self == '#<UNKNOWN>'
106
+ return nil if self == '#<UNKNOWN>'
110
107
  self
111
- elsif self.is_a?(Hash)
112
- result = {}
113
- unknown = false
114
- self.each_pair do |k, v|
115
- k2 = k.from_serial(index)
116
- v2 = v.from_serial(index)
117
- if k2 == "#<UNKNOWN>" || v2 == "#<UNKNOWN>"
118
- unknown = true
119
- break
120
- end
121
- result[k2] = v2
122
- end
123
- result = "#<UNKNOWN>" if unknown
124
- result
125
- elsif self && self != true
126
- STDERR.puts "Unable to unserialize #{self.class}"
127
- nil
128
108
  else
129
109
  # true, false, or nil
130
110
  self
@@ -208,3 +188,12 @@ class Hash
208
188
  result
209
189
  end
210
190
  end
191
+
192
+ class Set
193
+ def to_serial(index = [])
194
+ {
195
+ 'class' => 'Set',
196
+ 'data' => to_a.map { |el| el.to_serial(index) }
197
+ }
198
+ end
199
+ end