Sha256: fa0173da697b90655818ef1204a6992ddcaad9fd8773776f97b50e83400ef38a

Contents?: true

Size: 1.99 KB

Versions: 1

Compression:

Stored size: 1.99 KB

Contents

require 'active_record'

module SomehowHasRelation
  def self.included(base)
    base.send :extend, ClassMethods
    base.send :include, InstanceMethods
  end

  module ClassMethods
    def somehow_has(params={})
      remove_const('SOMEHOW_HAS_RELATION') if const_defined?('SOMEHOW_HAS_RELATION')
      const_set('SOMEHOW_HAS_RELATION', params)

      prefix = "related"
      filter = params[:if]
      relation = params[:one] || params[:many]
      related = params[:as] || "#{prefix}_#{relation}"

      # Dynamic Instance Method related_%{relation_name}
      define_method(related) do
        params[:through] ? somehow_look_for(relation, params[:through]).flatten : send_and_filter(relation, filter)
      end
    end

    def somehow_has_options(key=nil)
      if const_defined?('SOMEHOW_HAS_RELATION')
        key ? const_get('SOMEHOW_HAS_RELATION')[key] : const_get('SOMEHOW_HAS_RELATION')
      end
    end
  end

  module InstanceMethods
    def somehow_look_for(relation, through)
      first_step = send_and_filter(through)
      condition = self.class.somehow_has_options(:if)

      if first_step.is_a? Array
        first_step.map{|instance| instance.somehow_keep_looking_for(relation, condition)}
      else
        first_step.somehow_keep_looking_for(relation, condition)
      end
    end

    def somehow_keep_looking_for(relation, condition=nil)
      if self.class.somehow_has_options :through
        somehow_look_for(relation, self.class.somehow_has_options(:through))
      else
        condition.nil? ? send_and_filter(relation) : send_and_filter(relation, condition)
      end
    end

    private

    def send_and_filter(method, filter_proc=nil)
      filter_proc ? filter_relations_with(send(method), filter_proc) : send(method)
    end

    def filter_relations_with(to_filter, filter_proc)
      if to_filter.is_a? Array
        to_filter.select(&filter_proc)
      elsif filter_proc.to_proc.call(to_filter)
        to_filter
      end
    end
  end
end

ActiveRecord::Base.send :include, SomehowHasRelation

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
somehow_has_relation-0.0.1 lib/somehow_has_relation.rb