Yes, you still need a frame to listen for events. Here's a simple snippet you can use to make events trigger methods of the same name on your addon table:
Code:
-- Create the frame:
local eventFrame = CreateFrame("Frame")
-- Make the frame call your addon methods on events,
-- passing them all the event's arguments:
eventFrame:SetScript("OnEvent", function(self, event, ...)
return addon[event] and addon[event](addon, ...)
end)
-- Attach the frame to your addon table so you can
-- easily access it to register/unregister events:
addonTable.eventFrame = eventFrame
Then, when PLAYER_LOGIN fires, the function
addonTable:PLAYER_LOGIN() will be called if it exists. When UNIT_POWER fires, the function
addonTable:UNIT_POWER(unit, powerType) will be called if it exists. Both assuming, of course, that those events are registered on
eventFrame.