4

I have an array to which I keep adding blocks of code at different points of time. When a particular event occurs, an iterator iterates through this array and yields the blocks one after the other.

Many of these blocks are the same and I want to avoid executing duplicate blocks.

This is sample code:

    @after_event_hooks = []

    def add_after_event_hook(&block)
      @after_event_hooks << block
    end

Something like @after_event_hooks.uniq or @after_event_hooks |= block don't work.

Is there a way to compare blocks or check their uniqueness?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Paras Narang
  • 621
  • 1
  • 8
  • 20

3 Answers3

2

The blocks can not be checked for uniqueness since that will mean to check whether they represent the same functions, something that is not possible and has been researched in computer science for a long time.


You can probably use a function similar to the discussed in "Ruby block to string instead of executing", which is a function that takes a block and returns a string representation of the code in the block, and compare the output of the strings you receive.

I am not sure if this is fast enough to be worthy to compare them, instead of executing them multiple times. This also has the downside you need to be sure the code is exactly the same, even one variable with different name will break it.

Community
  • 1
  • 1
hahcho
  • 1,369
  • 9
  • 17
  • Not referring to blocks being functionally similar even if they have different statements. I want to identify two blocks as same only if they have the exact same statements in the same order. I'm sorry about this not being clear in the question. – Paras Narang Mar 21 '16 at 12:52
0

As @hakcho has said, it is not trivial to compare blocks. A simple solution might be having the API request for named hooks, so you can compare the names:

@after_event_hooks = {}

def add_after_event_hook(name, &block)
  @after_event_hooks[name] = block
end

def after_event_hooks
  @after_event_hooks.values
end
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
0

Maybe use something like this:

class AfterEvents
  attr_reader :hooks

  def initialize
    @hooks = {}
  end

  def method_missing(hook_sym, &block)
    @hooks[hook_sym] = block
  end
end

Here is a sample:

events = AfterEvents.new
events.foo { puts "Event Foo" }
events.bar { puts "Event Bar" }

# test
process = {:first => [:foo], :sec => [:bar], :all => [:foo, :bar]}

process.each { |event_sym, event_codes|
  puts "Processing event #{event_sym}"
  event_codes.each { |code| events.hooks[code].call }
}
# results:
# Processing event first
# Event Foo
# Processing event sec
# Event Bar
# Processing event all
# Event Foo
# Event Bar
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Lukas Baliak
  • 2,849
  • 2
  • 23
  • 26