Module: Leto

Defined in:
lib/leto/path.rb,
lib/leto/dig.rb,
lib/leto/call.rb,
lib/leto/utils.rb,
lib/leto/version.rb

Overview

Light wrapper around Array, mostly for nicer display.

Defined Under Namespace

Classes: Path

Constant Summary collapse

IMMUTABLE_CLASSES =
[
  FalseClass,
  Float,
  if defined?(Integer)
    Integer
  else
    Fixnum # rubocop:disable Lint/UnifiedInteger for Ruby < 2.4
  end,
  NilClass,
  Symbol,
  TrueClass,
].freeze
NON_DUPLICABLE_CLASSES =
[
  Method,
  Singleton,
  UnboundMethod
].freeze
VERSION =
"2.1.0"

Class Method Summary collapse

Class Method Details

.call(obj, max_depth: nil, path: nil, &block) ⇒ Object



2
3
4
5
6
7
# File 'lib/leto/call.rb', line 2

def self.call(obj, max_depth: nil, path: nil, &block)
  block_given? or return enum_for(__method__, obj, max_depth: max_depth, path: path)

  traverse(obj, path, 0, max_depth, build_seen_hash, block)
  obj
end

.deep_dup(obj, include_modules: false) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/leto/utils.rb', line 23

def self.deep_dup(obj, include_modules: false)
  return obj if IMMUTABLE_CLASSES.include?(obj.class) || !duplicable?(obj) ||
                (!include_modules && obj.is_a?(Module))

  copy = obj.dup

  trace(obj, max_depth: 1).each do |el, path|
    method, *args = path.steps[0]
    case method
    when :instance_variable_get
      copy.instance_variable_set(*args, deep_dup(el, include_modules: include_modules))
    when :[]
      copy[*args] = deep_dup(el, include_modules: include_modules)
    when :send # Data
      copy = copy.with(args[0] => deep_dup(el, include_modules: include_modules))
    when :begin
      return Range.new(deep_dup(obj.begin), deep_dup(obj.end), obj.exclude_end?)
    end
  end

  copy
end

.deep_eql?(obj1, obj2) ⇒ Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/leto/utils.rb', line 19

def self.deep_eql?(obj1, obj2)
  call(obj1).to_a == call(obj2).to_a
end

.deep_freeze(obj, include_modules: false) ⇒ Object



2
3
4
5
6
7
8
# File 'lib/leto/utils.rb', line 2

def self.deep_freeze(obj, include_modules: false)
  call(obj) do |el|
    el.freeze if el.respond_to?(:freeze) &&
                 !el.frozen? &&
                 (include_modules || !el.is_a?(Module))
  end
end

.deep_print(obj, print_method: :inspect, indent: 4, show_path: true) ⇒ Object



10
11
12
13
14
15
16
17
# File 'lib/leto/utils.rb', line 10

def self.deep_print(obj, print_method: :inspect, indent: 4, show_path: true)
  trace(obj) do |el, path|
    puts "#{' ' * path.count * indent}#{el.send(print_method)}" \
         "#{"  @ #{path.inspect}" if show_path}" \
         [0..78]
  end
  nil
end

.dig(obj, steps) ⇒ Object



2
3
4
# File 'lib/leto/dig.rb', line 2

def self.dig(obj, steps)
  Leto::Path.new(start: obj, steps: steps).resolve
end

.each_shared_object(obj1, obj2, filter: nil) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/leto/utils.rb', line 66

def self.each_shared_object(obj1, obj2, filter: nil)
  block_given? or return enum_for(__method__, obj1, obj2, filter: filter)

  obj2_els_with_path = trace(obj2).to_a
  trace(obj1).each do |el1, path1|
    next if filter && !filter.call(el1)

    obj2_els_with_path.reject do |el2, path2|
      yield(el1, path1, path2) if el1.equal?(el2)
    end
  end
end

.shared_mutable_state?(obj1, obj2) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/leto/utils.rb', line 46

def self.shared_mutable_state?(obj1, obj2)
  each_shared_object(obj1, obj2, filter: method(:mutable?)).any?
end

.shared_mutables(obj1, obj2) ⇒ Object

returns [[shared_object, path1, path2], …], e.g.: str1 = ‘foo’.dup str2 = ‘bar’.dup shared_mutables([str1, str2], [str2, str1]) # => [

["foo", [[:[], 0]], [[:[], 1]]],
["bar", [[:[], 1]], [[:[], 0]]]

]



58
59
60
# File 'lib/leto/utils.rb', line 58

def self.shared_mutables(obj1, obj2)
  each_shared_object(obj1, obj2, filter: method(:mutable?)).to_a
end

.shared_objects(obj1, obj2, filter: nil) ⇒ Object



62
63
64
# File 'lib/leto/utils.rb', line 62

def self.shared_objects(obj1, obj2, filter: nil)
  each_shared_object(obj1, obj2, filter: filter).to_a
end

.trace(obj, max_depth: nil, path: nil, &block) ⇒ Object



9
10
11
12
13
# File 'lib/leto/call.rb', line 9

def self.trace(obj, max_depth: nil, path: nil, &block)
  block_given? or return enum_for(__method__, obj, max_depth: max_depth, path: path)

  call(obj, max_depth: max_depth, path: path || Path.new(start: obj), &block)
end