Module: Lich::Util

Includes:
Enumerable
Defined in:
documented/util/util.rb,
documented/update.rb,
documented/util/opts.rb,
documented/magic-info.rb,
documented/util/textstripper.rb,
documented/util/login_helpers.rb,
documented/util/memoryreleaser.rb

Overview

Provides utility methods for text processing

Examples:

Using the TextStripper module

stripped_text = Lich::Util::TextStripper.strip(text, Lich::Util::TextStripper::Mode::HTML)

Defined Under Namespace

Modules: LoginHelpers, Magicinfo, MemoryReleaser, TextStripper, Update Classes: Opts

Class Method Summary collapse

Class Method Details

.anon_hook(prefix = '') ⇒ String

Generates a unique anonymous hook name based on the current time and a prefix.

Examples:

Lich::Util.anon_hook("test")

Parameters:

  • prefix (String) (defaults to: '')

    An optional prefix for the hook name.

Returns:

  • (String)

    The generated anonymous hook name.



66
67
68
69
# File 'documented/util/util.rb', line 66

def self.anon_hook(prefix = '')
  now = Time.now
  "Util::#{prefix}-#{now}-#{Random.rand(10000)}"
end

.deep_freeze(obj) ⇒ Object

Deep freezes an object, including all nested elements.

Examples:

frozen_obj = Lich::Util.deep_freeze({"key" => "value"})

Parameters:

  • obj (Object)

    The object to deep freeze.

Returns:

  • (Object)

    The deep-frozen object.



275
276
277
278
279
280
281
282
283
284
285
286
# File 'documented/util/util.rb', line 275

def self.deep_freeze(obj)
  case obj
  when Hash
    obj.each do |k, v|
      deep_freeze(k)
      deep_freeze(v)
    end
  when Array
    obj.each { |el| deep_freeze(el) }
  end
  obj.freeze
end

.install_gem_requirements(gems_to_install) ⇒ Object

Installs the specified Ruby gems and requires them if needed.

Examples:

Lich::Util.install_gem_requirements({"gem_name" => true})

Parameters:

  • gems_to_install (Hash)

    A hash of gem names and whether to require them after installation.

Raises:

  • (ArgumentError)

    If the input is not a hash or has invalid types.



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'documented/util/util.rb', line 237

def self.install_gem_requirements(gems_to_install)
  raise ArgumentError, "install_gem_requirements must be passed a Hash" unless gems_to_install.is_a?(Hash)
  require "rubygems"
  require "rubygems/dependency_installer"
  installer = Gem::DependencyInstaller.new({ :user_install => true, :document => nil })
  installed_gems = Gem::Specification.map { |gem| gem.name }.sort.uniq
  failed_gems = []

  gems_to_install.each do |gem_name, should_require|
    unless gem_name.is_a?(String) && (should_require.is_a?(TrueClass) || should_require.is_a?(FalseClass))
      raise ArgumentError, "install_gem_requirements must be passed a Hash with String key and TrueClass/FalseClass as value"
    end
    begin
      unless installed_gems.include?(gem_name)
        respond("--- Lich: Installing missing ruby gem '#{gem_name}' now, please wait!")
        installer.install(gem_name)
        respond("--- Lich: Done installing '#{gem_name}' gem!")
      end
      require gem_name if should_require
    rescue StandardError
      respond("--- Lich: error: Failed to install Ruby gem: #{gem_name}")
      respond("--- Lich: error: #{$!}")
      Lich.log("error: Failed to install Ruby gem: #{gem_name}")
      Lich.log("error: #{$!}")
      failed_gems.push(gem_name)
    end
  end
  unless failed_gems.empty?
    raise("Please install the failed gems: #{failed_gems.join(', ')} to run #{$lich_char}#{Script.current.name}")
  end
end

.issue_command(command, start_pattern, end_pattern = /<prompt/, include_end: true, timeout: 5, silent: nil, usexml: true, quiet: false, use_fput: true) ⇒ Array<String>

Issues a command and captures the output based on start and end patterns.

Examples:

output = Lich::Util.issue_command("some_command", /start_pattern/, /end_pattern/)

Parameters:

  • command (String)

    The command to issue.

  • start_pattern (Regexp)

    The pattern to identify the start of the output.

  • end_pattern (Regexp) (defaults to: /<prompt/)

    The pattern to identify the end of the output (default: /<prompt/).

  • include_end (Boolean) (defaults to: true)

    Whether to include the end line in the result (default: true).

  • timeout (Integer) (defaults to: 5)

    The timeout for the command (default: 5).

  • silent (Boolean, nil) (defaults to: nil)

    Whether to suppress output (default: nil).

  • usexml (Boolean) (defaults to: true)

    Whether to use XML output (default: true).

  • quiet (Boolean) (defaults to: false)

    Whether to suppress output during processing (default: false).

  • use_fput (Boolean) (defaults to: true)

    Whether to use fput instead of put (default: true).

Returns:

  • (Array<String>)

    The captured output lines.

Raises:

  • (Timeout::Error)

    If the command times out.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'documented/util/util.rb', line 85

def self.issue_command(command, start_pattern, end_pattern = /<prompt/, include_end: true, timeout: 5, silent: nil, usexml: true, quiet: false, use_fput: true)
  result = []
  name = self.anon_hook
  filter = false
  ignore_end = end_pattern.eql?(:ignore)

  save_script_silent = Script.current.silent
  save_want_downstream = Script.current.want_downstream
  save_want_downstream_xml = Script.current.want_downstream_xml

  Script.current.silent = silent if !silent.nil?
  Script.current.want_downstream = !usexml
  Script.current.want_downstream_xml = usexml

  begin
    Timeout::timeout(timeout, Interrupt) {
      DownstreamHook.add(name, proc { |line|
        if filter
          if ignore_end || line =~ end_pattern
            DownstreamHook.remove(name)
            filter = false
            if quiet && !ignore_end
              next(nil)
            else
              line
            end
          else
            if quiet
              next(nil)
            else
              line
            end
          end
        elsif line =~ start_pattern
          filter = true
          if quiet
            next(nil)
          else
            line
          end
        else
          line
        end
      })
      use_fput ? fput(command) : put(command)

      until (line = get) =~ start_pattern; end
      result << line.rstrip
      unless ignore_end
        until (line = get) =~ end_pattern
          result << line.rstrip
        end
      end
      unless ignore_end
        if include_end
          result << line.rstrip
        end
      end
    }
  rescue Interrupt
    nil
  ensure
    DownstreamHook.remove(name)
    Script.current.silent = save_script_silent if !silent.nil?
    Script.current.want_downstream = save_want_downstream
    Script.current.want_downstream_xml = save_want_downstream_xml
  end
  return result
end

.normalize_lookup(effect, val) ⇒ Boolean

Normalizes the lookup for effects based on the value type.

Examples:

Lich::Util.normalize_lookup("some_effect", "some_value")

Parameters:

  • effect (String)

    The effect type to look up.

  • val (String, Integer, Symbol)

    The value to normalize.

Returns:

  • (Boolean)

    True if the lookup is valid, false otherwise.

Raises:

  • (RuntimeError)

    If the value type is invalid.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'documented/util/util.rb', line 21

def self.normalize_lookup(effect, val)
  caller_type = "Effects::#{effect}"
  case val
  when String
    (eval caller_type).to_h.transform_keys(&:to_s).transform_keys(&:downcase).include?(val.downcase.gsub('_', ' '))
  when Integer
    #      seek = mappings.fetch(val, nil)
    (eval caller_type).active?(val)
  when Symbol
    (eval caller_type).to_h.transform_keys(&:to_s).transform_keys(&:downcase).include?(val.to_s.downcase.gsub('_', ' '))
  else
    fail "invalid lookup case #{val.class.name}"
  end
end

.normalize_name(name) ⇒ String

Normalizes a given name by converting it to a lowercase string and replacing or removing certain characters.

The normalization process handles the following cases:

  • Converts spaces and hyphens to underscores.

  • Removes colons and apostrophes.

  • Converts symbols to strings.

Normalizes a given name by converting it to a lowercase string and replacing or removing certain characters.

The normalization process handles the following cases:

  • Converts spaces and hyphens to underscores.

  • Removes colons and apostrophes.

  • Converts symbols to strings.

Examples:

Lich::Util.normalize_name("Example Name")

Parameters:

  • name (String, Symbol)

    The name to normalize.

Returns:

  • (String)

    The normalized name.



52
53
54
55
56
57
58
59
# File 'documented/util/util.rb', line 52

def self.normalize_name(name)
  normal_name = name.to_s.downcase
  normal_name.gsub!(' ', '_') if name =~ (/\s/)
  normal_name.gsub!('-', '_') if name =~ (/-/)
  normal_name.gsub!(":", '') if name =~ (/:/)
  normal_name.gsub!("'", '') if name =~ (/'/)
  normal_name
end

.quiet_command(command, start_pattern, end_pattern, include_end = true, timeout = 5, silent = true) ⇒ Array<String>

Issues a command quietly and captures the output.

Examples:

output = Lich::Util.quiet_command("some_command", /start_pattern/, /end_pattern/)

Parameters:

  • command (String)

    The command to issue.

  • start_pattern (Regexp)

    The pattern to identify the start of the output.

  • end_pattern (Regexp)

    The pattern to identify the end of the output.

  • include_end (Boolean) (defaults to: true)

    Whether to include the end line in the result (default: true).

  • timeout (Integer) (defaults to: 5)

    The timeout for the command (default: 5).

  • silent (Boolean) (defaults to: true)

    Whether to suppress output (default: true).

Returns:

  • (Array<String>)

    The captured output lines.



179
180
181
# File 'documented/util/util.rb', line 179

def self.quiet_command(command, start_pattern, end_pattern, include_end = true, timeout = 5, silent = true)
  return issue_command(command, start_pattern, end_pattern, include_end: include_end, timeout: timeout, silent: silent, usexml: false, quiet: true)
end

.quiet_command_xml(command, start_pattern, end_pattern = /<prompt/, include_end = true, timeout = 5, silent = true) ⇒ Array<String>

Issues a command quietly and captures the output in XML format.

Examples:

output = Lich::Util.quiet_command_xml("some_command", /start_pattern/, /end_pattern/)

Parameters:

  • command (String)

    The command to issue.

  • start_pattern (Regexp)

    The pattern to identify the start of the output.

  • end_pattern (Regexp) (defaults to: /<prompt/)

    The pattern to identify the end of the output (default: /<prompt/).

  • include_end (Boolean) (defaults to: true)

    Whether to include the end line in the result (default: true).

  • timeout (Integer) (defaults to: 5)

    The timeout for the command (default: 5).

  • silent (Boolean) (defaults to: true)

    Whether to suppress output (default: true).

Returns:

  • (Array<String>)

    The captured output lines.



165
166
167
# File 'documented/util/util.rb', line 165

def self.quiet_command_xml(command, start_pattern, end_pattern = /<prompt/, include_end = true, timeout = 5, silent = true)
  return issue_command(command, start_pattern, end_pattern, include_end: include_end, timeout: timeout, silent: silent, usexml: true, quiet: true)
end

.silver_count(timeout = 3) ⇒ Integer

Counts the amount of silver available within a specified timeout.

Examples:

silver_amount = Lich::Util.silver_count(5)

Parameters:

  • timeout (Integer) (defaults to: 3)

    The timeout for the count operation (default: 3).

Returns:

  • (Integer)

    The amount of silver counted.



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'documented/util/util.rb', line 188

def self.silver_count(timeout = 3)
  silence_me unless (undo_silence = silence_me)
  result = ''
  name = self.anon_hook
  filter = false

  start_pattern = /^\s*Name\:/
  end_pattern = /^\s*Mana\:\s+\-?[0-9]+\s+Silver\:\s+([0-9,]+)/
  ttl = Time.now + timeout
  begin
    # main thread
    DownstreamHook.add(name, proc { |line|
      if filter
        if line =~ end_pattern
          result = $1.dup
          DownstreamHook.remove(name)
          filter = false
        else
          next(nil)
        end
      elsif line =~ start_pattern
        filter = true
        next(nil)
      else
        line
      end
    })
    # script thread
    fput 'info'
    loop {
      # non-blocking check, this allows us to
      # check the time even when the buffer is empty
      line = get?
      break if line && line =~ end_pattern
      break if Time.now > ttl
      sleep(0.01) # prevent a tight-loop
    }
  ensure
    DownstreamHook.remove(name)
    silence_me if undo_silence
  end
  return result.gsub(',', '').to_i
end