Class: Mobb::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/mobb/base.rb

Direct Known Subclasses

Application

Constant Summary collapse

CALLERS_TO_IGNORE =
[
  /\/mobb(\/(base|main|show_exceptions))?\.rb$/,   # all sinatra code
  /^\(.*\)$/,                                         # generated code
  /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
  /active_support/,                                   # active_support require hacks
  /bundler(\/runtime)?\.rb/,                          # bundler require hacks
  /<internal:/,                                       # internal in ruby >= 1.9.2
  /src\/kernel\/bootstrap\/[A-Z]/                     # maglev kernel files
]

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.eventsObject (readonly)

Returns the value of attribute events.



160
161
162
# File 'lib/mobb/base.rb', line 160

def events
  @events
end

.filtersObject (readonly)

Returns the value of attribute filters.



160
161
162
# File 'lib/mobb/base.rb', line 160

def filters
  @filters
end

Class Method Details

.add_filter(type, pattern = /.*/, **options, &block) ⇒ Object



190
191
192
# File 'lib/mobb/base.rb', line 190

def add_filter(type, pattern = /.*/, **options, &block)
  filters[type] << compile!(type, pattern, options, &block)
end

.after(pattern = /.*/, **options, &block) ⇒ Object



186
187
188
# File 'lib/mobb/base.rb', line 186

def after(pattern = /.*/, **options, &block)
  add_filter(:after, pattern, options, &block)
end

.before(pattern = /.*/, **options, &block) ⇒ Object



182
183
184
# File 'lib/mobb/base.rb', line 182

def before(pattern = /.*/, **options, &block)
  add_filter(:before, pattern, options, &block)
end

.clear(*options) ⇒ Object



339
# File 'lib/mobb/base.rb', line 339

def clear(*options) options.each { |option| set(option, nil) }; end

.compile(pattern, options) ⇒ Object



233
# File 'lib/mobb/base.rb', line 233

def compile(pattern, options) Matcher.new(pattern, options); end

.compile!(type, pattern, options, &block) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/mobb/base.rb', line 211

def compile!(type, pattern, options, &block)
  at = options.delete(:at)
  options.each_pair { |option, args| send(option, *args) }

  matcher = case type
            when :message
              compile(pattern, options)
            when :ticker
              compile_cron(pattern, at)
            else
              compile(pattern, options)
            end
  unbound_method = generate_method("#{type}", &block)
  source_conditions, @source_conditions = @source_conditions, []
  dest_conditions, @dest_conditions = @dest_conditions, []
  wrapper = block.arity != 0 ?
    proc { |instance, args| unbound_method.bind(instance).call(*args) } :
    proc { |instance, args| unbound_method.bind(instance).call }

  [ matcher, wrapper, source_conditions, dest_conditions ]
end

.compile_cron(time, at) ⇒ Object



235
236
237
238
239
240
241
# File 'lib/mobb/base.rb', line 235

def compile_cron(time, at)
  if String === time
    Matcher.new(CronParser.new(time))
  else
    Matcher.new(CronParser.new(Whenever::Output::Cron.new(time, nil, at).time_in_cron_syntax))
  end
end

.condition(name = "#{caller.first[/`.*'/]} condition", &block) ⇒ Object Also known as: source_condition



304
305
306
# File 'lib/mobb/base.rb', line 304

def condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @source_conditions << generate_method(name, &block)
end

.cron(pattern, options = {}, &block) ⇒ Object Also known as: every



197
# File 'lib/mobb/base.rb', line 197

def cron(pattern, options = {}, &block) event(:ticker, pattern, options, &block); end

.dest_condition(name = "#{caller.first[/`.*'/]} condition", &block) ⇒ Object



309
310
311
312
313
314
315
316
317
# File 'lib/mobb/base.rb', line 309

def dest_condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @dest_conditions << generate_method(name) do |res|
    if String === res
      res = [res, {}]
    end
    block.call(res)
    res
  end
end

.dest_to(channel) ⇒ Object



331
332
333
334
335
# File 'lib/mobb/base.rb', line 331

def dest_to(channel)
  dest_condition do |res|
    res.last[:dest_channel] = channel
  end
end

.development?Boolean

Returns:

  • (Boolean)


264
# File 'lib/mobb/base.rb', line 264

def development?; environment == :development; end

.disable(*options) ⇒ Object



338
# File 'lib/mobb/base.rb', line 338

def disable(*options) options.each { |option| set(option, false) }; end

.enable(*options) ⇒ Object



337
# File 'lib/mobb/base.rb', line 337

def enable(*options) options.each { |option| set(option, true) }; end

.event(type, pattern, options, &block) ⇒ Object



200
201
202
203
204
205
# File 'lib/mobb/base.rb', line 200

def event(type, pattern, options, &block)
  signature = compile!(type, pattern, options, &block)
  (@events[type] ||= []) << signature
  invoke_hook(:event_added, type, pattern, block)
  signature
end

.extensionsObject



170
171
172
173
174
175
176
# File 'lib/mobb/base.rb', line 170

def extensions
  if superclass.respond_to?(:extensions)
    (@extensions + superclass.extensions).uniq
  else
    @extensions
  end
end

.generate_method(name, &block) ⇒ Object



243
244
245
246
247
248
# File 'lib/mobb/base.rb', line 243

def generate_method(name, &block)
  define_method(name, &block)
  method = instance_method(name)
  remove_method(name)
  method
end

.helpers(*extensions, &block) ⇒ Object



250
251
252
253
# File 'lib/mobb/base.rb', line 250

def helpers(*extensions, &block)
  class_eval(&block)   if block_given?
  include(*extensions) if extensions.any?
end

.ignore_bot(cond) ⇒ Object



319
320
321
322
323
# File 'lib/mobb/base.rb', line 319

def ignore_bot(cond)
  condition do
    @env.bot? != cond
  end
end

.invoke_hook(name, *args) ⇒ Object



207
208
209
# File 'lib/mobb/base.rb', line 207

def invoke_hook(name, *args)
  extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
end

.production?Boolean

Returns:

  • (Boolean)


265
# File 'lib/mobb/base.rb', line 265

def production?; environment == :production; end

.quit!Object



359
360
361
362
363
364
# File 'lib/mobb/base.rb', line 359

def quit!
  return unless running?
  running_service.respond_to?(:stop!) ? running_service.stop! : running_service.stop
  $stderr.puts "== Great sound Mobb, thank you so much"
  clear :running_service, :handler_name
end

.receive(pattern, options = {}, &block) ⇒ Object Also known as: on



194
# File 'lib/mobb/base.rb', line 194

def receive(pattern, options = {}, &block) event(:message, pattern, options, &block); end

.register(*extensions, &block) ⇒ Object



255
256
257
258
259
260
261
262
# File 'lib/mobb/base.rb', line 255

def register(*extensions, &block)
  extensions << Module.new(&block) if block_given?
  @extensions += extensions
  extensions.each do |extension|
    extend extension
    extension.registered(self) if extension.respond_to?(:registered)
  end
end

.reply_to_me(cond) ⇒ Object



325
326
327
328
329
# File 'lib/mobb/base.rb', line 325

def reply_to_me(cond)
  condition do
    @env.reply_to.include?(settings.name) == cond
  end
end

.reset!Object



162
163
164
165
166
167
168
# File 'lib/mobb/base.rb', line 162

def reset!
  @events = {}
  @filters = { before: [], after: [] }
  @source_conditions = []
  @dest_conditions = []
  @extensions = []
end

.run!(options = {}, &block) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/mobb/base.rb', line 341

def run!(options = {}, &block)
  return if running?

  set options
  handler = detect_repp_handler
  handler_name = handler.name.gsub(/.*::/, '')
  service_settings = settings.respond_to?(:service_settings) ? settings.service_settings : {}
  
  begin
    start_service(handler, service_settings, handler_name, &block)
  rescue => e
    $stderr.puts e.message
    $stderr.puts e.backtrace
  ensure
    quit!
  end
end

.running?Boolean

Returns:

  • (Boolean)


366
367
368
# File 'lib/mobb/base.rb', line 366

def running?
  running_service?
end

.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object

Raises:

  • (ArgumentError)


268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/mobb/base.rb', line 268

def set(option, value = (not_set = true), ignore_setter = false, &block)
  raise ArgumentError if block && !not_set
  value, not_set = block, false if block

  if not_set
    raise ArgumentError unless option.respond_to?(:each)
    option.each { |k,v| set(k,v) }
    return self
  end

  setter_name = "#{option}="
  if respond_to?(setter_name) && ! ignore_setter
    return __send__(setter_name, value)
  end

  setter = proc { |val| set(option, val, true) }
  getter = proc { value }

  case value
  when Proc
    getter = value
  when Symbol, Integer, FalseClass, TrueClass, NilClass
    getter = value.inspect
  when Hash
    setter = proc do |val|
      val = value.merge(val) if Hash === val
      set(option, val, true)
    end
  end

  define_singleton(setter_name, setter)
  define_singleton(option, getter)
  define_singleton("#{option}?", "!!#{option}") unless method_defined?("#{option}?")
  self
end

.settingsObject



178
179
180
# File 'lib/mobb/base.rb', line 178

def settings
  self
end

.test?Boolean

Returns:

  • (Boolean)


266
# File 'lib/mobb/base.rb', line 266

def test?; environment == :test; end

Instance Method Details

#call(env) ⇒ Object



60
61
62
# File 'lib/mobb/base.rb', line 60

def call(env)
  dup.call!(env)
end

#call!(env) ⇒ Object



64
65
66
67
68
# File 'lib/mobb/base.rb', line 64

def call!(env)
  @env = env
  invoke { dispatch! }
  [@body, @attachments]
end

#dispatch!Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/mobb/base.rb', line 70

def dispatch!
  # TODO: encode input messages

  invoke do
    filter! :before
    handle_event
  end
ensure
  begin
    filter! :after
  rescue ::Exception => boom
    # TODO: invoke { handle_exception!(boom) }
  end
end

#event_evalObject



143
# File 'lib/mobb/base.rb', line 143

def event_eval; throw :halt, yield; end

#filter!(type, base = settings) ⇒ Object



100
101
102
103
104
105
106
107
108
109
# File 'lib/mobb/base.rb', line 100

def filter!(type, base = settings)
  filter! type, base.superclass if base.superclass.respond_to?(:filters)
  base.filters[type].each { |signature|
    # TODO: Refactor compile! and process_event to change conditions in a hash (e,g, { source_cond: [], dest_cond: [] })
    pattern = signature.first
    source_conditions = signature[2]
    wrapper = signature[1]
    process_event(pattern, source_conditions, wrapper)
  }
end

#handle_event(base = settings, passed_block = nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/mobb/base.rb', line 111

def handle_event(base = settings, passed_block = nil)
  if responds = base.events[@env.event_type]
    responds.each do |pattern, block, source_conditions, dest_conditions|
      process_event(pattern, source_conditions) do |*args|
        event_eval do
          res = block[*args]
          dest_conditions.inject(res) { |acc, c| c.bind(self).call(acc) }
        end
      end
    end
  end

  # TODO: Define respond missing if receive reply message
  nil
end

#invokeObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/mobb/base.rb', line 85

def invoke
  res = catch(:halt) { yield }
  return if res.nil?
  
  res = [res] if String === res
  if Array === res && String === res.first
    tmp = res.dup
    @body = tmp.shift
    @attachments = tmp.pop
  else
    @attachments = res
  end
  nil
end

#process_event(pattern, conditions, block = nil, values = []) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/mobb/base.rb', line 127

def process_event(pattern, conditions, block = nil, values = [])
  res = pattern.match?(@env.body)
  catch(:pass) do
    conditions.each { |c| throw :pass unless c.bind(self).call }

    case res
    when ::Mobb::Matcher::Matched
      block ? block[self, *(res.matched)] : yield(self, *(res.matched))
    when TrueClass
      block ? block[self] : yield(self)
    else
      nil
    end
  end
end

#settingsObject



145
146
147
# File 'lib/mobb/base.rb', line 145

def settings
  self.class.settings
end