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.
146 lines
3.6 KiB
146 lines
3.6 KiB
#-- copyright
|
|
# OpenProject is a project management system.
|
|
# Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License version 3.
|
|
#
|
|
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
|
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
|
# Copyright (C) 2010-2013 the ChiliProject Team
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# See doc/COPYRIGHT.rdoc for more details.
|
|
#++
|
|
|
|
require 'enumerator'
|
|
|
|
module TimelinesCollectionProxy
|
|
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(TimelinesCollectionProxy::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
|
|
|