Regex Key Hash

While I was implementing the home dashboard widgets with Gridster, I needed to ajax load the contents of each widget base on the widget key. The Gridster widget keys are string based, however some keys are dynamically generated.

Let’s look at an example.

The simple case first. A widget key can be my_calendar. I need ruby to translate it to a symbol such as :my_calendar. I’ll then be able to utilise the translated value :my_calendar to fetch the widget content. To achieve this, it’s dead simple … A contrive way to do it can be somethign like this

class WidgetConfigTranslator

  MAP = {'my_calendar' => :my_calendar}

  # lines omitted
end

WidgetConfigTranslator::MAP['my_calendar'] #=> :my_calendar

Now let’s go to the deep end. Many widgets have dynamically generated keys like my_type_123 and my_type_456. I need to extract out :my_type, as well as the integers (sort of like type IDs) such as 123 and 456.

So … let’s see if we can implement a Hash-alike data structure that allows us to fetch values by passing in strings that can be recognised by a Regex.

class RegexKeyHash < Hash

  def [](search_term)
    search_term = search_term.to_s
    self.each do |key, value|
      if match_data = key.match(search_term)
        return [value, Hash[match_data.names.zip(match_data.captures)].symbolize_keys]
      end
    end
    nil
  end

end

class WidgetConfigTranslatorRevised

  DYNAMIC_WIDGET_KEY_SPLIT_MAP = RegexKeyHash[
    'my_calendar'               => :my_calendar,
    /^my_type_(?<type_id>\d+)$/ => :my_type
  ]

  # lines omitted
end

WidgetConfigTranslatorRevised::DYNAMIC_WIDGET_KEY_SPLIT_MAP['my_calendar'] #=> [:my_calendar, {}]
WidgetConfigTranslatorRevised::DYNAMIC_WIDGET_KEY_SPLIT_MAP['my_type_123'] #=> [:my_type, {type_id: 123}]
WidgetConfigTranslatorRevised::DYNAMIC_WIDGET_KEY_SPLIT_MAP['my_type_456'] #=> [:my_type, {type_id: 456}]

With the above in place, I can use the DYNAMIC_WIDGET_KEY_SPLIT_MAP constant as if it’s just a regular Hash object. The translated return values can be used to call up named URLs defined in my routes.rb and have the ability to pass in those additional params.

I don’t know if anybody would have a similar use case to use this implementation. However it solved my problem quite nicely.

Published: 2014-11-28
blog comments powered by Disqus