Module: Patriarch::Behaviours::ClassMethods

Defined in:
lib/patriarch/behaviours.rb

Overview

Gathers class methods that should be available for model that include Patriarch::Behaviours

Instance Method Summary collapse

Instance Method Details

#add_aliases_for_functionality(module_to_complete, behaviour, options) ⇒ Object

Adds alias for behaviour calls available to models if options allow to do so

Parameters:

  • module_to_complete (Module)
  • behaviour (String)
  • options (Object)


340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/patriarch/behaviours.rb', line 340

def add_aliases_for_functionality(module_to_complete,behaviour,options)
  if options[:as]
    behaviour_alias = options[:as].to_s
  end

  if options[:undo_as]
    behaviour_undo_alias = options[:undo_as].to_s
  end

  if options[:on]
    module_to_complete.class_eval do
      # add behaviour_alias
      if options[:as]
        alias_method behaviour_alias, behaviour
      end

      # add undo_behaviour_alias
      if options[:undo_as]
        alias_method behaviour_undo_alias, Patriarch.undo(behaviour)
      end
    end
  end
end

#add_behaviour(behaviour, options) ⇒ Object



326
327
328
329
330
331
332
333
334
# File 'lib/patriarch/behaviours.rb', line 326

def add_behaviour(behaviour,options)
  if options[:medium_between] || options[:via]
    add_tripartite_behaviour(behaviour,options)
  elsif options[:on] || options[:by]
    add_bipartite_behaviour(behaviour,options)
  else
    raise AddBehaviourSyntaxError, "syntax is wrong, declaration does not suplly enough arguments declared with right options"
  end
end

#add_bipartite_behaviour(behaviour, options) ⇒ Object

tool method shall be implemented

Parameters:

  • behaviour (Symbol)

    the bipartite behaviour we want to add to our model

  • options (Object)

    information useful to determine if supplementary functionality such as aliases or custom



521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
# File 'lib/patriarch/behaviours.rb', line 521

def add_bipartite_behaviour(behaviour,options)
  # add_behaviour :like, :by => bla,  :on => [:item,:user] || :community, :as => :love, :reverse_as => :hate ...

  behaviour = behaviour.to_s.underscore

  check_add_behaviour_syntax(options)

  methods_mod = Module.new do; end

  if options[:on]
    # Adds active methods and defines the hook to set callbacks on them
    add_functionality_for_bipartite(methods_mod,behaviour)
    add_aliases_for_functionality(methods_mod,behaviour,options)
    acted_on_model_list = Array(options[:on])
    Patriarch::Behaviours.complete_custom_active_module_bipartite(methods_mod,behaviour,acted_on_model_list,options)
  else
    targeted_by_model_list = Array(options[:by])
    Patriarch::Behaviours.complete_custom_passive_module_bipartite(methods_mod,behaviour,targeted_by_model_list,options)
  end

  # Finally includes the custom module
  include methods_mod
  # include in which we can override the methods of the previous custom module included there ...
  include "Patriarch::Behaviours::#{behaviour.classify}::ToolsMethods".constantize
  # register the behaviour we just added
  register_bipartite_behaviour(behaviour,options)
end

#add_functionality_for_bipartite(anon_module, behaviour) ⇒ Object

Add basic behaviours calls to models in bipartite situations

Parameters:

  • anon_module (Module)
  • behaviour (String)


367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/patriarch/behaviours.rb', line 367

def add_functionality_for_bipartite(anon_module,behaviour)
  anon_module.class_eval do

    # use define_method to get otherwise out of scope variables
    # usage of self.send(:define_method,:included) would fail as it would declare included
    # as a method available to class including this module not as an override of the included
    # hook
    (class << self; self; end).send(:define_method,:included) do |klass|
      klass.extend ActiveModel::Callbacks
      klass.send(:define_model_callbacks, behaviour, Patriarch.undo(behaviour))
    end

    # behave
    define_method(behaviour) do |entity,options={}|
      run_callbacks behaviour do
        "Patriarch::Services::#{behaviour.classify}::ManagerService".constantize.instance.resolve(self,entity,options)
      end
    end

    # undo_behave
    define_method(Patriarch.undo(behaviour).to_sym) do |entity,options={}|
      run_callbacks Patriarch.undo(behaviour).to_sym do
        "Patriarch::Services::#{(Patriarch.undo(behaviour)).classify}::ManagerService".constantize.instance.resolve(self,entity,options)
      end
    end

  end # class_eval
end

#add_functionality_for_tripartite(anon_module, behaviour) ⇒ Object

Add basic behaviours calls to models in tripartite situations

Parameters:

  • anon_module (Module)
  • behaviour (String)


399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/patriarch/behaviours.rb', line 399

def add_functionality_for_tripartite(anon_module,behaviour)
  anon_module.class_eval do

    # use define_method to get otherwise out of scope variables
    # usage of self.send(:define_method,:included) would fail as it would declare included
    # as a method available to class including this module not as an override of the included
    # hook
    (class << self; self; end).send(:define_method,:included) do |klass|
      klass.extend ActiveModel::Callbacks
      klass.send(:define_model_callbacks, behaviour, Patriarch.undo(behaviour))
    end

    # behave
    define_method(behaviour) do |via_entity,entity,options={}|
      run_callbacks behaviour.to_sym do
        "Patriarch::Services::#{behaviour.classify}::ManagerService".constantize.instance.resolve(self,entity,via_entity,options)
      end
    end

    # undo_behave
    define_method(Patriarch.undo(behaviour)) do |via_entity,entity,options={}|
      run_callbacks Patriarch.undo(behaviour).to_sym do
        "Patriarch::Services::#{Patriarch.undo(behaviour).classify}::ManagerService".constantize.instance.resolve(self,entity,via_entity,options)
      end
    end

  end # class_eval
end

#add_tripartite_behaviour(behaviour, options) ⇒ Object

tool method shall be implemented

Parameters:

  • behaviour (Symbol)

    the tripartite behaviour we want to add to our model

  • options (Object)

    information useful to determine if supplementary functionality such as aliases or custom



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/patriarch/behaviours.rb', line 483

def add_tripartite_behaviour(behaviour,options)
  behaviour = behaviour.to_s.underscore

  check_add_behaviour_syntax(options)

  methods_mod = Module.new do; end

  # Target on Actor cases
  if options[:via]
    # Actor case
    if options[:on]
      add_functionality_for_tripartite(methods_mod,behaviour)
      add_aliases_for_functionality(methods_mod,behaviour,options)
      acted_on_model_list = Array(options[:on])
      via_model_list = Array(options[:via])
      Patriarch::Behaviours.complete_custom_active_module_tripartite(methods_mod,behaviour,acted_on_model_list,via_model_list,options)
      #Target case
    elsif options[:by]
      targeted_by_model_list = Array(options[:by])
      via_model_list = Array(options[:via])
      Patriarch::Behaviours.complete_custom_passive_module_tripartite(methods_mod,behaviour,targeted_by_model_list,via_model_list,options)
    end
  # Medium case
  elsif options[:medium_between]
    # Define tool_methods_here ...
  end

  # Finally ...
  include methods_mod
  # include in which we can override the methods of the previous custom module included there ...
  include "Patriarch::Behaviours::#{behaviour.classify}::ToolsMethods".constantize
  # register behaviour we just added
  register_tripartite_behaviour(behaviour,options)
end

#check_add_behaviour_syntax(options) ⇒ Object

Helper that checks if options syntax is correct Raises errors if not with indications on what should be corrected

Parameters:

  • options (Object)


277
278
279
280
281
282
283
# File 'lib/patriarch/behaviours.rb', line 277

def check_add_behaviour_syntax(options)
  if options[:medium_between] || options[:via]
    check_tripartite_add_behaviour_syntax(options)
  elsif options[:on] || options[:by]
    check_bipartite_add_behaviour_syntax(options)
  end
end

#check_bipartite_add_behaviour_syntax(options) ⇒ Object

:nodoc:



286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/patriarch/behaviours.rb', line 286

def check_bipartite_add_behaviour_syntax(options)
  # Either you add a behaviour on another model or allow a behaviour on you by another model
  unless options[:by].nil? ^ options[:on].nil?
    raise AddBehaviourSyntaxError, "you must not define a behaviour as active (using on) and passive at the same time (using by)"
  end

  # as option should be a string or symbol
  if options[:as]
    unless [Symbol,String].include?(options[:as].class)
      raise AddBehaviourSyntaxError, "as option should be a string or symbol"
    end
  end
end

#check_tripartite_add_behaviour_syntax(options) ⇒ Object

:nodoc:



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/patriarch/behaviours.rb', line 301

def check_tripartite_add_behaviour_syntax(options)
  # Xor on options :medium_between and :via, disparate cases ...
  unless options[:medium_between].nil? ^ options[:via].nil?
    raise AddBehaviourSyntaxError, "you must not define a behaviour as active (using on) and passive at the same time (using by)"
  end

  if options[:via]
    unless options[:by].nil? ^ options[:on].nil?
      raise AddBehaviourSyntaxError, "you must not define a behaviour as active (using on) and passive at the same time (using by)"
    end
  else
    medium_between_option = options[:medium_between]
    unless medium_between_option.is_a?(Array) && medium_between_option.size == 2
      raise AddBehaviourSyntaxError, "syntax with medium medium_between requires that you provide an array of two symbols/strings"
    end
  end

  if options[:as]
    # as option should be a string or symbol
    unless [Symbol,String].include?(options[:as].class)
      raise AddBehaviourSyntaxError, "as option should be a string or symbol"
    end
  end
end

#register_bipartite_behaviour(behaviour, options) ⇒ Object

Registers at a class level a declaration of bipartite behaviour so that it can be used to check protagonist types when calling behaviours

Parameters:

  • behaviour (String)
  • options (Hash)


432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/patriarch/behaviours.rb', line 432

def register_bipartite_behaviour(behaviour,options)
  behaviour = behaviour.underscore.to_sym

  self.patriarch_behaviours ||= { }
  self.patriarch_behaviours[behaviour] ||= []

  Array(options[:on]).each do |target_class_sym|
    self.patriarch_behaviours[behaviour] << [self,target_class_sym.to_s.classify.constantize]
  end

  Array(options[:by]).each do |actor_class_sym|          
    self.patriarch_behaviours[behaviour] << [actor_class_sym.to_s.classify.constantize,self]
  end
end

#register_tripartite_behaviour(behaviour, options) ⇒ Object

Registers at a class level a declaration of tripartite behaviour so that it can be used to check protagonist types when calling behaviours

Parameters:

  • behaviour (String)
  • options (Hash)


451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/patriarch/behaviours.rb', line 451

def register_tripartite_behaviour(behaviour,options)
  behaviour = behaviour.underscore.to_sym

  self.patriarch_behaviours ||= { }
  self.patriarch_behaviours[behaviour]  ||= []

  Array(options[:via]).each do |medium_class_sym|
    Array(options[:on]).each do |target_class_sym|
      target_class = target_class_sym.to_s.classify.constantize
      medium_class = medium_class_sym.to_s.classify.constantize
      self.patriarch_behaviours[behaviour] << [self, target_class, medium_class]
    end

    Array(options[:by]).each do |actor_class_sym|
      actor_class  = actor_class_sym.to_s.classify.constantize
      medium_class = medium_class_sym.to_s.classify.constantize
      self.patriarch_behaviours[behaviour] << [actor_class, self, medium_class]
    end
  end

  # FIXME should support enumerations of medium betweens like this
  # [[actor1,target1],[actor2,target2]]
  if options[:medium_between]
    actor_class  = options[:medium_between].first.to_s.classify.constantize
    target_class = options[:medium_between].last.to_s.classify.constantize
    self.patriarch_behaviours[behaviour] << [actor_class, target_class, self]
  end
end