From 557b9c08c5ef00a2eb3cf96853b6f83716ea3f12 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 7 Jan 2011 16:41:17 +0100 Subject: [PATCH 1/3] move report from app/models to lib --- {app/models => lib}/report.rb | 0 {app/models => lib}/report/chainable.rb | 0 {app/models => lib}/report/filter.rb | 0 {app/models => lib}/report/filter/base.rb | 0 {app/models => lib}/report/filter/no_filter.rb | 0 {app/models => lib}/report/group_by.rb | 0 {app/models => lib}/report/group_by/base.rb | 0 {app/models => lib}/report/group_by/ruby_aggregation.rb | 0 {app/models => lib}/report/group_by/singleton_value.rb | 0 {app/models => lib}/report/group_by/sql_aggregation.rb | 0 {app/models => lib}/report/inherited_attribute.rb | 0 {app/models => lib}/report/inherited_namespace.rb | 0 {app/models => lib}/report/operator.rb | 0 {app/models => lib}/report/query_utils.rb | 0 {app/models => lib}/report/result.rb | 0 {app/models => lib}/report/sql_statement.rb | 0 {app/models => lib}/report/table.rb | 0 {app/models => lib}/report/transformer.rb | 0 {app/models => lib}/report/validation.rb | 0 {app/models => lib}/report/validation/dates.rb | 0 {app/models => lib}/report/validation/integers.rb | 0 {app/models => lib}/report/validation/sql.rb | 0 {app/models => lib}/report/walker.rb | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename {app/models => lib}/report.rb (100%) rename {app/models => lib}/report/chainable.rb (100%) rename {app/models => lib}/report/filter.rb (100%) rename {app/models => lib}/report/filter/base.rb (100%) rename {app/models => lib}/report/filter/no_filter.rb (100%) rename {app/models => lib}/report/group_by.rb (100%) rename {app/models => lib}/report/group_by/base.rb (100%) rename {app/models => lib}/report/group_by/ruby_aggregation.rb (100%) rename {app/models => lib}/report/group_by/singleton_value.rb (100%) rename {app/models => lib}/report/group_by/sql_aggregation.rb (100%) rename {app/models => lib}/report/inherited_attribute.rb (100%) rename {app/models => lib}/report/inherited_namespace.rb (100%) rename {app/models => lib}/report/operator.rb (100%) rename {app/models => lib}/report/query_utils.rb (100%) rename {app/models => lib}/report/result.rb (100%) rename {app/models => lib}/report/sql_statement.rb (100%) rename {app/models => lib}/report/table.rb (100%) rename {app/models => lib}/report/transformer.rb (100%) rename {app/models => lib}/report/validation.rb (100%) rename {app/models => lib}/report/validation/dates.rb (100%) rename {app/models => lib}/report/validation/integers.rb (100%) rename {app/models => lib}/report/validation/sql.rb (100%) rename {app/models => lib}/report/walker.rb (100%) diff --git a/app/models/report.rb b/lib/report.rb similarity index 100% rename from app/models/report.rb rename to lib/report.rb diff --git a/app/models/report/chainable.rb b/lib/report/chainable.rb similarity index 100% rename from app/models/report/chainable.rb rename to lib/report/chainable.rb diff --git a/app/models/report/filter.rb b/lib/report/filter.rb similarity index 100% rename from app/models/report/filter.rb rename to lib/report/filter.rb diff --git a/app/models/report/filter/base.rb b/lib/report/filter/base.rb similarity index 100% rename from app/models/report/filter/base.rb rename to lib/report/filter/base.rb diff --git a/app/models/report/filter/no_filter.rb b/lib/report/filter/no_filter.rb similarity index 100% rename from app/models/report/filter/no_filter.rb rename to lib/report/filter/no_filter.rb diff --git a/app/models/report/group_by.rb b/lib/report/group_by.rb similarity index 100% rename from app/models/report/group_by.rb rename to lib/report/group_by.rb diff --git a/app/models/report/group_by/base.rb b/lib/report/group_by/base.rb similarity index 100% rename from app/models/report/group_by/base.rb rename to lib/report/group_by/base.rb diff --git a/app/models/report/group_by/ruby_aggregation.rb b/lib/report/group_by/ruby_aggregation.rb similarity index 100% rename from app/models/report/group_by/ruby_aggregation.rb rename to lib/report/group_by/ruby_aggregation.rb diff --git a/app/models/report/group_by/singleton_value.rb b/lib/report/group_by/singleton_value.rb similarity index 100% rename from app/models/report/group_by/singleton_value.rb rename to lib/report/group_by/singleton_value.rb diff --git a/app/models/report/group_by/sql_aggregation.rb b/lib/report/group_by/sql_aggregation.rb similarity index 100% rename from app/models/report/group_by/sql_aggregation.rb rename to lib/report/group_by/sql_aggregation.rb diff --git a/app/models/report/inherited_attribute.rb b/lib/report/inherited_attribute.rb similarity index 100% rename from app/models/report/inherited_attribute.rb rename to lib/report/inherited_attribute.rb diff --git a/app/models/report/inherited_namespace.rb b/lib/report/inherited_namespace.rb similarity index 100% rename from app/models/report/inherited_namespace.rb rename to lib/report/inherited_namespace.rb diff --git a/app/models/report/operator.rb b/lib/report/operator.rb similarity index 100% rename from app/models/report/operator.rb rename to lib/report/operator.rb diff --git a/app/models/report/query_utils.rb b/lib/report/query_utils.rb similarity index 100% rename from app/models/report/query_utils.rb rename to lib/report/query_utils.rb diff --git a/app/models/report/result.rb b/lib/report/result.rb similarity index 100% rename from app/models/report/result.rb rename to lib/report/result.rb diff --git a/app/models/report/sql_statement.rb b/lib/report/sql_statement.rb similarity index 100% rename from app/models/report/sql_statement.rb rename to lib/report/sql_statement.rb diff --git a/app/models/report/table.rb b/lib/report/table.rb similarity index 100% rename from app/models/report/table.rb rename to lib/report/table.rb diff --git a/app/models/report/transformer.rb b/lib/report/transformer.rb similarity index 100% rename from app/models/report/transformer.rb rename to lib/report/transformer.rb diff --git a/app/models/report/validation.rb b/lib/report/validation.rb similarity index 100% rename from app/models/report/validation.rb rename to lib/report/validation.rb diff --git a/app/models/report/validation/dates.rb b/lib/report/validation/dates.rb similarity index 100% rename from app/models/report/validation/dates.rb rename to lib/report/validation/dates.rb diff --git a/app/models/report/validation/integers.rb b/lib/report/validation/integers.rb similarity index 100% rename from app/models/report/validation/integers.rb rename to lib/report/validation/integers.rb diff --git a/app/models/report/validation/sql.rb b/lib/report/validation/sql.rb similarity index 100% rename from app/models/report/validation/sql.rb rename to lib/report/validation/sql.rb diff --git a/app/models/report/walker.rb b/lib/report/walker.rb similarity index 100% rename from app/models/report/walker.rb rename to lib/report/walker.rb From c8adf39118e6751a032d87fd7d4532cebc1e9cf8 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 11 Jan 2011 16:52:01 +0100 Subject: [PATCH 2/3] switch to proactive autoloading. less harmfull, no load order issues. --- lib/proactive_autoloader.rb | 71 +++++++++++++++++++++++++++++++ lib/report.rb | 9 ++-- lib/report/filter.rb | 4 ++ lib/report/group_by.rb | 5 +++ lib/report/inherited_attribute.rb | 4 +- lib/report/query_utils.rb | 5 ++- lib/report/result.rb | 6 ++- lib/report/validation.rb | 6 +++ 8 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 lib/proactive_autoloader.rb diff --git a/lib/proactive_autoloader.rb b/lib/proactive_autoloader.rb new file mode 100644 index 0000000000..5334d8f70d --- /dev/null +++ b/lib/proactive_autoloader.rb @@ -0,0 +1,71 @@ +## +# From Urban Dictionary: +# proactive (91 up, 9 down) +# +# Originally a psychological term indicating an empowered, self-reliant +# individual, this has evolved through misuse into a neo-antonym of 'reactive', +# and is used as such to emphasise the preferability of one attitude or course +# of action over another. It connotes alertness, awareness and preparedness, and +# seeks to dispel any conceivable impression of incompetence. +# +# 'Proactive' is interesting in that it is perhaps the classic example of the +# unnecessary neologism. It serves as an antonym to 'reactive', yet 'reactive' +# is itself the antonym of 'active'. +# +# Arguably, since 'proactive' is now perhaps more widely used than 'active' for +# the specific purpose covered by the newer word, 'proactive' must be recognised +# as a legitimate word. The cult of hatred that has understandably grown up +# around the word can only help it endure further. +# +# One is 'active' as opposed to being 'passive' or 'reactive'. One is +# 'proactive' as opposed to 'speaking English'. +module ProactiveAutoloader + extend self + + ## + # Improved Module#autoload: + # * if path is not given, generate path according to ruby common sense + # * allow passing multiple constant names as symbols + # + # Example: + # autoload :Foo, :Bar, :Blah + def autoload(*list) + return super if list.size == 2 and String === list.last + list.each do |const| + super const, "#{name.underscore}/#{const.to_s.underscore}" + end + end + + ## + # Sets up autoload hooks in +klass+ for all Ruby files in +dir+, following + # common naming conventions. Subdirectories are *not* scanned. + def setup_autoloaders(klass, dir) + Dir.glob File.expand_path('*.rb', dir) do |file| + klass.autoload File.basename(file, '.rb').camelize, file + end + end + + ## + # If subclassed, say in foo/bar.rb and there is a directory foo/bar, + # set up autoload hooks in subclass for all ruby files in foo/bar + # (see setup_autoloaders). + def inherited(klass) + auto_setup_autoloaders(klass) + super + end + + ## + # If extending a class, say in foo/bar.rb and there is a directory foo/bar, + # set up autoload hooks in subclass for all ruby files in foo/bar + # (see setup_autoloaders). + def self.extended(klass) + auto_setup_autoloaders(klass) if klass.respond_to? :autoload + super + end + + private + + def auto_setup_autoloaders(klass) + setup_autoloaders klass, caller[1][/^((?!\.[^\.]+:\d+).)+/] + end +end diff --git a/lib/report.rb b/lib/report.rb index fd6112dc94..91b055d1ff 100644 --- a/lib/report.rb +++ b/lib/report.rb @@ -1,14 +1,11 @@ require 'forwardable' +require 'proactive_autoloader' class Report < ActiveRecord::Base - InheritedNamespace.activate unless defined? Rails && Rails.version =~ /^3./ - + extend ProactiveAutoloader extend Forwardable include Enumerable - #belongs_to :user - #belongs_to :project - #attr_protected :user_id, :project_id, :created_at, :updated_at - self.abstract_class = true #lets have subclasses have their own SQL tables + self.abstract_class = true # lets have subclasses have their own SQL tables def self.accepted_properties @@accepted_properties ||= [] diff --git a/lib/report/filter.rb b/lib/report/filter.rb index 71b9555645..f4687ea517 100644 --- a/lib/report/filter.rb +++ b/lib/report/filter.rb @@ -1,6 +1,10 @@ require "set" class Report::Filter + extend ProactiveAutoloader + autoload :Base, 'report/filter/base' + autoload :NoFilter, 'report/filter/no_filter' + def self.all @all ||= Set[] end diff --git a/lib/report/group_by.rb b/lib/report/group_by.rb index a480e7deae..171ef9de55 100644 --- a/lib/report/group_by.rb +++ b/lib/report/group_by.rb @@ -1,7 +1,12 @@ require "set" class Report::GroupBy + extend ProactiveAutoloader include Report::QueryUtils + autoload :Base, 'report/group_by/base' + autoload :RubyAggregation, 'report/group_by/ruby_aggregation' + autoload :SingletonValue, 'report/group_by/singleton_value.rb' + autoload :SqlAggregation, 'report/group_by/sql_aggregation' def self.all Set[engine::GroupBy::SingletonValue] diff --git a/lib/report/inherited_attribute.rb b/lib/report/inherited_attribute.rb index 0a320e0ae0..3d4656cfaf 100644 --- a/lib/report/inherited_attribute.rb +++ b/lib/report/inherited_attribute.rb @@ -1,6 +1,8 @@ require 'set' module Report::InheritedAttribute + include Report::QueryUtils + def inherited_attribute(*attributes) options = attributes.extract_options! list = options[:list] @@ -25,8 +27,6 @@ module Report::InheritedAttribute end end - alias singleton_class metaclass unless respond_to? :singleton_class - def define_singleton_method(name, &block) singleton_class.send :attr_writer, name singleton_class.class_eval { define_method(name, &block) } diff --git a/lib/report/query_utils.rb b/lib/report/query_utils.rb index d84e4fd8c8..3408aff20d 100644 --- a/lib/report/query_utils.rb +++ b/lib/report/query_utils.rb @@ -1,5 +1,8 @@ module Report::QueryUtils + alias singleton_class metaclass unless respond_to? :singleton_class + delegate :quoted_false, :quoted_true, :to => "ActiveRecord::Base.connection" + attr_writer :engine ## # Subclass of Report to be used for constant lookup and such. @@ -8,7 +11,7 @@ module Report::QueryUtils # @return [Class] subclass def engine return self.class.engine unless is_a? Module - Object.const_get(name[/^[^:]+/] || :Report) + @engine ||= Object.const_get(name[/^[^:]+/] || :Report) end ## diff --git a/lib/report/result.rb b/lib/report/result.rb index 6c5606db77..696b77bb0c 100644 --- a/lib/report/result.rb +++ b/lib/report/result.rb @@ -1,4 +1,6 @@ class Report::Result + include Report::QueryUtils + class Base attr_accessor :parent, :type, :important_fields attr_accessor :key @@ -243,8 +245,8 @@ class Report::Result def self.new(value, fields = {}, type = nil, important_fields = []) result = begin case value - when Array then WrappedResult.new value.map { |e| new e, {}, nil, important_fields } - when Hash then DirectResult.new value.with_indifferent_access + when Array then engine::Result::WrappedResult.new value.map { |e| new e, {}, nil, important_fields } + when Hash then engine::Result::DirectResult.new value.with_indifferent_access when Base then value else raise ArgumentError, "Cannot create Result from #{value.inspect}" end diff --git a/lib/report/validation.rb b/lib/report/validation.rb index bc8e1cd3d8..82d7c78213 100644 --- a/lib/report/validation.rb +++ b/lib/report/validation.rb @@ -1,4 +1,10 @@ module Report::Validation + extend ProactiveAutoloader + include Report::QueryUtils + autoload :Dates, 'report/validation/dates' + autoload :Integers, 'report/validation/integers' + autoload :Sql, 'report/validation/sql' + def register_validations(*validation_methods) validation_methods.flatten.each do |val_method| register_validation(val_method) From 174adc33879b7338d36c29c1c365a1d9015ee626 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 11 Jan 2011 17:02:31 +0100 Subject: [PATCH 3/3] remove obsolete file. --- lib/report/inherited_namespace.rb | 63 ------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 lib/report/inherited_namespace.rb diff --git a/lib/report/inherited_namespace.rb b/lib/report/inherited_namespace.rb deleted file mode 100644 index b95d42531b..0000000000 --- a/lib/report/inherited_namespace.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Report::InheritedNamespace - NESTED_NAMESPACES = %w[Validation Filter GroupBy Result Operator QueryUtils] - - module Hook - def const_missing(name, *) - super - rescue ArgumentError => error - # require 'ruby-debug'; debugger - rescue NameError => error - load_constant name, error - end - end - - def self.activate - Report.extend self - NESTED_NAMESPACES.each { |n| n.extend self } - end - - def inherited(klass) - super - propagate klass - end - - def included(klass) - super - propagate klass - end - - def propagate(klass) - klass.extend Report::InheritedNamespace - klass.extend Hook - return unless klass < Report - NESTED_NAMESPACES.each do |name| - if file = ActiveSupport::Dependencies.search_for_file("#{klass.name}::#{name}".underscore) - require_or_load file - propagate klass.const_get(name) - else - const_missing name - end - end - end - - def load_constant(name, error = NameError) - zuper = (Class === self ? superclass : ancestors.second).const_get(name) - klass = case zuper - when Class then const_set name, Class.new(zuper) - when Module then const_set name, Module.new { include zuper } - else const_set name, zuper - end - propagate klass - klass - rescue NameError, ArgumentError => new_error - if file = ActiveSupport::Dependencies.search_for_file("#{self.name}::#{name}".underscore) - require_or_load file - const_get name - else - error.message << "\n\tWas #{new_error.class}: #{new_error.message}" - new_error.backtrace[0..9].each { |l| error.message << "\n\t\t#{l}" } - error.message << "\n\t\t..." if new_error.backtrace.size > 10 - raise error - end - end -end