Class: Factbase::Fact

Inherits:
Object
  • Object
show all
Defined in:
lib/factbase/fact.rb

Overview

A single fact in a factbase.

This is an internal class, it is not supposed to be instantiated directly, by the Factbase class. However, it is possible to use it for testing directly, for example to make a fact with a single key/value pair inside:

require 'factbase/fact'
f = Factbase::Fact.new(Mutex.new, { 'foo' => [42, 256, 'Hello, world!'] })
assert_equal(42, f.foo)

A fact is basically a key/value hash map, where values are non-empty sets of values.

Author

Yegor Bugayenko ([email protected])

Copyright

Copyright © 2024 Yegor Bugayenko

License

MIT

Instance Method Summary collapse

Constructor Details

#initialize(mutex, map) ⇒ Fact

Ctor.

Parameters:

  • mutex (Mutex)

    A mutex to use for maps synchronization

  • map (Hash)

    A map of key/value pairs



48
49
50
51
# File 'lib/factbase/fact.rb', line 48

def initialize(mutex, map)
  @mutex = mutex
  @map = map
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args) ⇒ Object

When a method is missing, this method is called.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/factbase/fact.rb', line 60

def method_missing(*args)
  k = args[0].to_s
  if k.end_with?('=')
    kk = k[0..-2]
    raise "Invalid prop name '#{kk}'" unless kk.match?(/^[a-z_][_a-zA-Z0-9]*$/)
    raise "Prohibited prop name '#{kk}'" if kk == 'to_s'
    v = args[1]
    raise "Prop value can't be nil" if v.nil?
    raise "Prop value can't be empty" if v == ''
    raise "Prop type '#{v.class}' is not allowed" unless [String, Integer, Float, Time].include?(v.class)
    v = v.utc if v.is_a?(Time)
    @mutex.synchronize do
      before = @map[kk]
      return if before == v
      if before.nil?
        @map[kk] = v
        return
      end
      @map[kk] = [@map[kk]] unless @map[kk].is_a?(Array)
      @map[kk] << v
      @map[kk].uniq!
    end
    nil
  elsif k == '[]'
    @map[args[1].to_s]
  else
    v = @map[k]
    if v.nil?
      raise "Can't get '#{k}', the fact is empty" if @map.empty?
      raise "Can't find '#{k}' attribute out of [#{@map.keys.join(', ')}]"
    end
    v.is_a?(Array) ? v[0] : v
  end
end

Instance Method Details

#respond_to?(_method, _include_private = false) ⇒ Boolean

rubocop:disable Style/OptionalBooleanParameter

Returns:

  • (Boolean)


96
97
98
99
# File 'lib/factbase/fact.rb', line 96

def respond_to?(_method, _include_private = false)
  # rubocop:enable Style/OptionalBooleanParameter
  true
end

#respond_to_missing?(_method, _include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/factbase/fact.rb', line 101

def respond_to_missing?(_method, _include_private = false)
  true
end

#to_sString

Convert it to a string.

Returns:

  • (String)

    String representation of it (in JSON)



55
56
57
# File 'lib/factbase/fact.rb', line 55

def to_s
  "[ #{@map.map { |k, v| "#{k}: #{v}" }.join(', ')} ]"
end