gamefic 4.1.2 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e90aabf8b81551f127b57f7a70f62aa0cc92c0bc8e346ffe5056260678b0ae86
4
- data.tar.gz: 7607b66f7927acd8310ba3a0be94834102c8fcf1d7458c3bbd950de44cabd9b0
3
+ metadata.gz: 923f92309b7fcac0e2ed6aa4e691e2feea39521f15f19c7b7a560ddb7583b365
4
+ data.tar.gz: 858516d0d245300605612517d833e858b84b8a40473f6e9bf7d8670c5589cd77
5
5
  SHA512:
6
- metadata.gz: c84cc7bf2a99438d3b61a11197b43c51d3577413f0249ad44360bb7b97520b3c1fec48e39f833c0bd999ae5de3a1b934e2d4b17983544840bccb861504207eca
7
- data.tar.gz: 3c512256a34fa09048e79216a1defdc8fa076d89d2bb4549b1bbe35fbaae5c272eb156b84d5daa7f310a800d64217c49cb74c351115e7de8cd8ca25fd57382d5
6
+ metadata.gz: d3d3aa37745380138eb41ed6bee89231e96b385a1c5b8fffc42eb90bb23e9fdcb5d9ea0466fe7f5e1b2d9d459609ec002c3f80d6d6ab324658cbdea4fce1aee2
7
+ data.tar.gz: 16a1c623c7fc6173f306f43ca080b668b72fdef3700469a6b421abcf88df04c405137f1458727754fce9706107502d7bc0f1dd4cf6c91115784e14de38a6af5e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 4.2.0 - November 27, 2025
2
+ - Syntaxes support variable (piped) words
3
+ - Props::MultipleChoice#index_of
4
+
1
5
  ## 4.1.2 - May 25, 2025
2
6
  - Seed unreferenced entities
3
7
  - Ensure seed uniqueness
@@ -22,8 +22,10 @@ module Gamefic
22
22
  end
23
23
  end
24
24
 
25
+ # @return [Narrative]
25
26
  attr_reader :narrative
26
27
 
28
+ # @return [Proc]
27
29
  attr_reader :code
28
30
 
29
31
  # @param narrative [Narrative]
@@ -142,10 +142,10 @@ module Gamefic
142
142
  #
143
143
  # @param text [String]
144
144
  def description=(text)
145
- @description = (text if text != (format(Describable.default_description, name: definitely, Name: definitely.capitalize_first)))
145
+ @description = (text if text != format(Describable.default_description, name: definitely, Name: definitely.capitalize_first))
146
146
  end
147
147
 
148
- def synonyms= text
148
+ def synonyms=(text)
149
149
  @synonyms = text
150
150
  end
151
151
 
@@ -62,7 +62,7 @@ module Gamefic
62
62
  #
63
63
  # In the base Narrative class, this method runs all applicable player
64
64
  # conclude blocks and the narrative's own conclude blocks.
65
- #
65
+ #
66
66
  # @return [void]
67
67
  def turn
68
68
  players.select(&:concluding?).each { |plyr| player_conclude_blocks.each { |blk| blk[plyr] } }
@@ -77,6 +77,7 @@ module Gamefic
77
77
  # @param snapshot [String]
78
78
  # @return [self]
79
79
  def self.restore(snapshot)
80
+ # @sg-ignore
80
81
  Marshal.load(snapshot)
81
82
  end
82
83
 
data/lib/gamefic/order.rb CHANGED
@@ -20,9 +20,9 @@ module Gamefic
20
20
  def to_actions
21
21
  Action.sort(
22
22
  actor.narratives
23
- .responses_for(verb)
24
- .map { |response| match_arguments(response) }
25
- .compact
23
+ .responses_for(verb)
24
+ .map { |response| match_arguments(response) }
25
+ .compact
26
26
  )
27
27
  end
28
28
 
@@ -5,9 +5,6 @@ module Gamefic
5
5
  # Props for MultipleChoice scenes.
6
6
  #
7
7
  class MultipleChoice < Default
8
- # A message to send the player for an invalid choice. A formatting
9
- # token named %<input>s can be used to inject the user input.
10
- #
11
8
  # @return [String]
12
9
  attr_writer :invalid_message
13
10
 
@@ -18,6 +15,13 @@ module Gamefic
18
15
  @options ||= []
19
16
  end
20
17
 
18
+ # A message to send the player for an invalid choice. A formatting
19
+ # token named `%<input>s` can be used to inject the user input.
20
+ #
21
+ # @example
22
+ # props.invalid_message = '"%<input>s" is not a valid choice.'
23
+ #
24
+ # @return [String]
21
25
  def invalid_message
22
26
  @invalid_message ||= '"%<input>s" is not a valid choice.'
23
27
  end
@@ -28,7 +32,7 @@ module Gamefic
28
32
  def index
29
33
  return nil unless input
30
34
 
31
- @index ||= index_by_number || index_by_text
35
+ @index ||= index_of(input)
32
36
  end
33
37
 
34
38
  # The one-based index of the selected option.
@@ -53,15 +57,36 @@ module Gamefic
53
57
  !!index
54
58
  end
55
59
 
60
+ # Get the index of an option using input criteria, e.g., a one-based
61
+ # number or the text of the option. The return value is the option's
62
+ # zero-based index or nil.
63
+ #
64
+ # @example
65
+ # props = Gamefic::Props::MultipleChoice.new
66
+ # props.options.push 'First choice', 'Second choice'
67
+ #
68
+ # props.index_of(1) # => 0
69
+ # props.index_of('Second choice') # => 1
70
+ #
71
+ # @param option [String, Integer]
72
+ # @return [Integer, nil]
73
+ def index_of(option)
74
+ index_by_number(option) || index_by_text(option)
75
+ end
76
+
56
77
  private
57
78
 
58
- def index_by_number
59
- return input.to_i - 1 if input.match(/^\d+$/) && options[input.to_i - 1]
79
+ # @param [String, Integer]
80
+ # @return [Integer, nil]
81
+ def index_by_number(input)
82
+ return input.to_i - 1 if input.to_s.match(/^\d+$/) && options[input.to_i - 1]
60
83
 
61
84
  nil
62
85
  end
63
86
 
64
- def index_by_text
87
+ # @param [String]
88
+ # @return [Integer, nil]
89
+ def index_by_text(input)
65
90
  options.find_index { |opt| opt.casecmp?(input) }
66
91
  end
67
92
  end
@@ -7,7 +7,7 @@ module Gamefic
7
7
  class MultiplePartial < MultipleChoice
8
8
  private
9
9
 
10
- def index_by_text
10
+ def index_by_text(input)
11
11
  matches = options.map.with_index { |text, idx| next idx if text.downcase.start_with?(input.downcase) }.compact
12
12
  matches.first if matches.one?
13
13
  end
@@ -17,8 +17,15 @@ module Gamefic
17
17
  # @param command [String] The format of the original command
18
18
  # @param translation [String] The format of the translated command
19
19
  # @return [Syntax] the Syntax object
20
- def interpret command, translation
21
- syntaxes.push(Syntax.new(command, translation)).last
20
+ def interpret(command, translation)
21
+ parts = Syntax.split(command)
22
+ additions = if parts.first.include?('|')
23
+ parts.first.split('|').map { |verb| Syntax.new("#{verb} #{verb[1..].join(' ')}", translation) }
24
+ else
25
+ [Syntax.new(command, translation)]
26
+ end
27
+ syntaxes.concat additions
28
+ additions
22
29
  end
23
30
 
24
31
  def syntaxes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
2
4
  module Scripting
3
5
  # Scripting hook methods are instance methods that return callbacks for
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
2
4
  module Scripting
3
5
  module Responses
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
2
4
  module Scripting
3
5
  module Scenes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
2
4
  module Scripting
3
5
  module Seeds
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gamefic
2
4
  module Scripting
3
5
  module Syntaxes
@@ -35,7 +35,7 @@ module Gamefic
35
35
  .map { |blk| Binding.new(self, blk) }
36
36
  end
37
37
 
38
- def self.included other
38
+ def self.included(other)
39
39
  super
40
40
  other.extend Scriptable
41
41
  end
@@ -82,9 +82,10 @@ module Gamefic
82
82
  #
83
83
  # @param text [String]
84
84
  # @return [Boolean]
85
- def accept?(text)
85
+ def match?(text)
86
86
  !!text.match(regexp)
87
87
  end
88
+ alias accept? match?
88
89
 
89
90
  # Get a signature that identifies the form of the Syntax.
90
91
  # Signatures are used to compare Syntaxes to each other.
@@ -118,6 +119,48 @@ module Gamefic
118
119
  string.start_with?(':') ? nil : string.to_sym
119
120
  end
120
121
 
122
+ # Split a syntax template by words and expressions.
123
+ #
124
+ # @param template [String]
125
+ # @return [Array<String>]
126
+ def self.split(template)
127
+ parens = 0
128
+ result = template.normalize.chars.each.with_object(['']) do |char, result|
129
+ parens = parse_token(char, parens, result)
130
+ end
131
+ raise "Unbalanced parentheses in syntax '#{template}'" unless parens.zero?
132
+
133
+ result.pop if result.last.empty?
134
+
135
+ result
136
+ end
137
+
138
+ class << self
139
+ private
140
+
141
+ # @param char [String]
142
+ # @param parens [Integer]
143
+ # @param result [Array<String>]
144
+ def parse_token(char, parens, result)
145
+ case char
146
+ when /[()]/
147
+ parens += (char == '(' ? 1 : -1)
148
+ when /\s/
149
+ return parens if result.last.empty?
150
+
151
+ if parens.positive?
152
+ result.push(result.pop + char)
153
+ else
154
+ result.push ''
155
+ end
156
+ else
157
+ result.push(result.pop + char)
158
+ end
159
+
160
+ parens
161
+ end
162
+ end
163
+
121
164
  private
122
165
 
123
166
  # @return [String]
@@ -142,9 +185,9 @@ module Gamefic
142
185
 
143
186
  # @return [Array<String>]
144
187
  def make_tokens
145
- template.keywords.map.with_index do |word, idx|
188
+ Syntax.split(template).map.with_index do |word, idx|
189
+ next "(?:\\b#{word.gsub('|', '|\\b')})" if word.include?('|')
146
190
  next word unless word.match?(PARAM_REGEXP)
147
-
148
191
  next nil if idx.positive? && template.keywords[idx - 1].match?(PARAM_REGEXP)
149
192
 
150
193
  '([\w\W\s\S]*?)'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gamefic
4
- VERSION = '4.1.2'
4
+ VERSION = '4.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamefic
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-05-25 00:00:00.000000000 Z
10
+ date: 2025-11-27 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -240,7 +239,6 @@ homepage: https://gamefic.com
240
239
  licenses:
241
240
  - MIT
242
241
  metadata: {}
243
- post_install_message:
244
242
  rdoc_options: []
245
243
  require_paths:
246
244
  - lib
@@ -255,8 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
253
  - !ruby/object:Gem::Version
256
254
  version: '0'
257
255
  requirements: []
258
- rubygems_version: 3.5.22
259
- signing_key:
256
+ rubygems_version: 3.6.7
260
257
  specification_version: 4
261
258
  summary: Gamefic
262
259
  test_files: []