OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
openproject/lib/timelines/collection_proxy.rb

129 lines
2.7 KiB

#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'enumerator'
module Timelines::CollectionProxy
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def collection_proxy(name, options)
options.assert_valid_keys(:for, :leave_public)
relation_names = options[:for]
proxy_class = Class.new(Timelines::CollectionProxy::Proxy)
proxy_class.class_eval(&Proc.new) if block_given?
define_method name do
proxy_class.new(relation_names.map { |n| self.send(n) }, self)
end
protected(*relation_names) unless options[:leave_public]
end
end
class Proxy
include Enumerable
attr_reader :proxy_owner
def initialize(proxies, proxy_owner)
@proxies = proxies
@proxy_owner = proxy_owner
end
def blank?
@proxies.all?(&:blank?)
end
def present?
@proxies.any?(&:present?)
end
def empty?
@proxies.all?(&:empty?)
end
def to_ary
@proxies.map(&:to_a).flatten(1)
end
alias_method :to_a, :to_ary
alias_method :all, :to_ary
def find(*args, &block)
found = nil
error = nil
@proxies.each do |proxy|
begin
result = proxy.find(*args, &block)
case result
when nil
# do nothing - especially do not overwrite previous results
when Enumerable
found += result
else
found = result
end
# If somebody uses :first and :last, s/he will get strange results.
# Let's fix it, when it happens
break if found.present? and found.is_a?(Enumerable)
rescue ActiveRecord::RecordNotFound
error = $!
end
end
raise error if found.blank? and error.present?
found
end
def first
@proxies.find { |proxy| proxy.first }.first
end
def last
@proxies.reverse.find { |proxy| proxy.last }.last
end
def each(*args, &block)
@proxies.each do |proxy|
proxy.each(*args, &block)
end
end
def count
@proxies.inject(0) { |akku, proxy| akku + proxy.count }
end
def length
@proxies.inject(0) { |akku, proxy| akku + proxy.length }
end
def size
@proxies.inject(0) { |akku, proxy| akku + proxy.size }
end
%w[build create << delete delete_all replace push].each do |method|
class_eval %Q{
def #{method}(*args)
raise NotImplementedError, 'This proxy is read-only'
end
}
end
end
end