Module: Yast::Ops

Defined in:
src/ruby/yast/ops.rb

Overview

These emulate the YCP arithmetic and logic operators. In particular, nil as an argument mostly propagates to the results. You will probably want to check for nil beforehand and then use the normal Ruby operators.

Defined Under Namespace

Classes: GenericComparable, HashComparator, ListComparator

Constant Summary collapse

TYPES_MAP =

map of YCPTypes to ruby types

{
  "any"       => ::Object,
  "nil"       => ::NilClass,
  "void"      => ::NilClass,
  "boolean"   => [::TrueClass, ::FalseClass],
  "string"    => ::String,
  "symbol"    => ::Symbol,
  "integer"   => ::Integer,
  "float"     => ::Float,
  "list"      => ::Array,
  "map"       => ::Hash,
  "term"      => Yast::Term,
  "path"      => Yast::Path,
  "locale"    => ::String,
  "function"  => [Yast::FunRef, Yast::YReference],
  "byteblock" => Yast::Byteblock
}.freeze
SHORTCUT_TYPES =

Types for which we generate shortcut methods, e.g. get_string or Convert.to_string.

[
  "boolean",
  "string",
  "symbol",
  "integer",
  "float",
  "list",
  "map",
  "term",
  "path",
  "locale"
].freeze
OUTER_LOOP_FRAME =

To log the caller frame we need to skip 3 frames as 1 is method itself and each block contributes 2 frames (outer: called, inner: defined) Try for yourself: def a puts caller.inspect [0].each { |i| puts caller.inspect } end a

3

Class Method Summary collapse

Class Method Details

.add(first, second) ⇒ Object

Deprecated.

use ruby native operator +

Adds second to first.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'src/ruby/yast/ops.rb', line 234

def self.add(first, second)
  return nil if first.nil? || second.nil?

  case first
  when ::Array
    return Yast.deep_copy(first + second) if second.is_a?(::Array)

    Yast.deep_copy(first).push(Yast.deep_copy(second))
  when ::Hash
    Yast.deep_copy(first).merge(Yast.deep_copy(second))
  when ::String
    first + second.to_s
  else
    first + second
  end
end

.bitwise_and(first, second) ⇒ Object

Deprecated.

use ruby native operator &



285
286
287
288
289
# File 'src/ruby/yast/ops.rb', line 285

def self.bitwise_and(first, second)
  return nil if first.nil? || second.nil?

  first & second
end

.bitwise_not(value) ⇒ Object

Deprecated.

use ruby native operator ~



352
353
354
355
356
# File 'src/ruby/yast/ops.rb', line 352

def self.bitwise_not(value)
  return nil if value.nil?

  ~value
end

.bitwise_or(first, second) ⇒ Object

Deprecated.

use ruby native operator |



292
293
294
295
296
# File 'src/ruby/yast/ops.rb', line 292

def self.bitwise_or(first, second)
  return nil if first.nil? || second.nil?

  first | second
end

.bitwise_xor(first, second) ⇒ Object

Deprecated.

use ruby native operator ^



299
300
301
302
303
# File 'src/ruby/yast/ops.rb', line 299

def self.bitwise_xor(first, second)
  return nil if first.nil? || second.nil?

  first ^ second
end

.comparable_object(object, localized = false) ⇒ Object

Creates comparable wrapper that makes ycp compatible comparison



427
428
429
# File 'src/ruby/yast/ops.rb', line 427

def self.comparable_object(object, localized = false)
  GenericComparable.new(object, localized)
end

.divide(first, second) ⇒ Object

Deprecated.

use ruby native operator /

Note:

allows division with zero and in such case return nil

Divides first with second.



270
271
272
273
274
# File 'src/ruby/yast/ops.rb', line 270

def self.divide(first, second)
  return nil if first.nil? || second.nil? || second == 0

  first / second
end

.equal(first, second) ⇒ Object

Deprecated.

use ruby native operator ==



359
360
361
362
363
# File 'src/ruby/yast/ops.rb', line 359

def self.equal(first, second)
  first = comparable_object(first)

  first == second
end

.get(object, indexes, default = nil, skip_frames = 0) ⇒ Object

Deprecated.

Use the native Ruby operator []

Gets value from object at indexes. Eager to return default at slightest provocation.

Replacement

Consider using

  • object[index]
  • object[i1][i2]
  • object[index] || default if the value cannot be false or nil
  • object.fetch(index, default)
  • object.fetch(index) if you want an exception when index is absent

Parameters:

  • object (Array, Hash, Yast::Term)
  • indexes

    Usually a scalar, but also an array of scalars to recursively descend into object

  • default (defaults to: nil)

    the default value returned (via Yast.deep_copy) for any error; if a block is given, it is called to provide the default value (only when the default is needed, so it is useful for values that are expensive to compute).

  • skip_frames (Integer) (defaults to: 0)

    private, how many caller frames to skip when reporting warnings or exceptions

Returns:

  • The value in object at indexes, if it exists. The default value if object, indexes are nil, have wrong type, or indexes does not exist in object.



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
# File 'src/ruby/yast/ops.rb', line 116

def self.get(object, indexes, default = nil, skip_frames = 0)
  res = object
  default = Yast.deep_copy(default)
  skip_frames += OUTER_LOOP_FRAME
  indexes = [indexes] unless indexes.is_a? ::Array

  indexes.each do |i|
    case res
    when ::Array, Yast::Term
      if i.is_a?(::Integer)
        if (0..res.size - 1).cover? i
          res = res[i]
        else
          Yast.y2milestone skip_frames, "Index #{i} is out of array size"
          return block_given? ? yield : default
        end
      else
        Yast.y2warning skip_frames, "Passed #{i.inspect} as index key for array."
        return block_given? ? yield : default
      end
    when ::Hash
      return block_given? ? yield : default unless res.key?(i)

      res = res[i]
    when ::NilClass
      Yast.y2milestone skip_frames, "Ops.get called on nil."
      return block_given? ? yield : default
    else
      Yast.y2warning skip_frames, "Ops.get called on wrong type #{res.class}"
      return block_given? ? yield : default
    end
  end
  Yast.deep_copy(res)
end

.get_boolean(obj, idx) ⇒ Boolean?

Returns Convert.to_boolean(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_float(obj, idx) ⇒ Float?

Returns Convert.to_float(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_integer(obj, idx) ⇒ Integer?

Returns Convert.to_integer(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_list(obj, idx) ⇒ Array?

Returns Convert.to_list(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_locale(obj, idx) ⇒ String?

Returns Convert.to_locale(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_map(obj, idx) ⇒ Hash?

Returns Convert.to_map(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_path(obj, idx) ⇒ Path?

Returns Convert.to_path(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_string(obj, idx) ⇒ String?

Returns Convert.to_string(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_symbol(obj, idx) ⇒ Symbol?

Returns Convert.to_symbol(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.get_term(obj, idx) ⇒ Term?

Returns Convert.to_term(get(obj, idx, def)).

Returns:



72
73
74
75
76
# File 'src/ruby/yast/ops.rb', line 72

Ops::SHORTCUT_TYPES.each do |type|
  define_singleton_method("get_#{type}") do |object, indexes, default=nil, &block|
    Yast::Convert.public_send("to_#{type}", get(object, indexes, default, 1, &block))
  end
end

.greater_or_equal(first, second) ⇒ Object

Deprecated.

use ruby native operator >=



400
401
402
403
404
405
406
# File 'src/ruby/yast/ops.rb', line 400

def self.greater_or_equal(first, second)
  return nil if first.nil? || second.nil?

  first = comparable_object(first)

  first >= second
end

.greater_than(first, second) ⇒ Object

Deprecated.

use ruby native operator >



391
392
393
394
395
396
397
# File 'src/ruby/yast/ops.rb', line 391

def self.greater_than(first, second)
  return nil if first.nil? || second.nil?

  first = comparable_object(first)

  first > second
end

.is(object, type) ⇒ Object

Checks if object is given YCP type. There is also shorfcuts for most of types in format is_



416
417
418
419
420
421
422
423
424
# File 'src/ruby/yast/ops.rb', line 416

def self.is(object, type)
  type = "function" if type =~ /\(.*\)/ # reference to function
  type = type.gsub(/<.*>/, "")
  type = type.gsub(/\s+/, "")
  classes = TYPES_MAP[type]
  raise "Invalid type to detect in is '#{type}'" unless classes
  classes = [classes] unless classes.is_a? ::Array
  classes.any? { |cl| object.is_a? cl }
end

.less_or_equal(first, second) ⇒ Object

Deprecated.

use ruby native operator <=



382
383
384
385
386
387
388
# File 'src/ruby/yast/ops.rb', line 382

def self.less_or_equal(first, second)
  return nil if first.nil? || second.nil?

  first = comparable_object(first)

  first <= second
end

.less_than(first, second) ⇒ Object

Deprecated.

use ruby native operator <



373
374
375
376
377
378
379
# File 'src/ruby/yast/ops.rb', line 373

def self.less_than(first, second)
  return nil if first.nil? || second.nil?

  first = comparable_object(first)

  first < second
end

.logical_and(first, second) ⇒ Object

Deprecated.

use ruby native operator &&



320
321
322
323
324
325
# File 'src/ruby/yast/ops.rb', line 320

def self.logical_and(first, second)
  first = false if first.nil?
  second = false if second.nil?

  first && second
end

.logical_not(value) ⇒ Object

Deprecated.

use ruby native operator !

Note:

for nil returns nil to be compatible with ycp implementation



344
345
346
347
348
349
# File 'src/ruby/yast/ops.rb', line 344

def self.logical_not(value)
  # Yast really do it!!!
  return nil if value.nil?

  !value
end

.logical_or(first, second) ⇒ Object

Deprecated.

use ruby native operator ||



328
329
330
331
332
333
# File 'src/ruby/yast/ops.rb', line 328

def self.logical_or(first, second)
  first = false if first.nil?
  second = false if second.nil?

  first || second
end

.modulo(first, second) ⇒ Object

Deprecated.

use ruby native operator %

Computes module after division of first with second.



278
279
280
281
282
# File 'src/ruby/yast/ops.rb', line 278

def self.modulo(first, second)
  return nil if first.nil? || second.nil?

  first % second
end

.multiply(first, second) ⇒ Object

Deprecated.

use ruby native operator *

Multiplies first with second.



261
262
263
264
265
# File 'src/ruby/yast/ops.rb', line 261

def self.multiply(first, second)
  return nil if first.nil? || second.nil?

  first * second
end

.not_equal(first, second) ⇒ Object

Deprecated.

use ruby native operator !=



366
367
368
369
370
# File 'src/ruby/yast/ops.rb', line 366

def self.not_equal(first, second)
  first = comparable_object(first)

  first != second
end

.set(object, indexes, value) ⇒ void

Deprecated.

Use the native Ruby operator []=

This method returns an undefined value.

Sets value to object at given indexes.

If object or indexes is nil, set does nothing.

If indexes is an Array, set recursively descends through all but last indexes to find the destination container. As expected, if the last index does not exist, object is assigned. However, if an intermediate index does not exist, object is not asigned (no Perl-like autovivification).

Replacement

Ops.set(object, indexes, value) can be mechanically replaced by object[indexes] = value if all conditions below are met

  • object is a non-nil Array, Hash, Term
  • indexes is a non-nil scalar
  • value does not need Yast.deep_copy

Idiomatic Replacement

If you want cleaner code and are ready to rescue exceptions, this applies:

  • object will simply raise an error if it cannot handle []=; that works as expected.
  • If indexes is an Array of the form [i, j, k], use object[i][j][k] = value. Missing indexes will become nil and raise an exception on the next index.
  • value may need a deep copy: object[indexes] = deep_copy(value)


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 'src/ruby/yast/ops.rb', line 188

def self.set(object, indexes, value)
  return if indexes.nil? || object.nil?

  indexes = [indexes] unless indexes.is_a? ::Array
  last = indexes.pop
  res = object

  # return here is needed for quick exit of method and workaround with any or
  # all is nasty and decrease readability
  # rubocop:disable Lint/NonLocalExitFromIterator
  indexes.each do |i|
    case res
    when ::Array, Yast::Term
      if !i.is_a?(::Integer)
        Yast.y2warning OUTER_LOOP_FRAME, "Passed #{i.inspect} as index key for array."
        return
      end

      if !(0..res.size - 1).cover?(i)
        Yast.y2warning OUTER_LOOP_FRAME, "Index #{i} is out of array size"
        return
      end

      res = res[i]
    when ::Hash
      return unless res.key? i

      res = res[i]
    else
      Yast.y2warning OUTER_LOOP_FRAME, "Builtin assign called on wrong type #{res.class}"
      return
    end
  end
  # rubocop:enable Lint/NonLocalExitFromIterator

  case res
  when ::Array, Yast::Term, ::Hash
    res[last] = Yast.deep_copy(value)
  else
    # log is not in loop, so use simple 1 to get outside of method
    Yast.y2warning 1, "Builtin assign called on wrong type #{res.class}"
  end
end

.shift_left(first, second) ⇒ Object

Deprecated.

use ruby native operator <<



306
307
308
309
310
# File 'src/ruby/yast/ops.rb', line 306

def self.shift_left(first, second)
  return nil if first.nil? || second.nil?

  first << second
end

.shift_right(first, second) ⇒ Object

Deprecated.

use ruby native operator >>



313
314
315
316
317
# File 'src/ruby/yast/ops.rb', line 313

def self.shift_right(first, second)
  return nil if first.nil? || second.nil?

  first >> second
end

.subtract(first, second) ⇒ Object

Deprecated.

use ruby native operator -

Subtracts second from first.



253
254
255
256
257
# File 'src/ruby/yast/ops.rb', line 253

def self.subtract(first, second)
  return nil if first.nil? || second.nil?

  first - second
end

.unary_minus(value) ⇒ Object

Deprecated.

use ruby native operator -



336
337
338
339
340
# File 'src/ruby/yast/ops.rb', line 336

def self.unary_minus(value)
  return nil if value.nil?

  -value
end