Andrius Kairiukstis
Andrius Kairiukstis

Reputation: 11

It is possible to somehow use forward_missing_to to fetch/set hash values?

I am building client for Asterisk Manager (AMI), which sending back "events" (strings in key-value format). Depending on event type the keys are different. Some known would be defined similar as a property, but I also want to access everything else similar way (I need only getter).

Below is example and I am confused about forward_missing_to, to fetch hash value (i.e. e.foo => e.data["foo"] and e.foo? => e.data["foo"]?

class Event
  @data = Hash(String,String).new

  def initialize(data : Hash(String, String))
    @data.merge! data
  end

  # known field (event), here I could apply various validations etc.
  def event=(@name : String)
    @data["name"] = @name
  end

  def event : String
    @data["name"].not_nil!
  end

  # Confusing about this:
  forward_missing_to @data
end

Example of usage:

e = Event.new({"event" => "Test", "foo" => "bar"})
p e.event    # => "Test" (only this works)
p e.foo      # => expecting to get "bar"
p e.unknown  # => should throw Unhandled exception: Missing hash key: "unknown" (KeyError)
p e.unknown? # => nil

Upvotes: 1

Views: 85

Answers (1)

asterite
asterite

Reputation: 2926

forward_missing_to just means this:

e = Event.new({"event" => "Test", "foo" => "bar"})

# Same as invoking `foo` on the @data instance variable
# because you said forward_missing_to @data
e.foo 

It doesn't mean invoking ["foo"] on @data.

You can do it like this:

  macro method_missing(call)
    {% if call.args.empty? && !call.named_args %}
      @data[{{call.name.stringify}}]
    {% else %}
      {% raise "undefined method '#{call.name}' for #{@type}" %}
    {% end %}
  end

However, I wouldn't advise using method_missing, mainly because it might be eventually removed from the language (together with forward_missing_to).

Upvotes: 4

Related Questions