module Mongoid::Doable::ClassMethods

Public Instance Methods

doable(action, options = {}) click to toggle source

Examples

class Course
  include Monogid::Document
  include Monogid::Doable

  doable :like, by: :user
end

class User
  include Monogid::Document
  include Monogid::Doable

  doer :like, :course

  doable :follow, by: :user
  doer :follow, :user
end

user = User.first
course = Course.first

user.like!(course) # or
user.like_course!(course) # or
course.liked_by!(user) # or

user.liking_courses
user.liking_courses_count

course.likers
course.likers_count
# File lib/mongoid/doable.rb, line 41
def doable(action, options = {})
  doer_klass_names[action.to_sym] = (options[:by] || :user).to_s.classify

  action = action.to_s                                          # "like"
  base_action = (action[-1] == "e" ? action.chop : action)      # "lik"
  passive_action = base_action + "ed"                           # "liked"
  doer_action = base_action + "ers"                             # "likers"

  field_name = "#{doer_action}_ids"                             # "likers_ids"
  counter_field_name = "#{doer_action}_count"                   # "likers_count"
  field field_name, type: Array, default: [], versioned: false          # field :likers_ids, type: Array, default: [], versioned: false
  field counter_field_name, type: Integer, default: 0, versioned: false # field :likers_count, type: Integer, default: 0, versioned: false

  define_method "#{doer_action}" do                                 # def likers
    klass = self.class.doer_klass_names[action.to_sym].constantize  #   klass = User
    klass.where(:"_id".in => send(field_name))                      #   klass.where(:likers_ids.in => likers_ids)
  end                                                               # end

  define_method "#{passive_action}_by?" do |actor|              # def liked_by?(actor)
    return false if actor.blank?                                #   return false if actor.blank?
    send(field_name).include? actor.id                          #   likers_ids.include? actor.id
  end                                                           # end

  define_method "#{passive_action}_by!" do |actor|              # def liked_by!(actor)
    return false if actor.blank?                                #   return false if actor.blank?
    if actor.respond_to?("#{action}!")                          #   if actor.respond_to?(:like!)
      actor.send("#{action}!", self)                            #     actor.like!(self)
    else                                                        #   else
      add_to_set(field_name, actor.id)                          #     self.add_to_set(:liker_ids, actor.id)
      inc(counter_field_name.to_sym, 1)                         #     inc(:likers_count, 1)
    end                                                         #   end
  end                                                           # end

  define_method "un#{passive_action}_by!" do |actor|            # def unliked_by!(actor)
    return false if actor.blank?                                #   return false if actor.blank?
    if actor.respond_to?("un#{action}!")                        #   if actor.respond_to?(:unlike!)
      actor.send("un#{action}!", self)                          #     actor.unlike!(self)
    else                                                        #   else
      pull(field_name, actor.id)                                #     self.pull(:liker_ids, actor.id)
      inc(counter_field_name.to_sym, -1)                        #     inc(:likers_count, -1)
    end                                                         #   end
  end                                                           # end
end
doer(action, target, options = {}) click to toggle source
# File lib/mongoid/doable.rb, line 85
def doer(action, target, options = {})

  action = action.to_s                                                # "like"
  base_action = (action[-1] == "e" ? action.chop : action)            # "lik"
  ing_action = base_action + "ing"                                    # "liking"
  passive_action = base_action + "ed"                                 # "liked"
  doer_action = base_action + "ers"                                   # "likers"

  field_name = "#{ing_action}_#{target.to_s.pluralize}_ids"           # "liking_courses_ids"
  target_field_name = "#{doer_action}_ids"                            # "likers_ids"
  target_counter_name = "#{doer_action}_count"                        # "likers_count"
  klass_name = options[:class_name] || target.to_s.classify           # "Course"

  field field_name, type: Array, default: [], versioned: false        # field :liking_courses_ids, type Array, default: [], versioned: false

  define_method "#{ing_action}_#{target.to_s.pluralize}_count" do     # def liking_courses_count
    send(field_name).size                                             #   liking_courses_ids.size
  end                                                                 # end

  unless options[:embedded]
    define_method "#{ing_action}_#{target.to_s.pluralize}" do         # def liking_courses
      klass_name.constantize.where(:"_id".in => send(field_name))     #   Course.where(:liking_courses_ids.in => liking_courses_ids)
    end                                                               # end
  end


  unless method_defined? "#{ing_action}?"
    define_method "#{ing_action}?" do |model|                         # def liking?(course)
      field = model.class.name.split(":").last.downcase               #
      send("#{ing_action}_#{field}?", model)                          #   liking_course?(course)
    end                                                               # end
  end

  define_method "#{ing_action}_#{target}?" do |model|                 # def liking_course?(course)
    send(field_name).include?(model.id)                               #   liking_courses_ids.include?(course.id)
  end                                                                 # end

  unless method_defined? "#{action}!"
    define_method "#{action}!" do |model|                                                   # def like!(couse)
      field = model.class.name.split(":").last.downcase                                     #
      send("#{action}_#{field}!", model)                                                    #   like_course!(course)
    end                                                                                     # end
  end

  define_method "#{action}_#{target}!" do |model|                                           # def like_course!(course)
    return if send("#{ing_action}_#{target}?", model)                                       #   return if liking_course?(course)

    model.add_to_set(target_field_name, self.id) if model.respond_to?(target_field_name)    #   course.add_to_set(:likers_ids, self.id) if model.respond_to?(:likers_ids)
    model.inc(target_counter_name, 1)                                                       #   coruse.inc(:likers_ids, 1)
    add_to_set(field_name, model.id)                                                        #   add_to_set(:liking_courses_ids, course.id)
  end                                                                                       # end


  unless method_defined? "un#{action}!"
    define_method "un#{action}!" do |model|                                                 # def unlike!(course)
      field = model.class.name.split(":").last.downcase                                     #
      send("un#{action}_#{field}!", model)                                                  #   like_course!(course)
    end                                                                                     # end
  end

  define_method "un#{action}_#{target}!" do |model|                                         # def unlike_course!(course)
    return unless send("#{ing_action}_#{target}?", model)                                   #   return unless liking_course?(course)

    model.pull(target_field_name, self.id) if model.respond_to?(target_field_name)          #   course.pull(:likers_ids, self.id) if course.respond_to?(:likers_ids)
    model.inc(target_counter_name, -1)                                                      #   course.inc(likers_ids, -1)
    self.pull(field_name, model.id)                                                         #   self.pull(:liking_courses_ids)
  end                                                                                       # end

end
doer_klass_names() click to toggle source
# File lib/mongoid/doable.rb, line 155
def doer_klass_names                                                   # def doer_klass_names
  @doer_klass_names ||= {}                                             #   @doer_klass_names ||= {}
end